Commit 02b07434 authored by Marcel Apfelbaum's avatar Marcel Apfelbaum Committed by Michael S. Tsirkin
Browse files

hw/pxb: introduce pxb-pcie expander for PCIe machines



The pxb-pcie is the counterpart of pxb for PCI express machines.
The new device re-uses the pxb code, but appears to the guests
as a different device. The pxb-pcie device does not have an internal
pci-pci bridge and exposes a PCIe root bus instead of a PCI one.

Signed-off-by: default avatarMarcel Apfelbaum <marcel@redhat.com>
Reviewed-by: default avatarMichael S. Tsirkin <mst@redhat.com>
Signed-off-by: default avatarMichael S. Tsirkin <mst@redhat.com>
parent d7fd0e69
Loading
Loading
Loading
Loading
+83 −15
Original line number Diff line number Diff line
@@ -23,6 +23,9 @@
#define TYPE_PXB_BUS "pxb-bus"
#define PXB_BUS(obj) OBJECT_CHECK(PXBBus, (obj), TYPE_PXB_BUS)

#define TYPE_PXB_PCIE_BUS "pxb-pcie-bus"
#define PXB_PCIE_BUS(obj) OBJECT_CHECK(PXBBus, (obj), TYPE_PXB_PCIE_BUS)

typedef struct PXBBus {
    /*< private >*/
    PCIBus parent_obj;
@@ -34,6 +37,9 @@ typedef struct PXBBus {
#define TYPE_PXB_DEVICE "pxb"
#define PXB_DEV(obj) OBJECT_CHECK(PXBDev, (obj), TYPE_PXB_DEVICE)

#define TYPE_PXB_PCIE_DEVICE "pxb-pcie"
#define PXB_PCIE_DEV(obj) OBJECT_CHECK(PXBDev, (obj), TYPE_PXB_PCIE_DEVICE)

typedef struct PXBDev {
    /*< private >*/
    PCIDevice parent_obj;
@@ -43,13 +49,18 @@ typedef struct PXBDev {
    uint16_t numa_node;
} PXBDev;

static PXBDev *convert_to_pxb(PCIDevice *dev)
{
    return pci_bus_is_express(dev->bus) ? PXB_PCIE_DEV(dev) : PXB_DEV(dev);
}

static GList *pxb_dev_list;

#define TYPE_PXB_HOST "pxb-host"

static int pxb_bus_num(PCIBus *bus)
{
    PXBDev *pxb = PXB_DEV(bus->parent_dev);
    PXBDev *pxb = convert_to_pxb(bus->parent_dev);

    return pxb->bus_nr;
}
@@ -61,7 +72,7 @@ static bool pxb_is_root(PCIBus *bus)

static uint16_t pxb_bus_numa_node(PCIBus *bus)
{
    PXBDev *pxb = PXB_DEV(bus->parent_dev);
    PXBDev *pxb = convert_to_pxb(bus->parent_dev);

    return pxb->numa_node;
}
@@ -82,10 +93,18 @@ static const TypeInfo pxb_bus_info = {
    .class_init    = pxb_bus_class_init,
};

static const TypeInfo pxb_pcie_bus_info = {
    .name          = TYPE_PXB_PCIE_BUS,
    .parent        = TYPE_PCIE_BUS,
    .instance_size = sizeof(PXBBus),
    .class_init    = pxb_bus_class_init,
};

static const char *pxb_host_root_bus_path(PCIHostState *host_bridge,
                                          PCIBus *rootbus)
{
    PXBBus *bus = PXB_BUS(rootbus);
    PXBBus *bus = pci_bus_is_express(rootbus) ?
                  PXB_PCIE_BUS(rootbus) : PXB_BUS(rootbus);

    snprintf(bus->bus_path, 8, "0000:%02x", pxb_bus_num(rootbus));
    return bus->bus_path;
@@ -103,7 +122,7 @@ static char *pxb_host_ofw_unit_address(const SysBusDevice *dev)

    pxb_host = PCI_HOST_BRIDGE(dev);
    pxb_bus = pxb_host->bus;
    pxb_dev = PXB_DEV(pxb_bus->parent_dev);
    pxb_dev = convert_to_pxb(pxb_bus->parent_dev);
    position = g_list_index(pxb_dev_list, pxb_dev);
    assert(position >= 0);

@@ -193,10 +212,10 @@ static gint pxb_compare(gconstpointer a, gconstpointer b)
           0;
}

static int pxb_dev_initfn(PCIDevice *dev)
static int pxb_dev_init_common(PCIDevice *dev, bool pcie)
{
    PXBDev *pxb = PXB_DEV(dev);
    DeviceState *ds, *bds;
    PXBDev *pxb = convert_to_pxb(dev);
    DeviceState *ds, *bds = NULL;
    PCIBus *bus;
    const char *dev_name = NULL;

@@ -211,18 +230,21 @@ static int pxb_dev_initfn(PCIDevice *dev)
    }

    ds = qdev_create(NULL, TYPE_PXB_HOST);
    if (pcie) {
        bus = pci_bus_new(ds, dev_name, NULL, NULL, 0, TYPE_PXB_PCIE_BUS);
    } else {
        bus = pci_bus_new(ds, "pxb-internal", NULL, NULL, 0, TYPE_PXB_BUS);
        bds = qdev_create(BUS(bus), "pci-bridge");
        bds->id = dev_name;
        qdev_prop_set_uint8(bds, PCI_BRIDGE_DEV_PROP_CHASSIS_NR, pxb->bus_nr);
        qdev_prop_set_bit(bds, PCI_BRIDGE_DEV_PROP_SHPC, false);
    }

    bus->parent_dev = dev;
    bus->address_space_mem = dev->bus->address_space_mem;
    bus->address_space_io = dev->bus->address_space_io;
    bus->map_irq = pxb_map_irq_fn;

    bds = qdev_create(BUS(bus), "pci-bridge");
    bds->id = dev_name;
    qdev_prop_set_uint8(bds, PCI_BRIDGE_DEV_PROP_CHASSIS_NR, pxb->bus_nr);
    qdev_prop_set_bit(bds, PCI_BRIDGE_DEV_PROP_SHPC, false);

    PCI_HOST_BRIDGE(ds)->bus = bus;

    if (pxb_register_bus(dev, bus)) {
@@ -230,7 +252,9 @@ static int pxb_dev_initfn(PCIDevice *dev)
    }

    qdev_init_nofail(ds);
    if (bds) {
        qdev_init_nofail(bds);
    }

    pci_word_test_and_set_mask(dev->config + PCI_STATUS,
                               PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
@@ -240,9 +264,19 @@ static int pxb_dev_initfn(PCIDevice *dev)
    return 0;
}

static int pxb_dev_initfn(PCIDevice *dev)
{
    if (pci_bus_is_express(dev->bus)) {
        error_report("pxb devices cannot reside on a PCIe bus!");
        return -EINVAL;
    }

    return pxb_dev_init_common(dev, false);
}

static void pxb_dev_exitfn(PCIDevice *pci_dev)
{
    PXBDev *pxb = PXB_DEV(pci_dev);
    PXBDev *pxb = convert_to_pxb(pci_dev);

    pxb_dev_list = g_list_remove(pxb_dev_list, pxb);
}
@@ -276,11 +310,45 @@ static const TypeInfo pxb_dev_info = {
    .class_init    = pxb_dev_class_init,
};

static int pxb_pcie_dev_initfn(PCIDevice *dev)
{
    if (!pci_bus_is_express(dev->bus)) {
        error_report("pxb-pcie devices cannot reside on a PCI bus!");
        return -EINVAL;
    }

    return pxb_dev_init_common(dev, true);
}

static void pxb_pcie_dev_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);
    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);

    k->init = pxb_pcie_dev_initfn;
    k->exit = pxb_dev_exitfn;
    k->vendor_id = PCI_VENDOR_ID_REDHAT;
    k->device_id = PCI_DEVICE_ID_REDHAT_PXB_PCIE;
    k->class_id = PCI_CLASS_BRIDGE_HOST;

    dc->desc = "PCI Express Expander Bridge";
    dc->props = pxb_dev_properties;
}

static const TypeInfo pxb_pcie_dev_info = {
    .name          = TYPE_PXB_PCIE_DEVICE,
    .parent        = TYPE_PCI_DEVICE,
    .instance_size = sizeof(PXBDev),
    .class_init    = pxb_pcie_dev_class_init,
};

static void pxb_register_types(void)
{
    type_register_static(&pxb_bus_info);
    type_register_static(&pxb_pcie_bus_info);
    type_register_static(&pxb_host_info);
    type_register_static(&pxb_dev_info);
    type_register_static(&pxb_pcie_dev_info);
}

type_init(pxb_register_types)
+1 −0
Original line number Diff line number Diff line
@@ -93,6 +93,7 @@
#define PCI_DEVICE_ID_REDHAT_PCIE_HOST   0x0008
#define PCI_DEVICE_ID_REDHAT_PXB         0x0009
#define PCI_DEVICE_ID_REDHAT_BRIDGE_SEAT 0x000a
#define PCI_DEVICE_ID_REDHAT_PXB_PCIE    0x000b
#define PCI_DEVICE_ID_REDHAT_QXL         0x0100

#define FMT_PCIBUS                      PRIx64