Skip to contentSkip to conversation

target/openrisc: Support non-busy idle state using PMR SPR

PATCH In review Stafford Horne 2 participants 3 messages Apr 28, 2017 – Apr 29, 2017

lore
Share & tools
lore
#0 lore raw

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
index a98c799..febc469 100644
@@ -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
index c9b3f22..1d6330c 100644
@@ -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
index 938ccc3..2721432 100644
@@ -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
index 2c91fab..3959671 100644
@@ -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
index a82be62..a20cce7 100644
@@ -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
index fa3d6a4..44acf0d 100644
@@ -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
Reviewed-by on v1 1/1
#1 lore raw
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~

#2 lore raw
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,

Thanks,

-Stafford