1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <console/console.h>
7 #define GSMI_RET_SUCCESS 0x00
8 #define GSMI_RET_INVALID_PARAMETER 0x82
9 #define GSMI_RET_UNSUPPORTED 0x83
11 #define GSMI_CMD_SET_EVENT_LOG 0x08
12 #define GSMI_CMD_CLEAR_EVENT_LOG 0x09
13 #define GSMI_CMD_LOG_S0IX_SUSPEND 0x0a
14 #define GSMI_CMD_LOG_S0IX_RESUME 0x0b
15 #define GSMI_CMD_HANDSHAKE_TYPE 0xc1
17 #define GSMI_HANDSHAKE_NONE 0x7f
18 #define GSMI_LOG_ENTRY_TYPE_KERNEL 0xDEAD
20 struct gsmi_set_eventlog_param
{
26 struct gsmi_set_eventlog_type1
{
31 struct gsmi_clear_eventlog_param
{
36 void __weak
elog_gsmi_cb_platform_log_wake_source(void)
38 /* Default weak implementation, does nothing. */
41 void __weak
elog_gsmi_cb_mainboard_log_wake_source(void)
43 /* Default weak implementation, does nothing. */
46 /* Param is usually EBX, ret in EAX */
47 u32
gsmi_exec(u8 command
, u32
*param
)
49 struct gsmi_set_eventlog_param
*sel
;
50 struct gsmi_set_eventlog_type1
*type1
;
51 struct gsmi_clear_eventlog_param
*cel
;
52 u32 ret
= GSMI_RET_UNSUPPORTED
;
55 case GSMI_CMD_HANDSHAKE_TYPE
:
56 /* Used by kernel to verify basic SMI functionality */
57 printk(BIOS_DEBUG
, "GSMI Handshake\n");
58 ret
= GSMI_HANDSHAKE_NONE
;
61 case GSMI_CMD_SET_EVENT_LOG
:
62 /* Look for a type1 event */
63 sel
= (struct gsmi_set_eventlog_param
*)(uintptr_t)(*param
);
67 /* Make sure the input is usable */
68 if (sel
->type
!= 1 && sel
->data_ptr
!= 0 &&
69 sel
->data_len
!= sizeof(struct gsmi_set_eventlog_type1
))
72 /* Event structure within the data buffer */
73 type1
= (struct gsmi_set_eventlog_type1
*)(uintptr_t)(sel
->data_ptr
);
77 printk(BIOS_DEBUG
, "GSMI Set Event Log "
78 "(type=0x%x instance=0x%x)\n",
79 type1
->type
, type1
->instance
);
81 if (type1
->type
== GSMI_LOG_ENTRY_TYPE_KERNEL
) {
82 /* Special case for linux kernel shutdown reason */
83 elog_add_event_dword(ELOG_TYPE_OS_EVENT
,
86 /* Add other events that may be used for testing */
87 elog_add_event_dword(type1
->type
, type1
->instance
);
89 ret
= GSMI_RET_SUCCESS
;
92 case GSMI_CMD_CLEAR_EVENT_LOG
:
93 /* Get parameter buffer even though we don't use it */
94 cel
= (struct gsmi_clear_eventlog_param
*)(uintptr_t)(*param
);
98 printk(BIOS_DEBUG
, "GSMI Clear Event Log (%u%% type=%u)\n",
99 cel
->percentage
, cel
->data_type
);
101 if (elog_clear() == 0)
102 ret
= GSMI_RET_SUCCESS
;
105 case GSMI_CMD_LOG_S0IX_SUSPEND
:
106 case GSMI_CMD_LOG_S0IX_RESUME
:
107 ret
= GSMI_RET_SUCCESS
;
109 if (command
== GSMI_CMD_LOG_S0IX_SUSPEND
)
110 elog_add_event(ELOG_TYPE_S0IX_ENTER
);
112 elog_add_event(ELOG_TYPE_S0IX_EXIT
);
113 elog_gsmi_cb_platform_log_wake_source();
114 elog_gsmi_cb_mainboard_log_wake_source();
119 printk(BIOS_DEBUG
, "GSMI Unknown: 0x%02x\n", command
);