diff mbox

[RFC,10/14] spapr_pci: Track guest Partitionable Endpoints

Message ID 1442647117-2726-11-git-send-email-david@gibson.dropbear.id.au
State New
Headers show

Commit Message

David Gibson Sept. 19, 2015, 7:18 a.m. UTC
PAPR has a concept of Partitionable Endpoints (PEs) on PCI, which are
groups of devices that can't be isolated from each other, which is used in
the Enhanced Error Handling (EEH) interface.

At the moment, we don't model PEs in our PAPR host bridge implementation.
We get away with it because spapr-pci-host-bridge doesn't support the EEH
interfaces, and spapr-pci-vfio-host-bridge, which does, only supports
devices from a single IOMMU group, and therefore a single PE (although
that's not actually properly enforced).

In order to generalize this, this adds tracking of guest PEs to the PAPR
host bridge code.  For now, at least, we only construct PEs for VFIO
devices, since we don't implement EEH for emulated devices anyway
PEs.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr_pci.c          | 39 +++++++++++++++++++++++++++++++++++++++
 include/hw/pci-host/spapr.h |  8 ++++++++
 2 files changed, 47 insertions(+)
diff mbox

Patch

diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index 3a1ebea..81ad3ae 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -423,6 +423,29 @@  static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu,
     rtas_st(rets, 2, 1);/* 0 == level; 1 == edge */
 }
 
+static sPAPRPHBGuestPE *spapr_phb_pe_by_device(sPAPRPHBState *phb,
+                                               PCIDevice *pdev)
+{
+    VFIOGroup *group = vfio_pci_device_group(pdev);
+    sPAPRPHBGuestPE *pe;
+
+    if (!group) {
+        return NULL;
+    }
+
+    QLIST_FOREACH(pe, &phb->pe_list, list) {
+        if (pe->group == group) {
+            /* We already have a PE for this group */
+            return pe;
+        }
+    }
+
+    pe = g_malloc0(sizeof(*pe));
+    pe->group = group;
+    QLIST_INSERT_HEAD(&phb->pe_list, pe, list);
+    return pe;
+}
+
 static void rtas_ibm_set_eeh_option(PowerPCCPU *cpu,
                                     sPAPRMachineState *spapr,
                                     uint32_t token, uint32_t nargs,
@@ -1200,8 +1223,14 @@  static void spapr_phb_add_pci_device(sPAPRDRConnector *drc,
 
     if (object_dynamic_cast(OBJECT(pdev), "vfio-pci")) {
         sPAPRTCETable *tcet = spapr_tce_find_by_liobn(phb->dma_liobn);
+        sPAPRPHBGuestPE *pe;
 
         spapr_tce_need_vfio(tcet);
+
+        pe = spapr_phb_pe_by_device(phb, pdev);
+        if (pe) {
+            pe->num_devices++;
+        }
     }
 
     if (dev->hotplugged) {
@@ -1243,6 +1272,14 @@  static void spapr_phb_remove_pci_device(sPAPRDRConnector *drc,
                                         Error **errp)
 {
     sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+    sPAPRPHBGuestPE *pe =spapr_phb_pe_by_device(phb, pdev);
+
+    if (pe) {
+        if (--pe->num_devices == 0) {
+            QLIST_REMOVE(pe, list);
+            g_free(pe);
+        }
+    }
 
     drck->detach(drc, DEVICE(pdev), spapr_phb_remove_pci_device_cb, phb, errp);
 }
@@ -1501,6 +1538,8 @@  static void spapr_phb_realize(DeviceState *dev, Error **errp)
     info->finish_realize(sphb, errp);
 
     sphb->msi = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, g_free);
+
+    QLIST_INIT(&sphb->pe_list);
 }
 
 static void spapr_phb_finish_realize(sPAPRPHBState *sphb, Error **errp)
diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h
index 741fe65..535e5ef 100644
--- a/include/hw/pci-host/spapr.h
+++ b/include/hw/pci-host/spapr.h
@@ -62,6 +62,12 @@  typedef struct spapr_pci_msi_mig {
     spapr_pci_msi value;
 } spapr_pci_msi_mig;
 
+typedef struct sPAPRPHBGuestPE {
+    int num_devices;
+    VFIOGroup *group;
+    QLIST_ENTRY(sPAPRPHBGuestPE) list;
+} sPAPRPHBGuestPE;
+
 struct sPAPRPHBState {
     PCIHostState parent_obj;
 
@@ -88,6 +94,8 @@  struct sPAPRPHBState {
     int32_t msi_devs_num;
     spapr_pci_msi_mig *msi_devs;
 
+    QLIST_HEAD(, sPAPRPHBGuestPE) pe_list;
+
     QLIST_ENTRY(sPAPRPHBState) list;
 };