aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/mm
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2010-06-21 03:26:27 -0400
committerPaul Mundt <lethal@linux-sh.org>2010-06-21 03:26:27 -0400
commit598ee698d9db7beb06e12f4ea9d9a5fbc03a3a77 (patch)
tree07faddc4b00f302c0a87946b8e0aa0fbaf2ea10e /arch/sh/mm
parent7210ed74a1ab9ce148a66798fbeec88d27f42070 (diff)
sh: Fix up PUD trampling in ranged page table init for X2TLB.
page_table_range_init() presently allocates a PUD page for the 3-level page table case on X2 TLB configurations on each successive call. This results in the previous PUD page being trampled when PMDs with an overlapping PUD are initialized. This case was triggered by putting persistent kmaps immediately below the fixmap range for highmem. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/mm')
-rw-r--r--arch/sh/mm/init.c52
1 files changed, 38 insertions, 14 deletions
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
index 46f84de62469..82d46096e531 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -47,7 +47,6 @@ static pte_t *__get_pte_phys(unsigned long addr)
47 pgd_t *pgd; 47 pgd_t *pgd;
48 pud_t *pud; 48 pud_t *pud;
49 pmd_t *pmd; 49 pmd_t *pmd;
50 pte_t *pte;
51 50
52 pgd = pgd_offset_k(addr); 51 pgd = pgd_offset_k(addr);
53 if (pgd_none(*pgd)) { 52 if (pgd_none(*pgd)) {
@@ -67,8 +66,7 @@ static pte_t *__get_pte_phys(unsigned long addr)
67 return NULL; 66 return NULL;
68 } 67 }
69 68
70 pte = pte_offset_kernel(pmd, addr); 69 return pte_offset_kernel(pmd, addr);
71 return pte;
72} 70}
73 71
74static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot) 72static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot)
@@ -125,13 +123,45 @@ void __clear_fixmap(enum fixed_addresses idx, pgprot_t prot)
125 clear_pte_phys(address, prot); 123 clear_pte_phys(address, prot);
126} 124}
127 125
126static pmd_t * __init one_md_table_init(pud_t *pud)
127{
128 if (pud_none(*pud)) {
129 pmd_t *pmd;
130
131 pmd = alloc_bootmem_pages(PAGE_SIZE);
132 pud_populate(&init_mm, pud, pmd);
133 BUG_ON(pmd != pmd_offset(pud, 0));
134 }
135
136 return pmd_offset(pud, 0);
137}
138
139static pte_t * __init one_page_table_init(pmd_t *pmd)
140{
141 if (pmd_none(*pmd)) {
142 pte_t *pte;
143
144 pte = alloc_bootmem_pages(PAGE_SIZE);
145 pmd_populate_kernel(&init_mm, pmd, pte);
146 BUG_ON(pte != pte_offset_kernel(pmd, 0));
147 }
148
149 return pte_offset_kernel(pmd, 0);
150}
151
152static pte_t * __init page_table_kmap_check(pte_t *pte, pmd_t *pmd,
153 unsigned long vaddr, pte_t *lastpte)
154{
155 return pte;
156}
157
128void __init page_table_range_init(unsigned long start, unsigned long end, 158void __init page_table_range_init(unsigned long start, unsigned long end,
129 pgd_t *pgd_base) 159 pgd_t *pgd_base)
130{ 160{
131 pgd_t *pgd; 161 pgd_t *pgd;
132 pud_t *pud; 162 pud_t *pud;
133 pmd_t *pmd; 163 pmd_t *pmd;
134 pte_t *pte; 164 pte_t *pte = NULL;
135 int i, j, k; 165 int i, j, k;
136 unsigned long vaddr; 166 unsigned long vaddr;
137 167
@@ -144,19 +174,13 @@ void __init page_table_range_init(unsigned long start, unsigned long end,
144 for ( ; (i < PTRS_PER_PGD) && (vaddr != end); pgd++, i++) { 174 for ( ; (i < PTRS_PER_PGD) && (vaddr != end); pgd++, i++) {
145 pud = (pud_t *)pgd; 175 pud = (pud_t *)pgd;
146 for ( ; (j < PTRS_PER_PUD) && (vaddr != end); pud++, j++) { 176 for ( ; (j < PTRS_PER_PUD) && (vaddr != end); pud++, j++) {
147#ifdef __PAGETABLE_PMD_FOLDED 177 pmd = one_md_table_init(pud);
148 pmd = (pmd_t *)pud; 178#ifndef __PAGETABLE_PMD_FOLDED
149#else
150 pmd = (pmd_t *)alloc_bootmem_low_pages(PAGE_SIZE);
151 pud_populate(&init_mm, pud, pmd);
152 pmd += k; 179 pmd += k;
153#endif 180#endif
154 for (; (k < PTRS_PER_PMD) && (vaddr != end); pmd++, k++) { 181 for (; (k < PTRS_PER_PMD) && (vaddr != end); pmd++, k++) {
155 if (pmd_none(*pmd)) { 182 pte = page_table_kmap_check(one_page_table_init(pmd),
156 pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); 183 pmd, vaddr, pte);
157 pmd_populate_kernel(&init_mm, pmd, pte);
158 BUG_ON(pte != pte_offset_kernel(pmd, 0));
159 }
160 vaddr += PMD_SIZE; 184 vaddr += PMD_SIZE;
161 } 185 }
162 k = 0; 186 k = 0;