| /* SPDX-License-Identifier: GPL-2.0-only */ |
| |
| #include <console/console.h> |
| #include "ipmi_ops.h" |
| #include <string.h> |
| #include <types.h> |
| |
| enum cb_err ipmi_init_and_start_bmc_wdt(const int port, uint16_t countdown, |
| uint8_t action) |
| { |
| int ret; |
| struct ipmi_wdt_req req = {0}; |
| struct ipmi_rsp rsp; |
| printk(BIOS_INFO, "Initializing IPMI BMC watchdog timer\n"); |
| /* BIOS FRB2 */ |
| req.timer_use = 1; |
| req.timer_actions = action; |
| /* clear BIOS FRB2 expiration flag */ |
| req.timer_use_expiration_flags_clr = 2; |
| req.initial_countdown_val = countdown; |
| ret = ipmi_kcs_message(port, IPMI_NETFN_APPLICATION, 0x0, |
| IPMI_BMC_SET_WDG_TIMER, |
| (const unsigned char *) &req, sizeof(req), |
| (unsigned char *) &rsp, sizeof(rsp)); |
| |
| if (ret < sizeof(struct ipmi_rsp) || rsp.completion_code) { |
| printk(BIOS_ERR, "IPMI: %s set wdt command failed " |
| "(ret=%d resp=0x%x), failed to initialize and start " |
| "IPMI BMC watchdog timer\n", __func__, |
| ret, rsp.completion_code); |
| return CB_ERR; |
| } |
| |
| /* Reset command to start timer */ |
| ret = ipmi_kcs_message(port, IPMI_NETFN_APPLICATION, 0x0, |
| IPMI_BMC_RESET_WDG_TIMER, NULL, 0, |
| (unsigned char *) &rsp, sizeof(rsp)); |
| |
| if (ret < sizeof(struct ipmi_rsp) || rsp.completion_code) { |
| printk(BIOS_ERR, "IPMI: %s reset wdt command failed " |
| "(ret=%d resp=0x%x), failed to initialize and start " |
| "IPMI BMC watchdog timer\n", __func__, |
| ret, rsp.completion_code); |
| return CB_ERR; |
| } |
| |
| printk(BIOS_INFO, "IPMI BMC watchdog initialized and started.\n"); |
| return CB_SUCCESS; |
| } |
| |
| enum cb_err ipmi_stop_bmc_wdt(const int port) |
| { |
| int ret; |
| struct ipmi_wdt_req req; |
| struct ipmi_wdt_rsp rsp = {0}; |
| struct ipmi_rsp resp; |
| |
| /* Get current timer first */ |
| ret = ipmi_kcs_message(port, IPMI_NETFN_APPLICATION, 0x0, |
| IPMI_BMC_GET_WDG_TIMER, NULL, 0, |
| (unsigned char *) &rsp, sizeof(rsp)); |
| |
| if (ret < sizeof(struct ipmi_rsp) || rsp.resp.completion_code) { |
| printk(BIOS_ERR, "IPMI: %s get wdt command failed " |
| "(ret=%d resp=0x%x), IPMI BMC watchdog timer may still " |
| "be running\n", __func__, ret, |
| rsp.resp.completion_code); |
| return CB_ERR; |
| } |
| /* If bit 6 in timer_use is 0 then it's already stopped. */ |
| if (!(rsp.data.timer_use & (1 << 6))) { |
| printk(BIOS_DEBUG, "IPMI BMC watchdog is already stopped\n"); |
| return CB_SUCCESS; |
| } |
| /* Set timer stop running by clearing bit 6. */ |
| rsp.data.timer_use &= ~(1 << 6); |
| rsp.data.initial_countdown_val = 0; |
| req = rsp.data; |
| ret = ipmi_kcs_message(port, IPMI_NETFN_APPLICATION, 0x0, |
| IPMI_BMC_SET_WDG_TIMER, |
| (const unsigned char *) &req, sizeof(req), |
| (unsigned char *) &resp, sizeof(resp)); |
| |
| if (ret < sizeof(struct ipmi_rsp) || resp.completion_code) { |
| printk(BIOS_ERR, "IPMI: %s set wdt command stop timer failed " |
| "(ret=%d resp=0x%x), failed to stop IPMI " |
| "BMC watchdog timer\n", __func__, ret, |
| resp.completion_code); |
| return CB_ERR; |
| } |
| printk(BIOS_DEBUG, "IPMI BMC watchdog is stopped\n"); |
| |
| return CB_SUCCESS; |
| } |
| |
| enum cb_err ipmi_get_system_guid(const int port, uint8_t *uuid) |
| { |
| int ret; |
| struct ipmi_get_system_guid_rsp rsp; |
| |
| if (uuid == NULL) { |
| printk(BIOS_ERR, "%s failed, null pointer parameter\n", |
| __func__); |
| return CB_ERR; |
| } |
| |
| ret = ipmi_kcs_message(port, IPMI_NETFN_APPLICATION, 0x0, |
| IPMI_BMC_GET_SYSTEM_GUID, NULL, 0, |
| (unsigned char *) &rsp, sizeof(rsp)); |
| |
| if (ret < sizeof(struct ipmi_rsp) || rsp.resp.completion_code) { |
| printk(BIOS_ERR, "IPMI: %s command failed (ret=%d resp=0x%x)\n", |
| __func__, ret, rsp.resp.completion_code); |
| return CB_ERR; |
| } |
| |
| memcpy(uuid, rsp.data, 16); |
| return CB_SUCCESS; |
| } |
| |
| enum cb_err ipmi_add_sel(const int port, struct sel_event_record *sel) |
| { |
| int ret; |
| struct ipmi_add_sel_rsp rsp; |
| |
| if (sel == NULL) { |
| printk(BIOS_ERR, "%s failed, system evnt log is not present.\n", __func__); |
| return CB_ERR; |
| } |
| |
| ret = ipmi_kcs_message(port, IPMI_NETFN_STORAGE, 0x0, |
| IPMI_ADD_SEL_ENTRY, (const unsigned char *) sel, |
| 16, (unsigned char *) &rsp, sizeof(rsp)); |
| |
| if (ret < sizeof(struct ipmi_rsp) || rsp.resp.completion_code) { |
| printk(BIOS_ERR, "IPMI: %s command failed (ret=%d resp=0x%x)\n", |
| __func__, ret, rsp.resp.completion_code); |
| return CB_ERR; |
| } |
| return CB_SUCCESS; |
| } |