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