[RFC PATCH 31/35] target/arm: enable event stream on WFE instructions

Alex Bennée posted 35 patches 7 hours ago
Maintainers: Peter Maydell <peter.maydell@linaro.org>, Alexander Graf <agraf@csgraf.de>, Pedro Barbuda <pbarbuda@microsoft.com>, Mohamed Mediouni <mohamed@unpredictable.fr>
[RFC PATCH 31/35] target/arm: enable event stream on WFE instructions
Posted by Alex Bennée 7 hours ago
Now we can calculate when the next event stream event is we can re-use
the wfxt_timer and configure it to fire as we enter a WFE that is
going to sleep. Reverse the M-profile logic so we can enter a sleep
state in both profiles.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/cpu.h           |  2 ++
 target/arm/cpu.c           |  5 +++++
 target/arm/tcg/op_helper.c | 37 ++++++++++++++++++-------------------
 3 files changed, 25 insertions(+), 19 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 9c25b60ae83..6a7d92d73db 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -967,6 +967,8 @@ struct ArchCPU {
     QEMUTimer *pmu_timer;
     /* Timer used for WFxT timeouts */
     QEMUTimer *wfxt_timer;
+    /* Are we in a WFE */
+    bool waiting_for_event;
 
     /* GPIO outputs for generic timer */
     qemu_irq gt_timer_outputs[NUM_GTIMERS];
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index d51599dfdab..a0569f74cd5 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -780,6 +780,11 @@ static void arm_wfxt_timer_cb(void *opaque)
     ARMCPU *cpu = opaque;
     CPUState *cs = CPU(cpu);
 
+    if (cpu->waiting_for_event) {
+        CPUARMState *env = &cpu->env;
+        env->event_register.as_bool = true;
+    }
+
     /*
      * We expect the CPU to be halted; this will cause arm_cpu_is_work()
      * to return true (so we will come out of halt even with no other
diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c
index d513045269c..fbe160ab70a 100644
--- a/target/arm/tcg/op_helper.c
+++ b/target/arm/tcg/op_helper.c
@@ -494,31 +494,30 @@ void HELPER(wfe)(CPUARMState *env)
 #else
     /*
      * WFE (Wait For Event) is a hint instruction.
-     * For Cortex-M (M-profile), we implement the strict architectural behavior:
+     *
      * 1. Check the Event Register (set by SEV or SEVONPEND).
      * 2. If set, clear it and continue (consume the event).
      */
-    if (arm_feature(env, ARM_FEATURE_M)) {
-        CPUState *cs = env_cpu(env);
+    CPUState *cs = env_cpu(env);
+    ARMCPU *cpu = ARM_CPU(cs);
 
-        if (env->event_register.as_bool) {
-            env->event_register.as_bool = false;
-            return;
-        }
+    if (env->event_register.as_bool) {
+        env->event_register.as_bool = false;
+        return;
+    }
 
-        cs->exception_index = EXCP_HLT;
-        cs->halted = 1;
-        cpu_loop_exit(cs);
-    } else {
-        /*
-         * For A-profile and others, we rely on the existing "yield" behavior.
-         * Don't actually halt the CPU, just yield back to top
-         * level loop. This is not going into a "low power state"
-         * (ie halting until some event occurs), so we never take
-         * a configurable trap to a different exception level
-         */
-        HELPER(yield)(env);
+    /* For A-profile we also can be woken by the event stream */
+    if (arm_feature(env, ARM_FEATURE_AARCH64) && cpu->wfxt_timer) {
+        int64_t next_event = gt_calc_next_event_stream(env);
+        if (next_event > 0) {
+            cpu->waiting_for_event = true;
+            timer_mod(cpu->wfxt_timer, next_event);
+        }
     }
+
+    cs->exception_index = EXCP_HLT;
+    cs->halted = 1;
+    cpu_loop_exit(cs);
 #endif
 }
 
-- 
2.47.3