[PATCH v3 06/32] target/hexagon: Implement wait helper

Brian Cain posted 32 patches 3 weeks, 6 days ago
[PATCH v3 06/32] target/hexagon: Implement wait helper
Posted by Brian Cain 3 weeks, 6 days ago
From: Brian Cain <bcain@quicinc.com>

Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/op_helper.c | 51 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 49 insertions(+), 2 deletions(-)

diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 161c7eaf31f..6dfc1269809 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1484,9 +1484,56 @@ void HELPER(stop)(CPUHexagonState *env)
     hexagon_stop_thread(env);
 }
 
-void HELPER(wait)(CPUHexagonState *env, target_ulong PC)
+static void set_wait_mode(CPUHexagonState *env)
 {
-    g_assert_not_reached();
+    g_assert(bql_locked());
+
+    HexagonCPU *cpu = env_archcpu(env);
+    const uint32_t modectl = cpu->globalregs ?
+        hexagon_globalreg_read(cpu->globalregs, HEX_SREG_MODECTL,
+                               env->threadId) : 0;
+    uint32_t thread_wait_mask = GET_FIELD(MODECTL_W, modectl);
+    thread_wait_mask |= 0x1 << env->threadId;
+    SET_SYSTEM_FIELD(env, HEX_SREG_MODECTL, MODECTL_W, thread_wait_mask);
+}
+
+static void hexagon_wait_thread(CPUHexagonState *env, uint32_t PC)
+{
+    g_assert(bql_locked());
+
+    if (qemu_loglevel_mask(LOG_GUEST_ERROR) &&
+        (env->k0_lock_state != HEX_LOCK_UNLOCKED ||
+         env->tlb_lock_state != HEX_LOCK_UNLOCKED)) {
+        qemu_log("WARNING: executing wait() with acquired lock"
+                 "may lead to deadlock\n");
+    }
+    g_assert(get_exe_mode(env) != HEX_EXE_MODE_WAIT);
+
+    CPUState *cs = env_cpu(env);
+    /*
+     * The addtion of cpu_has_work is borrowed from arm's wfi helper
+     * and is critical for our stability
+     */
+    if ((cs->exception_index != HEX_EVENT_NONE) ||
+        (cpu_has_work(cs))) {
+        qemu_log_mask(CPU_LOG_INT,
+            "%s: thread %d skipping WAIT mode, have some work\n",
+            __func__, env->threadId);
+        return;
+    }
+    set_wait_mode(env);
+    env->wait_next_pc = PC + 4;
+
+    cpu_interrupt(cs, CPU_INTERRUPT_HALT);
+}
+
+void HELPER(wait)(CPUHexagonState *env, uint32_t PC)
+{
+    BQL_LOCK_GUARD();
+
+    if (!fIN_DEBUG_MODE(env->threadId)) {
+        hexagon_wait_thread(env, PC);
+    }
 }
 
 void HELPER(resume)(CPUHexagonState *env, uint32_t mask)
-- 
2.34.1

Re: [PATCH v3 06/32] target/hexagon: Implement wait helper
Posted by Taylor Simpson 3 weeks, 5 days ago
On Tue, Mar 10, 2026 at 10:08 PM Brian Cain <brian.cain@oss.qualcomm.com>
wrote:

> From: Brian Cain <bcain@quicinc.com>
>
> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
>  target/hexagon/op_helper.c | 51 ++++++++++++++++++++++++++++++++++++--
>  1 file changed, 49 insertions(+), 2 deletions(-)
>
> diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
> index 161c7eaf31f..6dfc1269809 100644
> --- a/target/hexagon/op_helper.c
> +++ b/target/hexagon/op_helper.c
> @@ -1484,9 +1484,56 @@ void HELPER(stop)(CPUHexagonState *env)
>      hexagon_stop_thread(env);
>  }
>
> -void HELPER(wait)(CPUHexagonState *env, target_ulong PC)
> +static void set_wait_mode(CPUHexagonState *env)
>  {
> -    g_assert_not_reached();
> +    g_assert(bql_locked());
> +
> +    HexagonCPU *cpu = env_archcpu(env);
> +    const uint32_t modectl = cpu->globalregs ?
> +        hexagon_globalreg_read(cpu->globalregs, HEX_SREG_MODECTL,
> +                               env->threadId) : 0;
> +    uint32_t thread_wait_mask = GET_FIELD(MODECTL_W, modectl);
> +    thread_wait_mask |= 0x1 << env->threadId;
> +    SET_SYSTEM_FIELD(env, HEX_SREG_MODECTL, MODECTL_W, thread_wait_mask);
>

Do you want to set modectl when cpu->globalregs is false?


> +}
> +
> +static void hexagon_wait_thread(CPUHexagonState *env, uint32_t PC)
> +{
> +    g_assert(bql_locked());
> +
> +    if (qemu_loglevel_mask(LOG_GUEST_ERROR) &&
> +        (env->k0_lock_state != HEX_LOCK_UNLOCKED ||
> +         env->tlb_lock_state != HEX_LOCK_UNLOCKED)) {
> +        qemu_log("WARNING: executing wait() with acquired lock"
> +                 "may lead to deadlock\n");
> +    }
> +    g_assert(get_exe_mode(env) != HEX_EXE_MODE_WAIT);
> +
> +    CPUState *cs = env_cpu(env);
> +    /*
> +     * The addtion of cpu_has_work is borrowed from arm's wfi helper
> +     * and is critical for our stability
> +     */
> +    if ((cs->exception_index != HEX_EVENT_NONE) ||
> +        (cpu_has_work(cs))) {
> +        qemu_log_mask(CPU_LOG_INT,
> +            "%s: thread %d skipping WAIT mode, have some work\n",
>

Don't use %d


> +            __func__, env->threadId);
> +        return;
> +    }
> +    set_wait_mode(env);
> +    env->wait_next_pc = PC + 4;
> +
> +    cpu_interrupt(cs, CPU_INTERRUPT_HALT);
> +}
> +
> +void HELPER(wait)(CPUHexagonState *env, uint32_t PC)

+{
> +    BQL_LOCK_GUARD();
> +
> +    if (!fIN_DEBUG_MODE(env->threadId)) {
> +        hexagon_wait_thread(env, PC);
> +    }
>  }
>
>  void HELPER(resume)(CPUHexagonState *env, uint32_t mask)
> --
> 2.34.1
>

Otherwise
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>