aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/sh/include/asm/pgalloc.h4
-rw-r--r--arch/sh/include/asm/pgalloc_pmd.h41
-rw-r--r--arch/sh/include/asm/pgtable.h4
-rw-r--r--arch/sh/include/asm/pgtable_pmd.h55
-rw-r--r--arch/sh/mm/Kconfig24
-rw-r--r--arch/sh/mm/fault_32.c3
-rw-r--r--arch/sh/mm/init.c6
7 files changed, 134 insertions, 3 deletions
diff --git a/arch/sh/include/asm/pgalloc.h b/arch/sh/include/asm/pgalloc.h
index fe9f037ac5fd..4ea27855c3b5 100644
--- a/arch/sh/include/asm/pgalloc.h
+++ b/arch/sh/include/asm/pgalloc.h
@@ -6,7 +6,11 @@
6 6
7#define QUICK_PT 1 /* Other page table pages that are zero on free */ 7#define QUICK_PT 1 /* Other page table pages that are zero on free */
8 8
9#ifdef CONFIG_PGTABLE_LEVELS_3
10#include <asm/pgalloc_pmd.h>
11#else
9#include <asm/pgalloc_nopmd.h> 12#include <asm/pgalloc_nopmd.h>
13#endif
10 14
11static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, 15static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
12 pte_t *pte) 16 pte_t *pte)
diff --git a/arch/sh/include/asm/pgalloc_pmd.h b/arch/sh/include/asm/pgalloc_pmd.h
new file mode 100644
index 000000000000..20f75cc4eb09
--- /dev/null
+++ b/arch/sh/include/asm/pgalloc_pmd.h
@@ -0,0 +1,41 @@
1#ifndef __ASM_SH_PGALLOC_PMD_H
2#define __ASM_SH_PGALLOC_PMD_H
3
4static inline pgd_t *pgd_alloc(struct mm_struct *mm)
5{
6 pgd_t *pgd;
7 int i;
8
9 pgd = kzalloc(sizeof(*pgd) * PTRS_PER_PGD, GFP_KERNEL | __GFP_REPEAT);
10
11 for (i = USER_PTRS_PER_PGD; i < PTRS_PER_PGD; i++)
12 pgd[i] = swapper_pg_dir[i];
13
14 return pgd;
15}
16
17static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
18{
19 kfree(pgd);
20}
21
22static inline void __check_pgt_cache(void)
23{
24}
25
26static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
27{
28 set_pud(pud, __pud((unsigned long)pmd));
29}
30
31static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
32{
33 return quicklist_alloc(QUICK_PT, GFP_KERNEL | __GFP_REPEAT, NULL);
34}
35
36static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
37{
38 quicklist_free(QUICK_PT, NULL, pmd);
39}
40
41#endif /* __ASM_SH_PGALLOC_PMD_H */
diff --git a/arch/sh/include/asm/pgtable.h b/arch/sh/include/asm/pgtable.h
index 9a0f66c1134c..9effcc3b0d10 100644
--- a/arch/sh/include/asm/pgtable.h
+++ b/arch/sh/include/asm/pgtable.h
@@ -12,7 +12,11 @@
12#ifndef __ASM_SH_PGTABLE_H 12#ifndef __ASM_SH_PGTABLE_H
13#define __ASM_SH_PGTABLE_H 13#define __ASM_SH_PGTABLE_H
14 14
15#ifdef CONFIG_PGTABLE_LEVELS_3
16#include <asm/pgtable_pmd.h>
17#else
15#include <asm/pgtable_nopmd.h> 18#include <asm/pgtable_nopmd.h>
19#endif
16#include <asm/page.h> 20#include <asm/page.h>
17 21
18#ifndef __ASSEMBLY__ 22#ifndef __ASSEMBLY__
diff --git a/arch/sh/include/asm/pgtable_pmd.h b/arch/sh/include/asm/pgtable_pmd.h
new file mode 100644
index 000000000000..78dc36e1c2dd
--- /dev/null
+++ b/arch/sh/include/asm/pgtable_pmd.h
@@ -0,0 +1,55 @@
1#ifndef __ASM_SH_PGTABLE_PMD_H
2#define __ASM_SH_PGTABLE_PMD_H
3
4#include <asm-generic/pgtable-nopud.h>
5
6/*
7 * Some cores need a 3-level page table layout, for example when using
8 * 64-bit PTEs and 4K pages.
9 */
10
11#define PTE_MAGNITUDE 3 /* 64-bit PTEs on extended mode SH-X2 TLB */
12
13/* PGD bits */
14#define PGDIR_SHIFT 30
15
16#define PTRS_PER_PGD 4
17#define USER_PTRS_PER_PGD 2
18
19/* PMD bits */
20#define PMD_SHIFT (PAGE_SHIFT + (PAGE_SHIFT - 3))
21#define PMD_SIZE (1UL << PMD_SHIFT)
22#define PMD_MASK (~(PMD_SIZE-1))
23
24#define PTRS_PER_PMD (PAGE_SIZE / sizeof(pmd_t))
25
26#define pmd_ERROR(e) \
27 printk("%s:%d: bad pmd %016llx.\n", __FILE__, __LINE__, pmd_val(e))
28
29typedef struct { unsigned long long pmd; } pmd_t;
30#define pmd_val(x) ((x).pmd)
31#define __pmd(x) ((pmd_t) { (x) } )
32
33static inline unsigned long pud_page_vaddr(pud_t pud)
34{
35 return pud_val(pud);
36}
37
38#define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
39static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address)
40{
41 return (pmd_t *)pud_page_vaddr(*pud) + pmd_index(address);
42}
43
44#define pud_none(x) (!pud_val(x))
45#define pud_present(x) (pud_val(x))
46#define pud_clear(xp) do { set_pud(xp, __pud(0)); } while (0)
47#define pud_bad(x) (pud_val(x) & ~PAGE_MASK)
48
49/*
50 * (puds are folded into pgds so this doesn't get actually called,
51 * but the define is needed for a generic inline function.)
52 */
53#define set_pud(pudptr, pudval) do { *(pudptr) = (pudval); } while(0)
54
55#endif /* __ASM_SH_PGTABLE_PMD_H */
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig
index 0e7ba8e891cf..b3f6c1a30b22 100644
--- a/arch/sh/mm/Kconfig
+++ b/arch/sh/mm/Kconfig
@@ -190,19 +190,37 @@ config ARCH_MEMORY_PROBE
190 depends on MEMORY_HOTPLUG 190 depends on MEMORY_HOTPLUG
191 191
192choice 192choice
193 prompt "Page table layout"
194 default PGTABLE_LEVELS_3 if X2TLB
195 default PGTABLE_LEVELS_2
196
197config PGTABLE_LEVELS_2
198 bool "2 Levels"
199 help
200 This is the default page table layout for all SuperH CPUs.
201
202config PGTABLE_LEVELS_3
203 bool "3 Levels"
204 depends on X2TLB
205 help
206 This enables a 3 level page table structure.
207
208endchoice
209
210choice
193 prompt "Kernel page size" 211 prompt "Kernel page size"
194 default PAGE_SIZE_8KB if X2TLB 212 default PAGE_SIZE_8KB if X2TLB
195 default PAGE_SIZE_4KB 213 default PAGE_SIZE_4KB
196 214
197config PAGE_SIZE_4KB 215config PAGE_SIZE_4KB
198 bool "4kB" 216 bool "4kB"
199 depends on !MMU || !X2TLB 217 depends on !MMU || !X2TLB || PGTABLE_LEVELS_3
200 help 218 help
201 This is the default page size used by all SuperH CPUs. 219 This is the default page size used by all SuperH CPUs.
202 220
203config PAGE_SIZE_8KB 221config PAGE_SIZE_8KB
204 bool "8kB" 222 bool "8kB"
205 depends on !MMU || X2TLB 223 depends on !MMU || X2TLB && !PGTABLE_LEVELS_3
206 help 224 help
207 This enables 8kB pages as supported by SH-X2 and later MMUs. 225 This enables 8kB pages as supported by SH-X2 and later MMUs.
208 226
@@ -214,7 +232,7 @@ config PAGE_SIZE_16KB
214 232
215config PAGE_SIZE_64KB 233config PAGE_SIZE_64KB
216 bool "64kB" 234 bool "64kB"
217 depends on !MMU || CPU_SH4 || CPU_SH5 235 depends on !MMU || CPU_SH4 && !PGTABLE_LEVELS_3 || CPU_SH5
218 help 236 help
219 This enables support for 64kB pages, possible on all SH-4 237 This enables support for 64kB pages, possible on all SH-4
220 CPUs and later. 238 CPUs and later.
diff --git a/arch/sh/mm/fault_32.c b/arch/sh/mm/fault_32.c
index 47530104e0ad..28e22839c665 100644
--- a/arch/sh/mm/fault_32.c
+++ b/arch/sh/mm/fault_32.c
@@ -53,6 +53,9 @@ static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)
53 if (!pud_present(*pud_k)) 53 if (!pud_present(*pud_k))
54 return NULL; 54 return NULL;
55 55
56 if (!pud_present(*pud))
57 set_pud(pud, *pud_k);
58
56 pmd = pmd_offset(pud, address); 59 pmd = pmd_offset(pud, address);
57 pmd_k = pmd_offset(pud_k, address); 60 pmd_k = pmd_offset(pud_k, address);
58 if (!pmd_present(*pmd_k)) 61 if (!pmd_present(*pmd_k))
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
index 432acd07e76a..761910d142f8 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -120,7 +120,13 @@ void __init page_table_range_init(unsigned long start, unsigned long end,
120 for ( ; (i < PTRS_PER_PGD) && (vaddr != end); pgd++, i++) { 120 for ( ; (i < PTRS_PER_PGD) && (vaddr != end); pgd++, i++) {
121 pud = (pud_t *)pgd; 121 pud = (pud_t *)pgd;
122 for ( ; (j < PTRS_PER_PUD) && (vaddr != end); pud++, j++) { 122 for ( ; (j < PTRS_PER_PUD) && (vaddr != end); pud++, j++) {
123#ifdef __PAGETABLE_PMD_FOLDED
123 pmd = (pmd_t *)pud; 124 pmd = (pmd_t *)pud;
125#else
126 pmd = (pmd_t *)alloc_bootmem_low_pages(PAGE_SIZE);
127 pud_populate(&init_mm, pud, pmd);
128 pmd += k;
129#endif
124 for (; (k < PTRS_PER_PMD) && (vaddr != end); pmd++, k++) { 130 for (; (k < PTRS_PER_PMD) && (vaddr != end); pmd++, k++) {
125 if (pmd_none(*pmd)) { 131 if (pmd_none(*pmd)) {
126 pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); 132 pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);