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