Blame SOURCES/kvm-s390x-pci-enable-for-load-store-interpretation.patch

bf143f
From 62fbb66d18f598d0896164383aab465e093fb0c1 Mon Sep 17 00:00:00 2001
bf143f
From: Matthew Rosato <mjrosato@linux.ibm.com>
bf143f
Date: Fri, 2 Sep 2022 13:27:32 -0400
bf143f
Subject: [PATCH 07/42] s390x/pci: enable for load/store interpretation
bf143f
MIME-Version: 1.0
bf143f
Content-Type: text/plain; charset=UTF-8
bf143f
Content-Transfer-Encoding: 8bit
bf143f
bf143f
RH-Author: Cédric Le Goater <clg@redhat.com>
bf143f
RH-MergeRequest: 226: s390: Enhanced Interpretation for PCI Functions and Secure Execution guest dump
bf143f
RH-Bugzilla: 1664378 2043909
bf143f
RH-Acked-by: Thomas Huth <thuth@redhat.com>
bf143f
RH-Acked-by: Cornelia Huck <cohuck@redhat.com>
bf143f
RH-Acked-by: Jon Maloy <jmaloy@redhat.com>
bf143f
RH-Commit: [7/41] 3a96e901e295bb9e0c530638c45b5da5d60c00bd
bf143f
bf143f
If the ZPCI_OP ioctl reports that is is available and usable, then the
bf143f
underlying KVM host will enable load/store intepretation for any guest
bf143f
device without a SHM bit in the guest function handle.  For a device that
bf143f
will be using interpretation support, ensure the guest function handle
bf143f
matches the host function handle; this value is re-checked every time the
bf143f
guest issues a SET PCI FN to enable the guest device as it is the only
bf143f
opportunity to reflect function handle changes.
bf143f
bf143f
By default, unless interpret=off is specified, interpretation support will
bf143f
always be assumed and exploited if the necessary ioctl and features are
bf143f
available on the host kernel.  When these are unavailable, we will silently
bf143f
revert to the interception model; this allows existing guest configurations
bf143f
to work unmodified on hosts with and without zPCI interpretation support,
bf143f
allowing QEMU to choose the best support model available.
bf143f
bf143f
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
bf143f
Acked-by: Thomas Huth <thuth@redhat.com>
bf143f
Message-Id: <20220902172737.170349-4-mjrosato@linux.ibm.com>
bf143f
Signed-off-by: Thomas Huth <thuth@redhat.com>
bf143f
(cherry picked from commit dd1d5fd9684beeb0c14c39f497ef2aa9ac683aa7)
bf143f
Signed-off-by: Cédric Le Goater <clg@redhat.com>
bf143f
---
bf143f
 hw/s390x/meson.build            |  1 +
bf143f
 hw/s390x/s390-pci-bus.c         | 66 ++++++++++++++++++++++++++++++++-
bf143f
 hw/s390x/s390-pci-inst.c        | 16 ++++++++
bf143f
 hw/s390x/s390-pci-kvm.c         | 22 +++++++++++
bf143f
 include/hw/s390x/s390-pci-bus.h |  1 +
bf143f
 include/hw/s390x/s390-pci-kvm.h | 24 ++++++++++++
bf143f
 target/s390x/kvm/kvm.c          |  7 ++++
bf143f
 target/s390x/kvm/kvm_s390x.h    |  1 +
bf143f
 8 files changed, 137 insertions(+), 1 deletion(-)
bf143f
 create mode 100644 hw/s390x/s390-pci-kvm.c
bf143f
 create mode 100644 include/hw/s390x/s390-pci-kvm.h
bf143f
bf143f
diff --git a/hw/s390x/meson.build b/hw/s390x/meson.build
bf143f
index 28484256ec..6e6e47fcda 100644
bf143f
--- a/hw/s390x/meson.build
bf143f
+++ b/hw/s390x/meson.build
bf143f
@@ -23,6 +23,7 @@ s390x_ss.add(when: 'CONFIG_KVM', if_true: files(
bf143f
   's390-skeys-kvm.c',
bf143f
   's390-stattrib-kvm.c',
bf143f
   'pv.c',
bf143f
+  's390-pci-kvm.c',
bf143f
 ))
bf143f
 s390x_ss.add(when: 'CONFIG_TCG', if_true: files(
bf143f
   'tod-tcg.c',
bf143f
diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
bf143f
index 01b58ebc70..18bfae0465 100644
bf143f
--- a/hw/s390x/s390-pci-bus.c
bf143f
+++ b/hw/s390x/s390-pci-bus.c
bf143f
@@ -16,6 +16,7 @@
bf143f
 #include "qapi/visitor.h"
bf143f
 #include "hw/s390x/s390-pci-bus.h"
bf143f
 #include "hw/s390x/s390-pci-inst.h"
bf143f
+#include "hw/s390x/s390-pci-kvm.h"
bf143f
 #include "hw/s390x/s390-pci-vfio.h"
bf143f
 #include "hw/pci/pci_bus.h"
bf143f
 #include "hw/qdev-properties.h"
bf143f
@@ -971,12 +972,51 @@ static void s390_pci_update_subordinate(PCIDevice *dev, uint32_t nr)
bf143f
     }
bf143f
 }
bf143f
 
bf143f
+static int s390_pci_interp_plug(S390pciState *s, S390PCIBusDevice *pbdev)
bf143f
+{
bf143f
+    uint32_t idx, fh;
bf143f
+
bf143f
+    if (!s390_pci_get_host_fh(pbdev, &fh)) {
bf143f
+        return -EPERM;
bf143f
+    }
bf143f
+
bf143f
+    /*
bf143f
+     * The host device is already in an enabled state, but we always present
bf143f
+     * the initial device state to the guest as disabled (ZPCI_FS_DISABLED).
bf143f
+     * Therefore, mask off the enable bit from the passthrough handle until
bf143f
+     * the guest issues a CLP SET PCI FN later to enable the device.
bf143f
+     */
bf143f
+    pbdev->fh = fh & ~FH_MASK_ENABLE;
bf143f
+
bf143f
+    /* Next, see if the idx is already in-use */
bf143f
+    idx = pbdev->fh & FH_MASK_INDEX;
bf143f
+    if (pbdev->idx != idx) {
bf143f
+        if (s390_pci_find_dev_by_idx(s, idx)) {
bf143f
+            return -EINVAL;
bf143f
+        }
bf143f
+        /*
bf143f
+         * Update the idx entry with the passed through idx
bf143f
+         * If the relinquished idx is lower than next_idx, use it
bf143f
+         * to replace next_idx
bf143f
+         */
bf143f
+        g_hash_table_remove(s->zpci_table, &pbdev->idx);
bf143f
+        if (idx < s->next_idx) {
bf143f
+            s->next_idx = idx;
bf143f
+        }
bf143f
+        pbdev->idx = idx;
bf143f
+        g_hash_table_insert(s->zpci_table, &pbdev->idx, pbdev);
bf143f
+    }
bf143f
+
bf143f
+    return 0;
bf143f
+}
bf143f
+
bf143f
 static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
bf143f
                               Error **errp)
bf143f
 {
bf143f
     S390pciState *s = S390_PCI_HOST_BRIDGE(hotplug_dev);
bf143f
     PCIDevice *pdev = NULL;
bf143f
     S390PCIBusDevice *pbdev = NULL;
bf143f
+    int rc;
bf143f
 
bf143f
     if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) {
bf143f
         PCIBridge *pb = PCI_BRIDGE(dev);
bf143f
@@ -1022,12 +1062,35 @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
bf143f
         set_pbdev_info(pbdev);
bf143f
 
bf143f
         if (object_dynamic_cast(OBJECT(dev), "vfio-pci")) {
bf143f
-            pbdev->fh |= FH_SHM_VFIO;
bf143f
+            /*
bf143f
+             * By default, interpretation is always requested; if the available
bf143f
+             * facilities indicate it is not available, fallback to the
bf143f
+             * interception model.
bf143f
+             */
bf143f
+            if (pbdev->interp) {
bf143f
+                if (s390_pci_kvm_interp_allowed()) {
bf143f
+                    rc = s390_pci_interp_plug(s, pbdev);
bf143f
+                    if (rc) {
bf143f
+                        error_setg(errp, "Plug failed for zPCI device in "
bf143f
+                                   "interpretation mode: %d", rc);
bf143f
+                        return;
bf143f
+                    }
bf143f
+                } else {
bf143f
+                    DPRINTF("zPCI interpretation facilities missing.\n");
bf143f
+                    pbdev->interp = false;
bf143f
+                }
bf143f
+            }
bf143f
             pbdev->iommu->dma_limit = s390_pci_start_dma_count(s, pbdev);
bf143f
             /* Fill in CLP information passed via the vfio region */
bf143f
             s390_pci_get_clp_info(pbdev);
bf143f
+            if (!pbdev->interp) {
bf143f
+                /* Do vfio passthrough but intercept for I/O */
bf143f
+                pbdev->fh |= FH_SHM_VFIO;
bf143f
+            }
bf143f
         } else {
bf143f
             pbdev->fh |= FH_SHM_EMUL;
bf143f
+            /* Always intercept emulated devices */
bf143f
+            pbdev->interp = false;
bf143f
         }
bf143f
 
bf143f
         if (s390_pci_msix_init(pbdev)) {
bf143f
@@ -1360,6 +1423,7 @@ static Property s390_pci_device_properties[] = {
bf143f
     DEFINE_PROP_UINT16("uid", S390PCIBusDevice, uid, UID_UNDEFINED),
bf143f
     DEFINE_PROP_S390_PCI_FID("fid", S390PCIBusDevice, fid),
bf143f
     DEFINE_PROP_STRING("target", S390PCIBusDevice, target),
bf143f
+    DEFINE_PROP_BOOL("interpret", S390PCIBusDevice, interp, true),
bf143f
     DEFINE_PROP_END_OF_LIST(),
bf143f
 };
bf143f
 
bf143f
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
bf143f
index 6d400d4147..651ec38635 100644
bf143f
--- a/hw/s390x/s390-pci-inst.c
bf143f
+++ b/hw/s390x/s390-pci-inst.c
bf143f
@@ -18,6 +18,8 @@
bf143f
 #include "sysemu/hw_accel.h"
bf143f
 #include "hw/s390x/s390-pci-inst.h"
bf143f
 #include "hw/s390x/s390-pci-bus.h"
bf143f
+#include "hw/s390x/s390-pci-kvm.h"
bf143f
+#include "hw/s390x/s390-pci-vfio.h"
bf143f
 #include "hw/s390x/tod.h"
bf143f
 
bf143f
 #ifndef DEBUG_S390PCI_INST
bf143f
@@ -246,6 +248,20 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
bf143f
                 goto out;
bf143f
             }
bf143f
 
bf143f
+            /*
bf143f
+             * Take this opportunity to make sure we still have an accurate
bf143f
+             * host fh.  It's possible part of the handle changed while the
bf143f
+             * device was disabled to the guest (e.g. vfio hot reset for
bf143f
+             * ISM during plug)
bf143f
+             */
bf143f
+            if (pbdev->interp) {
bf143f
+                /* Take this opportunity to make sure we are sync'd with host */
bf143f
+                if (!s390_pci_get_host_fh(pbdev, &pbdev->fh) ||
bf143f
+                    !(pbdev->fh & FH_MASK_ENABLE)) {
bf143f
+                    stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FH);
bf143f
+                    goto out;
bf143f
+                }
bf143f
+            }
bf143f
             pbdev->fh |= FH_MASK_ENABLE;
bf143f
             pbdev->state = ZPCI_FS_ENABLED;
bf143f
             stl_p(&ressetpci->fh, pbdev->fh);
bf143f
diff --git a/hw/s390x/s390-pci-kvm.c b/hw/s390x/s390-pci-kvm.c
bf143f
new file mode 100644
bf143f
index 0000000000..0f16104a74
bf143f
--- /dev/null
bf143f
+++ b/hw/s390x/s390-pci-kvm.c
bf143f
@@ -0,0 +1,22 @@
bf143f
+/*
bf143f
+ * s390 zPCI KVM interfaces
bf143f
+ *
bf143f
+ * Copyright 2022 IBM Corp.
bf143f
+ * Author(s): Matthew Rosato <mjrosato@linux.ibm.com>
bf143f
+ *
bf143f
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
bf143f
+ * your option) any later version. See the COPYING file in the top-level
bf143f
+ * directory.
bf143f
+ */
bf143f
+
bf143f
+#include "qemu/osdep.h"
bf143f
+
bf143f
+#include "kvm/kvm_s390x.h"
bf143f
+#include "hw/s390x/pv.h"
bf143f
+#include "hw/s390x/s390-pci-kvm.h"
bf143f
+#include "cpu_models.h"
bf143f
+
bf143f
+bool s390_pci_kvm_interp_allowed(void)
bf143f
+{
bf143f
+    return kvm_s390_get_zpci_op() && !s390_is_pv();
bf143f
+}
bf143f
diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h
bf143f
index da3cde2bb4..a9843dfe97 100644
bf143f
--- a/include/hw/s390x/s390-pci-bus.h
bf143f
+++ b/include/hw/s390x/s390-pci-bus.h
bf143f
@@ -350,6 +350,7 @@ struct S390PCIBusDevice {
bf143f
     IndAddr *indicator;
bf143f
     bool pci_unplug_request_processed;
bf143f
     bool unplug_requested;
bf143f
+    bool interp;
bf143f
     QTAILQ_ENTRY(S390PCIBusDevice) link;
bf143f
 };
bf143f
 
bf143f
diff --git a/include/hw/s390x/s390-pci-kvm.h b/include/hw/s390x/s390-pci-kvm.h
bf143f
new file mode 100644
bf143f
index 0000000000..80a2e7d0ca
bf143f
--- /dev/null
bf143f
+++ b/include/hw/s390x/s390-pci-kvm.h
bf143f
@@ -0,0 +1,24 @@
bf143f
+/*
bf143f
+ * s390 PCI KVM interfaces
bf143f
+ *
bf143f
+ * Copyright 2022 IBM Corp.
bf143f
+ * Author(s): Matthew Rosato <mjrosato@linux.ibm.com>
bf143f
+ *
bf143f
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
bf143f
+ * your option) any later version. See the COPYING file in the top-level
bf143f
+ * directory.
bf143f
+ */
bf143f
+
bf143f
+#ifndef HW_S390_PCI_KVM_H
bf143f
+#define HW_S390_PCI_KVM_H
bf143f
+
bf143f
+#ifdef CONFIG_KVM
bf143f
+bool s390_pci_kvm_interp_allowed(void);
bf143f
+#else
bf143f
+static inline bool s390_pci_kvm_interp_allowed(void)
bf143f
+{
bf143f
+    return false;
bf143f
+}
bf143f
+#endif
bf143f
+
bf143f
+#endif
bf143f
diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c
bf143f
index ba04997da1..30712487d4 100644
bf143f
--- a/target/s390x/kvm/kvm.c
bf143f
+++ b/target/s390x/kvm/kvm.c
bf143f
@@ -158,6 +158,7 @@ static int cap_ri;
bf143f
 static int cap_hpage_1m;
bf143f
 static int cap_vcpu_resets;
bf143f
 static int cap_protected;
bf143f
+static int cap_zpci_op;
bf143f
 
bf143f
 static bool mem_op_storage_key_support;
bf143f
 
bf143f
@@ -363,6 +364,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
bf143f
     cap_s390_irq = kvm_check_extension(s, KVM_CAP_S390_INJECT_IRQ);
bf143f
     cap_vcpu_resets = kvm_check_extension(s, KVM_CAP_S390_VCPU_RESETS);
bf143f
     cap_protected = kvm_check_extension(s, KVM_CAP_S390_PROTECTED);
bf143f
+    cap_zpci_op = kvm_check_extension(s, KVM_CAP_S390_ZPCI_OP);
bf143f
 
bf143f
     kvm_vm_enable_cap(s, KVM_CAP_S390_USER_SIGP, 0);
bf143f
     kvm_vm_enable_cap(s, KVM_CAP_S390_VECTOR_REGISTERS, 0);
bf143f
@@ -2579,3 +2581,8 @@ bool kvm_arch_cpu_check_are_resettable(void)
bf143f
 {
bf143f
     return true;
bf143f
 }
bf143f
+
bf143f
+int kvm_s390_get_zpci_op(void)
bf143f
+{
bf143f
+    return cap_zpci_op;
bf143f
+}
bf143f
diff --git a/target/s390x/kvm/kvm_s390x.h b/target/s390x/kvm/kvm_s390x.h
bf143f
index 05a5e1e6f4..aaae8570de 100644
bf143f
--- a/target/s390x/kvm/kvm_s390x.h
bf143f
+++ b/target/s390x/kvm/kvm_s390x.h
bf143f
@@ -27,6 +27,7 @@ void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu);
bf143f
 int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu);
bf143f
 int kvm_s390_get_hpage_1m(void);
bf143f
 int kvm_s390_get_ri(void);
bf143f
+int kvm_s390_get_zpci_op(void);
bf143f
 int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_clock);
bf143f
 int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_clock);
bf143f
 int kvm_s390_set_clock(uint8_t tod_high, uint64_t tod_clock);
bf143f
-- 
bf143f
2.37.3
bf143f