return 0;
 }
 
-static void smp_pseries_cause_ipi(int cpu)
+/* Cause IPI as setup by the interrupt controller (xics or xive) */
+static void (*ic_cause_ipi)(int cpu) __ro_after_init;
+
+/* Use msgsndp doorbells target is a sibling, else use interrupt controller */
+static void dbell_or_ic_cause_ipi(int cpu)
 {
-       /* POWER9 should not use this handler */
        if (doorbell_try_core_ipi(cpu))
                return;
 
-       icp_ops->cause_ipi(cpu);
+       ic_cause_ipi(cpu);
 }
 
 static int pseries_cause_nmi_ipi(int cpu)
        return 0;
 }
 
-static __init void pSeries_smp_probe_xics(void)
-{
-       xics_smp_probe();
-
-       if (cpu_has_feature(CPU_FTR_DBELL) && !is_secure_guest())
-               smp_ops->cause_ipi = smp_pseries_cause_ipi;
-       else
-               smp_ops->cause_ipi = icp_ops->cause_ipi;
-}
-
 static __init void pSeries_smp_probe(void)
 {
        if (xive_enabled())
-               /*
-                * Don't use P9 doorbells when XIVE is enabled. IPIs
-                * using MMIOs should be faster
-                */
                xive_smp_probe();
        else
-               pSeries_smp_probe_xics();
+               xics_smp_probe();
+
+       /* No doorbell facility, must use the interrupt controller for IPIs */
+       if (!cpu_has_feature(CPU_FTR_DBELL))
+               return;
+
+       /* Doorbells can only be used for IPIs between SMT siblings */
+       if (!cpu_has_feature(CPU_FTR_SMT))
+               return;
+
+       /*
+        * KVM emulates doorbells by disabling FSCR[MSGP] so msgsndp faults
+        * to the hypervisor which then reads the instruction from guest
+        * memory. This can't be done if the guest is secure, so don't use
+        * doorbells in secure guests.
+        *
+        * Under PowerVM, FSCR[MSGP] is enabled so doorbells could be used
+        * by secure guests if we distinguished this from KVM.
+        */
+       if (is_secure_guest())
+               return;
+
+       /*
+        * The guest can use doobells for SMT sibling IPIs, which stay in
+        * the core rather than going to the interrupt controller. This
+        * tends to be slower under KVM where doorbells are emulated, but
+        * faster for PowerVM where they're enabled.
+        */
+       ic_cause_ipi = smp_ops->cause_ipi;
+       smp_ops->cause_ipi = dbell_or_ic_cause_ipi;
 }
 
 static struct smp_ops_t pseries_smp_ops = {