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: Marcel Apfelbaum <marcel@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Marcel Apfelbaum 2015-11-26 18:00:27 +02:00 committed by Michael S. Tsirkin
parent d7fd0e6914
commit 02b07434be
2 changed files with 84 additions and 15 deletions

View File

@ -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)

View File

@ -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