From: Alistair Francis <alistair.fran...@wdc.com> The requirement of holding the iothread_mutex is burdersome when swapping the background and foreground registers in the Hypervisor extension. To avoid the requrirement let's set the interrupt asynchronously.
Signed-off-by: Alistair Francis <alistair.fran...@wdc.com> Reviewed-by: Palmer Dabbelt <pal...@sifive.com> Signed-off-by: Palmer Dabbelt <pal...@sifive.com> --- target/riscv/cpu_helper.c | 33 +++++++++++++++++++++++++++------ target/riscv/csr.c | 2 -- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 41d6db41c3dd..7318da289f6e 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -82,10 +82,31 @@ int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts) } } -/* iothread_mutex must be held */ +struct CpuAsyncInfo { + uint32_t new_mip; +}; + +static void riscv_cpu_update_mip_irqs_async(CPUState *target_cpu_state, + run_on_cpu_data data) +{ + CPURISCVState *env = &RISCV_CPU(target_cpu_state)->env; + RISCVCPU *cpu = riscv_env_get_cpu(env); + struct CpuAsyncInfo *info = (struct CpuAsyncInfo *) data.host_ptr; + + if (info->new_mip) { + cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); + } + + g_free(info); +} + uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value) { CPURISCVState *env = &cpu->env; + CPUState *cs = CPU(cpu); + struct CpuAsyncInfo *info; uint32_t old, new, cmp = atomic_read(&env->mip); do { @@ -94,11 +115,11 @@ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value) cmp = atomic_cmpxchg(&env->mip, old, new); } while (old != cmp); - if (new) { - cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); - } else { - cpu_reset_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); - } + info = g_new(struct CpuAsyncInfo, 1); + info->new_mip = new; + + async_run_on_cpu(cs, riscv_cpu_update_mip_irqs_async, + RUN_ON_CPU_HOST_PTR(info)); return old; } diff --git a/target/riscv/csr.c b/target/riscv/csr.c index e1d91b6c6049..f9d8d150e012 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -555,9 +555,7 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value, uint32_t old_mip; if (mask) { - qemu_mutex_lock_iothread(); old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); - qemu_mutex_unlock_iothread(); } else { old_mip = atomic_read(&env->mip); } -- 2.21.0