On Mon, Mar 16, 2026 at 11:49 AM Taylor Simpson
<ltaylorsimpson@gmail.com> wrote:
>
>
>
> On Tue, Mar 10, 2026 at 10:08 PM Brian Cain <brian.cain@oss.qualcomm.com> wrote:
>>
>> From: Brian Cain <bcain@quicinc.com>
>>
>> The hardware-assisted scheduler helps manage tasks on the run queue
>> and interrupt steering.
>>
>> This instruction is defined in the Qualcomm Hexagon V71 Programmer's Reference
>> Manual -
>> https://docs.qualcomm.com/bundle/publicresource/80-N2040-51_REV_AB_Hexagon_V71_ProgrammerS_Reference_Manual.pdf
>> See §11.9.2 SYSTEM MONITOR.
>
>
> This document doesn't have a section 11.9.2.
>
>>
>>
>> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
>> ---
>> target/hexagon/op_helper.c | 75 ++++++++++++++++++++++++++++++++++++++
>> 1 file changed, 75 insertions(+)
>>
>> diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
>> index 9090a5c20ab..36822219b4b 100644
>> --- a/target/hexagon/op_helper.c
>> +++ b/target/hexagon/op_helper.c
>> @@ -1575,6 +1575,62 @@ static void hexagon_wait_thread(CPUHexagonState *env, uint32_t PC)
>> cpu_interrupt(cs, CPU_INTERRUPT_HALT);
>> }
>>
>> +static inline QEMU_ALWAYS_INLINE void resched(CPUHexagonState *env)
>> +{
>> + uint32_t schedcfg;
>> + uint32_t schedcfg_en;
>> + int int_number;
>> + CPUState *cs;
>> + uint32_t lowest_th_prio = 0; /* 0 is highest prio */
>> + uint32_t bestwait_reg;
>> + uint32_t best_prio;
>> +
>> + BQL_LOCK_GUARD();
>> + qemu_log_mask(CPU_LOG_INT, "%s: check resched\n", __func__);
>> + HexagonCPU *cpu = env_archcpu(env);
>> + schedcfg = cpu->globalregs ?
>> + hexagon_globalreg_read(cpu->globalregs, HEX_SREG_SCHEDCFG,
>> + env->threadId) : 0;
>> + schedcfg_en = GET_FIELD(SCHEDCFG_EN, schedcfg);
>> + int_number = GET_FIELD(SCHEDCFG_INTNO, schedcfg);
>> +
>> + if (!schedcfg_en) {
>> + return;
>> + }
>> +
>> + CPU_FOREACH(cs) {
>> + HexagonCPU *thread = HEXAGON_CPU(cs);
>> + CPUHexagonState *thread_env = &(thread->env);
>> + uint32_t th_prio = GET_FIELD(
>> + STID_PRIO, thread_env->t_sreg[HEX_SREG_STID]);
>> + if (!hexagon_thread_is_enabled(thread_env)) {
>> + continue;
>> + }
>> +
>> + lowest_th_prio = (lowest_th_prio > th_prio)
>> + ? lowest_th_prio
>> + : th_prio;
>> + }
>> +
>> + bestwait_reg = cpu->globalregs ?
>> + hexagon_globalreg_read(cpu->globalregs, HEX_SREG_BESTWAIT,
>> + env->threadId) : 0;
>> + best_prio = GET_FIELD(BESTWAIT_PRIO, bestwait_reg);
>> +
>> + /*
>> + * If the lowest priority thread is lower priority than the
>> + * value in the BESTWAIT register, we must raise the reschedule
>> + * interrupt on the lowest priority thread.
>> + */
>> + if (lowest_th_prio > best_prio) {
>> + qemu_log_mask(CPU_LOG_INT,
>> + "%s: raising resched int %d, cur PC 0x" TARGET_FMT_lx "\n",
>
>
> Don't use %d
>
>>
>> + __func__, int_number, env->gpr[HEX_REG_PC]);
>> + SET_SYSTEM_FIELD(env, HEX_SREG_BESTWAIT, BESTWAIT_PRIO, ~0);
>
>
> Is ~0 the correct value here? Seems like it should be best_prio.
As tasks wait, the kernel can update the mutable BESTWAIT:PRIO field.
But when the scheduler is activated, then the bestwait priority resets.
>> + hex_raise_interrupts(env, 1 << int_number, CPU_INTERRUPT_SWI);
>> + }
>> +}
>> +
>> void HELPER(wait)(CPUHexagonState *env, uint32_t PC)
>> {
>> BQL_LOCK_GUARD();
>> @@ -1680,8 +1736,27 @@ uint64_t HELPER(greg_read_pair)(CPUHexagonState *env, uint32_t reg)
>> g_assert_not_reached();
>> }
>>
>> +/*
>> + * setprio/resched - See the Hexagon V73 Programmer's Reference Manual,
>> + * Section 6.4 "Interrupt and Thread Scheduling"
>
>
> Neither the V71 (mentioned above) or V73 PRM contain section 6.4.
I'll remove the section number references to avoid confusion,
especially since they're not stable.
>> + */
>> void HELPER(setprio)(CPUHexagonState *env, uint32_t thread, uint32_t prio)
>> {
>> + CPUState *cs;
>> +
>> + BQL_LOCK_GUARD();
>> + CPU_FOREACH(cs) {
>> + HexagonCPU *found_cpu = HEXAGON_CPU(cs);
>> + CPUHexagonState *found_env = &found_cpu->env;
>> + if (thread == found_env->threadId) {
>> + SET_SYSTEM_FIELD(found_env, HEX_SREG_STID, STID_PRIO, prio);
>> + qemu_log_mask(CPU_LOG_INT,
>> + "%s: tid " TARGET_FMT_lx " prio = 0x%x\n",
>
>
> Don't use %x
>
>>
>> + __func__, found_env->threadId, prio);
>> + resched(env);
>> + return;
>> + }
>> + }
>> g_assert_not_reached();
>> }
>>
>> --
>> 2.34.1
>>