xref: /aosp_15_r20/external/coreboot/src/soc/amd/common/block/cpu/smm/smi_apmc.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <acpi/acpi.h>
4 #include <amdblocks/acpi.h>
5 #include <amdblocks/psp.h>
6 #include <amdblocks/smm.h>
7 #include <arch/io.h>
8 #include <cpu/amd/amd64_save_state.h>
9 #include <cpu/x86/smm.h>
10 #include <elog.h>
11 #include <smmstore.h>
12 #include <types.h>
13 
14 /* bits in smm_io_trap   */
15 #define SMM_IO_TRAP_PORT_OFFSET		16
16 #define SMM_IO_TRAP_PORT_ADDRESS_MASK	0xffff
17 #define SMM_IO_TRAP_RW			(1 << 0)
18 #define SMM_IO_TRAP_VALID		(1 << 1)
19 
get_io_address(u32 info)20 static inline u16 get_io_address(u32 info)
21 {
22 	return ((info >> SMM_IO_TRAP_PORT_OFFSET) &
23 		SMM_IO_TRAP_PORT_ADDRESS_MASK);
24 }
25 
find_save_state(int cmd)26 static void *find_save_state(int cmd)
27 {
28 	unsigned int core;
29 	amd64_smm_state_save_area_t *state;
30 	u32 smm_io_trap;
31 	u8 reg_al;
32 
33 	/* Check all nodes looking for the one that issued the IO */
34 	for (core = 0; core < CONFIG_MAX_CPUS; core++) {
35 		state = smm_get_save_state(core);
36 		smm_io_trap = state->smm_io_trap_offset;
37 		/* Check for Valid IO Trap Word (bit1==1) */
38 		if (!(smm_io_trap & SMM_IO_TRAP_VALID))
39 			continue;
40 		/* Make sure it was a write (bit0==0) */
41 		if (smm_io_trap & SMM_IO_TRAP_RW)
42 			continue;
43 		/* Check for APMC IO port */
44 		if (pm_acpi_smi_cmd_port() != get_io_address(smm_io_trap))
45 			continue;
46 		/* Check AL against the requested command */
47 		reg_al = state->rax;
48 		if (reg_al == cmd)
49 			return state;
50 	}
51 	return NULL;
52 }
53 
handle_smi_gsmi(void)54 void handle_smi_gsmi(void)
55 {
56 	u8 sub_command;
57 	amd64_smm_state_save_area_t *io_smi;
58 	u32 reg_ebx;
59 
60 	io_smi = find_save_state(APM_CNT_ELOG_GSMI);
61 	if (!io_smi)
62 		return;
63 	/* Command and return value in EAX */
64 	sub_command = (io_smi->rax >> 8) & 0xff;
65 
66 	/* Parameter buffer in EBX */
67 	reg_ebx = io_smi->rbx;
68 
69 	/* drivers/elog/gsmi.c */
70 	io_smi->rax = gsmi_exec(sub_command, &reg_ebx);
71 }
72 
handle_smi_store(void)73 void handle_smi_store(void)
74 {
75 	u8 sub_command;
76 	amd64_smm_state_save_area_t *io_smi;
77 	u32 reg_ebx;
78 
79 	io_smi = find_save_state(APM_CNT_SMMSTORE);
80 	if (!io_smi)
81 		return;
82 	/* Command and return value in EAX */
83 	sub_command = (io_smi->rax >> 8) & 0xff;
84 
85 	/* Parameter buffer in EBX */
86 	reg_ebx = io_smi->rbx;
87 
88 	/* drivers/smmstore/smi.c */
89 	io_smi->rax = smmstore_exec(sub_command, (void *)(uintptr_t)reg_ebx);
90 }
91 
fch_apmc_smi_handler(void)92 void fch_apmc_smi_handler(void)
93 {
94 	const uint8_t cmd = apm_get_apmc();
95 
96 	switch (cmd) {
97 	case APM_CNT_ACPI_ENABLE:
98 		acpi_clear_pm_gpe_status();
99 		acpi_enable_sci();
100 		break;
101 	case APM_CNT_ACPI_DISABLE:
102 		acpi_disable_sci();
103 		break;
104 	case APM_CNT_ELOG_GSMI:
105 		if (CONFIG(ELOG_GSMI))
106 			handle_smi_gsmi();
107 	break;
108 	case APM_CNT_SMMSTORE:
109 		if (CONFIG(SMMSTORE))
110 			handle_smi_store();
111 	break;
112 	case APM_CNT_SMMINFO:
113 		psp_notify_smm();
114 		break;
115 	}
116 
117 	mainboard_smi_apmc(cmd);
118 }
119