nb/intel/gm45: Use common code for SMM in TSEG
This makes i82801ix use the common smm southbridge code to set up smm
relocation and smi handler setup. This is needed in this change for the
the smm relocation code relies on some southbridge functions provided
in the common code. Some of the old code is kept for the Q35 qemu
target.
This also caches the TSEG region and therefore increases MTRR usage a
little in some cases.
Currently SMRR msr's are not set on model_1067x and model_6fx since this needs
the MSRR enable bit and lock set in IA32_FEATURE_CONTROL. This will be handled
properly in the subsequent parallel mp init patchset.
Tested on Thinkpad X200: boots and going to and resuming from S3 still
works fine.
Change-Id: Ic80c65ea42fcf554ea5695772e8828d2f3b00b98
Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-on: https://review.coreboot.org/23419
Reviewed-by: Patrick Rudolph <siro@das-labor.org>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
diff --git a/src/cpu/intel/model_1067x/Makefile.inc b/src/cpu/intel/model_1067x/Makefile.inc
index 3e6cb2c..133c9cf 100644
--- a/src/cpu/intel/model_1067x/Makefile.inc
+++ b/src/cpu/intel/model_1067x/Makefile.inc
@@ -1,5 +1,6 @@
ramstage-y += model_1067x_init.c
subdirs-y += ../../x86/name
subdirs-y += ../common
+subdirs-$(CONFIG_SMM_TSEG) += ../smm/gen1
cpu_microcode_bins += 3rdparty/blobs/cpu/intel/model_1067x/microcode.bin
diff --git a/src/cpu/intel/model_6fx/Makefile.inc b/src/cpu/intel/model_6fx/Makefile.inc
index de6fd8d..a0824fd 100644
--- a/src/cpu/intel/model_6fx/Makefile.inc
+++ b/src/cpu/intel/model_6fx/Makefile.inc
@@ -1,5 +1,6 @@
ramstage-y += model_6fx_init.c
subdirs-y += ../../x86/name
subdirs-y += ../common
+subdirs-$(CONFIG_SMM_TSEG) += ../smm/gen1
cpu_microcode_bins += 3rdparty/blobs/cpu/intel/model_6fx/microcode.bin
diff --git a/src/cpu/intel/smm/gen1/smi.h b/src/cpu/intel/smm/gen1/smi.h
index c328eae..f4cbbc3 100644
--- a/src/cpu/intel/smm/gen1/smi.h
+++ b/src/cpu/intel/smm/gen1/smi.h
@@ -16,5 +16,6 @@
void southbridge_trigger_smi(void);
void southbridge_clear_smi_status(void);
u32 northbridge_get_tseg_base(void);
+u32 northbridge_get_tseg_size(void);
int cpu_get_apic_id_map(int *apic_id_map);
void northbridge_write_smram(u8 smram);
diff --git a/src/cpu/intel/smm/gen1/smmrelocate.c b/src/cpu/intel/smm/gen1/smmrelocate.c
index c50d8a4..b48fe00 100644
--- a/src/cpu/intel/smm/gen1/smmrelocate.c
+++ b/src/cpu/intel/smm/gen1/smmrelocate.c
@@ -147,7 +147,7 @@
/* TSEG base is usually aligned down (to 8MiB). So we can't
derive the TSEG size from the distance to GTT but use the
configuration value instead. */
- const u32 tseg_size = CONFIG_SMM_TSEG_SIZE;
+ const u32 tseg_size = northbridge_get_tseg_size();
/* The SMRAM available to the handler is 4MiB
since the IEDRAM lives at TSEGMB + 4MiB. */
diff --git a/src/northbridge/intel/fsp_sandybridge/northbridge.c b/src/northbridge/intel/fsp_sandybridge/northbridge.c
index 24969d4..b192161 100644
--- a/src/northbridge/intel/fsp_sandybridge/northbridge.c
+++ b/src/northbridge/intel/fsp_sandybridge/northbridge.c
@@ -296,6 +296,11 @@
pci_write_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), SMRAM, smram);
}
+u32 northbridge_get_tseg_size(void)
+{
+ return CONFIG_SMM_TSEG_SIZE;
+}
+
static struct pci_operations intel_pci_ops = {
.set_subsystem = intel_set_subsystem,
};
diff --git a/src/northbridge/intel/gm45/Kconfig b/src/northbridge/intel/gm45/Kconfig
index a45e841..7b4250f 100644
--- a/src/northbridge/intel/gm45/Kconfig
+++ b/src/northbridge/intel/gm45/Kconfig
@@ -30,6 +30,7 @@
select HAVE_VGA_TEXT_FRAMEBUFFER if MAINBOARD_DO_NATIVE_VGA_INIT
select POSTCAR_STAGE
select POSTCAR_CONSOLE
+ select SMM_TSEG
config CBFS_SIZE
hex
diff --git a/src/northbridge/intel/gm45/gm45.h b/src/northbridge/intel/gm45/gm45.h
index 5373e5e..95863d9 100644
--- a/src/northbridge/intel/gm45/gm45.h
+++ b/src/northbridge/intel/gm45/gm45.h
@@ -434,6 +434,7 @@
u32 decode_igd_memory_size(u32 gms);
u32 decode_igd_gtt_size(u32 gsm);
u32 decode_tseg_size(u8 esmramc);
+uintptr_t smm_region_start(void);
void init_iommu(void);
diff --git a/src/northbridge/intel/gm45/northbridge.c b/src/northbridge/intel/gm45/northbridge.c
index 663a9ff..da37e33 100644
--- a/src/northbridge/intel/gm45/northbridge.c
+++ b/src/northbridge/intel/gm45/northbridge.c
@@ -25,6 +25,7 @@
#include <boot/tables.h>
#include <arch/acpi.h>
#include <cbmem.h>
+#include <cpu/intel/smm/gen1/smi.h>
#include "chip.h"
#include "gm45.h"
#include "arch/acpi.h"
@@ -207,6 +208,43 @@
return NULL;
}
+u32 northbridge_get_tseg_base(void)
+{
+ return (u32)smm_region_start();
+}
+
+u32 northbridge_get_tseg_size(void)
+{
+ const u8 esmramc = pci_read_config8(dev_find_slot(0, PCI_DEVFN(0, 0)),
+ D0F0_ESMRAMC);
+ return decode_tseg_size(esmramc) << 10;
+}
+
+void northbridge_write_smram(u8 smram)
+{
+ pci_write_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), D0F0_SMRAM, smram);
+}
+
+/*
+ * Really doesn't belong here but will go away with parallel mp init,
+ * so let it be here for a while...
+ */
+int cpu_get_apic_id_map(int *apic_id_map)
+{
+ unsigned int i;
+
+ /* Logical processors (threads) per core */
+ const struct cpuid_result cpuid1 = cpuid(1);
+ /* Read number of cores. */
+ const char cores = (cpuid1.ebx >> 16) & 0xf;
+
+ /* TODO in parallel MP cpuid(1).ebx */
+ for (i = 0; i < cores; i++)
+ apic_id_map[i] = i;
+
+ return cores;
+}
+
static struct device_operations pci_domain_ops = {
.read_resources = mch_domain_read_resources,
.set_resources = mch_domain_set_resources,
diff --git a/src/northbridge/intel/gm45/ram_calc.c b/src/northbridge/intel/gm45/ram_calc.c
index 011d903..0e95341 100644
--- a/src/northbridge/intel/gm45/ram_calc.c
+++ b/src/northbridge/intel/gm45/ram_calc.c
@@ -83,7 +83,7 @@
}
}
-static uintptr_t smm_region_start(void)
+uintptr_t smm_region_start(void)
{
const pci_devfn_t dev = PCI_DEV(0, 0, 0);
@@ -135,14 +135,12 @@
/* Cache RAM as WB from 0 -> CACHE_TMP_RAMTOP. */
postcar_frame_add_mtrr(&pcf, 0, CACHE_TMP_RAMTOP, MTRR_TYPE_WRBACK);
- /* Cache two separate 4 MiB regions below the top of ram, this
- * satisfies MTRR alignment requirements. If you modify this to
- * cover TSEG, make sure UMA region is not set with WRBACK as it
- * causes hard-to-recover boot failures.
+ /* Cache a 8 MiB region below the top of ram and 8 MiB above top of
+ * ram to cover both cbmem as the TSEG region.
*/
top_of_ram = (uintptr_t)cbmem_top();
- postcar_frame_add_mtrr(&pcf, top_of_ram - 4*MiB, 4*MiB, MTRR_TYPE_WRBACK);
- postcar_frame_add_mtrr(&pcf, top_of_ram - 8*MiB, 4*MiB, MTRR_TYPE_WRBACK);
+ postcar_frame_add_mtrr(&pcf, top_of_ram - 8*MiB, 16*MiB,
+ MTRR_TYPE_WRBACK);
run_postcar_phase(&pcf);
diff --git a/src/northbridge/intel/nehalem/northbridge.c b/src/northbridge/intel/nehalem/northbridge.c
index 6fc61c3..8f55e3c 100644
--- a/src/northbridge/intel/nehalem/northbridge.c
+++ b/src/northbridge/intel/nehalem/northbridge.c
@@ -180,6 +180,11 @@
return pci_read_config32(dev, TSEG) & ~1;
}
+u32 northbridge_get_tseg_size(void)
+{
+ return CONFIG_SMM_TSEG_SIZE;
+}
+
static void mc_set_resources(struct device *dev)
{
/* And call the normal set_resources */
diff --git a/src/northbridge/intel/sandybridge/northbridge.c b/src/northbridge/intel/sandybridge/northbridge.c
index 8c2aaf3..aab3931 100644
--- a/src/northbridge/intel/sandybridge/northbridge.c
+++ b/src/northbridge/intel/sandybridge/northbridge.c
@@ -472,6 +472,11 @@
return northbridge_get_base_reg(dev, TSEG);
}
+u32 northbridge_get_tseg_size(void)
+{
+ return CONFIG_SMM_TSEG_SIZE;
+}
+
void northbridge_write_smram(u8 smram)
{
pci_write_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), SMRAM, smram);
diff --git a/src/southbridge/intel/common/smihandler.c b/src/southbridge/intel/common/smihandler.c
index fb2fe59..0fd8ab0 100644
--- a/src/southbridge/intel/common/smihandler.c
+++ b/src/southbridge/intel/common/smihandler.c
@@ -484,7 +484,11 @@
* @param node
* @param state_save
*/
+#if IS_ENABLED(CONFIG_SMM_TSEG)
void southbridge_smi_handler(void)
+#else
+void cpu_smi_handler(unsigned int node, smm_state_save_area_t *state_save)
+#endif
{
int i, dump = 0;
u32 smi_sts;
diff --git a/src/southbridge/intel/i82801ix/Kconfig b/src/southbridge/intel/i82801ix/Kconfig
index a6debcc..236b43a 100644
--- a/src/southbridge/intel/i82801ix/Kconfig
+++ b/src/southbridge/intel/i82801ix/Kconfig
@@ -26,7 +26,9 @@
select HAVE_SMI_HANDLER
select HAVE_USBDEBUG_OPTIONS
select SOUTHBRIDGE_INTEL_COMMON_GPIO
+ select SOUTHBRIDGE_INTEL_COMMON_SMM
select HAVE_INTEL_FIRMWARE if !BOARD_EMULATION_QEMU_X86_Q35
+ select ACPI_INTEL_HARDWARE_SLEEP_VALUES
if SOUTHBRIDGE_INTEL_I82801IX
diff --git a/src/southbridge/intel/i82801ix/Makefile.inc b/src/southbridge/intel/i82801ix/Makefile.inc
index e563cfc..32d8221 100644
--- a/src/southbridge/intel/i82801ix/Makefile.inc
+++ b/src/southbridge/intel/i82801ix/Makefile.inc
@@ -32,8 +32,10 @@
ramstage-y += ../i82801gx/reset.c
ramstage-y += ../i82801gx/watchdog.c
+ifneq ($(CONFIG_SMM_TSEG),y)
ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smi.c
ramstage-$(CONFIG_HAVE_SMI_HANDLER) += ../../../cpu/x86/smm/smmrelocate.S
+endif
smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c
romstage-y += early_init.c
diff --git a/src/southbridge/intel/i82801ix/smi.c b/src/southbridge/intel/i82801ix/smi.c
index bf3aa6b..2fa0c96 100644
--- a/src/southbridge/intel/i82801ix/smi.c
+++ b/src/southbridge/intel/i82801ix/smi.c
@@ -25,6 +25,7 @@
#include <cpu/x86/cache.h>
#include <cpu/x86/smm.h>
#include <string.h>
+#include <southbridge/intel/common/pmutil.h>
#include "i82801ix.h"
/* I945/GM45 */
@@ -40,199 +41,6 @@
*/
static u16 pmbase = DEFAULT_PMBASE;
-/**
- * @brief read and clear PM1_STS
- * @return PM1_STS register
- */
-static u16 reset_pm1_status(void)
-{
- u16 reg16;
-
- reg16 = inw(pmbase + PM1_STS);
- /* set status bits are cleared by writing 1 to them */
- outw(reg16, pmbase + PM1_STS);
-
- return reg16;
-}
-
-static void dump_pm1_status(u16 pm1_sts)
-{
- printk(BIOS_DEBUG, "PM1_STS: ");
- if (pm1_sts & (1 << 15)) printk(BIOS_DEBUG, "WAK ");
- if (pm1_sts & (1 << 14)) printk(BIOS_DEBUG, "PCIEXPWAK ");
- if (pm1_sts & (1 << 11)) printk(BIOS_DEBUG, "PRBTNOR ");
- if (pm1_sts & (1 << 10)) printk(BIOS_DEBUG, "RTC ");
- if (pm1_sts & (1 << 8)) printk(BIOS_DEBUG, "PWRBTN ");
- if (pm1_sts & (1 << 5)) printk(BIOS_DEBUG, "GBL ");
- if (pm1_sts & (1 << 4)) printk(BIOS_DEBUG, "BM ");
- if (pm1_sts & (1 << 0)) printk(BIOS_DEBUG, "TMROF ");
- printk(BIOS_DEBUG, "\n");
-}
-
-/**
- * @brief read and clear SMI_STS
- * @return SMI_STS register
- */
-static u32 reset_smi_status(void)
-{
- u32 reg32;
-
- reg32 = inl(pmbase + SMI_STS);
- /* set status bits are cleared by writing 1 to them */
- outl(reg32, pmbase + SMI_STS);
-
- return reg32;
-}
-
-static void dump_smi_status(u32 smi_sts)
-{
- printk(BIOS_DEBUG, "SMI_STS: ");
- if (smi_sts & (1 << 27)) printk(BIOS_DEBUG, "GPIO_UNLOCK ");
- if (smi_sts & (1 << 26)) printk(BIOS_DEBUG, "SPI ");
- if (smi_sts & (1 << 21)) printk(BIOS_DEBUG, "MONITOR ");
- if (smi_sts & (1 << 20)) printk(BIOS_DEBUG, "PCI_EXP_SMI ");
- if (smi_sts & (1 << 18)) printk(BIOS_DEBUG, "INTEL_USB2 ");
- if (smi_sts & (1 << 17)) printk(BIOS_DEBUG, "LEGACY_USB2 ");
- if (smi_sts & (1 << 16)) printk(BIOS_DEBUG, "SMBUS_SMI ");
- if (smi_sts & (1 << 15)) printk(BIOS_DEBUG, "SERIRQ_SMI ");
- if (smi_sts & (1 << 14)) printk(BIOS_DEBUG, "PERIODIC ");
- if (smi_sts & (1 << 13)) printk(BIOS_DEBUG, "TCO ");
- if (smi_sts & (1 << 12)) printk(BIOS_DEBUG, "DEVMON ");
- if (smi_sts & (1 << 11)) printk(BIOS_DEBUG, "MCSMI ");
- if (smi_sts & (1 << 10)) printk(BIOS_DEBUG, "GPI ");
- if (smi_sts & (1 << 9)) printk(BIOS_DEBUG, "GPE0 ");
- if (smi_sts & (1 << 8)) printk(BIOS_DEBUG, "PM1 ");
- if (smi_sts & (1 << 6)) printk(BIOS_DEBUG, "SWSMI_TMR ");
- if (smi_sts & (1 << 5)) printk(BIOS_DEBUG, "APM ");
- if (smi_sts & (1 << 4)) printk(BIOS_DEBUG, "SLP_SMI ");
- if (smi_sts & (1 << 3)) printk(BIOS_DEBUG, "LEGACY_USB ");
- if (smi_sts & (1 << 2)) printk(BIOS_DEBUG, "BIOS ");
- printk(BIOS_DEBUG, "\n");
-}
-
-
-/**
- * @brief read and clear GPE0_STS
- * @return GPE0_STS register
- */
-static u64 reset_gpe0_status(void)
-{
- u32 reg_h, reg_l;
-
- reg_l = inl(pmbase + GPE0_STS);
- reg_h = inl(pmbase + GPE0_STS + 4);
- /* set status bits are cleared by writing 1 to them */
- outl(reg_l, pmbase + GPE0_STS);
- outl(reg_h, pmbase + GPE0_STS + 4);
-
- return (((u64)reg_h) << 32) | reg_l;
-}
-
-static void dump_gpe0_status(u64 gpe0_sts)
-{
- int i;
- printk(BIOS_DEBUG, "GPE0_STS: ");
- if (gpe0_sts & (1LL << 32)) printk(BIOS_DEBUG, "USB6 ");
- for (i=31; i>= 16; i--) {
- if (gpe0_sts & (1 << i)) printk(BIOS_DEBUG, "GPIO%d ", (i-16));
- }
- if (gpe0_sts & (1 << 14)) printk(BIOS_DEBUG, "USB4 ");
- if (gpe0_sts & (1 << 13)) printk(BIOS_DEBUG, "PME_B0 ");
- if (gpe0_sts & (1 << 12)) printk(BIOS_DEBUG, "USB3 ");
- if (gpe0_sts & (1 << 11)) printk(BIOS_DEBUG, "PME ");
- if (gpe0_sts & (1 << 10)) printk(BIOS_DEBUG, "EL_SCI/BATLOW ");
- if (gpe0_sts & (1 << 9)) printk(BIOS_DEBUG, "PCI_EXP ");
- if (gpe0_sts & (1 << 8)) printk(BIOS_DEBUG, "RI ");
- if (gpe0_sts & (1 << 7)) printk(BIOS_DEBUG, "SMB_WAK ");
- if (gpe0_sts & (1 << 6)) printk(BIOS_DEBUG, "TCO_SCI ");
- if (gpe0_sts & (1 << 5)) printk(BIOS_DEBUG, "USB5 ");
- if (gpe0_sts & (1 << 4)) printk(BIOS_DEBUG, "USB2 ");
- if (gpe0_sts & (1 << 3)) printk(BIOS_DEBUG, "USB1 ");
- if (gpe0_sts & (1 << 2)) printk(BIOS_DEBUG, "SWGPE ");
- if (gpe0_sts & (1 << 1)) printk(BIOS_DEBUG, "HOT_PLUG ");
- if (gpe0_sts & (1 << 0)) printk(BIOS_DEBUG, "THRM ");
- printk(BIOS_DEBUG, "\n");
-}
-
-
-/**
- * @brief read and clear ALT_GP_SMI_STS
- * @return ALT_GP_SMI_STS register
- */
-static u16 reset_alt_gp_smi_status(void)
-{
- u16 reg16;
-
- reg16 = inl(pmbase + ALT_GP_SMI_STS);
- /* set status bits are cleared by writing 1 to them */
- outl(reg16, pmbase + ALT_GP_SMI_STS);
-
- return reg16;
-}
-
-static void dump_alt_gp_smi_status(u16 alt_gp_smi_sts)
-{
- int i;
- printk(BIOS_DEBUG, "ALT_GP_SMI_STS: ");
- for (i=15; i>= 0; i--) {
- if (alt_gp_smi_sts & (1 << i)) printk(BIOS_DEBUG, "GPI%d ", i);
- }
- printk(BIOS_DEBUG, "\n");
-}
-
-
-
-/**
- * @brief read and clear TCOx_STS
- * @return TCOx_STS registers
- */
-static u32 reset_tco_status(void)
-{
- u32 tcobase = pmbase + 0x60;
- u32 reg32;
-
- reg32 = inl(tcobase + 0x04);
- /* set status bits are cleared by writing 1 to them */
- outl(reg32 & ~(1<<18), tcobase + 0x04); // Don't clear BOOT_STS before SECOND_TO_STS
- if (reg32 & (1 << 18))
- outl(reg32 & (1<<18), tcobase + 0x04); // clear BOOT_STS
-
- return reg32;
-}
-
-
-static void dump_tco_status(u32 tco_sts)
-{
- printk(BIOS_DEBUG, "TCO_STS: ");
- if (tco_sts & (1 << 20)) printk(BIOS_DEBUG, "SMLINK_SLV ");
- if (tco_sts & (1 << 18)) printk(BIOS_DEBUG, "BOOT ");
- if (tco_sts & (1 << 17)) printk(BIOS_DEBUG, "SECOND_TO ");
- if (tco_sts & (1 << 16)) printk(BIOS_DEBUG, "INTRD_DET ");
- if (tco_sts & (1 << 12)) printk(BIOS_DEBUG, "DMISERR ");
- if (tco_sts & (1 << 10)) printk(BIOS_DEBUG, "DMISMI ");
- if (tco_sts & (1 << 9)) printk(BIOS_DEBUG, "DMISCI ");
- if (tco_sts & (1 << 8)) printk(BIOS_DEBUG, "BIOSWR ");
- if (tco_sts & (1 << 7)) printk(BIOS_DEBUG, "NEWCENTURY ");
- if (tco_sts & (1 << 3)) printk(BIOS_DEBUG, "TIMEOUT ");
- if (tco_sts & (1 << 2)) printk(BIOS_DEBUG, "TCO_INT ");
- if (tco_sts & (1 << 1)) printk(BIOS_DEBUG, "SW_TCO ");
- if (tco_sts & (1 << 0)) printk(BIOS_DEBUG, "NMI2SMI ");
- printk(BIOS_DEBUG, "\n");
-}
-
-
-/**
- * @brief Set the EOS bit
- */
-static void smi_set_eos(void)
-{
- u8 reg8;
-
- reg8 = inb(pmbase + SMI_EN);
- reg8 |= EOS;
- outb(reg8, pmbase + SMI_EN);
-}
-
extern uint8_t smm_relocation_start, smm_relocation_end;
static void *default_smm_area = NULL;
@@ -372,14 +180,3 @@
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)
-{
- /* The GDT or coreboot table is going to live here. But a long time
- * after we relocated the GNVS, so this is not troublesome.
- */
- *(u32 *)0x500 = (u32)gnvs;
- *(u32 *)0x504 = (u32)tcg;
- *(u32 *)0x508 = (u32)smi1;
- outb(APM_CNT_GNVS_UPDATE, 0xb2);
-}
diff --git a/src/southbridge/intel/i82801ix/smihandler.c b/src/southbridge/intel/i82801ix/smihandler.c
index 7ad00ed..e60fa9b 100644
--- a/src/southbridge/intel/i82801ix/smihandler.c
+++ b/src/southbridge/intel/i82801ix/smihandler.c
@@ -22,16 +22,11 @@
#include <cpu/x86/smm.h>
#include <device/pci_def.h>
#include <pc80/mc146818rtc.h>
+#include <southbridge/intel/common/pmutil.h>
#include "i82801ix.h"
#include "nvs.h"
-/* While we read PMBASE dynamically in case it changed, let's
- * initialize it with a sane value
- */
-u16 pmbase = DEFAULT_PMBASE;
-u8 smm_initialized = 0;
-
/* GNVS needs to be updated by an 0xEA PM Trap (B2) after it has been located
* by coreboot.
*/
@@ -39,160 +34,6 @@
void *tcg = (void *)0x0;
void *smi1 = (void *)0x0;
-/**
- * @brief read and clear PM1_STS
- * @return PM1_STS register
- */
-static u16 reset_pm1_status(void)
-{
- u16 reg16;
-
- reg16 = inw(pmbase + PM1_STS);
- /* set status bits are cleared by writing 1 to them */
- outw(reg16, pmbase + PM1_STS);
-
- return reg16;
-}
-
-static void dump_pm1_status(u16 pm1_sts)
-{
- printk(BIOS_DEBUG, "PM1_STS: ");
- if (pm1_sts & (1 << 15)) printk(BIOS_DEBUG, "WAK ");
- if (pm1_sts & (1 << 14)) printk(BIOS_DEBUG, "PCIEXPWAK ");
- if (pm1_sts & (1 << 11)) printk(BIOS_DEBUG, "PRBTNOR ");
- if (pm1_sts & (1 << 10)) printk(BIOS_DEBUG, "RTC ");
- if (pm1_sts & (1 << 8)) printk(BIOS_DEBUG, "PWRBTN ");
- if (pm1_sts & (1 << 5)) printk(BIOS_DEBUG, "GBL ");
- if (pm1_sts & (1 << 4)) printk(BIOS_DEBUG, "BM ");
- if (pm1_sts & (1 << 0)) printk(BIOS_DEBUG, "TMROF ");
- printk(BIOS_DEBUG, "\n");
-}
-
-/**
- * @brief read and clear SMI_STS
- * @return SMI_STS register
- */
-static u32 reset_smi_status(void)
-{
- u32 reg32;
-
- reg32 = inl(pmbase + SMI_STS);
- /* set status bits are cleared by writing 1 to them */
- outl(reg32, pmbase + SMI_STS);
-
- return reg32;
-}
-
-static void dump_smi_status(u32 smi_sts)
-{
- printk(BIOS_DEBUG, "SMI_STS: ");
- if (smi_sts & (1 << 27)) printk(BIOS_DEBUG, "GPIO_UNLOCK ");
- if (smi_sts & (1 << 26)) printk(BIOS_DEBUG, "SPI ");
- if (smi_sts & (1 << 21)) printk(BIOS_DEBUG, "MONITOR ");
- if (smi_sts & (1 << 20)) printk(BIOS_DEBUG, "PCI_EXP_SMI ");
- if (smi_sts & (1 << 18)) printk(BIOS_DEBUG, "INTEL_USB2 ");
- if (smi_sts & (1 << 17)) printk(BIOS_DEBUG, "LEGACY_USB2 ");
- if (smi_sts & (1 << 16)) printk(BIOS_DEBUG, "SMBUS_SMI ");
- if (smi_sts & (1 << 15)) printk(BIOS_DEBUG, "SERIRQ_SMI ");
- if (smi_sts & (1 << 14)) printk(BIOS_DEBUG, "PERIODIC ");
- if (smi_sts & (1 << 13)) printk(BIOS_DEBUG, "TCO ");
- if (smi_sts & (1 << 12)) printk(BIOS_DEBUG, "DEVMON ");
- if (smi_sts & (1 << 11)) printk(BIOS_DEBUG, "MCSMI ");
- if (smi_sts & (1 << 10)) printk(BIOS_DEBUG, "GPI ");
- if (smi_sts & (1 << 9)) printk(BIOS_DEBUG, "GPE0 ");
- if (smi_sts & (1 << 8)) printk(BIOS_DEBUG, "PM1 ");
- if (smi_sts & (1 << 6)) printk(BIOS_DEBUG, "SWSMI_TMR ");
- if (smi_sts & (1 << 5)) printk(BIOS_DEBUG, "APM ");
- if (smi_sts & (1 << 4)) printk(BIOS_DEBUG, "SLP_SMI ");
- if (smi_sts & (1 << 3)) printk(BIOS_DEBUG, "LEGACY_USB ");
- if (smi_sts & (1 << 2)) printk(BIOS_DEBUG, "BIOS ");
- printk(BIOS_DEBUG, "\n");
-}
-
-
-/**
- * @brief read and clear GPE0_STS
- * @return GPE0_STS register
- */
-static u64 reset_gpe0_status(void)
-{
- u32 reg_h, reg_l;
-
- reg_l = inl(pmbase + GPE0_STS);
- reg_h = inl(pmbase + GPE0_STS + 4);
- /* set status bits are cleared by writing 1 to them */
- outl(reg_l, pmbase + GPE0_STS);
- outl(reg_h, pmbase + GPE0_STS + 4);
-
- return (((u64)reg_h) << 32) | reg_l;
-}
-
-static void dump_gpe0_status(u64 gpe0_sts)
-{
- int i;
- printk(BIOS_DEBUG, "GPE0_STS: ");
- if (gpe0_sts & (1LL << 32)) printk(BIOS_DEBUG, "USB6 ");
- for (i=31; i>= 16; i--) {
- if (gpe0_sts & (1 << i)) printk(BIOS_DEBUG, "GPIO%d ", (i-16));
- }
- if (gpe0_sts & (1 << 14)) printk(BIOS_DEBUG, "USB4 ");
- if (gpe0_sts & (1 << 13)) printk(BIOS_DEBUG, "PME_B0 ");
- if (gpe0_sts & (1 << 12)) printk(BIOS_DEBUG, "USB3 ");
- if (gpe0_sts & (1 << 11)) printk(BIOS_DEBUG, "PME ");
- if (gpe0_sts & (1 << 10)) printk(BIOS_DEBUG, "EL_SCI/BATLOW ");
- if (gpe0_sts & (1 << 9)) printk(BIOS_DEBUG, "PCI_EXP ");
- if (gpe0_sts & (1 << 8)) printk(BIOS_DEBUG, "RI ");
- if (gpe0_sts & (1 << 7)) printk(BIOS_DEBUG, "SMB_WAK ");
- if (gpe0_sts & (1 << 6)) printk(BIOS_DEBUG, "TCO_SCI ");
- if (gpe0_sts & (1 << 5)) printk(BIOS_DEBUG, "USB5 ");
- if (gpe0_sts & (1 << 4)) printk(BIOS_DEBUG, "USB2 ");
- if (gpe0_sts & (1 << 3)) printk(BIOS_DEBUG, "USB1 ");
- if (gpe0_sts & (1 << 2)) printk(BIOS_DEBUG, "SWGPE ");
- if (gpe0_sts & (1 << 1)) printk(BIOS_DEBUG, "HOT_PLUG ");
- if (gpe0_sts & (1 << 0)) printk(BIOS_DEBUG, "THRM ");
- printk(BIOS_DEBUG, "\n");
-}
-
-
-
-/**
- * @brief read and clear TCOx_STS
- * @return TCOx_STS registers
- */
-static u32 reset_tco_status(void)
-{
- u32 tcobase = pmbase + 0x60;
- u32 reg32;
-
- reg32 = inl(tcobase + 0x04);
- /* set status bits are cleared by writing 1 to them */
- outl(reg32 & ~(1<<18), tcobase + 0x04); // Don't clear BOOT_STS before SECOND_TO_STS
- if (reg32 & (1 << 18))
- outl(reg32 & (1<<18), tcobase + 0x04); // clear BOOT_STS
-
- return reg32;
-}
-
-
-static void dump_tco_status(u32 tco_sts)
-{
- printk(BIOS_DEBUG, "TCO_STS: ");
- if (tco_sts & (1 << 20)) printk(BIOS_DEBUG, "SMLINK_SLV ");
- if (tco_sts & (1 << 18)) printk(BIOS_DEBUG, "BOOT ");
- if (tco_sts & (1 << 17)) printk(BIOS_DEBUG, "SECOND_TO ");
- if (tco_sts & (1 << 16)) printk(BIOS_DEBUG, "INTRD_DET ");
- if (tco_sts & (1 << 12)) printk(BIOS_DEBUG, "DMISERR ");
- if (tco_sts & (1 << 10)) printk(BIOS_DEBUG, "DMISMI ");
- if (tco_sts & (1 << 9)) printk(BIOS_DEBUG, "DMISCI ");
- if (tco_sts & (1 << 8)) printk(BIOS_DEBUG, "BIOSWR ");
- if (tco_sts & (1 << 7)) printk(BIOS_DEBUG, "NEWCENTURY ");
- if (tco_sts & (1 << 3)) printk(BIOS_DEBUG, "TIMEOUT ");
- if (tco_sts & (1 << 2)) printk(BIOS_DEBUG, "TCO_INT ");
- if (tco_sts & (1 << 1)) printk(BIOS_DEBUG, "SW_TCO ");
- if (tco_sts & (1 << 0)) printk(BIOS_DEBUG, "NMI2SMI ");
- printk(BIOS_DEBUG, "\n");
-}
-
int southbridge_io_trap_handler(int smif)
{
switch (smif) {
@@ -210,165 +51,15 @@
return 0;
}
-/**
- * @brief Set the EOS bit
- */
-void southbridge_smi_set_eos(void)
+void southbridge_update_gnvs(u8 apm_cnt, int *smm_done)
{
- u8 reg8;
-
- reg8 = inb(pmbase + SMI_EN);
- reg8 |= EOS;
- outb(reg8, pmbase + SMI_EN);
+ gnvs = *(global_nvs_t **)0x500;
+ tcg = *(void **)0x504;
+ smi1 = *(void **)0x508;
+ *smm_done = 1;
}
-static void southbridge_smi_apmc(unsigned int node, smm_state_save_area_t *state_save)
-{
- u32 pmctrl;
- u8 reg8;
-
- /* Emulate B2 register as the FADT / Linux expects it */
-
- reg8 = inb(APM_CNT);
- if (mainboard_smi_apmc(reg8))
- return;
-
- switch (reg8) {
- case APM_CNT_CST_CONTROL:
- /* Calling this function seems to cause
- * some kind of race condition in Linux
- * and causes a kernel oops
- */
- printk(BIOS_DEBUG, "C-state control\n");
- break;
- case APM_CNT_PST_CONTROL:
- /* Calling this function seems to cause
- * some kind of race condition in Linux
- * and causes a kernel oops
- */
- printk(BIOS_DEBUG, "P-state control\n");
- break;
- case APM_CNT_ACPI_DISABLE:
- pmctrl = inl(pmbase + PM1_CNT);
- pmctrl &= ~SCI_EN;
- outl(pmctrl, pmbase + PM1_CNT);
- printk(BIOS_DEBUG, "SMI#: ACPI disabled.\n");
- break;
- case APM_CNT_ACPI_ENABLE:
- pmctrl = inl(pmbase + PM1_CNT);
- pmctrl |= SCI_EN;
- outl(pmctrl, pmbase + PM1_CNT);
- printk(BIOS_DEBUG, "SMI#: ACPI enabled.\n");
- break;
- case APM_CNT_GNVS_UPDATE:
- if (smm_initialized) {
- printk(BIOS_DEBUG, "SMI#: SMM structures already initialized!\n");
- return;
- }
- gnvs = *(global_nvs_t **)0x500;
- tcg = *(void **)0x504;
- smi1 = *(void **)0x508;
- smm_initialized = 1;
- printk(BIOS_DEBUG, "SMI#: Setting up structures to %p, %p, %p\n", gnvs, tcg, smi1);
- break;
- default:
- printk(BIOS_DEBUG, "SMI#: Unknown function APM_CNT=%02x\n", reg8);
- }
-}
-
-static void southbridge_smi_pm1(unsigned int node, smm_state_save_area_t *state_save)
-{
- u16 pm1_sts;
- volatile u8 cmos_status;
-
- pm1_sts = reset_pm1_status();
- dump_pm1_status(pm1_sts);
-
- /* While OSPM is not active, poweroff immediately
- * on a power button event.
- */
- if (pm1_sts & PWRBTN_STS) {
- // power button pressed
- u32 reg32;
- reg32 = (7 << 10) | (1 << 13);
- outl(reg32, pmbase + PM1_CNT);
- }
-
- if (pm1_sts & RTC_STS) {
- /* read RTC status register to disable the interrupt */
- cmos_status = cmos_read(RTC_REG_C);
- printk(BIOS_DEBUG, "RTC IRQ status: %02X\n", cmos_status);
- }
-}
-
-static void southbridge_smi_gpe0(unsigned int node, smm_state_save_area_t *state_save)
-{
- u32 gpe0_sts;
-
- gpe0_sts = reset_gpe0_status();
- dump_gpe0_status(gpe0_sts);
-}
-
-static void southbridge_smi_gpi(unsigned int node, smm_state_save_area_t *state_save)
-{
- u16 reg16;
- reg16 = inw(pmbase + ALT_GP_SMI_STS);
- outl(reg16, pmbase + ALT_GP_SMI_STS);
-
- reg16 &= inw(pmbase + ALT_GP_SMI_EN);
-
- mainboard_smi_gpi(reg16);
-
- if (reg16)
- printk(BIOS_DEBUG, "GPI (mask %04x)\n",reg16);
-}
-
-
-static void southbridge_smi_tco(unsigned int node, smm_state_save_area_t *state_save)
-{
- u32 tco_sts;
-
- tco_sts = reset_tco_status();
-
- /* Any TCO event? */
- if (!tco_sts)
- return;
-
- if (tco_sts & (1 << 8)) { // BIOSWR
- u8 bios_cntl;
-
- bios_cntl = pci_read_config16(PCI_DEV(0, 0x1f, 0), 0xdc);
-
- if (bios_cntl & 1) {
- /* BWE is RW, so the SMI was caused by a
- * write to BWE, not by a write to the BIOS
- */
-
- /* This is the place where we notice someone
- * is trying to tinker with the BIOS. We are
- * trying to be nice and just ignore it. A more
- * resolute answer would be to power down the
- * box.
- */
- printk(BIOS_DEBUG, "Switching back to RO\n");
- pci_write_config32(PCI_DEV(0, 0x1f, 0), 0xdc, (bios_cntl & ~1));
- } /* No else for now? */
- } else if (tco_sts & (1 << 3)) { /* TIMEOUT */
- /* Handle TCO timeout */
- printk(BIOS_DEBUG, "TCO Timeout.\n");
- } else {
- dump_tco_status(tco_sts);
- }
-}
-
-#if DEBUG_PERIODIC_SMIS
-static void southbridge_smi_periodic(unsigned int node, smm_state_save_area_t *state_save)
-{
- printk(BIOS_DEBUG, "Periodic SMI.\n");
-}
-#endif
-
-static void southbridge_smi_monitor(unsigned int node, smm_state_save_area_t *state_save)
+void southbridge_smi_monitor(void)
{
#define IOTRAP(x) (trap_sts & (1 << x))
u32 trap_sts, trap_cycle;
@@ -422,104 +113,6 @@
#undef IOTRAP
}
-typedef void (*smi_handler_t)(unsigned int node,
- smm_state_save_area_t *state_save);
-
-smi_handler_t southbridge_smi[32] = {
- NULL, // [0] reserved
- NULL, // [1] reserved
- NULL, // [2] BIOS_STS
- NULL, // [3] LEGACY_USB_STS
- NULL, // [4] SLP_SMI_STS
- southbridge_smi_apmc, // [5] APM_STS
- NULL, // [6] SWSMI_TMR_STS
- NULL, // [7] reserved
- southbridge_smi_pm1, // [8] PM1_STS
- southbridge_smi_gpe0, // [9] GPE0_STS
- southbridge_smi_gpi, // [10] GPI_STS
- NULL, // [11] MCSMI_STS
- NULL, // [12] DEVMON_STS
- southbridge_smi_tco, // [13] TCO_STS
-#if DEBUG_PERIODIC_SMIS
- southbridge_smi_periodic, // [14] PERIODIC_STS
-#else
- NULL, // [14] PERIODIC_STS
-#endif
- NULL, // [15] SERIRQ_SMI_STS
- NULL, // [16] SMBUS_SMI_STS
- NULL, // [17] LEGACY_USB2_STS
- NULL, // [18] INTEL_USB2_STS
- NULL, // [19] reserved
- NULL, // [20] PCI_EXP_SMI_STS
- southbridge_smi_monitor, // [21] MONITOR_STS
- NULL, // [22] reserved
- NULL, // [23] reserved
- NULL, // [24] reserved
- NULL, // [25] reserved
- NULL, // [26] SPI_STS
- NULL, // [27] reserved
- NULL, // [28] reserved
- NULL, // [29] reserved
- NULL, // [30] reserved
- NULL // [31] reserved
-};
-
-static u32 southbrigde_smi_mask_events(u32 smi_sts)
+void southbridge_finalize_all(void)
{
- /* Clear all disabled bits in SMI_EN but the reserved ones. */
- smi_sts &= inl(pmbase + SMI_EN) | 0xf7f99700;
-
- /* Check if SCI is enabled. */
- if (inl(pmbase + PM1_CNT) & SCI_EN)
- /* Clear PM1, GPE. */
- smi_sts &= ~((1 << 8) | (1 << 9));
-
- /* Check if SPI generates SMI. */
- if (!(RCBA16(0x3806) & (1 << 15)) &&
- !(RCBA16(0x3891) & (1 << 15)))
- /* Clear SPI. */
- smi_sts &= ~(1 << 26);
-
- return smi_sts;
-}
-
-/**
- * @brief Interrupt handler for SMI#
- *
- * @param node
- * @param *state_save
- */
-void southbridge_smi_handler(unsigned int node, smm_state_save_area_t *state_save)
-{
- int i, dump = 0;
- u32 smi_sts;
-
- /* Update global variable pmbase */
- pmbase = pci_read_config16(PCI_DEV(0, 0x1f, 0), D31F0_PMBASE) & 0xfffc;
-
- /* We need to clear the SMI status registers, or we won't see what's
- * happening in the following calls.
- */
- smi_sts = reset_smi_status();
-
- /* Filter all non-enabled SMI events */
- smi_sts = southbrigde_smi_mask_events(smi_sts);
-
- /* Call SMI sub handler for each of the status bits */
- for (i = 0; i < 31; i++) {
- if (smi_sts & (1 << i)) {
- if (southbridge_smi[i])
- southbridge_smi[i](node, state_save);
- else {
- printk(BIOS_DEBUG, "SMI_STS[%d] occurred, but no "
- "handler available.\n", i);
- dump = 1;
- }
- }
- }
-
- if (dump) {
- dump_smi_status(smi_sts);
- }
-
}