diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-22 22:24:13 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-22 22:24:13 -0400 |
commit | 21f9debf74c3ae8fdd26fd2bc3c0169a08eba6b4 (patch) | |
tree | a7e9cdcaf0177bb9606d6e5982937cce55df9898 /arch/sparc | |
parent | bd28b14591b98f696bc9f94c5ba2e598ca487dfd (diff) | |
parent | 24e49ee3d76b70853a96520e46b8837e5eae65b2 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc
Pull sparc updates from David Miller:
"Some 32-bit kgdb cleanups from Sam Ravnborg, and a hugepage TLB flush
overhead fix on 64-bit from Nitin Gupta"
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc:
sparc64: Reduce TLB flushes during hugepte changes
aeroflex/greth: fix warning about unused variable
openprom: fix warning
sparc32: drop superfluous cast in calls to __nocache_pa()
sparc32: fix build with STRICT_MM_TYPECHECKS
sparc32: use proper prototype for trapbase
sparc32: drop local prototype in kgdb_32
sparc32: drop hardcoding trap_level in kgdb_trap
Diffstat (limited to 'arch/sparc')
-rw-r--r-- | arch/sparc/include/asm/head_32.h | 8 | ||||
-rw-r--r-- | arch/sparc/include/asm/kgdb.h | 2 | ||||
-rw-r--r-- | arch/sparc/include/asm/page_32.h | 2 | ||||
-rw-r--r-- | arch/sparc/include/asm/pgalloc_32.h | 4 | ||||
-rw-r--r-- | arch/sparc/include/asm/pgtable_32.h | 2 | ||||
-rw-r--r-- | arch/sparc/include/asm/pgtable_64.h | 43 | ||||
-rw-r--r-- | arch/sparc/include/asm/tlbflush_64.h | 3 | ||||
-rw-r--r-- | arch/sparc/kernel/entry.S | 10 | ||||
-rw-r--r-- | arch/sparc/kernel/kernel.h | 1 | ||||
-rw-r--r-- | arch/sparc/kernel/kgdb_32.c | 11 | ||||
-rw-r--r-- | arch/sparc/kernel/setup_32.c | 4 | ||||
-rw-r--r-- | arch/sparc/mm/hugetlbpage.c | 33 | ||||
-rw-r--r-- | arch/sparc/mm/init_64.c | 12 | ||||
-rw-r--r-- | arch/sparc/mm/io-unit.c | 4 | ||||
-rw-r--r-- | arch/sparc/mm/srmmu.c | 19 | ||||
-rw-r--r-- | arch/sparc/mm/tlb.c | 25 | ||||
-rw-r--r-- | arch/sparc/mm/tsb.c | 32 |
17 files changed, 130 insertions, 85 deletions
diff --git a/arch/sparc/include/asm/head_32.h b/arch/sparc/include/asm/head_32.h index 5f1dbe315bc8..6fc60fd182c4 100644 --- a/arch/sparc/include/asm/head_32.h +++ b/arch/sparc/include/asm/head_32.h | |||
@@ -43,10 +43,10 @@ | |||
43 | nop; | 43 | nop; |
44 | 44 | ||
45 | #ifdef CONFIG_KGDB | 45 | #ifdef CONFIG_KGDB |
46 | #define KGDB_TRAP(num) \ | 46 | #define KGDB_TRAP(num) \ |
47 | b kgdb_trap_low; \ | 47 | mov num, %l7; \ |
48 | rd %psr,%l0; \ | 48 | b kgdb_trap_low; \ |
49 | nop; \ | 49 | rd %psr,%l0; \ |
50 | nop; | 50 | nop; |
51 | #else | 51 | #else |
52 | #define KGDB_TRAP(num) \ | 52 | #define KGDB_TRAP(num) \ |
diff --git a/arch/sparc/include/asm/kgdb.h b/arch/sparc/include/asm/kgdb.h index 47366af7a589..a6ad7bf84bac 100644 --- a/arch/sparc/include/asm/kgdb.h +++ b/arch/sparc/include/asm/kgdb.h | |||
@@ -28,10 +28,10 @@ enum regnames { | |||
28 | #define NUMREGBYTES ((GDB_CSR + 1) * 4) | 28 | #define NUMREGBYTES ((GDB_CSR + 1) * 4) |
29 | #else | 29 | #else |
30 | #define NUMREGBYTES ((GDB_Y + 1) * 8) | 30 | #define NUMREGBYTES ((GDB_Y + 1) * 8) |
31 | #endif | ||
31 | 32 | ||
32 | struct pt_regs; | 33 | struct pt_regs; |
33 | asmlinkage void kgdb_trap(unsigned long trap_level, struct pt_regs *regs); | 34 | asmlinkage void kgdb_trap(unsigned long trap_level, struct pt_regs *regs); |
34 | #endif | ||
35 | 35 | ||
36 | void arch_kgdb_breakpoint(void); | 36 | void arch_kgdb_breakpoint(void); |
37 | 37 | ||
diff --git a/arch/sparc/include/asm/page_32.h b/arch/sparc/include/asm/page_32.h index f82a1f36b655..0efd0583a8c9 100644 --- a/arch/sparc/include/asm/page_32.h +++ b/arch/sparc/include/asm/page_32.h | |||
@@ -69,7 +69,6 @@ typedef struct { unsigned long iopgprot; } iopgprot_t; | |||
69 | 69 | ||
70 | #define __pte(x) ((pte_t) { (x) } ) | 70 | #define __pte(x) ((pte_t) { (x) } ) |
71 | #define __iopte(x) ((iopte_t) { (x) } ) | 71 | #define __iopte(x) ((iopte_t) { (x) } ) |
72 | /* #define __pmd(x) ((pmd_t) { (x) } ) */ /* XXX procedure with loop */ | ||
73 | #define __pgd(x) ((pgd_t) { (x) } ) | 72 | #define __pgd(x) ((pgd_t) { (x) } ) |
74 | #define __ctxd(x) ((ctxd_t) { (x) } ) | 73 | #define __ctxd(x) ((ctxd_t) { (x) } ) |
75 | #define __pgprot(x) ((pgprot_t) { (x) } ) | 74 | #define __pgprot(x) ((pgprot_t) { (x) } ) |
@@ -97,7 +96,6 @@ typedef unsigned long iopgprot_t; | |||
97 | 96 | ||
98 | #define __pte(x) (x) | 97 | #define __pte(x) (x) |
99 | #define __iopte(x) (x) | 98 | #define __iopte(x) (x) |
100 | /* #define __pmd(x) (x) */ /* XXX later */ | ||
101 | #define __pgd(x) (x) | 99 | #define __pgd(x) (x) |
102 | #define __ctxd(x) (x) | 100 | #define __ctxd(x) (x) |
103 | #define __pgprot(x) (x) | 101 | #define __pgprot(x) (x) |
diff --git a/arch/sparc/include/asm/pgalloc_32.h b/arch/sparc/include/asm/pgalloc_32.h index a3890da94428..0346c7e62452 100644 --- a/arch/sparc/include/asm/pgalloc_32.h +++ b/arch/sparc/include/asm/pgalloc_32.h | |||
@@ -29,9 +29,9 @@ static inline void free_pgd_fast(pgd_t *pgd) | |||
29 | 29 | ||
30 | static inline void pgd_set(pgd_t * pgdp, pmd_t * pmdp) | 30 | static inline void pgd_set(pgd_t * pgdp, pmd_t * pmdp) |
31 | { | 31 | { |
32 | unsigned long pa = __nocache_pa((unsigned long)pmdp); | 32 | unsigned long pa = __nocache_pa(pmdp); |
33 | 33 | ||
34 | set_pte((pte_t *)pgdp, (SRMMU_ET_PTD | (pa >> 4))); | 34 | set_pte((pte_t *)pgdp, __pte((SRMMU_ET_PTD | (pa >> 4)))); |
35 | } | 35 | } |
36 | 36 | ||
37 | #define pgd_populate(MM, PGD, PMD) pgd_set(PGD, PMD) | 37 | #define pgd_populate(MM, PGD, PMD) pgd_set(PGD, PMD) |
diff --git a/arch/sparc/include/asm/pgtable_32.h b/arch/sparc/include/asm/pgtable_32.h index 91b963a887b7..ce6f56980aef 100644 --- a/arch/sparc/include/asm/pgtable_32.h +++ b/arch/sparc/include/asm/pgtable_32.h | |||
@@ -298,7 +298,7 @@ static inline pte_t mk_pte_io(unsigned long page, pgprot_t pgprot, int space) | |||
298 | #define pgprot_noncached pgprot_noncached | 298 | #define pgprot_noncached pgprot_noncached |
299 | static inline pgprot_t pgprot_noncached(pgprot_t prot) | 299 | static inline pgprot_t pgprot_noncached(pgprot_t prot) |
300 | { | 300 | { |
301 | prot &= ~__pgprot(SRMMU_CACHE); | 301 | pgprot_val(prot) &= ~pgprot_val(__pgprot(SRMMU_CACHE)); |
302 | return prot; | 302 | return prot; |
303 | } | 303 | } |
304 | 304 | ||
diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h index 93ce0ada3c63..e7d82803a48f 100644 --- a/arch/sparc/include/asm/pgtable_64.h +++ b/arch/sparc/include/asm/pgtable_64.h | |||
@@ -375,7 +375,7 @@ static inline pgprot_t pgprot_noncached(pgprot_t prot) | |||
375 | #define pgprot_noncached pgprot_noncached | 375 | #define pgprot_noncached pgprot_noncached |
376 | 376 | ||
377 | #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) | 377 | #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) |
378 | static inline pte_t pte_mkhuge(pte_t pte) | 378 | static inline unsigned long __pte_huge_mask(void) |
379 | { | 379 | { |
380 | unsigned long mask; | 380 | unsigned long mask; |
381 | 381 | ||
@@ -390,8 +390,19 @@ static inline pte_t pte_mkhuge(pte_t pte) | |||
390 | : "=r" (mask) | 390 | : "=r" (mask) |
391 | : "i" (_PAGE_SZHUGE_4U), "i" (_PAGE_SZHUGE_4V)); | 391 | : "i" (_PAGE_SZHUGE_4U), "i" (_PAGE_SZHUGE_4V)); |
392 | 392 | ||
393 | return __pte(pte_val(pte) | mask); | 393 | return mask; |
394 | } | ||
395 | |||
396 | static inline pte_t pte_mkhuge(pte_t pte) | ||
397 | { | ||
398 | return __pte(pte_val(pte) | __pte_huge_mask()); | ||
399 | } | ||
400 | |||
401 | static inline bool is_hugetlb_pte(pte_t pte) | ||
402 | { | ||
403 | return !!(pte_val(pte) & __pte_huge_mask()); | ||
394 | } | 404 | } |
405 | |||
395 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | 406 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE |
396 | static inline pmd_t pmd_mkhuge(pmd_t pmd) | 407 | static inline pmd_t pmd_mkhuge(pmd_t pmd) |
397 | { | 408 | { |
@@ -403,6 +414,11 @@ static inline pmd_t pmd_mkhuge(pmd_t pmd) | |||
403 | return __pmd(pte_val(pte)); | 414 | return __pmd(pte_val(pte)); |
404 | } | 415 | } |
405 | #endif | 416 | #endif |
417 | #else | ||
418 | static inline bool is_hugetlb_pte(pte_t pte) | ||
419 | { | ||
420 | return false; | ||
421 | } | ||
406 | #endif | 422 | #endif |
407 | 423 | ||
408 | static inline pte_t pte_mkdirty(pte_t pte) | 424 | static inline pte_t pte_mkdirty(pte_t pte) |
@@ -856,6 +872,19 @@ static inline unsigned long pud_pfn(pud_t pud) | |||
856 | void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, | 872 | void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, |
857 | pte_t *ptep, pte_t orig, int fullmm); | 873 | pte_t *ptep, pte_t orig, int fullmm); |
858 | 874 | ||
875 | static void maybe_tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, | ||
876 | pte_t *ptep, pte_t orig, int fullmm) | ||
877 | { | ||
878 | /* It is more efficient to let flush_tlb_kernel_range() | ||
879 | * handle init_mm tlb flushes. | ||
880 | * | ||
881 | * SUN4V NOTE: _PAGE_VALID is the same value in both the SUN4U | ||
882 | * and SUN4V pte layout, so this inline test is fine. | ||
883 | */ | ||
884 | if (likely(mm != &init_mm) && pte_accessible(mm, orig)) | ||
885 | tlb_batch_add(mm, vaddr, ptep, orig, fullmm); | ||
886 | } | ||
887 | |||
859 | #define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR | 888 | #define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR |
860 | static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm, | 889 | static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm, |
861 | unsigned long addr, | 890 | unsigned long addr, |
@@ -872,15 +901,7 @@ static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr, | |||
872 | pte_t orig = *ptep; | 901 | pte_t orig = *ptep; |
873 | 902 | ||
874 | *ptep = pte; | 903 | *ptep = pte; |
875 | 904 | maybe_tlb_batch_add(mm, addr, ptep, orig, fullmm); | |
876 | /* It is more efficient to let flush_tlb_kernel_range() | ||
877 | * handle init_mm tlb flushes. | ||
878 | * | ||
879 | * SUN4V NOTE: _PAGE_VALID is the same value in both the SUN4U | ||
880 | * and SUN4V pte layout, so this inline test is fine. | ||
881 | */ | ||
882 | if (likely(mm != &init_mm) && pte_accessible(mm, orig)) | ||
883 | tlb_batch_add(mm, addr, ptep, orig, fullmm); | ||
884 | } | 905 | } |
885 | 906 | ||
886 | #define set_pte_at(mm,addr,ptep,pte) \ | 907 | #define set_pte_at(mm,addr,ptep,pte) \ |
diff --git a/arch/sparc/include/asm/tlbflush_64.h b/arch/sparc/include/asm/tlbflush_64.h index dea1cfa2122b..a8e192e90700 100644 --- a/arch/sparc/include/asm/tlbflush_64.h +++ b/arch/sparc/include/asm/tlbflush_64.h | |||
@@ -8,6 +8,7 @@ | |||
8 | #define TLB_BATCH_NR 192 | 8 | #define TLB_BATCH_NR 192 |
9 | 9 | ||
10 | struct tlb_batch { | 10 | struct tlb_batch { |
11 | bool huge; | ||
11 | struct mm_struct *mm; | 12 | struct mm_struct *mm; |
12 | unsigned long tlb_nr; | 13 | unsigned long tlb_nr; |
13 | unsigned long active; | 14 | unsigned long active; |
@@ -16,7 +17,7 @@ struct tlb_batch { | |||
16 | 17 | ||
17 | void flush_tsb_kernel_range(unsigned long start, unsigned long end); | 18 | void flush_tsb_kernel_range(unsigned long start, unsigned long end); |
18 | void flush_tsb_user(struct tlb_batch *tb); | 19 | void flush_tsb_user(struct tlb_batch *tb); |
19 | void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr); | 20 | void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr, bool huge); |
20 | 21 | ||
21 | /* TLB flush operations. */ | 22 | /* TLB flush operations. */ |
22 | 23 | ||
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index 51aa6e86a5f8..07918ab3062e 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S | |||
@@ -1225,20 +1225,18 @@ breakpoint_trap: | |||
1225 | RESTORE_ALL | 1225 | RESTORE_ALL |
1226 | 1226 | ||
1227 | #ifdef CONFIG_KGDB | 1227 | #ifdef CONFIG_KGDB |
1228 | .align 4 | 1228 | ENTRY(kgdb_trap_low) |
1229 | .globl kgdb_trap_low | ||
1230 | .type kgdb_trap_low,#function | ||
1231 | kgdb_trap_low: | ||
1232 | rd %wim,%l3 | 1229 | rd %wim,%l3 |
1233 | SAVE_ALL | 1230 | SAVE_ALL |
1234 | wr %l0, PSR_ET, %psr | 1231 | wr %l0, PSR_ET, %psr |
1235 | WRITE_PAUSE | 1232 | WRITE_PAUSE |
1236 | 1233 | ||
1234 | mov %l7, %o0 ! trap_level | ||
1237 | call kgdb_trap | 1235 | call kgdb_trap |
1238 | add %sp, STACKFRAME_SZ, %o0 | 1236 | add %sp, STACKFRAME_SZ, %o1 ! struct pt_regs *regs |
1239 | 1237 | ||
1240 | RESTORE_ALL | 1238 | RESTORE_ALL |
1241 | .size kgdb_trap_low,.-kgdb_trap_low | 1239 | ENDPROC(kgdb_trap_low) |
1242 | #endif | 1240 | #endif |
1243 | 1241 | ||
1244 | .align 4 | 1242 | .align 4 |
diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h index 5057ec2e4af6..c9804551262c 100644 --- a/arch/sparc/kernel/kernel.h +++ b/arch/sparc/kernel/kernel.h | |||
@@ -127,6 +127,7 @@ extern unsigned int t_nmi[]; | |||
127 | extern unsigned int linux_trap_ipi15_sun4d[]; | 127 | extern unsigned int linux_trap_ipi15_sun4d[]; |
128 | extern unsigned int linux_trap_ipi15_sun4m[]; | 128 | extern unsigned int linux_trap_ipi15_sun4m[]; |
129 | 129 | ||
130 | extern struct tt_entry trapbase; | ||
130 | extern struct tt_entry trapbase_cpu1; | 131 | extern struct tt_entry trapbase_cpu1; |
131 | extern struct tt_entry trapbase_cpu2; | 132 | extern struct tt_entry trapbase_cpu2; |
132 | extern struct tt_entry trapbase_cpu3; | 133 | extern struct tt_entry trapbase_cpu3; |
diff --git a/arch/sparc/kernel/kgdb_32.c b/arch/sparc/kernel/kgdb_32.c index dcf210811af4..6e8e318c57be 100644 --- a/arch/sparc/kernel/kgdb_32.c +++ b/arch/sparc/kernel/kgdb_32.c | |||
@@ -12,7 +12,8 @@ | |||
12 | #include <asm/irq.h> | 12 | #include <asm/irq.h> |
13 | #include <asm/cacheflush.h> | 13 | #include <asm/cacheflush.h> |
14 | 14 | ||
15 | extern unsigned long trapbase; | 15 | #include "kernel.h" |
16 | #include "entry.h" | ||
16 | 17 | ||
17 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | 18 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) |
18 | { | 19 | { |
@@ -133,21 +134,19 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, | |||
133 | return -1; | 134 | return -1; |
134 | } | 135 | } |
135 | 136 | ||
136 | extern void do_hw_interrupt(struct pt_regs *regs, unsigned long type); | 137 | asmlinkage void kgdb_trap(unsigned long trap_level, struct pt_regs *regs) |
137 | |||
138 | asmlinkage void kgdb_trap(struct pt_regs *regs) | ||
139 | { | 138 | { |
140 | unsigned long flags; | 139 | unsigned long flags; |
141 | 140 | ||
142 | if (user_mode(regs)) { | 141 | if (user_mode(regs)) { |
143 | do_hw_interrupt(regs, 0xfd); | 142 | do_hw_interrupt(regs, trap_level); |
144 | return; | 143 | return; |
145 | } | 144 | } |
146 | 145 | ||
147 | flushw_all(); | 146 | flushw_all(); |
148 | 147 | ||
149 | local_irq_save(flags); | 148 | local_irq_save(flags); |
150 | kgdb_handle_exception(0x172, SIGTRAP, 0, regs); | 149 | kgdb_handle_exception(trap_level, SIGTRAP, 0, regs); |
151 | local_irq_restore(flags); | 150 | local_irq_restore(flags); |
152 | } | 151 | } |
153 | 152 | ||
diff --git a/arch/sparc/kernel/setup_32.c b/arch/sparc/kernel/setup_32.c index 69d75ff1c25c..c4e65cb3280f 100644 --- a/arch/sparc/kernel/setup_32.c +++ b/arch/sparc/kernel/setup_32.c | |||
@@ -68,8 +68,6 @@ struct screen_info screen_info = { | |||
68 | * prints out pretty messages and returns. | 68 | * prints out pretty messages and returns. |
69 | */ | 69 | */ |
70 | 70 | ||
71 | extern unsigned long trapbase; | ||
72 | |||
73 | /* Pretty sick eh? */ | 71 | /* Pretty sick eh? */ |
74 | static void prom_sync_me(void) | 72 | static void prom_sync_me(void) |
75 | { | 73 | { |
@@ -300,7 +298,7 @@ void __init setup_arch(char **cmdline_p) | |||
300 | int i; | 298 | int i; |
301 | unsigned long highest_paddr; | 299 | unsigned long highest_paddr; |
302 | 300 | ||
303 | sparc_ttable = (struct tt_entry *) &trapbase; | 301 | sparc_ttable = &trapbase; |
304 | 302 | ||
305 | /* Initialize PROM console and command line. */ | 303 | /* Initialize PROM console and command line. */ |
306 | *cmdline_p = prom_getbootargs(); | 304 | *cmdline_p = prom_getbootargs(); |
diff --git a/arch/sparc/mm/hugetlbpage.c b/arch/sparc/mm/hugetlbpage.c index 4977800e9770..ba52e6466a82 100644 --- a/arch/sparc/mm/hugetlbpage.c +++ b/arch/sparc/mm/hugetlbpage.c | |||
@@ -176,17 +176,31 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, | |||
176 | pte_t *ptep, pte_t entry) | 176 | pte_t *ptep, pte_t entry) |
177 | { | 177 | { |
178 | int i; | 178 | int i; |
179 | pte_t orig[2]; | ||
180 | unsigned long nptes; | ||
179 | 181 | ||
180 | if (!pte_present(*ptep) && pte_present(entry)) | 182 | if (!pte_present(*ptep) && pte_present(entry)) |
181 | mm->context.huge_pte_count++; | 183 | mm->context.huge_pte_count++; |
182 | 184 | ||
183 | addr &= HPAGE_MASK; | 185 | addr &= HPAGE_MASK; |
184 | for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) { | 186 | |
185 | set_pte_at(mm, addr, ptep, entry); | 187 | nptes = 1 << HUGETLB_PAGE_ORDER; |
188 | orig[0] = *ptep; | ||
189 | orig[1] = *(ptep + nptes / 2); | ||
190 | for (i = 0; i < nptes; i++) { | ||
191 | *ptep = entry; | ||
186 | ptep++; | 192 | ptep++; |
187 | addr += PAGE_SIZE; | 193 | addr += PAGE_SIZE; |
188 | pte_val(entry) += PAGE_SIZE; | 194 | pte_val(entry) += PAGE_SIZE; |
189 | } | 195 | } |
196 | |||
197 | /* Issue TLB flush at REAL_HPAGE_SIZE boundaries */ | ||
198 | addr -= REAL_HPAGE_SIZE; | ||
199 | ptep -= nptes / 2; | ||
200 | maybe_tlb_batch_add(mm, addr, ptep, orig[1], 0); | ||
201 | addr -= REAL_HPAGE_SIZE; | ||
202 | ptep -= nptes / 2; | ||
203 | maybe_tlb_batch_add(mm, addr, ptep, orig[0], 0); | ||
190 | } | 204 | } |
191 | 205 | ||
192 | pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, | 206 | pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, |
@@ -194,19 +208,28 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, | |||
194 | { | 208 | { |
195 | pte_t entry; | 209 | pte_t entry; |
196 | int i; | 210 | int i; |
211 | unsigned long nptes; | ||
197 | 212 | ||
198 | entry = *ptep; | 213 | entry = *ptep; |
199 | if (pte_present(entry)) | 214 | if (pte_present(entry)) |
200 | mm->context.huge_pte_count--; | 215 | mm->context.huge_pte_count--; |
201 | 216 | ||
202 | addr &= HPAGE_MASK; | 217 | addr &= HPAGE_MASK; |
203 | 218 | nptes = 1 << HUGETLB_PAGE_ORDER; | |
204 | for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) { | 219 | for (i = 0; i < nptes; i++) { |
205 | pte_clear(mm, addr, ptep); | 220 | *ptep = __pte(0UL); |
206 | addr += PAGE_SIZE; | 221 | addr += PAGE_SIZE; |
207 | ptep++; | 222 | ptep++; |
208 | } | 223 | } |
209 | 224 | ||
225 | /* Issue TLB flush at REAL_HPAGE_SIZE boundaries */ | ||
226 | addr -= REAL_HPAGE_SIZE; | ||
227 | ptep -= nptes / 2; | ||
228 | maybe_tlb_batch_add(mm, addr, ptep, entry, 0); | ||
229 | addr -= REAL_HPAGE_SIZE; | ||
230 | ptep -= nptes / 2; | ||
231 | maybe_tlb_batch_add(mm, addr, ptep, entry, 0); | ||
232 | |||
210 | return entry; | 233 | return entry; |
211 | } | 234 | } |
212 | 235 | ||
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index 09e838801e39..652683cb4b4b 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c | |||
@@ -324,18 +324,6 @@ static void __update_mmu_tsb_insert(struct mm_struct *mm, unsigned long tsb_inde | |||
324 | tsb_insert(tsb, tag, tte); | 324 | tsb_insert(tsb, tag, tte); |
325 | } | 325 | } |
326 | 326 | ||
327 | #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) | ||
328 | static inline bool is_hugetlb_pte(pte_t pte) | ||
329 | { | ||
330 | if ((tlb_type == hypervisor && | ||
331 | (pte_val(pte) & _PAGE_SZALL_4V) == _PAGE_SZHUGE_4V) || | ||
332 | (tlb_type != hypervisor && | ||
333 | (pte_val(pte) & _PAGE_SZALL_4U) == _PAGE_SZHUGE_4U)) | ||
334 | return true; | ||
335 | return false; | ||
336 | } | ||
337 | #endif | ||
338 | |||
339 | void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) | 327 | void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) |
340 | { | 328 | { |
341 | struct mm_struct *mm; | 329 | struct mm_struct *mm; |
diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c index f311bf219016..338fb71535de 100644 --- a/arch/sparc/mm/io-unit.c +++ b/arch/sparc/mm/io-unit.c | |||
@@ -133,7 +133,7 @@ nexti: scan = find_next_zero_bit(iounit->bmap, limit, scan); | |||
133 | vaddr = IOUNIT_DMA_BASE + (scan << PAGE_SHIFT) + (vaddr & ~PAGE_MASK); | 133 | vaddr = IOUNIT_DMA_BASE + (scan << PAGE_SHIFT) + (vaddr & ~PAGE_MASK); |
134 | for (k = 0; k < npages; k++, iopte = __iopte(iopte_val(iopte) + 0x100), scan++) { | 134 | for (k = 0; k < npages; k++, iopte = __iopte(iopte_val(iopte) + 0x100), scan++) { |
135 | set_bit(scan, iounit->bmap); | 135 | set_bit(scan, iounit->bmap); |
136 | sbus_writel(iopte, &iounit->page_table[scan]); | 136 | sbus_writel(iopte_val(iopte), &iounit->page_table[scan]); |
137 | } | 137 | } |
138 | IOD(("%08lx\n", vaddr)); | 138 | IOD(("%08lx\n", vaddr)); |
139 | return vaddr; | 139 | return vaddr; |
@@ -228,7 +228,7 @@ static int iounit_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned lon | |||
228 | i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT); | 228 | i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT); |
229 | 229 | ||
230 | iopte = iounit->page_table + i; | 230 | iopte = iounit->page_table + i; |
231 | sbus_writel(MKIOPTE(__pa(page)), iopte); | 231 | sbus_writel(iopte_val(MKIOPTE(__pa(page))), iopte); |
232 | } | 232 | } |
233 | addr += PAGE_SIZE; | 233 | addr += PAGE_SIZE; |
234 | va += PAGE_SIZE; | 234 | va += PAGE_SIZE; |
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index 5cbc96d801ff..c7f2a5295b3a 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c | |||
@@ -107,17 +107,22 @@ static inline int srmmu_pmd_none(pmd_t pmd) | |||
107 | 107 | ||
108 | /* XXX should we hyper_flush_whole_icache here - Anton */ | 108 | /* XXX should we hyper_flush_whole_icache here - Anton */ |
109 | static inline void srmmu_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp) | 109 | static inline void srmmu_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp) |
110 | { set_pte((pte_t *)ctxp, (SRMMU_ET_PTD | (__nocache_pa((unsigned long) pgdp) >> 4))); } | 110 | { |
111 | pte_t pte; | ||
112 | |||
113 | pte = __pte((SRMMU_ET_PTD | (__nocache_pa(pgdp) >> 4))); | ||
114 | set_pte((pte_t *)ctxp, pte); | ||
115 | } | ||
111 | 116 | ||
112 | void pmd_set(pmd_t *pmdp, pte_t *ptep) | 117 | void pmd_set(pmd_t *pmdp, pte_t *ptep) |
113 | { | 118 | { |
114 | unsigned long ptp; /* Physical address, shifted right by 4 */ | 119 | unsigned long ptp; /* Physical address, shifted right by 4 */ |
115 | int i; | 120 | int i; |
116 | 121 | ||
117 | ptp = __nocache_pa((unsigned long) ptep) >> 4; | 122 | ptp = __nocache_pa(ptep) >> 4; |
118 | for (i = 0; i < PTRS_PER_PTE/SRMMU_REAL_PTRS_PER_PTE; i++) { | 123 | for (i = 0; i < PTRS_PER_PTE/SRMMU_REAL_PTRS_PER_PTE; i++) { |
119 | set_pte((pte_t *)&pmdp->pmdv[i], SRMMU_ET_PTD | ptp); | 124 | set_pte((pte_t *)&pmdp->pmdv[i], __pte(SRMMU_ET_PTD | ptp)); |
120 | ptp += (SRMMU_REAL_PTRS_PER_PTE*sizeof(pte_t) >> 4); | 125 | ptp += (SRMMU_REAL_PTRS_PER_PTE * sizeof(pte_t) >> 4); |
121 | } | 126 | } |
122 | } | 127 | } |
123 | 128 | ||
@@ -128,8 +133,8 @@ void pmd_populate(struct mm_struct *mm, pmd_t *pmdp, struct page *ptep) | |||
128 | 133 | ||
129 | ptp = page_to_pfn(ptep) << (PAGE_SHIFT-4); /* watch for overflow */ | 134 | ptp = page_to_pfn(ptep) << (PAGE_SHIFT-4); /* watch for overflow */ |
130 | for (i = 0; i < PTRS_PER_PTE/SRMMU_REAL_PTRS_PER_PTE; i++) { | 135 | for (i = 0; i < PTRS_PER_PTE/SRMMU_REAL_PTRS_PER_PTE; i++) { |
131 | set_pte((pte_t *)&pmdp->pmdv[i], SRMMU_ET_PTD | ptp); | 136 | set_pte((pte_t *)&pmdp->pmdv[i], __pte(SRMMU_ET_PTD | ptp)); |
132 | ptp += (SRMMU_REAL_PTRS_PER_PTE*sizeof(pte_t) >> 4); | 137 | ptp += (SRMMU_REAL_PTRS_PER_PTE * sizeof(pte_t) >> 4); |
133 | } | 138 | } |
134 | } | 139 | } |
135 | 140 | ||
@@ -911,7 +916,7 @@ void __init srmmu_paging_init(void) | |||
911 | 916 | ||
912 | /* ctx table has to be physically aligned to its size */ | 917 | /* ctx table has to be physically aligned to its size */ |
913 | srmmu_context_table = __srmmu_get_nocache(num_contexts * sizeof(ctxd_t), num_contexts * sizeof(ctxd_t)); | 918 | srmmu_context_table = __srmmu_get_nocache(num_contexts * sizeof(ctxd_t), num_contexts * sizeof(ctxd_t)); |
914 | srmmu_ctx_table_phys = (ctxd_t *)__nocache_pa((unsigned long)srmmu_context_table); | 919 | srmmu_ctx_table_phys = (ctxd_t *)__nocache_pa(srmmu_context_table); |
915 | 920 | ||
916 | for (i = 0; i < num_contexts; i++) | 921 | for (i = 0; i < num_contexts; i++) |
917 | srmmu_ctxd_set((ctxd_t *)__nocache_fix(&srmmu_context_table[i]), srmmu_swapper_pg_dir); | 922 | srmmu_ctxd_set((ctxd_t *)__nocache_fix(&srmmu_context_table[i]), srmmu_swapper_pg_dir); |
diff --git a/arch/sparc/mm/tlb.c b/arch/sparc/mm/tlb.c index 9df2190c097e..f81cd9736700 100644 --- a/arch/sparc/mm/tlb.c +++ b/arch/sparc/mm/tlb.c | |||
@@ -67,7 +67,7 @@ void arch_leave_lazy_mmu_mode(void) | |||
67 | } | 67 | } |
68 | 68 | ||
69 | static void tlb_batch_add_one(struct mm_struct *mm, unsigned long vaddr, | 69 | static void tlb_batch_add_one(struct mm_struct *mm, unsigned long vaddr, |
70 | bool exec) | 70 | bool exec, bool huge) |
71 | { | 71 | { |
72 | struct tlb_batch *tb = &get_cpu_var(tlb_batch); | 72 | struct tlb_batch *tb = &get_cpu_var(tlb_batch); |
73 | unsigned long nr; | 73 | unsigned long nr; |
@@ -84,13 +84,21 @@ static void tlb_batch_add_one(struct mm_struct *mm, unsigned long vaddr, | |||
84 | } | 84 | } |
85 | 85 | ||
86 | if (!tb->active) { | 86 | if (!tb->active) { |
87 | flush_tsb_user_page(mm, vaddr); | 87 | flush_tsb_user_page(mm, vaddr, huge); |
88 | global_flush_tlb_page(mm, vaddr); | 88 | global_flush_tlb_page(mm, vaddr); |
89 | goto out; | 89 | goto out; |
90 | } | 90 | } |
91 | 91 | ||
92 | if (nr == 0) | 92 | if (nr == 0) { |
93 | tb->mm = mm; | 93 | tb->mm = mm; |
94 | tb->huge = huge; | ||
95 | } | ||
96 | |||
97 | if (tb->huge != huge) { | ||
98 | flush_tlb_pending(); | ||
99 | tb->huge = huge; | ||
100 | nr = 0; | ||
101 | } | ||
94 | 102 | ||
95 | tb->vaddrs[nr] = vaddr; | 103 | tb->vaddrs[nr] = vaddr; |
96 | tb->tlb_nr = ++nr; | 104 | tb->tlb_nr = ++nr; |
@@ -104,6 +112,8 @@ out: | |||
104 | void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, | 112 | void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, |
105 | pte_t *ptep, pte_t orig, int fullmm) | 113 | pte_t *ptep, pte_t orig, int fullmm) |
106 | { | 114 | { |
115 | bool huge = is_hugetlb_pte(orig); | ||
116 | |||
107 | if (tlb_type != hypervisor && | 117 | if (tlb_type != hypervisor && |
108 | pte_dirty(orig)) { | 118 | pte_dirty(orig)) { |
109 | unsigned long paddr, pfn = pte_pfn(orig); | 119 | unsigned long paddr, pfn = pte_pfn(orig); |
@@ -129,7 +139,7 @@ void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, | |||
129 | 139 | ||
130 | no_cache_flush: | 140 | no_cache_flush: |
131 | if (!fullmm) | 141 | if (!fullmm) |
132 | tlb_batch_add_one(mm, vaddr, pte_exec(orig)); | 142 | tlb_batch_add_one(mm, vaddr, pte_exec(orig), huge); |
133 | } | 143 | } |
134 | 144 | ||
135 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | 145 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE |
@@ -145,7 +155,7 @@ static void tlb_batch_pmd_scan(struct mm_struct *mm, unsigned long vaddr, | |||
145 | if (pte_val(*pte) & _PAGE_VALID) { | 155 | if (pte_val(*pte) & _PAGE_VALID) { |
146 | bool exec = pte_exec(*pte); | 156 | bool exec = pte_exec(*pte); |
147 | 157 | ||
148 | tlb_batch_add_one(mm, vaddr, exec); | 158 | tlb_batch_add_one(mm, vaddr, exec, false); |
149 | } | 159 | } |
150 | pte++; | 160 | pte++; |
151 | vaddr += PAGE_SIZE; | 161 | vaddr += PAGE_SIZE; |
@@ -185,8 +195,9 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr, | |||
185 | pte_t orig_pte = __pte(pmd_val(orig)); | 195 | pte_t orig_pte = __pte(pmd_val(orig)); |
186 | bool exec = pte_exec(orig_pte); | 196 | bool exec = pte_exec(orig_pte); |
187 | 197 | ||
188 | tlb_batch_add_one(mm, addr, exec); | 198 | tlb_batch_add_one(mm, addr, exec, true); |
189 | tlb_batch_add_one(mm, addr + REAL_HPAGE_SIZE, exec); | 199 | tlb_batch_add_one(mm, addr + REAL_HPAGE_SIZE, exec, |
200 | true); | ||
190 | } else { | 201 | } else { |
191 | tlb_batch_pmd_scan(mm, addr, orig); | 202 | tlb_batch_pmd_scan(mm, addr, orig); |
192 | } | 203 | } |
diff --git a/arch/sparc/mm/tsb.c b/arch/sparc/mm/tsb.c index a06576683c38..a0604a493a36 100644 --- a/arch/sparc/mm/tsb.c +++ b/arch/sparc/mm/tsb.c | |||
@@ -76,14 +76,15 @@ void flush_tsb_user(struct tlb_batch *tb) | |||
76 | 76 | ||
77 | spin_lock_irqsave(&mm->context.lock, flags); | 77 | spin_lock_irqsave(&mm->context.lock, flags); |
78 | 78 | ||
79 | base = (unsigned long) mm->context.tsb_block[MM_TSB_BASE].tsb; | 79 | if (!tb->huge) { |
80 | nentries = mm->context.tsb_block[MM_TSB_BASE].tsb_nentries; | 80 | base = (unsigned long) mm->context.tsb_block[MM_TSB_BASE].tsb; |
81 | if (tlb_type == cheetah_plus || tlb_type == hypervisor) | 81 | nentries = mm->context.tsb_block[MM_TSB_BASE].tsb_nentries; |
82 | base = __pa(base); | 82 | if (tlb_type == cheetah_plus || tlb_type == hypervisor) |
83 | __flush_tsb_one(tb, PAGE_SHIFT, base, nentries); | 83 | base = __pa(base); |
84 | 84 | __flush_tsb_one(tb, PAGE_SHIFT, base, nentries); | |
85 | } | ||
85 | #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) | 86 | #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) |
86 | if (mm->context.tsb_block[MM_TSB_HUGE].tsb) { | 87 | if (tb->huge && mm->context.tsb_block[MM_TSB_HUGE].tsb) { |
87 | base = (unsigned long) mm->context.tsb_block[MM_TSB_HUGE].tsb; | 88 | base = (unsigned long) mm->context.tsb_block[MM_TSB_HUGE].tsb; |
88 | nentries = mm->context.tsb_block[MM_TSB_HUGE].tsb_nentries; | 89 | nentries = mm->context.tsb_block[MM_TSB_HUGE].tsb_nentries; |
89 | if (tlb_type == cheetah_plus || tlb_type == hypervisor) | 90 | if (tlb_type == cheetah_plus || tlb_type == hypervisor) |
@@ -94,20 +95,21 @@ void flush_tsb_user(struct tlb_batch *tb) | |||
94 | spin_unlock_irqrestore(&mm->context.lock, flags); | 95 | spin_unlock_irqrestore(&mm->context.lock, flags); |
95 | } | 96 | } |
96 | 97 | ||
97 | void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr) | 98 | void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr, bool huge) |
98 | { | 99 | { |
99 | unsigned long nentries, base, flags; | 100 | unsigned long nentries, base, flags; |
100 | 101 | ||
101 | spin_lock_irqsave(&mm->context.lock, flags); | 102 | spin_lock_irqsave(&mm->context.lock, flags); |
102 | 103 | ||
103 | base = (unsigned long) mm->context.tsb_block[MM_TSB_BASE].tsb; | 104 | if (!huge) { |
104 | nentries = mm->context.tsb_block[MM_TSB_BASE].tsb_nentries; | 105 | base = (unsigned long) mm->context.tsb_block[MM_TSB_BASE].tsb; |
105 | if (tlb_type == cheetah_plus || tlb_type == hypervisor) | 106 | nentries = mm->context.tsb_block[MM_TSB_BASE].tsb_nentries; |
106 | base = __pa(base); | 107 | if (tlb_type == cheetah_plus || tlb_type == hypervisor) |
107 | __flush_tsb_one_entry(base, vaddr, PAGE_SHIFT, nentries); | 108 | base = __pa(base); |
108 | 109 | __flush_tsb_one_entry(base, vaddr, PAGE_SHIFT, nentries); | |
110 | } | ||
109 | #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) | 111 | #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) |
110 | if (mm->context.tsb_block[MM_TSB_HUGE].tsb) { | 112 | if (huge && mm->context.tsb_block[MM_TSB_HUGE].tsb) { |
111 | base = (unsigned long) mm->context.tsb_block[MM_TSB_HUGE].tsb; | 113 | base = (unsigned long) mm->context.tsb_block[MM_TSB_HUGE].tsb; |
112 | nentries = mm->context.tsb_block[MM_TSB_HUGE].tsb_nentries; | 114 | nentries = mm->context.tsb_block[MM_TSB_HUGE].tsb_nentries; |
113 | if (tlb_type == cheetah_plus || tlb_type == hypervisor) | 115 | if (tlb_type == cheetah_plus || tlb_type == hypervisor) |