mirror of https://gitee.com/openkylin/qemu.git
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…
Reference in New Issue