aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorRussell King <rmk@dyn-67.arm.linux.org.uk>2007-04-21 05:47:29 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2007-04-21 15:36:00 -0400
commitb29e9f5e64fb90d2e4be1c7ef8c925b56669c74a (patch)
tree99331c544296b82abe31c55e6bca1ae37dd142c5 /arch/arm
parent24e6c6996fb6e0e716c1dda1def1bb023a0fe43b (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>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mm/ioremap.c65
-rw-r--r--arch/arm/mm/mm.h9
-rw-r--r--arch/arm/mm/mmu.c14
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
41static int remap_area_pte(pmd_t *pmd, unsigned long addr, unsigned long end, 44static 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
64static inline int remap_area_pmd(pgd_t *pgd, unsigned long addr, 68static 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
86static int remap_area_pages(unsigned long start, unsigned long pfn, 90static 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
179static int 181static int
180remap_area_sections(unsigned long virt, unsigned long pfn, 182remap_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
219static int 211static int
220remap_area_supersections(unsigned long virt, unsigned long pfn, 212remap_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
19struct mem_type {
20 unsigned int prot_pte;
21 unsigned int prot_l1;
22 unsigned int prot_sect;
23 unsigned int domain;
24};
25
26const struct mem_type *get_mem_type(unsigned int type);
27
19#endif 28#endif
20 29
21struct map_desc; 30struct 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
179struct mem_type { 179static 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
186static 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
233const 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 */