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:
		
							parent
							
								
									d7fd0e6914
								
							
						
					
					
						commit
						02b07434be
					
				@ -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)
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user