diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-20 17:31:26 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-20 17:31:26 -0500 |
commit | 8ec4942212a6d337982967778a3dc3b60aea782e (patch) | |
tree | 35e58e18bb32969fbf6b7d229323fac144e1b265 | |
parent | 79a69d342d71b2b4eafdf51e2451606cfe380a44 (diff) | |
parent | f9fd3488f6a3c2c5cc8613e4fd7fbbaa57f6bf8f (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc
Pull sparc updates from David Miller:
"Mostly more sparc64 THP bug fixes, and a refactoring of SMP bootup on
sparc32 from Sam Ravnborg."
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc:
sparc32: refactor smp boot
sparc64: Fix huge PMD to PTE translation for sun4u in TLB miss handler.
sparc64: Fix tsb_grow() in atomic context.
sparc64: Handle hugepage TSB being NULL.
sparc64: Fix gfp_flags setting in tsb_grow().
-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/include/asm/tsb.h | 28 | ||||
-rw-r--r-- | arch/sparc/kernel/kernel.h | 12 | ||||
-rw-r--r-- | arch/sparc/kernel/leon_smp.c | 33 | ||||
-rw-r--r-- | arch/sparc/kernel/smp_32.c | 86 | ||||
-rw-r--r-- | arch/sparc/kernel/sun4d_smp.c | 29 | ||||
-rw-r--r-- | arch/sparc/kernel/sun4m_smp.c | 33 | ||||
-rw-r--r-- | arch/sparc/kernel/trampoline_32.S | 17 | ||||
-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 | 62 | ||||
-rw-r--r-- | arch/sparc/mm/tlb.c | 11 | ||||
-rw-r--r-- | arch/sparc/mm/tsb.c | 2 |
14 files changed, 246 insertions, 120 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/include/asm/tsb.h b/arch/sparc/include/asm/tsb.h index b4c258de4443..e696432b950d 100644 --- a/arch/sparc/include/asm/tsb.h +++ b/arch/sparc/include/asm/tsb.h | |||
@@ -157,17 +157,26 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end; | |||
157 | andn REG2, 0x7, REG2; \ | 157 | andn REG2, 0x7, REG2; \ |
158 | add REG1, REG2, REG1; | 158 | add REG1, REG2, REG1; |
159 | 159 | ||
160 | /* This macro exists only to make the PMD translator below easier | 160 | /* These macros exists only to make the PMD translator below |
161 | * to read. It hides the ELF section switch for the sun4v code | 161 | * easier to read. It hides the ELF section switch for the |
162 | * patching. | 162 | * sun4v code patching. |
163 | */ | 163 | */ |
164 | #define OR_PTE_BIT(REG, NAME) \ | 164 | #define OR_PTE_BIT_1INSN(REG, NAME) \ |
165 | 661: or REG, _PAGE_##NAME##_4U, REG; \ | 165 | 661: or REG, _PAGE_##NAME##_4U, REG; \ |
166 | .section .sun4v_1insn_patch, "ax"; \ | 166 | .section .sun4v_1insn_patch, "ax"; \ |
167 | .word 661b; \ | 167 | .word 661b; \ |
168 | or REG, _PAGE_##NAME##_4V, REG; \ | 168 | or REG, _PAGE_##NAME##_4V, REG; \ |
169 | .previous; | 169 | .previous; |
170 | 170 | ||
171 | #define OR_PTE_BIT_2INSN(REG, TMP, NAME) \ | ||
172 | 661: sethi %hi(_PAGE_##NAME##_4U), TMP; \ | ||
173 | or REG, TMP, REG; \ | ||
174 | .section .sun4v_2insn_patch, "ax"; \ | ||
175 | .word 661b; \ | ||
176 | mov -1, TMP; \ | ||
177 | or REG, _PAGE_##NAME##_4V, REG; \ | ||
178 | .previous; | ||
179 | |||
171 | /* Load into REG the PTE value for VALID, CACHE, and SZHUGE. */ | 180 | /* Load into REG the PTE value for VALID, CACHE, and SZHUGE. */ |
172 | #define BUILD_PTE_VALID_SZHUGE_CACHE(REG) \ | 181 | #define BUILD_PTE_VALID_SZHUGE_CACHE(REG) \ |
173 | 661: sethi %uhi(_PAGE_VALID|_PAGE_SZHUGE_4U), REG; \ | 182 | 661: sethi %uhi(_PAGE_VALID|_PAGE_SZHUGE_4U), REG; \ |
@@ -214,12 +223,13 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end; | |||
214 | andn REG1, PMD_HUGE_PROTBITS, REG2; \ | 223 | andn REG1, PMD_HUGE_PROTBITS, REG2; \ |
215 | sllx REG2, PMD_PADDR_SHIFT, REG2; \ | 224 | sllx REG2, PMD_PADDR_SHIFT, REG2; \ |
216 | /* REG2 now holds PFN << PAGE_SHIFT */ \ | 225 | /* REG2 now holds PFN << PAGE_SHIFT */ \ |
217 | andcc REG1, PMD_HUGE_EXEC, %g0; \ | 226 | andcc REG1, PMD_HUGE_WRITE, %g0; \ |
218 | bne,a,pt %xcc, 1f; \ | ||
219 | OR_PTE_BIT(REG2, EXEC); \ | ||
220 | 1: andcc REG1, PMD_HUGE_WRITE, %g0; \ | ||
221 | bne,a,pt %xcc, 1f; \ | 227 | bne,a,pt %xcc, 1f; \ |
222 | OR_PTE_BIT(REG2, W); \ | 228 | OR_PTE_BIT_1INSN(REG2, W); \ |
229 | 1: andcc REG1, PMD_HUGE_EXEC, %g0; \ | ||
230 | be,pt %xcc, 1f; \ | ||
231 | nop; \ | ||
232 | OR_PTE_BIT_2INSN(REG2, REG1, EXEC); \ | ||
223 | /* REG1 can now be clobbered, build final PTE */ \ | 233 | /* REG1 can now be clobbered, build final PTE */ \ |
224 | 1: BUILD_PTE_VALID_SZHUGE_CACHE(REG1); \ | 234 | 1: BUILD_PTE_VALID_SZHUGE_CACHE(REG1); \ |
225 | ba,pt %xcc, PTE_LABEL; \ | 235 | ba,pt %xcc, PTE_LABEL; \ |
diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h index 291bb5de9ce0..a702d9ab019c 100644 --- a/arch/sparc/kernel/kernel.h +++ b/arch/sparc/kernel/kernel.h | |||
@@ -48,6 +48,10 @@ extern void sun4m_init_IRQ(void); | |||
48 | extern void sun4m_unmask_profile_irq(void); | 48 | extern void sun4m_unmask_profile_irq(void); |
49 | extern void sun4m_clear_profile_irq(int cpu); | 49 | extern void sun4m_clear_profile_irq(int cpu); |
50 | 50 | ||
51 | /* sun4m_smp.c */ | ||
52 | void sun4m_cpu_pre_starting(void *arg); | ||
53 | void sun4m_cpu_pre_online(void *arg); | ||
54 | |||
51 | /* sun4d_irq.c */ | 55 | /* sun4d_irq.c */ |
52 | extern spinlock_t sun4d_imsk_lock; | 56 | extern spinlock_t sun4d_imsk_lock; |
53 | 57 | ||
@@ -60,6 +64,14 @@ extern int show_sun4d_interrupts(struct seq_file *, void *); | |||
60 | extern void sun4d_distribute_irqs(void); | 64 | extern void sun4d_distribute_irqs(void); |
61 | extern void sun4d_free_irq(unsigned int irq, void *dev_id); | 65 | extern void sun4d_free_irq(unsigned int irq, void *dev_id); |
62 | 66 | ||
67 | /* sun4d_smp.c */ | ||
68 | void sun4d_cpu_pre_starting(void *arg); | ||
69 | void sun4d_cpu_pre_online(void *arg); | ||
70 | |||
71 | /* leon_smp.c */ | ||
72 | void leon_cpu_pre_starting(void *arg); | ||
73 | void leon_cpu_pre_online(void *arg); | ||
74 | |||
63 | /* head_32.S */ | 75 | /* head_32.S */ |
64 | extern unsigned int t_nmi[]; | 76 | extern unsigned int t_nmi[]; |
65 | extern unsigned int linux_trap_ipi15_sun4d[]; | 77 | extern unsigned int linux_trap_ipi15_sun4d[]; |
diff --git a/arch/sparc/kernel/leon_smp.c b/arch/sparc/kernel/leon_smp.c index 0f3fb6d9c8ef..9b40c9c12a0c 100644 --- a/arch/sparc/kernel/leon_smp.c +++ b/arch/sparc/kernel/leon_smp.c | |||
@@ -69,31 +69,19 @@ static inline unsigned long do_swap(volatile unsigned long *ptr, | |||
69 | return val; | 69 | return val; |
70 | } | 70 | } |
71 | 71 | ||
72 | void __cpuinit leon_callin(void) | 72 | void __cpuinit leon_cpu_pre_starting(void *arg) |
73 | { | 73 | { |
74 | int cpuid = hard_smp_processor_id(); | ||
75 | |||
76 | local_ops->cache_all(); | ||
77 | local_ops->tlb_all(); | ||
78 | leon_configure_cache_smp(); | 74 | leon_configure_cache_smp(); |
75 | } | ||
79 | 76 | ||
80 | notify_cpu_starting(cpuid); | 77 | void __cpuinit leon_cpu_pre_online(void *arg) |
81 | 78 | { | |
82 | /* Get our local ticker going. */ | 79 | int cpuid = hard_smp_processor_id(); |
83 | register_percpu_ce(cpuid); | ||
84 | |||
85 | calibrate_delay(); | ||
86 | smp_store_cpu_info(cpuid); | ||
87 | |||
88 | local_ops->cache_all(); | ||
89 | local_ops->tlb_all(); | ||
90 | 80 | ||
91 | /* | 81 | /* Allow master to continue. The master will then give us the |
92 | * Unblock the master CPU _only_ when the scheduler state | 82 | * go-ahead by setting the smp_commenced_mask and will wait without |
93 | * of all secondary CPUs will be up-to-date, so after | 83 | * timeouts until our setup is completed fully (signified by |
94 | * the SMP initialization the master will be just allowed | 84 | * our bit being set in the cpu_online_mask). |
95 | * to call the scheduler code. | ||
96 | * Allow master to continue. | ||
97 | */ | 85 | */ |
98 | do_swap(&cpu_callin_map[cpuid], 1); | 86 | do_swap(&cpu_callin_map[cpuid], 1); |
99 | 87 | ||
@@ -110,9 +98,6 @@ void __cpuinit leon_callin(void) | |||
110 | 98 | ||
111 | while (!cpumask_test_cpu(cpuid, &smp_commenced_mask)) | 99 | while (!cpumask_test_cpu(cpuid, &smp_commenced_mask)) |
112 | mb(); | 100 | mb(); |
113 | |||
114 | local_irq_enable(); | ||
115 | set_cpu_online(cpuid, true); | ||
116 | } | 101 | } |
117 | 102 | ||
118 | /* | 103 | /* |
diff --git a/arch/sparc/kernel/smp_32.c b/arch/sparc/kernel/smp_32.c index 79db45e5134a..9e7e6d718367 100644 --- a/arch/sparc/kernel/smp_32.c +++ b/arch/sparc/kernel/smp_32.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/seq_file.h> | 20 | #include <linux/seq_file.h> |
21 | #include <linux/cache.h> | 21 | #include <linux/cache.h> |
22 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
23 | #include <linux/cpu.h> | ||
23 | 24 | ||
24 | #include <asm/ptrace.h> | 25 | #include <asm/ptrace.h> |
25 | #include <linux/atomic.h> | 26 | #include <linux/atomic.h> |
@@ -32,8 +33,10 @@ | |||
32 | #include <asm/cacheflush.h> | 33 | #include <asm/cacheflush.h> |
33 | #include <asm/tlbflush.h> | 34 | #include <asm/tlbflush.h> |
34 | #include <asm/cpudata.h> | 35 | #include <asm/cpudata.h> |
36 | #include <asm/timer.h> | ||
35 | #include <asm/leon.h> | 37 | #include <asm/leon.h> |
36 | 38 | ||
39 | #include "kernel.h" | ||
37 | #include "irq.h" | 40 | #include "irq.h" |
38 | 41 | ||
39 | volatile unsigned long cpu_callin_map[NR_CPUS] __cpuinitdata = {0,}; | 42 | volatile unsigned long cpu_callin_map[NR_CPUS] __cpuinitdata = {0,}; |
@@ -294,6 +297,89 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *tidle) | |||
294 | return ret; | 297 | return ret; |
295 | } | 298 | } |
296 | 299 | ||
300 | void __cpuinit arch_cpu_pre_starting(void *arg) | ||
301 | { | ||
302 | local_ops->cache_all(); | ||
303 | local_ops->tlb_all(); | ||
304 | |||
305 | switch(sparc_cpu_model) { | ||
306 | case sun4m: | ||
307 | sun4m_cpu_pre_starting(arg); | ||
308 | break; | ||
309 | case sun4d: | ||
310 | sun4d_cpu_pre_starting(arg); | ||
311 | break; | ||
312 | case sparc_leon: | ||
313 | leon_cpu_pre_starting(arg); | ||
314 | break; | ||
315 | default: | ||
316 | BUG(); | ||
317 | } | ||
318 | } | ||
319 | |||
320 | void __cpuinit arch_cpu_pre_online(void *arg) | ||
321 | { | ||
322 | unsigned int cpuid = hard_smp_processor_id(); | ||
323 | |||
324 | register_percpu_ce(cpuid); | ||
325 | |||
326 | calibrate_delay(); | ||
327 | smp_store_cpu_info(cpuid); | ||
328 | |||
329 | local_ops->cache_all(); | ||
330 | local_ops->tlb_all(); | ||
331 | |||
332 | switch(sparc_cpu_model) { | ||
333 | case sun4m: | ||
334 | sun4m_cpu_pre_online(arg); | ||
335 | break; | ||
336 | case sun4d: | ||
337 | sun4d_cpu_pre_online(arg); | ||
338 | break; | ||
339 | case sparc_leon: | ||
340 | leon_cpu_pre_online(arg); | ||
341 | break; | ||
342 | default: | ||
343 | BUG(); | ||
344 | } | ||
345 | } | ||
346 | |||
347 | void __cpuinit sparc_start_secondary(void *arg) | ||
348 | { | ||
349 | unsigned int cpu; | ||
350 | |||
351 | /* | ||
352 | * SMP booting is extremely fragile in some architectures. So run | ||
353 | * the cpu initialization code first before anything else. | ||
354 | */ | ||
355 | arch_cpu_pre_starting(arg); | ||
356 | |||
357 | preempt_disable(); | ||
358 | cpu = smp_processor_id(); | ||
359 | |||
360 | /* Invoke the CPU_STARTING notifier callbacks */ | ||
361 | notify_cpu_starting(cpu); | ||
362 | |||
363 | arch_cpu_pre_online(arg); | ||
364 | |||
365 | /* Set the CPU in the cpu_online_mask */ | ||
366 | set_cpu_online(cpu, true); | ||
367 | |||
368 | /* Enable local interrupts now */ | ||
369 | local_irq_enable(); | ||
370 | |||
371 | wmb(); | ||
372 | cpu_idle(); | ||
373 | |||
374 | /* We should never reach here! */ | ||
375 | BUG(); | ||
376 | } | ||
377 | |||
378 | void __cpuinit smp_callin(void) | ||
379 | { | ||
380 | sparc_start_secondary(NULL); | ||
381 | } | ||
382 | |||
297 | void smp_bogo(struct seq_file *m) | 383 | void smp_bogo(struct seq_file *m) |
298 | { | 384 | { |
299 | int i; | 385 | int i; |
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c index ddaea31de586..c9eb82f23d92 100644 --- a/arch/sparc/kernel/sun4d_smp.c +++ b/arch/sparc/kernel/sun4d_smp.c | |||
@@ -50,10 +50,9 @@ static inline void show_leds(int cpuid) | |||
50 | "i" (ASI_M_CTL)); | 50 | "i" (ASI_M_CTL)); |
51 | } | 51 | } |
52 | 52 | ||
53 | void __cpuinit smp4d_callin(void) | 53 | void __cpuinit sun4d_cpu_pre_starting(void *arg) |
54 | { | 54 | { |
55 | int cpuid = hard_smp_processor_id(); | 55 | int cpuid = hard_smp_processor_id(); |
56 | unsigned long flags; | ||
57 | 56 | ||
58 | /* Show we are alive */ | 57 | /* Show we are alive */ |
59 | cpu_leds[cpuid] = 0x6; | 58 | cpu_leds[cpuid] = 0x6; |
@@ -61,26 +60,20 @@ void __cpuinit smp4d_callin(void) | |||
61 | 60 | ||
62 | /* Enable level15 interrupt, disable level14 interrupt for now */ | 61 | /* Enable level15 interrupt, disable level14 interrupt for now */ |
63 | cc_set_imsk((cc_get_imsk() & ~0x8000) | 0x4000); | 62 | cc_set_imsk((cc_get_imsk() & ~0x8000) | 0x4000); |
63 | } | ||
64 | 64 | ||
65 | local_ops->cache_all(); | 65 | void __cpuinit sun4d_cpu_pre_online(void *arg) |
66 | local_ops->tlb_all(); | 66 | { |
67 | unsigned long flags; | ||
68 | int cpuid; | ||
67 | 69 | ||
68 | notify_cpu_starting(cpuid); | 70 | cpuid = hard_smp_processor_id(); |
69 | /* | 71 | |
70 | * Unblock the master CPU _only_ when the scheduler state | 72 | /* Unblock the master CPU _only_ when the scheduler state |
71 | * of all secondary CPUs will be up-to-date, so after | 73 | * of all secondary CPUs will be up-to-date, so after |
72 | * the SMP initialization the master will be just allowed | 74 | * the SMP initialization the master will be just allowed |
73 | * to call the scheduler code. | 75 | * to call the scheduler code. |
74 | */ | 76 | */ |
75 | /* Get our local ticker going. */ | ||
76 | register_percpu_ce(cpuid); | ||
77 | |||
78 | calibrate_delay(); | ||
79 | smp_store_cpu_info(cpuid); | ||
80 | local_ops->cache_all(); | ||
81 | local_ops->tlb_all(); | ||
82 | |||
83 | /* Allow master to continue. */ | ||
84 | sun4d_swap((unsigned long *)&cpu_callin_map[cpuid], 1); | 77 | sun4d_swap((unsigned long *)&cpu_callin_map[cpuid], 1); |
85 | local_ops->cache_all(); | 78 | local_ops->cache_all(); |
86 | local_ops->tlb_all(); | 79 | local_ops->tlb_all(); |
@@ -106,16 +99,12 @@ void __cpuinit smp4d_callin(void) | |||
106 | local_ops->cache_all(); | 99 | local_ops->cache_all(); |
107 | local_ops->tlb_all(); | 100 | local_ops->tlb_all(); |
108 | 101 | ||
109 | local_irq_enable(); /* We don't allow PIL 14 yet */ | ||
110 | |||
111 | while (!cpumask_test_cpu(cpuid, &smp_commenced_mask)) | 102 | while (!cpumask_test_cpu(cpuid, &smp_commenced_mask)) |
112 | barrier(); | 103 | barrier(); |
113 | 104 | ||
114 | spin_lock_irqsave(&sun4d_imsk_lock, flags); | 105 | spin_lock_irqsave(&sun4d_imsk_lock, flags); |
115 | cc_set_imsk(cc_get_imsk() & ~0x4000); /* Allow PIL 14 as well */ | 106 | cc_set_imsk(cc_get_imsk() & ~0x4000); /* Allow PIL 14 as well */ |
116 | spin_unlock_irqrestore(&sun4d_imsk_lock, flags); | 107 | spin_unlock_irqrestore(&sun4d_imsk_lock, flags); |
117 | set_cpu_online(cpuid, true); | ||
118 | |||
119 | } | 108 | } |
120 | 109 | ||
121 | /* | 110 | /* |
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c index 128af7304288..8a65f158153d 100644 --- a/arch/sparc/kernel/sun4m_smp.c +++ b/arch/sparc/kernel/sun4m_smp.c | |||
@@ -34,30 +34,19 @@ swap_ulong(volatile unsigned long *ptr, unsigned long val) | |||
34 | return val; | 34 | return val; |
35 | } | 35 | } |
36 | 36 | ||
37 | void __cpuinit smp4m_callin(void) | 37 | void __cpuinit sun4m_cpu_pre_starting(void *arg) |
38 | { | 38 | { |
39 | int cpuid = hard_smp_processor_id(); | 39 | } |
40 | |||
41 | local_ops->cache_all(); | ||
42 | local_ops->tlb_all(); | ||
43 | |||
44 | notify_cpu_starting(cpuid); | ||
45 | |||
46 | register_percpu_ce(cpuid); | ||
47 | |||
48 | calibrate_delay(); | ||
49 | smp_store_cpu_info(cpuid); | ||
50 | 40 | ||
51 | local_ops->cache_all(); | 41 | void __cpuinit sun4m_cpu_pre_online(void *arg) |
52 | local_ops->tlb_all(); | 42 | { |
43 | int cpuid = hard_smp_processor_id(); | ||
53 | 44 | ||
54 | /* | 45 | /* Allow master to continue. The master will then give us the |
55 | * Unblock the master CPU _only_ when the scheduler state | 46 | * go-ahead by setting the smp_commenced_mask and will wait without |
56 | * of all secondary CPUs will be up-to-date, so after | 47 | * timeouts until our setup is completed fully (signified by |
57 | * the SMP initialization the master will be just allowed | 48 | * our bit being set in the cpu_online_mask). |
58 | * to call the scheduler code. | ||
59 | */ | 49 | */ |
60 | /* Allow master to continue. */ | ||
61 | swap_ulong(&cpu_callin_map[cpuid], 1); | 50 | swap_ulong(&cpu_callin_map[cpuid], 1); |
62 | 51 | ||
63 | /* XXX: What's up with all the flushes? */ | 52 | /* XXX: What's up with all the flushes? */ |
@@ -75,10 +64,6 @@ void __cpuinit smp4m_callin(void) | |||
75 | 64 | ||
76 | while (!cpumask_test_cpu(cpuid, &smp_commenced_mask)) | 65 | while (!cpumask_test_cpu(cpuid, &smp_commenced_mask)) |
77 | mb(); | 66 | mb(); |
78 | |||
79 | local_irq_enable(); | ||
80 | |||
81 | set_cpu_online(cpuid, true); | ||
82 | } | 67 | } |
83 | 68 | ||
84 | /* | 69 | /* |
diff --git a/arch/sparc/kernel/trampoline_32.S b/arch/sparc/kernel/trampoline_32.S index af27acab4486..6cdb08cdabf0 100644 --- a/arch/sparc/kernel/trampoline_32.S +++ b/arch/sparc/kernel/trampoline_32.S | |||
@@ -79,18 +79,15 @@ cpu3_startup: | |||
79 | nop | 79 | nop |
80 | 80 | ||
81 | /* Start this processor. */ | 81 | /* Start this processor. */ |
82 | call smp4m_callin | 82 | call smp_callin |
83 | nop | 83 | nop |
84 | 84 | ||
85 | b,a smp_do_cpu_idle | 85 | b,a smp_panic |
86 | 86 | ||
87 | .text | 87 | .text |
88 | .align 4 | 88 | .align 4 |
89 | 89 | ||
90 | smp_do_cpu_idle: | 90 | smp_panic: |
91 | call cpu_idle | ||
92 | mov 0, %o0 | ||
93 | |||
94 | call cpu_panic | 91 | call cpu_panic |
95 | nop | 92 | nop |
96 | 93 | ||
@@ -144,10 +141,10 @@ sun4d_cpu_startup: | |||
144 | nop | 141 | nop |
145 | 142 | ||
146 | /* Start this processor. */ | 143 | /* Start this processor. */ |
147 | call smp4d_callin | 144 | call smp_callin |
148 | nop | 145 | nop |
149 | 146 | ||
150 | b,a smp_do_cpu_idle | 147 | b,a smp_panic |
151 | 148 | ||
152 | __CPUINIT | 149 | __CPUINIT |
153 | .align 4 | 150 | .align 4 |
@@ -201,7 +198,7 @@ leon_smp_cpu_startup: | |||
201 | nop | 198 | nop |
202 | 199 | ||
203 | /* Start this processor. */ | 200 | /* Start this processor. */ |
204 | call leon_callin | 201 | call smp_callin |
205 | nop | 202 | nop |
206 | 203 | ||
207 | b,a smp_do_cpu_idle | 204 | b,a smp_panic |
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 c3b72423c846..82bbf048a5b0 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c | |||
@@ -314,16 +314,31 @@ static void __update_mmu_tsb_insert(struct mm_struct *mm, unsigned long tsb_inde | |||
314 | struct tsb *tsb = mm->context.tsb_block[tsb_index].tsb; | 314 | struct tsb *tsb = mm->context.tsb_block[tsb_index].tsb; |
315 | unsigned long tag; | 315 | unsigned long tag; |
316 | 316 | ||
317 | if (unlikely(!tsb)) | ||
318 | return; | ||
319 | |||
317 | tsb += ((address >> tsb_hash_shift) & | 320 | tsb += ((address >> tsb_hash_shift) & |
318 | (mm->context.tsb_block[tsb_index].tsb_nentries - 1UL)); | 321 | (mm->context.tsb_block[tsb_index].tsb_nentries - 1UL)); |
319 | tag = (address >> 22UL); | 322 | tag = (address >> 22UL); |
320 | tsb_insert(tsb, tag, tte); | 323 | tsb_insert(tsb, tag, tte); |
321 | } | 324 | } |
322 | 325 | ||
326 | #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) | ||
327 | static inline bool is_hugetlb_pte(pte_t pte) | ||
328 | { | ||
329 | if ((tlb_type == hypervisor && | ||
330 | (pte_val(pte) & _PAGE_SZALL_4V) == _PAGE_SZHUGE_4V) || | ||
331 | (tlb_type != hypervisor && | ||
332 | (pte_val(pte) & _PAGE_SZALL_4U) == _PAGE_SZHUGE_4U)) | ||
333 | return true; | ||
334 | return false; | ||
335 | } | ||
336 | #endif | ||
337 | |||
323 | void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) | 338 | void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) |
324 | { | 339 | { |
325 | unsigned long tsb_index, tsb_hash_shift, flags; | ||
326 | struct mm_struct *mm; | 340 | struct mm_struct *mm; |
341 | unsigned long flags; | ||
327 | pte_t pte = *ptep; | 342 | pte_t pte = *ptep; |
328 | 343 | ||
329 | if (tlb_type != hypervisor) { | 344 | if (tlb_type != hypervisor) { |
@@ -335,25 +350,16 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t * | |||
335 | 350 | ||
336 | mm = vma->vm_mm; | 351 | mm = vma->vm_mm; |
337 | 352 | ||
338 | tsb_index = MM_TSB_BASE; | ||
339 | tsb_hash_shift = PAGE_SHIFT; | ||
340 | |||
341 | spin_lock_irqsave(&mm->context.lock, flags); | 353 | spin_lock_irqsave(&mm->context.lock, flags); |
342 | 354 | ||
343 | #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) | 355 | #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) |
344 | if (mm->context.tsb_block[MM_TSB_HUGE].tsb != NULL) { | 356 | if (mm->context.huge_pte_count && is_hugetlb_pte(pte)) |
345 | if ((tlb_type == hypervisor && | 357 | __update_mmu_tsb_insert(mm, MM_TSB_HUGE, HPAGE_SHIFT, |
346 | (pte_val(pte) & _PAGE_SZALL_4V) == _PAGE_SZHUGE_4V) || | 358 | address, pte_val(pte)); |
347 | (tlb_type != hypervisor && | 359 | else |
348 | (pte_val(pte) & _PAGE_SZALL_4U) == _PAGE_SZHUGE_4U)) { | ||
349 | tsb_index = MM_TSB_HUGE; | ||
350 | tsb_hash_shift = HPAGE_SHIFT; | ||
351 | } | ||
352 | } | ||
353 | #endif | 360 | #endif |
354 | 361 | __update_mmu_tsb_insert(mm, MM_TSB_BASE, PAGE_SHIFT, | |
355 | __update_mmu_tsb_insert(mm, tsb_index, tsb_hash_shift, | 362 | address, pte_val(pte)); |
356 | address, pte_val(pte)); | ||
357 | 363 | ||
358 | spin_unlock_irqrestore(&mm->context.lock, flags); | 364 | spin_unlock_irqrestore(&mm->context.lock, flags); |
359 | } | 365 | } |
@@ -2712,14 +2718,28 @@ static void context_reload(void *__data) | |||
2712 | load_secondary_context(mm); | 2718 | load_secondary_context(mm); |
2713 | } | 2719 | } |
2714 | 2720 | ||
2715 | void hugetlb_setup(struct mm_struct *mm) | 2721 | void hugetlb_setup(struct pt_regs *regs) |
2716 | { | 2722 | { |
2717 | struct tsb_config *tp = &mm->context.tsb_block[MM_TSB_HUGE]; | 2723 | struct mm_struct *mm = current->mm; |
2724 | struct tsb_config *tp; | ||
2718 | 2725 | ||
2719 | if (likely(tp->tsb != NULL)) | 2726 | if (in_atomic() || !mm) { |
2720 | 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); | ||
2721 | 2742 | ||
2722 | tsb_grow(mm, MM_TSB_HUGE, 0); | ||
2723 | tsb_context_switch(mm); | 2743 | tsb_context_switch(mm); |
2724 | smp_tsb_sync(mm); | 2744 | smp_tsb_sync(mm); |
2725 | 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)) { |
diff --git a/arch/sparc/mm/tsb.c b/arch/sparc/mm/tsb.c index 7f6474347491..428982b9becf 100644 --- a/arch/sparc/mm/tsb.c +++ b/arch/sparc/mm/tsb.c | |||
@@ -314,7 +314,7 @@ void tsb_grow(struct mm_struct *mm, unsigned long tsb_index, unsigned long rss) | |||
314 | retry_tsb_alloc: | 314 | retry_tsb_alloc: |
315 | gfp_flags = GFP_KERNEL; | 315 | gfp_flags = GFP_KERNEL; |
316 | if (new_size > (PAGE_SIZE * 2)) | 316 | if (new_size > (PAGE_SIZE * 2)) |
317 | gfp_flags = __GFP_NOWARN | __GFP_NORETRY; | 317 | gfp_flags |= __GFP_NOWARN | __GFP_NORETRY; |
318 | 318 | ||
319 | new_tsb = kmem_cache_alloc_node(tsb_caches[new_cache_index], | 319 | new_tsb = kmem_cache_alloc_node(tsb_caches[new_cache_index], |
320 | gfp_flags, numa_node_id()); | 320 | gfp_flags, numa_node_id()); |