diff options
author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2007-04-21 05:47:29 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2007-04-21 15:36:00 -0400 |
commit | b29e9f5e64fb90d2e4be1c7ef8c925b56669c74a (patch) | |
tree | 99331c544296b82abe31c55e6bca1ae37dd142c5 | |
parent | 24e6c6996fb6e0e716c1dda1def1bb023a0fe43b (diff) |
[ARM] mm 5: Use mem_types table in ioremap
We really want to be using the memory type table in ioremap, so we
only have to do the CPU type fixups in one place.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r-- | arch/arm/mm/ioremap.c | 65 | ||||
-rw-r--r-- | arch/arm/mm/mm.h | 9 | ||||
-rw-r--r-- | arch/arm/mm/mmu.c | 14 |
3 files changed, 42 insertions, 46 deletions
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c index 800855b2dc83..b26b36109d54 100644 --- a/arch/arm/mm/ioremap.c +++ b/arch/arm/mm/ioremap.c | |||
@@ -32,6 +32,9 @@ | |||
32 | #include <asm/tlbflush.h> | 32 | #include <asm/tlbflush.h> |
33 | #include <asm/sizes.h> | 33 | #include <asm/sizes.h> |
34 | 34 | ||
35 | #include <asm/mach/map.h> | ||
36 | #include "mm.h" | ||
37 | |||
35 | /* | 38 | /* |
36 | * Used by ioremap() and iounmap() code to mark (super)section-mapped | 39 | * Used by ioremap() and iounmap() code to mark (super)section-mapped |
37 | * I/O regions in vm_struct->flags field. | 40 | * I/O regions in vm_struct->flags field. |
@@ -39,8 +42,9 @@ | |||
39 | #define VM_ARM_SECTION_MAPPING 0x80000000 | 42 | #define VM_ARM_SECTION_MAPPING 0x80000000 |
40 | 43 | ||
41 | static int remap_area_pte(pmd_t *pmd, unsigned long addr, unsigned long end, | 44 | static int remap_area_pte(pmd_t *pmd, unsigned long addr, unsigned long end, |
42 | unsigned long phys_addr, pgprot_t prot) | 45 | unsigned long phys_addr, const struct mem_type *type) |
43 | { | 46 | { |
47 | pgprot_t prot = __pgprot(type->prot_pte); | ||
44 | pte_t *pte; | 48 | pte_t *pte; |
45 | 49 | ||
46 | pte = pte_alloc_kernel(pmd, addr); | 50 | pte = pte_alloc_kernel(pmd, addr); |
@@ -63,7 +67,7 @@ static int remap_area_pte(pmd_t *pmd, unsigned long addr, unsigned long end, | |||
63 | 67 | ||
64 | static inline int remap_area_pmd(pgd_t *pgd, unsigned long addr, | 68 | static inline int remap_area_pmd(pgd_t *pgd, unsigned long addr, |
65 | unsigned long end, unsigned long phys_addr, | 69 | unsigned long end, unsigned long phys_addr, |
66 | pgprot_t prot) | 70 | const struct mem_type *type) |
67 | { | 71 | { |
68 | unsigned long next; | 72 | unsigned long next; |
69 | pmd_t *pmd; | 73 | pmd_t *pmd; |
@@ -75,7 +79,7 @@ static inline int remap_area_pmd(pgd_t *pgd, unsigned long addr, | |||
75 | 79 | ||
76 | do { | 80 | do { |
77 | next = pmd_addr_end(addr, end); | 81 | next = pmd_addr_end(addr, end); |
78 | ret = remap_area_pte(pmd, addr, next, phys_addr, prot); | 82 | ret = remap_area_pte(pmd, addr, next, phys_addr, type); |
79 | if (ret) | 83 | if (ret) |
80 | return ret; | 84 | return ret; |
81 | phys_addr += next - addr; | 85 | phys_addr += next - addr; |
@@ -84,13 +88,11 @@ static inline int remap_area_pmd(pgd_t *pgd, unsigned long addr, | |||
84 | } | 88 | } |
85 | 89 | ||
86 | static int remap_area_pages(unsigned long start, unsigned long pfn, | 90 | static int remap_area_pages(unsigned long start, unsigned long pfn, |
87 | unsigned long size, unsigned long flags) | 91 | size_t size, const struct mem_type *type) |
88 | { | 92 | { |
89 | unsigned long addr = start; | 93 | unsigned long addr = start; |
90 | unsigned long next, end = start + size; | 94 | unsigned long next, end = start + size; |
91 | unsigned long phys_addr = __pfn_to_phys(pfn); | 95 | unsigned long phys_addr = __pfn_to_phys(pfn); |
92 | pgprot_t prot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | | ||
93 | L_PTE_DIRTY | L_PTE_WRITE | flags); | ||
94 | pgd_t *pgd; | 96 | pgd_t *pgd; |
95 | int err = 0; | 97 | int err = 0; |
96 | 98 | ||
@@ -98,7 +100,7 @@ static int remap_area_pages(unsigned long start, unsigned long pfn, | |||
98 | pgd = pgd_offset_k(addr); | 100 | pgd = pgd_offset_k(addr); |
99 | do { | 101 | do { |
100 | next = pgd_addr_end(addr, end); | 102 | next = pgd_addr_end(addr, end); |
101 | err = remap_area_pmd(pgd, addr, next, phys_addr, prot); | 103 | err = remap_area_pmd(pgd, addr, next, phys_addr, type); |
102 | if (err) | 104 | if (err) |
103 | break; | 105 | break; |
104 | phys_addr += next - addr; | 106 | phys_addr += next - addr; |
@@ -178,9 +180,9 @@ static void unmap_area_sections(unsigned long virt, unsigned long size) | |||
178 | 180 | ||
179 | static int | 181 | static int |
180 | remap_area_sections(unsigned long virt, unsigned long pfn, | 182 | remap_area_sections(unsigned long virt, unsigned long pfn, |
181 | unsigned long size, unsigned long flags) | 183 | size_t size, const struct mem_type *type) |
182 | { | 184 | { |
183 | unsigned long prot, addr = virt, end = virt + size; | 185 | unsigned long addr = virt, end = virt + size; |
184 | pgd_t *pgd; | 186 | pgd_t *pgd; |
185 | 187 | ||
186 | /* | 188 | /* |
@@ -189,23 +191,13 @@ remap_area_sections(unsigned long virt, unsigned long pfn, | |||
189 | */ | 191 | */ |
190 | unmap_area_sections(virt, size); | 192 | unmap_area_sections(virt, size); |
191 | 193 | ||
192 | prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_DOMAIN(DOMAIN_IO) | | ||
193 | (flags & (L_PTE_CACHEABLE | L_PTE_BUFFERABLE)); | ||
194 | |||
195 | /* | ||
196 | * ARMv6 and above need XN set to prevent speculative prefetches | ||
197 | * hitting IO. | ||
198 | */ | ||
199 | if (cpu_architecture() >= CPU_ARCH_ARMv6) | ||
200 | prot |= PMD_SECT_XN; | ||
201 | |||
202 | pgd = pgd_offset_k(addr); | 194 | pgd = pgd_offset_k(addr); |
203 | do { | 195 | do { |
204 | pmd_t *pmd = pmd_offset(pgd, addr); | 196 | pmd_t *pmd = pmd_offset(pgd, addr); |
205 | 197 | ||
206 | pmd[0] = __pmd(__pfn_to_phys(pfn) | prot); | 198 | pmd[0] = __pmd(__pfn_to_phys(pfn) | type->prot_sect); |
207 | pfn += SZ_1M >> PAGE_SHIFT; | 199 | pfn += SZ_1M >> PAGE_SHIFT; |
208 | pmd[1] = __pmd(__pfn_to_phys(pfn) | prot); | 200 | pmd[1] = __pmd(__pfn_to_phys(pfn) | type->prot_sect); |
209 | pfn += SZ_1M >> PAGE_SHIFT; | 201 | pfn += SZ_1M >> PAGE_SHIFT; |
210 | flush_pmd_entry(pmd); | 202 | flush_pmd_entry(pmd); |
211 | 203 | ||
@@ -218,9 +210,9 @@ remap_area_sections(unsigned long virt, unsigned long pfn, | |||
218 | 210 | ||
219 | static int | 211 | static int |
220 | remap_area_supersections(unsigned long virt, unsigned long pfn, | 212 | remap_area_supersections(unsigned long virt, unsigned long pfn, |
221 | unsigned long size, unsigned long flags) | 213 | size_t size, const struct mem_type *type) |
222 | { | 214 | { |
223 | unsigned long prot, addr = virt, end = virt + size; | 215 | unsigned long addr = virt, end = virt + size; |
224 | pgd_t *pgd; | 216 | pgd_t *pgd; |
225 | 217 | ||
226 | /* | 218 | /* |
@@ -229,22 +221,12 @@ remap_area_supersections(unsigned long virt, unsigned long pfn, | |||
229 | */ | 221 | */ |
230 | unmap_area_sections(virt, size); | 222 | unmap_area_sections(virt, size); |
231 | 223 | ||
232 | prot = PMD_TYPE_SECT | PMD_SECT_SUPER | PMD_SECT_AP_WRITE | | ||
233 | PMD_DOMAIN(DOMAIN_IO) | | ||
234 | (flags & (L_PTE_CACHEABLE | L_PTE_BUFFERABLE)); | ||
235 | |||
236 | /* | ||
237 | * ARMv6 and above need XN set to prevent speculative prefetches | ||
238 | * hitting IO. | ||
239 | */ | ||
240 | if (cpu_architecture() >= CPU_ARCH_ARMv6) | ||
241 | prot |= PMD_SECT_XN; | ||
242 | |||
243 | pgd = pgd_offset_k(virt); | 224 | pgd = pgd_offset_k(virt); |
244 | do { | 225 | do { |
245 | unsigned long super_pmd_val, i; | 226 | unsigned long super_pmd_val, i; |
246 | 227 | ||
247 | super_pmd_val = __pfn_to_phys(pfn) | prot; | 228 | super_pmd_val = __pfn_to_phys(pfn) | type->prot_sect | |
229 | PMD_SECT_SUPER; | ||
248 | super_pmd_val |= ((pfn >> (32 - PAGE_SHIFT)) & 0xf) << 20; | 230 | super_pmd_val |= ((pfn >> (32 - PAGE_SHIFT)) & 0xf) << 20; |
249 | 231 | ||
250 | for (i = 0; i < 8; i++) { | 232 | for (i = 0; i < 8; i++) { |
@@ -282,6 +264,8 @@ void __iomem * | |||
282 | __ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size, | 264 | __ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size, |
283 | unsigned long flags) | 265 | unsigned long flags) |
284 | { | 266 | { |
267 | const struct mem_type *type; | ||
268 | struct mem_type t; | ||
285 | int err; | 269 | int err; |
286 | unsigned long addr; | 270 | unsigned long addr; |
287 | struct vm_struct * area; | 271 | struct vm_struct * area; |
@@ -292,6 +276,11 @@ __ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size, | |||
292 | if (pfn >= 0x100000 && (__pfn_to_phys(pfn) & ~SUPERSECTION_MASK)) | 276 | if (pfn >= 0x100000 && (__pfn_to_phys(pfn) & ~SUPERSECTION_MASK)) |
293 | return NULL; | 277 | return NULL; |
294 | 278 | ||
279 | t = *get_mem_type(MT_DEVICE); | ||
280 | t.prot_sect |= flags; | ||
281 | t.prot_pte |= flags; | ||
282 | type = &t; | ||
283 | |||
295 | size = PAGE_ALIGN(size); | 284 | size = PAGE_ALIGN(size); |
296 | 285 | ||
297 | area = get_vm_area(size, VM_IOREMAP); | 286 | area = get_vm_area(size, VM_IOREMAP); |
@@ -305,13 +294,13 @@ __ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size, | |||
305 | cpu_is_xsc3()) && pfn >= 0x100000 && | 294 | cpu_is_xsc3()) && pfn >= 0x100000 && |
306 | !((__pfn_to_phys(pfn) | size | addr) & ~SUPERSECTION_MASK)) { | 295 | !((__pfn_to_phys(pfn) | size | addr) & ~SUPERSECTION_MASK)) { |
307 | area->flags |= VM_ARM_SECTION_MAPPING; | 296 | area->flags |= VM_ARM_SECTION_MAPPING; |
308 | err = remap_area_supersections(addr, pfn, size, flags); | 297 | err = remap_area_supersections(addr, pfn, size, type); |
309 | } else if (!((__pfn_to_phys(pfn) | size | addr) & ~PMD_MASK)) { | 298 | } else if (!((__pfn_to_phys(pfn) | size | addr) & ~PMD_MASK)) { |
310 | area->flags |= VM_ARM_SECTION_MAPPING; | 299 | area->flags |= VM_ARM_SECTION_MAPPING; |
311 | err = remap_area_sections(addr, pfn, size, flags); | 300 | err = remap_area_sections(addr, pfn, size, type); |
312 | } else | 301 | } else |
313 | #endif | 302 | #endif |
314 | err = remap_area_pages(addr, pfn, size, flags); | 303 | err = remap_area_pages(addr, pfn, size, type); |
315 | 304 | ||
316 | if (err) { | 305 | if (err) { |
317 | vunmap((void *)addr); | 306 | vunmap((void *)addr); |
diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h index a44e30970635..66f8612c5e5b 100644 --- a/arch/arm/mm/mm.h +++ b/arch/arm/mm/mm.h | |||
@@ -16,6 +16,15 @@ static inline pmd_t *pmd_off_k(unsigned long virt) | |||
16 | return pmd_off(pgd_offset_k(virt), virt); | 16 | return pmd_off(pgd_offset_k(virt), virt); |
17 | } | 17 | } |
18 | 18 | ||
19 | struct mem_type { | ||
20 | unsigned int prot_pte; | ||
21 | unsigned int prot_l1; | ||
22 | unsigned int prot_sect; | ||
23 | unsigned int domain; | ||
24 | }; | ||
25 | |||
26 | const struct mem_type *get_mem_type(unsigned int type); | ||
27 | |||
19 | #endif | 28 | #endif |
20 | 29 | ||
21 | struct map_desc; | 30 | struct map_desc; |
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 5821e67cf8c2..6cb80b4973d2 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c | |||
@@ -176,14 +176,7 @@ void adjust_cr(unsigned long mask, unsigned long set) | |||
176 | } | 176 | } |
177 | #endif | 177 | #endif |
178 | 178 | ||
179 | struct mem_type { | 179 | static struct mem_type mem_types[] = { |
180 | unsigned int prot_pte; | ||
181 | unsigned int prot_l1; | ||
182 | unsigned int prot_sect; | ||
183 | unsigned int domain; | ||
184 | }; | ||
185 | |||
186 | static struct mem_type mem_types[] __initdata = { | ||
187 | [MT_DEVICE] = { | 180 | [MT_DEVICE] = { |
188 | .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | | 181 | .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | |
189 | L_PTE_WRITE, | 182 | L_PTE_WRITE, |
@@ -237,6 +230,11 @@ static struct mem_type mem_types[] __initdata = { | |||
237 | } | 230 | } |
238 | }; | 231 | }; |
239 | 232 | ||
233 | const struct mem_type *get_mem_type(unsigned int type) | ||
234 | { | ||
235 | return type < ARRAY_SIZE(mem_types) ? &mem_types[type] : NULL; | ||
236 | } | ||
237 | |||
240 | /* | 238 | /* |
241 | * Adjust the PMD section entries according to the CPU in use. | 239 | * Adjust the PMD section entries according to the CPU in use. |
242 | */ | 240 | */ |