On Tue, Mar 10, 2015 at 05:32:08PM +0200, Marcel Apfelbaum wrote:
From: Marcel Apfelbaum marcel.a@redhat.com
Instead of assuming it has only one bus, it enumerates all the host bridges until it finds the one with bus number corresponding with the config register.
This really only works for PXB since that listens in on config cycles on the main bus. Best limit to that.
One also wonders what will happen when multiple PXBs are present on separate root complexes.
Signed-off-by: Marcel Apfelbaum marcel@redhat.com
hw/pci-host/piix.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-)
diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c index 0033ab4..3c3a192 100644 --- a/hw/pci-host/piix.c +++ b/hw/pci-host/piix.c @@ -255,6 +255,61 @@ static void i440fx_pcihost_get_pci_hole64_end(Object *obj, Visitor *v, visit_type_uint64(v, &w64.end, name, errp); }
+static PCIBus *i440fx_find_primary_bus(int bus_num) +{
- PCIHostState *host;
- PCIBus *bus = NULL;
- int current = -1;
- HOST_BRIDGE_FOREACH(host) {
int b = pci_bus_num(host->bus);
if (b <= bus_num && b > current) {
current = b;
bus = host->bus;
}
- }
- return bus;
+}
+static void i440fx_pcihost_data_write(void *opaque, hwaddr addr,
uint64_t val, unsigned len)
+{
- uint32_t config_reg = PCI_HOST_BRIDGE(opaque)->config_reg;
- if (config_reg & (1u << 31)) {
int bus_num = (config_reg >> 16) & 0xFF;
PCIBus *bus = i440fx_find_primary_bus(bus_num);
if (bus) {
pci_data_write(bus, config_reg | (addr & 3), val, len);
}
- }
+}
+static uint64_t i440fx_pcihost_data_read(void *opaque,
hwaddr addr, unsigned len)
+{
- uint32_t config_reg = PCI_HOST_BRIDGE(opaque)->config_reg;
- if (config_reg & (1U << 31)) {
int bus_num = (config_reg >> 16) & 0xFF;
PCIBus *bus = i440fx_find_primary_bus(bus_num);
if (bus) {
return pci_data_read(bus, config_reg | (addr & 3), len);
}
- }
- return 0xffffffff;
+}
+const MemoryRegionOps i440fx_pcihost_data_le_ops = {
- .read = i440fx_pcihost_data_read,
- .write = i440fx_pcihost_data_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
+};
static void i440fx_pcihost_initfn(Object *obj) { PCIHostState *s = PCI_HOST_BRIDGE(obj); @@ -262,7 +317,7 @@ static void i440fx_pcihost_initfn(Object *obj)
memory_region_init_io(&s->conf_mem, obj, &pci_host_conf_le_ops, s, "pci-conf-idx", 4);
- memory_region_init_io(&s->data_mem, obj, &pci_host_data_le_ops, s,
memory_region_init_io(&s->data_mem, obj, &i440fx_pcihost_data_le_ops, s, "pci-conf-data", 4);
object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_START, "int",
-- 2.1.0