aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/smp-bmips.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel/smp-bmips.c')
-rw-r--r--arch/mips/kernel/smp-bmips.c114
1 files changed, 73 insertions, 41 deletions
diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c
index 06bb5ed6d80a..b8bd9340c9c7 100644
--- a/arch/mips/kernel/smp-bmips.c
+++ b/arch/mips/kernel/smp-bmips.c
@@ -35,6 +35,7 @@
35#include <asm/bmips.h> 35#include <asm/bmips.h>
36#include <asm/traps.h> 36#include <asm/traps.h>
37#include <asm/barrier.h> 37#include <asm/barrier.h>
38#include <asm/cpu-features.h>
38 39
39static int __maybe_unused max_cpus = 1; 40static int __maybe_unused max_cpus = 1;
40 41
@@ -42,6 +43,12 @@ static int __maybe_unused max_cpus = 1;
42int bmips_smp_enabled = 1; 43int bmips_smp_enabled = 1;
43int bmips_cpu_offset; 44int bmips_cpu_offset;
44cpumask_t bmips_booted_mask; 45cpumask_t bmips_booted_mask;
46unsigned long bmips_tp1_irqs = IE_IRQ1;
47
48#define RESET_FROM_KSEG0 0x80080800
49#define RESET_FROM_KSEG1 0xa0080800
50
51static void bmips_set_reset_vec(int cpu, u32 val);
45 52
46#ifdef CONFIG_SMP 53#ifdef CONFIG_SMP
47 54
@@ -194,6 +201,9 @@ static void bmips_boot_secondary(int cpu, struct task_struct *idle)
194 pr_info("SMP: Booting CPU%d...\n", cpu); 201 pr_info("SMP: Booting CPU%d...\n", cpu);
195 202
196 if (cpumask_test_cpu(cpu, &bmips_booted_mask)) { 203 if (cpumask_test_cpu(cpu, &bmips_booted_mask)) {
204 /* kseg1 might not exist if this CPU enabled XKS01 */
205 bmips_set_reset_vec(cpu, RESET_FROM_KSEG0);
206
197 switch (current_cpu_type()) { 207 switch (current_cpu_type()) {
198 case CPU_BMIPS4350: 208 case CPU_BMIPS4350:
199 case CPU_BMIPS4380: 209 case CPU_BMIPS4380:
@@ -203,8 +213,9 @@ static void bmips_boot_secondary(int cpu, struct task_struct *idle)
203 bmips5000_send_ipi_single(cpu, 0); 213 bmips5000_send_ipi_single(cpu, 0);
204 break; 214 break;
205 } 215 }
206 } 216 } else {
207 else { 217 bmips_set_reset_vec(cpu, RESET_FROM_KSEG1);
218
208 switch (current_cpu_type()) { 219 switch (current_cpu_type()) {
209 case CPU_BMIPS4350: 220 case CPU_BMIPS4350:
210 case CPU_BMIPS4380: 221 case CPU_BMIPS4380:
@@ -213,17 +224,7 @@ static void bmips_boot_secondary(int cpu, struct task_struct *idle)
213 set_c0_brcm_cmt_ctrl(0x01); 224 set_c0_brcm_cmt_ctrl(0x01);
214 break; 225 break;
215 case CPU_BMIPS5000: 226 case CPU_BMIPS5000:
216 if (cpu & 0x01) 227 write_c0_brcm_action(ACTION_BOOT_THREAD(cpu));
217 write_c0_brcm_action(ACTION_BOOT_THREAD(cpu));
218 else {
219 /*
220 * core N thread 0 was already booted; just
221 * pulse the NMI line
222 */
223 bmips_write_zscm_reg(0x210, 0xc0000000);
224 udelay(10);
225 bmips_write_zscm_reg(0x210, 0x00);
226 }
227 break; 228 break;
228 } 229 }
229 cpumask_set_cpu(cpu, &bmips_booted_mask); 230 cpumask_set_cpu(cpu, &bmips_booted_mask);
@@ -235,31 +236,12 @@ static void bmips_boot_secondary(int cpu, struct task_struct *idle)
235 */ 236 */
236static void bmips_init_secondary(void) 237static void bmips_init_secondary(void)
237{ 238{
238 /* move NMI vector to kseg0, in case XKS01 is enabled */
239
240 void __iomem *cbr;
241 unsigned long old_vec;
242 unsigned long relo_vector;
243 int boot_cpu;
244
245 switch (current_cpu_type()) { 239 switch (current_cpu_type()) {
246 case CPU_BMIPS4350: 240 case CPU_BMIPS4350:
247 case CPU_BMIPS4380: 241 case CPU_BMIPS4380:
248 cbr = BMIPS_GET_CBR();
249
250 boot_cpu = !!(read_c0_brcm_cmt_local() & (1 << 31));
251 relo_vector = boot_cpu ? BMIPS_RELO_VECTOR_CONTROL_0 :
252 BMIPS_RELO_VECTOR_CONTROL_1;
253
254 old_vec = __raw_readl(cbr + relo_vector);
255 __raw_writel(old_vec & ~0x20000000, cbr + relo_vector);
256
257 clear_c0_cause(smp_processor_id() ? C_SW1 : C_SW0); 242 clear_c0_cause(smp_processor_id() ? C_SW1 : C_SW0);
258 break; 243 break;
259 case CPU_BMIPS5000: 244 case CPU_BMIPS5000:
260 write_c0_brcm_bootvec(read_c0_brcm_bootvec() &
261 (smp_processor_id() & 0x01 ? ~0x20000000 : ~0x2000));
262
263 write_c0_brcm_action(ACTION_CLR_IPI(smp_processor_id(), 0)); 245 write_c0_brcm_action(ACTION_CLR_IPI(smp_processor_id(), 0));
264 break; 246 break;
265 } 247 }
@@ -276,7 +258,7 @@ static void bmips_smp_finish(void)
276 write_c0_compare(read_c0_count() + mips_hpt_frequency / HZ); 258 write_c0_compare(read_c0_count() + mips_hpt_frequency / HZ);
277 259
278 irq_enable_hazard(); 260 irq_enable_hazard();
279 set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ1 | IE_IRQ5 | ST0_IE); 261 set_c0_status(IE_SW0 | IE_SW1 | bmips_tp1_irqs | IE_IRQ5 | ST0_IE);
280 irq_enable_hazard(); 262 irq_enable_hazard();
281} 263}
282 264
@@ -381,6 +363,7 @@ static int bmips_cpu_disable(void)
381 363
382 set_cpu_online(cpu, false); 364 set_cpu_online(cpu, false);
383 cpu_clear(cpu, cpu_callin_map); 365 cpu_clear(cpu, cpu_callin_map);
366 clear_c0_status(IE_IRQ5);
384 367
385 local_flush_tlb_all(); 368 local_flush_tlb_all();
386 local_flush_icache_range(0, ~0); 369 local_flush_icache_range(0, ~0);
@@ -405,7 +388,8 @@ void __ref play_dead(void)
405 * IRQ handlers; this clears ST0_IE and returns immediately. 388 * IRQ handlers; this clears ST0_IE and returns immediately.
406 */ 389 */
407 clear_c0_cause(CAUSEF_IV | C_SW0 | C_SW1); 390 clear_c0_cause(CAUSEF_IV | C_SW0 | C_SW1);
408 change_c0_status(IE_IRQ5 | IE_IRQ1 | IE_SW0 | IE_SW1 | ST0_IE | ST0_BEV, 391 change_c0_status(
392 IE_IRQ5 | bmips_tp1_irqs | IE_SW0 | IE_SW1 | ST0_IE | ST0_BEV,
409 IE_SW0 | IE_SW1 | ST0_IE | ST0_BEV); 393 IE_SW0 | IE_SW1 | ST0_IE | ST0_BEV);
410 irq_disable_hazard(); 394 irq_disable_hazard();
411 395
@@ -473,10 +457,61 @@ static inline void bmips_nmi_handler_setup(void)
473 &bmips_smp_int_vec_end); 457 &bmips_smp_int_vec_end);
474} 458}
475 459
460struct reset_vec_info {
461 int cpu;
462 u32 val;
463};
464
465static void bmips_set_reset_vec_remote(void *vinfo)
466{
467 struct reset_vec_info *info = vinfo;
468 int shift = info->cpu & 0x01 ? 16 : 0;
469 u32 mask = ~(0xffff << shift), val = info->val >> 16;
470
471 preempt_disable();
472 if (smp_processor_id() > 0) {
473 smp_call_function_single(0, &bmips_set_reset_vec_remote,
474 info, 1);
475 } else {
476 if (info->cpu & 0x02) {
477 /* BMIPS5200 "should" use mask/shift, but it's buggy */
478 bmips_write_zscm_reg(0xa0, (val << 16) | val);
479 bmips_read_zscm_reg(0xa0);
480 } else {
481 write_c0_brcm_bootvec((read_c0_brcm_bootvec() & mask) |
482 (val << shift));
483 }
484 }
485 preempt_enable();
486}
487
488static void bmips_set_reset_vec(int cpu, u32 val)
489{
490 struct reset_vec_info info;
491
492 if (current_cpu_type() == CPU_BMIPS5000) {
493 /* this needs to run from CPU0 (which is always online) */
494 info.cpu = cpu;
495 info.val = val;
496 bmips_set_reset_vec_remote(&info);
497 } else {
498 void __iomem *cbr = BMIPS_GET_CBR();
499
500 if (cpu == 0)
501 __raw_writel(val, cbr + BMIPS_RELO_VECTOR_CONTROL_0);
502 else {
503 if (current_cpu_type() != CPU_BMIPS4380)
504 return;
505 __raw_writel(val, cbr + BMIPS_RELO_VECTOR_CONTROL_1);
506 }
507 }
508 __sync();
509 back_to_back_c0_hazard();
510}
511
476void bmips_ebase_setup(void) 512void bmips_ebase_setup(void)
477{ 513{
478 unsigned long new_ebase = ebase; 514 unsigned long new_ebase = ebase;
479 void __iomem __maybe_unused *cbr;
480 515
481 BUG_ON(ebase != CKSEG0); 516 BUG_ON(ebase != CKSEG0);
482 517
@@ -496,15 +531,14 @@ void bmips_ebase_setup(void)
496 &bmips_smp_int_vec, 0x80); 531 &bmips_smp_int_vec, 0x80);
497 __sync(); 532 __sync();
498 return; 533 return;
534 case CPU_BMIPS3300:
499 case CPU_BMIPS4380: 535 case CPU_BMIPS4380:
500 /* 536 /*
501 * 0x8000_0000: reset/NMI (initially in kseg1) 537 * 0x8000_0000: reset/NMI (initially in kseg1)
502 * 0x8000_0400: normal vectors 538 * 0x8000_0400: normal vectors
503 */ 539 */
504 new_ebase = 0x80000400; 540 new_ebase = 0x80000400;
505 cbr = BMIPS_GET_CBR(); 541 bmips_set_reset_vec(0, RESET_FROM_KSEG0);
506 __raw_writel(0x80080800, cbr + BMIPS_RELO_VECTOR_CONTROL_0);
507 __raw_writel(0xa0080800, cbr + BMIPS_RELO_VECTOR_CONTROL_1);
508 break; 542 break;
509 case CPU_BMIPS5000: 543 case CPU_BMIPS5000:
510 /* 544 /*
@@ -512,10 +546,8 @@ void bmips_ebase_setup(void)
512 * 0x8000_1000: normal vectors 546 * 0x8000_1000: normal vectors
513 */ 547 */
514 new_ebase = 0x80001000; 548 new_ebase = 0x80001000;
515 write_c0_brcm_bootvec(0xa0088008); 549 bmips_set_reset_vec(0, RESET_FROM_KSEG0);
516 write_c0_ebase(new_ebase); 550 write_c0_ebase(new_ebase);
517 if (max_cpus > 2)
518 bmips_write_zscm_reg(0xa0, 0xa008a008);
519 break; 551 break;
520 default: 552 default:
521 return; 553 return;