diff options
Diffstat (limited to 'src/soc')
-rw-r--r-- | src/soc/amd/stoneyridge/smihandler.c | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/src/soc/amd/stoneyridge/smihandler.c b/src/soc/amd/stoneyridge/smihandler.c index a0748fe2fc..7cc8900aa1 100644 --- a/src/soc/amd/stoneyridge/smihandler.c +++ b/src/soc/amd/stoneyridge/smihandler.c @@ -24,6 +24,66 @@ #include <device/pci_def.h> #include <soc/smi.h> #include <soc/southbridge.h> +#include <elog.h> + +/* bits in smm_io_trap */ +#define SMM_IO_TRAP_PORT_OFFSET 16 +#define SMM_IO_TRAP_PORT_ADDRESS_MASK 0xffff +#define SMM_IO_TRAP_RW (1 << 0) +#define SMM_IO_TRAP_VALID (1 << 1) + +static inline u16 get_io_address(u32 info) +{ + return ((info >> SMM_IO_TRAP_PORT_OFFSET) & + SMM_IO_TRAP_PORT_ADDRESS_MASK); +} + +static void *find_save_state(int cmd) +{ + int core; + amd64_smm_state_save_area_t *state; + u32 smm_io_trap; + u8 reg_al; + + /* Check all nodes looking for the one that issued the IO */ + for (core = 0; core < CONFIG_MAX_CPUS; core++) { + state = smm_get_save_state(core); + smm_io_trap = state->smm_io_trap_offset; + /* Check for Valid IO Trap Word (bit1==1) */ + if (!(smm_io_trap & SMM_IO_TRAP_VALID)) + continue; + /* Make sure it was a write (bit0==0) */ + if (smm_io_trap & SMM_IO_TRAP_RW) + continue; + /* Check for APMC IO port */ + if (pm_acpi_smi_cmd_port() != get_io_address(smm_io_trap)) + continue; + /* Check AL against the requested command */ + reg_al = state->rax; + if (reg_al == cmd) + return state; + } + return NULL; +} + +static void southbridge_smi_gsmi(void) +{ + u8 sub_command; + amd64_smm_state_save_area_t *io_smi; + u32 reg_ebx; + + io_smi = find_save_state(ELOG_GSMI_APM_CNT); + if (!io_smi) + return; + /* Command and return value in EAX */ + sub_command = (io_smi->rax >> 8) & 0xff; + + /* Parameter buffer in EBX */ + reg_ebx = io_smi->rbx; + + /* drivers/elog/gsmi.c */ + io_smi->rax = gsmi_exec(sub_command, ®_ebx); +} static void sb_apmc_smi_handler(void) { @@ -41,6 +101,10 @@ static void sb_apmc_smi_handler(void) reg32 &= ~(1 << 0); /* clear SCI_EN */ outl(ACPI_PM1_CNT_BLK, reg32); break; + case ELOG_GSMI_APM_CNT: + if (IS_ENABLED(CONFIG_ELOG_GSMI)) + southbridge_smi_gsmi(); + break; } mainboard_smi_apmc(cmd); @@ -88,6 +152,10 @@ static void sb_slp_typ_handler(void) } if (slp_typ >= ACPI_S3) { + /* Sleep Type Elog S3, S4, and S5 entry */ + if (IS_ENABLED(CONFIG_ELOG_GSMI)) + elog_add_event_byte(ELOG_TYPE_ACPI_ENTER, slp_typ); + wbinvd(); disable_all_smi_status(); |