1 /* 2 * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 */ 8 9 #include <linux/vmalloc.h> 10 #include <linux/init.h> 11 #include <linux/module.h> 12 #include <linux/io.h> 13 #include <linux/mm.h> 14 #include <linux/slab.h> 15 #include <asm/cache.h> 16 17 void __iomem *ioremap(unsigned long paddr, unsigned long size) 18 { 19 unsigned long end; 20 21 /* Don't allow wraparound or zero size */ 22 end = paddr + size - 1; 23 if (!size || (end < paddr)) 24 return NULL; 25 26 /* If the region is h/w uncached, avoid MMU mappings */ 27 if (paddr >= ARC_UNCACHED_ADDR_SPACE) 28 return (void __iomem *)paddr; 29 30 return ioremap_prot(paddr, size, PAGE_KERNEL_NO_CACHE); 31 } 32 EXPORT_SYMBOL(ioremap); 33 34 /* 35 * ioremap with access flags 36 * Cache semantics wise it is same as ioremap - "forced" uncached. 37 * However unline vanilla ioremap which bypasses ARC MMU for addresses in 38 * ARC hardware uncached region, this one still goes thru the MMU as caller 39 * might need finer access control (R/W/X) 40 */ 41 void __iomem *ioremap_prot(phys_addr_t paddr, unsigned long size, 42 unsigned long flags) 43 { 44 void __iomem *vaddr; 45 struct vm_struct *area; 46 unsigned long off, end; 47 pgprot_t prot = __pgprot(flags); 48 49 /* Don't allow wraparound, zero size */ 50 end = paddr + size - 1; 51 if ((!size) || (end < paddr)) 52 return NULL; 53 54 /* An early platform driver might end up here */ 55 if (!slab_is_available()) 56 return NULL; 57 58 /* force uncached */ 59 prot = pgprot_noncached(prot); 60 61 /* Mappings have to be page-aligned */ 62 off = paddr & ~PAGE_MASK; 63 paddr &= PAGE_MASK; 64 size = PAGE_ALIGN(end + 1) - paddr; 65 66 /* 67 * Ok, go for it.. 68 */ 69 area = get_vm_area(size, VM_IOREMAP); 70 if (!area) 71 return NULL; 72 area->phys_addr = paddr; 73 vaddr = (void __iomem *)area->addr; 74 if (ioremap_page_range((unsigned long)vaddr, 75 (unsigned long)vaddr + size, paddr, prot)) { 76 vunmap((void __force *)vaddr); 77 return NULL; 78 } 79 return (void __iomem *)(off + (char __iomem *)vaddr); 80 } 81 EXPORT_SYMBOL(ioremap_prot); 82 83 84 void iounmap(const void __iomem *addr) 85 { 86 if (addr >= (void __force __iomem *)ARC_UNCACHED_ADDR_SPACE) 87 return; 88 89 vfree((void *)(PAGE_MASK & (unsigned long __force)addr)); 90 } 91 EXPORT_SYMBOL(iounmap); 92