aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2010-11-21 11:27:49 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2011-02-21 14:24:14 -0500
commit516295e5ab4bf986865cfff856d484ec678e3b0b (patch)
tree2125f49635462fca18ac6d36ebf7363d3cc6d521 /arch/arm
parentf60892d3e36dcdd0d9f30db05beae7a446a93f28 (diff)
ARM: pgtable: add pud-level code
Add pud_offset() et.al. between the pgd and pmd code in preparation of using pgtable-nopud.h rather than 4level-fixup.h. This incorporates a fix from Jamie Iles <jamie@jamieiles.com> for uaccess_with_memcpy.c. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/include/asm/pgtable.h1
-rw-r--r--arch/arm/lib/uaccess_with_memcpy.c7
-rw-r--r--arch/arm/mm/dma-mapping.c11
-rw-r--r--arch/arm/mm/fault-armv.c7
-rw-r--r--arch/arm/mm/fault.c29
-rw-r--r--arch/arm/mm/idmap.c35
-rw-r--r--arch/arm/mm/mm.h2
-rw-r--r--arch/arm/mm/mmu.c22
-rw-r--r--arch/arm/mm/pgd.c24
9 files changed, 116 insertions, 22 deletions
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index ca567914d303..5750704e0271 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -301,6 +301,7 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
301#define pgd_present(pgd) (1) 301#define pgd_present(pgd) (1)
302#define pgd_clear(pgdp) do { } while (0) 302#define pgd_clear(pgdp) do { } while (0)
303#define set_pgd(pgd,pgdp) do { } while (0) 303#define set_pgd(pgd,pgdp) do { } while (0)
304#define set_pud(pud,pudp) do { } while (0)
304 305
305 306
306/* Find an entry in the second-level page table.. */ 307/* Find an entry in the second-level page table.. */
diff --git a/arch/arm/lib/uaccess_with_memcpy.c b/arch/arm/lib/uaccess_with_memcpy.c
index e2d2f2cd0c4f..8b9b13649f81 100644
--- a/arch/arm/lib/uaccess_with_memcpy.c
+++ b/arch/arm/lib/uaccess_with_memcpy.c
@@ -27,13 +27,18 @@ pin_page_for_write(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp)
27 pgd_t *pgd; 27 pgd_t *pgd;
28 pmd_t *pmd; 28 pmd_t *pmd;
29 pte_t *pte; 29 pte_t *pte;
30 pud_t *pud;
30 spinlock_t *ptl; 31 spinlock_t *ptl;
31 32
32 pgd = pgd_offset(current->mm, addr); 33 pgd = pgd_offset(current->mm, addr);
33 if (unlikely(pgd_none(*pgd) || pgd_bad(*pgd))) 34 if (unlikely(pgd_none(*pgd) || pgd_bad(*pgd)))
34 return 0; 35 return 0;
35 36
36 pmd = pmd_offset(pgd, addr); 37 pud = pud_offset(pgd, addr);
38 if (unlikely(pud_none(*pud) || pud_bad(*pud)))
39 return 0;
40
41 pmd = pmd_offset(pud, addr);
37 if (unlikely(pmd_none(*pmd) || pmd_bad(*pmd))) 42 if (unlikely(pmd_none(*pmd) || pmd_bad(*pmd)))
38 return 0; 43 return 0;
39 44
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index ac6a36142fcd..a9bdfcda23f4 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -148,6 +148,7 @@ static int __init consistent_init(void)
148{ 148{
149 int ret = 0; 149 int ret = 0;
150 pgd_t *pgd; 150 pgd_t *pgd;
151 pud_t *pud;
151 pmd_t *pmd; 152 pmd_t *pmd;
152 pte_t *pte; 153 pte_t *pte;
153 int i = 0; 154 int i = 0;
@@ -155,7 +156,15 @@ static int __init consistent_init(void)
155 156
156 do { 157 do {
157 pgd = pgd_offset(&init_mm, base); 158 pgd = pgd_offset(&init_mm, base);
158 pmd = pmd_alloc(&init_mm, pgd, base); 159
160 pud = pud_alloc(&init_mm, pgd, base);
161 if (!pud) {
162 printk(KERN_ERR "%s: no pud tables\n", __func__);
163 ret = -ENOMEM;
164 break;
165 }
166
167 pmd = pmd_alloc(&init_mm, pud, base);
159 if (!pmd) { 168 if (!pmd) {
160 printk(KERN_ERR "%s: no pmd tables\n", __func__); 169 printk(KERN_ERR "%s: no pmd tables\n", __func__);
161 ret = -ENOMEM; 170 ret = -ENOMEM;
diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c
index 01210dba0221..7cab79179421 100644
--- a/arch/arm/mm/fault-armv.c
+++ b/arch/arm/mm/fault-armv.c
@@ -95,6 +95,7 @@ static int adjust_pte(struct vm_area_struct *vma, unsigned long address,
95{ 95{
96 spinlock_t *ptl; 96 spinlock_t *ptl;
97 pgd_t *pgd; 97 pgd_t *pgd;
98 pud_t *pud;
98 pmd_t *pmd; 99 pmd_t *pmd;
99 pte_t *pte; 100 pte_t *pte;
100 int ret; 101 int ret;
@@ -103,7 +104,11 @@ static int adjust_pte(struct vm_area_struct *vma, unsigned long address,
103 if (pgd_none_or_clear_bad(pgd)) 104 if (pgd_none_or_clear_bad(pgd))
104 return 0; 105 return 0;
105 106
106 pmd = pmd_offset(pgd, address); 107 pud = pud_offset(pgd, address);
108 if (pud_none_or_clear_bad(pud))
109 return 0;
110
111 pmd = pmd_offset(pud, address);
107 if (pmd_none_or_clear_bad(pmd)) 112 if (pmd_none_or_clear_bad(pmd))
108 return 0; 113 return 0;
109 114
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index ef0e24f578ef..bc0e1d88fd3b 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -80,6 +80,7 @@ void show_pte(struct mm_struct *mm, unsigned long addr)
80 addr, (long long)pgd_val(*pgd)); 80 addr, (long long)pgd_val(*pgd));
81 81
82 do { 82 do {
83 pud_t *pud;
83 pmd_t *pmd; 84 pmd_t *pmd;
84 pte_t *pte; 85 pte_t *pte;
85 86
@@ -91,7 +92,19 @@ void show_pte(struct mm_struct *mm, unsigned long addr)
91 break; 92 break;
92 } 93 }
93 94
94 pmd = pmd_offset(pgd, addr); 95 pud = pud_offset(pgd, addr);
96 if (PTRS_PER_PUD != 1)
97 printk(", *pud=%08lx", pud_val(*pud));
98
99 if (pud_none(*pud))
100 break;
101
102 if (pud_bad(*pud)) {
103 printk("(bad)");
104 break;
105 }
106
107 pmd = pmd_offset(pud, addr);
95 if (PTRS_PER_PMD != 1) 108 if (PTRS_PER_PMD != 1)
96 printk(", *pmd=%08llx", (long long)pmd_val(*pmd)); 109 printk(", *pmd=%08llx", (long long)pmd_val(*pmd));
97 110
@@ -390,6 +403,7 @@ do_translation_fault(unsigned long addr, unsigned int fsr,
390{ 403{
391 unsigned int index; 404 unsigned int index;
392 pgd_t *pgd, *pgd_k; 405 pgd_t *pgd, *pgd_k;
406 pud_t *pud, *pud_k;
393 pmd_t *pmd, *pmd_k; 407 pmd_t *pmd, *pmd_k;
394 408
395 if (addr < TASK_SIZE) 409 if (addr < TASK_SIZE)
@@ -408,12 +422,19 @@ do_translation_fault(unsigned long addr, unsigned int fsr,
408 422
409 if (pgd_none(*pgd_k)) 423 if (pgd_none(*pgd_k))
410 goto bad_area; 424 goto bad_area;
411
412 if (!pgd_present(*pgd)) 425 if (!pgd_present(*pgd))
413 set_pgd(pgd, *pgd_k); 426 set_pgd(pgd, *pgd_k);
414 427
415 pmd_k = pmd_offset(pgd_k, addr); 428 pud = pud_offset(pgd, addr);
416 pmd = pmd_offset(pgd, addr); 429 pud_k = pud_offset(pgd_k, addr);
430
431 if (pud_none(*pud_k))
432 goto bad_area;
433 if (!pud_present(*pud))
434 set_pud(pud, *pud_k);
435
436 pmd = pmd_offset(pud, addr);
437 pmd_k = pmd_offset(pud_k, addr);
417 438
418 /* 439 /*
419 * On ARM one Linux PGD entry contains two hardware entries (see page 440 * On ARM one Linux PGD entry contains two hardware entries (see page
diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c
index 57299446f787..2be9139a4ef3 100644
--- a/arch/arm/mm/idmap.c
+++ b/arch/arm/mm/idmap.c
@@ -4,10 +4,10 @@
4#include <asm/pgalloc.h> 4#include <asm/pgalloc.h>
5#include <asm/pgtable.h> 5#include <asm/pgtable.h>
6 6
7static void idmap_add_pmd(pgd_t *pgd, unsigned long addr, unsigned long end, 7static void idmap_add_pmd(pud_t *pud, unsigned long addr, unsigned long end,
8 unsigned long prot) 8 unsigned long prot)
9{ 9{
10 pmd_t *pmd = pmd_offset(pgd, addr); 10 pmd_t *pmd = pmd_offset(pud, addr);
11 11
12 addr = (addr & PMD_MASK) | prot; 12 addr = (addr & PMD_MASK) | prot;
13 pmd[0] = __pmd(addr); 13 pmd[0] = __pmd(addr);
@@ -16,6 +16,18 @@ static void idmap_add_pmd(pgd_t *pgd, unsigned long addr, unsigned long end,
16 flush_pmd_entry(pmd); 16 flush_pmd_entry(pmd);
17} 17}
18 18
19static void idmap_add_pud(pgd_t *pgd, unsigned long addr, unsigned long end,
20 unsigned long prot)
21{
22 pud_t *pud = pud_offset(pgd, addr);
23 unsigned long next;
24
25 do {
26 next = pud_addr_end(addr, end);
27 idmap_add_pmd(pud, addr, next, prot);
28 } while (pud++, addr = next, addr != end);
29}
30
19void identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long end) 31void identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long end)
20{ 32{
21 unsigned long prot, next; 33 unsigned long prot, next;
@@ -27,17 +39,28 @@ void identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long end)
27 pgd += pgd_index(addr); 39 pgd += pgd_index(addr);
28 do { 40 do {
29 next = pgd_addr_end(addr, end); 41 next = pgd_addr_end(addr, end);
30 idmap_add_pmd(pgd, addr, next, prot); 42 idmap_add_pud(pgd, addr, next, prot);
31 } while (pgd++, addr = next, addr != end); 43 } while (pgd++, addr = next, addr != end);
32} 44}
33 45
34#ifdef CONFIG_SMP 46#ifdef CONFIG_SMP
35static void idmap_del_pmd(pgd_t *pgd, unsigned long addr, unsigned long end) 47static void idmap_del_pmd(pud_t *pud, unsigned long addr, unsigned long end)
36{ 48{
37 pmd_t *pmd = pmd_offset(pgd, addr); 49 pmd_t *pmd = pmd_offset(pud, addr);
38 pmd_clear(pmd); 50 pmd_clear(pmd);
39} 51}
40 52
53static void idmap_del_pud(pgd_t *pgd, unsigned long addr, unsigned long end)
54{
55 pud_t *pud = pud_offset(pgd, addr);
56 unsigned long next;
57
58 do {
59 next = pud_addr_end(addr, end);
60 idmap_del_pmd(pud, addr, next);
61 } while (pud++, addr = next, addr != end);
62}
63
41void identity_mapping_del(pgd_t *pgd, unsigned long addr, unsigned long end) 64void identity_mapping_del(pgd_t *pgd, unsigned long addr, unsigned long end)
42{ 65{
43 unsigned long next; 66 unsigned long next;
@@ -45,7 +68,7 @@ void identity_mapping_del(pgd_t *pgd, unsigned long addr, unsigned long end)
45 pgd += pgd_index(addr); 68 pgd += pgd_index(addr);
46 do { 69 do {
47 next = pgd_addr_end(addr, end); 70 next = pgd_addr_end(addr, end);
48 idmap_del_pmd(pgd, addr, next); 71 idmap_del_pud(pgd, addr, next);
49 } while (pgd++, addr = next, addr != end); 72 } while (pgd++, addr = next, addr != end);
50} 73}
51#endif 74#endif
diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h
index 36960df5fb76..d2384106af9c 100644
--- a/arch/arm/mm/mm.h
+++ b/arch/arm/mm/mm.h
@@ -7,7 +7,7 @@ extern pmd_t *top_pmd;
7 7
8static inline pmd_t *pmd_off(pgd_t *pgd, unsigned long virt) 8static inline pmd_t *pmd_off(pgd_t *pgd, unsigned long virt)
9{ 9{
10 return pmd_offset(pgd, virt); 10 return pmd_offset(pud_offset(pgd, virt), virt);
11} 11}
12 12
13static inline pmd_t *pmd_off_k(unsigned long virt) 13static inline pmd_t *pmd_off_k(unsigned long virt)
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 176749010935..82ef6966ae09 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -550,11 +550,11 @@ static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr,
550 } while (pte++, addr += PAGE_SIZE, addr != end); 550 } while (pte++, addr += PAGE_SIZE, addr != end);
551} 551}
552 552
553static void __init alloc_init_section(pgd_t *pgd, unsigned long addr, 553static void __init alloc_init_section(pud_t *pud, unsigned long addr,
554 unsigned long end, phys_addr_t phys, 554 unsigned long end, phys_addr_t phys,
555 const struct mem_type *type) 555 const struct mem_type *type)
556{ 556{
557 pmd_t *pmd = pmd_offset(pgd, addr); 557 pmd_t *pmd = pmd_offset(pud, addr);
558 558
559 /* 559 /*
560 * Try a section mapping - end, addr and phys must all be aligned 560 * Try a section mapping - end, addr and phys must all be aligned
@@ -583,6 +583,19 @@ static void __init alloc_init_section(pgd_t *pgd, unsigned long addr,
583 } 583 }
584} 584}
585 585
586static void alloc_init_pud(pgd_t *pgd, unsigned long addr, unsigned long end,
587 unsigned long phys, const struct mem_type *type)
588{
589 pud_t *pud = pud_offset(pgd, addr);
590 unsigned long next;
591
592 do {
593 next = pud_addr_end(addr, end);
594 alloc_init_section(pud, addr, next, phys, type);
595 phys += next - addr;
596 } while (pud++, addr = next, addr != end);
597}
598
586static void __init create_36bit_mapping(struct map_desc *md, 599static void __init create_36bit_mapping(struct map_desc *md,
587 const struct mem_type *type) 600 const struct mem_type *type)
588{ 601{
@@ -630,7 +643,8 @@ static void __init create_36bit_mapping(struct map_desc *md,
630 pgd = pgd_offset_k(addr); 643 pgd = pgd_offset_k(addr);
631 end = addr + length; 644 end = addr + length;
632 do { 645 do {
633 pmd_t *pmd = pmd_offset(pgd, addr); 646 pud_t *pud = pud_offset(pgd, addr);
647 pmd_t *pmd = pmd_offset(pud, addr);
634 int i; 648 int i;
635 649
636 for (i = 0; i < 16; i++) 650 for (i = 0; i < 16; i++)
@@ -696,7 +710,7 @@ static void __init create_mapping(struct map_desc *md)
696 do { 710 do {
697 unsigned long next = pgd_addr_end(addr, end); 711 unsigned long next = pgd_addr_end(addr, end);
698 712
699 alloc_init_section(pgd, addr, next, phys, type); 713 alloc_init_pud(pgd, addr, next, phys, type);
700 714
701 phys += next - addr; 715 phys += next - addr;
702 addr = next; 716 addr = next;
diff --git a/arch/arm/mm/pgd.c b/arch/arm/mm/pgd.c
index 93292a18cf77..f7fafb1741f4 100644
--- a/arch/arm/mm/pgd.c
+++ b/arch/arm/mm/pgd.c
@@ -23,6 +23,7 @@
23pgd_t *pgd_alloc(struct mm_struct *mm) 23pgd_t *pgd_alloc(struct mm_struct *mm)
24{ 24{
25 pgd_t *new_pgd, *init_pgd; 25 pgd_t *new_pgd, *init_pgd;
26 pud_t *new_pud, *init_pud;
26 pmd_t *new_pmd, *init_pmd; 27 pmd_t *new_pmd, *init_pmd;
27 pte_t *new_pte, *init_pte; 28 pte_t *new_pte, *init_pte;
28 29
@@ -46,7 +47,11 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
46 * On ARM, first page must always be allocated since it 47 * On ARM, first page must always be allocated since it
47 * contains the machine vectors. 48 * contains the machine vectors.
48 */ 49 */
49 new_pmd = pmd_alloc(mm, new_pgd, 0); 50 new_pud = pud_alloc(mm, new_pgd, 0);
51 if (!new_pud)
52 goto no_pud;
53
54 new_pmd = pmd_alloc(mm, new_pud, 0);
50 if (!new_pmd) 55 if (!new_pmd)
51 goto no_pmd; 56 goto no_pmd;
52 57
@@ -54,7 +59,8 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
54 if (!new_pte) 59 if (!new_pte)
55 goto no_pte; 60 goto no_pte;
56 61
57 init_pmd = pmd_offset(init_pgd, 0); 62 init_pud = pud_offset(init_pgd, 0);
63 init_pmd = pmd_offset(init_pud, 0);
58 init_pte = pte_offset_map(init_pmd, 0); 64 init_pte = pte_offset_map(init_pmd, 0);
59 set_pte_ext(new_pte, *init_pte, 0); 65 set_pte_ext(new_pte, *init_pte, 0);
60 pte_unmap(init_pte); 66 pte_unmap(init_pte);
@@ -66,6 +72,8 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
66no_pte: 72no_pte:
67 pmd_free(mm, new_pmd); 73 pmd_free(mm, new_pmd);
68no_pmd: 74no_pmd:
75 pud_free(mm, new_pud);
76no_pud:
69 free_pages((unsigned long)new_pgd, 2); 77 free_pages((unsigned long)new_pgd, 2);
70no_pgd: 78no_pgd:
71 return NULL; 79 return NULL;
@@ -74,6 +82,7 @@ no_pgd:
74void pgd_free(struct mm_struct *mm, pgd_t *pgd_base) 82void pgd_free(struct mm_struct *mm, pgd_t *pgd_base)
75{ 83{
76 pgd_t *pgd; 84 pgd_t *pgd;
85 pud_t *pud;
77 pmd_t *pmd; 86 pmd_t *pmd;
78 pgtable_t pte; 87 pgtable_t pte;
79 88
@@ -84,7 +93,11 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd_base)
84 if (pgd_none_or_clear_bad(pgd)) 93 if (pgd_none_or_clear_bad(pgd))
85 goto no_pgd; 94 goto no_pgd;
86 95
87 pmd = pmd_offset(pgd, 0); 96 pud = pud_offset(pgd, 0);
97 if (pud_none_or_clear_bad(pud))
98 goto no_pud;
99
100 pmd = pmd_offset(pud, 0);
88 if (pmd_none_or_clear_bad(pmd)) 101 if (pmd_none_or_clear_bad(pmd))
89 goto no_pmd; 102 goto no_pmd;
90 103
@@ -92,8 +105,11 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd_base)
92 pmd_clear(pmd); 105 pmd_clear(pmd);
93 pte_free(mm, pte); 106 pte_free(mm, pte);
94no_pmd: 107no_pmd:
95 pgd_clear(pgd); 108 pud_clear(pud);
96 pmd_free(mm, pmd); 109 pmd_free(mm, pmd);
110no_pud:
111 pgd_clear(pgd);
112 pud_free(mm, pud);
97no_pgd: 113no_pgd:
98 free_pages((unsigned long) pgd_base, 2); 114 free_pages((unsigned long) pgd_base, 2);
99} 115}