Blame SOURCES/kvm-hw-pci-introduce-PCI-Expander-Bridge-PXB.patch

8be556
From 95cdd8dd0fa39e7865b9a3549ddb70a06e53d47b Mon Sep 17 00:00:00 2001
8be556
From: Marcel Apfelbaum <marcel@redhat.com>
8be556
Date: Wed, 24 Jun 2015 13:53:30 +0200
8be556
Subject: [PATCH 207/217] hw/pci: introduce PCI Expander Bridge (PXB)
8be556
8be556
Message-id: <1435154016-26233-38-git-send-email-marcel@redhat.com>
8be556
Patchwork-id: 66464
8be556
O-Subject: [RHEL-7.2 qemu-kvm-rhev PATCH 37/43] hw/pci: introduce PCI Expander Bridge (PXB)
8be556
Bugzilla: 1103313
8be556
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
8be556
RH-Acked-by: Michael S. Tsirkin <mst@redhat.com>
8be556
RH-Acked-by: Igor Mammedov <imammedo@redhat.com>
8be556
8be556
From: Marcel Apfelbaum <marcel.a@redhat.com>
8be556
8be556
PXB is a "light-weight" host bridge whose purpose is to enable
8be556
the main host bridge to support multiple PCI root buses
8be556
for pc machines.
8be556
8be556
As oposed to PCI-2-PCI bridge's secondary bus, PXB's bus
8be556
is a primary bus and can be associated with a NUMA node
8be556
(different from the main host bridge) allowing the guest OS
8be556
to recognize the proximity of a pass-through device to
8be556
other resources as RAM and CPUs.
8be556
8be556
The PXB is composed from:
8be556
 - A primary PCI bus (can be associated with a NUMA node)
8be556
   Acts like a normal pci bus and from the functionality point
8be556
   of view is an "expansion" of the bus behind the
8be556
   main host bridge.
8be556
 - A pci-2-pci bridge behind the primary PCI bus where the actual
8be556
   devices will be attached.
8be556
 - A host-bridge PCI device
8be556
   Situated on the bus behind the main host bridge, allows
8be556
   the BIOS to configure the bus number and IO/mem resources.
8be556
   It does not have its own config/data register for configuration
8be556
   cycles, this being handled by the main host bridge.
8be556
-  A host-bridge sysbus to comply with QEMU current design.
8be556
8be556
Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
8be556
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
8be556
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
8be556
Acked-by: Laszlo Ersek <lersek@redhat.com>
8be556
(cherry picked from commit 40d14bef8012087ade60f254487d31db822a1a44)
8be556
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
8be556
---
8be556
 hw/pci-bridge/Makefile.objs         |   1 +
8be556
 hw/pci-bridge/pci_expander_bridge.c | 196 ++++++++++++++++++++++++++++++++++++
8be556
 include/hw/pci/pci.h                |   1 +
8be556
 3 files changed, 198 insertions(+)
8be556
 create mode 100644 hw/pci-bridge/pci_expander_bridge.c
8be556
8be556
diff --git a/hw/pci-bridge/Makefile.objs b/hw/pci-bridge/Makefile.objs
8be556
index 96c596e..f2adfe3 100644
8be556
--- a/hw/pci-bridge/Makefile.objs
8be556
+++ b/hw/pci-bridge/Makefile.objs
8be556
@@ -1,4 +1,5 @@
8be556
 common-obj-y += pci_bridge_dev.o
8be556
+common-obj-y += pci_expander_bridge.o
8be556
 common-obj-$(CONFIG_XIO3130) += xio3130_upstream.o xio3130_downstream.o
8be556
 common-obj-$(CONFIG_IOH3420) += ioh3420.o
8be556
 common-obj-$(CONFIG_I82801B11) += i82801b11.o
8be556
diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c
8be556
new file mode 100644
8be556
index 0000000..88e85c1
8be556
--- /dev/null
8be556
+++ b/hw/pci-bridge/pci_expander_bridge.c
8be556
@@ -0,0 +1,196 @@
8be556
+/*
8be556
+ * PCI Expander Bridge Device Emulation
8be556
+ *
8be556
+ * Copyright (C) 2015 Red Hat Inc
8be556
+ *
8be556
+ * Authors:
8be556
+ *   Marcel Apfelbaum <marcel@redhat.com>
8be556
+ *
8be556
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
8be556
+ * See the COPYING file in the top-level directory.
8be556
+ */
8be556
+
8be556
+#include "hw/pci/pci.h"
8be556
+#include "hw/pci/pci_bus.h"
8be556
+#include "hw/pci/pci_host.h"
8be556
+#include "hw/pci/pci_bus.h"
8be556
+#include "hw/i386/pc.h"
8be556
+#include "qemu/range.h"
8be556
+#include "qemu/error-report.h"
8be556
+
8be556
+#define TYPE_PXB_BUS "pxb-bus"
8be556
+#define PXB_BUS(obj) OBJECT_CHECK(PXBBus, (obj), TYPE_PXB_BUS)
8be556
+
8be556
+typedef struct PXBBus {
8be556
+    /*< private >*/
8be556
+    PCIBus parent_obj;
8be556
+    /*< public >*/
8be556
+
8be556
+    char bus_path[8];
8be556
+} PXBBus;
8be556
+
8be556
+#define TYPE_PXB_DEVICE "pxb"
8be556
+#define PXB_DEV(obj) OBJECT_CHECK(PXBDev, (obj), TYPE_PXB_DEVICE)
8be556
+
8be556
+typedef struct PXBDev {
8be556
+    /*< private >*/
8be556
+    PCIDevice parent_obj;
8be556
+    /*< public >*/
8be556
+
8be556
+    uint8_t bus_nr;
8be556
+} PXBDev;
8be556
+
8be556
+#define TYPE_PXB_HOST "pxb-host"
8be556
+
8be556
+static int pxb_bus_num(PCIBus *bus)
8be556
+{
8be556
+    PXBDev *pxb = PXB_DEV(bus->parent_dev);
8be556
+
8be556
+    return pxb->bus_nr;
8be556
+}
8be556
+
8be556
+static bool pxb_is_root(PCIBus *bus)
8be556
+{
8be556
+    return true; /* by definition */
8be556
+}
8be556
+
8be556
+static void pxb_bus_class_init(ObjectClass *class, void *data)
8be556
+{
8be556
+    PCIBusClass *pbc = PCI_BUS_CLASS(class);
8be556
+
8be556
+    pbc->bus_num = pxb_bus_num;
8be556
+    pbc->is_root = pxb_is_root;
8be556
+}
8be556
+
8be556
+static const TypeInfo pxb_bus_info = {
8be556
+    .name          = TYPE_PXB_BUS,
8be556
+    .parent        = TYPE_PCI_BUS,
8be556
+    .instance_size = sizeof(PXBBus),
8be556
+    .class_init    = pxb_bus_class_init,
8be556
+};
8be556
+
8be556
+static const char *pxb_host_root_bus_path(PCIHostState *host_bridge,
8be556
+                                          PCIBus *rootbus)
8be556
+{
8be556
+    PXBBus *bus = PXB_BUS(rootbus);
8be556
+
8be556
+    snprintf(bus->bus_path, 8, "0000:%02x", pxb_bus_num(rootbus));
8be556
+    return bus->bus_path;
8be556
+}
8be556
+
8be556
+static void pxb_host_class_init(ObjectClass *class, void *data)
8be556
+{
8be556
+    DeviceClass *dc = DEVICE_CLASS(class);
8be556
+    PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(class);
8be556
+
8be556
+    dc->fw_name = "pci";
8be556
+    hc->root_bus_path = pxb_host_root_bus_path;
8be556
+}
8be556
+
8be556
+static const TypeInfo pxb_host_info = {
8be556
+    .name          = TYPE_PXB_HOST,
8be556
+    .parent        = TYPE_PCI_HOST_BRIDGE,
8be556
+    .class_init    = pxb_host_class_init,
8be556
+};
8be556
+
8be556
+/*
8be556
+ * Registers the PXB bus as a child of the i440fx root bus.
8be556
+ *
8be556
+ * Returns 0 on successs, -1 if i440fx host was not
8be556
+ * found or the bus number is already in use.
8be556
+ */
8be556
+static int pxb_register_bus(PCIDevice *dev, PCIBus *pxb_bus)
8be556
+{
8be556
+    PCIBus *bus = dev->bus;
8be556
+    int pxb_bus_num = pci_bus_num(pxb_bus);
8be556
+
8be556
+    if (bus->parent_dev) {
8be556
+        error_report("PXB devices can be attached only to root bus.");
8be556
+        return -1;
8be556
+    }
8be556
+
8be556
+    QLIST_FOREACH(bus, &bus->child, sibling) {
8be556
+        if (pci_bus_num(bus) == pxb_bus_num) {
8be556
+            error_report("Bus %d is already in use.", pxb_bus_num);
8be556
+            return -1;
8be556
+        }
8be556
+    }
8be556
+    QLIST_INSERT_HEAD(&dev->bus->child, pxb_bus, sibling);
8be556
+
8be556
+    return 0;
8be556
+}
8be556
+
8be556
+static int pxb_dev_initfn(PCIDevice *dev)
8be556
+{
8be556
+    PXBDev *pxb = PXB_DEV(dev);
8be556
+    DeviceState *ds, *bds;
8be556
+    PCIBus *bus;
8be556
+    const char *dev_name = NULL;
8be556
+
8be556
+    if (dev->qdev.id && *dev->qdev.id) {
8be556
+        dev_name = dev->qdev.id;
8be556
+    }
8be556
+
8be556
+    ds = qdev_create(NULL, TYPE_PXB_HOST);
8be556
+    bus = pci_bus_new(ds, "pxb-internal", NULL, NULL, 0, TYPE_PXB_BUS);
8be556
+
8be556
+    bus->parent_dev = dev;
8be556
+    bus->address_space_mem = dev->bus->address_space_mem;
8be556
+    bus->address_space_io = dev->bus->address_space_io;
8be556
+    bus->map_irq = pci_swizzle_map_irq_fn;
8be556
+
8be556
+    bds = qdev_create(BUS(bus), "pci-bridge");
8be556
+    bds->id = dev_name;
8be556
+    qdev_prop_set_uint8(bds, "chassis_nr", pxb->bus_nr);
8be556
+
8be556
+    PCI_HOST_BRIDGE(ds)->bus = bus;
8be556
+
8be556
+    if (pxb_register_bus(dev, bus)) {
8be556
+        return -EINVAL;
8be556
+    }
8be556
+
8be556
+    qdev_init_nofail(ds);
8be556
+    qdev_init_nofail(bds);
8be556
+
8be556
+    pci_word_test_and_set_mask(dev->config + PCI_STATUS,
8be556
+                               PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
8be556
+    pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_HOST);
8be556
+
8be556
+    return 0;
8be556
+}
8be556
+
8be556
+static Property pxb_dev_properties[] = {
8be556
+    /* Note: 0 is not a legal a PXB bus number. */
8be556
+    DEFINE_PROP_UINT8("bus_nr", PXBDev, bus_nr, 0),
8be556
+    DEFINE_PROP_END_OF_LIST(),
8be556
+};
8be556
+
8be556
+static void pxb_dev_class_init(ObjectClass *klass, void *data)
8be556
+{
8be556
+    DeviceClass *dc = DEVICE_CLASS(klass);
8be556
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
8be556
+
8be556
+    k->init = pxb_dev_initfn;
8be556
+    k->vendor_id = PCI_VENDOR_ID_REDHAT;
8be556
+    k->device_id = PCI_DEVICE_ID_REDHAT_PXB;
8be556
+    k->class_id = PCI_CLASS_BRIDGE_HOST;
8be556
+
8be556
+    dc->desc = "PCI Expander Bridge";
8be556
+    dc->props = pxb_dev_properties;
8be556
+}
8be556
+
8be556
+static const TypeInfo pxb_dev_info = {
8be556
+    .name          = TYPE_PXB_DEVICE,
8be556
+    .parent        = TYPE_PCI_DEVICE,
8be556
+    .instance_size = sizeof(PXBDev),
8be556
+    .class_init    = pxb_dev_class_init,
8be556
+};
8be556
+
8be556
+static void pxb_register_types(void)
8be556
+{
8be556
+    type_register_static(&pxb_bus_info);
8be556
+    type_register_static(&pxb_host_info);
8be556
+    type_register_static(&pxb_dev_info);
8be556
+}
8be556
+
8be556
+type_init(pxb_register_types)
8be556
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
8be556
index 9586b73..3d1d3ea 100644
8be556
--- a/include/hw/pci/pci.h
8be556
+++ b/include/hw/pci/pci.h
8be556
@@ -90,6 +90,7 @@
8be556
 #define PCI_DEVICE_ID_REDHAT_TEST        0x0005
8be556
 #define PCI_DEVICE_ID_REDHAT_SDHCI       0x0007
8be556
 #define PCI_DEVICE_ID_REDHAT_PCIE_HOST   0x0008
8be556
+#define PCI_DEVICE_ID_REDHAT_PXB         0x0009
8be556
 #define PCI_DEVICE_ID_REDHAT_QXL         0x0100
8be556
 
8be556
 #define FMT_PCIBUS                      PRIx64
8be556
-- 
8be556
1.8.3.1
8be556