qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH 12/14] pcbios: make pci bar initialization to be awa


From: Isaku Yamahata
Subject: [Qemu-devel] [PATCH 12/14] pcbios: make pci bar initialization to be aware of preferchable memory.
Date: Wed, 30 Sep 2009 19:18:47 +0900

make pci bar initialization to be aware of preferchable memory.

Signed-off-by: Isaku Yamahata <address@hidden>
---
 rombios32.c |  256 +++++++++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 213 insertions(+), 43 deletions(-)

diff --git a/rombios32.c b/rombios32.c
index e22307e..c334db2 100644
--- a/rombios32.c
+++ b/rombios32.c
@@ -699,7 +699,28 @@ void smp_probe(void)
 #define PCI_COMMAND            0x04    /* 16 bits */
 #define  PCI_COMMAND_IO                0x1     /* Enable response in I/O space 
*/
 #define  PCI_COMMAND_MEMORY    0x2     /* Enable response in Memory space */
+#define  PCI_COMMAND_MASTER     0x4     /* Enable bus master */
 #define PCI_CLASS_DEVICE        0x0a    /* Device class */
+#define  PCI_CLASS_BRIDGE_PCI   0x0604  /* pci bridge */
+#define PCI_PRIMARY_BUS         0x18
+#define PCI_SECONDARY_BUS       0x19
+#define PCI_SUBORDINATE_BUS     0x1a
+#define PCI_IO_BASE             0x1c
+#define PCI_IO_LIMIT            0x1d
+#define  PCI_IO_SHIFT           8
+#define PCI_MEMORY_BASE         0x20
+#define PCI_MEMORY_LIMIT        0x22
+#define  PCI_MEMORY_SHIFT       16
+#define PCI_IO_BASE_UPPER16     0x30
+#define PCI_IO_LIMIT_UPPER16    0x32
+
+#define PCI_PREF_MEMORY_BASE    0x24    /* Prefetchable memory range behind */
+#define PCI_PREF_MEMORY_LIMIT   0x26
+#define  PCI_PREF_MEMORY_SHIFT  16
+#define PCI_PREF_BASE_UPPER32   0x28    /* Upper half of prefetchable memory 
range */
+#define PCI_PREF_LIMIT_UPPER32  0x2c
+
+
 #define PCI_INTERRUPT_LINE     0x3c    /* 8 bits */
 #define PCI_INTERRUPT_PIN      0x3d    /* 8 bits */
 #define PCI_MIN_GNT            0x3e    /* 8 bits */
@@ -1117,10 +1138,183 @@ static void pci_align_addr(uint32_t *paddr, uint32_t 
size)
     *paddr = (*paddr + size - 1) & ~(size - 1);
 }
 
+static uint32_t pci_bios_allocate_range(PCIDevice *d, int region_num)
+{
+    uint32_t *paddr;
+    int ofs;
+    uint32_t val, size;
+
+    if (region_num == PCI_ROM_SLOT) {
+        ofs = 0x30;
+        pci_config_writel(d, ofs, 0xfffffffe);
+    } else {
+        ofs = 0x10 + region_num * 4;
+        pci_config_writel(d, ofs, 0xffffffff);
+    }
+
+    val = pci_config_readl(d, ofs);
+    if (val != 0) {
+        size = (~(val & ~0xf)) + 1;
+        if (val & PCI_ADDRESS_SPACE_IO)
+            paddr = &pci_bios_io_addr;
+        else if (val & PCI_ADDRESS_SPACE_MEM_PREFETCH)
+            paddr = &pci_bios_prefmem_addr;
+        else if (size >= 0x04000000 || d->bus != 0)
+            paddr = &pci_bios_bigmem_addr;
+        else
+            paddr = &pci_bios_mem_addr;
+        pci_align_addr(paddr, size);
+        pci_set_io_region_addr(d, region_num, *paddr);
+        *paddr += size;
+    }
+    return val & (PCI_ADDRESS_SPACE_IO |
+                  PCI_ADDRESS_SPACE_TYPE_MASK |
+                  PCI_ADDRESS_SPACE_MEM_PREFETCH);
+}
+
+void pci_for_each_device_in_bus(int bus, void (*init_func)(PCIDevice *d))
+{
+    PCIDevice d1, *d = &d1;
+    int devfn;
+    uint16_t vendor_id, device_id;
+
+    for(devfn = 0; devfn < 256; devfn++) {
+        d->bus = bus;
+        d->devfn = devfn;
+        vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
+        device_id = pci_config_readw(d, PCI_DEVICE_ID);
+        if (vendor_id != 0xffff || device_id != 0xffff) {
+            init_func(d);
+        }
+    }
+}
+
+static void pci_bios_init_device(PCIDevice *d);
+
+static void pci_bios_init_device_bridge(PCIDevice *d)
+{
+    int i;
+    uint32_t br_io_base;
+    uint32_t br_io_end;
+    uint32_t br_bigmem_base;
+    uint32_t br_bigmem_end;
+    uint32_t br_prefmem_base;
+    uint32_t br_prefmem_end;
+    uint16_t cmd;
+
+    static uint8_t bus = 0;
+    uint8_t pribus;
+    uint8_t secbus;
+    uint8_t subbus;
+
+    for (i = 0; i < 2; i++) {
+        pci_bios_allocate_range(d, i);
+    }
+
+    pribus = pci_config_readb(d, PCI_PRIMARY_BUS);
+    if (pribus != d->bus) {
+        pci_config_writeb(d, PCI_PRIMARY_BUS, d->bus);
+        BX_INFO("PCI: pribus = 0x%x -> 0x%x\n", pribus, d->bus);
+    } else {
+        BX_INFO("PCI: pribus = 0x%x\n", pribus);
+    }
+
+    secbus = pci_config_readb(d, PCI_SECONDARY_BUS);
+    if (secbus == 0 || bus > secbus) {
+        bus++;
+        pci_config_writeb(d, PCI_SECONDARY_BUS, bus);
+        BX_INFO("PCI: secbus changed = 0x%x -> 0x%x\n", secbus, bus);
+    } else if (bus < secbus) {
+        bus = secbus;
+        BX_INFO("PCI: secbus = 0x%x\n", bus);
+    }
+
+    /* set to max for access to all subordinate buses.
+       later set it to accurate value */
+    subbus = pci_config_readb(d, PCI_SUBORDINATE_BUS);;
+    pci_config_writeb(d, PCI_SUBORDINATE_BUS, 256);
+
+    /* IO BASE is assumed to be 16 bit */
+    pci_align_addr(&pci_bios_io_addr, 4096);
+    pci_align_addr(&pci_bios_bigmem_addr, 1UL << 20);
+    pci_align_addr(&pci_bios_prefmem_addr, 1UL << 20);
+    br_io_base = pci_bios_io_addr;
+    br_bigmem_base = pci_bios_bigmem_addr;
+    br_prefmem_base = pci_bios_prefmem_addr;
+    pci_for_each_device_in_bus(bus, pci_bios_init_device);
+    pci_align_addr(&pci_bios_io_addr, 4096);
+    pci_align_addr(&pci_bios_bigmem_addr, 1UL << 20);
+    pci_align_addr(&pci_bios_prefmem_addr, 1UL << 20);
+
+    if (subbus != bus) {
+        BX_INFO("PCI: subordinate bus = 0x%x -> 0x%x\n", subbus, bus);
+    } else {
+        BX_INFO("PCI: subordinate bus = 0x%x\n", subbus);
+    }
+    if (subbus > bus){
+        bus = subbus;
+    }
+    pci_config_writeb(d, PCI_SUBORDINATE_BUS, bus);
+
+    br_io_end = pci_bios_io_addr;
+    if (br_io_end == br_io_base) {
+        br_io_base = 0xffff;
+        br_io_end = 1;
+    }
+    pci_config_writeb(d, PCI_IO_BASE,
+                      br_io_base >> PCI_IO_SHIFT);
+    pci_config_writew(d, PCI_IO_BASE_UPPER16, 0);
+    pci_config_writeb(d, PCI_IO_LIMIT,
+                      (br_io_end - 1) >> PCI_IO_SHIFT);
+    pci_config_writew(d, PCI_IO_LIMIT_UPPER16, 0);
+
+    br_bigmem_end = pci_bios_bigmem_addr;
+    if (br_bigmem_end == br_bigmem_base) {
+        br_bigmem_base = 0xffffffff;
+        br_bigmem_end = 1;
+    }
+    pci_config_writew(d, PCI_MEMORY_BASE,
+                      br_bigmem_base >> PCI_MEMORY_SHIFT);
+    pci_config_writew(d, PCI_MEMORY_LIMIT,
+                      (br_bigmem_end -1) >> PCI_MEMORY_SHIFT);
+
+    br_prefmem_end = pci_bios_prefmem_addr;
+    if (br_prefmem_end == br_prefmem_base) {
+        br_prefmem_base = 0xffffffff;
+        br_prefmem_end = 1;
+    }
+    pci_config_writew(d, PCI_PREF_MEMORY_BASE,
+                      br_prefmem_base >> PCI_PREF_MEMORY_SHIFT);
+    pci_config_writew(d, PCI_PREF_MEMORY_LIMIT,
+                      (br_prefmem_end - 1) >> PCI_PREF_MEMORY_SHIFT);
+    pci_config_writel(d, PCI_PREF_BASE_UPPER32, 0);
+    pci_config_writel(d, PCI_PREF_LIMIT_UPPER32, 0);
+
+    BX_INFO("PCI: br subord bus 0x%x\n", bus);
+    BX_INFO("PCI: br IO   = [0x%lx, 0x%lx)\n", br_io_base, br_io_end);
+    BX_INFO("PCI: br MEM  = [0x%lx, 0x%lx)\n",
+            br_bigmem_base, br_bigmem_end);
+    BX_INFO("PCI: br PREF = [0x%lx, 0x%lx)\n",
+            br_prefmem_base, br_prefmem_end);
+
+    cmd = pci_config_readw(d, PCI_COMMAND);
+    if (br_io_end > br_io_base) {
+        cmd |= PCI_COMMAND_IO;
+    } else {
+        cmd &= ~PCI_COMMAND_IO;
+    }
+    cmd &= ~PCI_COMMAND_MEMORY;
+    if (br_bigmem_end > br_bigmem_base ||
+        br_prefmem_end > br_prefmem_base) {
+        cmd |= PCI_COMMAND_MEMORY;
+    }
+    cmd |= PCI_COMMAND_MASTER;
+    pci_config_writew(d, PCI_COMMAND, cmd);
+}
+
 static void pci_bios_init_device(PCIDevice *d)
 {
     int class;
-    uint32_t *paddr;
     int i, pin, pic_irq, vendor_id, device_id;
 
     class = pci_config_readw(d, PCI_CLASS_DEVICE);
@@ -1148,8 +1342,14 @@ static void pci_bios_init_device(PCIDevice *d)
     case 0x0300: /* Display controller - VGA compatible controller */
         if (vendor_id != 0x1234)
             goto default_map;
-        /* VGA: map frame buffer to default Bochs VBE address */
-        pci_set_io_region_addr(d, 0, 0xE0000000);
+        if (mch_found) {
+            /* avoid MCFG area. use [0xf8000000, 0xf8800000)
+               0x2000000 = 8M VRAM_SIZE */
+            pci_set_io_region_addr(d, 0, 0xf8000000);
+        } else {
+            /* VGA: map frame buffer to default Bochs VBE address */
+            pci_set_io_region_addr(d, 0, 0xE0000000);
+        }
         break;
     case 0x0800: /* Generic system peripheral - PIC */
         if (vendor_id == PCI_VENDOR_ID_IBM) {
@@ -1167,35 +1367,14 @@ static void pci_bios_init_device(PCIDevice *d)
             pci_set_io_region_addr(d, 0, 0x80800000);
         }
         break;
+    case PCI_CLASS_BRIDGE_PCI:
+        pci_bios_init_device_bridge(d);
+        break;
     default:
     default_map:
         /* default memory mappings */
         for(i = 0; i < PCI_NUM_REGIONS; i++) {
-            int ofs;
-            uint32_t val, size ;
-
-            if (i == PCI_ROM_SLOT) {
-                ofs = 0x30;
-                pci_config_writel(d, ofs, 0xfffffffe);
-            } else {
-                ofs = 0x10 + i * 4;
-                pci_config_writel(d, ofs, 0xffffffff);
-            }
-            val = pci_config_readl(d, ofs);
-            if (val != 0) {
-                size = (~(val & ~0xf)) + 1;
-                if (val & PCI_ADDRESS_SPACE_IO)
-                    paddr = &pci_bios_io_addr;
-                else if (val & PCI_ADDRESS_SPACE_MEM_PREFETCH)
-                    paddr = &pci_bios_prefmem_addr;
-                else if (size >= 0x04000000)
-                    paddr = &pci_bios_bigmem_addr;
-                else
-                    paddr = &pci_bios_mem_addr;
-                pci_align_addr(paddr, size);
-                pci_set_io_region_addr(d, i, *paddr);
-                *paddr += size;
-            }
+            uint32_t val = pci_bios_allocate_range(d, i);
 
             /* 64bit bar */
             if (!(val & PCI_ADDRESS_SPACE_IO) &&
@@ -1247,20 +1426,10 @@ static void pci_bios_init_device(PCIDevice *d)
 
 void pci_for_each_device(void (*init_func)(PCIDevice *d))
 {
-    PCIDevice d1, *d = &d1;
-    int bus, devfn;
-    uint16_t vendor_id, device_id;
+    int bus;
 
-    for(bus = 0; bus < 1; bus++) {
-        for(devfn = 0; devfn < 256; devfn++) {
-            d->bus = bus;
-            d->devfn = devfn;
-            vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
-            device_id = pci_config_readw(d, PCI_DEVICE_ID);
-            if (vendor_id != 0xffff || device_id != 0xffff) {
-                init_func(d);
-            }
-        }
+    for(bus = 0; bus < 256; bus++) {
+        pci_for_each_device_in_bus(bus, init_func);
     }
 }
 
@@ -1274,12 +1443,13 @@ void pci_bios_init(void)
     pci_bios_prefmem_addr = pci_bios_bigmem_addr + 0x08000000;
     pci_align_addr(&pci_bios_prefmem_addr, 0x08000000);
     if (pci_bios_prefmem_addr >= 0xe0000000) {
-        pci_bios_prefmem_addr = 0xf800000;
+        /* 0x2000000 = 8M vga frame buffer */
+        pci_bios_prefmem_addr = 0xf800000 + 0x2000000;
     }
 
     pci_for_each_device(pci_bios_init_bridges);
 
-    pci_for_each_device(pci_bios_init_device);
+    pci_for_each_device_in_bus(0, pci_bios_init_device);
 }
 
 /****************************************************/
-- 
1.6.0.2





reply via email to

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