jan.kiszka@siemens.com, juzhang@redhat.com, agraf@suse.de, yamahata@valinux.co.jp, mkletzan@redhat.com, afaerber@suse.de, armbru@redhat.com, lcapitulino@redhat.com, alex.williamson@redhat.com Message-Id: 3552c1f47b1af1abef3e4806935f19babab0ac7c.1347565443.git.jbaron@redhat.com In-Reply-To: cover.1347565443.git.jbaron@redhat.com References: cover.1347565443.git.jbaron@redhat.com Subject: [PATCH 5/9] seabios: add q35 initialization functions.
From: Isaku Yamahata yamahata@valinux.co.jp
add q35 initialization functions.
[jbaron@redhat.com: restructured to current seabios base] Signed-off-by: Isaku Yamahata yamahata@valinux.co.jp Signed-off-by: Jason Baron jbaron@redhat.com --- src/acpi.c | 69 +++++++++++++++++++++++++++++++++++++++++++- src/dev-q35.h | 46 +++++++++++++++++++++++++++++ src/pciinit.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/shadow.c | 13 ++++++++ src/smm.c | 37 +++++++++++++++++++++++ 5 files changed, 251 insertions(+), 3 deletions(-) create mode 100644 src/dev-q35.h
diff --git a/src/acpi.c b/src/acpi.c index 3577c70..6cf345a 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -14,6 +14,7 @@ #include "ioport.h" // inl #include "paravirt.h" // qemu_cfg_irq0_override #include "memmap.h" +#include "dev-q35.h"
/****************************************************/ /* ACPI tables init */ @@ -261,11 +262,37 @@ static void piix4_fadt_init(struct pci_device *pci, void *arg) (1 << 15)); }
+/* PCI_VENDOR_ID_INTEL && PCI_DEVICE_ID_INTEL_ICH9_LPC */ +void ich9_lpc_fadt_init(struct pci_device *dev, void *arg) +{ + struct fadt_descriptor_rev1 *fadt = arg; + + fadt->model = 1; + fadt->reserved1 = 0; + fadt->sci_int = cpu_to_le16(9); + fadt->smi_cmd = cpu_to_le32(PORT_SMI_CMD); + fadt->acpi_enable = ICH9_ACPI_ENABLE; + fadt->acpi_disable = ICH9_ACPI_DISABLE; + fadt->pm1a_evt_blk = cpu_to_le32(PORT_ACPI_PM_BASE); + fadt->pm1a_cnt_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x04); + fadt->pm_tmr_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x08); + fadt->gpe0_blk = cpu_to_le32(PORT_ACPI_PM_BASE + ICH9_PMIO_GPE0_STS); + fadt->pm1_evt_len = 4; + fadt->pm1_cnt_len = 2; + fadt->pm_tmr_len = 4; + fadt->gpe0_blk_len = ICH9_PMIO_GPE0_BLK_LEN; + fadt->plvl2_lat = cpu_to_le16(0xfff); // C2 state not supported + fadt->plvl3_lat = cpu_to_le16(0xfff); // C3 state not supported + /* WBINVD + PROC_C1 + SLP_BUTTON + FIX_RTC + RTC_S4 */ + fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 5) | (1 << 6) | (1 << 7)); +} + static const struct pci_device_id fadt_init_tbl[] = { /* PIIX4 Power Management device (for ACPI) */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, piix4_fadt_init), - + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_LPC, + ich9_lpc_fadt_init), PCI_DEVICE_END };
@@ -744,11 +771,49 @@ struct acpi_mcfg struct e820entry *e820; };
+/* PCI_VENDOR_ID_INTEL && DEVICE_ID_INTEL_Q35_MCH */ +void mch_mcfg_find(struct pci_device *dev, void *arg) +{ + struct acpi_mcfg *mcfg = arg; + + mcfg->nr = 1; +} + +/* PCI_VENDOR_ID_INTEL && DEVICE_ID_INTEL_Q35_MCH */ +void mch_mcfg_init(struct pci_device *dev, void *arg) +{ + u16 bdf = dev->bdf; + + u64 addr = Q35_HOST_BRIDGE_PCIEXBAR_ADDR | Q35_HOST_BRIDGE_PCIEXBAREN; + u32 upper = addr >> 32; + u32 lower = addr & 0xffffffff; + + /* at first disable the region. and then update/enable it. */ + 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); + + struct acpi_mcfg *mcfg = arg; + struct acpi_mcfg_allocation *alloc = &mcfg->mcfg->allocation[0]; + alloc->address = Q35_HOST_BRIDGE_PCIEXBAR_ADDR; + alloc->pci_segment = Q35_HOST_PCIE_PCI_SEGMENT; + alloc->start_bus_number = Q35_HOST_PCIE_START_BUS_NUMBER; + alloc->end_bus_number = Q35_HOST_PCIE_END_BUS_NUMBER; + + mcfg->e820->start = Q35_HOST_BRIDGE_PCIEXBAR_ADDR; + mcfg->e820->size = Q35_HOST_BRIDGE_PCIEXBAR_SIZE; + mcfg->e820->type = E820_RESERVED; +} + static const struct pci_device_id mcfg_find_tbl[] = { + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_Q35_MCH, + mch_mcfg_find), PCI_DEVICE_END, };
static const struct pci_device_id mcfg_init_tbl[] = { + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_Q35_MCH, + mch_mcfg_init), PCI_DEVICE_END, };
@@ -811,7 +876,7 @@ build_mcfg(void) static const struct pci_device_id acpi_find_tbl[] = { /* PIIX4 Power Management device. */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL), - + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_LPC, NULL), PCI_DEVICE_END, };
diff --git a/src/dev-q35.h b/src/dev-q35.h new file mode 100644 index 0000000..91310b5 --- /dev/null +++ b/src/dev-q35.h @@ -0,0 +1,46 @@ +#ifndef __DEV_Q35_H +#define __DEV_Q35_H + +#include "types.h" // u16 + +#define PCI_DEVICE_ID_INTEL_Q35_MCH 0x29c0 +#define Q35_HOST_BRIDGE_PAM0 0x90 +#define Q35_HOST_BRIDGE_SMRAM 0x9d +#define Q35_HOST_BRIDGE_PCIEXBAR 0x60 +#define Q35_HOST_BRIDGE_PCIEXBAR_SIZE (256 * 1024 * 1024) +#define Q35_HOST_BRIDGE_PCIEXBAR_ADDR 0xe0000000 +#define Q35_HOST_BRIDGE_PCIEXBAREN ((u64)1) +#define Q35_HOST_PCIE_PCI_SEGMENT 0 +#define Q35_HOST_PCIE_START_BUS_NUMBER 0 +#define Q35_HOST_PCIE_END_BUS_NUMBER 255 + +#define PCI_DEVICE_ID_INTEL_ICH9_LPC 0x2918 +#define ICH9_LPC_PMBASE 0x40 +#define ICH9_LPC_PMBASE_RTE 0x1 + +#define ICH9_LPC_ACPI_CTRL 0x44 +#define ICH9_LPC_ACPI_CTRL_ACPI_EN 0x80 +#define ICH9_LPC_PIRQA_ROUT 0x60 +#define ICH9_LPC_PIRQE_ROUT 0x68 +#define ICH9_LPC_PIRQ_ROUT_IRQEN 0x80 +#define ICH9_LPC_PORT_ELCR1 0x4d0 +#define ICH9_LPC_PORT_ELCR2 0x4d1 +#define PCI_DEVICE_ID_INTEL_ICH9_SMBUS 0x2930 +#define ICH9_SMB_SMB_BASE 0x20 +#define ICH9_SMB_HOSTC 0x40 +#define ICH9_SMB_HOSTC_HST_EN 0x01 + +#define ICH9_ACPI_ENABLE 0x2 +#define ICH9_ACPI_DISABLE 0x3 + +/* ICH9 LPC PM I/O registers are 128 ports and 128-aligned */ +#define ICH9_PMIO_GPE0_STS 0x20 +#define ICH9_PMIO_GPE0_BLK_LEN 0x10 +#define ICH9_PMIO_SMI_EN 0x30 +#define ICH9_PMIO_SMI_EN_APMC_EN (1 << 5) + +/* FADT ACPI_ENABLE/ACPI_DISABLE */ +#define ICH9_APM_ACPI_ENABLE 0x2 +#define ICH9_APM_ACPI_DISABLE 0x3 + +#endif // dev-q35.h diff --git a/src/pciinit.c b/src/pciinit.c index 3b8525e..71256e4 100644 --- a/src/pciinit.c +++ b/src/pciinit.c @@ -12,6 +12,7 @@ #include "ioport.h" // PORT_ATA1_CMD_BASE #include "config.h" // CONFIG_* #include "xen.h" // usingXen +#include "dev-q35.h" // usingXen
#define PCI_DEVICE_MEM_MIN 0x1000 #define PCI_BRIDGE_IO_MIN 0x1000 @@ -119,12 +120,45 @@ static void piix_isa_bridge_init(struct pci_device *pci, void *arg) 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 */ +void mch_isa_bridge_init(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 | ICH9_LPC_PIRQ_ROUT_IRQEN); + /* PIRQ[E-H] routing */ + pci_config_writeb(bdf, ICH9_LPC_PIRQE_ROUT + i, + irq | ICH9_LPC_PIRQ_ROUT_IRQEN); + } + + 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]); +} + static const struct pci_device_id pci_isa_bridge_tbl[] = { /* PIIX3/PIIX4 PCI to ISA bridge */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, piix_isa_bridge_init), PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, piix_isa_bridge_init), + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_LPC, + mch_isa_bridge_init),
PCI_DEVICE_END }; @@ -193,11 +227,40 @@ static void piix4_pm_init(struct pci_device *pci, void *arg) pci_config_writeb(bdf, 0xd2, 0x09); /* enable SMBus io space */ }
+/* ICH9 LPC Power Management device (for ACPI) */ +/* PCI_VENDOR_ID_INTEL && PCI_DEVICE_ID_INTEL_ICH9_LPC */ +void ich9_lpc_pm_init(struct pci_device *dev, void *arg) +{ + u16 bdf = dev->bdf; + /* pm io base */ + pci_config_writel(bdf, ICH9_LPC_PMBASE, + PORT_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); +} + +/* ICH9 SMBUS */ +/* PCI_VENDOR_ID_INTEL && PCI_DEVICE_ID_INTEL_ICH9_SMBUS */ +void ich9_smbus_init(struct pci_device *dev, void *arg) +{ + u16 bdf = dev->bdf; + /* map smbus into io space */ + pci_config_writel(bdf, ICH9_SMB_SMB_BASE, + PORT_SMB_BASE | 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[] = { /* PIIX4 Power Management device (for ACPI) */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, piix4_pm_init), - + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_LPC, + ich9_lpc_pm_init), + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_SMBUS, + ich9_smbus_init), PCI_DEVICE_END, };
@@ -647,9 +710,33 @@ void i440fx_mem_addr_init(struct pci_device *dev, void *arg) }
+void mch_mem_addr_init(struct pci_device *dev, void *arg) +{ + struct pci_mem_addr *addr = arg; + u64 s, e; + +#if BUILD_MAX_HIGHMEM != 0xe0000000 +# error "please adjust memory mapping area" +#endif + + /* + * BUILD_MAX_HIGHMEM == 0xe0000000 + * [0xe000 0000, 0xf000 0000) for MCFG + * 4GB - 512MB, 4GB - 256MB + * [0xf000 0000, 0xfec0 0000) for DMI interface(subtractive decode) + * 4GB - 256MB, 4GB - 20MB + */ + s = BUILD_MAX_HIGHMEM + 256 * 1024 * 1024; + e = s + 128 * 1024 * 1024 - 1; + *(addr->pcimem_start) = s; + *(addr->pcimem_end) = e; +} + static const struct pci_device_id pci_mem_addr_tbl[] = { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, i440fx_mem_addr_init), + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_Q35_MCH, + mch_mem_addr_init), PCI_DEVICE_END, };
diff --git a/src/shadow.c b/src/shadow.c index 11c4d5e..a2195da 100644 --- a/src/shadow.c +++ b/src/shadow.c @@ -11,6 +11,7 @@ #include "pci_ids.h" // PCI_VENDOR_ID_INTEL #include "pci_regs.h" // PCI_VENDOR_ID #include "xen.h" // usingXen +#include "dev-q35.h" // PCI_VENDOR_ID_INTEL
// On the emulators, the bios at 0xf0000 is also at 0xffff0000 #define BIOS_SRC_OFFSET 0xfff00000 @@ -101,9 +102,16 @@ static void i440fx_bios_make_readonly(struct pci_device *pci, void *arg) make_bios_readonly_intel(pci->bdf, I440FX_PAM0); }
+void mch_bios_make_readonly(struct pci_device *pci, void *arg) +{ + make_bios_readonly_intel(pci->bdf, Q35_HOST_BRIDGE_PAM0); +} + static const struct pci_device_id dram_controller_make_readonly_tbl[] = { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, i440fx_bios_make_readonly), + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_Q35_MCH, + mch_bios_make_readonly), PCI_DEVICE_END };
@@ -127,6 +135,11 @@ make_bios_writable(void) make_bios_writable_intel(bdf, I440FX_PAM0); return; } + if (vendor == PCI_VENDOR_ID_INTEL + && device == PCI_DEVICE_ID_INTEL_Q35_MCH) { + make_bios_writable_intel(bdf, Q35_HOST_BRIDGE_PAM0); + return; + } } dprintf(1, "Unable to unlock ram - bridge not found\n"); } diff --git a/src/smm.c b/src/smm.c index d0d1476..63fc242 100644 --- a/src/smm.c +++ b/src/smm.c @@ -11,6 +11,7 @@ #include "ioport.h" // outb #include "pci_ids.h" // PCI_VENDOR_ID_INTEL #include "xen.h" // usingXen +#include "dev-q35.h"
ASM32FLAT( ".global smm_relocation_start\n" @@ -137,9 +138,45 @@ static void piix4_apmc_smm_init(struct pci_device *pci, void *arg) pci_config_writeb(i440_pci->bdf, I440FX_SMRAM, 0x02 | 0x08); }
+/* PCI_VENDOR_ID_INTEL && PCI_DEVICE_ID_INTEL_ICH9_LPC */ +void ich9_lpc_apmc_smm_init(struct pci_device *dev, void *arg) +{ + struct pci_device *mch_dev; + int mch_bdf; + + // This code is hardcoded for Q35 Power Management device. + mch_dev = pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_Q35_MCH); + mch_bdf = mch_dev->bdf; + + if (mch_bdf < 0) + return; + + /* check if SMM init is already done */ + u32 value = inl(PORT_ACPI_PM_BASE + ICH9_PMIO_SMI_EN); + if (value & ICH9_PMIO_SMI_EN_APMC_EN) + return; + + /* enable the SMM memory window */ + pci_config_writeb(mch_bdf, Q35_HOST_BRIDGE_SMRAM, 0x02 | 0x48); + + smm_save_and_copy(); + + /* enable SMI generation when writing to the APMC register */ + outl(value | ICH9_PMIO_SMI_EN_APMC_EN, + PORT_ACPI_PM_BASE + ICH9_PMIO_SMI_EN); + + smm_relocate_and_restore(); + + /* close the SMM memory window and enable normal SMM */ + pci_config_writeb(mch_bdf, Q35_HOST_BRIDGE_SMRAM, 0x02 | 0x08); +} + static const struct pci_device_id smm_init_tbl[] = { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, piix4_apmc_smm_init), + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_LPC, + ich9_lpc_apmc_smm_init),
PCI_DEVICE_END, };