Changes v1 -> v2: - simplified foreachpci_in_bus() - add overlap check during pci bar assignemnt. - use c99 initialization.
Patch description:
This patch set allows seabios to initialize multi pci bus and 64bit BAR.
Currently seabios is able to initialize only pci root bus. However multi pci bus support is wanted because - more pci bus is wanted in qemu for many slots - pci express support is commin in qemu which requires multi pci bus. those patches on Qemu part are under way, though.
Isaku Yamahata (8): seabios: pci: introduce foreachpci_in_bus() helper macro. seabios: pciinit: factor out pci bar region allocation logic. seabios: pciinit: make pci memory space assignment 64bit aware. seabios: pciinit: make pci bar assigner preferchable memory aware. seabios: pciinit: factor out bar offset calculation. seabios: pciinit: make bar offset calculation pci bridge aware. seabios: pciinit: pci bridge bus initialization. seabios: pciinit: initialize pci bridge filtering registers.
src/config.h | 17 +++ src/pci.h | 10 ++ src/pciinit.c | 324 +++++++++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 306 insertions(+), 45 deletions(-)
This patch introduces foreachpci_in_bus() helper macro for depth first recursion. foreachpci() is for width first recursion. The macro will be used later to initialize pci bridge that requires depth first recursion.
Signed-off-by: Isaku Yamahata yamahata@valinux.co.jp
--- changes v1 -> v2: - simplified according to Kevin's suggestion. --- src/pci.h | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/src/pci.h b/src/pci.h index 8a21c06..e40e116 100644 --- a/src/pci.h +++ b/src/pci.h @@ -21,6 +21,9 @@ static inline u8 pci_bdf_to_fn(u16 bdf) { static inline u16 pci_to_bdf(int bus, int dev, int fn) { return (bus<<8) | (dev<<3) | fn; } +static inline u16 pci_bus_devfn_to_bdf(int bus, u16 devfn) { + return (bus << 8) | devfn; +}
static inline u32 pci_vd(u16 vendor, u16 device) { return (device << 16) | vendor; @@ -50,6 +53,13 @@ int pci_next(int bdf, int *pmax); ; BDF >= 0 \ ; BDF=pci_next(BDF+1, &MAX))
+#define foreachpci_in_bus(BDF, MAX, BUS) \ + for (MAX = pci_bus_devfn_to_bdf(BUS, 0) + 0x0100, \ + BDF = pci_next(pci_bus_devfn_to_bdf(BUS, 0), &MAX) \ + ; BDF >= 0 && BDF < pci_bus_devfn_to_bdf(BUS, 0) + 0x0100 \ + ; MAX = pci_bus_devfn_to_bdf(BUS, 0) + 0x0100, \ + BDF = pci_next(BDF + 1, &MAX)) + // pirtable.c void create_pirtable(void);
factor out pci bar region allocation logic.
Signed-off-by: Isaku Yamahata yamahata@valinux.co.jp --- src/pciinit.c | 84 ++++++++++++++++++++++++++++++++------------------------- 1 files changed, 47 insertions(+), 37 deletions(-)
diff --git a/src/pciinit.c b/src/pciinit.c index 0556ee2..488c77b 100644 --- a/src/pciinit.c +++ b/src/pciinit.c @@ -37,6 +37,50 @@ static void pci_set_io_region_addr(u16 bdf, int region_num, u32 addr) dprintf(1, "region %d: 0x%08x\n", region_num, addr); }
+static void pci_bios_allocate_region(u16 bdf, int region_num) +{ + u32 *paddr; + int ofs; + if (region_num == PCI_ROM_SLOT) + ofs = PCI_ROM_ADDRESS; + else + ofs = PCI_BASE_ADDRESS_0 + region_num * 4; + + u32 old = pci_config_readl(bdf, ofs); + u32 mask; + if (region_num == PCI_ROM_SLOT) { + mask = PCI_ROM_ADDRESS_MASK; + pci_config_writel(bdf, ofs, mask); + } else { + if (old & PCI_BASE_ADDRESS_SPACE_IO) + mask = PCI_BASE_ADDRESS_IO_MASK; + else + mask = PCI_BASE_ADDRESS_MEM_MASK; + pci_config_writel(bdf, ofs, ~0); + } + u32 val = pci_config_readl(bdf, ofs); + pci_config_writel(bdf, ofs, old); + + if (val != 0) { + u32 size = (~(val & mask)) + 1; + if (val & PCI_BASE_ADDRESS_SPACE_IO) + paddr = &pci_bios_io_addr; + else + paddr = &pci_bios_mem_addr; + *paddr = ALIGN(*paddr, size); + pci_set_io_region_addr(bdf, region_num, *paddr); + *paddr += size; + } +} + +static void pci_bios_allocate_regions(u16 bdf) +{ + int i; + for (i = 0; i < PCI_NUM_REGIONS; i++) { + pci_bios_allocate_region(bdf, i); + } +} + /* return the global irq number corresponding to a given device irq pin. We could also use the bus number to have a more precise mapping. */ @@ -78,8 +122,7 @@ static void pci_bios_init_bridges(u16 bdf) static void pci_bios_init_device(u16 bdf) { int class; - u32 *paddr; - int i, pin, pic_irq, vendor_id, device_id; + int pin, pic_irq, vendor_id, device_id;
class = pci_config_readw(bdf, PCI_CLASS_DEVICE); vendor_id = pci_config_readw(bdf, PCI_VENDOR_ID); @@ -94,7 +137,7 @@ static void pci_bios_init_device(u16 bdf) /* PIIX3/PIIX4 IDE */ pci_config_writew(bdf, 0x40, 0x8000); // enable IDE0 pci_config_writew(bdf, 0x42, 0x8000); // enable IDE1 - goto default_map; + pci_bios_allocate_regions(bdf); } else { /* IDE: we map it as in ISA mode */ pci_set_io_region_addr(bdf, 0, PORT_ATA1_CMD_BASE); @@ -121,41 +164,8 @@ static void pci_bios_init_device(u16 bdf) } break; default: - default_map: /* default memory mappings */ - for (i = 0; i < PCI_NUM_REGIONS; i++) { - int ofs; - if (i == PCI_ROM_SLOT) - ofs = PCI_ROM_ADDRESS; - else - ofs = PCI_BASE_ADDRESS_0 + i * 4; - - u32 old = pci_config_readl(bdf, ofs); - u32 mask; - if (i == PCI_ROM_SLOT) { - mask = PCI_ROM_ADDRESS_MASK; - pci_config_writel(bdf, ofs, mask); - } else { - if (old & PCI_BASE_ADDRESS_SPACE_IO) - mask = PCI_BASE_ADDRESS_IO_MASK; - else - mask = PCI_BASE_ADDRESS_MEM_MASK; - pci_config_writel(bdf, ofs, ~0); - } - u32 val = pci_config_readl(bdf, ofs); - pci_config_writel(bdf, ofs, old); - - if (val != 0) { - u32 size = (~(val & mask)) + 1; - if (val & PCI_BASE_ADDRESS_SPACE_IO) - paddr = &pci_bios_io_addr; - else - paddr = &pci_bios_mem_addr; - *paddr = ALIGN(*paddr, size); - pci_set_io_region_addr(bdf, i, *paddr); - *paddr += size; - } - } + pci_bios_allocate_regions(bdf); break; }
make pci memory space assignment 64bit aware. If 64bit memory space is found while assigning pci memory space, clear higher bit and skip to next bar.
This patch is preparation for q35 chipset initialization which has 64bit bar.
Signed-off-by: Isaku Yamahata yamahata@valinux.co.jp --- src/pciinit.c | 19 +++++++++++++++++-- 1 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/src/pciinit.c b/src/pciinit.c index 488c77b..b635e44 100644 --- a/src/pciinit.c +++ b/src/pciinit.c @@ -37,7 +37,12 @@ static void pci_set_io_region_addr(u16 bdf, int region_num, u32 addr) dprintf(1, "region %d: 0x%08x\n", region_num, addr); }
-static void pci_bios_allocate_region(u16 bdf, int region_num) +/* + * return value + * 0: 32bit BAR + * non 0: 64bit BAR + */ +static int pci_bios_allocate_region(u16 bdf, int region_num) { u32 *paddr; int ofs; @@ -71,13 +76,23 @@ static void pci_bios_allocate_region(u16 bdf, int region_num) pci_set_io_region_addr(bdf, region_num, *paddr); *paddr += size; } + + int is_64bit = !(val & PCI_BASE_ADDRESS_SPACE_IO) && + (val & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64; + if (is_64bit) { + pci_config_writel(bdf, ofs + 4, 0); + } + return is_64bit; }
static void pci_bios_allocate_regions(u16 bdf) { int i; for (i = 0; i < PCI_NUM_REGIONS; i++) { - pci_bios_allocate_region(bdf, i); + int is_64bit = pci_bios_allocate_region(bdf, i); + if (is_64bit){ + i++; + } } }
Make pci bar assigner preferchable memory aware. This is needed for PCI bridge support because memory space and prefetchable memory space is filtered independently based on memory base/limit and prefetchable memory base/limit of pci bridge. On bus 0, such a distinction isn't necessary so keep existing behavior by checking bus=0.
With this patch, pci mem assignment area has been decreased. To make seabios behave as before for compatible reason, define CONFIG_OLD_PCIMEM_ASSIGNMENT.
Signed-off-by: Isaku Yamahata yamahata@valinux.co.jp
--- changes v1 -> v2. - introduced BUILD_PCI{MEM, PERFMEM}_{START, SIZE, END} - added range overlap check of pci mem/perfmem area. --- src/config.h | 17 +++++++++++++++++ src/pciinit.c | 49 ++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 59 insertions(+), 7 deletions(-)
diff --git a/src/config.h b/src/config.h index ad569c6..b1e17de 100644 --- a/src/config.h +++ b/src/config.h @@ -151,7 +151,24 @@ // 32KB for shadow ram copying (works around emulator deficiencies) #define BUILD_BIOS_TMP_ADDR 0x30000 #define BUILD_MAX_HIGHMEM 0xe0000000 + +// Support old pci mem assignment behaviour +//#define CONFIG_OLD_PCIMEM_ASSIGNMENT 1 +#if CONFIG_OLD_PCIMEM_ASSIGNMENT +#define BUILD_PCIMEM_START 0xf0000000 +#define BUILD_PCIMEM_SIZE (BUILD_PCIMEM_END - BUILD_PCIMEM_START) +#define BUILD_PCIMEM_END 0xfec00000 /* IOAPIC is mapped at */ +#define BUILD_PCIPREFMEM_START 0 +#define BUILD_PCIPREFMEM_SIZE 0 +#define BUILD_PCIPREFMEM_END 0 +#else #define BUILD_PCIMEM_START 0xf0000000 +#define BUILD_PCIMEM_SIZE 0x08000000 /* half- of pci window */ +#define BUILD_PCIMEM_END (BUILD_PCIMEM_START + BUILD_PCIMEM_SIZE) +#define BUILD_PCIPREFMEM_START BUILD_PCIMEM_END +#define BUILD_PCIPREFMEM_SIZE (BUILD_PCIPREFMEM_END - BUILD_PCIPREFMEM_START) +#define BUILD_PCIPREFMEM_END 0xfec00000 /* IOAPIC is mapped at */ +#endif
#define BUILD_APIC_ADDR 0xfee00000 #define BUILD_IOAPIC_ADDR 0xfec00000 diff --git a/src/pciinit.c b/src/pciinit.c index b635e44..a65c58d 100644 --- a/src/pciinit.c +++ b/src/pciinit.c @@ -16,6 +16,7 @@
static u32 pci_bios_io_addr; static u32 pci_bios_mem_addr; +static u32 pci_bios_prefmem_addr; /* host irqs corresponding to PCI irqs A-D */ static u8 pci_irqs[4] = { 10, 10, 11, 11 @@ -66,21 +67,54 @@ static int pci_bios_allocate_region(u16 bdf, int region_num) u32 val = pci_config_readl(bdf, ofs); pci_config_writel(bdf, ofs, old);
+ u32 size = (~(val & mask)) + 1; if (val != 0) { - u32 size = (~(val & mask)) + 1; - if (val & PCI_BASE_ADDRESS_SPACE_IO) + if (val & PCI_BASE_ADDRESS_SPACE_IO) { paddr = &pci_bios_io_addr; - else + if (ALIGN(*paddr, size) + size >= 64 * 1024) { + dprintf(1, + "io region of (bdf 0x%x bar %d) can't be mapped.\n", + bdf, region_num); + size = 0; + } + } else if ((val & PCI_BASE_ADDRESS_MEM_PREFETCH) && + /* keep behaviour on bus = 0 */ + pci_bdf_to_bus(bdf) != 0 && + /* If pci_bios_prefmem_addr == 0, keep old behaviour */ + pci_bios_prefmem_addr != 0) { + paddr = &pci_bios_prefmem_addr; + if (ALIGN(*paddr, size) + size >= BUILD_PCIPREFMEM_END) { + dprintf(1, + "prefmem region of (bdf 0x%x bar %d) can't be mapped. " + "decrease BUILD_PCIMEM_SIZE and recompile. size %x\n", + bdf, region_num, BUILD_PCIPREFMEM_SIZE); + size = 0; + } + } else { paddr = &pci_bios_mem_addr; - *paddr = ALIGN(*paddr, size); - pci_set_io_region_addr(bdf, region_num, *paddr); - *paddr += size; + if (ALIGN(*paddr, size) + size >= BUILD_PCIMEM_END) { + dprintf(1, + "mem region of (bdf 0x%x bar %d) can't be mapped. " + "increase BUILD_PCIMEM_SIZE and recompile. size %x\n", + bdf, region_num, BUILD_PCIMEM_SIZE); + size = 0; + } + } + if (size > 0) { + *paddr = ALIGN(*paddr, size); + pci_set_io_region_addr(bdf, region_num, *paddr); + *paddr += size; + } }
int is_64bit = !(val & PCI_BASE_ADDRESS_SPACE_IO) && (val & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64; if (is_64bit) { - pci_config_writel(bdf, ofs + 4, 0); + if (size > 0) { + pci_config_writel(bdf, ofs + 4, 0); + } else { + pci_config_writel(bdf, ofs + 4, ~0); + } } return is_64bit; } @@ -220,6 +254,7 @@ pci_setup(void)
pci_bios_io_addr = 0xc000; pci_bios_mem_addr = BUILD_PCIMEM_START; + pci_bios_prefmem_addr = BUILD_PCIPREFMEM_START;
int bdf, max; foreachpci(bdf, max) {
This patch factors out bar offset calculation. Later the calculation logic will be enhanced.
Signed-off-by: Isaku Yamahata yamahata@valinux.co.jp --- src/pciinit.c | 20 ++++++++++---------- 1 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/src/pciinit.c b/src/pciinit.c index a65c58d..9109739 100644 --- a/src/pciinit.c +++ b/src/pciinit.c @@ -22,15 +22,19 @@ static u8 pci_irqs[4] = { 10, 10, 11, 11 };
+static u32 pci_bar(u16 bdf, int region_num) +{ + if (region_num != PCI_ROM_SLOT) { + return PCI_BASE_ADDRESS_0 + region_num * 4; + } + return PCI_ROM_ADDRESS; +} + static void pci_set_io_region_addr(u16 bdf, int region_num, u32 addr) { u32 ofs, old_addr;
- if (region_num == PCI_ROM_SLOT) { - ofs = PCI_ROM_ADDRESS; - } else { - ofs = PCI_BASE_ADDRESS_0 + region_num * 4; - } + ofs = pci_bar(bdf, region_num);
old_addr = pci_config_readl(bdf, ofs);
@@ -46,11 +50,7 @@ static void pci_set_io_region_addr(u16 bdf, int region_num, u32 addr) static int pci_bios_allocate_region(u16 bdf, int region_num) { u32 *paddr; - int ofs; - if (region_num == PCI_ROM_SLOT) - ofs = PCI_ROM_ADDRESS; - else - ofs = PCI_BASE_ADDRESS_0 + region_num * 4; + u32 ofs = pci_bar(bdf, region_num);
u32 old = pci_config_readl(bdf, ofs); u32 mask;
This patch makes pci bar offset calculation pci bridge aware. The offset of pci bridge rom is different from normal device.
Signed-off-by: Isaku Yamahata yamahata@valinux.co.jp --- src/pciinit.c | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/src/pciinit.c b/src/pciinit.c index 9109739..23b79bc 100644 --- a/src/pciinit.c +++ b/src/pciinit.c @@ -27,7 +27,11 @@ static u32 pci_bar(u16 bdf, int region_num) if (region_num != PCI_ROM_SLOT) { return PCI_BASE_ADDRESS_0 + region_num * 4; } - return PCI_ROM_ADDRESS; + +#define PCI_HEADER_TYPE_MULTI_FUNCTION 0x80 + u8 type = pci_config_readb(bdf, PCI_HEADER_TYPE); + type &= ~PCI_HEADER_TYPE_MULTI_FUNCTION; + return type == PCI_HEADER_TYPE_BRIDGE ? PCI_ROM_ADDRESS1 : PCI_ROM_ADDRESS; }
static void pci_set_io_region_addr(u16 bdf, int region_num, u32 addr)
pci bridge bus initialization.
Signed-off-by: Isaku Yamahata yamahata@valinux.co.jp --- src/pciinit.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 70 insertions(+), 0 deletions(-)
diff --git a/src/pciinit.c b/src/pciinit.c index 23b79bc..d22ee10 100644 --- a/src/pciinit.c +++ b/src/pciinit.c @@ -247,6 +247,74 @@ static void pci_bios_init_device(u16 bdf) } }
+static void +pci_bios_init_bus_rec(int bus, u8 *pci_bus) +{ + int bdf, max; + u16 class; + + dprintf(1, "PCI: %s bus = 0x%x\n", __func__, bus); + + /* prevent accidental access to unintended devices */ + foreachpci_in_bus(bdf, max, bus) { + class = pci_config_readw(bdf, PCI_CLASS_DEVICE); + if (class == PCI_CLASS_BRIDGE_PCI) { + pci_config_writeb(bdf, PCI_SECONDARY_BUS, 255); + pci_config_writeb(bdf, PCI_SUBORDINATE_BUS, 0); + } + } + + foreachpci_in_bus(bdf, max, bus) { + class = pci_config_readw(bdf, PCI_CLASS_DEVICE); + if (class != PCI_CLASS_BRIDGE_PCI) { + continue; + } + dprintf(1, "PCI: %s bdf = 0x%x\n", __func__, bdf); + + u8 pribus = pci_config_readb(bdf, PCI_PRIMARY_BUS); + if (pribus != bus) { + dprintf(1, "PCI: primary bus = 0x%x -> 0x%x\n", pribus, bus); + pci_config_writeb(bdf, PCI_PRIMARY_BUS, bus); + } else { + dprintf(1, "PCI: primary bus = 0x%x\n", pribus); + } + + u8 secbus = pci_config_readb(bdf, PCI_SECONDARY_BUS); + (*pci_bus)++; + if (*pci_bus != secbus) { + dprintf(1, "PCI: secondary bus = 0x%x -> 0x%x\n", + secbus, *pci_bus); + secbus = *pci_bus; + pci_config_writeb(bdf, PCI_SECONDARY_BUS, secbus); + } else { + dprintf(1, "PCI: secondary bus = 0x%x\n", secbus); + } + + /* set to max for access to all subordinate buses. + later set it to accurate value */ + u8 subbus = pci_config_readb(bdf, PCI_SUBORDINATE_BUS); + pci_config_writeb(bdf, PCI_SUBORDINATE_BUS, 255); + + pci_bios_init_bus_rec(secbus, pci_bus); + + if (subbus != *pci_bus) { + dprintf(1, "PCI: subordinate bus = 0x%x -> 0x%x\n", + subbus, *pci_bus); + subbus = *pci_bus; + } else { + dprintf(1, "PCI: subordinate bus = 0x%x\n", subbus); + } + pci_config_writeb(bdf, PCI_SUBORDINATE_BUS, subbus); + } +} + +static void +pci_bios_init_bus(void) +{ + u8 pci_bus = 0; + pci_bios_init_bus_rec(0 /* host bus */, &pci_bus); +} + void pci_setup(void) { @@ -260,6 +328,8 @@ pci_setup(void) pci_bios_mem_addr = BUILD_PCIMEM_START; pci_bios_prefmem_addr = BUILD_PCIPREFMEM_START;
+ pci_bios_init_bus(); + int bdf, max; foreachpci(bdf, max) { pci_bios_init_bridges(bdf);
initialize pci bridge filtering registers.
Signed-off-by: Isaku Yamahata yamahata@valinux.co.jp
--- chages v1 -> v2. - use c99 initialization. --- src/pciinit.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 103 insertions(+), 3 deletions(-)
diff --git a/src/pciinit.c b/src/pciinit.c index d22ee10..3f6d79c 100644 --- a/src/pciinit.c +++ b/src/pciinit.c @@ -14,6 +14,8 @@ #define PCI_ROM_SLOT 6 #define PCI_NUM_REGIONS 7
+static void pci_bios_init_device_in_bus(int bus); + static u32 pci_bios_io_addr; static u32 pci_bios_mem_addr; static u32 pci_bios_prefmem_addr; @@ -172,6 +174,95 @@ static void pci_bios_init_bridges(u16 bdf) } }
+#define PCI_IO_ALIGN 4096 +#define PCI_IO_SHIFT 8 +#define PCI_MEMORY_ALIGN (1UL << 20) +#define PCI_MEMORY_SHIFT 16 +#define PCI_PREF_MEMORY_ALIGN (1UL << 20) +#define PCI_PREF_MEMORY_SHIFT 16 + +static void pci_bios_init_device_bridge(u16 bdf) +{ + pci_bios_allocate_region(bdf, 0); + pci_bios_allocate_region(bdf, 1); + pci_bios_allocate_region(bdf, PCI_ROM_SLOT); + + u32 io_old = pci_bios_io_addr; + u32 mem_old = pci_bios_mem_addr; + u32 prefmem_old = pci_bios_prefmem_addr; + + /* IO BASE is assumed to be 16 bit */ + pci_bios_io_addr = ALIGN(pci_bios_io_addr, PCI_IO_ALIGN); + pci_bios_mem_addr = ALIGN(pci_bios_mem_addr, PCI_MEMORY_ALIGN); + pci_bios_prefmem_addr = + ALIGN(pci_bios_prefmem_addr, PCI_PREF_MEMORY_ALIGN); + + u32 io_base = pci_bios_io_addr; + u32 mem_base = pci_bios_mem_addr; + u32 prefmem_base = pci_bios_prefmem_addr; + + u8 secbus = pci_config_readb(bdf, PCI_SECONDARY_BUS); + if (secbus > 0) { + pci_bios_init_device_in_bus(secbus); + } + + pci_bios_io_addr = ALIGN(pci_bios_io_addr, PCI_IO_ALIGN); + pci_bios_mem_addr = ALIGN(pci_bios_mem_addr, PCI_MEMORY_ALIGN); + pci_bios_prefmem_addr = + ALIGN(pci_bios_prefmem_addr, PCI_PREF_MEMORY_ALIGN); + + u32 io_end = pci_bios_io_addr; + if (io_end == io_base) { + pci_bios_io_addr = io_old; + io_base = 0xffff; + io_end = 1; + } + pci_config_writeb(bdf, PCI_IO_BASE, io_base >> PCI_IO_SHIFT); + pci_config_writew(bdf, PCI_IO_BASE_UPPER16, 0); + pci_config_writeb(bdf, PCI_IO_LIMIT, (io_end - 1) >> PCI_IO_SHIFT); + pci_config_writew(bdf, PCI_IO_LIMIT_UPPER16, 0); + + u32 mem_end = pci_bios_mem_addr; + if (mem_end == mem_base) { + pci_bios_mem_addr = mem_old; + mem_base = 0xffffffff; + mem_end = 1; + } + pci_config_writew(bdf, PCI_MEMORY_BASE, mem_base >> PCI_MEMORY_SHIFT); + pci_config_writew(bdf, PCI_MEMORY_LIMIT, (mem_end -1) >> PCI_MEMORY_SHIFT); + + u32 prefmem_end = pci_bios_prefmem_addr; + if (prefmem_end == prefmem_base) { + pci_bios_prefmem_addr = prefmem_old; + prefmem_base = 0xffffffff; + prefmem_end = 1; + } + pci_config_writew(bdf, PCI_PREF_MEMORY_BASE, + prefmem_base >> PCI_PREF_MEMORY_SHIFT); + pci_config_writew(bdf, PCI_PREF_MEMORY_LIMIT, + (prefmem_end - 1) >> PCI_PREF_MEMORY_SHIFT); + pci_config_writel(bdf, PCI_PREF_BASE_UPPER32, 0); + pci_config_writel(bdf, PCI_PREF_LIMIT_UPPER32, 0); + + dprintf(1, "PCI: br io = [0x%x, 0x%x)\n", io_base, io_end); + dprintf(1, "PCI: br mem = [0x%x, 0x%x)\n", mem_base, mem_end); + dprintf(1, "PCI: br pref = [0x%x, 0x%x)\n", prefmem_base, prefmem_end); + + u16 cmd = pci_config_readw(bdf, PCI_COMMAND); + cmd &= ~PCI_COMMAND_IO; + if (io_end > io_base) { + cmd |= PCI_COMMAND_IO; + } + cmd &= ~PCI_COMMAND_MEMORY; + if (mem_end > mem_base || prefmem_end > prefmem_base) { + cmd |= PCI_COMMAND_MEMORY; + } + cmd |= PCI_COMMAND_MASTER; + pci_config_writew(bdf, PCI_COMMAND, cmd); + + pci_config_maskw(bdf, PCI_BRIDGE_CONTROL, 0, PCI_BRIDGE_CTL_SERR); +} + static void pci_bios_init_device(u16 bdf) { int class; @@ -216,6 +307,9 @@ static void pci_bios_init_device(u16 bdf) pci_set_io_region_addr(bdf, 0, 0x80800000); } break; + case PCI_CLASS_BRIDGE_PCI: + pci_bios_init_device_bridge(bdf); + break; default: /* default memory mappings */ pci_bios_allocate_regions(bdf); @@ -247,6 +341,14 @@ static void pci_bios_init_device(u16 bdf) } }
+static void pci_bios_init_device_in_bus(int bus) +{ + int bdf, max; + foreachpci_in_bus(bdf, max, bus) { + pci_bios_init_device(bdf); + } +} + static void pci_bios_init_bus_rec(int bus, u8 *pci_bus) { @@ -334,7 +436,5 @@ pci_setup(void) foreachpci(bdf, max) { pci_bios_init_bridges(bdf); } - foreachpci(bdf, max) { - pci_bios_init_device(bdf); - } + pci_bios_init_device_in_bus(0 /* host bus */); }
On Tue, Jun 22, 2010 at 05:57:45PM +0900, Isaku Yamahata wrote:
Changes v1 -> v2:
- simplified foreachpci_in_bus()
- add overlap check during pci bar assignemnt.
- use c99 initialization.
Patch description:
This patch set allows seabios to initialize multi pci bus and 64bit BAR.
Currently seabios is able to initialize only pci root bus. However multi pci bus support is wanted because
- more pci bus is wanted in qemu for many slots
- pci express support is commin in qemu which requires multi pci bus.
those patches on Qemu part are under way, though.
Thanks. I've committed this series.
-Kevin