yeahuh / rpms / qemu-kvm

Forked from rpms/qemu-kvm 2 years ago
Clone

Blame SOURCES/kvm-spapr-Fix-EEH-capability-issue-on-KVM-guest-for-PCI-.patch

a83cc2
From 389b2a01f9b75575996eaab195a9697840ae5f29 Mon Sep 17 00:00:00 2001
a83cc2
From: Mahesh Salgaonkar <mahesh@linux.ibm.com>
a83cc2
Date: Wed, 30 Jun 2021 13:27:47 -0400
a83cc2
Subject: [PATCH 2/6] spapr: Fix EEH capability issue on KVM guest for PCI
a83cc2
 passthru
a83cc2
a83cc2
RH-Author: Miroslav Rezanina <mrezanin@redhat.com>
a83cc2
RH-MergeRequest: 22: Synchronize with RHEL-AV 8.5 release 23 to RHEL 9
a83cc2
RH-Commit: [1/5] 86642761bad229c080e180ea9ebd0a4f67d2a4f7 (mrezanin/centos-src-qemu-kvm)
a83cc2
RH-Bugzilla: 1957194
a83cc2
a83cc2
With upstream kernel, especially after commit 98ba956f6a389
a83cc2
("powerpc/pseries/eeh: Rework device EEH PE determination") we see that KVM
a83cc2
guest isn't able to enable EEH option for PCI pass-through devices anymore.
a83cc2
a83cc2
[root@atest-guest ~]# dmesg | grep EEH
a83cc2
[    0.032337] EEH: pSeries platform initialized
a83cc2
[    0.298207] EEH: No capable adapters found: recovery disabled.
a83cc2
[root@atest-guest ~]#
a83cc2
a83cc2
So far the linux kernel was assuming pe_config_addr equal to device's
a83cc2
config_addr and using it to enable EEH on the PE through ibm,set-eeh-option
a83cc2
RTAS call. Which wasn't the correct way as per PAPR. The linux kernel
a83cc2
commit 98ba956f6a389 fixed this flow. With that fixed, linux now uses PE
a83cc2
config address returned by ibm,get-config-addr-info2 RTAS call to enable
a83cc2
EEH option per-PE basis instead of per-device basis. However this has
a83cc2
uncovered a bug in qemu where ibm,set-eeh-option is treating PE config
a83cc2
address as per-device config address.
a83cc2
a83cc2
Hence in qemu guest with recent kernel the ibm,set-eeh-option RTAS call
a83cc2
fails with -3 return value indicating that there is no PCI device exist for
a83cc2
the specified PE config address. The rtas_ibm_set_eeh_option call uses
a83cc2
pci_find_device() to get the PC device that matches specific bus and devfn
a83cc2
extracted from PE config address passed as argument. Thus it tries to map
a83cc2
the PE config address to a single specific PCI device 'bus->devices[devfn]'
a83cc2
which always results into checking device on slot 0 'bus->devices[0]'.
a83cc2
This succeeds when there is a pass-through device (vfio-pci) present on
a83cc2
slot 0. But in cases where there is no pass-through device present in slot
a83cc2
0, but present in non-zero slots, ibm,set-eeh-option call fails to enable
a83cc2
the EEH capability.
a83cc2
a83cc2
hw/ppc/spapr_pci_vfio.c: spapr_phb_vfio_eeh_set_option()
a83cc2
   case RTAS_EEH_ENABLE: {
a83cc2
        PCIHostState *phb;
a83cc2
        PCIDevice *pdev;
a83cc2
a83cc2
        /*
a83cc2
         * The EEH functionality is enabled on basis of PCI device,
a83cc2
         * instead of PE. We need check the validity of the PCI
a83cc2
         * device address.
a83cc2
         */
a83cc2
        phb = PCI_HOST_BRIDGE(sphb);
a83cc2
        pdev = pci_find_device(phb->bus,
a83cc2
                               (addr >> 16) & 0xFF, (addr >> 8) & 0xFF);
a83cc2
        if (!pdev || !object_dynamic_cast(OBJECT(pdev), "vfio-pci")) {
a83cc2
            return RTAS_OUT_PARAM_ERROR;
a83cc2
        }
a83cc2
a83cc2
hw/pci/pci.c:pci_find_device()
a83cc2
a83cc2
PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn)
a83cc2
{
a83cc2
    bus = pci_find_bus_nr(bus, bus_num);
a83cc2
a83cc2
    if (!bus)
a83cc2
        return NULL;
a83cc2
a83cc2
    return bus->devices[devfn];
a83cc2
}
a83cc2
a83cc2
This patch fixes ibm,set-eeh-option to check for presence of any PCI device
a83cc2
(vfio-pci) under specified bus and enable the EEH if found. The current
a83cc2
code already makes sure that all the devices on that bus are from same
a83cc2
iommu group (within same PE) and fail very early if it does not.
a83cc2
a83cc2
After this fix guest is able to find EEH capable devices and enable EEH
a83cc2
recovery on it.
a83cc2
a83cc2
[root@atest-guest ~]# dmesg | grep EEH
a83cc2
[    0.048139] EEH: pSeries platform initialized
a83cc2
[    0.405115] EEH: Capable adapter found: recovery enabled.
a83cc2
[root@atest-guest ~]#
a83cc2
a83cc2
Reviewed-by: Daniel Henrique Barboza <danielhb413@gmail.com>
a83cc2
Signed-off-by: Mahesh Salgaonkar <mahesh@linux.ibm.com>
a83cc2
Message-Id: <162158429107.145117.5843504911924013125.stgit@jupiter>
a83cc2
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
a83cc2
(cherry picked from commit ac9ef668321ebb6eb871a0c4dd380fa7d7891b4e)
a83cc2
Signed-off-by: Daniel Henrique Barboza <dbarboza@redhat.com>
a83cc2
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
a83cc2
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
a83cc2
---
a83cc2
 hw/ppc/spapr_pci_vfio.c | 40 +++++++++++++++++++++++++++++++++-------
a83cc2
 1 file changed, 33 insertions(+), 7 deletions(-)
a83cc2
a83cc2
diff --git a/hw/ppc/spapr_pci_vfio.c b/hw/ppc/spapr_pci_vfio.c
a83cc2
index e0547b1740..6587c8cb5b 100644
a83cc2
--- a/hw/ppc/spapr_pci_vfio.c
a83cc2
+++ b/hw/ppc/spapr_pci_vfio.c
a83cc2
@@ -47,6 +47,16 @@ void spapr_phb_vfio_reset(DeviceState *qdev)
a83cc2
     spapr_phb_vfio_eeh_reenable(SPAPR_PCI_HOST_BRIDGE(qdev));
a83cc2
 }
a83cc2
 
a83cc2
+static void spapr_eeh_pci_find_device(PCIBus *bus, PCIDevice *pdev,
a83cc2
+                                      void *opaque)
a83cc2
+{
a83cc2
+    bool *found = opaque;
a83cc2
+
a83cc2
+    if (object_dynamic_cast(OBJECT(pdev), "vfio-pci")) {
a83cc2
+        *found = true;
a83cc2
+    }
a83cc2
+}
a83cc2
+
a83cc2
 int spapr_phb_vfio_eeh_set_option(SpaprPhbState *sphb,
a83cc2
                                   unsigned int addr, int option)
a83cc2
 {
a83cc2
@@ -59,17 +69,33 @@ int spapr_phb_vfio_eeh_set_option(SpaprPhbState *sphb,
a83cc2
         break;
a83cc2
     case RTAS_EEH_ENABLE: {
a83cc2
         PCIHostState *phb;
a83cc2
-        PCIDevice *pdev;
a83cc2
+        bool found = false;
a83cc2
 
a83cc2
         /*
a83cc2
-         * The EEH functionality is enabled on basis of PCI device,
a83cc2
-         * instead of PE. We need check the validity of the PCI
a83cc2
-         * device address.
a83cc2
+         * The EEH functionality is enabled per sphb level instead of
a83cc2
+         * per PCI device. We have already identified this specific sphb
a83cc2
+         * based on buid passed as argument to ibm,set-eeh-option rtas
a83cc2
+         * call. Now we just need to check the validity of the PCI
a83cc2
+         * pass-through devices (vfio-pci) under this sphb bus.
a83cc2
+         * We have already validated that all the devices under this sphb
a83cc2
+         * are from same iommu group (within same PE) before comming here.
a83cc2
+         *
a83cc2
+         * Prior to linux commit 98ba956f6a389 ("powerpc/pseries/eeh:
a83cc2
+         * Rework device EEH PE determination") kernel would call
a83cc2
+         * eeh-set-option for each device in the PE using the device's
a83cc2
+         * config_address as the argument rather than the PE address.
a83cc2
+         * Hence if we check validity of supplied config_addr whether
a83cc2
+         * it matches to this PHB will cause issues with older kernel
a83cc2
+         * versions v5.9 and older. If we return an error from
a83cc2
+         * eeh-set-option when the argument isn't a valid PE address
a83cc2
+         * then older kernels (v5.9 and older) will interpret that as
a83cc2
+         * EEH not being supported.
a83cc2
          */
a83cc2
         phb = PCI_HOST_BRIDGE(sphb);
a83cc2
-        pdev = pci_find_device(phb->bus,
a83cc2
-                               (addr >> 16) & 0xFF, (addr >> 8) & 0xFF);
a83cc2
-        if (!pdev || !object_dynamic_cast(OBJECT(pdev), "vfio-pci")) {
a83cc2
+        pci_for_each_device(phb->bus, (addr >> 16) & 0xFF,
a83cc2
+                            spapr_eeh_pci_find_device, &found);
a83cc2
+
a83cc2
+        if (!found) {
a83cc2
             return RTAS_OUT_PARAM_ERROR;
a83cc2
         }
a83cc2
 
a83cc2
-- 
a83cc2
2.27.0
a83cc2