Angel Pons | 8a3453f | 2020-04-02 23:48:19 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Johnny Lin | f4abe51 | 2019-10-21 09:54:36 +0800 | [diff] [blame] | 2 | |
| 3 | #include <console/console.h> |
| 4 | #include "ipmi_ops.h" |
Sergii Dmytruk | ef7dd5d | 2021-10-22 01:02:32 +0300 | [diff] [blame] | 5 | #include "ipmi_if.h" |
Johnny Lin | 53509cf | 2019-11-14 14:55:04 +0800 | [diff] [blame] | 6 | #include <string.h> |
Elyes HAOUAS | 4f66cb9 | 2019-12-01 13:21:52 +0100 | [diff] [blame] | 7 | #include <types.h> |
Johnny Lin | f4abe51 | 2019-10-21 09:54:36 +0800 | [diff] [blame] | 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; |
Sergii Dmytruk | ef7dd5d | 2021-10-22 01:02:32 +0300 | [diff] [blame] | 22 | ret = ipmi_message(port, IPMI_NETFN_APPLICATION, 0x0, |
Johnny Lin | f4abe51 | 2019-10-21 09:54:36 +0800 | [diff] [blame] | 23 | IPMI_BMC_SET_WDG_TIMER, |
Elyes Haouas | 1ef547e | 2022-11-18 15:05:39 +0100 | [diff] [blame] | 24 | (const unsigned char *)&req, sizeof(req), |
| 25 | (unsigned char *)&rsp, sizeof(rsp)); |
Johnny Lin | f4abe51 | 2019-10-21 09:54:36 +0800 | [diff] [blame] | 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 */ |
Sergii Dmytruk | ef7dd5d | 2021-10-22 01:02:32 +0300 | [diff] [blame] | 36 | ret = ipmi_message(port, IPMI_NETFN_APPLICATION, 0x0, |
Johnny Lin | f4abe51 | 2019-10-21 09:54:36 +0800 | [diff] [blame] | 37 | IPMI_BMC_RESET_WDG_TIMER, NULL, 0, |
Elyes Haouas | 1ef547e | 2022-11-18 15:05:39 +0100 | [diff] [blame] | 38 | (unsigned char *)&rsp, sizeof(rsp)); |
Johnny Lin | f4abe51 | 2019-10-21 09:54:36 +0800 | [diff] [blame] | 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 */ |
Sergii Dmytruk | ef7dd5d | 2021-10-22 01:02:32 +0300 | [diff] [blame] | 60 | ret = ipmi_message(port, IPMI_NETFN_APPLICATION, 0x0, |
Johnny Lin | f4abe51 | 2019-10-21 09:54:36 +0800 | [diff] [blame] | 61 | IPMI_BMC_GET_WDG_TIMER, NULL, 0, |
Elyes Haouas | 1ef547e | 2022-11-18 15:05:39 +0100 | [diff] [blame] | 62 | (unsigned char *)&rsp, sizeof(rsp)); |
Johnny Lin | f4abe51 | 2019-10-21 09:54:36 +0800 | [diff] [blame] | 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; |
Sergii Dmytruk | ef7dd5d | 2021-10-22 01:02:32 +0300 | [diff] [blame] | 80 | ret = ipmi_message(port, IPMI_NETFN_APPLICATION, 0x0, |
Johnny Lin | f4abe51 | 2019-10-21 09:54:36 +0800 | [diff] [blame] | 81 | IPMI_BMC_SET_WDG_TIMER, |
Elyes Haouas | 1ef547e | 2022-11-18 15:05:39 +0100 | [diff] [blame] | 82 | (const unsigned char *)&req, sizeof(req), |
| 83 | (unsigned char *)&resp, sizeof(resp)); |
Johnny Lin | f4abe51 | 2019-10-21 09:54:36 +0800 | [diff] [blame] | 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 | } |
Johnny Lin | 53509cf | 2019-11-14 14:55:04 +0800 | [diff] [blame] | 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 | |
Sergii Dmytruk | ef7dd5d | 2021-10-22 01:02:32 +0300 | [diff] [blame] | 108 | ret = ipmi_message(port, IPMI_NETFN_APPLICATION, 0x0, |
Johnny Lin | 53509cf | 2019-11-14 14:55:04 +0800 | [diff] [blame] | 109 | IPMI_BMC_GET_SYSTEM_GUID, NULL, 0, |
Elyes Haouas | 1ef547e | 2022-11-18 15:05:39 +0100 | [diff] [blame] | 110 | (unsigned char *)&rsp, sizeof(rsp)); |
Johnny Lin | 53509cf | 2019-11-14 14:55:04 +0800 | [diff] [blame] | 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 | } |
Morgan Jang | ea9787a | 2020-04-09 13:50:43 +0800 | [diff] [blame] | 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) { |
Arthur Heymans | 478da72 | 2021-03-25 10:09:23 +0100 | [diff] [blame] | 128 | printk(BIOS_ERR, "%s failed, system event log is not present.\n", __func__); |
Morgan Jang | ea9787a | 2020-04-09 13:50:43 +0800 | [diff] [blame] | 129 | return CB_ERR; |
| 130 | } |
| 131 | |
Sergii Dmytruk | ef7dd5d | 2021-10-22 01:02:32 +0300 | [diff] [blame] | 132 | ret = ipmi_message(port, IPMI_NETFN_STORAGE, 0x0, |
Elyes Haouas | 1ef547e | 2022-11-18 15:05:39 +0100 | [diff] [blame] | 133 | IPMI_ADD_SEL_ENTRY, (const unsigned char *)sel, |
| 134 | 16, (unsigned char *)&rsp, sizeof(rsp)); |
Morgan Jang | ea9787a | 2020-04-09 13:50:43 +0800 | [diff] [blame] | 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 | } |