/ src / drivers / ipmi / ipmi_ops.c
ipmi_ops.c
  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  
  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  
 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  
 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  
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  }