KVM: PPC: Book3S HV: XIVE: Add get/set accessors for the VP XIVE state
authorCédric Le Goater <clg@kaod.org>
Thu, 18 Apr 2019 10:39:35 +0000 (12:39 +0200)
committerPaul Mackerras <paulus@ozlabs.org>
Tue, 30 Apr 2019 09:35:16 +0000 (19:35 +1000)
The state of the thread interrupt management registers needs to be
collected for migration. These registers are cached under the
'xive_saved_state.w01' field of the VCPU when the VPCU context is
pulled from the HW thread. An OPAL call retrieves the backup of the
IPB register in the underlying XIVE NVT structure and merges it in the
KVM state.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
Documentation/virtual/kvm/api.txt
Documentation/virtual/kvm/devices/xive.txt
arch/powerpc/include/asm/kvm_ppc.h
arch/powerpc/include/uapi/asm/kvm.h
arch/powerpc/kvm/book3s.c
arch/powerpc/kvm/book3s_xive_native.c

index e38eb17b7be60f4f6de16f5d08855fbe507a4655..5b505520a616e8f7319b27a38ce4fdd28ddc4e32 100644 (file)
@@ -1985,6 +1985,7 @@ registers, find a list below:
   PPC   | KVM_REG_PPC_TLB3PS            | 32
   PPC   | KVM_REG_PPC_EPTCFG            | 32
   PPC   | KVM_REG_PPC_ICP_STATE         | 64
+  PPC   | KVM_REG_PPC_VP_STATE          | 128
   PPC   | KVM_REG_PPC_TB_OFFSET         | 64
   PPC   | KVM_REG_PPC_SPMC1             | 32
   PPC   | KVM_REG_PPC_SPMC2             | 32
index 7ffd4c7be7b5164926312a2d0708107683432503..525d1eebcf34a3ef1af7604ae18622fe4f0d22d4 100644 (file)
@@ -107,6 +107,23 @@ the legacy interrupt mode, referred as XICS (POWER7/8).
     -ENOENT: Unknown source number
     -EINVAL: Not initialized source number
 
+* VCPU state
+
+  The XIVE IC maintains VP interrupt state in an internal structure
+  called the NVT. When a VP is not dispatched on a HW processor
+  thread, this structure can be updated by HW if the VP is the target
+  of an event notification.
+
+  It is important for migration to capture the cached IPB from the NVT
+  as it synthesizes the priorities of the pending interrupts. We
+  capture a bit more to report debug information.
+
+  KVM_REG_PPC_VP_STATE (2 * 64bits)
+  bits:     |  63  ....  32  |  31  ....  0  |
+  values:   |   TIMA word0   |   TIMA word1  |
+  bits:     | 127       ..........       64  |
+  values:   |            unused              |
+
 * Migration:
 
   Saving the state of a VM using the XIVE native exploitation mode
index 9fc2753e516e3224c5a2549b45edbbee4bbfc02f..bc892380e6cd543d5b757690bcc110b77e2c008c 100644 (file)
@@ -269,6 +269,7 @@ union kvmppc_one_reg {
                u64     addr;
                u64     length;
        }       vpaval;
+       u64     xive_timaval[2];
 };
 
 struct kvmppc_ops {
@@ -604,6 +605,10 @@ extern int kvmppc_xive_native_connect_vcpu(struct kvm_device *dev,
 extern void kvmppc_xive_native_cleanup_vcpu(struct kvm_vcpu *vcpu);
 extern void kvmppc_xive_native_init_module(void);
 extern void kvmppc_xive_native_exit_module(void);
+extern int kvmppc_xive_native_get_vp(struct kvm_vcpu *vcpu,
+                                    union kvmppc_one_reg *val);
+extern int kvmppc_xive_native_set_vp(struct kvm_vcpu *vcpu,
+                                    union kvmppc_one_reg *val);
 
 #else
 static inline int kvmppc_xive_set_xive(struct kvm *kvm, u32 irq, u32 server,
@@ -636,6 +641,12 @@ static inline int kvmppc_xive_native_connect_vcpu(struct kvm_device *dev,
 static inline void kvmppc_xive_native_cleanup_vcpu(struct kvm_vcpu *vcpu) { }
 static inline void kvmppc_xive_native_init_module(void) { }
 static inline void kvmppc_xive_native_exit_module(void) { }
+static inline int kvmppc_xive_native_get_vp(struct kvm_vcpu *vcpu,
+                                           union kvmppc_one_reg *val)
+{ return 0; }
+static inline int kvmppc_xive_native_set_vp(struct kvm_vcpu *vcpu,
+                                           union kvmppc_one_reg *val)
+{ return -ENOENT; }
 
 #endif /* CONFIG_KVM_XIVE */
 
index 12744608a61ca531a587b2e34650889e313c9ba0..cd3f16b70a2e3cfde323918d1f35c0c3ca0980f4 100644 (file)
@@ -482,6 +482,8 @@ struct kvm_ppc_cpu_char {
 #define  KVM_REG_PPC_ICP_PPRI_SHIFT    16      /* pending irq priority */
 #define  KVM_REG_PPC_ICP_PPRI_MASK     0xff
 
+#define KVM_REG_PPC_VP_STATE   (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x8d)
+
 /* Device control API: PPC-specific devices */
 #define KVM_DEV_MPIC_GRP_MISC          1
 #define   KVM_DEV_MPIC_BASE_ADDR       0       /* 64-bit */
index 7c3348fa27e1501f0bb39a6aa157a6d31fbbb075..efd15101eef09e795b273ecb6b89c54314b418a9 100644 (file)
@@ -651,6 +651,18 @@ int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id,
                                *val = get_reg_val(id, kvmppc_xics_get_icp(vcpu));
                        break;
 #endif /* CONFIG_KVM_XICS */
+#ifdef CONFIG_KVM_XIVE
+               case KVM_REG_PPC_VP_STATE:
+                       if (!vcpu->arch.xive_vcpu) {
+                               r = -ENXIO;
+                               break;
+                       }
+                       if (xive_enabled())
+                               r = kvmppc_xive_native_get_vp(vcpu, val);
+                       else
+                               r = -ENXIO;
+                       break;
+#endif /* CONFIG_KVM_XIVE */
                case KVM_REG_PPC_FSCR:
                        *val = get_reg_val(id, vcpu->arch.fscr);
                        break;
@@ -724,6 +736,18 @@ int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id,
                                r = kvmppc_xics_set_icp(vcpu, set_reg_val(id, *val));
                        break;
 #endif /* CONFIG_KVM_XICS */
+#ifdef CONFIG_KVM_XIVE
+               case KVM_REG_PPC_VP_STATE:
+                       if (!vcpu->arch.xive_vcpu) {
+                               r = -ENXIO;
+                               break;
+                       }
+                       if (xive_enabled())
+                               r = kvmppc_xive_native_set_vp(vcpu, val);
+                       else
+                               r = -ENXIO;
+                       break;
+#endif /* CONFIG_KVM_XIVE */
                case KVM_REG_PPC_FSCR:
                        vcpu->arch.fscr = set_reg_val(id, *val);
                        break;
index 16d23ef3bd39c4f53e014196a831fda0b71f6f64..2f9d5e9439a653634714826a925e728658a38892 100644 (file)
@@ -896,6 +896,82 @@ static int kvmppc_xive_native_create(struct kvm_device *dev, u32 type)
        return ret;
 }
 
+/*
+ * Interrupt Pending Buffer (IPB) offset
+ */
+#define TM_IPB_SHIFT 40
+#define TM_IPB_MASK  (((u64) 0xFF) << TM_IPB_SHIFT)
+
+int kvmppc_xive_native_get_vp(struct kvm_vcpu *vcpu, union kvmppc_one_reg *val)
+{
+       struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
+       u64 opal_state;
+       int rc;
+
+       if (!kvmppc_xive_enabled(vcpu))
+               return -EPERM;
+
+       if (!xc)
+               return -ENOENT;
+
+       /* Thread context registers. We only care about IPB and CPPR */
+       val->xive_timaval[0] = vcpu->arch.xive_saved_state.w01;
+
+       /* Get the VP state from OPAL */
+       rc = xive_native_get_vp_state(xc->vp_id, &opal_state);
+       if (rc)
+               return rc;
+
+       /*
+        * Capture the backup of IPB register in the NVT structure and
+        * merge it in our KVM VP state.
+        */
+       val->xive_timaval[0] |= cpu_to_be64(opal_state & TM_IPB_MASK);
+
+       pr_devel("%s NSR=%02x CPPR=%02x IBP=%02x PIPR=%02x w01=%016llx w2=%08x opal=%016llx\n",
+                __func__,
+                vcpu->arch.xive_saved_state.nsr,
+                vcpu->arch.xive_saved_state.cppr,
+                vcpu->arch.xive_saved_state.ipb,
+                vcpu->arch.xive_saved_state.pipr,
+                vcpu->arch.xive_saved_state.w01,
+                (u32) vcpu->arch.xive_cam_word, opal_state);
+
+       return 0;
+}
+
+int kvmppc_xive_native_set_vp(struct kvm_vcpu *vcpu, union kvmppc_one_reg *val)
+{
+       struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu;
+       struct kvmppc_xive *xive = vcpu->kvm->arch.xive;
+
+       pr_devel("%s w01=%016llx vp=%016llx\n", __func__,
+                val->xive_timaval[0], val->xive_timaval[1]);
+
+       if (!kvmppc_xive_enabled(vcpu))
+               return -EPERM;
+
+       if (!xc || !xive)
+               return -ENOENT;
+
+       /* We can't update the state of a "pushed" VCPU  */
+       if (WARN_ON(vcpu->arch.xive_pushed))
+               return -EBUSY;
+
+       /*
+        * Restore the thread context registers. IPB and CPPR should
+        * be the only ones that matter.
+        */
+       vcpu->arch.xive_saved_state.w01 = val->xive_timaval[0];
+
+       /*
+        * There is no need to restore the XIVE internal state (IPB
+        * stored in the NVT) as the IPB register was merged in KVM VP
+        * state when captured.
+        */
+       return 0;
+}
+
 static int xive_native_debug_show(struct seq_file *m, void *private)
 {
        struct kvmppc_xive *xive = m->private;