target/openrisc: Support non-busy idle state using PMR SPR
PATCH 1/1 target/openrisc: Support non-busy idle state using PMR SPR
The OpenRISC architecture has the Power Management Register (PMR) special purpose register to manage cpu power states. The interesting modes are:
* Doze Mode (DME) - Stop cpu except timer & pic - wake on interrupt
* Sleep Mode (SME) - Stop cpu and all units - wake on interrupt
* Suspend Model (SUME) - Stop cpu and all units - wake on reset
The linux kernel will set DME when idle.
This patch implements the PMR SPR and halts the qemu cpu when there is a change to DME or SME. This means that openrisc qemu in no longer peggs a host cpu at 100%.
In order for this to work we need to kick the CPU when timers are expired. Update the cpu timer to kick the cpu upon each timer event.
---
Changes since last RFC - none
hw/openrisc/cputimer.c | 1 + target/openrisc/cpu.c | 3 ++- target/openrisc/cpu.h | 10 ++++++++++ target/openrisc/interrupt.c | 2 ++ target/openrisc/machine.c | 1 + target/openrisc/sys_helper.c | 13 +++++++++++++ 6 files changed, 29 insertions(+), 1 deletion(-)
hw/openrisc/cputimer.c +1 -0
@@ -61,6 +61,7 @@ void cpu_openrisc_timer_update(OpenRISCCPU *cpu) } next = now + (uint64_t )wait *TIMER_PERIOD ;timer_mod (cpu->env.timer, next); +qemu_cpu_kick (CPU (cpu)); }void cpu_openrisc_count_start (OpenRISCCPU *cpu)
target/openrisc/cpu.c +2 -1
@@ -51,7 +51,8 @@ static void openrisc_cpu_reset(CPUState *s) cpu->env.lock_addr =-1 ; s->exception_index =-1 ; - cpu->env.upr =UPR_UP |UPR_DMP |UPR_IMP |UPR_PICP |UPR_TTP ; + cpu->env.upr =UPR_UP |UPR_DMP |UPR_IMP |UPR_PICP |UPR_TTP | +UPR_PMP ; cpu->env.dmmucfgr = (DMMUCFGR_NTW & (0 <<2 )) | (DMMUCFGR_NTS & (6 <<2 )); cpu->env.immucfgr = (IMMUCFGR_NTW & (0 <<2 )) | (IMMUCFGR_NTS & (6 <<2 ));
target/openrisc/cpu.h +10 -0
@@ -140,6 +140,15 @@ enum { IMMUCFGR_HTR = (1 << 11), }; +/* Power management register */ +enum { +PMR_SDF = (15 <<0 ), +PMR_DME = (1 <<4 ), +PMR_SME = (1 <<5 ), +PMR_DCGE = (1 <<6 ), +PMR_SUME = (1 <<7 ), +}; +/* Float point control status register */ enum {FPCSR_FPEE =1 ,
@@ -284,6 +293,7 @@ typedef struct CPUOpenRISCState {uint32_t immucfgr;/* IMMU configure register */ uint32_t esr;/* Exception supervisor register */ uint32_t evbar;/* Exception vector base address register */ +uint32_t pmr;/* Power Management Register */ uint32_t fpcsr;/* Float register */ float_status fp_status;
target/openrisc/interrupt.c +2 -0
@@ -60,6 +60,8 @@ void openrisc_cpu_do_interrupt(CPUState *cs) env->sr |=SR_SM ; env->sr &= ~SR_IEE ; env->sr &= ~SR_TEE ; + env->pmr &= ~PMR_DME ; + env->pmr &= ~PMR_SME ; env->tlb->cpu_openrisc_map_address_data = &cpu_openrisc_get_phys_nommu; env->tlb->cpu_openrisc_map_address_code = &cpu_openrisc_get_phys_nommu; env->lock_addr =-1 ;
target/openrisc/machine.c +1 -0
@@ -138,6 +138,7 @@ static const VMStateDescription vmstate_env = {VMSTATE_UINT32 (dmmucfgr, CPUOpenRISCState),VMSTATE_UINT32 (immucfgr, CPUOpenRISCState),VMSTATE_UINT32 (evbar, CPUOpenRISCState), +VMSTATE_UINT32 (pmr, CPUOpenRISCState),VMSTATE_UINT32 (esr, CPUOpenRISCState),VMSTATE_UINT32 (fpcsr, CPUOpenRISCState), VMSTATE_UINT64(mac, CPUOpenRISCState),
target/openrisc/sys_helper.c +13 -0
@@ -22,6 +22,7 @@#include "cpu.h" #include "exec/exec-all.h" #include "exec/helper-proto.h" +#include "exception.h" #define TO_SPR (group, number) (((group) << 11) + (number))
@@ -141,6 +142,15 @@ void HELPER(mtspr)(CPUOpenRISCState *env,case TO_SPR (5 ,2 ):/* MACHI */ env->mac =deposit64 (env->mac,32 ,32 , rb);break ; +case TO_SPR (8 ,0 ):/* PMR */ + env->pmr = rb; +if (env->pmr &PMR_DME || env->pmr &PMR_SME ) { +cpu_restore_state (cs,GETPC ()); + env->pc +=4 ; + cs->halted =1 ; +raise_exception (cpu,EXCP_HLT ); + } +break ;case TO_SPR (9 ,0 ):/* PICMR */ env->picmr |= rb;break ;
@@ -287,6 +297,9 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env,return env->mac >>32 ;break ; +case TO_SPR (8 ,0 ):/* PMR */ +return env->pmr; +case TO_SPR (9 ,0 ):/* PICMR */ return env->picmr;
Signature · 1 line
2.9.3
Quoted 1 line · Stafford Horne
+
raise_exception(cpu, EXCP_HLT);
One minor tweak -- EXCP_HALTED.
HLT is, in theory, i386 specific. Not that you'd have noticed a difference. FWIW, I've just found the same error in target/alpha.
Otherwise,
r~
Quoted 7 lines · Richard Henderson
Quoted 1 line · Stafford Horne
+
raise_exception(cpu, EXCP_HLT);One minor tweak --
EXCP_HALTED.HLT is, in theory, i386 specific. Not that you'd have noticed a difference. FWIW, I've just found the same error in target/alpha.
Oh, I didnt notice that.
Quoted 4 lines
Otherwise,
Reviewed-by Richard Henderson <[email protected]>
Thanks,
-Stafford