diff mbox

[v5,for-2.3,22/28] hw/pci: piix - suport multiple host bridges

Message ID 1426001534-7151-23-git-send-email-marcel@redhat.com
State New
Headers show

Commit Message

Marcel Apfelbaum March 10, 2015, 3:32 p.m. UTC
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.

Signed-off-by: Marcel Apfelbaum <marcel@redhat.com>
---
 hw/pci-host/piix.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 56 insertions(+), 1 deletion(-)

Comments

Michael S. Tsirkin March 10, 2015, 4:22 p.m. UTC | #1
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
diff mbox

Patch

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",