From: Narayana Murty N <nnmlinux@linux.ibm.com>
To: qemu-devel@nongnu.org, qemu-ppc@nongnu.org, mahesh@linux.ibm.com,
sbhat@linux.ibm.com, anushree.mathur@linux.vnet.ibm.com,
clg@redhat.com, sourabhjain@linux.ibm.com, adityag@linux.ibm.com,
nikhilks@linux.ibm.com
Cc: pierrick.bouvier@oss.qualcomm.com, rathc@linux.ibm.com,
npiggin@gmail.com, harshpb@linux.ibm.com,
amachhiw@linux.ibm.com, hbathini@linux.ibm.com,
shivangu@linux.ibm.com
Subject: [PATCH v5 5/6] ppc/spapr: Split VFIO EEH support from general VFIO code
Date: Tue, 1 Sep 2026 23:11:09 +0530 [thread overview]
Message-ID: <20260901174110.45356-6-nnmlinux@linux.ibm.com> (raw)
In-Reply-To: <20260901174110.45356-1-nnmlinux@linux.ibm.com>
Move all EEH and error-injection functions from spapr_pci_vfio.c into
a dedicated hw/ppc/spapr_eeh.c. spapr_eeh.c is compiled only
when CONFIG_VFIO_PCI is enabled;
spapr_pci_vfio.c is retained as a stub-only file compiled on Linux
when CONFIG_VFIO_PCI is not available, providing the non-functional
fallback implementations needed for Linux/pseries builds that do not
include VFIO PCI.
meson.build: replace the single spapr_pci_vfio.c entry with an
if_true/if_false pair keyed on CONFIG_VFIO_PCI:
CONFIG_VFIO_PCI=y -> spapr_eeh.c (real implementation)
CONFIG_VFIO_PCI=n -> spapr_pci_vfio-stubs.c (stubs)
No functional change to the EEH state machine.
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Signed-off-by: Narayana Murty N <nnmlinux@linux.ibm.com>
---
include/hw/pci-host/spapr.h | 56 +---
include/hw/ppc/spapr_vfio.h | 31 ++
hw/ppc/spapr_eeh.c | 571 +++++++++++++++++++++++++++++++++
hw/ppc/spapr_pci.c | 1 +
hw/ppc/spapr_pci_vfio.c | 591 +----------------------------------
stubs/spapr_phb_vfio-stubs.c | 62 ++++
hw/ppc/Kconfig | 2 +-
hw/ppc/meson.build | 1 +
stubs/meson.build | 1 +
9 files changed, 670 insertions(+), 646 deletions(-)
create mode 100644 include/hw/ppc/spapr_vfio.h
create mode 100644 hw/ppc/spapr_eeh.c
create mode 100644 stubs/spapr_phb_vfio-stubs.c
diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h
index 492f66e1ef..d2bc90a3d2 100644
--- a/include/hw/pci-host/spapr.h
+++ b/include/hw/pci-host/spapr.h
@@ -116,61 +116,7 @@ void spapr_phb_remove_pci_device_cb(DeviceState *dev);
int spapr_pci_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
void *fdt, int *fdt_start_offset, Error **errp);
-/* VFIO EEH hooks */
-#ifdef CONFIG_LINUX
-bool spapr_phb_eeh_available(SpaprPhbState *sphb);
-int spapr_phb_vfio_eeh_set_option(SpaprPhbState *sphb,
- unsigned int addr, int option);
-int spapr_phb_vfio_eeh_get_state(SpaprPhbState *sphb, int *state);
-int spapr_phb_vfio_eeh_reset(SpaprPhbState *sphb, int option);
-int spapr_phb_vfio_eeh_configure(SpaprPhbState *sphb);
-void spapr_phb_vfio_reset(DeviceState *qdev);
-int spapr_phb_vfio_errinjct(SpaprPhbState *sphb, uint32_t type,
- uint32_t func, uint64_t addr, uint64_t mask);
-int spapr_phb_vfio_translate_errinjct_addr(SpaprPhbState *sphb,
- uint32_t config_addr,
- uint64_t guest_addr,
- uint64_t *host_pci_bus_addr);
-#else
-static inline bool spapr_phb_eeh_available(SpaprPhbState *sphb)
-{
- return false;
-}
-static inline int spapr_phb_vfio_eeh_set_option(SpaprPhbState *sphb,
- unsigned int addr, int option)
-{
- return RTAS_OUT_HW_ERROR;
-}
-static inline int spapr_phb_vfio_eeh_get_state(SpaprPhbState *sphb,
- int *state)
-{
- return RTAS_OUT_HW_ERROR;
-}
-static inline int spapr_phb_vfio_eeh_reset(SpaprPhbState *sphb, int option)
-{
- return RTAS_OUT_HW_ERROR;
-}
-static inline int spapr_phb_vfio_eeh_configure(SpaprPhbState *sphb)
-{
- return RTAS_OUT_HW_ERROR;
-}
-static inline void spapr_phb_vfio_reset(DeviceState *qdev)
-{
-}
-static inline int spapr_phb_vfio_errinjct(SpaprPhbState *sphb, uint32_t type,
- uint32_t func, uint64_t addr,
- uint64_t mask)
-{
- return RTAS_OUT_NOT_SUPPORTED;
-}
-static inline int spapr_phb_vfio_translate_errinjct_addr(SpaprPhbState *sphb,
- uint32_t config_addr,
- uint64_t guest_addr,
- uint64_t *host_addr)
-{
- return -ENOTSUP;
-}
-#endif
+/* VFIO EEH hooks - see hw/ppc/spapr_vfio.h for declarations */
void spapr_phb_dma_reset(SpaprPhbState *sphb);
diff --git a/include/hw/ppc/spapr_vfio.h b/include/hw/ppc/spapr_vfio.h
new file mode 100644
index 0000000000..5aabb262f2
--- /dev/null
+++ b/include/hw/ppc/spapr_vfio.h
@@ -0,0 +1,31 @@
+/*
+ * sPAPR VFIO EEH Header
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef HW_PPC_SPAPR_VFIO_H
+#define HW_PPC_SPAPR_VFIO_H
+
+/*
+ * Forward declarations to avoid pulling in full spapr headers
+ * This allows stubs and other files to compile without libfdt dependencies
+ */
+typedef struct SpaprPhbState SpaprPhbState;
+typedef struct DeviceState DeviceState;
+
+/* VFIO EEH function declarations */
+bool spapr_phb_eeh_available(SpaprPhbState *sphb);
+int spapr_phb_vfio_eeh_set_option(SpaprPhbState *sphb,
+ unsigned int addr, int option);
+int spapr_phb_vfio_eeh_get_state(SpaprPhbState *sphb, int *state);
+int spapr_phb_vfio_eeh_reset(SpaprPhbState *sphb, int option);
+int spapr_phb_vfio_eeh_configure(SpaprPhbState *sphb);
+void spapr_phb_vfio_reset(DeviceState *qdev);
+void spapr_phb_vfio_eeh_reenable(SpaprPhbState *sphb);
+int spapr_phb_vfio_errinjct(SpaprPhbState *sphb, uint32_t type,
+ uint32_t func, uint64_t addr, uint64_t mask);
+int spapr_phb_vfio_translate_errinjct_addr(SpaprPhbState *sphb,
+ uint32_t config_addr,
+ uint64_t guest_addr,
+ uint64_t *host_pci_bus_addr);
+#endif /* HW_PPC_SPAPR_VFIO_H */
diff --git a/hw/ppc/spapr_eeh.c b/hw/ppc/spapr_eeh.c
new file mode 100644
index 0000000000..a9b7fe2d67
--- /dev/null
+++ b/hw/ppc/spapr_eeh.c
@@ -0,0 +1,571 @@
+/*
+ * QEMU sPAPR PCI host for VFIO
+ *
+ * Copyright (c) 2011-2014 Alexey Kardashevskiy, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License,
+ * or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include <sys/ioctl.h>
+#include <linux/vfio.h>
+#include "hw/ppc/spapr.h"
+#include "hw/pci-host/spapr.h"
+#include "hw/pci/msix.h"
+#include "hw/pci/pci_device.h"
+#include "hw/vfio/vfio-container-legacy.h"
+#include "qemu/error-report.h"
+#include "hw/vfio/pci.h"
+#include "hw/ppc/spapr_vfio.h"
+
+/*
+ * Interfaces for IBM EEH (Enhanced Error Handling)
+ */
+static bool vfio_eeh_container_ok(VFIOLegacyContainer *container)
+{
+ /*
+ * As of 2016-03-04 (linux-4.5) the host kernel EEH/VFIO
+ * implementation is broken if there are multiple groups in a
+ * container. The hardware works in units of Partitionable
+ * Endpoints (== IOMMU groups) and the EEH operations naively
+ * iterate across all groups in the container, without any logic
+ * to make sure the groups have their state synchronized. For
+ * certain operations (ENABLE) that might be ok, until an error
+ * occurs, but for others (GET_STATE) it's clearly broken.
+ */
+
+ /*
+ * XXX Once fixed kernels exist, test for them here
+ */
+
+ if (QLIST_EMPTY(&container->group_list)) {
+ return false;
+ }
+
+ if (QLIST_NEXT(QLIST_FIRST(&container->group_list), container_next)) {
+ return false;
+ }
+
+ return true;
+}
+
+static int vfio_eeh_container_op(VFIOLegacyContainer *container, uint32_t op)
+{
+ struct vfio_eeh_pe_op pe_op = {
+ .argsz = sizeof(pe_op),
+ .op = op,
+ };
+ int ret;
+
+ if (!vfio_eeh_container_ok(container)) {
+ error_report("vfio/eeh: EEH_PE_OP 0x%x: "
+ "kernel requires a container with exactly one group", op);
+ return -EPERM;
+ }
+
+ ret = ioctl(container->fd, VFIO_EEH_PE_OP, &pe_op);
+ if (ret < 0) {
+ error_report("vfio/eeh: EEH_PE_OP 0x%x failed: %m", op);
+ return -errno;
+ }
+
+ return ret;
+}
+
+static VFIOLegacyContainer *vfio_eeh_as_container(AddressSpace *as)
+{
+ VFIOAddressSpace *space = vfio_address_space_get(as);
+ VFIOContainer *bcontainer = NULL;
+
+ if (QLIST_EMPTY(&space->containers)) {
+ /* No containers to act on */
+ goto out;
+ }
+
+ bcontainer = QLIST_FIRST(&space->containers);
+
+ if (QLIST_NEXT(bcontainer, next)) {
+ /*
+ * We don't yet have logic to synchronize EEH state across
+ * multiple containers
+ */
+ bcontainer = NULL;
+ goto out;
+ }
+
+out:
+ vfio_address_space_put(space);
+ return VFIO_IOMMU_LEGACY(bcontainer);
+}
+
+static bool vfio_eeh_as_ok(AddressSpace *as)
+{
+ VFIOLegacyContainer *container = vfio_eeh_as_container(as);
+
+ return (container != NULL) && vfio_eeh_container_ok(container);
+}
+
+static int vfio_eeh_as_op(AddressSpace *as, uint32_t op)
+{
+ VFIOLegacyContainer *container = vfio_eeh_as_container(as);
+
+ if (!container) {
+ return -ENODEV;
+ }
+ return vfio_eeh_container_op(container, op);
+}
+
+bool spapr_phb_eeh_available(SpaprPhbState *sphb)
+{
+ return vfio_eeh_as_ok(&sphb->iommu_as);
+}
+
+void spapr_phb_vfio_eeh_reenable(SpaprPhbState *sphb)
+{
+ vfio_eeh_as_op(&sphb->iommu_as, VFIO_EEH_PE_ENABLE);
+}
+
+static void spapr_eeh_pci_find_device(PCIBus *bus, PCIDevice *pdev,
+ void *opaque)
+{
+ bool *found = opaque;
+
+ if (object_dynamic_cast(OBJECT(pdev), "vfio-pci")) {
+ *found = true;
+ }
+}
+
+int spapr_phb_vfio_eeh_set_option(SpaprPhbState *sphb,
+ unsigned int addr, int option)
+{
+ uint32_t op;
+ int ret;
+
+ switch (option) {
+ case RTAS_EEH_DISABLE:
+ op = VFIO_EEH_PE_DISABLE;
+ break;
+ case RTAS_EEH_ENABLE: {
+ PCIHostState *phb;
+ bool found = false;
+
+ /*
+ * The EEH functionality is enabled per sphb level instead of
+ * per PCI device. We have already identified this specific sphb
+ * based on buid passed as argument to ibm,set-eeh-option rtas
+ * call. Now we just need to check the validity of the PCI
+ * pass-through devices (vfio-pci) under this sphb bus.
+ * We have already validated that all the devices under this sphb
+ * are from same iommu group (within same PE) before coming here.
+ *
+ * Prior to linux commit 98ba956f6a389 ("powerpc/pseries/eeh:
+ * Rework device EEH PE determination") kernel would call
+ * eeh-set-option for each device in the PE using the device's
+ * config_address as the argument rather than the PE address.
+ * Hence if we check validity of supplied config_addr whether
+ * it matches to this PHB will cause issues with older kernel
+ * versions v5.9 and older. If we return an error from
+ * eeh-set-option when the argument isn't a valid PE address
+ * then older kernels (v5.9 and older) will interpret that as
+ * EEH not being supported.
+ */
+ phb = PCI_HOST_BRIDGE(sphb);
+ pci_for_each_device(phb->bus, (addr >> 16) & 0xFF,
+ spapr_eeh_pci_find_device, &found);
+
+ if (!found) {
+ return RTAS_OUT_PARAM_ERROR;
+ }
+
+ op = VFIO_EEH_PE_ENABLE;
+ break;
+ }
+ case RTAS_EEH_THAW_IO:
+ op = VFIO_EEH_PE_UNFREEZE_IO;
+ break;
+ case RTAS_EEH_THAW_DMA:
+ op = VFIO_EEH_PE_UNFREEZE_DMA;
+ break;
+ default:
+ return RTAS_OUT_PARAM_ERROR;
+ }
+
+ ret = vfio_eeh_as_op(&sphb->iommu_as, op);
+ if (ret < 0) {
+ return RTAS_OUT_HW_ERROR;
+ }
+
+ return RTAS_OUT_SUCCESS;
+}
+
+int spapr_phb_vfio_eeh_get_state(SpaprPhbState *sphb, int *state)
+{
+ int ret;
+
+ ret = vfio_eeh_as_op(&sphb->iommu_as, VFIO_EEH_PE_GET_STATE);
+ if (ret < 0) {
+ return RTAS_OUT_PARAM_ERROR;
+ }
+
+ *state = ret;
+ return RTAS_OUT_SUCCESS;
+}
+
+static void spapr_phb_vfio_eeh_clear_dev_msix(PCIBus *bus,
+ PCIDevice *pdev,
+ void *opaque)
+{
+ /* Check if the device is VFIO PCI device */
+ if (!object_dynamic_cast(OBJECT(pdev), "vfio-pci")) {
+ return;
+ }
+
+ /*
+ * The MSIx table will be cleaned out by reset. We need
+ * disable it so that it can be reenabled properly. Also,
+ * the cached MSIx table should be cleared as it's not
+ * reflecting the contents in hardware.
+ */
+ if (msix_enabled(pdev)) {
+ uint16_t flags;
+
+ flags = pci_host_config_read_common(pdev,
+ pdev->msix_cap + PCI_MSIX_FLAGS,
+ pci_config_size(pdev), 2);
+ flags &= ~PCI_MSIX_FLAGS_ENABLE;
+ pci_host_config_write_common(pdev,
+ pdev->msix_cap + PCI_MSIX_FLAGS,
+ pci_config_size(pdev), flags, 2);
+ }
+
+ msix_reset(pdev);
+}
+
+static void spapr_phb_vfio_eeh_clear_bus_msix(PCIBus *bus, void *opaque)
+{
+ pci_for_each_device_under_bus(bus, spapr_phb_vfio_eeh_clear_dev_msix,
+ NULL);
+}
+
+static void spapr_phb_vfio_eeh_pre_reset(SpaprPhbState *sphb)
+{
+ PCIHostState *phb = PCI_HOST_BRIDGE(sphb);
+
+ pci_for_each_bus(phb->bus, spapr_phb_vfio_eeh_clear_bus_msix, NULL);
+}
+
+int spapr_phb_vfio_eeh_reset(SpaprPhbState *sphb, int option)
+{
+ uint32_t op;
+ int ret;
+
+ switch (option) {
+ case RTAS_SLOT_RESET_DEACTIVATE:
+ op = VFIO_EEH_PE_RESET_DEACTIVATE;
+ break;
+ case RTAS_SLOT_RESET_HOT:
+ spapr_phb_vfio_eeh_pre_reset(sphb);
+ op = VFIO_EEH_PE_RESET_HOT;
+ break;
+ case RTAS_SLOT_RESET_FUNDAMENTAL:
+ spapr_phb_vfio_eeh_pre_reset(sphb);
+ op = VFIO_EEH_PE_RESET_FUNDAMENTAL;
+ break;
+ default:
+ return RTAS_OUT_PARAM_ERROR;
+ }
+
+ ret = vfio_eeh_as_op(&sphb->iommu_as, op);
+ if (ret < 0) {
+ return RTAS_OUT_HW_ERROR;
+ }
+
+ return RTAS_OUT_SUCCESS;
+}
+
+int spapr_phb_vfio_eeh_configure(SpaprPhbState *sphb)
+{
+ int ret;
+
+ ret = vfio_eeh_as_op(&sphb->iommu_as, VFIO_EEH_PE_CONFIGURE);
+ if (ret < 0) {
+ return RTAS_OUT_PARAM_ERROR;
+ }
+
+ return RTAS_OUT_SUCCESS;
+}
+
+typedef struct SpaprVFIOErrinjctBarMatch {
+ uint64_t guest_addr;
+
+ PCIDevice *pdev;
+ VFIOPCIDevice *vdev;
+ int bar;
+
+ uint64_t guest_bar_start;
+ uint64_t bar_size;
+ uint64_t offset;
+} SpaprVFIOErrinjctBarMatch;
+
+static VFIOPCIDevice *spapr_vfio_errinjct_pci_to_vfio(PCIDevice *pdev)
+{
+ if (!object_dynamic_cast(OBJECT(pdev), TYPE_VFIO_PCI)) {
+ return NULL;
+ }
+
+ return container_of(pdev, VFIOPCIDevice, parent_obj);
+}
+
+static void spapr_vfio_errinjct_find_bar_cb(PCIBus *bus,
+ PCIDevice *pdev,
+ void *opaque)
+{
+ SpaprVFIOErrinjctBarMatch *ctx = opaque;
+ VFIOPCIDevice *vdev;
+ int bar;
+
+ if (ctx->pdev) {
+ return;
+ }
+
+ vdev = spapr_vfio_errinjct_pci_to_vfio(pdev);
+ if (!vdev) {
+ return;
+ }
+
+ for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
+ pcibus_t guest_bar_start;
+ uint64_t bar_size;
+ uint64_t offset;
+
+ bar_size = vdev->bars[bar].region.size;
+ if (!bar_size) {
+ continue;
+ }
+
+ guest_bar_start = pci_get_bar_addr(pdev, bar);
+ if (guest_bar_start == PCI_BAR_UNMAPPED) {
+ continue;
+ }
+
+ if (ctx->guest_addr < guest_bar_start ||
+ ctx->guest_addr - guest_bar_start >= bar_size) {
+ if (vdev->bars[bar].mem64) {
+ bar++;
+ }
+ continue;
+ }
+
+ offset = ctx->guest_addr - guest_bar_start;
+
+ ctx->pdev = pdev;
+ ctx->vdev = vdev;
+ ctx->bar = bar;
+ ctx->guest_bar_start = guest_bar_start;
+ ctx->bar_size = bar_size;
+ ctx->offset = offset;
+
+ return;
+ }
+}
+
+static int spapr_vfio_errinjct_get_host_bar(VFIOPCIDevice *vdev,
+ int bar,
+ uint64_t *host_bar_start)
+{
+ g_autofree char *path = NULL;
+ g_autofree char *contents = NULL;
+ char *line;
+ char *saveptr = NULL;
+ unsigned long long start;
+ unsigned long long end;
+ unsigned long long flags;
+ int i;
+
+ if (!vdev || !host_bar_start || bar < 0 || bar >= PCI_STD_NUM_BARS) {
+ return -EINVAL;
+ }
+
+ /*
+ * Read the host Linux sysfs resource file for the BAR. Do not use a
+ * VFIO PCI config-space read because that may return the
+ * guest-programmed BAR value rather than the host resource address.
+ */
+ path = g_strdup_printf("/sys/bus/pci/devices/%04x:%02x:%02x.%u/resource",
+ vdev->host.domain,
+ vdev->host.bus,
+ vdev->host.slot,
+ vdev->host.function);
+
+ if (!g_file_get_contents(path, &contents, NULL, NULL)) {
+ error_report("vfio/eeh errinjct: failed to read %s", path);
+ return -ENOENT;
+ }
+
+ line = strtok_r(contents, "\n", &saveptr);
+
+ for (i = 0; line; i++, line = strtok_r(NULL, "\n", &saveptr)) {
+ if (i != bar) {
+ continue;
+ }
+
+ if (sscanf(line, "%llx %llx %llx", &start, &end, &flags) != 3) {
+ error_report("vfio/eeh errinjct: malformed %s BAR%d",
+ path, bar);
+ return -EINVAL;
+ }
+
+ if (!start || end < start) {
+ error_report("vfio/eeh errinjct: invalid host resource BAR%d "
+ "start=0x%llx end=0x%llx flags=0x%llx",
+ bar, start, end, flags);
+ return -EINVAL;
+ }
+
+ *host_bar_start = start;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+int spapr_phb_vfio_translate_errinjct_addr(SpaprPhbState *sphb,
+ uint32_t config_addr,
+ uint64_t guest_addr,
+ uint64_t *host_pci_bus_addr)
+{
+ PCIHostState *phb;
+ SpaprVFIOErrinjctBarMatch ctx = {
+ .guest_addr = guest_addr,
+ .pdev = NULL,
+ .vdev = NULL,
+ .bar = -1,
+ };
+ uint64_t host_bar_start;
+ int rc;
+
+ if (!sphb || !host_pci_bus_addr) {
+ return -EINVAL;
+ }
+
+ phb = PCI_HOST_BRIDGE(sphb);
+
+ /*
+ * BUID has already selected @sphb before this helper is called.
+ * config_addr is retained for logging/debug only. Do not rely on it
+ * to find the target device; some RTAS IOA buffers may not carry a
+ * valid guest BDF-style config address. Scan VFIO BARs under this
+ * PHB and match guest_addr against the guest BAR layout instead.
+ */
+ pci_for_each_device_under_bus(phb->bus,
+ spapr_vfio_errinjct_find_bar_cb,
+ &ctx);
+
+ if (!ctx.pdev) {
+ error_report("vfio/eeh errinjct: guest addr 0x%" PRIx64
+ " not within any VFIO BAR under BUID=0x%016" PRIx64
+ " config_addr=0x%08x",
+ guest_addr, sphb->buid, config_addr);
+ return -ENODEV;
+ }
+
+ rc = spapr_vfio_errinjct_get_host_bar(ctx.vdev, ctx.bar, &host_bar_start);
+ if (rc) {
+ error_report("vfio/eeh errinjct: failed to get host BAR%d for "
+ "dev=%s BUID=0x%016" PRIx64 " config_addr=0x%08x rc=%d",
+ ctx.bar, ctx.pdev->name, sphb->buid, config_addr, rc);
+ return rc;
+ }
+
+ if (host_bar_start == ctx.guest_bar_start) {
+ error_report("vfio/eeh errinjct: refusing guest BAR as host BAR: "
+ "dev=%s BAR%d guest_bar=0x%" PRIx64
+ " host_bar=0x%" PRIx64,
+ ctx.pdev->name, ctx.bar,
+ ctx.guest_bar_start, host_bar_start);
+ return -EOPNOTSUPP;
+ }
+
+ *host_pci_bus_addr = host_bar_start + ctx.offset;
+ return 0;
+}
+
+static int spapr_vfio_errinjct_rtas_type_to_vfio(uint32_t rtas_type)
+{
+ switch (rtas_type) {
+ case RTAS_ERR_TYPE_IOA_BUS_ERROR:
+ return EEH_ERR_TYPE_32;
+ case RTAS_ERR_TYPE_IOA_BUS_ERROR_64:
+ return EEH_ERR_TYPE_64;
+ default:
+ return -1;
+ }
+}
+
+static bool spapr_vfio_errinjct_func_valid(uint32_t func)
+{
+ return func <= EEH_ERR_FUNC_MAX;
+}
+
+int spapr_phb_vfio_errinjct(SpaprPhbState *sphb, uint32_t type,
+ uint32_t func, uint64_t addr, uint64_t mask)
+{
+ VFIOLegacyContainer *container;
+ struct vfio_eeh_pe_op op = {
+ .op = VFIO_EEH_PE_INJECT_ERR,
+ .argsz = sizeof(op),
+ };
+ int vfio_type;
+
+ if (!sphb) {
+ return RTAS_OUT_PARAM_ERROR;
+ }
+
+ if (!spapr_vfio_errinjct_func_valid(func)) {
+ return RTAS_OUT_PARAM_ERROR;
+ }
+
+ vfio_type = spapr_vfio_errinjct_rtas_type_to_vfio(type);
+ if (vfio_type < 0) {
+ return RTAS_OUT_NOT_SUPPORTED;
+ }
+
+ container = vfio_eeh_as_container(&sphb->iommu_as);
+ if (!container) {
+ error_report("vfio/eeh errinjct: no VFIO EEH container for PHB");
+ return RTAS_OUT_NOT_SUPPORTED;
+ }
+
+ op.err.type = vfio_type;
+ op.err.func = func;
+ op.err.addr = addr;
+ op.err.mask = mask;
+
+ if (ioctl(container->fd, VFIO_EEH_PE_OP, &op) < 0) {
+ error_report("vfio/eeh errinjct: VFIO_EEH_PE_OP failed: %s",
+ strerror(errno));
+ switch (errno) {
+ case EINVAL:
+ return RTAS_OUT_PARAM_ERROR;
+ case ENOTTY:
+ case EOPNOTSUPP:
+ return RTAS_OUT_NOT_SUPPORTED;
+ default:
+ return RTAS_OUT_HW_ERROR;
+ }
+ }
+
+ return RTAS_OUT_SUCCESS;
+}
+
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index 20cb913f12..33a1011890 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -33,6 +33,7 @@
#include "hw/pci/msix.h"
#include "hw/pci/pci_host.h"
#include "hw/ppc/spapr.h"
+#include "hw/ppc/spapr_vfio.h"
#include "hw/pci-host/spapr.h"
#include <libfdt.h>
#include "trace.h"
diff --git a/hw/ppc/spapr_pci_vfio.c b/hw/ppc/spapr_pci_vfio.c
index 2f428531cc..e6ecc3f1ee 100644
--- a/hw/ppc/spapr_pci_vfio.c
+++ b/hw/ppc/spapr_pci_vfio.c
@@ -22,120 +22,12 @@
#include <linux/vfio.h>
#include "hw/ppc/spapr.h"
#include "hw/pci-host/spapr.h"
+#include "hw/ppc/spapr_vfio.h"
#include "hw/pci/msix.h"
#include "hw/pci/pci_device.h"
#include "hw/vfio/vfio-container-legacy.h"
#include "qemu/error-report.h"
#include "hw/vfio/pci.h"
-#include CONFIG_DEVICES /* CONFIG_VFIO_PCI */
-
-/*
- * Interfaces for IBM EEH (Enhanced Error Handling)
- */
-#ifdef CONFIG_VFIO_PCI
-static bool vfio_eeh_container_ok(VFIOLegacyContainer *container)
-{
- /*
- * As of 2016-03-04 (linux-4.5) the host kernel EEH/VFIO
- * implementation is broken if there are multiple groups in a
- * container. The hardware works in units of Partitionable
- * Endpoints (== IOMMU groups) and the EEH operations naively
- * iterate across all groups in the container, without any logic
- * to make sure the groups have their state synchronized. For
- * certain operations (ENABLE) that might be ok, until an error
- * occurs, but for others (GET_STATE) it's clearly broken.
- */
-
- /*
- * XXX Once fixed kernels exist, test for them here
- */
-
- if (QLIST_EMPTY(&container->group_list)) {
- return false;
- }
-
- if (QLIST_NEXT(QLIST_FIRST(&container->group_list), container_next)) {
- return false;
- }
-
- return true;
-}
-
-static int vfio_eeh_container_op(VFIOLegacyContainer *container, uint32_t op)
-{
- struct vfio_eeh_pe_op pe_op = {
- .argsz = sizeof(pe_op),
- .op = op,
- };
- int ret;
-
- if (!vfio_eeh_container_ok(container)) {
- error_report("vfio/eeh: EEH_PE_OP 0x%x: "
- "kernel requires a container with exactly one group", op);
- return -EPERM;
- }
-
- ret = ioctl(container->fd, VFIO_EEH_PE_OP, &pe_op);
- if (ret < 0) {
- error_report("vfio/eeh: EEH_PE_OP 0x%x failed: %m", op);
- return -errno;
- }
-
- return ret;
-}
-
-static VFIOLegacyContainer *vfio_eeh_as_container(AddressSpace *as)
-{
- VFIOAddressSpace *space = vfio_address_space_get(as);
- VFIOContainer *bcontainer = NULL;
-
- if (QLIST_EMPTY(&space->containers)) {
- /* No containers to act on */
- goto out;
- }
-
- bcontainer = QLIST_FIRST(&space->containers);
-
- if (QLIST_NEXT(bcontainer, next)) {
- /*
- * We don't yet have logic to synchronize EEH state across
- * multiple containers
- */
- bcontainer = NULL;
- goto out;
- }
-
-out:
- vfio_address_space_put(space);
- return VFIO_IOMMU_LEGACY(bcontainer);
-}
-
-static bool vfio_eeh_as_ok(AddressSpace *as)
-{
- VFIOLegacyContainer *container = vfio_eeh_as_container(as);
-
- return (container != NULL) && vfio_eeh_container_ok(container);
-}
-
-static int vfio_eeh_as_op(AddressSpace *as, uint32_t op)
-{
- VFIOLegacyContainer *container = vfio_eeh_as_container(as);
-
- if (!container) {
- return -ENODEV;
- }
- return vfio_eeh_container_op(container, op);
-}
-
-bool spapr_phb_eeh_available(SpaprPhbState *sphb)
-{
- return vfio_eeh_as_ok(&sphb->iommu_as);
-}
-
-static void spapr_phb_vfio_eeh_reenable(SpaprPhbState *sphb)
-{
- vfio_eeh_as_op(&sphb->iommu_as, VFIO_EEH_PE_ENABLE);
-}
void spapr_phb_vfio_reset(DeviceState *qdev)
{
@@ -147,484 +39,3 @@ void spapr_phb_vfio_reset(DeviceState *qdev)
*/
spapr_phb_vfio_eeh_reenable(SPAPR_PCI_HOST_BRIDGE(qdev));
}
-
-static void spapr_eeh_pci_find_device(PCIBus *bus, PCIDevice *pdev,
- void *opaque)
-{
- bool *found = opaque;
-
- if (object_dynamic_cast(OBJECT(pdev), "vfio-pci")) {
- *found = true;
- }
-}
-
-int spapr_phb_vfio_eeh_set_option(SpaprPhbState *sphb,
- unsigned int addr, int option)
-{
- uint32_t op;
- int ret;
-
- switch (option) {
- case RTAS_EEH_DISABLE:
- op = VFIO_EEH_PE_DISABLE;
- break;
- case RTAS_EEH_ENABLE: {
- PCIHostState *phb;
- bool found = false;
-
- /*
- * The EEH functionality is enabled per sphb level instead of
- * per PCI device. We have already identified this specific sphb
- * based on buid passed as argument to ibm,set-eeh-option rtas
- * call. Now we just need to check the validity of the PCI
- * pass-through devices (vfio-pci) under this sphb bus.
- * We have already validated that all the devices under this sphb
- * are from same iommu group (within same PE) before coming here.
- *
- * Prior to linux commit 98ba956f6a389 ("powerpc/pseries/eeh:
- * Rework device EEH PE determination") kernel would call
- * eeh-set-option for each device in the PE using the device's
- * config_address as the argument rather than the PE address.
- * Hence if we check validity of supplied config_addr whether
- * it matches to this PHB will cause issues with older kernel
- * versions v5.9 and older. If we return an error from
- * eeh-set-option when the argument isn't a valid PE address
- * then older kernels (v5.9 and older) will interpret that as
- * EEH not being supported.
- */
- phb = PCI_HOST_BRIDGE(sphb);
- pci_for_each_device(phb->bus, (addr >> 16) & 0xFF,
- spapr_eeh_pci_find_device, &found);
-
- if (!found) {
- return RTAS_OUT_PARAM_ERROR;
- }
-
- op = VFIO_EEH_PE_ENABLE;
- break;
- }
- case RTAS_EEH_THAW_IO:
- op = VFIO_EEH_PE_UNFREEZE_IO;
- break;
- case RTAS_EEH_THAW_DMA:
- op = VFIO_EEH_PE_UNFREEZE_DMA;
- break;
- default:
- return RTAS_OUT_PARAM_ERROR;
- }
-
- ret = vfio_eeh_as_op(&sphb->iommu_as, op);
- if (ret < 0) {
- return RTAS_OUT_HW_ERROR;
- }
-
- return RTAS_OUT_SUCCESS;
-}
-
-int spapr_phb_vfio_eeh_get_state(SpaprPhbState *sphb, int *state)
-{
- int ret;
-
- ret = vfio_eeh_as_op(&sphb->iommu_as, VFIO_EEH_PE_GET_STATE);
- if (ret < 0) {
- return RTAS_OUT_PARAM_ERROR;
- }
-
- *state = ret;
- return RTAS_OUT_SUCCESS;
-}
-
-static void spapr_phb_vfio_eeh_clear_dev_msix(PCIBus *bus,
- PCIDevice *pdev,
- void *opaque)
-{
- /* Check if the device is VFIO PCI device */
- if (!object_dynamic_cast(OBJECT(pdev), "vfio-pci")) {
- return;
- }
-
- /*
- * The MSIx table will be cleaned out by reset. We need
- * disable it so that it can be reenabled properly. Also,
- * the cached MSIx table should be cleared as it's not
- * reflecting the contents in hardware.
- */
- if (msix_enabled(pdev)) {
- uint16_t flags;
-
- flags = pci_host_config_read_common(pdev,
- pdev->msix_cap + PCI_MSIX_FLAGS,
- pci_config_size(pdev), 2);
- flags &= ~PCI_MSIX_FLAGS_ENABLE;
- pci_host_config_write_common(pdev,
- pdev->msix_cap + PCI_MSIX_FLAGS,
- pci_config_size(pdev), flags, 2);
- }
-
- msix_reset(pdev);
-}
-
-static void spapr_phb_vfio_eeh_clear_bus_msix(PCIBus *bus, void *opaque)
-{
- pci_for_each_device_under_bus(bus, spapr_phb_vfio_eeh_clear_dev_msix,
- NULL);
-}
-
-static void spapr_phb_vfio_eeh_pre_reset(SpaprPhbState *sphb)
-{
- PCIHostState *phb = PCI_HOST_BRIDGE(sphb);
-
- pci_for_each_bus(phb->bus, spapr_phb_vfio_eeh_clear_bus_msix, NULL);
-}
-
-int spapr_phb_vfio_eeh_reset(SpaprPhbState *sphb, int option)
-{
- uint32_t op;
- int ret;
-
- switch (option) {
- case RTAS_SLOT_RESET_DEACTIVATE:
- op = VFIO_EEH_PE_RESET_DEACTIVATE;
- break;
- case RTAS_SLOT_RESET_HOT:
- spapr_phb_vfio_eeh_pre_reset(sphb);
- op = VFIO_EEH_PE_RESET_HOT;
- break;
- case RTAS_SLOT_RESET_FUNDAMENTAL:
- spapr_phb_vfio_eeh_pre_reset(sphb);
- op = VFIO_EEH_PE_RESET_FUNDAMENTAL;
- break;
- default:
- return RTAS_OUT_PARAM_ERROR;
- }
-
- ret = vfio_eeh_as_op(&sphb->iommu_as, op);
- if (ret < 0) {
- return RTAS_OUT_HW_ERROR;
- }
-
- return RTAS_OUT_SUCCESS;
-}
-
-int spapr_phb_vfio_eeh_configure(SpaprPhbState *sphb)
-{
- int ret;
-
- ret = vfio_eeh_as_op(&sphb->iommu_as, VFIO_EEH_PE_CONFIGURE);
- if (ret < 0) {
- return RTAS_OUT_PARAM_ERROR;
- }
-
- return RTAS_OUT_SUCCESS;
-}
-
-typedef struct SpaprVFIOErrinjctBarMatch {
- uint64_t guest_addr;
-
- PCIDevice *pdev;
- VFIOPCIDevice *vdev;
- int bar;
-
- uint64_t guest_bar_start;
- uint64_t bar_size;
- uint64_t offset;
-} SpaprVFIOErrinjctBarMatch;
-
-static VFIOPCIDevice *spapr_vfio_errinjct_pci_to_vfio(PCIDevice *pdev)
-{
- if (!object_dynamic_cast(OBJECT(pdev), TYPE_VFIO_PCI)) {
- return NULL;
- }
-
- return container_of(pdev, VFIOPCIDevice, parent_obj);
-}
-
-static void spapr_vfio_errinjct_find_bar_cb(PCIBus *bus,
- PCIDevice *pdev,
- void *opaque)
-{
- SpaprVFIOErrinjctBarMatch *ctx = opaque;
- VFIOPCIDevice *vdev;
- int bar;
-
- if (ctx->pdev) {
- return;
- }
-
- vdev = spapr_vfio_errinjct_pci_to_vfio(pdev);
- if (!vdev) {
- return;
- }
-
- for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
- pcibus_t guest_bar_start;
- uint64_t bar_size;
- uint64_t offset;
-
- bar_size = vdev->bars[bar].region.size;
- if (!bar_size) {
- continue;
- }
-
- guest_bar_start = pci_get_bar_addr(pdev, bar);
- if (guest_bar_start == PCI_BAR_UNMAPPED) {
- continue;
- }
-
- if (ctx->guest_addr < guest_bar_start ||
- ctx->guest_addr - guest_bar_start >= bar_size) {
- if (vdev->bars[bar].mem64) {
- bar++;
- }
- continue;
- }
-
- offset = ctx->guest_addr - guest_bar_start;
-
- ctx->pdev = pdev;
- ctx->vdev = vdev;
- ctx->bar = bar;
- ctx->guest_bar_start = guest_bar_start;
- ctx->bar_size = bar_size;
- ctx->offset = offset;
-
- return;
- }
-}
-
-static int spapr_vfio_errinjct_get_host_bar(VFIOPCIDevice *vdev,
- int bar,
- uint64_t *host_bar_start)
-{
- g_autofree char *path = NULL;
- g_autofree char *contents = NULL;
- char *line;
- char *saveptr = NULL;
- unsigned long long start;
- unsigned long long end;
- unsigned long long flags;
- int i;
-
- if (!vdev || !host_bar_start || bar < 0 || bar >= PCI_STD_NUM_BARS) {
- return -EINVAL;
- }
-
- /*
- * Read the host Linux sysfs resource file for the BAR. Do not use a
- * VFIO PCI config-space read because that may return the
- * guest-programmed BAR value rather than the host resource address.
- */
- path = g_strdup_printf("/sys/bus/pci/devices/%04x:%02x:%02x.%u/resource",
- vdev->host.domain,
- vdev->host.bus,
- vdev->host.slot,
- vdev->host.function);
-
- if (!g_file_get_contents(path, &contents, NULL, NULL)) {
- error_report("vfio/eeh errinjct: failed to read %s", path);
- return -ENOENT;
- }
-
- line = strtok_r(contents, "\n", &saveptr);
-
- for (i = 0; line; i++, line = strtok_r(NULL, "\n", &saveptr)) {
- if (i != bar) {
- continue;
- }
-
- if (sscanf(line, "%llx %llx %llx", &start, &end, &flags) != 3) {
- error_report("vfio/eeh errinjct: malformed %s BAR%d",
- path, bar);
- return -EINVAL;
- }
-
- if (!start || end < start) {
- error_report("vfio/eeh errinjct: invalid host resource BAR%d "
- "start=0x%llx end=0x%llx flags=0x%llx",
- bar, start, end, flags);
- return -EINVAL;
- }
-
- *host_bar_start = start;
- return 0;
- }
-
- return -EINVAL;
-}
-
-int spapr_phb_vfio_translate_errinjct_addr(SpaprPhbState *sphb,
- uint32_t config_addr,
- uint64_t guest_addr,
- uint64_t *host_pci_bus_addr)
-{
- PCIHostState *phb;
- SpaprVFIOErrinjctBarMatch ctx = {
- .guest_addr = guest_addr,
- .pdev = NULL,
- .vdev = NULL,
- .bar = -1,
- };
- uint64_t host_bar_start;
- int rc;
-
- if (!sphb || !host_pci_bus_addr) {
- return -EINVAL;
- }
-
- phb = PCI_HOST_BRIDGE(sphb);
-
- /*
- * BUID has already selected @sphb before this helper is called.
- * config_addr is retained for logging/debug only. Do not rely on it
- * to find the target device; some RTAS IOA buffers may not carry a
- * valid guest BDF-style config address. Scan VFIO BARs under this
- * PHB and match guest_addr against the guest BAR layout instead.
- */
- pci_for_each_device_under_bus(phb->bus,
- spapr_vfio_errinjct_find_bar_cb,
- &ctx);
-
- if (!ctx.pdev) {
- error_report("vfio/eeh errinjct: guest addr 0x%" PRIx64
- " not within any VFIO BAR under BUID=0x%016" PRIx64
- " config_addr=0x%08x",
- guest_addr, sphb->buid, config_addr);
- return -ENODEV;
- }
-
- rc = spapr_vfio_errinjct_get_host_bar(ctx.vdev, ctx.bar, &host_bar_start);
- if (rc) {
- error_report("vfio/eeh errinjct: failed to get host BAR%d for "
- "dev=%s BUID=0x%016" PRIx64 " config_addr=0x%08x rc=%d",
- ctx.bar, ctx.pdev->name, sphb->buid, config_addr, rc);
- return rc;
- }
-
- if (host_bar_start == ctx.guest_bar_start) {
- error_report("vfio/eeh errinjct: refusing guest BAR as host BAR: "
- "dev=%s BAR%d guest_bar=0x%" PRIx64
- " host_bar=0x%" PRIx64,
- ctx.pdev->name, ctx.bar,
- ctx.guest_bar_start, host_bar_start);
- return -EOPNOTSUPP;
- }
-
- *host_pci_bus_addr = host_bar_start + ctx.offset;
- return 0;
-}
-
-static int spapr_vfio_errinjct_rtas_type_to_vfio(uint32_t rtas_type)
-{
- switch (rtas_type) {
- case RTAS_ERR_TYPE_IOA_BUS_ERROR:
- return EEH_ERR_TYPE_32;
- case RTAS_ERR_TYPE_IOA_BUS_ERROR_64:
- return EEH_ERR_TYPE_64;
- default:
- return -1;
- }
-}
-
-static bool spapr_vfio_errinjct_func_valid(uint32_t func)
-{
- return func <= EEH_ERR_FUNC_MAX;
-}
-
-int spapr_phb_vfio_errinjct(SpaprPhbState *sphb, uint32_t type,
- uint32_t func, uint64_t addr, uint64_t mask)
-{
- VFIOLegacyContainer *container;
- struct vfio_eeh_pe_op op = {
- .op = VFIO_EEH_PE_INJECT_ERR,
- .argsz = sizeof(op),
- };
- int vfio_type;
-
- if (!sphb) {
- return RTAS_OUT_PARAM_ERROR;
- }
-
- if (!spapr_vfio_errinjct_func_valid(func)) {
- return RTAS_OUT_PARAM_ERROR;
- }
-
- vfio_type = spapr_vfio_errinjct_rtas_type_to_vfio(type);
- if (vfio_type < 0) {
- return RTAS_OUT_NOT_SUPPORTED;
- }
-
- container = vfio_eeh_as_container(&sphb->iommu_as);
- if (!container) {
- error_report("vfio/eeh errinjct: no VFIO EEH container for PHB");
- return RTAS_OUT_NOT_SUPPORTED;
- }
-
- op.err.type = vfio_type;
- op.err.func = func;
- op.err.addr = addr;
- op.err.mask = mask;
-
- if (ioctl(container->fd, VFIO_EEH_PE_OP, &op) < 0) {
- error_report("vfio/eeh errinjct: VFIO_EEH_PE_OP failed: %s",
- strerror(errno));
- switch (errno) {
- case EINVAL:
- return RTAS_OUT_PARAM_ERROR;
- case ENOTTY:
- case EOPNOTSUPP:
- return RTAS_OUT_NOT_SUPPORTED;
- default:
- return RTAS_OUT_HW_ERROR;
- }
- }
-
- return RTAS_OUT_SUCCESS;
-}
-
-#else
-
-bool spapr_phb_eeh_available(SpaprPhbState *sphb)
-{
- return false;
-}
-
-void spapr_phb_vfio_reset(DeviceState *qdev)
-{
-}
-
-int spapr_phb_vfio_eeh_set_option(SpaprPhbState *sphb,
- unsigned int addr, int option)
-{
- return RTAS_OUT_NOT_SUPPORTED;
-}
-
-int spapr_phb_vfio_eeh_get_state(SpaprPhbState *sphb, int *state)
-{
- return RTAS_OUT_NOT_SUPPORTED;
-}
-
-int spapr_phb_vfio_eeh_reset(SpaprPhbState *sphb, int option)
-{
- return RTAS_OUT_NOT_SUPPORTED;
-}
-
-int spapr_phb_vfio_eeh_configure(SpaprPhbState *sphb)
-{
- return RTAS_OUT_NOT_SUPPORTED;
-}
-
-int spapr_phb_vfio_errinjct(SpaprPhbState *sphb, uint32_t type,
- uint32_t func, uint64_t addr, uint64_t mask)
-{
- return RTAS_OUT_NOT_SUPPORTED;
-}
-
-int spapr_phb_vfio_translate_errinjct_addr(SpaprPhbState *sphb,
- uint32_t config_addr,
- uint64_t guest_addr,
- uint64_t *host_pci_bus_addr)
-{
- return -ENOTSUP;
-}
-
-#endif /* CONFIG_VFIO_PCI */
diff --git a/stubs/spapr_phb_vfio-stubs.c b/stubs/spapr_phb_vfio-stubs.c
new file mode 100644
index 0000000000..4d86d9000e
--- /dev/null
+++ b/stubs/spapr_phb_vfio-stubs.c
@@ -0,0 +1,62 @@
+/*
+ * Stubs for sPAPR PCI VFIO EEH
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/ppc/spapr_vfio.h"
+
+/* RTAS return codes */
+#define RTAS_OUT_NOT_SUPPORTED (-3)
+
+
+bool spapr_phb_eeh_available(SpaprPhbState *sphb)
+{
+ return false;
+}
+
+int spapr_phb_vfio_eeh_set_option(SpaprPhbState *sphb,
+ unsigned int addr, int option)
+{
+ return RTAS_OUT_NOT_SUPPORTED;
+}
+
+int spapr_phb_vfio_eeh_get_state(SpaprPhbState *sphb, int *state)
+{
+ return RTAS_OUT_NOT_SUPPORTED;
+}
+
+int spapr_phb_vfio_eeh_reset(SpaprPhbState *sphb, int option)
+{
+ return RTAS_OUT_NOT_SUPPORTED;
+}
+
+int spapr_phb_vfio_eeh_configure(SpaprPhbState *sphb)
+{
+ return RTAS_OUT_NOT_SUPPORTED;
+}
+
+void spapr_phb_vfio_reset(DeviceState *qdev)
+{
+}
+
+void spapr_phb_vfio_eeh_reenable(SpaprPhbState *sphb)
+{
+}
+
+int spapr_phb_vfio_errinjct(SpaprPhbState *sphb, uint32_t type,
+ uint32_t func, uint64_t addr, uint64_t mask)
+{
+ return RTAS_OUT_NOT_SUPPORTED;
+}
+
+int spapr_phb_vfio_translate_errinjct_addr(SpaprPhbState *sphb,
+ uint32_t config_addr,
+ uint64_t guest_addr,
+ uint64_t *host_pci_bus_addr)
+{
+ return -ENOTSUP;
+}
+
+
diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig
index 347dcce690..3714d708d9 100644
--- a/hw/ppc/Kconfig
+++ b/hw/ppc/Kconfig
@@ -6,7 +6,7 @@ config PSERIES
imply PCI_DEVICES
imply TEST_DEVICES
imply VIRTIO_VGA
- imply VFIO_PCI if LINUX # needed by spapr_pci_vfio.c
+ imply VFIO_PCI if LINUX # needed by spapr_pci_vfio.c and spapr_eeh.c
select NVDIMM
select DIMM
select PCI
diff --git a/hw/ppc/meson.build b/hw/ppc/meson.build
index 37aa535db2..4e03973440 100644
--- a/hw/ppc/meson.build
+++ b/hw/ppc/meson.build
@@ -36,6 +36,7 @@ ppc_ss.add(when: 'CONFIG_SPAPR_RNG', if_true: files('spapr_rng.c'))
if host_os == 'linux'
ppc_ss.add(when: 'CONFIG_PSERIES', if_true: files(
'spapr_pci_vfio.c',
+ 'spapr_eeh.c',
))
endif
diff --git a/stubs/meson.build b/stubs/meson.build
index 3b2f2680b1..2879d6f70e 100644
--- a/stubs/meson.build
+++ b/stubs/meson.build
@@ -90,6 +90,7 @@ if have_system
stub_ss.add(files('hmp-cmd-info_tlb.c'))
stub_ss.add(files('hmp-cmds-hw-s390x.c'))
stub_ss.add(files('hmp-cmds-target-i386.c'))
+ stub_ss.add(files('spapr_phb_vfio-stubs.c'))
endif
if have_system or have_user
--
2.51.1
next prev parent reply other threads:[~2026-09-01 17:43 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-01 17:41 [PATCH v5 0/6] ppc/spapr: Add RTAS error injection support for VFIO EEH Narayana Murty N
2026-09-01 17:41 ` [PATCH v5 1/6] ppc/spapr: Add VFIO EEH error injection backend Narayana Murty N
2026-09-01 17:41 ` [PATCH v5 2/6] ppc/spapr: Add ibm,errinjct RTAS call handler Narayana Murty N
2026-09-01 17:41 ` [PATCH v5 3/6] ppc/spapr: Add support for ibm, open-errinjct and ibm, close-errinjct Narayana Murty N
2026-09-01 17:41 ` [PATCH v5 4/6] ppc/spapr: Advertise RTAS error injection call support via FDT property Narayana Murty N
2026-09-01 17:41 ` Narayana Murty N [this message]
2026-09-01 17:41 ` [PATCH v5 6/6] MAINTAINERS: Add self as sPAPR EEH reviewer under PPC RAS Narayana Murty N
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260901174110.45356-6-nnmlinux@linux.ibm.com \
--to=nnmlinux@linux.ibm.com \
--cc=adityag@linux.ibm.com \
--cc=amachhiw@linux.ibm.com \
--cc=anushree.mathur@linux.vnet.ibm.com \
--cc=clg@redhat.com \
--cc=harshpb@linux.ibm.com \
--cc=hbathini@linux.ibm.com \
--cc=mahesh@linux.ibm.com \
--cc=nikhilks@linux.ibm.com \
--cc=npiggin@gmail.com \
--cc=pierrick.bouvier@oss.qualcomm.com \
--cc=qemu-devel@nongnu.org \
--cc=qemu-ppc@nongnu.org \
--cc=rathc@linux.ibm.com \
--cc=sbhat@linux.ibm.com \
--cc=shivangu@linux.ibm.com \
--cc=sourabhjain@linux.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.