diff options
author | Stafford Horne <shorne@gmail.com> | 2017-06-23 18:09:59 -0400 |
---|---|---|
committer | Stafford Horne <shorne@gmail.com> | 2017-11-03 01:01:14 -0400 |
commit | c056718464512da06d7f65a27d5e4f1707b24c80 (patch) | |
tree | 3b3b3076d876428ae8b81826f7171f22e84009a5 | |
parent | b441aab7aa0e15955c432736b08a218a6a4c77f0 (diff) |
openrisc: sleep instead of spin on secondary wait
Currently we do a spin on secondary cpus when waiting to boot. This
theoretically causes issues with power consumption and does cause issues
with qemu cycle burning (it starves cpu 0 from actually being able to
boot.)
This change puts each secondary cpu to sleep if they have a power
management unit, then signals them to wake via IPI when its time to boot.
If the cpus have no power management unit they will loop as before.
Note: The wakeup IPI requires a special interrupt handler as on secondary
cpu's the interrupt infrastructure is not yet established. This
interrupt handler is set and reset by updating SPR_EVBAR.
Signed-off-by: Stafford Horne <shorne@gmail.com>
-rw-r--r-- | arch/openrisc/kernel/head.S | 51 | ||||
-rw-r--r-- | arch/openrisc/kernel/smp.c | 5 |
2 files changed, 54 insertions, 2 deletions
diff --git a/arch/openrisc/kernel/head.S b/arch/openrisc/kernel/head.S index a9972dc103f8..fb02b2a1d6f2 100644 --- a/arch/openrisc/kernel/head.S +++ b/arch/openrisc/kernel/head.S | |||
@@ -712,9 +712,45 @@ _flush_tlb: | |||
712 | 712 | ||
713 | #ifdef CONFIG_SMP | 713 | #ifdef CONFIG_SMP |
714 | secondary_wait: | 714 | secondary_wait: |
715 | /* Doze the cpu until we are asked to run */ | ||
716 | /* If we dont have power management skip doze */ | ||
717 | l.mfspr r25,r0,SPR_UPR | ||
718 | l.andi r25,r25,SPR_UPR_PMP | ||
719 | l.sfeq r25,r0 | ||
720 | l.bf secondary_check_release | ||
721 | l.nop | ||
722 | |||
723 | /* Setup special secondary exception handler */ | ||
724 | LOAD_SYMBOL_2_GPR(r3, _secondary_evbar) | ||
725 | tophys(r25,r3) | ||
726 | l.mtspr r0,r25,SPR_EVBAR | ||
727 | |||
728 | /* Enable Interrupts */ | ||
729 | l.mfspr r25,r0,SPR_SR | ||
730 | l.ori r25,r25,SPR_SR_IEE | ||
731 | l.mtspr r0,r25,SPR_SR | ||
732 | |||
733 | /* Unmask interrupts interrupts */ | ||
734 | l.mfspr r25,r0,SPR_PICMR | ||
735 | l.ori r25,r25,0xffff | ||
736 | l.mtspr r0,r25,SPR_PICMR | ||
737 | |||
738 | /* Doze */ | ||
739 | l.mfspr r25,r0,SPR_PMR | ||
740 | LOAD_SYMBOL_2_GPR(r3, SPR_PMR_DME) | ||
741 | l.or r25,r25,r3 | ||
742 | l.mtspr r0,r25,SPR_PMR | ||
743 | |||
744 | /* Wakeup - Restore exception handler */ | ||
745 | l.mtspr r0,r0,SPR_EVBAR | ||
746 | |||
747 | secondary_check_release: | ||
748 | /* | ||
749 | * Check if we actually got the release signal, if not go-back to | ||
750 | * sleep. | ||
751 | */ | ||
715 | l.mfspr r25,r0,SPR_COREID | 752 | l.mfspr r25,r0,SPR_COREID |
716 | l.movhi r3,hi(secondary_release) | 753 | LOAD_SYMBOL_2_GPR(r3, secondary_release) |
717 | l.ori r3,r3,lo(secondary_release) | ||
718 | tophys(r4, r3) | 754 | tophys(r4, r3) |
719 | l.lwz r3,0(r4) | 755 | l.lwz r3,0(r4) |
720 | l.sfeq r25,r3 | 756 | l.sfeq r25,r3 |
@@ -1663,6 +1699,17 @@ ENTRY(_early_uart_init) | |||
1663 | l.jr r9 | 1699 | l.jr r9 |
1664 | l.nop | 1700 | l.nop |
1665 | 1701 | ||
1702 | .align 0x1000 | ||
1703 | .global _secondary_evbar | ||
1704 | _secondary_evbar: | ||
1705 | |||
1706 | .space 0x800 | ||
1707 | /* Just disable interrupts and Return */ | ||
1708 | l.ori r3,r0,SPR_SR_SM | ||
1709 | l.mtspr r0,r3,SPR_ESR_BASE | ||
1710 | l.rfe | ||
1711 | |||
1712 | |||
1666 | .section .rodata | 1713 | .section .rodata |
1667 | _string_unhandled_exception: | 1714 | _string_unhandled_exception: |
1668 | .string "\n\rRunarunaround: Unhandled exception 0x\0" | 1715 | .string "\n\rRunarunaround: Unhandled exception 0x\0" |
diff --git a/arch/openrisc/kernel/smp.c b/arch/openrisc/kernel/smp.c index 154c94a0cfbc..685b4934fa39 100644 --- a/arch/openrisc/kernel/smp.c +++ b/arch/openrisc/kernel/smp.c | |||
@@ -26,6 +26,7 @@ unsigned long secondary_release = -1; | |||
26 | struct thread_info *secondary_thread_info; | 26 | struct thread_info *secondary_thread_info; |
27 | 27 | ||
28 | enum ipi_msg_type { | 28 | enum ipi_msg_type { |
29 | IPI_WAKEUP, | ||
29 | IPI_RESCHEDULE, | 30 | IPI_RESCHEDULE, |
30 | IPI_CALL_FUNC, | 31 | IPI_CALL_FUNC, |
31 | IPI_CALL_FUNC_SINGLE, | 32 | IPI_CALL_FUNC_SINGLE, |
@@ -42,6 +43,7 @@ static void boot_secondary(unsigned int cpu, struct task_struct *idle) | |||
42 | spin_lock(&boot_lock); | 43 | spin_lock(&boot_lock); |
43 | 44 | ||
44 | secondary_release = cpu; | 45 | secondary_release = cpu; |
46 | smp_cross_call(cpumask_of(cpu), IPI_WAKEUP); | ||
45 | 47 | ||
46 | /* | 48 | /* |
47 | * now the secondary core is starting up let it run its | 49 | * now the secondary core is starting up let it run its |
@@ -140,6 +142,9 @@ void handle_IPI(unsigned int ipi_msg) | |||
140 | unsigned int cpu = smp_processor_id(); | 142 | unsigned int cpu = smp_processor_id(); |
141 | 143 | ||
142 | switch (ipi_msg) { | 144 | switch (ipi_msg) { |
145 | case IPI_WAKEUP: | ||
146 | break; | ||
147 | |||
143 | case IPI_RESCHEDULE: | 148 | case IPI_RESCHEDULE: |
144 | scheduler_ipi(); | 149 | scheduler_ipi(); |
145 | break; | 150 | break; |