qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 3/6] Fill PCI regions with etnries


From: Alexey Korolev
Subject: [Qemu-devel] [PATCH 3/6] Fill PCI regions with etnries
Date: Thu, 1 Mar 2012 19:40:59 +1300

In this patch we fill pci_regions with entries. 

The idea of implementation is pretty much the same as it was before in 
pci_check_devices()
function.
The pci_bios_fill_regions() function scans pci devices.
1) If pci device is a pci-to-pci bridge
   a) we create empty entry.
   b) Associate new entry with pci_region, which is provided by pci-to-pci 
bridge
   c) Add new entry to a list of pci_region of parent bus.
2) If pci device is not a bridge.
   a) Scan PCI BARs.
   b) Get size and attributes. (Type and is64bit)
   c) Add new entry to a list of pci_region of parent bus.

Then the pci_bios_fill_regions() scans pci_regions in reverse order
to calculate size of pci_region_entries belonging to a bridge.


Signed-off-by: Alexey Korolev <address@hidden>
---
 src/pciinit.c |  103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 98 insertions(+), 5 deletions(-)

diff --git a/src/pciinit.c b/src/pciinit.c
index b02da89..03ece34 100644
--- a/src/pciinit.c
+++ b/src/pciinit.c
@@ -12,11 +12,10 @@
 #include "pci_regs.h" // PCI_COMMAND
 #include "xen.h" // usingXen
 
-#define PCI_IO_INDEX_SHIFT 2
-#define PCI_MEM_INDEX_SHIFT 12
-
-#define PCI_BRIDGE_IO_MIN      0x1000
-#define PCI_BRIDGE_MEM_MIN   0x100000
+#define PCI_DEV_IO_MINSIZE 4
+#define PCI_DEV_MEM_MINSIZE 0x1000
+#define PCI_BRIDGE_IO_MINSIZE 0x1000
+#define PCI_BRIDGE_MEM_MINSIZE 0x100000
 
 enum pci_region_type {
     PCI_REGION_TYPE_IO,
@@ -408,6 +407,96 @@ dump_entry(struct pci_region_entry *entry)
         region_type_name[entry->type],entry->is64bit ? "64bits" : "32bits");
 }
 
+/****************************************************************
+ * Build topology and calculate size of entries
+ ****************************************************************/
+struct pci_region_entry *
+pci_region_create_entry(struct pci_region *parent, struct pci_device *dev,
+                       u64 size, int type, int is64bit)
+{
+    struct pci_region_entry *entry= malloc_tmp(sizeof(*entry));
+    if (!entry) {
+            warn_noalloc();
+            return NULL;
+    }
+    memset(entry, 0, sizeof(*entry));
+
+    entry->dev = dev;
+    entry->type = type;
+    entry->is64bit = is64bit;
+    entry->size = size;
+    region_entry_add(parent, entry);
+    entry->parent_region = parent;
+    return entry;
+}
+
+static int pci_bios_fill_regions(struct pci_region *regions)
+{
+    struct pci_region *this_region, *parent;
+    enum pci_region_type type;
+    struct pci_device *pci;
+    struct pci_region_entry *entry;
+    int is64bit, i;
+    u64 size, min_size;
+
+    foreachpci(pci) {
+        if (pci->class == PCI_CLASS_BRIDGE_PCI) {
+            this_region = &regions[pci->secondary_bus * PCI_REGION_TYPE_COUNT];
+            parent = &regions[pci_bdf_to_bus(pci->bdf) * 
PCI_REGION_TYPE_COUNT];
+            for (type = 0; type < PCI_REGION_TYPE_COUNT;
+                           type++, this_region++, parent++) {
+                /* Only prefetchable bridge regions can be 64bit */
+                is64bit = (type == PCI_REGION_TYPE_PREFMEM);
+                entry = pci_region_create_entry(parent, pci, 0, type, is64bit);
+                if (!entry)
+                    return -1;
+                entry->this_region = this_region;
+                this_region->this_entry = entry;
+            }
+            continue;
+        }
+        for (i = 0; i < PCI_NUM_REGIONS; i++) {
+            size = pci_get_bar_size(pci, i, &type, &is64bit);
+            if (size == 0)
+                continue;
+            min_size = (type == PCI_REGION_TYPE_IO) ?
+                PCI_DEV_IO_MINSIZE : PCI_DEV_MEM_MINSIZE;
+            size = (size > min_size) ? size : min_size;
+
+            parent = &regions[pci_bdf_to_bus(pci->bdf) * PCI_REGION_TYPE_COUNT
+                              + type];
+            entry = pci_region_create_entry(parent, pci, size, type, is64bit);
+            if (!entry)
+                return -1;
+            entry->bar = i;
+            dump_entry(entry);
+            if (is64bit)
+                i++;
+        }
+    }
+
+    for (i = (MaxPCIBus + 1) * PCI_REGION_TYPE_COUNT ; i < 0; i--) {
+        struct pci_region_entry *this_entry = regions[i-1].this_entry;
+        if(!this_entry)
+            continue;
+
+        is64bit = this_entry->is64bit;
+        size = 0;
+        foreach_region_entry(&regions[i-1], entry) {
+            size += entry->size;
+            is64bit &= entry->is64bit;
+        }
+        min_size = (this_entry->type == PCI_REGION_TYPE_IO) ?
+                PCI_BRIDGE_IO_MINSIZE : PCI_BRIDGE_MEM_MINSIZE;
+        size = (size > min_size) ? size : min_size;
+        this_entry->is64bit = is64bit;
+        this_entry->size = pci_size_roundup(size);
+        dump_entry(entry);
+    }
+    return 0;
+}
+
+
 static void pci_bios_bus_reserve(struct pci_bus *bus, int type, u32 size)
 {
     u32 index;
@@ -645,6 +734,10 @@ pci_setup(void)
         return;
     }
     memset(regions, 0, sizeof(*regions) * num_regions);
+    if (pci_bios_fill_regions(regions)) {
+        free(regions);
+        return;
+    }
     pci_bios_check_devices(busses);
     if (pci_bios_init_root_regions(&busses[0], start, end) != 0) {
         panic("PCI: out of address space\n");
-- 
1.7.5.4





reply via email to

[Prev in Thread] Current Thread [Next in Thread]