diff options
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mm/ioremap.c | 72 | ||||
-rw-r--r-- | arch/arm/mm/mm.h | 14 | ||||
-rw-r--r-- | arch/arm/mm/mmu.c | 3 |
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 | |||
45 | int ioremap_page(unsigned long virt, unsigned long phys, | 39 | int 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) | |||
313 | void __iounmap(volatile void __iomem *io_addr) | 329 | void __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 | ||
22 | extern void __flush_dcache_page(struct address_space *mapping, struct page *page); | 22 | extern 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 | } |