diff options
author | Alistair Francis | 2019-04-20 04:26:54 +0200 |
---|---|---|
committer | Palmer Dabbelt | 2019-05-24 21:09:24 +0200 |
commit | 0a01f2eecba47a48c9d06e3fb9acbd2a8a842cfc (patch) | |
tree | b68ccceb76bda361e2dfedec4fe55fe34040acbe /target/riscv | |
parent | target/riscv: Mark privilege level 2 as reserved (diff) | |
download | qemu-0a01f2eecba47a48c9d06e3fb9acbd2a8a842cfc.tar.gz qemu-0a01f2eecba47a48c9d06e3fb9acbd2a8a842cfc.tar.xz qemu-0a01f2eecba47a48c9d06e3fb9acbd2a8a842cfc.zip |
target/riscv: Trigger interrupt on MIP update asynchronously
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.francis@wdc.com>
Reviewed-by: Palmer Dabbelt <palmer@sifive.com>
Signed-off-by: Palmer Dabbelt <palmer@sifive.com>
Diffstat (limited to 'target/riscv')
-rw-r--r-- | target/riscv/cpu_helper.c | 33 | ||||
-rw-r--r-- | 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 41d6db41c3..7318da289f 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 e1d91b6c60..f9d8d150e0 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); } |