diff options
-rw-r--r-- | arch/sparc/include/asm/hugetlb.h | 1 | ||||
-rw-r--r-- | arch/sparc/include/asm/page_64.h | 4 | ||||
-rw-r--r-- | arch/sparc/kernel/tsb.S | 39 | ||||
-rw-r--r-- | arch/sparc/mm/fault_64.c | 9 | ||||
-rw-r--r-- | arch/sparc/mm/init_64.c | 24 | ||||
-rw-r--r-- | arch/sparc/mm/tlb.c | 11 |
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 | ||
13 | static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm) | 13 | static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm) |
14 | { | 14 | { |
15 | hugetlb_setup(mm); | ||
16 | } | 15 | } |
17 | 16 | ||
18 | static inline int is_hugepage_only_range(struct mm_struct *mm, | 17 | static 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) |
30 | struct mm_struct; | 30 | struct pt_regs; |
31 | extern void hugetlb_setup(struct mm_struct *mm); | 31 | extern 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 | |||
157 | 661: 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 | |||
145 | 60: | 176 | 60: |
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 | ||
2721 | void hugetlb_setup(struct mm_struct *mm) | 2721 | void 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)) { |