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

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