>From 99ff4d141d5a460eaf20fe2d4d13117c888eae15 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 25 May 2011 13:56:52 +0200
Subject: [PATCH] init boot devices only on address space shortage

---
 src/pci.c     |    3 ++
 src/pciinit.c |   79 ++++++++++++++++++++++++++++++++++++++++++++++++++------
 src/util.h    |    1 +
 3 files changed, 74 insertions(+), 9 deletions(-)

diff --git a/src/pci.c b/src/pci.c
index 944a393..26c34bc 100644
--- a/src/pci.c
+++ b/src/pci.c
@@ -221,6 +221,9 @@ int pci_init_device(const struct pci_device_id *ids, u16 bdf, void *arg)
     u16 device_id = pci_config_readw(bdf, PCI_DEVICE_ID);
     u16 class = pci_config_readw(bdf, PCI_CLASS_DEVICE);
 
+    if (!pci_enable_device(bdf))
+        return -1;
+
     while (ids->vendid || ids->class_mask) {
         if ((ids->vendid == PCI_ANY_ID || ids->vendid == vendor_id) &&
             (ids->devid == PCI_ANY_ID || ids->devid == device_id) &&
diff --git a/src/pciinit.c b/src/pciinit.c
index 2e97b31..4aebd52 100644
--- a/src/pciinit.c
+++ b/src/pciinit.c
@@ -44,6 +44,7 @@ static struct pci_bus {
     u32 io_base, mem_base, prefmem_base;
 } *busses;
 static int busses_count;
+static int boot_devices_only = 0;
 
 static void pci_bios_init_device_in_bus(int bus);
 static void pci_bios_check_device_in_bus(int bus);
@@ -144,6 +145,50 @@ static const struct pci_device_id pci_isa_bridge_tbl[] = {
 #define PCI_PREF_MEMORY_ALIGN   (1UL << 20)
 #define PCI_PREF_MEMORY_SHIFT   16
 
+static int is_boot_device(u16 bdf)
+{
+    u32 ofs, old, val;
+    u16 class;
+
+    class = pci_config_readw(bdf, PCI_CLASS_DEVICE);
+
+    /* check base class */
+    switch (class >> 8) {
+    case PCI_BASE_CLASS_STORAGE:
+    case PCI_BASE_CLASS_NETWORK:
+    case PCI_BASE_CLASS_BRIDGE:
+    case PCI_BASE_CLASS_SYSTEM:
+        return 1;
+    }
+
+    /* check class */
+    switch (class) {
+    case PCI_CLASS_DISPLAY_VGA:
+    case PCI_CLASS_SERIAL_USB:
+        return 1;
+    }
+
+    /* check if ROM present */
+    ofs = pci_bar(bdf, PCI_ROM_SLOT);
+    old = pci_config_readl(bdf, ofs);
+    pci_config_writel(bdf, ofs, PCI_ROM_ADDRESS_MASK);
+    val = pci_config_readl(bdf, ofs);
+    pci_config_writel(bdf, ofs, old);
+    if (val != 0) {
+        return 1;
+    }
+
+    return 0;
+}
+
+int pci_enable_device(u16 bdf)
+{
+    if (boot_devices_only) {
+        return is_boot_device(bdf);
+    }
+    return 1;
+}
+
 static void storage_ide_init(u16 bdf, void *arg)
 {
     /* IDE: we map it as in ISA mode */
@@ -387,6 +432,9 @@ static void pci_bios_check_device(struct pci_bus *bus, u16 bdf)
     u16 class;
     int i;
 
+    if (!pci_enable_device(bdf))
+        return;
+
     class = pci_config_readw(bdf, PCI_CLASS_DEVICE);
     if (class == PCI_CLASS_BRIDGE_PCI) {
         u8 secbus = pci_config_readb(bdf, PCI_SECONDARY_BUS);
@@ -437,6 +485,9 @@ static void pci_bios_map_device(struct pci_bus *bus, u16 bdf)
     u16 class;
     int i;
 
+    if (!pci_enable_device(bdf))
+        return;
+
     class = pci_config_readw(bdf, PCI_CLASS_DEVICE);
     if (class == PCI_CLASS_BRIDGE_PCI) {
         u8 secbus = pci_config_readb(bdf, PCI_SECONDARY_BUS);
@@ -499,10 +550,12 @@ static void pci_bios_map_device(struct pci_bus *bus, u16 bdf)
 
 static void pci_bios_check_device_in_bus(int bus)
 {
-    int bdf, max;
+    int bdf, max, boot;
 
     dprintf(1, "PCI: check devices bus %d\n", bus);
     foreachpci_in_bus(bdf, max, bus) {
+        boot = is_boot_device(bdf);
+        dprintf(1, "PCI: check device bus %d, bfd 0x%x, boot %d\n", bus, bdf, boot);
         pci_bios_check_device(&busses[bus], bdf);
     }
 }
@@ -568,7 +621,7 @@ static void pci_bios_init_bus_bases(struct pci_bus *bus)
     }
 }
 
-static void pci_bios_init_root_regions(void)
+static int pci_bios_init_root_regions(void)
 {
     struct pci_bus *bus = &busses[0];
     u32 reserved = 0xffffffff - 0xfec00000 + 1;
@@ -595,14 +648,12 @@ static void pci_bios_init_root_regions(void)
     bus->io_base = 0xc000;
 
     /* simple sanity check */
-    /* TODO: check e820 table */
-    if (bus->mem_base < RamSize) {
+    if (reserved > 0x10000000) {
         dprintf(1, "PCI: out of space for memory bars\n");
-        /* Hmm, what to do now? */
+        return -1;
+    } else {
+        return 0;
     }
-
-    dprintf(1, "PCI: init bases bus 0 (primary)\n");
-    pci_bios_init_bus_bases(bus);
 }
 
 void
@@ -619,6 +670,15 @@ pci_setup(void)
 
     dprintf(1, "=== PCI new allocation pass #1 ===\n");
     pci_bios_check_device_in_bus(0 /* host bus */);
+    if (pci_bios_init_root_regions() != 0) {
+        dprintf(1, "=== PCI new allocation pass #1a (boot only) ===\n");
+        boot_devices_only = 1;
+        memset(busses, 0, busses_count * sizeof(struct pci_bus));
+        pci_bios_check_device_in_bus(0 /* host bus */);
+        if (pci_bios_init_root_regions() != 0) {
+            /* Hmm, we are in serious trouble now */
+        }
+    }
 
     pci_region_init(&pci_bios_io_region, 0xc000, 64 * 1024 - 1);
     struct pci_mem_addr addr = {
@@ -628,7 +688,8 @@ pci_setup(void)
     pci_find_init_device(pci_mem_addr_tbl, &addr);
 
     dprintf(1, "=== PCI new allocation pass #2 ===\n");
-    pci_bios_init_root_regions();
+    dprintf(1, "PCI: init bases bus 0 (primary)\n");
+    pci_bios_init_bus_bases(&busses[0]);
     pci_bios_map_device_in_bus(0 /* host bus */);
 
     pci_bios_init_device_in_bus(0 /* host bus */);
diff --git a/src/util.h b/src/util.h
index 2160b37..ff61031 100644
--- a/src/util.h
+++ b/src/util.h
@@ -381,6 +381,7 @@ u32 pci_region_size(const struct pci_region *r);
 
 // pciinit.c
 extern const u8 pci_irqs[4];
+int pci_enable_device(u16 bdf);
 void pci_bios_allocate_regions(u16 bdf, void *arg);
 void pci_setup(void);
 
-- 
1.7.1

