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 */
>