hw/pci-bridge: format special OFW unit address for PXB host
We have agreed that OpenFirmware device paths in the "bootorder" fw_cfg file should follow the pattern /pci@i0cf8,%x/... for devices that live behind an extra root bus. The extra root bus in question is the %x'th among the extra root buses. (In other words, %x gives the position of the affected extra root bus relative to the other extra root buses, in bus_nr order.) %x starts at 1, and is formatted in hex. The portion of the unit address that comes before the comma is dynamically taken from the main host bridge, similarly to sysbus_get_fw_dev_path(). Cc: Kevin O'Connor <kevin@koconnor.net> Cc: Michael S. Tsirkin <mst@redhat.com> Cc: Marcel Apfelbaum <marcel@redhat.com> Signed-off-by: Laszlo Ersek <lersek@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
0b336b3b98
commit
48ea3dedc5
|
@ -43,6 +43,8 @@ typedef struct PXBDev {
|
||||||
uint16_t numa_node;
|
uint16_t numa_node;
|
||||||
} PXBDev;
|
} PXBDev;
|
||||||
|
|
||||||
|
static GList *pxb_dev_list;
|
||||||
|
|
||||||
#define TYPE_PXB_HOST "pxb-host"
|
#define TYPE_PXB_HOST "pxb-host"
|
||||||
|
|
||||||
static int pxb_bus_num(PCIBus *bus)
|
static int pxb_bus_num(PCIBus *bus)
|
||||||
|
@ -89,12 +91,45 @@ static const char *pxb_host_root_bus_path(PCIHostState *host_bridge,
|
||||||
return bus->bus_path;
|
return bus->bus_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *pxb_host_ofw_unit_address(const SysBusDevice *dev)
|
||||||
|
{
|
||||||
|
const PCIHostState *pxb_host;
|
||||||
|
const PCIBus *pxb_bus;
|
||||||
|
const PXBDev *pxb_dev;
|
||||||
|
int position;
|
||||||
|
const DeviceState *pxb_dev_base;
|
||||||
|
const PCIHostState *main_host;
|
||||||
|
const SysBusDevice *main_host_sbd;
|
||||||
|
|
||||||
|
pxb_host = PCI_HOST_BRIDGE(dev);
|
||||||
|
pxb_bus = pxb_host->bus;
|
||||||
|
pxb_dev = PXB_DEV(pxb_bus->parent_dev);
|
||||||
|
position = g_list_index(pxb_dev_list, pxb_dev);
|
||||||
|
assert(position >= 0);
|
||||||
|
|
||||||
|
pxb_dev_base = DEVICE(pxb_dev);
|
||||||
|
main_host = PCI_HOST_BRIDGE(pxb_dev_base->parent_bus->parent);
|
||||||
|
main_host_sbd = SYS_BUS_DEVICE(main_host);
|
||||||
|
|
||||||
|
if (main_host_sbd->num_mmio > 0) {
|
||||||
|
return g_strdup_printf(TARGET_FMT_plx ",%x",
|
||||||
|
main_host_sbd->mmio[0].addr, position + 1);
|
||||||
|
}
|
||||||
|
if (main_host_sbd->num_pio > 0) {
|
||||||
|
return g_strdup_printf("i%04x,%x",
|
||||||
|
main_host_sbd->pio[0], position + 1);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void pxb_host_class_init(ObjectClass *class, void *data)
|
static void pxb_host_class_init(ObjectClass *class, void *data)
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS(class);
|
DeviceClass *dc = DEVICE_CLASS(class);
|
||||||
|
SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(class);
|
||||||
PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(class);
|
PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(class);
|
||||||
|
|
||||||
dc->fw_name = "pci";
|
dc->fw_name = "pci";
|
||||||
|
sbc->explicit_ofw_unit_address = pxb_host_ofw_unit_address;
|
||||||
hc->root_bus_path = pxb_host_root_bus_path;
|
hc->root_bus_path = pxb_host_root_bus_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,6 +184,15 @@ static int pxb_map_irq_fn(PCIDevice *pci_dev, int pin)
|
||||||
return pin - PCI_SLOT(pxb->devfn);
|
return pin - PCI_SLOT(pxb->devfn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gint pxb_compare(gconstpointer a, gconstpointer b)
|
||||||
|
{
|
||||||
|
const PXBDev *pxb_a = a, *pxb_b = b;
|
||||||
|
|
||||||
|
return pxb_a->bus_nr < pxb_b->bus_nr ? -1 :
|
||||||
|
pxb_a->bus_nr > pxb_b->bus_nr ? 1 :
|
||||||
|
0;
|
||||||
|
}
|
||||||
|
|
||||||
static int pxb_dev_initfn(PCIDevice *dev)
|
static int pxb_dev_initfn(PCIDevice *dev)
|
||||||
{
|
{
|
||||||
PXBDev *pxb = PXB_DEV(dev);
|
PXBDev *pxb = PXB_DEV(dev);
|
||||||
|
@ -192,9 +236,17 @@ static int pxb_dev_initfn(PCIDevice *dev)
|
||||||
PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
|
PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
|
||||||
pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_HOST);
|
pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_HOST);
|
||||||
|
|
||||||
|
pxb_dev_list = g_list_insert_sorted(pxb_dev_list, pxb, pxb_compare);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pxb_dev_exitfn(PCIDevice *pci_dev)
|
||||||
|
{
|
||||||
|
PXBDev *pxb = PXB_DEV(pci_dev);
|
||||||
|
|
||||||
|
pxb_dev_list = g_list_remove(pxb_dev_list, pxb);
|
||||||
|
}
|
||||||
|
|
||||||
static Property pxb_dev_properties[] = {
|
static Property pxb_dev_properties[] = {
|
||||||
/* Note: 0 is not a legal a PXB bus number. */
|
/* Note: 0 is not a legal a PXB bus number. */
|
||||||
DEFINE_PROP_UINT8("bus_nr", PXBDev, bus_nr, 0),
|
DEFINE_PROP_UINT8("bus_nr", PXBDev, bus_nr, 0),
|
||||||
|
@ -208,6 +260,7 @@ static void pxb_dev_class_init(ObjectClass *klass, void *data)
|
||||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||||
|
|
||||||
k->init = pxb_dev_initfn;
|
k->init = pxb_dev_initfn;
|
||||||
|
k->exit = pxb_dev_exitfn;
|
||||||
k->vendor_id = PCI_VENDOR_ID_REDHAT;
|
k->vendor_id = PCI_VENDOR_ID_REDHAT;
|
||||||
k->device_id = PCI_DEVICE_ID_REDHAT_PXB;
|
k->device_id = PCI_DEVICE_ID_REDHAT_PXB;
|
||||||
k->class_id = PCI_CLASS_BRIDGE_HOST;
|
k->class_id = PCI_CLASS_BRIDGE_HOST;
|
||||||
|
|
Loading…
Reference in New Issue