qemu-ppc
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-ppc] [PATCH 2/3] VFIO: Introduce EEH handler


From: Gavin Shan
Subject: [Qemu-ppc] [PATCH 2/3] VFIO: Introduce EEH handler
Date: Tue, 20 May 2014 18:40:40 +1000

The patch introduces vfio_eeh_handler(), which is going to handle
EEH RTAS request routed by sPAPR platform.

Signed-off-by: Gavin Shan <address@hidden>
---
 hw/misc/vfio.c         | 109 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/hw/misc/vfio.h |   2 +
 2 files changed, 111 insertions(+)

diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c
index 0796abf..537bd26 100644
--- a/hw/misc/vfio.c
+++ b/hw/misc/vfio.c
@@ -32,6 +32,7 @@
 #include "hw/pci/msi.h"
 #include "hw/pci/msix.h"
 #include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
 #include "qemu-common.h"
 #include "qemu/error-report.h"
 #include "qemu/event_notifier.h"
@@ -188,6 +189,7 @@ typedef struct VFIOMSIXInfo {
 typedef struct VFIODevice {
     PCIDevice pdev;
     int fd;
+    int pe_addr; /* EEH PE address */
     VFIOINTx intx;
     unsigned int config_size;
     uint8_t *emulated_config_bits; /* QEMU emulated bits, little-endian */
@@ -4086,6 +4088,9 @@ static int vfio_initfn(PCIDevice *pdev)
     add_boot_device_path(vdev->bootindex, &pdev->qdev, NULL);
     vfio_register_err_notifier(vdev);
 
+    /* Initialize EEH PE address to invalid one */
+    vdev->pe_addr = -1;
+
     return 0;
 
 out_teardown:
@@ -4310,3 +4315,107 @@ put_group_exit:
 
     return n;
 }
+
+static VFIODevice *vfio_dev_find_by_addr(PCIBus *rootbus, uint32_t bdn)
+{
+    VFIOGroup *group;
+    VFIODevice *vdev;
+    PCIDevice *pdev;
+
+    QLIST_FOREACH(group, &group_list, next) {
+        QLIST_FOREACH(vdev, &group->device_list, next) {
+            pdev = &vdev->pdev;
+            if (rootbus == pci_device_root_bus(pdev) &&
+                pdev == pci_find_device(rootbus,
+                                        (bdn >> 16) & 0xFF, (bdn >> 8) & 0xFF))
+                       return vdev;
+        }
+    }
+
+    return NULL;
+}
+
+static VFIODevice *vfio_dev_find_by_pe(PCIBus *rootbus, uint32_t pe_addr)
+{
+    VFIOGroup *group;
+    VFIODevice *vdev;
+    PCIDevice *pdev;
+
+    QLIST_FOREACH(group, &group_list, next) {
+        QLIST_FOREACH(vdev, &group->device_list, next) {
+            pdev = &vdev->pdev;
+            if (rootbus == pci_device_root_bus(pdev) &&
+                vdev->pe_addr == pe_addr)
+                       return vdev;
+        }
+    }
+
+    return NULL;
+}
+
+int vfio_eeh_handler(struct vfio_eeh_op *info,
+                     PCIBus *rootbus, uint32_t addr)
+{
+    int ret = 0;
+    VFIODevice *vdev;
+
+    switch (info->op) {
+    case VFIO_EEH_OP_SET_OPTION:
+        if (info->option.option == 1) {
+             vdev = vfio_dev_find_by_addr(rootbus, addr);
+        } else {
+             vdev = vfio_dev_find_by_pe(rootbus, addr);
+        }
+
+        if (!vdev) {
+            info->option.ret = -3;
+            return -ENODEV;
+        }
+
+        ret = ioctl(vdev->fd, VFIO_EEH_OP, info);
+        break;
+    case VFIO_EEH_OP_GET_ADDR:
+        vdev = vfio_dev_find_by_addr(rootbus, addr);
+        if (!vdev) {
+            info->addr.ret = -3;
+            return -ENODEV;
+        }
+
+        if (info->addr.option == 0) {
+            if (vdev->pe_addr != -1) {
+                 info->addr.ret = 0;
+                 info->addr.info = vdev->pe_addr;
+            } else {
+                ret = ioctl(vdev->fd, VFIO_EEH_OP, info);
+                if (ret == 0) {
+                    vdev->pe_addr = info->addr.info;
+                }
+            }
+        } else {
+            info->addr.ret = 0;
+            info->addr.info = 1;
+        }
+
+        break;
+    case VFIO_EEH_OP_GET_STATE:
+    case VFIO_EEH_OP_PE_RESET:
+    case VFIO_EEH_OP_PE_CONFIG:
+        vdev = vfio_dev_find_by_pe(rootbus, addr);
+        if (!vdev) {
+            if (info->op == VFIO_EEH_OP_GET_STATE) {
+                info->state.ret = -3;
+            } else if (info->op == VFIO_EEH_OP_PE_RESET) {
+                info->reset.ret = -3;
+            } else if (info->op == VFIO_EEH_OP_PE_CONFIG) {
+                info->config.ret = -3;
+            }
+
+            return -ENODEV;
+        }
+
+        ret = ioctl(vdev->fd, VFIO_EEH_OP, info);
+        break;
+    }
+
+    return ret;
+}
diff --git a/include/hw/misc/vfio.h b/include/hw/misc/vfio.h
index 53ec665..8f61755 100644
--- a/include/hw/misc/vfio.h
+++ b/include/hw/misc/vfio.h
@@ -30,4 +30,6 @@ static inline long vfio_kvm_notify(Notifier *n, unsigned 
request, void *data)
     return p.ret;
 }
 
+extern int vfio_eeh_handler(struct vfio_eeh_op *info,
+                            PCIBus *rootbus, uint32_t addr);
 #endif
-- 
1.8.3.2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]