Message ID | 20240711141851.406677-2-npiggin@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | ppc/pnv: Better big-core model, lpar-per-core, PC unit | expand |
On 7/11/24 16:18, Nicholas Piggin wrote: > POWER8 (ISA v2.07S) introduced the doorbell facility, the msgsnd > instruction behaved mostly like msgsndp, it was addressed by TIR > and could only send interrupts between threads on the core. > > ISA v3.0 changed msgsnd to be addressed by PIR and can interrupt > any thread in the system. > > msgsnd only implements the v3.0 semantics, which can make > multi-threaded POWER8 hang when booting Linux (due to IPIs > failing). This change adds v2.07 semantics. S-o-b is missing. Thanks, C. > --- > target/ppc/excp_helper.c | 74 ++++++++++++++++++++++++---------------- > 1 file changed, 44 insertions(+), 30 deletions(-) > > diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c > index 0cd542675f..c0120c8a88 100644 > --- a/target/ppc/excp_helper.c > +++ b/target/ppc/excp_helper.c > @@ -2998,6 +2998,41 @@ static inline bool dbell_bcast_subproc(target_ulong rb) > return (rb & DBELL_BRDCAST_MASK) == DBELL_BRDCAST_SUBPROC; > } > > +/* > + * Send an interrupt to a thread in the same core as env). > + */ > +static void msgsnd_core_tir(CPUPPCState *env, uint32_t target_tir, int irq) > +{ > + PowerPCCPU *cpu = env_archcpu(env); > + CPUState *cs = env_cpu(env); > + uint32_t nr_threads = cs->nr_threads; > + > + if (!(env->flags & POWERPC_FLAG_SMT_1LPAR)) { > + nr_threads = 1; /* msgsndp behaves as 1-thread in LPAR-per-thread mode*/ > + } > + > + if (target_tir >= nr_threads) { > + return; > + } > + > + if (nr_threads == 1) { > + ppc_set_irq(cpu, irq, 1); > + } else { > + CPUState *ccs; > + > + /* Does iothread need to be locked for walking CPU list? */ > + bql_lock(); > + THREAD_SIBLING_FOREACH(cs, ccs) { > + PowerPCCPU *ccpu = POWERPC_CPU(ccs); > + if (target_tir == ppc_cpu_tir(ccpu)) { > + ppc_set_irq(ccpu, irq, 1); > + break; > + } > + } > + bql_unlock(); > + } > +} > + > void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb) > { > if (!dbell_type_server(rb)) { > @@ -3018,6 +3053,13 @@ void helper_book3s_msgsnd(CPUPPCState *env, target_ulong rb) > return; > } > > + /* POWER8 msgsnd is like msgsndp (targets a thread within core) */ > + if (!(env->insns_flags2 & PPC2_ISA300)) { > + msgsnd_core_tir(env, rb & PPC_BITMASK(57, 63), PPC_INTERRUPT_HDOORBELL); > + return; > + } > + > + /* POWER9 and later msgsnd is a global (targets any thread) */ > cpu = ppc_get_vcpu_by_pir(pir); > if (!cpu) { > return; > @@ -3064,41 +3106,13 @@ void helper_book3s_msgclrp(CPUPPCState *env, target_ulong rb) > */ > void helper_book3s_msgsndp(CPUPPCState *env, target_ulong rb) > { > - CPUState *cs = env_cpu(env); > - PowerPCCPU *cpu = env_archcpu(env); > - 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); > > - if (!(env->flags & POWERPC_FLAG_SMT_1LPAR)) { > - nr_threads = 1; /* msgsndp behaves as 1-thread in LPAR-per-thread mode*/ > - } > - > - if (!dbell_type_server(rb) || ttir >= nr_threads) { > - return; > - } > - > - if (nr_threads == 1) { > - ppc_set_irq(cpu, PPC_INTERRUPT_DOORBELL, 1); > + if (!dbell_type_server(rb)) { > return; > } > > - /* Does iothread need to be locked for walking CPU list? */ > - bql_lock(); > - 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); > - bql_unlock(); > - return; > - } > - } > - > - g_assert_not_reached(); > + msgsnd_core_tir(env, rb & PPC_BITMASK(57, 63), PPC_INTERRUPT_DOORBELL); > } > #endif /* TARGET_PPC64 */ >
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 0cd542675f..c0120c8a88 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -2998,6 +2998,41 @@ static inline bool dbell_bcast_subproc(target_ulong rb) return (rb & DBELL_BRDCAST_MASK) == DBELL_BRDCAST_SUBPROC; } +/* + * Send an interrupt to a thread in the same core as env). + */ +static void msgsnd_core_tir(CPUPPCState *env, uint32_t target_tir, int irq) +{ + PowerPCCPU *cpu = env_archcpu(env); + CPUState *cs = env_cpu(env); + uint32_t nr_threads = cs->nr_threads; + + if (!(env->flags & POWERPC_FLAG_SMT_1LPAR)) { + nr_threads = 1; /* msgsndp behaves as 1-thread in LPAR-per-thread mode*/ + } + + if (target_tir >= nr_threads) { + return; + } + + if (nr_threads == 1) { + ppc_set_irq(cpu, irq, 1); + } else { + CPUState *ccs; + + /* Does iothread need to be locked for walking CPU list? */ + bql_lock(); + THREAD_SIBLING_FOREACH(cs, ccs) { + PowerPCCPU *ccpu = POWERPC_CPU(ccs); + if (target_tir == ppc_cpu_tir(ccpu)) { + ppc_set_irq(ccpu, irq, 1); + break; + } + } + bql_unlock(); + } +} + void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb) { if (!dbell_type_server(rb)) { @@ -3018,6 +3053,13 @@ void helper_book3s_msgsnd(CPUPPCState *env, target_ulong rb) return; } + /* POWER8 msgsnd is like msgsndp (targets a thread within core) */ + if (!(env->insns_flags2 & PPC2_ISA300)) { + msgsnd_core_tir(env, rb & PPC_BITMASK(57, 63), PPC_INTERRUPT_HDOORBELL); + return; + } + + /* POWER9 and later msgsnd is a global (targets any thread) */ cpu = ppc_get_vcpu_by_pir(pir); if (!cpu) { return; @@ -3064,41 +3106,13 @@ void helper_book3s_msgclrp(CPUPPCState *env, target_ulong rb) */ void helper_book3s_msgsndp(CPUPPCState *env, target_ulong rb) { - CPUState *cs = env_cpu(env); - PowerPCCPU *cpu = env_archcpu(env); - 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); - if (!(env->flags & POWERPC_FLAG_SMT_1LPAR)) { - nr_threads = 1; /* msgsndp behaves as 1-thread in LPAR-per-thread mode*/ - } - - if (!dbell_type_server(rb) || ttir >= nr_threads) { - return; - } - - if (nr_threads == 1) { - ppc_set_irq(cpu, PPC_INTERRUPT_DOORBELL, 1); + if (!dbell_type_server(rb)) { return; } - /* Does iothread need to be locked for walking CPU list? */ - bql_lock(); - 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); - bql_unlock(); - return; - } - } - - g_assert_not_reached(); + msgsnd_core_tir(env, rb & PPC_BITMASK(57, 63), PPC_INTERRUPT_DOORBELL); } #endif /* TARGET_PPC64 */