aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/sparc/include/asm/hugetlb.h1
-rw-r--r--arch/sparc/include/asm/page_64.h4
-rw-r--r--arch/sparc/kernel/tsb.S39
-rw-r--r--arch/sparc/mm/fault_64.c9
-rw-r--r--arch/sparc/mm/init_64.c24
-rw-r--r--arch/sparc/mm/tlb.c11
6 files changed, 72 insertions, 16 deletions
diff --git a/arch/sparc/include/asm/hugetlb.h b/arch/sparc/include/asm/hugetlb.h
index 9661e9bc7bb6..7eb57d245044 100644
--- a/arch/sparc/include/asm/hugetlb.h
+++ b/arch/sparc/include/asm/hugetlb.h
@@ -12,7 +12,6 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
12 12
13static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm) 13static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm)
14{ 14{
15 hugetlb_setup(mm);
16} 15}
17 16
18static inline int is_hugepage_only_range(struct mm_struct *mm, 17static inline int is_hugepage_only_range(struct mm_struct *mm,
diff --git a/arch/sparc/include/asm/page_64.h b/arch/sparc/include/asm/page_64.h
index 4b39f74d6ca0..e15538899f3d 100644
--- a/arch/sparc/include/asm/page_64.h
+++ b/arch/sparc/include/asm/page_64.h
@@ -27,8 +27,8 @@
27#ifndef __ASSEMBLY__ 27#ifndef __ASSEMBLY__
28 28
29#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) 29#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
30struct mm_struct; 30struct pt_regs;
31extern void hugetlb_setup(struct mm_struct *mm); 31extern void hugetlb_setup(struct pt_regs *regs);
32#endif 32#endif
33 33
34#define WANT_PAGE_VIRTUAL 34#define WANT_PAGE_VIRTUAL
diff --git a/arch/sparc/kernel/tsb.S b/arch/sparc/kernel/tsb.S
index d4bdc7a62375..a313e4a9399b 100644
--- a/arch/sparc/kernel/tsb.S
+++ b/arch/sparc/kernel/tsb.S
@@ -136,12 +136,43 @@ tsb_miss_page_table_walk_sun4v_fastpath:
136 nop 136 nop
137 137
138 /* It is a huge page, use huge page TSB entry address we 138 /* It is a huge page, use huge page TSB entry address we
139 * calculated above. 139 * calculated above. If the huge page TSB has not been
140 * allocated, setup a trap stack and call hugetlb_setup()
141 * to do so, then return from the trap to replay the TLB
142 * miss.
143 *
144 * This is necessary to handle the case of transparent huge
145 * pages where we don't really have a non-atomic context
146 * in which to allocate the hugepage TSB hash table. When
147 * the 'mm' faults in the hugepage for the first time, we
148 * thus handle it here. This also makes sure that we can
149 * allocate the TSB hash table on the correct NUMA node.
140 */ 150 */
141 TRAP_LOAD_TRAP_BLOCK(%g7, %g2) 151 TRAP_LOAD_TRAP_BLOCK(%g7, %g2)
142 ldx [%g7 + TRAP_PER_CPU_TSB_HUGE_TEMP], %g2 152 ldx [%g7 + TRAP_PER_CPU_TSB_HUGE_TEMP], %g1
143 cmp %g2, -1 153 cmp %g1, -1
144 movne %xcc, %g2, %g1 154 bne,pt %xcc, 60f
155 nop
156
157661: rdpr %pstate, %g5
158 wrpr %g5, PSTATE_AG | PSTATE_MG, %pstate
159 .section .sun4v_2insn_patch, "ax"
160 .word 661b
161 SET_GL(1)
162 nop
163 .previous
164
165 rdpr %tl, %g3
166 cmp %g3, 1
167 bne,pn %xcc, winfix_trampoline
168 nop
169 ba,pt %xcc, etrap
170 rd %pc, %g7
171 call hugetlb_setup
172 add %sp, PTREGS_OFF, %o0
173 ba,pt %xcc, rtrap
174 nop
175
14560: 17660:
146#endif 177#endif
147 178
diff --git a/arch/sparc/mm/fault_64.c b/arch/sparc/mm/fault_64.c
index 097aee763af3..5062ff389e83 100644
--- a/arch/sparc/mm/fault_64.c
+++ b/arch/sparc/mm/fault_64.c
@@ -472,8 +472,13 @@ good_area:
472#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) 472#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
473 mm_rss = mm->context.huge_pte_count; 473 mm_rss = mm->context.huge_pte_count;
474 if (unlikely(mm_rss > 474 if (unlikely(mm_rss >
475 mm->context.tsb_block[MM_TSB_HUGE].tsb_rss_limit)) 475 mm->context.tsb_block[MM_TSB_HUGE].tsb_rss_limit)) {
476 tsb_grow(mm, MM_TSB_HUGE, mm_rss); 476 if (mm->context.tsb_block[MM_TSB_HUGE].tsb)
477 tsb_grow(mm, MM_TSB_HUGE, mm_rss);
478 else
479 hugetlb_setup(regs);
480
481 }
477#endif 482#endif
478 return; 483 return;
479 484
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c
index 0d0bc392c35f..82bbf048a5b0 100644
--- a/arch/sparc/mm/init_64.c
+++ b/arch/sparc/mm/init_64.c
@@ -2718,14 +2718,28 @@ static void context_reload(void *__data)
2718 load_secondary_context(mm); 2718 load_secondary_context(mm);
2719} 2719}
2720 2720
2721void hugetlb_setup(struct mm_struct *mm) 2721void hugetlb_setup(struct pt_regs *regs)
2722{ 2722{
2723 struct tsb_config *tp = &mm->context.tsb_block[MM_TSB_HUGE]; 2723 struct mm_struct *mm = current->mm;
2724 struct tsb_config *tp;
2724 2725
2725 if (likely(tp->tsb != NULL)) 2726 if (in_atomic() || !mm) {
2726 return; 2727 const struct exception_table_entry *entry;
2728
2729 entry = search_exception_tables(regs->tpc);
2730 if (entry) {
2731 regs->tpc = entry->fixup;
2732 regs->tnpc = regs->tpc + 4;
2733 return;
2734 }
2735 pr_alert("Unexpected HugeTLB setup in atomic context.\n");
2736 die_if_kernel("HugeTSB in atomic", regs);
2737 }
2738
2739 tp = &mm->context.tsb_block[MM_TSB_HUGE];
2740 if (likely(tp->tsb == NULL))
2741 tsb_grow(mm, MM_TSB_HUGE, 0);
2727 2742
2728 tsb_grow(mm, MM_TSB_HUGE, 0);
2729 tsb_context_switch(mm); 2743 tsb_context_switch(mm);
2730 smp_tsb_sync(mm); 2744 smp_tsb_sync(mm);
2731 2745
diff --git a/arch/sparc/mm/tlb.c b/arch/sparc/mm/tlb.c
index 3e8fec391fe0..ba6ae7ffdc2c 100644
--- a/arch/sparc/mm/tlb.c
+++ b/arch/sparc/mm/tlb.c
@@ -135,8 +135,15 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr,
135 mm->context.huge_pte_count++; 135 mm->context.huge_pte_count++;
136 else 136 else
137 mm->context.huge_pte_count--; 137 mm->context.huge_pte_count--;
138 if (mm->context.huge_pte_count == 1) 138
139 hugetlb_setup(mm); 139 /* Do not try to allocate the TSB hash table if we
140 * don't have one already. We have various locks held
141 * and thus we'll end up doing a GFP_KERNEL allocation
142 * in an atomic context.
143 *
144 * Instead, we let the first TLB miss on a hugepage
145 * take care of this.
146 */
140 } 147 }
141 148
142 if (!pmd_none(orig)) { 149 if (!pmd_none(orig)) {