xref: /aosp_15_r20/external/coreboot/src/drivers/ipmi/ipmi_ops.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <console/console.h>
4 #include "ipmi_ops.h"
5 #include "ipmi_if.h"
6 #include <string.h>
7 #include <types.h>
8 
ipmi_init_and_start_bmc_wdt(const int port,uint16_t countdown,uint8_t action)9 enum cb_err ipmi_init_and_start_bmc_wdt(const int port, uint16_t countdown,
10 				uint8_t action)
11 {
12 	int ret;
13 	struct ipmi_wdt_req req = {0};
14 	struct ipmi_rsp rsp;
15 	printk(BIOS_INFO, "Initializing IPMI BMC watchdog timer\n");
16 	/* BIOS FRB2 */
17 	req.timer_use = 1;
18 	req.timer_actions = action;
19 	/* clear BIOS FRB2 expiration flag */
20 	req.timer_use_expiration_flags_clr = 2;
21 	req.initial_countdown_val = countdown;
22 	ret = ipmi_message(port, IPMI_NETFN_APPLICATION, 0x0,
23 			IPMI_BMC_SET_WDG_TIMER,
24 			(const unsigned char *)&req, sizeof(req),
25 			(unsigned char *)&rsp, sizeof(rsp));
26 
27 	if (ret < sizeof(struct ipmi_rsp) || rsp.completion_code) {
28 		printk(BIOS_ERR, "IPMI: %s set wdt command failed "
29 			"(ret=%d resp=0x%x), failed to initialize and start "
30 			"IPMI BMC watchdog timer\n", __func__,
31 			ret, rsp.completion_code);
32 		return CB_ERR;
33 	}
34 
35 	/* Reset command to start timer */
36 	ret = ipmi_message(port, IPMI_NETFN_APPLICATION, 0x0,
37 			IPMI_BMC_RESET_WDG_TIMER, NULL, 0,
38 			(unsigned char *)&rsp, sizeof(rsp));
39 
40 	if (ret < sizeof(struct ipmi_rsp) || rsp.completion_code) {
41 		printk(BIOS_ERR, "IPMI: %s reset wdt command failed "
42 			"(ret=%d resp=0x%x), failed to initialize and start "
43 			"IPMI BMC watchdog timer\n", __func__,
44 			ret, rsp.completion_code);
45 		return CB_ERR;
46 	}
47 
48 	printk(BIOS_INFO, "IPMI BMC watchdog initialized and started.\n");
49 	return CB_SUCCESS;
50 }
51 
ipmi_stop_bmc_wdt(const int port)52 enum cb_err ipmi_stop_bmc_wdt(const int port)
53 {
54 	int ret;
55 	struct ipmi_wdt_req req;
56 	struct ipmi_wdt_rsp rsp = {0};
57 	struct ipmi_rsp resp;
58 
59 	/* Get current timer first */
60 	ret = ipmi_message(port, IPMI_NETFN_APPLICATION, 0x0,
61 			IPMI_BMC_GET_WDG_TIMER, NULL, 0,
62 			(unsigned char *)&rsp, sizeof(rsp));
63 
64 	if (ret < sizeof(struct ipmi_rsp) || rsp.resp.completion_code) {
65 		printk(BIOS_ERR, "IPMI: %s get wdt command failed "
66 			"(ret=%d resp=0x%x), IPMI BMC watchdog timer may still "
67 			"be running\n", __func__, ret,
68 			 rsp.resp.completion_code);
69 		return CB_ERR;
70 	}
71 	/* If bit 6 in timer_use is 0 then it's already stopped. */
72 	if (!(rsp.data.timer_use & (1 << 6))) {
73 		printk(BIOS_DEBUG, "IPMI BMC watchdog is already stopped\n");
74 		return CB_SUCCESS;
75 	}
76 	/* Set timer stop running by clearing bit 6. */
77 	rsp.data.timer_use &= ~(1 << 6);
78 	rsp.data.initial_countdown_val = 0;
79 	req = rsp.data;
80 	ret = ipmi_message(port, IPMI_NETFN_APPLICATION, 0x0,
81 			IPMI_BMC_SET_WDG_TIMER,
82 			(const unsigned char *)&req, sizeof(req),
83 			(unsigned char *)&resp, sizeof(resp));
84 
85 	if (ret < sizeof(struct ipmi_rsp) || resp.completion_code) {
86 		printk(BIOS_ERR, "IPMI: %s set wdt command stop timer failed "
87 			"(ret=%d resp=0x%x), failed to stop IPMI "
88 			"BMC watchdog timer\n", __func__, ret,
89 			resp.completion_code);
90 		return CB_ERR;
91 	}
92 	printk(BIOS_DEBUG, "IPMI BMC watchdog is stopped\n");
93 
94 	return CB_SUCCESS;
95 }
96 
ipmi_get_system_guid(const int port,uint8_t * uuid)97 enum cb_err ipmi_get_system_guid(const int port, uint8_t *uuid)
98 {
99 	int ret;
100 	struct ipmi_get_system_guid_rsp rsp;
101 
102 	if (uuid == NULL) {
103 		printk(BIOS_ERR, "%s failed, null pointer parameter\n",
104 			 __func__);
105 		return CB_ERR;
106 	}
107 
108 	ret = ipmi_message(port, IPMI_NETFN_APPLICATION, 0x0,
109 			IPMI_BMC_GET_SYSTEM_GUID, NULL, 0,
110 			(unsigned char *)&rsp, sizeof(rsp));
111 
112 	if (ret < sizeof(struct ipmi_rsp) || rsp.resp.completion_code) {
113 		printk(BIOS_ERR, "IPMI: %s command failed (ret=%d resp=0x%x)\n",
114 			 __func__, ret, rsp.resp.completion_code);
115 		return CB_ERR;
116 	}
117 
118 	memcpy(uuid, rsp.data, 16);
119 	return CB_SUCCESS;
120 }
121 
ipmi_add_sel(const int port,struct sel_event_record * sel)122 enum cb_err ipmi_add_sel(const int port, struct sel_event_record *sel)
123 {
124 	int ret;
125 	struct ipmi_add_sel_rsp rsp;
126 
127 	if (sel == NULL) {
128 		printk(BIOS_ERR, "%s failed, system event log is not present.\n", __func__);
129 		return CB_ERR;
130 	}
131 
132 	ret = ipmi_message(port, IPMI_NETFN_STORAGE, 0x0,
133 			IPMI_ADD_SEL_ENTRY, (const unsigned char *)sel,
134 			16, (unsigned char *)&rsp, sizeof(rsp));
135 
136 	if (ret < sizeof(struct ipmi_rsp) || rsp.resp.completion_code) {
137 		printk(BIOS_ERR, "IPMI: %s command failed (ret=%d resp=0x%x)\n",
138 			 __func__, ret, rsp.resp.completion_code);
139 		return CB_ERR;
140 	}
141 	return CB_SUCCESS;
142 }
143