target/ppc: Add msgsnd/p and DPDES SMT support

Doorbells in SMT need to coordinate msgsnd/msgclr and DPDES access from
multiple threads that affect the same state.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
master
Nicholas Piggin 2023-06-22 19:33:53 +10:00 committed by Cédric Le Goater
parent c5d98a7b3d
commit d24e80b2ae
5 changed files with 78 additions and 11 deletions

View File

@ -1436,6 +1436,12 @@ int ppc_cpu_pir(PowerPCCPU *cpu)
return env->spr_cb[SPR_PIR].default_value; return env->spr_cb[SPR_PIR].default_value;
} }
int ppc_cpu_tir(PowerPCCPU *cpu)
{
CPUPPCState *env = &cpu->env;
return env->spr_cb[SPR_TIR].default_value;
}
PowerPCCPU *ppc_get_vcpu_by_pir(int pir) PowerPCCPU *ppc_get_vcpu_by_pir(int pir)
{ {
CPUState *cs; CPUState *cs;

View File

@ -6,6 +6,7 @@
void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level); void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level);
PowerPCCPU *ppc_get_vcpu_by_pir(int pir); PowerPCCPU *ppc_get_vcpu_by_pir(int pir);
int ppc_cpu_pir(PowerPCCPU *cpu); int ppc_cpu_pir(PowerPCCPU *cpu);
int ppc_cpu_tir(PowerPCCPU *cpu);
/* PowerPC hardware exceptions management helpers */ /* PowerPC hardware exceptions management helpers */
typedef void (*clk_setup_cb)(void *opaque, uint32_t freq); typedef void (*clk_setup_cb)(void *opaque, uint32_t freq);

View File

@ -3186,22 +3186,42 @@ void helper_book3s_msgclrp(CPUPPCState *env, target_ulong rb)
} }
/* /*
* sends a message to other threads that are on the same * sends a message to another thread on the same
* multi-threaded processor * multi-threaded processor
*/ */
void helper_book3s_msgsndp(CPUPPCState *env, target_ulong rb) void helper_book3s_msgsndp(CPUPPCState *env, target_ulong rb)
{ {
int pir = env->spr_cb[SPR_PIR].default_value; CPUState *cs = env_cpu(env);
PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUState *ccs;
uint32_t nr_threads = cs->nr_threads;
int ttir = rb & PPC_BITMASK(57, 63);
helper_hfscr_facility_check(env, HFSCR_MSGP, "msgsndp", HFSCR_IC_MSGP); helper_hfscr_facility_check(env, HFSCR_MSGP, "msgsndp", HFSCR_IC_MSGP);
if (!dbell_type_server(rb)) { if (!dbell_type_server(rb) || ttir >= nr_threads) {
return; return;
} }
/* TODO: TCG supports only one thread */ if (nr_threads == 1) {
ppc_set_irq(cpu, PPC_INTERRUPT_DOORBELL, 1);
return;
}
book3s_msgsnd_common(pir, PPC_INTERRUPT_DOORBELL); /* Does iothread need to be locked for walking CPU list? */
qemu_mutex_lock_iothread();
THREAD_SIBLING_FOREACH(cs, ccs) {
PowerPCCPU *ccpu = POWERPC_CPU(ccs);
uint32_t thread_id = ppc_cpu_tir(ccpu);
if (ttir == thread_id) {
ppc_set_irq(ccpu, PPC_INTERRUPT_DOORBELL, 1);
qemu_mutex_unlock_iothread();
return;
}
}
g_assert_not_reached();
} }
#endif /* TARGET_PPC64 */ #endif /* TARGET_PPC64 */

View File

@ -184,32 +184,64 @@ void helper_store_pcr(CPUPPCState *env, target_ulong value)
*/ */
target_ulong helper_load_dpdes(CPUPPCState *env) target_ulong helper_load_dpdes(CPUPPCState *env)
{ {
CPUState *cs = env_cpu(env);
CPUState *ccs;
uint32_t nr_threads = cs->nr_threads;
target_ulong dpdes = 0; target_ulong dpdes = 0;
helper_hfscr_facility_check(env, HFSCR_MSGP, "load DPDES", HFSCR_IC_MSGP); helper_hfscr_facility_check(env, HFSCR_MSGP, "load DPDES", HFSCR_IC_MSGP);
/* TODO: TCG supports only one thread */ if (nr_threads == 1) {
if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) { if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
dpdes = 1; dpdes = 1;
}
return dpdes;
} }
qemu_mutex_lock_iothread();
THREAD_SIBLING_FOREACH(cs, ccs) {
PowerPCCPU *ccpu = POWERPC_CPU(ccs);
CPUPPCState *cenv = &ccpu->env;
uint32_t thread_id = ppc_cpu_tir(ccpu);
if (cenv->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
dpdes |= (0x1 << thread_id);
}
}
qemu_mutex_unlock_iothread();
return dpdes; return dpdes;
} }
void helper_store_dpdes(CPUPPCState *env, target_ulong val) void helper_store_dpdes(CPUPPCState *env, target_ulong val)
{ {
PowerPCCPU *cpu = env_archcpu(env); PowerPCCPU *cpu = env_archcpu(env);
CPUState *cs = env_cpu(env);
CPUState *ccs;
uint32_t nr_threads = cs->nr_threads;
helper_hfscr_facility_check(env, HFSCR_MSGP, "store DPDES", HFSCR_IC_MSGP); helper_hfscr_facility_check(env, HFSCR_MSGP, "store DPDES", HFSCR_IC_MSGP);
/* TODO: TCG supports only one thread */ if (val & ~(nr_threads - 1)) {
if (val & ~0x1) {
qemu_log_mask(LOG_GUEST_ERROR, "Invalid DPDES register value " qemu_log_mask(LOG_GUEST_ERROR, "Invalid DPDES register value "
TARGET_FMT_lx"\n", val); TARGET_FMT_lx"\n", val);
val &= (nr_threads - 1); /* Ignore the invalid bits */
}
if (nr_threads == 1) {
ppc_set_irq(cpu, PPC_INTERRUPT_DOORBELL, val & 0x1);
return; return;
} }
ppc_set_irq(cpu, PPC_INTERRUPT_DOORBELL, val & 0x1); /* Does iothread need to be locked for walking CPU list? */
qemu_mutex_lock_iothread();
THREAD_SIBLING_FOREACH(cs, ccs) {
PowerPCCPU *ccpu = POWERPC_CPU(ccs);
uint32_t thread_id = ppc_cpu_tir(ccpu);
ppc_set_irq(cpu, PPC_INTERRUPT_DOORBELL, val & (0x1 << thread_id));
}
qemu_mutex_unlock_iothread();
} }
#endif /* defined(TARGET_PPC64) */ #endif /* defined(TARGET_PPC64) */

View File

@ -815,11 +815,19 @@ void spr_write_pcr(DisasContext *ctx, int sprn, int gprn)
/* DPDES */ /* DPDES */
void spr_read_dpdes(DisasContext *ctx, int gprn, int sprn) void spr_read_dpdes(DisasContext *ctx, int gprn, int sprn)
{ {
if (!gen_serialize_core(ctx)) {
return;
}
gen_helper_load_dpdes(cpu_gpr[gprn], cpu_env); gen_helper_load_dpdes(cpu_gpr[gprn], cpu_env);
} }
void spr_write_dpdes(DisasContext *ctx, int sprn, int gprn) void spr_write_dpdes(DisasContext *ctx, int sprn, int gprn)
{ {
if (!gen_serialize_core(ctx)) {
return;
}
gen_helper_store_dpdes(cpu_env, cpu_gpr[gprn]); gen_helper_store_dpdes(cpu_env, cpu_gpr[gprn]);
} }
#endif #endif