aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mm/ioremap.c72
-rw-r--r--arch/arm/mm/mm.h14
-rw-r--r--arch/arm/mm/mmu.c3
3 files changed, 64 insertions, 25 deletions
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index bc7d9bd766d1..12c7ad215ce7 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -36,12 +36,6 @@
36#include <asm/mach/map.h> 36#include <asm/mach/map.h>
37#include "mm.h" 37#include "mm.h"
38 38
39/*
40 * Used by ioremap() and iounmap() code to mark (super)section-mapped
41 * I/O regions in vm_struct->flags field.
42 */
43#define VM_ARM_SECTION_MAPPING 0x80000000
44
45int ioremap_page(unsigned long virt, unsigned long phys, 39int ioremap_page(unsigned long virt, unsigned long phys,
46 const struct mem_type *mtype) 40 const struct mem_type *mtype)
47{ 41{
@@ -201,12 +195,6 @@ void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn,
201 if (pfn >= 0x100000 && (__pfn_to_phys(pfn) & ~SUPERSECTION_MASK)) 195 if (pfn >= 0x100000 && (__pfn_to_phys(pfn) & ~SUPERSECTION_MASK))
202 return NULL; 196 return NULL;
203 197
204 /*
205 * Don't allow RAM to be mapped - this causes problems with ARMv6+
206 */
207 if (WARN_ON(pfn_valid(pfn)))
208 return NULL;
209
210 type = get_mem_type(mtype); 198 type = get_mem_type(mtype);
211 if (!type) 199 if (!type)
212 return NULL; 200 return NULL;
@@ -216,6 +204,34 @@ void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn,
216 */ 204 */
217 size = PAGE_ALIGN(offset + size); 205 size = PAGE_ALIGN(offset + size);
218 206
207 /*
208 * Try to reuse one of the static mapping whenever possible.
209 */
210 read_lock(&vmlist_lock);
211 for (area = vmlist; area; area = area->next) {
212 if (!size || (sizeof(phys_addr_t) == 4 && pfn >= 0x100000))
213 break;
214 if (!(area->flags & VM_ARM_STATIC_MAPPING))
215 continue;
216 if ((area->flags & VM_ARM_MTYPE_MASK) != VM_ARM_MTYPE(mtype))
217 continue;
218 if (__phys_to_pfn(area->phys_addr) > pfn ||
219 __pfn_to_phys(pfn) + size-1 > area->phys_addr + area->size-1)
220 continue;
221 /* we can drop the lock here as we know *area is static */
222 read_unlock(&vmlist_lock);
223 addr = (unsigned long)area->addr;
224 addr += __pfn_to_phys(pfn) - area->phys_addr;
225 return (void __iomem *) (offset + addr);
226 }
227 read_unlock(&vmlist_lock);
228
229 /*
230 * Don't allow RAM to be mapped - this causes problems with ARMv6+
231 */
232 if (WARN_ON(pfn_valid(pfn)))
233 return NULL;
234
219 area = get_vm_area_caller(size, VM_IOREMAP, caller); 235 area = get_vm_area_caller(size, VM_IOREMAP, caller);
220 if (!area) 236 if (!area)
221 return NULL; 237 return NULL;
@@ -313,26 +329,34 @@ __arm_ioremap_exec(unsigned long phys_addr, size_t size, bool cached)
313void __iounmap(volatile void __iomem *io_addr) 329void __iounmap(volatile void __iomem *io_addr)
314{ 330{
315 void *addr = (void *)(PAGE_MASK & (unsigned long)io_addr); 331 void *addr = (void *)(PAGE_MASK & (unsigned long)io_addr);
316#ifndef CONFIG_SMP
317 struct vm_struct *vm; 332 struct vm_struct *vm;
318 333
319 /*
320 * If this is a section based mapping we need to handle it
321 * specially as the VM subsystem does not know how to handle
322 * such a beast.
323 */
324 read_lock(&vmlist_lock); 334 read_lock(&vmlist_lock);
325 for (vm = vmlist; vm; vm = vm->next) { 335 for (vm = vmlist; vm; vm = vm->next) {
326 if ((vm->flags & VM_IOREMAP) && (vm->addr == addr)) { 336 if (vm->addr > addr)
327 if (vm->flags & VM_ARM_SECTION_MAPPING) {
328 unmap_area_sections((unsigned long)vm->addr,
329 vm->size);
330 }
331 break; 337 break;
338 if (!(vm->flags & VM_IOREMAP))
339 continue;
340 /* If this is a static mapping we must leave it alone */
341 if ((vm->flags & VM_ARM_STATIC_MAPPING) &&
342 (vm->addr <= addr) && (vm->addr + vm->size > addr)) {
343 read_unlock(&vmlist_lock);
344 return;
332 } 345 }
346#ifndef CONFIG_SMP
347 /*
348 * If this is a section based mapping we need to handle it
349 * specially as the VM subsystem does not know how to handle
350 * such a beast.
351 */
352 if ((vm->addr == addr) &&
353 (vm->flags & VM_ARM_SECTION_MAPPING)) {
354 unmap_area_sections((unsigned long)vm->addr, vm->size);
355 break;
356 }
357#endif
333 } 358 }
334 read_unlock(&vmlist_lock); 359 read_unlock(&vmlist_lock);
335#endif
336 360
337 vunmap(addr); 361 vunmap(addr);
338} 362}
diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h
index ad7cce3bc431..70f6d3ea4834 100644
--- a/arch/arm/mm/mm.h
+++ b/arch/arm/mm/mm.h
@@ -21,6 +21,20 @@ const struct mem_type *get_mem_type(unsigned int type);
21 21
22extern void __flush_dcache_page(struct address_space *mapping, struct page *page); 22extern void __flush_dcache_page(struct address_space *mapping, struct page *page);
23 23
24/*
25 * ARM specific vm_struct->flags bits.
26 */
27
28/* (super)section-mapped I/O regions used by ioremap()/iounmap() */
29#define VM_ARM_SECTION_MAPPING 0x80000000
30
31/* permanent static mappings from iotable_init() */
32#define VM_ARM_STATIC_MAPPING 0x40000000
33
34/* mapping type (attributes) for permanent static mappings */
35#define VM_ARM_MTYPE(mt) ((mt) << 20)
36#define VM_ARM_MTYPE_MASK (0x1f << 20)
37
24#endif 38#endif
25 39
26#ifdef CONFIG_ZONE_DMA 40#ifdef CONFIG_ZONE_DMA
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index c61481577ae1..27e366af67f9 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -749,7 +749,8 @@ void __init iotable_init(struct map_desc *io_desc, int nr)
749 vm->addr = (void *)(md->virtual & PAGE_MASK); 749 vm->addr = (void *)(md->virtual & PAGE_MASK);
750 vm->size = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK)); 750 vm->size = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));
751 vm->phys_addr = __pfn_to_phys(md->pfn); 751 vm->phys_addr = __pfn_to_phys(md->pfn);
752 vm->flags = VM_IOREMAP; 752 vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
753 vm->flags |= VM_ARM_MTYPE(md->type);
753 vm->caller = iotable_init; 754 vm->caller = iotable_init;
754 vm_area_add_early(vm++); 755 vm_area_add_early(vm++);
755 } 756 }