diff options
author | Graf Yang <graf.yang@analog.com> | 2009-01-07 10:14:39 -0500 |
---|---|---|
committer | Bryan Wu <cooloney@kernel.org> | 2009-01-07 10:14:39 -0500 |
commit | 6b3087c64a92a36ae20d33479b4df6d7afc910d4 (patch) | |
tree | 95984fc623658ebf150d0d912a7f6c5a0301a5a9 /arch/blackfin/mach-common | |
parent | c51b4488cd5bff08ed5690a8f303ff7f0894da2a (diff) |
Blackfin arch: SMP supporting patchset: Blackfin header files and machine common code
Blackfin dual core BF561 processor can support SMP like features.
https://docs.blackfin.uclinux.org/doku.php?id=linux-kernel:smp-like
In this patch, we provide SMP extend to Blackfin header files
and machine common code
Signed-off-by: Graf Yang <graf.yang@analog.com>
Signed-off-by: Bryan Wu <cooloney@kernel.org>
Diffstat (limited to 'arch/blackfin/mach-common')
-rw-r--r-- | arch/blackfin/mach-common/Makefile | 1 | ||||
-rw-r--r-- | arch/blackfin/mach-common/cache.S | 36 | ||||
-rw-r--r-- | arch/blackfin/mach-common/entry.S | 92 | ||||
-rw-r--r-- | arch/blackfin/mach-common/head.S | 29 | ||||
-rw-r--r-- | arch/blackfin/mach-common/ints-priority.c | 41 | ||||
-rw-r--r-- | arch/blackfin/mach-common/smp.c | 476 |
6 files changed, 605 insertions, 70 deletions
diff --git a/arch/blackfin/mach-common/Makefile b/arch/blackfin/mach-common/Makefile index e6ed57c56d4b..9388b4ab7349 100644 --- a/arch/blackfin/mach-common/Makefile +++ b/arch/blackfin/mach-common/Makefile | |||
@@ -10,3 +10,4 @@ obj-$(CONFIG_BFIN_ICACHE_LOCK) += lock.o | |||
10 | obj-$(CONFIG_PM) += pm.o dpmc_modes.o | 10 | obj-$(CONFIG_PM) += pm.o dpmc_modes.o |
11 | obj-$(CONFIG_CPU_FREQ) += cpufreq.o | 11 | obj-$(CONFIG_CPU_FREQ) += cpufreq.o |
12 | obj-$(CONFIG_CPU_VOLTAGE) += dpmc.o | 12 | obj-$(CONFIG_CPU_VOLTAGE) += dpmc.o |
13 | obj-$(CONFIG_SMP) += smp.o | ||
diff --git a/arch/blackfin/mach-common/cache.S b/arch/blackfin/mach-common/cache.S index 3c98dacbf289..118751287437 100644 --- a/arch/blackfin/mach-common/cache.S +++ b/arch/blackfin/mach-common/cache.S | |||
@@ -97,3 +97,39 @@ ENTRY(_blackfin_dflush_page) | |||
97 | P1 = 1 << (PAGE_SHIFT - L1_CACHE_SHIFT); | 97 | P1 = 1 << (PAGE_SHIFT - L1_CACHE_SHIFT); |
98 | jump .Ldfr; | 98 | jump .Ldfr; |
99 | ENDPROC(_blackfin_dflush_page) | 99 | ENDPROC(_blackfin_dflush_page) |
100 | |||
101 | /* Invalidate the Entire Data cache by | ||
102 | * clearing DMC[1:0] bits | ||
103 | */ | ||
104 | ENTRY(_blackfin_invalidate_entire_dcache) | ||
105 | [--SP] = ( R7:5); | ||
106 | |||
107 | P0.L = LO(DMEM_CONTROL); | ||
108 | P0.H = HI(DMEM_CONTROL); | ||
109 | R7 = [P0]; | ||
110 | R5 = R7; /* Save DMEM_CNTR */ | ||
111 | |||
112 | /* Clear the DMC[1:0] bits, All valid bits in the data | ||
113 | * cache are set to the invalid state | ||
114 | */ | ||
115 | BITCLR(R7,DMC0_P); | ||
116 | BITCLR(R7,DMC1_P); | ||
117 | CLI R6; | ||
118 | SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */ | ||
119 | .align 8; | ||
120 | [P0] = R7; | ||
121 | SSYNC; | ||
122 | STI R6; | ||
123 | |||
124 | /* Configures the data cache again */ | ||
125 | |||
126 | CLI R6; | ||
127 | SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */ | ||
128 | .align 8; | ||
129 | [P0] = R5; | ||
130 | SSYNC; | ||
131 | STI R6; | ||
132 | |||
133 | ( R7:5) = [SP++]; | ||
134 | RTS; | ||
135 | ENDPROC(_blackfin_invalidate_entire_dcache) | ||
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index c6ae8442fc4e..5531f49c84e6 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/init.h> | 36 | #include <linux/init.h> |
37 | #include <linux/linkage.h> | 37 | #include <linux/linkage.h> |
38 | #include <linux/unistd.h> | 38 | #include <linux/unistd.h> |
39 | #include <linux/threads.h> | ||
39 | #include <asm/blackfin.h> | 40 | #include <asm/blackfin.h> |
40 | #include <asm/errno.h> | 41 | #include <asm/errno.h> |
41 | #include <asm/fixed_code.h> | 42 | #include <asm/fixed_code.h> |
@@ -75,11 +76,11 @@ ENTRY(_ex_workaround_261) | |||
75 | * handle it. | 76 | * handle it. |
76 | */ | 77 | */ |
77 | P4 = R7; /* Store EXCAUSE */ | 78 | P4 = R7; /* Store EXCAUSE */ |
78 | p5.l = _last_cplb_fault_retx; | 79 | |
79 | p5.h = _last_cplb_fault_retx; | 80 | GET_PDA(p5, r7); |
80 | r7 = [p5]; | 81 | r7 = [p5 + PDA_LFRETX]; |
81 | r6 = retx; | 82 | r6 = retx; |
82 | [p5] = r6; | 83 | [p5 + PDA_LFRETX] = r6; |
83 | cc = r6 == r7; | 84 | cc = r6 == r7; |
84 | if !cc jump _bfin_return_from_exception; | 85 | if !cc jump _bfin_return_from_exception; |
85 | /* fall through */ | 86 | /* fall through */ |
@@ -324,7 +325,9 @@ ENTRY(_ex_trap_c) | |||
324 | [p4] = p5; | 325 | [p4] = p5; |
325 | csync; | 326 | csync; |
326 | 327 | ||
328 | GET_PDA(p5, r6); | ||
327 | #ifndef CONFIG_DEBUG_DOUBLEFAULT | 329 | #ifndef CONFIG_DEBUG_DOUBLEFAULT |
330 | |||
328 | /* | 331 | /* |
329 | * Save these registers, as they are only valid in exception context | 332 | * Save these registers, as they are only valid in exception context |
330 | * (where we are now - as soon as we defer to IRQ5, they can change) | 333 | * (where we are now - as soon as we defer to IRQ5, they can change) |
@@ -335,29 +338,25 @@ ENTRY(_ex_trap_c) | |||
335 | p4.l = lo(DCPLB_FAULT_ADDR); | 338 | p4.l = lo(DCPLB_FAULT_ADDR); |
336 | p4.h = hi(DCPLB_FAULT_ADDR); | 339 | p4.h = hi(DCPLB_FAULT_ADDR); |
337 | r7 = [p4]; | 340 | r7 = [p4]; |
338 | p5.h = _saved_dcplb_fault_addr; | 341 | [p5 + PDA_DCPLB] = r7; |
339 | p5.l = _saved_dcplb_fault_addr; | ||
340 | [p5] = r7; | ||
341 | 342 | ||
342 | r7 = [p4 + (ICPLB_FAULT_ADDR - DCPLB_FAULT_ADDR)]; | 343 | p4.l = lo(ICPLB_FAULT_ADDR); |
343 | p5.h = _saved_icplb_fault_addr; | 344 | p4.h = hi(ICPLB_FAULT_ADDR); |
344 | p5.l = _saved_icplb_fault_addr; | 345 | r6 = [p4]; |
345 | [p5] = r7; | 346 | [p5 + PDA_ICPLB] = r6; |
346 | 347 | ||
347 | r6 = retx; | 348 | r6 = retx; |
348 | p4.l = _saved_retx; | 349 | [p5 + PDA_RETX] = r6; |
349 | p4.h = _saved_retx; | ||
350 | [p4] = r6; | ||
351 | #endif | 350 | #endif |
352 | r6 = SYSCFG; | 351 | r6 = SYSCFG; |
353 | [p4 + 4] = r6; | 352 | [p5 + PDA_SYSCFG] = r6; |
354 | BITCLR(r6, 0); | 353 | BITCLR(r6, 0); |
355 | SYSCFG = r6; | 354 | SYSCFG = r6; |
356 | 355 | ||
357 | /* Disable all interrupts, but make sure level 5 is enabled so | 356 | /* Disable all interrupts, but make sure level 5 is enabled so |
358 | * we can switch to that level. Save the old mask. */ | 357 | * we can switch to that level. Save the old mask. */ |
359 | cli r6; | 358 | cli r6; |
360 | [p4 + 8] = r6; | 359 | [p5 + PDA_EXIMASK] = r6; |
361 | 360 | ||
362 | p4.l = lo(SAFE_USER_INSTRUCTION); | 361 | p4.l = lo(SAFE_USER_INSTRUCTION); |
363 | p4.h = hi(SAFE_USER_INSTRUCTION); | 362 | p4.h = hi(SAFE_USER_INSTRUCTION); |
@@ -424,17 +423,16 @@ ENDPROC(_double_fault) | |||
424 | ENTRY(_exception_to_level5) | 423 | ENTRY(_exception_to_level5) |
425 | SAVE_ALL_SYS | 424 | SAVE_ALL_SYS |
426 | 425 | ||
427 | p4.l = _saved_retx; | 426 | GET_PDA(p4, r7); /* Fetch current PDA */ |
428 | p4.h = _saved_retx; | 427 | r6 = [p4 + PDA_RETX]; |
429 | r6 = [p4]; | ||
430 | [sp + PT_PC] = r6; | 428 | [sp + PT_PC] = r6; |
431 | 429 | ||
432 | r6 = [p4 + 4]; | 430 | r6 = [p4 + PDA_SYSCFG]; |
433 | [sp + PT_SYSCFG] = r6; | 431 | [sp + PT_SYSCFG] = r6; |
434 | 432 | ||
435 | /* Restore interrupt mask. We haven't pushed RETI, so this | 433 | /* Restore interrupt mask. We haven't pushed RETI, so this |
436 | * doesn't enable interrupts until we return from this handler. */ | 434 | * doesn't enable interrupts until we return from this handler. */ |
437 | r6 = [p4 + 8]; | 435 | r6 = [p4 + PDA_EXIMASK]; |
438 | sti r6; | 436 | sti r6; |
439 | 437 | ||
440 | /* Restore the hardware error vector. */ | 438 | /* Restore the hardware error vector. */ |
@@ -478,8 +476,8 @@ ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/ | |||
478 | * scratch register (for want of a better option). | 476 | * scratch register (for want of a better option). |
479 | */ | 477 | */ |
480 | EX_SCRATCH_REG = sp; | 478 | EX_SCRATCH_REG = sp; |
481 | sp.l = _exception_stack_top; | 479 | GET_PDA_SAFE(sp); |
482 | sp.h = _exception_stack_top; | 480 | sp = [sp + PDA_EXSTACK] |
483 | /* Try to deal with syscalls quickly. */ | 481 | /* Try to deal with syscalls quickly. */ |
484 | [--sp] = ASTAT; | 482 | [--sp] = ASTAT; |
485 | [--sp] = (R7:6,P5:4); | 483 | [--sp] = (R7:6,P5:4); |
@@ -501,27 +499,22 @@ ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/ | |||
501 | * but they are not very interesting, so don't save them | 499 | * but they are not very interesting, so don't save them |
502 | */ | 500 | */ |
503 | 501 | ||
502 | GET_PDA(p5, r7); | ||
504 | p4.l = lo(DCPLB_FAULT_ADDR); | 503 | p4.l = lo(DCPLB_FAULT_ADDR); |
505 | p4.h = hi(DCPLB_FAULT_ADDR); | 504 | p4.h = hi(DCPLB_FAULT_ADDR); |
506 | r7 = [p4]; | 505 | r7 = [p4]; |
507 | p5.h = _saved_dcplb_fault_addr; | 506 | [p5 + PDA_DCPLB] = r7; |
508 | p5.l = _saved_dcplb_fault_addr; | ||
509 | [p5] = r7; | ||
510 | 507 | ||
511 | r7 = [p4 + (ICPLB_FAULT_ADDR - DCPLB_FAULT_ADDR)]; | 508 | p4.l = lo(ICPLB_FAULT_ADDR); |
512 | p5.h = _saved_icplb_fault_addr; | 509 | p4.h = hi(ICPLB_FAULT_ADDR); |
513 | p5.l = _saved_icplb_fault_addr; | 510 | r7 = [p4]; |
514 | [p5] = r7; | 511 | [p5 + PDA_ICPLB] = r7; |
515 | 512 | ||
516 | p4.l = _saved_retx; | ||
517 | p4.h = _saved_retx; | ||
518 | r6 = retx; | 513 | r6 = retx; |
519 | [p4] = r6; | 514 | [p5 + PDA_RETX] = r6; |
520 | 515 | ||
521 | r7 = SEQSTAT; /* reason code is in bit 5:0 */ | 516 | r7 = SEQSTAT; /* reason code is in bit 5:0 */ |
522 | p4.l = _saved_seqstat; | 517 | [p5 + PDA_SEQSTAT] = r7; |
523 | p4.h = _saved_seqstat; | ||
524 | [p4] = r7; | ||
525 | #else | 518 | #else |
526 | r7 = SEQSTAT; /* reason code is in bit 5:0 */ | 519 | r7 = SEQSTAT; /* reason code is in bit 5:0 */ |
527 | #endif | 520 | #endif |
@@ -546,11 +539,11 @@ ENTRY(_kernel_execve) | |||
546 | p0 = sp; | 539 | p0 = sp; |
547 | r3 = SIZEOF_PTREGS / 4; | 540 | r3 = SIZEOF_PTREGS / 4; |
548 | r4 = 0(x); | 541 | r4 = 0(x); |
549 | 0: | 542 | .Lclear_regs: |
550 | [p0++] = r4; | 543 | [p0++] = r4; |
551 | r3 += -1; | 544 | r3 += -1; |
552 | cc = r3 == 0; | 545 | cc = r3 == 0; |
553 | if !cc jump 0b (bp); | 546 | if !cc jump .Lclear_regs (bp); |
554 | 547 | ||
555 | p0 = sp; | 548 | p0 = sp; |
556 | sp += -16; | 549 | sp += -16; |
@@ -558,7 +551,7 @@ ENTRY(_kernel_execve) | |||
558 | call _do_execve; | 551 | call _do_execve; |
559 | SP += 16; | 552 | SP += 16; |
560 | cc = r0 == 0; | 553 | cc = r0 == 0; |
561 | if ! cc jump 1f; | 554 | if ! cc jump .Lexecve_failed; |
562 | /* Success. Copy our temporary pt_regs to the top of the kernel | 555 | /* Success. Copy our temporary pt_regs to the top of the kernel |
563 | * stack and do a normal exception return. | 556 | * stack and do a normal exception return. |
564 | */ | 557 | */ |
@@ -574,12 +567,12 @@ ENTRY(_kernel_execve) | |||
574 | p0 = fp; | 567 | p0 = fp; |
575 | r4 = [p0--]; | 568 | r4 = [p0--]; |
576 | r3 = SIZEOF_PTREGS / 4; | 569 | r3 = SIZEOF_PTREGS / 4; |
577 | 0: | 570 | .Lcopy_regs: |
578 | r4 = [p0--]; | 571 | r4 = [p0--]; |
579 | [p1--] = r4; | 572 | [p1--] = r4; |
580 | r3 += -1; | 573 | r3 += -1; |
581 | cc = r3 == 0; | 574 | cc = r3 == 0; |
582 | if ! cc jump 0b (bp); | 575 | if ! cc jump .Lcopy_regs (bp); |
583 | 576 | ||
584 | r0 = (KERNEL_STACK_SIZE - SIZEOF_PTREGS) (z); | 577 | r0 = (KERNEL_STACK_SIZE - SIZEOF_PTREGS) (z); |
585 | p1 = r0; | 578 | p1 = r0; |
@@ -591,7 +584,7 @@ ENTRY(_kernel_execve) | |||
591 | 584 | ||
592 | RESTORE_CONTEXT; | 585 | RESTORE_CONTEXT; |
593 | rti; | 586 | rti; |
594 | 1: | 587 | .Lexecve_failed: |
595 | unlink; | 588 | unlink; |
596 | rts; | 589 | rts; |
597 | ENDPROC(_kernel_execve) | 590 | ENDPROC(_kernel_execve) |
@@ -925,9 +918,14 @@ _schedule_and_signal_from_int: | |||
925 | p1 = rets; | 918 | p1 = rets; |
926 | [sp + PT_RESERVED] = p1; | 919 | [sp + PT_RESERVED] = p1; |
927 | 920 | ||
921 | #ifdef CONFIG_SMP | ||
922 | GET_PDA(p0, r0); /* Fetch current PDA (can't migrate to other CPU here) */ | ||
923 | r0 = [p0 + PDA_IRQFLAGS]; | ||
924 | #else | ||
928 | p0.l = _irq_flags; | 925 | p0.l = _irq_flags; |
929 | p0.h = _irq_flags; | 926 | p0.h = _irq_flags; |
930 | r0 = [p0]; | 927 | r0 = [p0]; |
928 | #endif | ||
931 | sti r0; | 929 | sti r0; |
932 | 930 | ||
933 | r0 = sp; | 931 | r0 = sp; |
@@ -1539,12 +1537,6 @@ ENTRY(_sys_call_table) | |||
1539 | .endr | 1537 | .endr |
1540 | END(_sys_call_table) | 1538 | END(_sys_call_table) |
1541 | 1539 | ||
1542 | #if ANOMALY_05000261 | ||
1543 | /* Used by the assembly entry point to work around an anomaly. */ | ||
1544 | _last_cplb_fault_retx: | ||
1545 | .long 0; | ||
1546 | #endif | ||
1547 | |||
1548 | #ifdef CONFIG_EXCEPTION_L1_SCRATCH | 1540 | #ifdef CONFIG_EXCEPTION_L1_SCRATCH |
1549 | /* .section .l1.bss.scratch */ | 1541 | /* .section .l1.bss.scratch */ |
1550 | .set _exception_stack_top, L1_SCRATCH_START + L1_SCRATCH_LENGTH | 1542 | .set _exception_stack_top, L1_SCRATCH_START + L1_SCRATCH_LENGTH |
@@ -1554,8 +1546,8 @@ _last_cplb_fault_retx: | |||
1554 | #else | 1546 | #else |
1555 | .bss | 1547 | .bss |
1556 | #endif | 1548 | #endif |
1557 | _exception_stack: | 1549 | ENTRY(_exception_stack) |
1558 | .rept 1024 | 1550 | .rept 1024 * NR_CPUS |
1559 | .long 0 | 1551 | .long 0 |
1560 | .endr | 1552 | .endr |
1561 | _exception_stack_top: | 1553 | _exception_stack_top: |
diff --git a/arch/blackfin/mach-common/head.S b/arch/blackfin/mach-common/head.S index c1dcaebbd3a9..a621ae444810 100644 --- a/arch/blackfin/mach-common/head.S +++ b/arch/blackfin/mach-common/head.S | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <asm/blackfin.h> | 13 | #include <asm/blackfin.h> |
14 | #include <asm/thread_info.h> | 14 | #include <asm/thread_info.h> |
15 | #include <asm/trace.h> | 15 | #include <asm/trace.h> |
16 | #include <asm/asm-offsets.h> | ||
16 | 17 | ||
17 | __INIT | 18 | __INIT |
18 | 19 | ||
@@ -111,33 +112,26 @@ ENTRY(__start) | |||
111 | * This happens here, since L1 gets clobbered | 112 | * This happens here, since L1 gets clobbered |
112 | * below | 113 | * below |
113 | */ | 114 | */ |
114 | p0.l = _saved_retx; | 115 | GET_PDA(p0, r0); |
115 | p0.h = _saved_retx; | 116 | r7 = [p0 + PDA_RETX]; |
116 | p1.l = _init_saved_retx; | 117 | p1.l = _init_saved_retx; |
117 | p1.h = _init_saved_retx; | 118 | p1.h = _init_saved_retx; |
118 | r0 = [p0]; | 119 | [p1] = r7; |
119 | [p1] = r0; | ||
120 | 120 | ||
121 | p0.l = _saved_dcplb_fault_addr; | 121 | r7 = [p0 + PDA_DCPLB]; |
122 | p0.h = _saved_dcplb_fault_addr; | ||
123 | p1.l = _init_saved_dcplb_fault_addr; | 122 | p1.l = _init_saved_dcplb_fault_addr; |
124 | p1.h = _init_saved_dcplb_fault_addr; | 123 | p1.h = _init_saved_dcplb_fault_addr; |
125 | r0 = [p0]; | 124 | [p1] = r7; |
126 | [p1] = r0; | ||
127 | 125 | ||
128 | p0.l = _saved_icplb_fault_addr; | 126 | r7 = [p0 + PDA_ICPLB]; |
129 | p0.h = _saved_icplb_fault_addr; | ||
130 | p1.l = _init_saved_icplb_fault_addr; | 127 | p1.l = _init_saved_icplb_fault_addr; |
131 | p1.h = _init_saved_icplb_fault_addr; | 128 | p1.h = _init_saved_icplb_fault_addr; |
132 | r0 = [p0]; | 129 | [p1] = r7; |
133 | [p1] = r0; | ||
134 | 130 | ||
135 | p0.l = _saved_seqstat; | 131 | r7 = [p0 + PDA_SEQSTAT]; |
136 | p0.h = _saved_seqstat; | ||
137 | p1.l = _init_saved_seqstat; | 132 | p1.l = _init_saved_seqstat; |
138 | p1.h = _init_saved_seqstat; | 133 | p1.h = _init_saved_seqstat; |
139 | r0 = [p0]; | 134 | [p1] = r7; |
140 | [p1] = r0; | ||
141 | #endif | 135 | #endif |
142 | 136 | ||
143 | /* Initialize stack pointer */ | 137 | /* Initialize stack pointer */ |
@@ -255,6 +249,9 @@ ENTRY(_real_start) | |||
255 | sp = sp + p1; | 249 | sp = sp + p1; |
256 | usp = sp; | 250 | usp = sp; |
257 | fp = sp; | 251 | fp = sp; |
252 | sp += -12; | ||
253 | call _init_pda | ||
254 | sp += 12; | ||
258 | jump.l _start_kernel; | 255 | jump.l _start_kernel; |
259 | ENDPROC(_real_start) | 256 | ENDPROC(_real_start) |
260 | 257 | ||
diff --git a/arch/blackfin/mach-common/ints-priority.c b/arch/blackfin/mach-common/ints-priority.c index d45d0c59fac7..eb8dfcfc3544 100644 --- a/arch/blackfin/mach-common/ints-priority.c +++ b/arch/blackfin/mach-common/ints-priority.c | |||
@@ -55,6 +55,7 @@ | |||
55 | * - | 55 | * - |
56 | */ | 56 | */ |
57 | 57 | ||
58 | #ifndef CONFIG_SMP | ||
58 | /* Initialize this to an actual value to force it into the .data | 59 | /* Initialize this to an actual value to force it into the .data |
59 | * section so that we know it is properly initialized at entry into | 60 | * section so that we know it is properly initialized at entry into |
60 | * the kernel but before bss is initialized to zero (which is where | 61 | * the kernel but before bss is initialized to zero (which is where |
@@ -63,6 +64,7 @@ | |||
63 | */ | 64 | */ |
64 | unsigned long irq_flags = 0x1f; | 65 | unsigned long irq_flags = 0x1f; |
65 | EXPORT_SYMBOL(irq_flags); | 66 | EXPORT_SYMBOL(irq_flags); |
67 | #endif | ||
66 | 68 | ||
67 | /* The number of spurious interrupts */ | 69 | /* The number of spurious interrupts */ |
68 | atomic_t num_spurious; | 70 | atomic_t num_spurious; |
@@ -163,6 +165,10 @@ static void bfin_internal_mask_irq(unsigned int irq) | |||
163 | mask_bit = SIC_SYSIRQ(irq) % 32; | 165 | mask_bit = SIC_SYSIRQ(irq) % 32; |
164 | bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) & | 166 | bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) & |
165 | ~(1 << mask_bit)); | 167 | ~(1 << mask_bit)); |
168 | #ifdef CONFIG_SMP | ||
169 | bfin_write_SICB_IMASK(mask_bank, bfin_read_SICB_IMASK(mask_bank) & | ||
170 | ~(1 << mask_bit)); | ||
171 | #endif | ||
166 | #endif | 172 | #endif |
167 | } | 173 | } |
168 | 174 | ||
@@ -177,6 +183,10 @@ static void bfin_internal_unmask_irq(unsigned int irq) | |||
177 | mask_bit = SIC_SYSIRQ(irq) % 32; | 183 | mask_bit = SIC_SYSIRQ(irq) % 32; |
178 | bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) | | 184 | bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) | |
179 | (1 << mask_bit)); | 185 | (1 << mask_bit)); |
186 | #ifdef CONFIG_SMP | ||
187 | bfin_write_SICB_IMASK(mask_bank, bfin_read_SICB_IMASK(mask_bank) | | ||
188 | (1 << mask_bit)); | ||
189 | #endif | ||
180 | #endif | 190 | #endif |
181 | } | 191 | } |
182 | 192 | ||
@@ -896,7 +906,7 @@ static struct irq_chip bfin_gpio_irqchip = { | |||
896 | #endif | 906 | #endif |
897 | }; | 907 | }; |
898 | 908 | ||
899 | void __init init_exception_vectors(void) | 909 | void __cpuinit init_exception_vectors(void) |
900 | { | 910 | { |
901 | /* cannot program in software: | 911 | /* cannot program in software: |
902 | * evt0 - emulation (jtag) | 912 | * evt0 - emulation (jtag) |
@@ -935,6 +945,10 @@ int __init init_arch_irq(void) | |||
935 | # ifdef CONFIG_BF54x | 945 | # ifdef CONFIG_BF54x |
936 | bfin_write_SIC_IMASK2(SIC_UNMASK_ALL); | 946 | bfin_write_SIC_IMASK2(SIC_UNMASK_ALL); |
937 | # endif | 947 | # endif |
948 | # ifdef CONFIG_SMP | ||
949 | bfin_write_SICB_IMASK0(SIC_UNMASK_ALL); | ||
950 | bfin_write_SICB_IMASK1(SIC_UNMASK_ALL); | ||
951 | # endif | ||
938 | #else | 952 | #else |
939 | bfin_write_SIC_IMASK(SIC_UNMASK_ALL); | 953 | bfin_write_SIC_IMASK(SIC_UNMASK_ALL); |
940 | #endif | 954 | #endif |
@@ -995,6 +1009,17 @@ int __init init_arch_irq(void) | |||
995 | 1009 | ||
996 | break; | 1010 | break; |
997 | #endif | 1011 | #endif |
1012 | #ifdef CONFIG_TICK_SOURCE_SYSTMR0 | ||
1013 | case IRQ_TIMER0: | ||
1014 | set_irq_handler(irq, handle_percpu_irq); | ||
1015 | break; | ||
1016 | #endif | ||
1017 | #ifdef CONFIG_SMP | ||
1018 | case IRQ_SUPPLE_0: | ||
1019 | case IRQ_SUPPLE_1: | ||
1020 | set_irq_handler(irq, handle_percpu_irq); | ||
1021 | break; | ||
1022 | #endif | ||
998 | default: | 1023 | default: |
999 | set_irq_handler(irq, handle_simple_irq); | 1024 | set_irq_handler(irq, handle_simple_irq); |
1000 | break; | 1025 | break; |
@@ -1029,7 +1054,7 @@ int __init init_arch_irq(void) | |||
1029 | search_IAR(); | 1054 | search_IAR(); |
1030 | 1055 | ||
1031 | /* Enable interrupts IVG7-15 */ | 1056 | /* Enable interrupts IVG7-15 */ |
1032 | irq_flags = irq_flags | IMASK_IVG15 | | 1057 | irq_flags |= IMASK_IVG15 | |
1033 | IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 | | 1058 | IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 | |
1034 | IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW; | 1059 | IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW; |
1035 | 1060 | ||
@@ -1070,8 +1095,16 @@ void do_irq(int vec, struct pt_regs *fp) | |||
1070 | || defined(BF538_FAMILY) || defined(CONFIG_BF51x) | 1095 | || defined(BF538_FAMILY) || defined(CONFIG_BF51x) |
1071 | unsigned long sic_status[3]; | 1096 | unsigned long sic_status[3]; |
1072 | 1097 | ||
1073 | sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0(); | 1098 | if (smp_processor_id()) { |
1074 | sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1(); | 1099 | #ifdef CONFIG_SMP |
1100 | /* This will be optimized out in UP mode. */ | ||
1101 | sic_status[0] = bfin_read_SICB_ISR0() & bfin_read_SICB_IMASK0(); | ||
1102 | sic_status[1] = bfin_read_SICB_ISR1() & bfin_read_SICB_IMASK1(); | ||
1103 | #endif | ||
1104 | } else { | ||
1105 | sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0(); | ||
1106 | sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1(); | ||
1107 | } | ||
1075 | #ifdef CONFIG_BF54x | 1108 | #ifdef CONFIG_BF54x |
1076 | sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2(); | 1109 | sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2(); |
1077 | #endif | 1110 | #endif |
diff --git a/arch/blackfin/mach-common/smp.c b/arch/blackfin/mach-common/smp.c new file mode 100644 index 000000000000..7aeecedd3147 --- /dev/null +++ b/arch/blackfin/mach-common/smp.c | |||
@@ -0,0 +1,476 @@ | |||
1 | /* | ||
2 | * File: arch/blackfin/kernel/smp.c | ||
3 | * Author: Philippe Gerum <rpm@xenomai.org> | ||
4 | * IPI management based on arch/arm/kernel/smp.c. | ||
5 | * | ||
6 | * Copyright 2007 Analog Devices Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, see the file COPYING, or write | ||
20 | * to the Free Software Foundation, Inc., | ||
21 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/spinlock.h> | ||
28 | #include <linux/sched.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/cache.h> | ||
31 | #include <linux/profile.h> | ||
32 | #include <linux/errno.h> | ||
33 | #include <linux/mm.h> | ||
34 | #include <linux/cpu.h> | ||
35 | #include <linux/smp.h> | ||
36 | #include <linux/seq_file.h> | ||
37 | #include <linux/irq.h> | ||
38 | #include <asm/atomic.h> | ||
39 | #include <asm/cacheflush.h> | ||
40 | #include <asm/mmu_context.h> | ||
41 | #include <asm/pgtable.h> | ||
42 | #include <asm/pgalloc.h> | ||
43 | #include <asm/processor.h> | ||
44 | #include <asm/ptrace.h> | ||
45 | #include <asm/cpu.h> | ||
46 | #include <linux/err.h> | ||
47 | |||
48 | struct corelock_slot corelock __attribute__ ((__section__(".l2.bss"))); | ||
49 | |||
50 | void __cpuinitdata *init_retx_coreb, *init_saved_retx_coreb, | ||
51 | *init_saved_seqstat_coreb, *init_saved_icplb_fault_addr_coreb, | ||
52 | *init_saved_dcplb_fault_addr_coreb; | ||
53 | |||
54 | cpumask_t cpu_possible_map; | ||
55 | EXPORT_SYMBOL(cpu_possible_map); | ||
56 | |||
57 | cpumask_t cpu_online_map; | ||
58 | EXPORT_SYMBOL(cpu_online_map); | ||
59 | |||
60 | #define BFIN_IPI_RESCHEDULE 0 | ||
61 | #define BFIN_IPI_CALL_FUNC 1 | ||
62 | #define BFIN_IPI_CPU_STOP 2 | ||
63 | |||
64 | struct blackfin_flush_data { | ||
65 | unsigned long start; | ||
66 | unsigned long end; | ||
67 | }; | ||
68 | |||
69 | void *secondary_stack; | ||
70 | |||
71 | |||
72 | struct smp_call_struct { | ||
73 | void (*func)(void *info); | ||
74 | void *info; | ||
75 | int wait; | ||
76 | cpumask_t pending; | ||
77 | cpumask_t waitmask; | ||
78 | }; | ||
79 | |||
80 | static struct blackfin_flush_data smp_flush_data; | ||
81 | |||
82 | static DEFINE_SPINLOCK(stop_lock); | ||
83 | |||
84 | struct ipi_message { | ||
85 | struct list_head list; | ||
86 | unsigned long type; | ||
87 | struct smp_call_struct call_struct; | ||
88 | }; | ||
89 | |||
90 | struct ipi_message_queue { | ||
91 | struct list_head head; | ||
92 | spinlock_t lock; | ||
93 | unsigned long count; | ||
94 | }; | ||
95 | |||
96 | static DEFINE_PER_CPU(struct ipi_message_queue, ipi_msg_queue); | ||
97 | |||
98 | static void ipi_cpu_stop(unsigned int cpu) | ||
99 | { | ||
100 | spin_lock(&stop_lock); | ||
101 | printk(KERN_CRIT "CPU%u: stopping\n", cpu); | ||
102 | dump_stack(); | ||
103 | spin_unlock(&stop_lock); | ||
104 | |||
105 | cpu_clear(cpu, cpu_online_map); | ||
106 | |||
107 | local_irq_disable(); | ||
108 | |||
109 | while (1) | ||
110 | SSYNC(); | ||
111 | } | ||
112 | |||
113 | static void ipi_flush_icache(void *info) | ||
114 | { | ||
115 | struct blackfin_flush_data *fdata = info; | ||
116 | |||
117 | /* Invalidate the memory holding the bounds of the flushed region. */ | ||
118 | blackfin_dcache_invalidate_range((unsigned long)fdata, | ||
119 | (unsigned long)fdata + sizeof(*fdata)); | ||
120 | |||
121 | blackfin_icache_flush_range(fdata->start, fdata->end); | ||
122 | } | ||
123 | |||
124 | static void ipi_call_function(unsigned int cpu, struct ipi_message *msg) | ||
125 | { | ||
126 | int wait; | ||
127 | void (*func)(void *info); | ||
128 | void *info; | ||
129 | func = msg->call_struct.func; | ||
130 | info = msg->call_struct.info; | ||
131 | wait = msg->call_struct.wait; | ||
132 | cpu_clear(cpu, msg->call_struct.pending); | ||
133 | func(info); | ||
134 | if (wait) | ||
135 | cpu_clear(cpu, msg->call_struct.waitmask); | ||
136 | else | ||
137 | kfree(msg); | ||
138 | } | ||
139 | |||
140 | static irqreturn_t ipi_handler(int irq, void *dev_instance) | ||
141 | { | ||
142 | struct ipi_message *msg, *mg; | ||
143 | struct ipi_message_queue *msg_queue; | ||
144 | unsigned int cpu = smp_processor_id(); | ||
145 | |||
146 | platform_clear_ipi(cpu); | ||
147 | |||
148 | msg_queue = &__get_cpu_var(ipi_msg_queue); | ||
149 | msg_queue->count++; | ||
150 | |||
151 | spin_lock(&msg_queue->lock); | ||
152 | list_for_each_entry_safe(msg, mg, &msg_queue->head, list) { | ||
153 | list_del(&msg->list); | ||
154 | switch (msg->type) { | ||
155 | case BFIN_IPI_RESCHEDULE: | ||
156 | /* That's the easiest one; leave it to | ||
157 | * return_from_int. */ | ||
158 | kfree(msg); | ||
159 | break; | ||
160 | case BFIN_IPI_CALL_FUNC: | ||
161 | ipi_call_function(cpu, msg); | ||
162 | break; | ||
163 | case BFIN_IPI_CPU_STOP: | ||
164 | ipi_cpu_stop(cpu); | ||
165 | kfree(msg); | ||
166 | break; | ||
167 | default: | ||
168 | printk(KERN_CRIT "CPU%u: Unknown IPI message \ | ||
169 | 0x%lx\n", cpu, msg->type); | ||
170 | kfree(msg); | ||
171 | break; | ||
172 | } | ||
173 | } | ||
174 | spin_unlock(&msg_queue->lock); | ||
175 | return IRQ_HANDLED; | ||
176 | } | ||
177 | |||
178 | static void ipi_queue_init(void) | ||
179 | { | ||
180 | unsigned int cpu; | ||
181 | struct ipi_message_queue *msg_queue; | ||
182 | for_each_possible_cpu(cpu) { | ||
183 | msg_queue = &per_cpu(ipi_msg_queue, cpu); | ||
184 | INIT_LIST_HEAD(&msg_queue->head); | ||
185 | spin_lock_init(&msg_queue->lock); | ||
186 | msg_queue->count = 0; | ||
187 | } | ||
188 | } | ||
189 | |||
190 | int smp_call_function(void (*func)(void *info), void *info, int wait) | ||
191 | { | ||
192 | unsigned int cpu; | ||
193 | cpumask_t callmap; | ||
194 | unsigned long flags; | ||
195 | struct ipi_message_queue *msg_queue; | ||
196 | struct ipi_message *msg; | ||
197 | |||
198 | callmap = cpu_online_map; | ||
199 | cpu_clear(smp_processor_id(), callmap); | ||
200 | if (cpus_empty(callmap)) | ||
201 | return 0; | ||
202 | |||
203 | msg = kmalloc(sizeof(*msg), GFP_ATOMIC); | ||
204 | INIT_LIST_HEAD(&msg->list); | ||
205 | msg->call_struct.func = func; | ||
206 | msg->call_struct.info = info; | ||
207 | msg->call_struct.wait = wait; | ||
208 | msg->call_struct.pending = callmap; | ||
209 | msg->call_struct.waitmask = callmap; | ||
210 | msg->type = BFIN_IPI_CALL_FUNC; | ||
211 | |||
212 | for_each_cpu_mask(cpu, callmap) { | ||
213 | msg_queue = &per_cpu(ipi_msg_queue, cpu); | ||
214 | spin_lock_irqsave(&msg_queue->lock, flags); | ||
215 | list_add(&msg->list, &msg_queue->head); | ||
216 | spin_unlock_irqrestore(&msg_queue->lock, flags); | ||
217 | platform_send_ipi_cpu(cpu); | ||
218 | } | ||
219 | if (wait) { | ||
220 | while (!cpus_empty(msg->call_struct.waitmask)) | ||
221 | blackfin_dcache_invalidate_range( | ||
222 | (unsigned long)(&msg->call_struct.waitmask), | ||
223 | (unsigned long)(&msg->call_struct.waitmask)); | ||
224 | kfree(msg); | ||
225 | } | ||
226 | return 0; | ||
227 | } | ||
228 | EXPORT_SYMBOL_GPL(smp_call_function); | ||
229 | |||
230 | int smp_call_function_single(int cpuid, void (*func) (void *info), void *info, | ||
231 | int wait) | ||
232 | { | ||
233 | unsigned int cpu = cpuid; | ||
234 | cpumask_t callmap; | ||
235 | unsigned long flags; | ||
236 | struct ipi_message_queue *msg_queue; | ||
237 | struct ipi_message *msg; | ||
238 | |||
239 | if (cpu_is_offline(cpu)) | ||
240 | return 0; | ||
241 | cpus_clear(callmap); | ||
242 | cpu_set(cpu, callmap); | ||
243 | |||
244 | msg = kmalloc(sizeof(*msg), GFP_ATOMIC); | ||
245 | INIT_LIST_HEAD(&msg->list); | ||
246 | msg->call_struct.func = func; | ||
247 | msg->call_struct.info = info; | ||
248 | msg->call_struct.wait = wait; | ||
249 | msg->call_struct.pending = callmap; | ||
250 | msg->call_struct.waitmask = callmap; | ||
251 | msg->type = BFIN_IPI_CALL_FUNC; | ||
252 | |||
253 | msg_queue = &per_cpu(ipi_msg_queue, cpu); | ||
254 | spin_lock_irqsave(&msg_queue->lock, flags); | ||
255 | list_add(&msg->list, &msg_queue->head); | ||
256 | spin_unlock_irqrestore(&msg_queue->lock, flags); | ||
257 | platform_send_ipi_cpu(cpu); | ||
258 | |||
259 | if (wait) { | ||
260 | while (!cpus_empty(msg->call_struct.waitmask)) | ||
261 | blackfin_dcache_invalidate_range( | ||
262 | (unsigned long)(&msg->call_struct.waitmask), | ||
263 | (unsigned long)(&msg->call_struct.waitmask)); | ||
264 | kfree(msg); | ||
265 | } | ||
266 | return 0; | ||
267 | } | ||
268 | EXPORT_SYMBOL_GPL(smp_call_function_single); | ||
269 | |||
270 | void smp_send_reschedule(int cpu) | ||
271 | { | ||
272 | unsigned long flags; | ||
273 | struct ipi_message_queue *msg_queue; | ||
274 | struct ipi_message *msg; | ||
275 | |||
276 | if (cpu_is_offline(cpu)) | ||
277 | return; | ||
278 | |||
279 | msg = kmalloc(sizeof(*msg), GFP_ATOMIC); | ||
280 | memset(msg, 0, sizeof(msg)); | ||
281 | INIT_LIST_HEAD(&msg->list); | ||
282 | msg->type = BFIN_IPI_RESCHEDULE; | ||
283 | |||
284 | msg_queue = &per_cpu(ipi_msg_queue, cpu); | ||
285 | spin_lock_irqsave(&msg_queue->lock, flags); | ||
286 | list_add(&msg->list, &msg_queue->head); | ||
287 | spin_unlock_irqrestore(&msg_queue->lock, flags); | ||
288 | platform_send_ipi_cpu(cpu); | ||
289 | |||
290 | return; | ||
291 | } | ||
292 | |||
293 | void smp_send_stop(void) | ||
294 | { | ||
295 | unsigned int cpu; | ||
296 | cpumask_t callmap; | ||
297 | unsigned long flags; | ||
298 | struct ipi_message_queue *msg_queue; | ||
299 | struct ipi_message *msg; | ||
300 | |||
301 | callmap = cpu_online_map; | ||
302 | cpu_clear(smp_processor_id(), callmap); | ||
303 | if (cpus_empty(callmap)) | ||
304 | return; | ||
305 | |||
306 | msg = kmalloc(sizeof(*msg), GFP_ATOMIC); | ||
307 | memset(msg, 0, sizeof(msg)); | ||
308 | INIT_LIST_HEAD(&msg->list); | ||
309 | msg->type = BFIN_IPI_CPU_STOP; | ||
310 | |||
311 | for_each_cpu_mask(cpu, callmap) { | ||
312 | msg_queue = &per_cpu(ipi_msg_queue, cpu); | ||
313 | spin_lock_irqsave(&msg_queue->lock, flags); | ||
314 | list_add(&msg->list, &msg_queue->head); | ||
315 | spin_unlock_irqrestore(&msg_queue->lock, flags); | ||
316 | platform_send_ipi_cpu(cpu); | ||
317 | } | ||
318 | return; | ||
319 | } | ||
320 | |||
321 | int __cpuinit __cpu_up(unsigned int cpu) | ||
322 | { | ||
323 | struct task_struct *idle; | ||
324 | int ret; | ||
325 | |||
326 | idle = fork_idle(cpu); | ||
327 | if (IS_ERR(idle)) { | ||
328 | printk(KERN_ERR "CPU%u: fork() failed\n", cpu); | ||
329 | return PTR_ERR(idle); | ||
330 | } | ||
331 | |||
332 | secondary_stack = task_stack_page(idle) + THREAD_SIZE; | ||
333 | smp_wmb(); | ||
334 | |||
335 | ret = platform_boot_secondary(cpu, idle); | ||
336 | |||
337 | if (ret) { | ||
338 | cpu_clear(cpu, cpu_present_map); | ||
339 | printk(KERN_CRIT "CPU%u: processor failed to boot (%d)\n", cpu, ret); | ||
340 | free_task(idle); | ||
341 | } else | ||
342 | cpu_set(cpu, cpu_online_map); | ||
343 | |||
344 | secondary_stack = NULL; | ||
345 | |||
346 | return ret; | ||
347 | } | ||
348 | |||
349 | static void __cpuinit setup_secondary(unsigned int cpu) | ||
350 | { | ||
351 | #ifndef CONFIG_TICK_SOURCE_SYSTMR0 | ||
352 | struct irq_desc *timer_desc; | ||
353 | #endif | ||
354 | unsigned long ilat; | ||
355 | |||
356 | bfin_write_IMASK(0); | ||
357 | CSYNC(); | ||
358 | ilat = bfin_read_ILAT(); | ||
359 | CSYNC(); | ||
360 | bfin_write_ILAT(ilat); | ||
361 | CSYNC(); | ||
362 | |||
363 | /* Reserve the PDA space for the secondary CPU. */ | ||
364 | reserve_pda(); | ||
365 | |||
366 | /* Enable interrupt levels IVG7-15. IARs have been already | ||
367 | * programmed by the boot CPU. */ | ||
368 | irq_flags |= IMASK_IVG15 | | ||
369 | IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 | | ||
370 | IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW; | ||
371 | |||
372 | #ifdef CONFIG_TICK_SOURCE_SYSTMR0 | ||
373 | /* Power down the core timer, just to play safe. */ | ||
374 | bfin_write_TCNTL(0); | ||
375 | |||
376 | /* system timer0 has been setup by CoreA. */ | ||
377 | #else | ||
378 | timer_desc = irq_desc + IRQ_CORETMR; | ||
379 | setup_core_timer(); | ||
380 | timer_desc->chip->enable(IRQ_CORETMR); | ||
381 | #endif | ||
382 | } | ||
383 | |||
384 | void __cpuinit secondary_start_kernel(void) | ||
385 | { | ||
386 | unsigned int cpu = smp_processor_id(); | ||
387 | struct mm_struct *mm = &init_mm; | ||
388 | |||
389 | if (_bfin_swrst & SWRST_DBL_FAULT_B) { | ||
390 | printk(KERN_EMERG "CoreB Recovering from DOUBLE FAULT event\n"); | ||
391 | #ifdef CONFIG_DEBUG_DOUBLEFAULT | ||
392 | printk(KERN_EMERG " While handling exception (EXCAUSE = 0x%x) at %pF\n", | ||
393 | (int)init_saved_seqstat_coreb & SEQSTAT_EXCAUSE, init_saved_retx_coreb); | ||
394 | printk(KERN_NOTICE " DCPLB_FAULT_ADDR: %pF\n", init_saved_dcplb_fault_addr_coreb); | ||
395 | printk(KERN_NOTICE " ICPLB_FAULT_ADDR: %pF\n", init_saved_icplb_fault_addr_coreb); | ||
396 | #endif | ||
397 | printk(KERN_NOTICE " The instruction at %pF caused a double exception\n", | ||
398 | init_retx_coreb); | ||
399 | } | ||
400 | |||
401 | /* | ||
402 | * We want the D-cache to be enabled early, in case the atomic | ||
403 | * support code emulates cache coherence (see | ||
404 | * __ARCH_SYNC_CORE_DCACHE). | ||
405 | */ | ||
406 | init_exception_vectors(); | ||
407 | |||
408 | bfin_setup_caches(cpu); | ||
409 | |||
410 | local_irq_disable(); | ||
411 | |||
412 | /* Attach the new idle task to the global mm. */ | ||
413 | atomic_inc(&mm->mm_users); | ||
414 | atomic_inc(&mm->mm_count); | ||
415 | current->active_mm = mm; | ||
416 | BUG_ON(current->mm); /* Can't be, but better be safe than sorry. */ | ||
417 | |||
418 | preempt_disable(); | ||
419 | |||
420 | setup_secondary(cpu); | ||
421 | |||
422 | local_irq_enable(); | ||
423 | |||
424 | platform_secondary_init(cpu); | ||
425 | |||
426 | cpu_idle(); | ||
427 | } | ||
428 | |||
429 | void __init smp_prepare_boot_cpu(void) | ||
430 | { | ||
431 | } | ||
432 | |||
433 | void __init smp_prepare_cpus(unsigned int max_cpus) | ||
434 | { | ||
435 | platform_prepare_cpus(max_cpus); | ||
436 | ipi_queue_init(); | ||
437 | platform_request_ipi(&ipi_handler); | ||
438 | } | ||
439 | |||
440 | void __init smp_cpus_done(unsigned int max_cpus) | ||
441 | { | ||
442 | unsigned long bogosum = 0; | ||
443 | unsigned int cpu; | ||
444 | |||
445 | for_each_online_cpu(cpu) | ||
446 | bogosum += per_cpu(cpu_data, cpu).loops_per_jiffy; | ||
447 | |||
448 | printk(KERN_INFO "SMP: Total of %d processors activated " | ||
449 | "(%lu.%02lu BogoMIPS).\n", | ||
450 | num_online_cpus(), | ||
451 | bogosum / (500000/HZ), | ||
452 | (bogosum / (5000/HZ)) % 100); | ||
453 | } | ||
454 | |||
455 | void smp_icache_flush_range_others(unsigned long start, unsigned long end) | ||
456 | { | ||
457 | smp_flush_data.start = start; | ||
458 | smp_flush_data.end = end; | ||
459 | |||
460 | if (smp_call_function(&ipi_flush_icache, &smp_flush_data, 1)) | ||
461 | printk(KERN_WARNING "SMP: failed to run I-cache flush request on other CPUs\n"); | ||
462 | } | ||
463 | EXPORT_SYMBOL_GPL(smp_icache_flush_range_others); | ||
464 | |||
465 | #ifdef __ARCH_SYNC_CORE_DCACHE | ||
466 | unsigned long barrier_mask __attribute__ ((__section__(".l2.bss"))); | ||
467 | |||
468 | void resync_core_dcache(void) | ||
469 | { | ||
470 | unsigned int cpu = get_cpu(); | ||
471 | blackfin_invalidate_entire_dcache(); | ||
472 | ++per_cpu(cpu_data, cpu).dcache_invld_count; | ||
473 | put_cpu(); | ||
474 | } | ||
475 | EXPORT_SYMBOL(resync_core_dcache); | ||
476 | #endif | ||