]> git.baikalelectronics.ru Git - kernel.git/commitdiff
KVM: PPC: Book3S HV: XIVE: Add support for automatic save-restore
authorCédric Le Goater <clg@kaod.org>
Tue, 20 Jul 2021 13:42:09 +0000 (15:42 +0200)
committerMichael Ellerman <mpe@ellerman.id.au>
Tue, 10 Aug 2021 13:15:02 +0000 (23:15 +1000)
On P10, the feature doing an automatic "save & restore" of a VCPU
interrupt context is set by default in OPAL. When a VP context is
pulled out, the state of the interrupt registers are saved by the XIVE
interrupt controller under the internal NVP structure representing the
VP. This saves a costly store/load in guest entries and exits.

If OPAL advertises the "save & restore" feature in the device tree,
it should also have set the 'H' bit in the CAM line. Check that when
vCPUs are connected to their ICP in KVM before going any further.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20210720134209.256133-3-clg@kaod.org
arch/powerpc/include/asm/xive-regs.h
arch/powerpc/include/asm/xive.h
arch/powerpc/kvm/book3s_xive.c
arch/powerpc/kvm/book3s_xive.h
arch/powerpc/kvm/book3s_xive_native.c
arch/powerpc/sysdev/xive/native.c

index 8b211faa0e4293c5e7ce02339ab485baa6cfea9b..cf8bb6ac4463c1c4da4f86ef9b4eef9e403b9760 100644 (file)
 #define   TM_QW0W2_VU          PPC_BIT32(0)
 #define   TM_QW0W2_LOGIC_SERV  PPC_BITMASK32(1,31) // XX 2,31 ?
 #define   TM_QW1W2_VO          PPC_BIT32(0)
+#define   TM_QW1W2_HO           PPC_BIT32(1) /* P10 XIVE2 */
 #define   TM_QW1W2_OS_CAM      PPC_BITMASK32(8,31)
 #define   TM_QW2W2_VP          PPC_BIT32(0)
+#define   TM_QW2W2_HP           PPC_BIT32(1) /* P10 XIVE2 */
 #define   TM_QW2W2_POOL_CAM    PPC_BITMASK32(8,31)
 #define   TM_QW3W2_VT          PPC_BIT32(0)
+#define   TM_QW3W2_HT           PPC_BIT32(1) /* P10 XIVE2 */
 #define   TM_QW3W2_LP          PPC_BIT32(6)
 #define   TM_QW3W2_LE          PPC_BIT32(7)
 #define   TM_QW3W2_T           PPC_BIT32(31)
index 20ae50ab083c58efd152ee964ac7658c4040a07d..92930b0b5d0e17bcd7ec834fc1ce0c03c66b0a4e 100644 (file)
@@ -126,6 +126,7 @@ int xive_native_enable_vp(u32 vp_id, bool single_escalation);
 int xive_native_disable_vp(u32 vp_id);
 int xive_native_get_vp_info(u32 vp_id, u32 *out_cam_id, u32 *out_chip_id);
 bool xive_native_has_single_escalation(void);
+bool xive_native_has_save_restore(void);
 
 int xive_native_get_queue_info(u32 vp_id, uint32_t prio,
                               u64 *out_qpage,
index 555cc610e7ab7524116ea9f237c6805acd2fe5d8..912c1e9eef6b4302295fa976eeddbff22a21eb20 100644 (file)
  */
 #define XIVE_Q_GAP     2
 
+static bool kvmppc_xive_vcpu_has_save_restore(struct kvm_vcpu *vcpu)
+{
+       struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
+
+       /* Check enablement at VP level */
+       return xc->vp_cam & TM_QW1W2_HO;
+}
+
+bool kvmppc_xive_check_save_restore(struct kvm_vcpu *vcpu)
+{
+       struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
+       struct kvmppc_xive *xive = xc->xive;
+
+       if (xive->flags & KVMPPC_XIVE_FLAG_SAVE_RESTORE)
+               return kvmppc_xive_vcpu_has_save_restore(vcpu);
+
+       return true;
+}
+
 /*
  * Push a vcpu's context to the XIVE on guest entry.
  * This assumes we are in virtual mode (MMU on)
@@ -77,7 +96,8 @@ void kvmppc_xive_push_vcpu(struct kvm_vcpu *vcpu)
                return;
 
        eieio();
-       __raw_writeq(vcpu->arch.xive_saved_state.w01, tima + TM_QW1_OS);
+       if (!kvmppc_xive_vcpu_has_save_restore(vcpu))
+               __raw_writeq(vcpu->arch.xive_saved_state.w01, tima + TM_QW1_OS);
        __raw_writel(vcpu->arch.xive_cam_word, tima + TM_QW1_OS + TM_WORD2);
        vcpu->arch.xive_pushed = 1;
        eieio();
@@ -149,7 +169,8 @@ void kvmppc_xive_pull_vcpu(struct kvm_vcpu *vcpu)
        /* First load to pull the context, we ignore the value */
        __raw_readl(tima + TM_SPC_PULL_OS_CTX);
        /* Second load to recover the context state (Words 0 and 1) */
-       vcpu->arch.xive_saved_state.w01 = __raw_readq(tima + TM_QW1_OS);
+       if (!kvmppc_xive_vcpu_has_save_restore(vcpu))
+               vcpu->arch.xive_saved_state.w01 = __raw_readq(tima + TM_QW1_OS);
 
        /* Fixup some of the state for the next load */
        vcpu->arch.xive_saved_state.lsmfb = 0;
@@ -1319,6 +1340,12 @@ int kvmppc_xive_connect_vcpu(struct kvm_device *dev,
        if (r)
                goto bail;
 
+       if (!kvmppc_xive_check_save_restore(vcpu)) {
+               pr_err("inconsistent save-restore setup for VCPU %d\n", cpu);
+               r = -EIO;
+               goto bail;
+       }
+
        /* Configure VCPU fields for use by assembly push/pull */
        vcpu->arch.xive_saved_state.w01 = cpu_to_be64(0xff000000);
        vcpu->arch.xive_cam_word = cpu_to_be32(xc->vp_cam | TM_QW1W2_VO);
@@ -2138,6 +2165,9 @@ static int kvmppc_xive_create(struct kvm_device *dev, u32 type)
        if (xive_native_has_single_escalation())
                xive->flags |= KVMPPC_XIVE_FLAG_SINGLE_ESCALATION;
 
+       if (xive_native_has_save_restore())
+               xive->flags |= KVMPPC_XIVE_FLAG_SAVE_RESTORE;
+
        kvm->arch.xive = xive;
        return 0;
 }
index 73c3cd25093ce6255811b5a70e7ed24eae683b13..e6a9651c6f1e2c04a1414231629700495cee00d0 100644 (file)
@@ -98,6 +98,7 @@ struct kvmppc_xive_ops {
 };
 
 #define KVMPPC_XIVE_FLAG_SINGLE_ESCALATION 0x1
+#define KVMPPC_XIVE_FLAG_SAVE_RESTORE 0x2
 
 struct kvmppc_xive {
        struct kvm *kvm;
@@ -309,6 +310,7 @@ void xive_cleanup_single_escalation(struct kvm_vcpu *vcpu,
                                    struct kvmppc_xive_vcpu *xc, int irq);
 int kvmppc_xive_compute_vp_id(struct kvmppc_xive *xive, u32 cpu, u32 *vp);
 int kvmppc_xive_set_nr_servers(struct kvmppc_xive *xive, u64 addr);
+bool kvmppc_xive_check_save_restore(struct kvm_vcpu *vcpu);
 
 static inline bool kvmppc_xive_has_single_escalation(struct kvmppc_xive *xive)
 {
index 2abb1358a268379854acc725a1a023bae810bd55..af65ea21bde7cc7ac6f48391d2892dc2111f3b46 100644 (file)
@@ -168,6 +168,12 @@ int kvmppc_xive_native_connect_vcpu(struct kvm_device *dev,
                goto bail;
        }
 
+       if (!kvmppc_xive_check_save_restore(vcpu)) {
+               pr_err("inconsistent save-restore setup for VCPU %d\n", server_num);
+               rc = -EIO;
+               goto bail;
+       }
+
        /*
         * Enable the VP first as the single escalation mode will
         * affect escalation interrupts numbering
@@ -1114,6 +1120,9 @@ static int kvmppc_xive_native_create(struct kvm_device *dev, u32 type)
        if (xive_native_has_single_escalation())
                xive->flags |= KVMPPC_XIVE_FLAG_SINGLE_ESCALATION;
 
+       if (xive_native_has_save_restore())
+               xive->flags |= KVMPPC_XIVE_FLAG_SAVE_RESTORE;
+
        xive->ops = &kvmppc_xive_native_ops;
 
        kvm->arch.xive = xive;
index 57e3f15404354601d44f8cb7228b06df8c41a396..1aec282cd650d0b798fb5d1791dd7840c3500d80 100644 (file)
@@ -41,6 +41,7 @@ static u32 xive_queue_shift;
 static u32 xive_pool_vps = XIVE_INVALID_VP;
 static struct kmem_cache *xive_provision_cache;
 static bool xive_has_single_esc;
+static bool xive_has_save_restore;
 
 int xive_native_populate_irq_data(u32 hw_irq, struct xive_irq_data *data)
 {
@@ -588,6 +589,9 @@ bool __init xive_native_init(void)
        if (of_get_property(np, "single-escalation-support", NULL) != NULL)
                xive_has_single_esc = true;
 
+       if (of_get_property(np, "vp-save-restore", NULL))
+               xive_has_save_restore = true;
+
        /* Configure Thread Management areas for KVM */
        for_each_possible_cpu(cpu)
                kvmppc_set_xive_tima(cpu, r.start, tima);
@@ -752,6 +756,12 @@ bool xive_native_has_single_escalation(void)
 }
 EXPORT_SYMBOL_GPL(xive_native_has_single_escalation);
 
+bool xive_native_has_save_restore(void)
+{
+       return xive_has_save_restore;
+}
+EXPORT_SYMBOL_GPL(xive_native_has_save_restore);
+
 int xive_native_get_queue_info(u32 vp_id, u32 prio,
                               u64 *out_qpage,
                               u64 *out_qsize,