11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * arch/sh/mm/ioremap.c 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4d9b9487af79955a8e8fcddc963f56697e020cfedPaul Mundt * (C) Copyright 1995 1996 Linus Torvalds 5d9b9487af79955a8e8fcddc963f56697e020cfedPaul Mundt * (C) Copyright 2005 - 2010 Paul Mundt 6d9b9487af79955a8e8fcddc963f56697e020cfedPaul Mundt * 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Re-map IO memory to kernel address space so that we can access it. 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is needed for high PCI addresses that aren't mapped in the 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 640k-1MB IO memory area on PC's 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11b66c1a3919abb40f9bd8fb92a0d9fd77eb899c54Paul Mundt * This file is subject to the terms and conditions of the GNU General 12b66c1a3919abb40f9bd8fb92a0d9fd77eb899c54Paul Mundt * Public License. See the file "COPYING" in the main directory of this 13b66c1a3919abb40f9bd8fb92a0d9fd77eb899c54Paul Mundt * archive for more details. 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/vmalloc.h> 16b66c1a3919abb40f9bd8fb92a0d9fd77eb899c54Paul Mundt#include <linux/module.h> 175a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h> 19a3e61d50dc82475ebca3ff8b18c174c02c5ff511Paul Mundt#include <linux/pci.h> 205b3e1a85c2145813898ac50530c70e6d03a6aa19Haavard Skinnemoen#include <linux/io.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/page.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pgalloc.h> 23b66c1a3919abb40f9bd8fb92a0d9fd77eb899c54Paul Mundt#include <asm/addrspace.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/cacheflush.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/tlbflush.h> 260fd14754141e3604529579232d34fcffd89c24b9Paul Mundt#include <asm/mmu.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Remap an arbitrary physical address space into the kernel virtual 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * address space. Needed when the kernel wants to access high addresses 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * directly. 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NOTE! We need to allow non-page-aligned mappings too: we will obviously 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * have to convert them into an offset in a page-aligned mapping, but the 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * caller shouldn't need to know that small detail. 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 37af1415314a4190b8ea06e53808d392fcf91555afPaul Mundtvoid __iomem * __init_refok 3890e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt__ioremap_caller(phys_addr_t phys_addr, unsigned long size, 39d57d64080ddc0ff13fcffc898b6251074a482ba1Paul Mundt pgprot_t pgprot, void *caller) 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 41bf3cdeda901c7f42de3cddc8c5aa19f6b8d8f9dfPaul Mundt struct vm_struct *area; 42b66c1a3919abb40f9bd8fb92a0d9fd77eb899c54Paul Mundt unsigned long offset, last_addr, addr, orig_addr; 4390e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt void __iomem *mapped; 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Don't allow wraparound or zero size */ 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last_addr = phys_addr + size - 1; 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!size || last_addr < phys_addr) 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5190e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt * If we can't yet use the regular approach, go the fixmap route. 5290e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt */ 5390e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt if (!mem_init_done) 5490e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt return ioremap_fixed(phys_addr, size, pgprot); 5590e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt 5690e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt /* 5790e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt * First try to remap through the PMB. 5890e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt * PMB entries are all pre-faulted. 5990e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt */ 6090e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt mapped = pmb_remap_caller(phys_addr, size, pgprot, caller); 6190e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt if (mapped && !IS_ERR(mapped)) 6290e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt return mapped; 6390e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt 6490e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt /* 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Mappings have to be page-aligned 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset = phys_addr & ~PAGE_MASK; 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds phys_addr &= PAGE_MASK; 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = PAGE_ALIGN(last_addr+1) - phys_addr; 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ok, go for it.. 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 74bf3cdeda901c7f42de3cddc8c5aa19f6b8d8f9dfPaul Mundt area = get_vm_area_caller(size, VM_IOREMAP, caller); 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!area) 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds area->phys_addr = phys_addr; 78b66c1a3919abb40f9bd8fb92a0d9fd77eb899c54Paul Mundt orig_addr = addr = (unsigned long)area->addr; 79b66c1a3919abb40f9bd8fb92a0d9fd77eb899c54Paul Mundt 8090e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt if (ioremap_page_range(addr, addr + size, phys_addr, pgprot)) { 8190e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt vunmap((void *)orig_addr); 8290e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt return NULL; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 84b66c1a3919abb40f9bd8fb92a0d9fd77eb899c54Paul Mundt 85b66c1a3919abb40f9bd8fb92a0d9fd77eb899c54Paul Mundt return (void __iomem *)(offset + (char *)orig_addr); 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 87bf3cdeda901c7f42de3cddc8c5aa19f6b8d8f9dfPaul MundtEXPORT_SYMBOL(__ioremap_caller); 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8978bf04fc96f509474c6b443b515d6b79bb7bf584Paul Mundt/* 9078bf04fc96f509474c6b443b515d6b79bb7bf584Paul Mundt * Simple checks for non-translatable mappings. 9178bf04fc96f509474c6b443b515d6b79bb7bf584Paul Mundt */ 9278bf04fc96f509474c6b443b515d6b79bb7bf584Paul Mundtstatic inline int iomapping_nontranslatable(unsigned long offset) 9378bf04fc96f509474c6b443b515d6b79bb7bf584Paul Mundt{ 9478bf04fc96f509474c6b443b515d6b79bb7bf584Paul Mundt#ifdef CONFIG_29BIT 9578bf04fc96f509474c6b443b515d6b79bb7bf584Paul Mundt /* 9678bf04fc96f509474c6b443b515d6b79bb7bf584Paul Mundt * In 29-bit mode this includes the fixed P1/P2 areas, as well as 9778bf04fc96f509474c6b443b515d6b79bb7bf584Paul Mundt * parts of P3. 9878bf04fc96f509474c6b443b515d6b79bb7bf584Paul Mundt */ 9978bf04fc96f509474c6b443b515d6b79bb7bf584Paul Mundt if (PXSEG(offset) < P3SEG || offset >= P3_ADDR_MAX) 10078bf04fc96f509474c6b443b515d6b79bb7bf584Paul Mundt return 1; 10178bf04fc96f509474c6b443b515d6b79bb7bf584Paul Mundt#endif 10278bf04fc96f509474c6b443b515d6b79bb7bf584Paul Mundt 10378bf04fc96f509474c6b443b515d6b79bb7bf584Paul Mundt return 0; 10478bf04fc96f509474c6b443b515d6b79bb7bf584Paul Mundt} 10578bf04fc96f509474c6b443b515d6b79bb7bf584Paul Mundt 106b66c1a3919abb40f9bd8fb92a0d9fd77eb899c54Paul Mundtvoid __iounmap(void __iomem *addr) 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 108b66c1a3919abb40f9bd8fb92a0d9fd77eb899c54Paul Mundt unsigned long vaddr = (unsigned long __force)addr; 109b66c1a3919abb40f9bd8fb92a0d9fd77eb899c54Paul Mundt struct vm_struct *p; 110b66c1a3919abb40f9bd8fb92a0d9fd77eb899c54Paul Mundt 11178bf04fc96f509474c6b443b515d6b79bb7bf584Paul Mundt /* 11278bf04fc96f509474c6b443b515d6b79bb7bf584Paul Mundt * Nothing to do if there is no translatable mapping. 11378bf04fc96f509474c6b443b515d6b79bb7bf584Paul Mundt */ 11478bf04fc96f509474c6b443b515d6b79bb7bf584Paul Mundt if (iomapping_nontranslatable(vaddr)) 115b66c1a3919abb40f9bd8fb92a0d9fd77eb899c54Paul Mundt return; 116b66c1a3919abb40f9bd8fb92a0d9fd77eb899c54Paul Mundt 11712b6b01cb47dc3eefbef866592193661dad7afb9Paul Mundt /* 11812b6b01cb47dc3eefbef866592193661dad7afb9Paul Mundt * There's no VMA if it's from an early fixed mapping. 11912b6b01cb47dc3eefbef866592193661dad7afb9Paul Mundt */ 12012b6b01cb47dc3eefbef866592193661dad7afb9Paul Mundt if (iounmap_fixed(addr) == 0) 12112b6b01cb47dc3eefbef866592193661dad7afb9Paul Mundt return; 12212b6b01cb47dc3eefbef866592193661dad7afb9Paul Mundt 123b66c1a3919abb40f9bd8fb92a0d9fd77eb899c54Paul Mundt /* 12490e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt * If the PMB handled it, there's nothing else to do. 125b66c1a3919abb40f9bd8fb92a0d9fd77eb899c54Paul Mundt */ 12690e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt if (pmb_unmap(addr) == 0) 12790e7d649d86f21d478dc134f74c88e19dd472393Paul Mundt return; 128b66c1a3919abb40f9bd8fb92a0d9fd77eb899c54Paul Mundt 129b66c1a3919abb40f9bd8fb92a0d9fd77eb899c54Paul Mundt p = remove_vm_area((void *)(vaddr & PAGE_MASK)); 130b66c1a3919abb40f9bd8fb92a0d9fd77eb899c54Paul Mundt if (!p) { 131866e6b9e5019e210d96ced31fbae531ed756e486Harvey Harrison printk(KERN_ERR "%s: bad address %p\n", __func__, addr); 132b66c1a3919abb40f9bd8fb92a0d9fd77eb899c54Paul Mundt return; 133b66c1a3919abb40f9bd8fb92a0d9fd77eb899c54Paul Mundt } 134b66c1a3919abb40f9bd8fb92a0d9fd77eb899c54Paul Mundt 135b66c1a3919abb40f9bd8fb92a0d9fd77eb899c54Paul Mundt kfree(p); 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 137b66c1a3919abb40f9bd8fb92a0d9fd77eb899c54Paul MundtEXPORT_SYMBOL(__iounmap); 138