summaryrefslogtreecommitdiffstats
path: root/qemu/roms/seabios/src/fw/pciinit.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/seabios/src/fw/pciinit.c')
-rw-r--r--qemu/roms/seabios/src/fw/pciinit.c964
1 files changed, 0 insertions, 964 deletions
diff --git a/qemu/roms/seabios/src/fw/pciinit.c b/qemu/roms/seabios/src/fw/pciinit.c
deleted file mode 100644
index c31c2fa0c..000000000
--- a/qemu/roms/seabios/src/fw/pciinit.c
+++ /dev/null
@@ -1,964 +0,0 @@
-// Initialize PCI devices (on emulators)
-//
-// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
-// Copyright (C) 2006 Fabrice Bellard
-//
-// This file may be distributed under the terms of the GNU LGPLv3 license.
-
-#include "byteorder.h" // le64_to_cpu
-#include "config.h" // CONFIG_*
-#include "dev-q35.h" // Q35_HOST_BRIDGE_PCIEXBAR_ADDR
-#include "dev-piix.h" // PIIX_*
-#include "e820map.h" // e820_add
-#include "hw/ata.h" // PORT_ATA1_CMD_BASE
-#include "hw/pci.h" // pci_config_readl
-#include "hw/pci_ids.h" // PCI_VENDOR_ID_INTEL
-#include "hw/pci_regs.h" // PCI_COMMAND
-#include "list.h" // struct hlist_node
-#include "malloc.h" // free
-#include "output.h" // dprintf
-#include "paravirt.h" // RamSize
-#include "romfile.h" // romfile_loadint
-#include "string.h" // memset
-#include "util.h" // pci_setup
-#include "x86.h" // outb
-
-#define PCI_DEVICE_MEM_MIN (1<<12) // 4k == page size
-#define PCI_BRIDGE_MEM_MIN (1<<21) // 2M == hugepage size
-#define PCI_BRIDGE_IO_MIN 0x1000 // mandated by pci bridge spec
-
-static const char *region_type_name[] = {
- [ PCI_REGION_TYPE_IO ] = "io",
- [ PCI_REGION_TYPE_MEM ] = "mem",
- [ PCI_REGION_TYPE_PREFMEM ] = "prefmem",
-};
-
-u64 pcimem_start = BUILD_PCIMEM_START;
-u64 pcimem_end = BUILD_PCIMEM_END;
-u64 pcimem64_start = BUILD_PCIMEM64_START;
-u64 pcimem64_end = BUILD_PCIMEM64_END;
-u64 pci_io_low_end = 0xa000;
-
-struct pci_region_entry {
- struct pci_device *dev;
- int bar;
- u64 size;
- u64 align;
- int is64;
- enum pci_region_type type;
- struct hlist_node node;
-};
-
-struct pci_region {
- /* pci region assignments */
- u64 base;
- struct hlist_head list;
-};
-
-struct pci_bus {
- struct pci_region r[PCI_REGION_TYPE_COUNT];
- struct pci_device *bus_dev;
-};
-
-static u32 pci_bar(struct pci_device *pci, int region_num)
-{
- if (region_num != PCI_ROM_SLOT) {
- return PCI_BASE_ADDRESS_0 + region_num * 4;
- }
-
-#define PCI_HEADER_TYPE_MULTI_FUNCTION 0x80
- u8 type = pci->header_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(struct pci_device *pci, int bar, u64 addr, int is64)
-{
- u32 ofs = pci_bar(pci, bar);
- pci_config_writel(pci->bdf, ofs, addr);
- if (is64)
- pci_config_writel(pci->bdf, ofs + 4, addr >> 32);
-}
-
-
-/****************************************************************
- * Misc. device init
- ****************************************************************/
-
-/* host irqs corresponding to PCI irqs A-D */
-const u8 pci_irqs[4] = {
- 10, 10, 11, 11
-};
-
-static int dummy_pci_slot_get_irq(struct pci_device *pci, int pin)
-{
- dprintf(1, "pci_slot_get_irq called with unknown routing\n");
-
- return 0xff; /* PCI defined "unknown" or "no connection" for x86 */
-}
-
-static int (*pci_slot_get_irq)(struct pci_device *pci, int pin) =
- dummy_pci_slot_get_irq;
-
-// Return the global irq number corresponding to a host bus device irq pin.
-static int piix_pci_slot_get_irq(struct pci_device *pci, int pin)
-{
- int slot_addend = 0;
-
- while (pci->parent != NULL) {
- slot_addend += pci_bdf_to_dev(pci->bdf);
- pci = pci->parent;
- }
- slot_addend += pci_bdf_to_dev(pci->bdf) - 1;
- return pci_irqs[(pin - 1 + slot_addend) & 3];
-}
-
-static int mch_pci_slot_get_irq(struct pci_device *pci, int pin)
-{
- int pin_addend = 0;
- while (pci->parent != NULL) {
- pin_addend += pci_bdf_to_dev(pci->bdf);
- pci = pci->parent;
- }
- u8 slot = pci_bdf_to_dev(pci->bdf);
- if (slot <= 24)
- /* Slots 0-24 rotate slot:pin mapping similar to piix above, but
- with a different starting index - see q35-acpi-dsdt.dsl */
- return pci_irqs[(pin - 1 + pin_addend + slot) & 3];
- /* Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H) */
- return pci_irqs[(pin - 1 + pin_addend) & 3];
-}
-
-/* PIIX3/PIIX4 PCI to ISA bridge */
-static void piix_isa_bridge_setup(struct pci_device *pci, void *arg)
-{
- int i, irq;
- u8 elcr[2];
-
- elcr[0] = 0x00;
- elcr[1] = 0x00;
- for (i = 0; i < 4; i++) {
- irq = pci_irqs[i];
- /* set to trigger level */
- elcr[irq >> 3] |= (1 << (irq & 7));
- /* activate irq remapping in PIIX */
- pci_config_writeb(pci->bdf, 0x60 + i, irq);
- }
- outb(elcr[0], PIIX_PORT_ELCR1);
- outb(elcr[1], PIIX_PORT_ELCR2);
- dprintf(1, "PIIX3/PIIX4 init: elcr=%02x %02x\n", elcr[0], elcr[1]);
-}
-
-/* ICH9 LPC PCI to ISA bridge */
-/* PCI_VENDOR_ID_INTEL && PCI_DEVICE_ID_INTEL_ICH9_LPC */
-static void mch_isa_bridge_setup(struct pci_device *dev, void *arg)
-{
- u16 bdf = dev->bdf;
- int i, irq;
- u8 elcr[2];
-
- elcr[0] = 0x00;
- elcr[1] = 0x00;
-
- for (i = 0; i < 4; i++) {
- irq = pci_irqs[i];
- /* set to trigger level */
- elcr[irq >> 3] |= (1 << (irq & 7));
-
- /* activate irq remapping in LPC */
-
- /* PIRQ[A-D] routing */
- pci_config_writeb(bdf, ICH9_LPC_PIRQA_ROUT + i, irq);
- /* PIRQ[E-H] routing */
- pci_config_writeb(bdf, ICH9_LPC_PIRQE_ROUT + i, irq);
- }
- outb(elcr[0], ICH9_LPC_PORT_ELCR1);
- outb(elcr[1], ICH9_LPC_PORT_ELCR2);
- dprintf(1, "Q35 LPC init: elcr=%02x %02x\n", elcr[0], elcr[1]);
-
- /* pm io base */
- pci_config_writel(bdf, ICH9_LPC_PMBASE,
- acpi_pm_base | ICH9_LPC_PMBASE_RTE);
-
- /* acpi enable, SCI: IRQ9 000b = irq9*/
- pci_config_writeb(bdf, ICH9_LPC_ACPI_CTRL, ICH9_LPC_ACPI_CTRL_ACPI_EN);
-
- /* set root complex register block BAR */
- pci_config_writel(bdf, ICH9_LPC_RCBA,
- ICH9_LPC_RCBA_ADDR | ICH9_LPC_RCBA_EN);
- e820_add(ICH9_LPC_RCBA_ADDR, 16*1024, E820_RESERVED);
-
- acpi_pm1a_cnt = acpi_pm_base + 0x04;
- pmtimer_setup(acpi_pm_base + 0x08);
-}
-
-static void storage_ide_setup(struct pci_device *pci, void *arg)
-{
- /* IDE: we map it as in ISA mode */
- pci_set_io_region_addr(pci, 0, PORT_ATA1_CMD_BASE, 0);
- pci_set_io_region_addr(pci, 1, PORT_ATA1_CTRL_BASE, 0);
- pci_set_io_region_addr(pci, 2, PORT_ATA2_CMD_BASE, 0);
- pci_set_io_region_addr(pci, 3, PORT_ATA2_CTRL_BASE, 0);
-}
-
-/* PIIX3/PIIX4 IDE */
-static void piix_ide_setup(struct pci_device *pci, void *arg)
-{
- u16 bdf = pci->bdf;
- pci_config_writew(bdf, 0x40, 0x8000); // enable IDE0
- pci_config_writew(bdf, 0x42, 0x8000); // enable IDE1
-}
-
-static void pic_ibm_setup(struct pci_device *pci, void *arg)
-{
- /* PIC, IBM, MPIC & MPIC2 */
- pci_set_io_region_addr(pci, 0, 0x80800000 + 0x00040000, 0);
-}
-
-static void apple_macio_setup(struct pci_device *pci, void *arg)
-{
- /* macio bridge */
- pci_set_io_region_addr(pci, 0, 0x80800000, 0);
-}
-
-static void piix4_pm_config_setup(u16 bdf)
-{
- // acpi sci is hardwired to 9
- pci_config_writeb(bdf, PCI_INTERRUPT_LINE, 9);
-
- pci_config_writel(bdf, PIIX_PMBASE, acpi_pm_base | 1);
- pci_config_writeb(bdf, PIIX_PMREGMISC, 0x01); /* enable PM io space */
- pci_config_writel(bdf, PIIX_SMBHSTBASE, (acpi_pm_base + 0x100) | 1);
- pci_config_writeb(bdf, PIIX_SMBHSTCFG, 0x09); /* enable SMBus io space */
-}
-
-static int PiixPmBDF = -1;
-
-/* PIIX4 Power Management device (for ACPI) */
-static void piix4_pm_setup(struct pci_device *pci, void *arg)
-{
- PiixPmBDF = pci->bdf;
- piix4_pm_config_setup(pci->bdf);
-
- acpi_pm1a_cnt = acpi_pm_base + 0x04;
- pmtimer_setup(acpi_pm_base + 0x08);
-}
-
-/* ICH9 SMBUS */
-/* PCI_VENDOR_ID_INTEL && PCI_DEVICE_ID_INTEL_ICH9_SMBUS */
-static void ich9_smbus_setup(struct pci_device *dev, void *arg)
-{
- u16 bdf = dev->bdf;
- /* map smbus into io space */
- pci_config_writel(bdf, ICH9_SMB_SMB_BASE,
- (acpi_pm_base + 0x100) | PCI_BASE_ADDRESS_SPACE_IO);
-
- /* enable SMBus */
- pci_config_writeb(bdf, ICH9_SMB_HOSTC, ICH9_SMB_HOSTC_HST_EN);
-}
-
-static const struct pci_device_id pci_device_tbl[] = {
- /* PIIX3/PIIX4 PCI to ISA bridge */
- PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0,
- piix_isa_bridge_setup),
- PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0,
- piix_isa_bridge_setup),
- PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_LPC,
- mch_isa_bridge_setup),
-
- /* STORAGE IDE */
- PCI_DEVICE_CLASS(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1,
- PCI_CLASS_STORAGE_IDE, piix_ide_setup),
- PCI_DEVICE_CLASS(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB,
- PCI_CLASS_STORAGE_IDE, piix_ide_setup),
- PCI_DEVICE_CLASS(PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE,
- storage_ide_setup),
-
- /* PIC, IBM, MIPC & MPIC2 */
- PCI_DEVICE_CLASS(PCI_VENDOR_ID_IBM, 0x0046, PCI_CLASS_SYSTEM_PIC,
- pic_ibm_setup),
- PCI_DEVICE_CLASS(PCI_VENDOR_ID_IBM, 0xFFFF, PCI_CLASS_SYSTEM_PIC,
- pic_ibm_setup),
-
- /* PIIX4 Power Management device (for ACPI) */
- PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
- piix4_pm_setup),
- PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_SMBUS,
- ich9_smbus_setup),
-
- /* 0xff00 */
- PCI_DEVICE_CLASS(PCI_VENDOR_ID_APPLE, 0x0017, 0xff00, apple_macio_setup),
- PCI_DEVICE_CLASS(PCI_VENDOR_ID_APPLE, 0x0022, 0xff00, apple_macio_setup),
-
- PCI_DEVICE_END,
-};
-
-void pci_resume(void)
-{
- if (!CONFIG_QEMU) {
- return;
- }
-
- if (PiixPmBDF >= 0) {
- piix4_pm_config_setup(PiixPmBDF);
- }
-}
-
-static void pci_bios_init_device(struct pci_device *pci)
-{
- u16 bdf = pci->bdf;
- dprintf(1, "PCI: init bdf=%02x:%02x.%x id=%04x:%04x\n"
- , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf)
- , pci->vendor, pci->device);
-
- /* map the interrupt */
- int pin = pci_config_readb(bdf, PCI_INTERRUPT_PIN);
- if (pin != 0)
- pci_config_writeb(bdf, PCI_INTERRUPT_LINE, pci_slot_get_irq(pci, pin));
-
- pci_init_device(pci_device_tbl, pci, NULL);
-
- /* enable memory mappings */
- pci_config_maskw(bdf, PCI_COMMAND, 0,
- PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_SERR);
- /* enable SERR# for forwarding */
- if (pci->header_type & PCI_HEADER_TYPE_BRIDGE)
- pci_config_maskw(bdf, PCI_BRIDGE_CONTROL, 0,
- PCI_BRIDGE_CTL_SERR);
-}
-
-static void pci_bios_init_devices(void)
-{
- struct pci_device *pci;
- foreachpci(pci) {
- pci_bios_init_device(pci);
- }
-}
-
-static void pci_enable_default_vga(void)
-{
- struct pci_device *pci;
-
- foreachpci(pci) {
- if (is_pci_vga(pci)) {
- dprintf(1, "PCI: Using %02x:%02x.%x for primary VGA\n",
- pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
- pci_bdf_to_fn(pci->bdf));
- return;
- }
- }
-
- pci = pci_find_class(PCI_CLASS_DISPLAY_VGA);
- if (!pci) {
- dprintf(1, "PCI: No VGA devices found\n");
- return;
- }
-
- dprintf(1, "PCI: Enabling %02x:%02x.%x for primary VGA\n",
- pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
- pci_bdf_to_fn(pci->bdf));
-
- pci_config_maskw(pci->bdf, PCI_COMMAND, 0,
- PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
-
- while (pci->parent) {
- pci = pci->parent;
-
- dprintf(1, "PCI: Setting VGA enable on bridge %02x:%02x.%x\n",
- pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
- pci_bdf_to_fn(pci->bdf));
-
- pci_config_maskw(pci->bdf, PCI_BRIDGE_CONTROL, 0, PCI_BRIDGE_CTL_VGA);
- pci_config_maskw(pci->bdf, PCI_COMMAND, 0,
- PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
- }
-}
-
-/****************************************************************
- * Platform device initialization
- ****************************************************************/
-
-static void i440fx_mem_addr_setup(struct pci_device *dev, void *arg)
-{
- if (RamSize <= 0x80000000)
- pcimem_start = 0x80000000;
- else if (RamSize <= 0xc0000000)
- pcimem_start = 0xc0000000;
-
- pci_slot_get_irq = piix_pci_slot_get_irq;
-}
-
-static void mch_mem_addr_setup(struct pci_device *dev, void *arg)
-{
- u64 addr = Q35_HOST_BRIDGE_PCIEXBAR_ADDR;
- u32 size = Q35_HOST_BRIDGE_PCIEXBAR_SIZE;
-
- /* setup mmconfig */
- u16 bdf = dev->bdf;
- u32 upper = addr >> 32;
- u32 lower = (addr & 0xffffffff) | Q35_HOST_BRIDGE_PCIEXBAREN;
- pci_config_writel(bdf, Q35_HOST_BRIDGE_PCIEXBAR, 0);
- pci_config_writel(bdf, Q35_HOST_BRIDGE_PCIEXBAR + 4, upper);
- pci_config_writel(bdf, Q35_HOST_BRIDGE_PCIEXBAR, lower);
- e820_add(addr, size, E820_RESERVED);
-
- /* setup pci i/o window (above mmconfig) */
- pcimem_start = addr + size;
-
- pci_slot_get_irq = mch_pci_slot_get_irq;
-
- /* setup io address space */
- if (acpi_pm_base < 0x1000)
- pci_io_low_end = 0x10000;
- else
- pci_io_low_end = acpi_pm_base;
-}
-
-static const struct pci_device_id pci_platform_tbl[] = {
- PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441,
- i440fx_mem_addr_setup),
- PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_Q35_MCH,
- mch_mem_addr_setup),
- PCI_DEVICE_END
-};
-
-static void pci_bios_init_platform(void)
-{
- struct pci_device *pci;
- foreachpci(pci) {
- pci_init_device(pci_platform_tbl, pci, NULL);
- }
-}
-
-
-/****************************************************************
- * Bus initialization
- ****************************************************************/
-
-static void
-pci_bios_init_bus_rec(int bus, u8 *pci_bus)
-{
- int bdf;
- u16 class;
-
- dprintf(1, "PCI: %s bus = 0x%x\n", __func__, bus);
-
- /* prevent accidental access to unintended devices */
- foreachbdf(bdf, 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);
- }
- }
-
- foreachbdf(bdf, 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 extraroots = romfile_loadint("etc/extra-pci-roots", 0);
- u8 pci_bus = 0;
-
- pci_bios_init_bus_rec(0 /* host bus */, &pci_bus);
-
- if (extraroots) {
- while (pci_bus < 0xff) {
- pci_bus++;
- pci_bios_init_bus_rec(pci_bus, &pci_bus);
- }
- }
-}
-
-
-/****************************************************************
- * Bus sizing
- ****************************************************************/
-
-static void
-pci_bios_get_bar(struct pci_device *pci, int bar,
- int *ptype, u64 *psize, int *pis64)
-{
- u32 ofs = pci_bar(pci, bar);
- u16 bdf = pci->bdf;
- u32 old = pci_config_readl(bdf, ofs);
- int is64 = 0, type = PCI_REGION_TYPE_MEM;
- u64 mask;
-
- if (bar == 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;
- type = PCI_REGION_TYPE_IO;
- } else {
- mask = PCI_BASE_ADDRESS_MEM_MASK;
- if (old & PCI_BASE_ADDRESS_MEM_PREFETCH)
- type = PCI_REGION_TYPE_PREFMEM;
- is64 = ((old & PCI_BASE_ADDRESS_MEM_TYPE_MASK)
- == PCI_BASE_ADDRESS_MEM_TYPE_64);
- }
- pci_config_writel(bdf, ofs, ~0);
- }
- u64 val = pci_config_readl(bdf, ofs);
- pci_config_writel(bdf, ofs, old);
- if (is64) {
- u32 hold = pci_config_readl(bdf, ofs + 4);
- pci_config_writel(bdf, ofs + 4, ~0);
- u32 high = pci_config_readl(bdf, ofs + 4);
- pci_config_writel(bdf, ofs + 4, hold);
- val |= ((u64)high << 32);
- mask |= ((u64)0xffffffff << 32);
- *psize = (~(val & mask)) + 1;
- } else {
- *psize = ((~(val & mask)) + 1) & 0xffffffff;
- }
- *ptype = type;
- *pis64 = is64;
-}
-
-static int pci_bios_bridge_region_is64(struct pci_region *r,
- struct pci_device *pci, int type)
-{
- if (type != PCI_REGION_TYPE_PREFMEM)
- return 0;
- u32 pmem = pci_config_readl(pci->bdf, PCI_PREF_MEMORY_BASE);
- if (!pmem) {
- pci_config_writel(pci->bdf, PCI_PREF_MEMORY_BASE, 0xfff0fff0);
- pmem = pci_config_readl(pci->bdf, PCI_PREF_MEMORY_BASE);
- pci_config_writel(pci->bdf, PCI_PREF_MEMORY_BASE, 0x0);
- }
- if ((pmem & PCI_PREF_RANGE_TYPE_MASK) != PCI_PREF_RANGE_TYPE_64)
- return 0;
- struct pci_region_entry *entry;
- hlist_for_each_entry(entry, &r->list, node) {
- if (!entry->is64)
- return 0;
- }
- return 1;
-}
-
-static u64 pci_region_align(struct pci_region *r)
-{
- struct pci_region_entry *entry;
- hlist_for_each_entry(entry, &r->list, node) {
- // The first entry in the sorted list has the largest alignment
- return entry->align;
- }
- return 1;
-}
-
-static u64 pci_region_sum(struct pci_region *r)
-{
- u64 sum = 0;
- struct pci_region_entry *entry;
- hlist_for_each_entry(entry, &r->list, node) {
- sum += entry->size;
- }
- return sum;
-}
-
-static void pci_region_migrate_64bit_entries(struct pci_region *from,
- struct pci_region *to)
-{
- struct hlist_node *n, **last = &to->list.first;
- struct pci_region_entry *entry;
- hlist_for_each_entry_safe(entry, n, &from->list, node) {
- if (!entry->is64)
- continue;
- if (entry->dev->class == PCI_CLASS_SERIAL_USB)
- continue;
- // Move from source list to destination list.
- hlist_del(&entry->node);
- hlist_add(&entry->node, last);
- last = &entry->node.next;
- }
-}
-
-static struct pci_region_entry *
-pci_region_create_entry(struct pci_bus *bus, struct pci_device *dev,
- int bar, u64 size, u64 align, int type, int is64)
-{
- struct pci_region_entry *entry = malloc_tmp(sizeof(*entry));
- if (!entry) {
- warn_noalloc();
- return NULL;
- }
- memset(entry, 0, sizeof(*entry));
- entry->dev = dev;
- entry->bar = bar;
- entry->size = size;
- entry->align = align;
- entry->is64 = is64;
- entry->type = type;
- // Insert into list in sorted order.
- struct hlist_node **pprev;
- struct pci_region_entry *pos;
- hlist_for_each_entry_pprev(pos, pprev, &bus->r[type].list, node) {
- if (pos->align < align || (pos->align == align && pos->size < size))
- break;
- }
- hlist_add(&entry->node, pprev);
- return entry;
-}
-
-static int pci_bus_hotplug_support(struct pci_bus *bus, u8 pcie_cap)
-{
- u8 shpc_cap;
-
- if (pcie_cap) {
- u16 pcie_flags = pci_config_readw(bus->bus_dev->bdf,
- pcie_cap + PCI_EXP_FLAGS);
- u8 port_type = ((pcie_flags & PCI_EXP_FLAGS_TYPE) >>
- (__builtin_ffs(PCI_EXP_FLAGS_TYPE) - 1));
- u8 downstream_port = (port_type == PCI_EXP_TYPE_DOWNSTREAM) ||
- (port_type == PCI_EXP_TYPE_ROOT_PORT);
- /*
- * PCI Express SPEC, 7.8.2:
- * Slot Implemented – When Set, this bit indicates that the Link
- * HwInit associated with this Port is connected to a slot (as
- * compared to being connected to a system-integrated device or
- * being disabled).
- * This bit is valid for Downstream Ports. This bit is undefined
- * for Upstream Ports.
- */
- u16 slot_implemented = pcie_flags & PCI_EXP_FLAGS_SLOT;
-
- return downstream_port && slot_implemented;
- }
-
- shpc_cap = pci_find_capability(bus->bus_dev, PCI_CAP_ID_SHPC, 0);
- return !!shpc_cap;
-}
-
-static int pci_bios_check_devices(struct pci_bus *busses)
-{
- dprintf(1, "PCI: check devices\n");
-
- // Calculate resources needed for regular (non-bus) devices.
- struct pci_device *pci;
- foreachpci(pci) {
- if (pci->class == PCI_CLASS_BRIDGE_PCI)
- busses[pci->secondary_bus].bus_dev = pci;
-
- struct pci_bus *bus = &busses[pci_bdf_to_bus(pci->bdf)];
- if (!bus->bus_dev)
- /*
- * Resources for all root busses go in busses[0]
- */
- bus = &busses[0];
- int i;
- for (i = 0; i < PCI_NUM_REGIONS; i++) {
- if ((pci->class == PCI_CLASS_BRIDGE_PCI) &&
- (i >= PCI_BRIDGE_NUM_REGIONS && i < PCI_ROM_SLOT))
- continue;
- int type, is64;
- u64 size;
- pci_bios_get_bar(pci, i, &type, &size, &is64);
- if (size == 0)
- continue;
-
- if (type != PCI_REGION_TYPE_IO && size < PCI_DEVICE_MEM_MIN)
- size = PCI_DEVICE_MEM_MIN;
- struct pci_region_entry *entry = pci_region_create_entry(
- bus, pci, i, size, size, type, is64);
- if (!entry)
- return -1;
-
- if (is64)
- i++;
- }
- }
-
- // Propagate required bus resources to parent busses.
- int secondary_bus;
- for (secondary_bus=MaxPCIBus; secondary_bus>0; secondary_bus--) {
- struct pci_bus *s = &busses[secondary_bus];
- if (!s->bus_dev)
- continue;
- struct pci_bus *parent = &busses[pci_bdf_to_bus(s->bus_dev->bdf)];
- if (!parent->bus_dev)
- /*
- * Resources for all root busses go in busses[0]
- */
- parent = &busses[0];
- int type;
- u8 pcie_cap = pci_find_capability(s->bus_dev, PCI_CAP_ID_EXP, 0);
- int hotplug_support = pci_bus_hotplug_support(s, pcie_cap);
- for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) {
- u64 align = (type == PCI_REGION_TYPE_IO) ?
- PCI_BRIDGE_IO_MIN : PCI_BRIDGE_MEM_MIN;
- if (!pci_bridge_has_region(s->bus_dev, type))
- continue;
- if (pci_region_align(&s->r[type]) > align)
- align = pci_region_align(&s->r[type]);
- u64 sum = pci_region_sum(&s->r[type]);
- int resource_optional = pcie_cap && (type == PCI_REGION_TYPE_IO);
- if (!sum && hotplug_support && !resource_optional)
- sum = align; /* reserve min size for hot-plug */
- u64 size = ALIGN(sum, align);
- int is64 = pci_bios_bridge_region_is64(&s->r[type],
- s->bus_dev, type);
- // entry->bar is -1 if the entry represents a bridge region
- struct pci_region_entry *entry = pci_region_create_entry(
- parent, s->bus_dev, -1, size, align, type, is64);
- if (!entry)
- return -1;
- dprintf(1, "PCI: secondary bus %d size %08llx type %s\n",
- entry->dev->secondary_bus, size,
- region_type_name[entry->type]);
- }
- }
- return 0;
-}
-
-
-/****************************************************************
- * BAR assignment
- ****************************************************************/
-
-// Setup region bases (given the regions' size and alignment)
-static int pci_bios_init_root_regions_io(struct pci_bus *bus)
-{
- /*
- * QEMU I/O address space usage:
- * 0000 - 0fff legacy isa, pci config, pci root bus, ...
- * 1000 - 9fff free
- * a000 - afff hotplug (cpu, pci via acpi, i440fx/piix only)
- * b000 - bfff power management (PORT_ACPI_PM_BASE)
- * [ qemu 1.4+ implements pci config registers
- * properly so guests can place the registers
- * where they want, on older versions its fixed ]
- * c000 - ffff free, traditionally used for pci io
- */
- struct pci_region *r_io = &bus->r[PCI_REGION_TYPE_IO];
- u64 sum = pci_region_sum(r_io);
- if (sum < 0x4000) {
- /* traditional region is big enougth, use it */
- r_io->base = 0xc000;
- } else if (sum < pci_io_low_end - 0x1000) {
- /* use the larger region at 0x1000 */
- r_io->base = 0x1000;
- } else {
- /* not enouth io address space -> error out */
- return -1;
- }
- dprintf(1, "PCI: IO: %4llx - %4llx\n", r_io->base, r_io->base + sum - 1);
- return 0;
-}
-
-static int pci_bios_init_root_regions_mem(struct pci_bus *bus)
-{
- struct pci_region *r_end = &bus->r[PCI_REGION_TYPE_PREFMEM];
- struct pci_region *r_start = &bus->r[PCI_REGION_TYPE_MEM];
-
- if (pci_region_align(r_start) < pci_region_align(r_end)) {
- // Swap regions to improve alignment.
- r_end = r_start;
- r_start = &bus->r[PCI_REGION_TYPE_PREFMEM];
- }
- u64 sum = pci_region_sum(r_end);
- u64 align = pci_region_align(r_end);
- r_end->base = ALIGN_DOWN((pcimem_end - sum), align);
- sum = pci_region_sum(r_start);
- align = pci_region_align(r_start);
- r_start->base = ALIGN_DOWN((r_end->base - sum), align);
-
- if ((r_start->base < pcimem_start) ||
- (r_start->base > pcimem_end))
- // Memory range requested is larger than available.
- return -1;
- return 0;
-}
-
-#define PCI_IO_SHIFT 8
-#define PCI_MEMORY_SHIFT 16
-#define PCI_PREF_MEMORY_SHIFT 16
-
-static void
-pci_region_map_one_entry(struct pci_region_entry *entry, u64 addr)
-{
- u16 bdf = entry->dev->bdf;
- if (entry->bar >= 0) {
- dprintf(1, "PCI: map device bdf=%02x:%02x.%x"
- " bar %d, addr %08llx, size %08llx [%s]\n",
- pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf),
- entry->bar, addr, entry->size, region_type_name[entry->type]);
-
- pci_set_io_region_addr(entry->dev, entry->bar, addr, entry->is64);
- return;
- }
-
- u64 limit = addr + entry->size - 1;
- if (entry->type == PCI_REGION_TYPE_IO) {
- pci_config_writeb(bdf, PCI_IO_BASE, addr >> PCI_IO_SHIFT);
- pci_config_writew(bdf, PCI_IO_BASE_UPPER16, 0);
- pci_config_writeb(bdf, PCI_IO_LIMIT, limit >> PCI_IO_SHIFT);
- pci_config_writew(bdf, PCI_IO_LIMIT_UPPER16, 0);
- }
- if (entry->type == PCI_REGION_TYPE_MEM) {
- pci_config_writew(bdf, PCI_MEMORY_BASE, addr >> PCI_MEMORY_SHIFT);
- pci_config_writew(bdf, PCI_MEMORY_LIMIT, limit >> PCI_MEMORY_SHIFT);
- }
- if (entry->type == PCI_REGION_TYPE_PREFMEM) {
- pci_config_writew(bdf, PCI_PREF_MEMORY_BASE, addr >> PCI_PREF_MEMORY_SHIFT);
- pci_config_writew(bdf, PCI_PREF_MEMORY_LIMIT, limit >> PCI_PREF_MEMORY_SHIFT);
- pci_config_writel(bdf, PCI_PREF_BASE_UPPER32, addr >> 32);
- pci_config_writel(bdf, PCI_PREF_LIMIT_UPPER32, limit >> 32);
- }
-}
-
-static void pci_region_map_entries(struct pci_bus *busses, struct pci_region *r)
-{
- struct hlist_node *n;
- struct pci_region_entry *entry;
- hlist_for_each_entry_safe(entry, n, &r->list, node) {
- u64 addr = r->base;
- r->base += entry->size;
- if (entry->bar == -1)
- // Update bus base address if entry is a bridge region
- busses[entry->dev->secondary_bus].r[entry->type].base = addr;
- pci_region_map_one_entry(entry, addr);
- hlist_del(&entry->node);
- free(entry);
- }
-}
-
-static void pci_bios_map_devices(struct pci_bus *busses)
-{
- if (pci_bios_init_root_regions_io(busses))
- panic("PCI: out of I/O address space\n");
-
- dprintf(1, "PCI: 32: %016llx - %016llx\n", pcimem_start, pcimem_end);
- if (pci_bios_init_root_regions_mem(busses)) {
- struct pci_region r64_mem, r64_pref;
- r64_mem.list.first = NULL;
- r64_pref.list.first = NULL;
- pci_region_migrate_64bit_entries(&busses[0].r[PCI_REGION_TYPE_MEM],
- &r64_mem);
- pci_region_migrate_64bit_entries(&busses[0].r[PCI_REGION_TYPE_PREFMEM],
- &r64_pref);
-
- if (pci_bios_init_root_regions_mem(busses))
- panic("PCI: out of 32bit address space\n");
-
- u64 sum_mem = pci_region_sum(&r64_mem);
- u64 sum_pref = pci_region_sum(&r64_pref);
- u64 align_mem = pci_region_align(&r64_mem);
- u64 align_pref = pci_region_align(&r64_pref);
-
- r64_mem.base = le64_to_cpu(romfile_loadint("etc/reserved-memory-end", 0));
- if (r64_mem.base < 0x100000000LL + RamSizeOver4G)
- r64_mem.base = 0x100000000LL + RamSizeOver4G;
- r64_mem.base = ALIGN(r64_mem.base, align_mem);
- r64_mem.base = ALIGN(r64_mem.base, (1LL<<30)); // 1G hugepage
- r64_pref.base = r64_mem.base + sum_mem;
- r64_pref.base = ALIGN(r64_pref.base, align_pref);
- r64_pref.base = ALIGN(r64_pref.base, (1LL<<30)); // 1G hugepage
- pcimem64_start = r64_mem.base;
- pcimem64_end = r64_pref.base + sum_pref;
- pcimem64_end = ALIGN(pcimem64_end, (1LL<<30)); // 1G hugepage
- dprintf(1, "PCI: 64: %016llx - %016llx\n", pcimem64_start, pcimem64_end);
-
- pci_region_map_entries(busses, &r64_mem);
- pci_region_map_entries(busses, &r64_pref);
- } else {
- // no bars mapped high -> drop 64bit window (see dsdt)
- pcimem64_start = 0;
- }
- // Map regions on each device.
- int bus;
- for (bus = 0; bus<=MaxPCIBus; bus++) {
- int type;
- for (type = 0; type < PCI_REGION_TYPE_COUNT; type++)
- pci_region_map_entries(busses, &busses[bus].r[type]);
- }
-}
-
-
-/****************************************************************
- * Main setup code
- ****************************************************************/
-
-void
-pci_setup(void)
-{
- if (!CONFIG_QEMU)
- return;
-
- dprintf(3, "pci setup\n");
-
- dprintf(1, "=== PCI bus & bridge init ===\n");
- if (pci_probe_host() != 0) {
- return;
- }
- pci_bios_init_bus();
-
- dprintf(1, "=== PCI device probing ===\n");
- pci_probe_devices();
-
- pcimem_start = RamSize;
- pci_bios_init_platform();
-
- dprintf(1, "=== PCI new allocation pass #1 ===\n");
- struct pci_bus *busses = malloc_tmp(sizeof(*busses) * (MaxPCIBus + 1));
- if (!busses) {
- warn_noalloc();
- return;
- }
- memset(busses, 0, sizeof(*busses) * (MaxPCIBus + 1));
- if (pci_bios_check_devices(busses))
- return;
-
- dprintf(1, "=== PCI new allocation pass #2 ===\n");
- pci_bios_map_devices(busses);
-
- pci_bios_init_devices();
-
- free(busses);
-
- pci_enable_default_vga();
-}