diff options
author | Aaron Durbin <adurbin@chromium.org> | 2012-12-21 21:21:48 -0600 |
---|---|---|
committer | Ronald G. Minnich <rminnich@gmail.com> | 2013-03-18 17:07:50 +0100 |
commit | 29ffa54969414b833de5c61b507b061f920d650b (patch) | |
tree | e359cc2f27216e9d10e980cce2a2d7c0745729e5 /src/southbridge | |
parent | b7ecf6d83047e70ed5846ac35833a04983318b9c (diff) |
haswell: Use SMM Modules
This commit adds support for using the SMM modules for haswell-based
boards. The SMI handling was also refactored to put the relocation
handler and permanent SMM handler loading in the cpu directory. All
tseg adjustment support is dropped by relying on the SMM module support
to perform the necessary relocations.
Change-Id: I8dd23610772fc4408567d9f4adf339596eac7b1f
Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/2728
Tested-by: build bot (Jenkins)
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
Diffstat (limited to 'src/southbridge')
-rw-r--r-- | src/southbridge/intel/lynxpoint/lpc.c | 52 | ||||
-rw-r--r-- | src/southbridge/intel/lynxpoint/pch.h | 5 | ||||
-rw-r--r-- | src/southbridge/intel/lynxpoint/smi.c | 96 | ||||
-rw-r--r-- | src/southbridge/intel/lynxpoint/smihandler.c | 82 |
4 files changed, 44 insertions, 191 deletions
diff --git a/src/southbridge/intel/lynxpoint/lpc.c b/src/southbridge/intel/lynxpoint/lpc.c index facea7cdd6..eaf926ca7c 100644 --- a/src/southbridge/intel/lynxpoint/lpc.c +++ b/src/southbridge/intel/lynxpoint/lpc.c @@ -29,13 +29,13 @@ #include <arch/ioapic.h> #include <arch/acpi.h> #include <cpu/cpu.h> +#include <cpu/x86/smm.h> #include <elog.h> #include "pch.h" #define NMI_OFF 0 #define ENABLE_ACPI_MODE_IN_COREBOOT 0 -#define TEST_SMM_FLASH_LOCKDOWN 0 typedef struct southbridge_intel_lynxpoint_config config_t; @@ -428,58 +428,22 @@ static void enable_clock_gating(device_t dev) #endif } -#if CONFIG_HAVE_SMI_HANDLER -static void pch_lock_smm(struct device *dev) +static void pch_set_acpi_mode(void) { -#if TEST_SMM_FLASH_LOCKDOWN - u8 reg8; -#endif - +#if CONFIG_HAVE_SMI_HANDLER if (acpi_slp_type != 3) { #if ENABLE_ACPI_MODE_IN_COREBOOT printk(BIOS_DEBUG, "Enabling ACPI via APMC:\n"); - outb(0xe1, 0xb2); // Enable ACPI mode + outb(APM_CNT_ACPI_ENABLE, APM_CNT); printk(BIOS_DEBUG, "done.\n"); #else printk(BIOS_DEBUG, "Disabling ACPI via APMC:\n"); - outb(0x1e, 0xb2); // Disable ACPI mode + outb(APM_CNT_ACPI_DISABLE, APM_CNT); printk(BIOS_DEBUG, "done.\n"); #endif } - - /* Don't allow evil boot loaders, kernels, or - * userspace applications to deceive us: - */ - smm_lock(); - -#if TEST_SMM_FLASH_LOCKDOWN - /* Now try this: */ - printk(BIOS_DEBUG, "Locking BIOS to RO... "); - reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */ - printk(BIOS_DEBUG, " BLE: %s; BWE: %s\n", (reg8&2)?"on":"off", - (reg8&1)?"rw":"ro"); - reg8 &= ~(1 << 0); /* clear BIOSWE */ - pci_write_config8(dev, 0xdc, reg8); - reg8 |= (1 << 1); /* set BLE */ - pci_write_config8(dev, 0xdc, reg8); - printk(BIOS_DEBUG, "ok.\n"); - reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */ - printk(BIOS_DEBUG, " BLE: %s; BWE: %s\n", (reg8&2)?"on":"off", - (reg8&1)?"rw":"ro"); - - printk(BIOS_DEBUG, "Writing:\n"); - *(volatile u8 *)0xfff00000 = 0x00; - printk(BIOS_DEBUG, "Testing:\n"); - reg8 |= (1 << 0); /* set BIOSWE */ - pci_write_config8(dev, 0xdc, reg8); - - reg8 = pci_read_config8(dev, 0xdc); /* BIOS_CNTL */ - printk(BIOS_DEBUG, " BLE: %s; BWE: %s\n", (reg8&2)?"on":"off", - (reg8&1)?"rw":"ro"); - printk(BIOS_DEBUG, "Done.\n"); -#endif +#endif /* CONFIG_HAVE_SMI_HANDLER */ } -#endif static void pch_disable_smm_only_flashing(struct device *dev) { @@ -567,9 +531,7 @@ static void lpc_init(struct device *dev) pch_disable_smm_only_flashing(dev); -#if CONFIG_HAVE_SMI_HANDLER - pch_lock_smm(dev); -#endif + pch_set_acpi_mode(); pch_fixups(dev); } diff --git a/src/southbridge/intel/lynxpoint/pch.h b/src/southbridge/intel/lynxpoint/pch.h index f27ae90eab..6f17d38124 100644 --- a/src/southbridge/intel/lynxpoint/pch.h +++ b/src/southbridge/intel/lynxpoint/pch.h @@ -97,6 +97,11 @@ void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue); void pch_log_state(void); #endif void acpi_create_intel_hpet(acpi_hpet_t * hpet); + +/* These helpers are for performing SMM relocation. */ +void southbridge_smm_init(void); +void southbridge_trigger_smi(void); +void southbridge_clear_smi_status(void); #else void enable_smbus(void); void enable_usb_bar(void); diff --git a/src/southbridge/intel/lynxpoint/smi.c b/src/southbridge/intel/lynxpoint/smi.c index 0bb98813ed..80dea2ce5b 100644 --- a/src/southbridge/intel/lynxpoint/smi.c +++ b/src/southbridge/intel/lynxpoint/smi.c @@ -30,13 +30,6 @@ #include <string.h> #include "pch.h" -#if CONFIG_NORTHBRIDGE_INTEL_HASWELL -#include "northbridge/intel/haswell/haswell.h" -#endif - -extern unsigned char _binary_smm_start; -extern unsigned char _binary_smm_size; - /* While we read PMBASE dynamically in case it changed, let's * initialize it with a sane value */ @@ -232,15 +225,17 @@ static void smi_set_eos(void) outb(reg8, pmbase + SMI_EN); } -extern uint8_t smm_relocation_start, smm_relocation_end; - -static void smm_relocate(void) +void southbridge_smm_init(void) { u32 smi_en; u16 pm1_en; u32 gpe0_en; - printk(BIOS_DEBUG, "Initializing SMM handler..."); +#if CONFIG_ELOG + /* Log events from chipset before clearing */ + pch_log_state(); +#endif + printk(BIOS_DEBUG, "Initializing Southbridge SMI..."); pmbase = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x1f, 0)), PMBASE) & 0xff80; @@ -253,10 +248,6 @@ static void smm_relocate(void) return; } - /* copy the SMM relocation code */ - memcpy((void *)0x38000, &smm_relocation_start, - &smm_relocation_end - &smm_relocation_start); - printk(BIOS_DEBUG, "\n"); dump_smi_status(reset_smi_status()); dump_pm1_status(reset_pm1_status()); @@ -305,7 +296,10 @@ static void smm_relocate(void) smi_en |= EOS | GBL_SMI_EN; outl(smi_en, pmbase + SMI_EN); +} +void southbridge_trigger_smi(void) +{ /** * There are several methods of raising a controlled SMI# via * software, among them: @@ -324,78 +318,18 @@ static void smm_relocate(void) outb(0x00, 0xb2); } -static int smm_handler_copied = 0; - -static void smm_install(void) -{ - device_t dev = dev_find_slot(0, PCI_DEVFN(0, 0)); - u32 smm_base = 0xa0000; - struct ied_header ied = { - .signature = "INTEL RSVD", - .size = IED_SIZE, - .reserved = {0}, - }; - - /* The first CPU running this gets to copy the SMM handler. But not all - * of them. - */ - if (smm_handler_copied) - return; - smm_handler_copied = 1; - - /* enable the SMM memory window */ - pci_write_config8(dev, SMRAM, D_OPEN | G_SMRAME | C_BASE_SEG); - -#if CONFIG_SMM_TSEG - smm_base = pci_read_config32(dev, TSEG) & ~1; -#endif - - /* copy the real SMM handler */ - printk(BIOS_DEBUG, "Installing SMM handler to 0x%08x\n", smm_base); - memcpy((void *)smm_base, &_binary_smm_start, (size_t)&_binary_smm_size); - - /* copy the IED header into place */ - if (CONFIG_SMM_TSEG_SIZE > IED_SIZE) { - /* Top of TSEG region */ - smm_base += CONFIG_SMM_TSEG_SIZE - IED_SIZE; - printk(BIOS_DEBUG, "Installing IED header to 0x%08x\n", - smm_base); - memcpy((void *)smm_base, &ied, sizeof(ied)); - } - wbinvd(); - - /* close the SMM memory window and enable normal SMM */ - pci_write_config8(dev, SMRAM, G_SMRAME | C_BASE_SEG); -} - -void smm_init(void) +void southbridge_clear_smi_status(void) { -#if CONFIG_ELOG - /* Log events from chipset before clearing */ - pch_log_state(); -#endif - - /* Put SMM code to 0xa0000 */ - smm_install(); + /* Clear SMI status */ + reset_smi_status(); - /* Put relocation code to 0x38000 and relocate SMBASE */ - smm_relocate(); + /* Clear PM1 status */ + reset_pm1_status(); - /* We're done. Make sure SMIs can happen! */ + /* Set EOS bit so other SMIs can occur. */ smi_set_eos(); } -void smm_lock(void) -{ - /* LOCK the SMM memory window and enable normal SMM. - * After running this function, only a full reset can - * make the SMM registers writable again. - */ - printk(BIOS_DEBUG, "Locking SMM.\n"); - pci_write_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), SMRAM, - D_LCK | G_SMRAME | C_BASE_SEG); -} - void smm_setup_structures(void *gnvs, void *tcg, void *smi1) { /* diff --git a/src/southbridge/intel/lynxpoint/smihandler.c b/src/southbridge/intel/lynxpoint/smihandler.c index 7c982d129a..48dca2c8fd 100644 --- a/src/southbridge/intel/lynxpoint/smihandler.c +++ b/src/southbridge/intel/lynxpoint/smihandler.c @@ -33,12 +33,6 @@ #include "nvs.h" -/* We are using PCIe accesses for now - * 1. the chipset can do it - * 2. we don't need to worry about how we leave 0xcf8/0xcfc behind - */ -#include <northbridge/intel/haswell/haswell.h> - /* While we read PMBASE dynamically in case it changed, let's * initialize it with a sane value */ @@ -53,28 +47,12 @@ static u8 smm_initialized = 0; /* GNVS needs to be updated by an 0xEA PM Trap (B2) after it has been located * by coreboot. */ -static global_nvs_t *gnvs = (global_nvs_t *)0x0; +static global_nvs_t *gnvs; global_nvs_t *smm_get_gnvs(void) { return gnvs; } -#if CONFIG_SMM_TSEG -static u32 tseg_base = 0; -u32 smi_get_tseg_base(void) -{ - if (!tseg_base) - tseg_base = pci_read_config32(PCI_DEV(0, 0, 0), TSEG) & ~1; - return tseg_base; -} -void tseg_relocate(void **ptr) -{ - /* Adjust pointer with TSEG base */ - if (*ptr && *ptr < (void*)smi_get_tseg_base()) - *ptr = (void *)(((u8*)*ptr) + smi_get_tseg_base()); -} -#endif - /** * @brief read and clear PM1_STS * @return PM1_STS register @@ -290,7 +268,7 @@ static void busmaster_disable_on_bus(int bus) } } -static void southbridge_smi_sleep(unsigned int node, smm_state_save_area_t *state_save) +static void southbridge_smi_sleep(void) { u8 reg8; u32 reg32; @@ -305,8 +283,6 @@ static void southbridge_smi_sleep(unsigned int node, smm_state_save_area_t *stat outb(tmp70, 0x70); outb(tmp72, 0x72); - void (*mainboard_sleep)(u8 slp_typ) = mainboard_smi_sleep; - /* First, disable further SMIs */ reg8 = inb(pmbase + SMI_EN); reg8 &= ~SLP_SMI_EN; @@ -318,9 +294,7 @@ static void southbridge_smi_sleep(unsigned int node, smm_state_save_area_t *stat slp_typ = (reg32 >> 10) & 7; /* Do any mainboard sleep handling */ - tseg_relocate((void **)&mainboard_sleep); - if (mainboard_sleep) - mainboard_sleep(slp_typ-2); + mainboard_smi_sleep(slp_typ-2); #if CONFIG_ELOG_GSMI /* Log S3, S4, and S5 entry */ @@ -390,17 +364,14 @@ static void southbridge_smi_sleep(unsigned int node, smm_state_save_area_t *stat * core in case we are not running on the same core that * initiated the IO transaction. */ -/* FIXME: Confirm Haswell's SMM save state area structure. */ static em64t101_smm_state_save_area_t *smi_apmc_find_state_save(u8 cmd) { em64t101_smm_state_save_area_t *state; - u32 base = smi_get_tseg_base() + 0x8000 + 0x7d00; int node; /* Check all nodes looking for the one that issued the IO */ for (node = 0; node < CONFIG_MAX_CPUS; node++) { - state = (em64t101_smm_state_save_area_t *) - (base - (node * 0x400)); + state = smm_get_save_state(node); /* Check for Synchronous IO (bit0==1) */ if (!(state->io_misc_info & (1 << 0))) @@ -447,11 +418,10 @@ static void southbridge_smi_gsmi(void) } #endif -static void southbridge_smi_apmc(unsigned int node, smm_state_save_area_t *state_save) +static void southbridge_smi_apmc(void) { u32 pmctrl; u8 reg8; - int (*mainboard_apmc)(u8 apmc) = mainboard_smi_apmc; em64t101_smm_state_save_area_t *state; /* Emulate B2 register as the FADT / Linux expects it */ @@ -504,12 +474,10 @@ static void southbridge_smi_apmc(unsigned int node, smm_state_save_area_t *state #endif } - tseg_relocate((void **)&mainboard_apmc); - if (mainboard_apmc) - mainboard_apmc(reg8); + mainboard_smi_apmc(reg8); } -static void southbridge_smi_pm1(unsigned int node, smm_state_save_area_t *state_save) +static void southbridge_smi_pm1(void) { u16 pm1_sts; @@ -530,7 +498,7 @@ static void southbridge_smi_pm1(unsigned int node, smm_state_save_area_t *state_ } } -static void southbridge_smi_gpe0(unsigned int node, smm_state_save_area_t *state_save) +static void southbridge_smi_gpe0(void) { u32 gpe0_sts; @@ -538,27 +506,20 @@ static void southbridge_smi_gpe0(unsigned int node, smm_state_save_area_t *state dump_gpe0_status(gpe0_sts); } -static void southbridge_smi_gpi(unsigned int node, smm_state_save_area_t *state_save) +static void southbridge_smi_gpi(void) { - void (*mainboard_gpi)(u16 gpi_sts) = mainboard_smi_gpi; u16 reg16; reg16 = inw(pmbase + ALT_GP_SMI_STS); outw(reg16, pmbase + ALT_GP_SMI_STS); reg16 &= inw(pmbase + ALT_GP_SMI_EN); - tseg_relocate((void **)&mainboard_gpi); - if (mainboard_gpi) { - mainboard_gpi(reg16); - } else { - if (reg16) - printk(BIOS_DEBUG, "GPI (mask %04x)\n",reg16); - } + mainboard_smi_gpi(reg16); outw(reg16, pmbase + ALT_GP_SMI_STS); } -static void southbridge_smi_mc(unsigned int node, smm_state_save_area_t *state_save) +static void southbridge_smi_mc(void) { u32 reg32; @@ -573,7 +534,7 @@ static void southbridge_smi_mc(unsigned int node, smm_state_save_area_t *state_s -static void southbridge_smi_tco(unsigned int node, smm_state_save_area_t *state_save) +static void southbridge_smi_tco(void) { u32 tco_sts; @@ -610,7 +571,7 @@ static void southbridge_smi_tco(unsigned int node, smm_state_save_area_t *state_ } } -static void southbridge_smi_periodic(unsigned int node, smm_state_save_area_t *state_save) +static void southbridge_smi_periodic(void) { u32 reg32; @@ -623,7 +584,7 @@ static void southbridge_smi_periodic(unsigned int node, smm_state_save_area_t *s printk(BIOS_DEBUG, "Periodic SMI.\n"); } -static void southbridge_smi_monitor(unsigned int node, smm_state_save_area_t *state_save) +static void southbridge_smi_monitor(void) { #define IOTRAP(x) (trap_sts & (1 << x)) u32 trap_sts, trap_cycle; @@ -677,8 +638,7 @@ static void southbridge_smi_monitor(unsigned int node, smm_state_save_area_t *st #undef IOTRAP } -typedef void (*smi_handler_t)(unsigned int node, - smm_state_save_area_t *state_save); +typedef void (*smi_handler_t)(void); static smi_handler_t southbridge_smi[32] = { NULL, // [0] reserved @@ -721,7 +681,7 @@ static smi_handler_t southbridge_smi[32] = { * @param smm_revision revision of the smm state save map */ -void southbridge_smi_handler(unsigned int node, smm_state_save_area_t *state_save) +void southbridge_smi_handler(void) { int i, dump = 0; u32 smi_sts; @@ -738,15 +698,7 @@ void southbridge_smi_handler(unsigned int node, smm_state_save_area_t *state_sav for (i = 0; i < 31; i++) { if (smi_sts & (1 << i)) { if (southbridge_smi[i]) { -#if CONFIG_SMM_TSEG - smi_handler_t handler = (smi_handler_t) - ((u8*)southbridge_smi[i] + - smi_get_tseg_base()); - if (handler) - handler(node, state_save); -#else - southbridge_smi[i](node, state_save); -#endif + southbridge_smi[i](); } else { printk(BIOS_DEBUG, "SMI_STS[%d] occured, but no " "handler available.\n", i); |