diff options
-rw-r--r-- | src/paravirt.c | 1 | ||||
-rw-r--r-- | src/smm.c | 66 | ||||
-rw-r--r-- | src/util.h | 1 |
3 files changed, 37 insertions, 31 deletions
diff --git a/src/paravirt.c b/src/paravirt.c index f0610397..4a26c6e9 100644 --- a/src/paravirt.c +++ b/src/paravirt.c @@ -106,6 +106,7 @@ qemu_platform_setup(void) // Initialize pci pci_setup(); + smm_device_setup(); smm_setup(); // Initialize mtrr and smp @@ -6,6 +6,7 @@ // This file may be distributed under the terms of the GNU LGPLv3 license. #include "pci.h" // pci_config_writel +#include "pci_regs.h" // PCI_DEVICE_ID #include "util.h" // wbinvd #include "config.h" // CONFIG_* #include "ioport.h" // outb @@ -111,46 +112,30 @@ smm_relocate_and_restore(void) #define PIIX_APMC_EN (1 << 25) // This code is hardcoded for PIIX4 Power Management device. -static void piix4_apmc_smm_setup(struct pci_device *pci, void *arg) +static void piix4_apmc_smm_setup(int isabdf, int i440_bdf) { - struct pci_device *i440_pci = pci_find_device(PCI_VENDOR_ID_INTEL - , PCI_DEVICE_ID_INTEL_82441); - if (!i440_pci) - return; - /* check if SMM init is already done */ - u32 value = pci_config_readl(pci->bdf, PIIX_DEVACTB); + u32 value = pci_config_readl(isabdf, PIIX_DEVACTB); if (value & PIIX_APMC_EN) return; /* enable the SMM memory window */ - pci_config_writeb(i440_pci->bdf, I440FX_SMRAM, 0x02 | 0x48); + pci_config_writeb(i440_bdf, I440FX_SMRAM, 0x02 | 0x48); smm_save_and_copy(); /* enable SMI generation when writing to the APMC register */ - pci_config_writel(pci->bdf, PIIX_DEVACTB, value | PIIX_APMC_EN); + pci_config_writel(isabdf, PIIX_DEVACTB, value | PIIX_APMC_EN); smm_relocate_and_restore(); /* close the SMM memory window and enable normal SMM */ - pci_config_writeb(i440_pci->bdf, I440FX_SMRAM, 0x02 | 0x08); + pci_config_writeb(i440_bdf, I440FX_SMRAM, 0x02 | 0x08); } /* PCI_VENDOR_ID_INTEL && PCI_DEVICE_ID_INTEL_ICH9_LPC */ -void ich9_lpc_apmc_smm_setup(struct pci_device *dev, void *arg) +void ich9_lpc_apmc_smm_setup(int isabdf, int mch_bdf) { - 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) @@ -171,21 +156,40 @@ void ich9_lpc_apmc_smm_setup(struct pci_device *dev, void *arg) 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_setup), - PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_LPC, - ich9_lpc_apmc_smm_setup), +static int SMMISADeviceBDF = -1, SMMPMDeviceBDF = -1; + +void +smm_device_setup(void) +{ + if (!CONFIG_USE_SMM) + return; - PCI_DEVICE_END, -}; + struct pci_device *isapci, *pmpci; + isapci = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3); + pmpci = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441); + if (isapci && pmpci) { + SMMISADeviceBDF = isapci->bdf; + SMMPMDeviceBDF = pmpci->bdf; + return; + } + isapci = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_LPC); + pmpci = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_Q35_MCH); + if (isapci && pmpci) { + SMMISADeviceBDF = isapci->bdf; + SMMPMDeviceBDF = pmpci->bdf; + } +} void smm_setup(void) { - if (!CONFIG_USE_SMM) + if (!CONFIG_USE_SMM || SMMISADeviceBDF < 0) return; dprintf(3, "init smm\n"); - pci_find_init_device(smm_init_tbl, NULL); + u16 device = pci_config_readw(SMMISADeviceBDF, PCI_DEVICE_ID); + if (device == PCI_DEVICE_ID_INTEL_82371AB_3) + piix4_apmc_smm_setup(SMMISADeviceBDF, SMMPMDeviceBDF); + else + ich9_lpc_apmc_smm_setup(SMMISADeviceBDF, SMMPMDeviceBDF); } @@ -314,6 +314,7 @@ extern const u8 pci_irqs[4]; void pci_setup(void); // smm.c +void smm_device_setup(void); void smm_setup(void); // smp.c |