Blame SOURCES/kvm-spapr_pci-enable-basic-hotplug-operations.patch

8be556
From 5ff5f42d0e12141a66f7038902627c6802c4ec11 Mon Sep 17 00:00:00 2001
8be556
From: Laurent Vivier <lvivier@redhat.com>
8be556
Date: Thu, 25 Jun 2015 13:44:40 +0200
8be556
Subject: [PATCH 101/217] spapr_pci: enable basic hotplug operations
8be556
8be556
Message-id: <1435239881-28541-14-git-send-email-lvivier@redhat.com>
8be556
Patchwork-id: 66491
8be556
O-Subject: [RHEL7.2 qemu-kvm-rhev PATCH 13/14] spapr_pci: enable basic hotplug operations
8be556
Bugzilla: 1172478
8be556
RH-Acked-by: Michael S. Tsirkin <mst@redhat.com>
8be556
RH-Acked-by: Thomas Huth <thuth@redhat.com>
8be556
RH-Acked-by: David Gibson <dgibson@redhat.com>
8be556
8be556
From: Michael Roth <mdroth@linux.vnet.ibm.com>
8be556
8be556
This enables hotplug of PCI devices to a PHB. Upon hotplug we
8be556
generate the OF-nodes required by PAPR specification and
8be556
IEEE 1275-1994 "PCI Bus Binding to Open Firmware" for the
8be556
device.
8be556
8be556
We associate the corresponding FDT for these nodes with the DRC
8be556
corresponding to the slot, which will be fetched via
8be556
ibm,configure-connector RTAS calls by the guest as described by PAPR
8be556
specification.
8be556
8be556
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
8be556
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
8be556
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
8be556
Signed-off-by: Alexander Graf <agraf@suse.de>
8be556
(cherry picked from commit 7454c7af91bdd60216e2b6eead827c012bb4d0d0)
8be556
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
8be556
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
8be556
8be556
Conflicts:
8be556
	hw/ppc/spapr_pci.c
8be556
8be556
Conflicts on context of missing commits:
8be556
    46c5874 spapr_pci: Make find_phb()/find_dev() public
8be556
    ccf9ff8 spapr_pci: Rework device-tree rendering
8be556
---
8be556
 hw/ppc/spapr_pci.c | 399 ++++++++++++++++++++++++++++++++++++++++++++++++++---
8be556
 1 file changed, 380 insertions(+), 19 deletions(-)
8be556
8be556
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
8be556
index 4017279..c0a34ae 100644
8be556
--- a/hw/ppc/spapr_pci.c
8be556
+++ b/hw/ppc/spapr_pci.c
8be556
@@ -33,9 +33,11 @@
8be556
 #include <libfdt.h>
8be556
 #include "trace.h"
8be556
 #include "qemu/error-report.h"
8be556
+#include "qapi/qmp/qerror.h"
8be556
 
8be556
 #include "hw/pci/pci_bus.h"
8be556
 #include "hw/ppc/spapr_drc.h"
8be556
+#include "sysemu/device_tree.h"
8be556
 
8be556
 /* Copied from the kernel arch/powerpc/platforms/pseries/msi.c */
8be556
 #define RTAS_QUERY_FN           0
8be556
@@ -48,6 +50,14 @@
8be556
 #define RTAS_TYPE_MSI           1
8be556
 #define RTAS_TYPE_MSIX          2
8be556
 
8be556
+#define _FDT(exp) \
8be556
+    do { \
8be556
+        int ret = (exp);                                           \
8be556
+        if (ret < 0) {                                             \
8be556
+            return ret;                                            \
8be556
+        }                                                          \
8be556
+    } while (0)
8be556
+
8be556
 static sPAPRPHBState *find_phb(sPAPREnvironment *spapr, uint64_t buid)
8be556
 {
8be556
     sPAPRPHBState *sphb;
8be556
@@ -732,6 +742,368 @@ static AddressSpace *spapr_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
8be556
     return &phb->iommu_as;
8be556
 }
8be556
 
8be556
+/* Macros to operate with address in OF binding to PCI */
8be556
+#define b_x(x, p, l)    (((x) & ((1<<(l))-1)) << (p))
8be556
+#define b_n(x)          b_x((x), 31, 1) /* 0 if relocatable */
8be556
+#define b_p(x)          b_x((x), 30, 1) /* 1 if prefetchable */
8be556
+#define b_t(x)          b_x((x), 29, 1) /* 1 if the address is aliased */
8be556
+#define b_ss(x)         b_x((x), 24, 2) /* the space code */
8be556
+#define b_bbbbbbbb(x)   b_x((x), 16, 8) /* bus number */
8be556
+#define b_ddddd(x)      b_x((x), 11, 5) /* device number */
8be556
+#define b_fff(x)        b_x((x), 8, 3)  /* function number */
8be556
+#define b_rrrrrrrr(x)   b_x((x), 0, 8)  /* register number */
8be556
+
8be556
+/* for 'reg'/'assigned-addresses' OF properties */
8be556
+#define RESOURCE_CELLS_SIZE 2
8be556
+#define RESOURCE_CELLS_ADDRESS 3
8be556
+
8be556
+typedef struct ResourceFields {
8be556
+    uint32_t phys_hi;
8be556
+    uint32_t phys_mid;
8be556
+    uint32_t phys_lo;
8be556
+    uint32_t size_hi;
8be556
+    uint32_t size_lo;
8be556
+} QEMU_PACKED ResourceFields;
8be556
+
8be556
+typedef struct ResourceProps {
8be556
+    ResourceFields reg[8];
8be556
+    ResourceFields assigned[7];
8be556
+    uint32_t reg_len;
8be556
+    uint32_t assigned_len;
8be556
+} ResourceProps;
8be556
+
8be556
+/* fill in the 'reg'/'assigned-resources' OF properties for
8be556
+ * a PCI device. 'reg' describes resource requirements for a
8be556
+ * device's IO/MEM regions, 'assigned-addresses' describes the
8be556
+ * actual resource assignments.
8be556
+ *
8be556
+ * the properties are arrays of ('phys-addr', 'size') pairs describing
8be556
+ * the addressable regions of the PCI device, where 'phys-addr' is a
8be556
+ * RESOURCE_CELLS_ADDRESS-tuple of 32-bit integers corresponding to
8be556
+ * (phys.hi, phys.mid, phys.lo), and 'size' is a
8be556
+ * RESOURCE_CELLS_SIZE-tuple corresponding to (size.hi, size.lo).
8be556
+ *
8be556
+ * phys.hi = 0xYYXXXXZZ, where:
8be556
+ *   0xYY = npt000ss
8be556
+ *          |||   |
8be556
+ *          |||   +-- space code: 1 if IO region, 2 if MEM region
8be556
+ *          ||+------ for non-relocatable IO: 1 if aliased
8be556
+ *          ||        for relocatable IO: 1 if below 64KB
8be556
+ *          ||        for MEM: 1 if below 1MB
8be556
+ *          |+------- 1 if region is prefetchable
8be556
+ *          +-------- 1 if region is non-relocatable
8be556
+ *   0xXXXX = bbbbbbbb dddddfff, encoding bus, slot, and function
8be556
+ *            bits respectively
8be556
+ *   0xZZ = rrrrrrrr, the register number of the BAR corresponding
8be556
+ *          to the region
8be556
+ *
8be556
+ * phys.mid and phys.lo correspond respectively to the hi/lo portions
8be556
+ * of the actual address of the region.
8be556
+ *
8be556
+ * how the phys-addr/size values are used differ slightly between
8be556
+ * 'reg' and 'assigned-addresses' properties. namely, 'reg' has
8be556
+ * an additional description for the config space region of the
8be556
+ * device, and in the case of QEMU has n=0 and phys.mid=phys.lo=0
8be556
+ * to describe the region as relocatable, with an address-mapping
8be556
+ * that corresponds directly to the PHB's address space for the
8be556
+ * resource. 'assigned-addresses' always has n=1 set with an absolute
8be556
+ * address assigned for the resource. in general, 'assigned-addresses'
8be556
+ * won't be populated, since addresses for PCI devices are generally
8be556
+ * unmapped initially and left to the guest to assign.
8be556
+ *
8be556
+ * note also that addresses defined in these properties are, at least
8be556
+ * for PAPR guests, relative to the PHBs IO/MEM windows, and
8be556
+ * correspond directly to the addresses in the BARs.
8be556
+ *
8be556
+ * in accordance with PCI Bus Binding to Open Firmware,
8be556
+ * IEEE Std 1275-1994, section 4.1.1, as implemented by PAPR+ v2.7,
8be556
+ * Appendix C.
8be556
+ */
8be556
+static void populate_resource_props(PCIDevice *d, ResourceProps *rp)
8be556
+{
8be556
+    int bus_num = pci_bus_num(PCI_BUS(qdev_get_parent_bus(DEVICE(d))));
8be556
+    uint32_t dev_id = (b_bbbbbbbb(bus_num) |
8be556
+                       b_ddddd(PCI_SLOT(d->devfn)) |
8be556
+                       b_fff(PCI_FUNC(d->devfn)));
8be556
+    ResourceFields *reg, *assigned;
8be556
+    int i, reg_idx = 0, assigned_idx = 0;
8be556
+
8be556
+    /* config space region */
8be556
+    reg = &rp->reg[reg_idx++];
8be556
+    reg->phys_hi = cpu_to_be32(dev_id);
8be556
+    reg->phys_mid = 0;
8be556
+    reg->phys_lo = 0;
8be556
+    reg->size_hi = 0;
8be556
+    reg->size_lo = 0;
8be556
+
8be556
+    for (i = 0; i < PCI_NUM_REGIONS; i++) {
8be556
+        if (!d->io_regions[i].size) {
8be556
+            continue;
8be556
+        }
8be556
+
8be556
+        reg = &rp->reg[reg_idx++];
8be556
+
8be556
+        reg->phys_hi = cpu_to_be32(dev_id | b_rrrrrrrr(pci_bar(d, i)));
8be556
+        if (d->io_regions[i].type & PCI_BASE_ADDRESS_SPACE_IO) {
8be556
+            reg->phys_hi |= cpu_to_be32(b_ss(1));
8be556
+        } else {
8be556
+            reg->phys_hi |= cpu_to_be32(b_ss(2));
8be556
+        }
8be556
+        reg->phys_mid = 0;
8be556
+        reg->phys_lo = 0;
8be556
+        reg->size_hi = cpu_to_be32(d->io_regions[i].size >> 32);
8be556
+        reg->size_lo = cpu_to_be32(d->io_regions[i].size);
8be556
+
8be556
+        if (d->io_regions[i].addr == PCI_BAR_UNMAPPED) {
8be556
+            continue;
8be556
+        }
8be556
+
8be556
+        assigned = &rp->assigned[assigned_idx++];
8be556
+        assigned->phys_hi = cpu_to_be32(reg->phys_hi | b_n(1));
8be556
+        assigned->phys_mid = cpu_to_be32(d->io_regions[i].addr >> 32);
8be556
+        assigned->phys_lo = cpu_to_be32(d->io_regions[i].addr);
8be556
+        assigned->size_hi = reg->size_hi;
8be556
+        assigned->size_lo = reg->size_lo;
8be556
+    }
8be556
+
8be556
+    rp->reg_len = reg_idx * sizeof(ResourceFields);
8be556
+    rp->assigned_len = assigned_idx * sizeof(ResourceFields);
8be556
+}
8be556
+
8be556
+static int spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset,
8be556
+                                       int phb_index, int drc_index,
8be556
+                                       const char *drc_name)
8be556
+{
8be556
+    ResourceProps rp;
8be556
+    bool is_bridge = false;
8be556
+    int pci_status;
8be556
+
8be556
+    if (pci_default_read_config(dev, PCI_HEADER_TYPE, 1) ==
8be556
+        PCI_HEADER_TYPE_BRIDGE) {
8be556
+        is_bridge = true;
8be556
+    }
8be556
+
8be556
+    /* in accordance with PAPR+ v2.7 13.6.3, Table 181 */
8be556
+    _FDT(fdt_setprop_cell(fdt, offset, "vendor-id",
8be556
+                          pci_default_read_config(dev, PCI_VENDOR_ID, 2)));
8be556
+    _FDT(fdt_setprop_cell(fdt, offset, "device-id",
8be556
+                          pci_default_read_config(dev, PCI_DEVICE_ID, 2)));
8be556
+    _FDT(fdt_setprop_cell(fdt, offset, "revision-id",
8be556
+                          pci_default_read_config(dev, PCI_REVISION_ID, 1)));
8be556
+    _FDT(fdt_setprop_cell(fdt, offset, "class-code",
8be556
+                          pci_default_read_config(dev, PCI_CLASS_DEVICE, 2)
8be556
+                            << 8));
8be556
+    if (pci_default_read_config(dev, PCI_INTERRUPT_PIN, 1)) {
8be556
+        _FDT(fdt_setprop_cell(fdt, offset, "interrupts",
8be556
+                 pci_default_read_config(dev, PCI_INTERRUPT_PIN, 1)));
8be556
+    }
8be556
+
8be556
+    if (!is_bridge) {
8be556
+        _FDT(fdt_setprop_cell(fdt, offset, "min-grant",
8be556
+            pci_default_read_config(dev, PCI_MIN_GNT, 1)));
8be556
+        _FDT(fdt_setprop_cell(fdt, offset, "max-latency",
8be556
+            pci_default_read_config(dev, PCI_MAX_LAT, 1)));
8be556
+    }
8be556
+
8be556
+    if (pci_default_read_config(dev, PCI_SUBSYSTEM_ID, 2)) {
8be556
+        _FDT(fdt_setprop_cell(fdt, offset, "subsystem-id",
8be556
+                 pci_default_read_config(dev, PCI_SUBSYSTEM_ID, 2)));
8be556
+    }
8be556
+
8be556
+    if (pci_default_read_config(dev, PCI_SUBSYSTEM_VENDOR_ID, 2)) {
8be556
+        _FDT(fdt_setprop_cell(fdt, offset, "subsystem-vendor-id",
8be556
+                 pci_default_read_config(dev, PCI_SUBSYSTEM_VENDOR_ID, 2)));
8be556
+    }
8be556
+
8be556
+    _FDT(fdt_setprop_cell(fdt, offset, "cache-line-size",
8be556
+        pci_default_read_config(dev, PCI_CACHE_LINE_SIZE, 1)));
8be556
+
8be556
+    /* the following fdt cells are masked off the pci status register */
8be556
+    pci_status = pci_default_read_config(dev, PCI_STATUS, 2);
8be556
+    _FDT(fdt_setprop_cell(fdt, offset, "devsel-speed",
8be556
+                          PCI_STATUS_DEVSEL_MASK & pci_status));
8be556
+
8be556
+    if (pci_status & PCI_STATUS_FAST_BACK) {
8be556
+        _FDT(fdt_setprop(fdt, offset, "fast-back-to-back", NULL, 0));
8be556
+    }
8be556
+    if (pci_status & PCI_STATUS_66MHZ) {
8be556
+        _FDT(fdt_setprop(fdt, offset, "66mhz-capable", NULL, 0));
8be556
+    }
8be556
+    if (pci_status & PCI_STATUS_UDF) {
8be556
+        _FDT(fdt_setprop(fdt, offset, "udf-supported", NULL, 0));
8be556
+    }
8be556
+
8be556
+    /* NOTE: this is normally generated by firmware via path/unit name,
8be556
+     * but in our case we must set it manually since it does not get
8be556
+     * processed by OF beforehand
8be556
+     */
8be556
+    _FDT(fdt_setprop_string(fdt, offset, "name", "pci"));
8be556
+    _FDT(fdt_setprop(fdt, offset, "ibm,loc-code", drc_name, strlen(drc_name)));
8be556
+    _FDT(fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index));
8be556
+
8be556
+    _FDT(fdt_setprop_cell(fdt, offset, "#address-cells",
8be556
+                          RESOURCE_CELLS_ADDRESS));
8be556
+    _FDT(fdt_setprop_cell(fdt, offset, "#size-cells",
8be556
+                          RESOURCE_CELLS_SIZE));
8be556
+    _FDT(fdt_setprop_cell(fdt, offset, "ibm,req#msi-x",
8be556
+                          RESOURCE_CELLS_SIZE));
8be556
+
8be556
+    populate_resource_props(dev, &rp);
8be556
+    _FDT(fdt_setprop(fdt, offset, "reg", (uint8_t *)rp.reg, rp.reg_len));
8be556
+    _FDT(fdt_setprop(fdt, offset, "assigned-addresses",
8be556
+                     (uint8_t *)rp.assigned, rp.assigned_len));
8be556
+
8be556
+    return 0;
8be556
+}
8be556
+
8be556
+/* create OF node for pci device and required OF DT properties */
8be556
+static void *spapr_create_pci_child_dt(sPAPRPHBState *phb, PCIDevice *dev,
8be556
+                                       int drc_index, const char *drc_name,
8be556
+                                       int *dt_offset)
8be556
+{
8be556
+    void *fdt;
8be556
+    int offset, ret, fdt_size;
8be556
+    int slot = PCI_SLOT(dev->devfn);
8be556
+    int func = PCI_FUNC(dev->devfn);
8be556
+    char nodename[512];
8be556
+
8be556
+    fdt = create_device_tree(&fdt_size);
8be556
+    if (func != 0) {
8be556
+        sprintf(nodename, "pci@%d,%d", slot, func);
8be556
+    } else {
8be556
+        sprintf(nodename, "pci@%d", slot);
8be556
+    }
8be556
+    offset = fdt_add_subnode(fdt, 0, nodename);
8be556
+    ret = spapr_populate_pci_child_dt(dev, fdt, offset, phb->index, drc_index,
8be556
+                                      drc_name);
8be556
+    g_assert(!ret);
8be556
+
8be556
+    *dt_offset = offset;
8be556
+    return fdt;
8be556
+}
8be556
+
8be556
+static void spapr_phb_add_pci_device(sPAPRDRConnector *drc,
8be556
+                                     sPAPRPHBState *phb,
8be556
+                                     PCIDevice *pdev,
8be556
+                                     Error **errp)
8be556
+{
8be556
+    sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
8be556
+    DeviceState *dev = DEVICE(pdev);
8be556
+    int drc_index = drck->get_index(drc);
8be556
+    const char *drc_name = drck->get_name(drc);
8be556
+    void *fdt = NULL;
8be556
+    int fdt_start_offset = 0;
8be556
+
8be556
+    /* boot-time devices get their device tree node created by SLOF, but for
8be556
+     * hotplugged devices we need QEMU to generate it so the guest can fetch
8be556
+     * it via RTAS
8be556
+     */
8be556
+    if (dev->hotplugged) {
8be556
+        fdt = spapr_create_pci_child_dt(phb, pdev, drc_index, drc_name,
8be556
+                                        &fdt_start_offset);
8be556
+    }
8be556
+
8be556
+    drck->attach(drc, DEVICE(pdev),
8be556
+                 fdt, fdt_start_offset, !dev->hotplugged, errp);
8be556
+    if (*errp) {
8be556
+        g_free(fdt);
8be556
+    }
8be556
+}
8be556
+
8be556
+static void spapr_phb_remove_pci_device_cb(DeviceState *dev, void *opaque)
8be556
+{
8be556
+    /* some version guests do not wait for completion of a device
8be556
+     * cleanup (generally done asynchronously by the kernel) before
8be556
+     * signaling to QEMU that the device is safe, but instead sleep
8be556
+     * for some 'safe' period of time. unfortunately on a busy host
8be556
+     * this sleep isn't guaranteed to be long enough, resulting in
8be556
+     * bad things like IRQ lines being left asserted during final
8be556
+     * device removal. to deal with this we call reset just prior
8be556
+     * to finalizing the device, which will put the device back into
8be556
+     * an 'idle' state, as the device cleanup code expects.
8be556
+     */
8be556
+    pci_device_reset(PCI_DEVICE(dev));
8be556
+    object_unparent(OBJECT(dev));
8be556
+}
8be556
+
8be556
+static void spapr_phb_remove_pci_device(sPAPRDRConnector *drc,
8be556
+                                        sPAPRPHBState *phb,
8be556
+                                        PCIDevice *pdev,
8be556
+                                        Error **errp)
8be556
+{
8be556
+    sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
8be556
+
8be556
+    drck->detach(drc, DEVICE(pdev), spapr_phb_remove_pci_device_cb, phb, errp);
8be556
+}
8be556
+
8be556
+static sPAPRDRConnector *spapr_phb_get_pci_drc(sPAPRPHBState *phb,
8be556
+                                               PCIDevice *pdev)
8be556
+{
8be556
+    uint32_t busnr = pci_bus_num(PCI_BUS(qdev_get_parent_bus(DEVICE(pdev))));
8be556
+    return spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_PCI,
8be556
+                                    (phb->index << 16) |
8be556
+                                    (busnr << 8) |
8be556
+                                    pdev->devfn);
8be556
+}
8be556
+
8be556
+static void spapr_phb_hot_plug_child(HotplugHandler *plug_handler,
8be556
+                                     DeviceState *plugged_dev, Error **errp)
8be556
+{
8be556
+    sPAPRPHBState *phb = SPAPR_PCI_HOST_BRIDGE(DEVICE(plug_handler));
8be556
+    PCIDevice *pdev = PCI_DEVICE(plugged_dev);
8be556
+    sPAPRDRConnector *drc = spapr_phb_get_pci_drc(phb, pdev);
8be556
+    Error *local_err = NULL;
8be556
+
8be556
+    /* if DR is disabled we don't need to do anything in the case of
8be556
+     * hotplug or coldplug callbacks
8be556
+     */
8be556
+    if (!phb->dr_enabled) {
8be556
+        /* if this is a hotplug operation initiated by the user
8be556
+         * we need to let them know it's not enabled
8be556
+         */
8be556
+        if (plugged_dev->hotplugged) {
8be556
+            error_set(errp, QERR_BUS_NO_HOTPLUG,
8be556
+                      object_get_typename(OBJECT(phb)));
8be556
+        }
8be556
+        return;
8be556
+    }
8be556
+
8be556
+    g_assert(drc);
8be556
+
8be556
+    spapr_phb_add_pci_device(drc, phb, pdev, &local_err);
8be556
+    if (local_err) {
8be556
+        error_propagate(errp, local_err);
8be556
+        return;
8be556
+    }
8be556
+}
8be556
+
8be556
+static void spapr_phb_hot_unplug_child(HotplugHandler *plug_handler,
8be556
+                                       DeviceState *plugged_dev, Error **errp)
8be556
+{
8be556
+    sPAPRPHBState *phb = SPAPR_PCI_HOST_BRIDGE(DEVICE(plug_handler));
8be556
+    PCIDevice *pdev = PCI_DEVICE(plugged_dev);
8be556
+    sPAPRDRConnectorClass *drck;
8be556
+    sPAPRDRConnector *drc = spapr_phb_get_pci_drc(phb, pdev);
8be556
+    Error *local_err = NULL;
8be556
+
8be556
+    if (!phb->dr_enabled) {
8be556
+        error_set(errp, QERR_BUS_NO_HOTPLUG,
8be556
+                  object_get_typename(OBJECT(phb)));
8be556
+        return;
8be556
+    }
8be556
+
8be556
+    g_assert(drc);
8be556
+
8be556
+    drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
8be556
+    if (!drck->release_pending(drc)) {
8be556
+        spapr_phb_remove_pci_device(drc, phb, pdev, &local_err);
8be556
+        if (local_err) {
8be556
+            error_propagate(errp, local_err);
8be556
+            return;
8be556
+        }
8be556
+    }
8be556
+}
8be556
+
8be556
 static void spapr_phb_realize(DeviceState *dev, Error **errp)
8be556
 {
8be556
     SysBusDevice *s = SYS_BUS_DEVICE(dev);
8be556
@@ -825,6 +1197,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
8be556
                            &sphb->memspace, &sphb->iospace,
8be556
                            PCI_DEVFN(0, 0), PCI_NUM_PINS, TYPE_PCI_BUS);
8be556
     phb->bus = bus;
8be556
+    qbus_set_hotplug_handler(BUS(phb->bus), DEVICE(sphb), NULL);
8be556
 
8be556
     /*
8be556
      * Initialize PHB address space.
8be556
@@ -1061,6 +1434,7 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data)
8be556
     PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
8be556
     DeviceClass *dc = DEVICE_CLASS(klass);
8be556
     sPAPRPHBClass *spc = SPAPR_PCI_HOST_BRIDGE_CLASS(klass);
8be556
+    HotplugHandlerClass *hp = HOTPLUG_HANDLER_CLASS(klass);
8be556
 
8be556
     hc->root_bus_path = spapr_phb_root_bus_path;
8be556
     dc->realize = spapr_phb_realize;
8be556
@@ -1070,6 +1444,8 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data)
8be556
     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
8be556
     dc->cannot_instantiate_with_device_add_yet = false;
8be556
     spc->finish_realize = spapr_phb_finish_realize;
8be556
+    hp->plug = spapr_phb_hot_plug_child;
8be556
+    hp->unplug = spapr_phb_hot_unplug_child;
8be556
 }
8be556
 
8be556
 static const TypeInfo spapr_phb_info = {
8be556
@@ -1078,6 +1454,10 @@ static const TypeInfo spapr_phb_info = {
8be556
     .instance_size = sizeof(sPAPRPHBState),
8be556
     .class_init    = spapr_phb_class_init,
8be556
     .class_size    = sizeof(sPAPRPHBClass),
8be556
+    .interfaces    = (InterfaceInfo[]) {
8be556
+        { TYPE_HOTPLUG_HANDLER },
8be556
+        { }
8be556
+    }
8be556
 };
8be556
 
8be556
 PCIHostState *spapr_create_phb(sPAPREnvironment *spapr, int index)
8be556
@@ -1091,17 +1471,6 @@ PCIHostState *spapr_create_phb(sPAPREnvironment *spapr, int index)
8be556
     return PCI_HOST_BRIDGE(dev);
8be556
 }
8be556
 
8be556
-/* Macros to operate with address in OF binding to PCI */
8be556
-#define b_x(x, p, l)    (((x) & ((1<<(l))-1)) << (p))
8be556
-#define b_n(x)          b_x((x), 31, 1) /* 0 if relocatable */
8be556
-#define b_p(x)          b_x((x), 30, 1) /* 1 if prefetchable */
8be556
-#define b_t(x)          b_x((x), 29, 1) /* 1 if the address is aliased */
8be556
-#define b_ss(x)         b_x((x), 24, 2) /* the space code */
8be556
-#define b_bbbbbbbb(x)   b_x((x), 16, 8) /* bus number */
8be556
-#define b_ddddd(x)      b_x((x), 11, 5) /* device number */
8be556
-#define b_fff(x)        b_x((x), 8, 3)  /* function number */
8be556
-#define b_rrrrrrrr(x)   b_x((x), 0, 8)  /* register number */
8be556
-
8be556
 typedef struct sPAPRTCEDT {
8be556
     void *fdt;
8be556
     int node_off;
8be556
@@ -1171,14 +1540,6 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb,
8be556
         return bus_off;
8be556
     }
8be556
 
8be556
-#define _FDT(exp) \
8be556
-    do { \
8be556
-        int ret = (exp);                                           \
8be556
-        if (ret < 0) {                                             \
8be556
-            return ret;                                            \
8be556
-        }                                                          \
8be556
-    } while (0)
8be556
-
8be556
     /* Write PHB properties */
8be556
     _FDT(fdt_setprop_string(fdt, bus_off, "device_type", "pci"));
8be556
     _FDT(fdt_setprop_string(fdt, bus_off, "compatible", "IBM,Logical_PHB"));
8be556
-- 
8be556
1.8.3.1
8be556