summaryrefslogtreecommitdiffstats
path: root/hw/s390x
diff options
context:
space:
mode:
authorMatthew Rosato2022-09-02 19:27:34 +0200
committerThomas Huth2022-09-26 17:23:47 +0200
commitd0bc7091c2013ad2fa164100cf7b17962370e8ab (patch)
tree76dcd424722b6637b1d4d27fee9ec682e2e2fd15 /hw/s390x
parents390x/pci: don't fence interpreted devices without MSI-X (diff)
downloadqemu-d0bc7091c2013ad2fa164100cf7b17962370e8ab.tar.gz
qemu-d0bc7091c2013ad2fa164100cf7b17962370e8ab.tar.xz
qemu-d0bc7091c2013ad2fa164100cf7b17962370e8ab.zip
s390x/pci: enable adapter event notification for interpreted devices
Use the associated kvm ioctl operation to enable adapter event notification and forwarding for devices when requested. This feature will be set up with or without firmware assist based upon the 'forwarding_assist' setting. Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com> Message-Id: <20220902172737.170349-6-mjrosato@linux.ibm.com> [thuth: Rename "forwarding_assist" property to "forwarding-assist"] Signed-off-by: Thomas Huth <thuth@redhat.com>
Diffstat (limited to 'hw/s390x')
-rw-r--r--hw/s390x/s390-pci-bus.c20
-rw-r--r--hw/s390x/s390-pci-inst.c40
-rw-r--r--hw/s390x/s390-pci-kvm.c30
3 files changed, 85 insertions, 5 deletions
diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
index 816d17af99..2f19973913 100644
--- a/hw/s390x/s390-pci-bus.c
+++ b/hw/s390x/s390-pci-bus.c
@@ -190,7 +190,10 @@ void s390_pci_sclp_deconfigure(SCCB *sccb)
rc = SCLP_RC_NO_ACTION_REQUIRED;
break;
default:
- if (pbdev->summary_ind) {
+ if (pbdev->interp && (pbdev->fh & FH_MASK_ENABLE)) {
+ /* Interpreted devices were using interrupt forwarding */
+ s390_pci_kvm_aif_disable(pbdev);
+ } else if (pbdev->summary_ind) {
pci_dereg_irqs(pbdev);
}
if (pbdev->iommu->enabled) {
@@ -1082,6 +1085,7 @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
} else {
DPRINTF("zPCI interpretation facilities missing.\n");
pbdev->interp = false;
+ pbdev->forwarding_assist = false;
}
}
pbdev->iommu->dma_limit = s390_pci_start_dma_count(s, pbdev);
@@ -1090,11 +1094,13 @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
if (!pbdev->interp) {
/* Do vfio passthrough but intercept for I/O */
pbdev->fh |= FH_SHM_VFIO;
+ pbdev->forwarding_assist = false;
}
} else {
pbdev->fh |= FH_SHM_EMUL;
/* Always intercept emulated devices */
pbdev->interp = false;
+ pbdev->forwarding_assist = false;
}
if (s390_pci_msix_init(pbdev) && !pbdev->interp) {
@@ -1244,7 +1250,10 @@ static void s390_pcihost_reset(DeviceState *dev)
/* Process all pending unplug requests */
QTAILQ_FOREACH_SAFE(pbdev, &s->zpci_devs, link, next) {
if (pbdev->unplug_requested) {
- if (pbdev->summary_ind) {
+ if (pbdev->interp && (pbdev->fh & FH_MASK_ENABLE)) {
+ /* Interpreted devices were using interrupt forwarding */
+ s390_pci_kvm_aif_disable(pbdev);
+ } else if (pbdev->summary_ind) {
pci_dereg_irqs(pbdev);
}
if (pbdev->iommu->enabled) {
@@ -1382,7 +1391,10 @@ static void s390_pci_device_reset(DeviceState *dev)
break;
}
- if (pbdev->summary_ind) {
+ if (pbdev->interp && (pbdev->fh & FH_MASK_ENABLE)) {
+ /* Interpreted devices were using interrupt forwarding */
+ s390_pci_kvm_aif_disable(pbdev);
+ } else if (pbdev->summary_ind) {
pci_dereg_irqs(pbdev);
}
if (pbdev->iommu->enabled) {
@@ -1428,6 +1440,8 @@ static Property s390_pci_device_properties[] = {
DEFINE_PROP_S390_PCI_FID("fid", S390PCIBusDevice, fid),
DEFINE_PROP_STRING("target", S390PCIBusDevice, target),
DEFINE_PROP_BOOL("interpret", S390PCIBusDevice, interp, true),
+ DEFINE_PROP_BOOL("forwarding-assist", S390PCIBusDevice, forwarding_assist,
+ true),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
index 651ec38635..20a9bcc7af 100644
--- a/hw/s390x/s390-pci-inst.c
+++ b/hw/s390x/s390-pci-inst.c
@@ -1066,6 +1066,32 @@ static void fmb_update(void *opaque)
timer_mod(pbdev->fmb_timer, t + pbdev->pci_group->zpci_group.mui);
}
+static int mpcifc_reg_int_interp(S390PCIBusDevice *pbdev, ZpciFib *fib)
+{
+ int rc;
+
+ rc = s390_pci_kvm_aif_enable(pbdev, fib, pbdev->forwarding_assist);
+ if (rc) {
+ DPRINTF("Failed to enable interrupt forwarding\n");
+ return rc;
+ }
+
+ return 0;
+}
+
+static int mpcifc_dereg_int_interp(S390PCIBusDevice *pbdev, ZpciFib *fib)
+{
+ int rc;
+
+ rc = s390_pci_kvm_aif_disable(pbdev);
+ if (rc) {
+ DPRINTF("Failed to disable interrupt forwarding\n");
+ return rc;
+ }
+
+ return 0;
+}
+
int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
uintptr_t ra)
{
@@ -1120,7 +1146,12 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
switch (oc) {
case ZPCI_MOD_FC_REG_INT:
- if (pbdev->summary_ind) {
+ if (pbdev->interp) {
+ if (mpcifc_reg_int_interp(pbdev, &fib)) {
+ cc = ZPCI_PCI_LS_ERR;
+ s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
+ }
+ } else if (pbdev->summary_ind) {
cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
} else if (reg_irqs(env, pbdev, fib)) {
@@ -1129,7 +1160,12 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
}
break;
case ZPCI_MOD_FC_DEREG_INT:
- if (!pbdev->summary_ind) {
+ if (pbdev->interp) {
+ if (mpcifc_dereg_int_interp(pbdev, &fib)) {
+ cc = ZPCI_PCI_LS_ERR;
+ s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
+ }
+ } else if (!pbdev->summary_ind) {
cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
} else {
diff --git a/hw/s390x/s390-pci-kvm.c b/hw/s390x/s390-pci-kvm.c
index 0f16104a74..9134fe185f 100644
--- a/hw/s390x/s390-pci-kvm.c
+++ b/hw/s390x/s390-pci-kvm.c
@@ -11,12 +11,42 @@
#include "qemu/osdep.h"
+#include <linux/kvm.h>
+
#include "kvm/kvm_s390x.h"
#include "hw/s390x/pv.h"
+#include "hw/s390x/s390-pci-bus.h"
#include "hw/s390x/s390-pci-kvm.h"
+#include "hw/s390x/s390-pci-inst.h"
#include "cpu_models.h"
bool s390_pci_kvm_interp_allowed(void)
{
return kvm_s390_get_zpci_op() && !s390_is_pv();
}
+
+int s390_pci_kvm_aif_enable(S390PCIBusDevice *pbdev, ZpciFib *fib, bool assist)
+{
+ struct kvm_s390_zpci_op args = {
+ .fh = pbdev->fh,
+ .op = KVM_S390_ZPCIOP_REG_AEN,
+ .u.reg_aen.ibv = fib->aibv,
+ .u.reg_aen.sb = fib->aisb,
+ .u.reg_aen.noi = FIB_DATA_NOI(fib->data),
+ .u.reg_aen.isc = FIB_DATA_ISC(fib->data),
+ .u.reg_aen.sbo = FIB_DATA_AISBO(fib->data),
+ .u.reg_aen.flags = (assist) ? 0 : KVM_S390_ZPCIOP_REGAEN_HOST
+ };
+
+ return kvm_vm_ioctl(kvm_state, KVM_S390_ZPCI_OP, &args);
+}
+
+int s390_pci_kvm_aif_disable(S390PCIBusDevice *pbdev)
+{
+ struct kvm_s390_zpci_op args = {
+ .fh = pbdev->fh,
+ .op = KVM_S390_ZPCIOP_DEREG_AEN
+ };
+
+ return kvm_vm_ioctl(kvm_state, KVM_S390_ZPCI_OP, &args);
+}