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>
This commit is contained in:
parent
b441aab7aa
commit
c056718464
@ -712,9 +712,45 @@ _flush_tlb:
|
|||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
secondary_wait:
|
secondary_wait:
|
||||||
|
/* Doze the cpu until we are asked to run */
|
||||||
|
/* If we dont have power management skip doze */
|
||||||
|
l.mfspr r25,r0,SPR_UPR
|
||||||
|
l.andi r25,r25,SPR_UPR_PMP
|
||||||
|
l.sfeq r25,r0
|
||||||
|
l.bf secondary_check_release
|
||||||
|
l.nop
|
||||||
|
|
||||||
|
/* Setup special secondary exception handler */
|
||||||
|
LOAD_SYMBOL_2_GPR(r3, _secondary_evbar)
|
||||||
|
tophys(r25,r3)
|
||||||
|
l.mtspr r0,r25,SPR_EVBAR
|
||||||
|
|
||||||
|
/* Enable Interrupts */
|
||||||
|
l.mfspr r25,r0,SPR_SR
|
||||||
|
l.ori r25,r25,SPR_SR_IEE
|
||||||
|
l.mtspr r0,r25,SPR_SR
|
||||||
|
|
||||||
|
/* Unmask interrupts interrupts */
|
||||||
|
l.mfspr r25,r0,SPR_PICMR
|
||||||
|
l.ori r25,r25,0xffff
|
||||||
|
l.mtspr r0,r25,SPR_PICMR
|
||||||
|
|
||||||
|
/* Doze */
|
||||||
|
l.mfspr r25,r0,SPR_PMR
|
||||||
|
LOAD_SYMBOL_2_GPR(r3, SPR_PMR_DME)
|
||||||
|
l.or r25,r25,r3
|
||||||
|
l.mtspr r0,r25,SPR_PMR
|
||||||
|
|
||||||
|
/* Wakeup - Restore exception handler */
|
||||||
|
l.mtspr r0,r0,SPR_EVBAR
|
||||||
|
|
||||||
|
secondary_check_release:
|
||||||
|
/*
|
||||||
|
* Check if we actually got the release signal, if not go-back to
|
||||||
|
* sleep.
|
||||||
|
*/
|
||||||
l.mfspr r25,r0,SPR_COREID
|
l.mfspr r25,r0,SPR_COREID
|
||||||
l.movhi r3,hi(secondary_release)
|
LOAD_SYMBOL_2_GPR(r3, secondary_release)
|
||||||
l.ori r3,r3,lo(secondary_release)
|
|
||||||
tophys(r4, r3)
|
tophys(r4, r3)
|
||||||
l.lwz r3,0(r4)
|
l.lwz r3,0(r4)
|
||||||
l.sfeq r25,r3
|
l.sfeq r25,r3
|
||||||
@ -1663,6 +1699,17 @@ ENTRY(_early_uart_init)
|
|||||||
l.jr r9
|
l.jr r9
|
||||||
l.nop
|
l.nop
|
||||||
|
|
||||||
|
.align 0x1000
|
||||||
|
.global _secondary_evbar
|
||||||
|
_secondary_evbar:
|
||||||
|
|
||||||
|
.space 0x800
|
||||||
|
/* Just disable interrupts and Return */
|
||||||
|
l.ori r3,r0,SPR_SR_SM
|
||||||
|
l.mtspr r0,r3,SPR_ESR_BASE
|
||||||
|
l.rfe
|
||||||
|
|
||||||
|
|
||||||
.section .rodata
|
.section .rodata
|
||||||
_string_unhandled_exception:
|
_string_unhandled_exception:
|
||||||
.string "\n\rRunarunaround: Unhandled exception 0x\0"
|
.string "\n\rRunarunaround: Unhandled exception 0x\0"
|
||||||
|
@ -26,6 +26,7 @@ unsigned long secondary_release = -1;
|
|||||||
struct thread_info *secondary_thread_info;
|
struct thread_info *secondary_thread_info;
|
||||||
|
|
||||||
enum ipi_msg_type {
|
enum ipi_msg_type {
|
||||||
|
IPI_WAKEUP,
|
||||||
IPI_RESCHEDULE,
|
IPI_RESCHEDULE,
|
||||||
IPI_CALL_FUNC,
|
IPI_CALL_FUNC,
|
||||||
IPI_CALL_FUNC_SINGLE,
|
IPI_CALL_FUNC_SINGLE,
|
||||||
@ -42,6 +43,7 @@ static void boot_secondary(unsigned int cpu, struct task_struct *idle)
|
|||||||
spin_lock(&boot_lock);
|
spin_lock(&boot_lock);
|
||||||
|
|
||||||
secondary_release = cpu;
|
secondary_release = cpu;
|
||||||
|
smp_cross_call(cpumask_of(cpu), IPI_WAKEUP);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* now the secondary core is starting up let it run its
|
* now the secondary core is starting up let it run its
|
||||||
@ -140,6 +142,9 @@ void handle_IPI(unsigned int ipi_msg)
|
|||||||
unsigned int cpu = smp_processor_id();
|
unsigned int cpu = smp_processor_id();
|
||||||
|
|
||||||
switch (ipi_msg) {
|
switch (ipi_msg) {
|
||||||
|
case IPI_WAKEUP:
|
||||||
|
break;
|
||||||
|
|
||||||
case IPI_RESCHEDULE:
|
case IPI_RESCHEDULE:
|
||||||
scheduler_ipi();
|
scheduler_ipi();
|
||||||
break;
|
break;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user