diff options
author | Cédric Le Goater <clg@kaod.org> | 2018-01-18 15:54:03 +0100 |
---|---|---|
committer | David Gibson <david@gibson.dropbear.id.au> | 2018-01-20 17:15:05 +1100 |
commit | 7af1e7b022641e4cc330a75ab50fa64683fe4847 (patch) | |
tree | df50949b9f51441a74eb47417d56219d3635e968 /target/ppc/excp_helper.c | |
parent | 3a14ba466488fc717dccd4429487295d79fe0775 (diff) |
target/ppc: add support for hypervisor doorbells on book3s CPUs
The hypervisor doorbells are used by skiboot and Linux on POWER9
processors to wake up secondaries.
This adds processor control support to the Server architecture by
reusing the Embedded support. They are very similar, only the bits
definition of the CPU identifier differ.
Still to be done is message broadcast to all threads of the same
processor.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Diffstat (limited to 'target/ppc/excp_helper.c')
-rw-r--r-- | target/ppc/excp_helper.c | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 4e548a4487..c092fbead0 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -417,6 +417,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */ + case POWERPC_EXCP_SDOOR_HV: /* Hypervisor Doorbell interrupt */ case POWERPC_EXCP_HV_EMU: srr0 = SPR_HSRR0; srr1 = SPR_HSRR1; @@ -846,6 +847,11 @@ static void ppc_hw_interrupt(CPUPPCState *env) powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI); return; } + if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDOORBELL)) { + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDOORBELL); + powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_SDOOR_HV); + return; + } if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) { env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM); powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM); @@ -1145,4 +1151,50 @@ void helper_msgsnd(target_ulong rb) } qemu_mutex_unlock_iothread(); } + +/* Server Processor Control */ +static int book3s_dbell2irq(target_ulong rb) +{ + int msg = rb & DBELL_TYPE_MASK; + + /* A Directed Hypervisor Doorbell message is sent only if the + * message type is 5. All other types are reserved and the + * instruction is a no-op */ + return msg == DBELL_TYPE_DBELL_SERVER ? PPC_INTERRUPT_HDOORBELL : -1; +} + +void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb) +{ + int irq = book3s_dbell2irq(rb); + + if (irq < 0) { + return; + } + + env->pending_interrupts &= ~(1 << irq); +} + +void helper_book3s_msgsnd(target_ulong rb) +{ + int irq = book3s_dbell2irq(rb); + int pir = rb & DBELL_PROCIDTAG_MASK; + CPUState *cs; + + if (irq < 0) { + return; + } + + qemu_mutex_lock_iothread(); + CPU_FOREACH(cs) { + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *cenv = &cpu->env; + + /* TODO: broadcast message to all threads of the same processor */ + if (cenv->spr_cb[SPR_PIR].default_value == pir) { + cenv->pending_interrupts |= 1 << irq; + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + } + } + qemu_mutex_unlock_iothread(); +} #endif |