@@ -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);
}
/****************************************************/
make pci bar initialization to be aware of preferchable memory. Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp> --- rombios32.c | 256 +++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 213 insertions(+), 43 deletions(-)