Blob Blame History Raw
From b2d132c9e3a65858fb745bdeafd1700a58db9bdc Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Mon, 27 Jan 2014 15:31:28 -0500
Subject: [PATCH 6/6] pci: improve io address space allocation

Message-id: <1390836688-16749-4-git-send-email-kraxel@redhat.com>
Patchwork-id: 56958
O-Subject: [RHEL-7 seabios PATCH 3/3] pci: improve io address space allocation
Bugzilla: 1055832
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Acked-by: Michael S. Tsirkin <mst@redhat.com>

This patch improves the io address space allocation.  It adds a check
that the region above 0xc000 which is traditionally used for pci io
is actually big enougth.  If it isn't it tries the larger window at
0x1000.  If that is to small too it errors out.

When creating guests with multiple pci-pci bridges (and devices with
io regions behind them) the 0xc000 -> 0xffff region quickly becomes
too small.

While being at it document the io address space layout used by
qemu/seabios.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit fc3cd00045cbe96ca1e6b6601d26901f040bfcdb)
---
 src/pciinit.c | 45 ++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 40 insertions(+), 5 deletions(-)

Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
---
 src/pciinit.c | 45 ++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 40 insertions(+), 5 deletions(-)

diff --git a/src/pciinit.c b/src/pciinit.c
index 4e5d7d0..fe58f59 100644
--- a/src/pciinit.c
+++ b/src/pciinit.c
@@ -663,10 +663,42 @@ static int pci_bios_check_devices(struct pci_bus *busses)
  ****************************************************************/
 
 // Setup region bases (given the regions' size and alignment)
-static int pci_bios_init_root_regions(struct pci_bus *bus)
-{
-    bus->r[PCI_REGION_TYPE_IO].base = 0xc000;
+static int pci_bios_init_root_regions_io(struct pci_bus *bus)
+{
+    /*
+     * QEMU I/O address space usage:
+     *   0000 - 0fff    legacy isa, pci config, pci root bus, ...
+     *   1000 - 9fff    free
+     *   a000 - afff    hotplug (cpu, pci via acpi, i440fx/piix only)
+     *   b000 - bfff    power management (PORT_ACPI_PM_BASE)
+     *                  [ qemu 1.4+ implements pci config registers
+     *                    properly so guests can place the registers
+     *                    where they want, on older versions its fixed ]
+     *   c000 - ffff    free, traditionally used for pci io
+     */
+    struct pci_region *r_io = &bus->r[PCI_REGION_TYPE_IO];
+    u64 sum = pci_region_sum(r_io);
+    if (sum < 0x4000) {
+        /* traditional region is big enougth, use it */
+        r_io->base = 0xc000;
+    } else if (sum < 0x9000) {
+        /* use the larger region at 0x1000 */
+        r_io->base = 0x1000;
+    } else {
+        /*
+         * Not enougth io address space -> error out.
+         *
+         * TODO: on q35 we can move PORT_ACPI_PM_BASE out of
+         * the way, then use the whole 1000 -> ffff region.
+         */
+        return -1;
+    }
+    dprintf(1, "PCI: IO: %4llx - %4llx\n", r_io->base, r_io->base + sum - 1);
+    return 0;
+}
 
+static int pci_bios_init_root_regions_mem(struct pci_bus *bus)
+{
     struct pci_region *r_end = &bus->r[PCI_REGION_TYPE_PREFMEM];
     struct pci_region *r_start = &bus->r[PCI_REGION_TYPE_MEM];
 
@@ -744,8 +776,11 @@ static void pci_region_map_entries(struct pci_bus *busses, struct pci_region *r)
 
 static void pci_bios_map_devices(struct pci_bus *busses)
 {
+    if (pci_bios_init_root_regions_io(busses))
+        panic("PCI: out of I/O address space\n");
+
     dprintf(1, "PCI: 32: %016llx - %016llx\n", pcimem_start, pcimem_end);
-    if (pci_bios_init_root_regions(busses)) {
+    if (pci_bios_init_root_regions_mem(busses)) {
         struct pci_region r64_mem, r64_pref;
         r64_mem.list = NULL;
         r64_pref.list = NULL;
@@ -754,7 +789,7 @@ static void pci_bios_map_devices(struct pci_bus *busses)
         pci_region_migrate_64bit_entries(&busses[0].r[PCI_REGION_TYPE_PREFMEM],
                                          &r64_pref);
 
-        if (pci_bios_init_root_regions(busses))
+        if (pci_bios_init_root_regions_mem(busses))
             panic("PCI: out of 32bit address space\n");
 
         u64 sum_mem = pci_region_sum(&r64_mem);
-- 
1.8.3.1