diff options
author | Len Brown <len.brown@intel.com> | 2006-01-07 03:50:18 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2006-01-07 03:50:18 -0500 |
commit | ed03f430cdc8c802652467e9097606fedc2c7abc (patch) | |
tree | 30941ec1e6f93e99358fefe18175e5dd800a4379 /arch/x86_64/mm/ioremap.c | |
parent | ed349a8a0a780ed27e2a765f16cee54d9b63bfee (diff) | |
parent | 6f957eaf79356a32e838f5f262ee9a60544b1d5b (diff) | |
download | op-kernel-dev-ed03f430cdc8c802652467e9097606fedc2c7abc.zip op-kernel-dev-ed03f430cdc8c802652467e9097606fedc2c7abc.tar.gz |
Pull pnpacpi into acpica branch
Diffstat (limited to 'arch/x86_64/mm/ioremap.c')
-rw-r--r-- | arch/x86_64/mm/ioremap.c | 37 |
1 files changed, 31 insertions, 6 deletions
diff --git a/arch/x86_64/mm/ioremap.c b/arch/x86_64/mm/ioremap.c index ecf7acb..ae20706 100644 --- a/arch/x86_64/mm/ioremap.c +++ b/arch/x86_64/mm/ioremap.c @@ -247,9 +247,15 @@ void __iomem *ioremap_nocache (unsigned long phys_addr, unsigned long size) return __ioremap(phys_addr, size, _PAGE_PCD); } +/** + * iounmap - Free a IO remapping + * @addr: virtual address from ioremap_* + * + * Caller must ensure there is only one unmapping for the same pointer. + */ void iounmap(volatile void __iomem *addr) { - struct vm_struct *p; + struct vm_struct *p, *o; if (addr <= high_memory) return; @@ -257,12 +263,31 @@ void iounmap(volatile void __iomem *addr) addr < phys_to_virt(ISA_END_ADDRESS)) return; - write_lock(&vmlist_lock); - p = __remove_vm_area((void *)((unsigned long)addr & PAGE_MASK)); - if (!p) + addr = (volatile void __iomem *)(PAGE_MASK & (unsigned long __force)addr); + /* Use the vm area unlocked, assuming the caller + ensures there isn't another iounmap for the same address + in parallel. Reuse of the virtual address is prevented by + leaving it in the global lists until we're done with it. + cpa takes care of the direct mappings. */ + read_lock(&vmlist_lock); + for (p = vmlist; p; p = p->next) { + if (p->addr == addr) + break; + } + read_unlock(&vmlist_lock); + + if (!p) { printk("iounmap: bad address %p\n", addr); - else if (p->flags >> 20) + dump_stack(); + return; + } + + /* Reset the direct mapping. Can block */ + if (p->flags >> 20) ioremap_change_attr(p->phys_addr, p->size, 0); - write_unlock(&vmlist_lock); + + /* Finally remove it */ + o = remove_vm_area((void *)addr); + BUG_ON(p != o || o == NULL); kfree(p); } |