Johnny Lin has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/36179 )
Change subject: drivers/ipmi: Add IPMI BMC FRB2 watchdog timer support ......................................................................
drivers/ipmi: Add IPMI BMC FRB2 watchdog timer support
Add a function for initializing and starting FRB2 timer with the provided countdown and action values, and a stop function for stopping the timer.
Tested on OCP Monolake.
Change-Id: Ic91905e5f01b962473b6b3a9616266d2d95b1d6b Signed-off-by: Johnny Lin johnny_lin@wiwynn.com --- M src/drivers/ipmi/ipmi_kcs.c M src/drivers/ipmi/ipmi_kcs.h 2 files changed, 103 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/79/36179/1
diff --git a/src/drivers/ipmi/ipmi_kcs.c b/src/drivers/ipmi/ipmi_kcs.c index 4d1e3e1..d58a9c7 100644 --- a/src/drivers/ipmi/ipmi_kcs.c +++ b/src/drivers/ipmi/ipmi_kcs.c @@ -235,6 +235,85 @@ return ret; }
+int init_and_start_ipmi_bmc_wdt(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)\n", + __func__, ret, rsp.completion_code); + return 1; + } + + /* 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)\n", + __func__, ret, rsp.completion_code); + return 1; + } + + printk(BIOS_INFO, "IPMI BMC watchdog initialized and started.\n"); + return 0; +} + +int stop_ipmi_bmc_wdt(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)\n", + __func__, ret, rsp.resp.completion_code); + return 1; + } + /* 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 0; + } + /* 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)\n", + __func__, ret, resp.completion_code); + return 1; + } + printk(BIOS_DEBUG, "IPMI BMC watchdog is stopped\n"); + + return 0; +} + int ipmi_kcs_message(int port, int netfn, int lun, int cmd, const unsigned char *inmsg, int inlen, unsigned char *outmsg, int outlen) diff --git a/src/drivers/ipmi/ipmi_kcs.h b/src/drivers/ipmi/ipmi_kcs.h index a194dd2..e83d82a 100644 --- a/src/drivers/ipmi/ipmi_kcs.h +++ b/src/drivers/ipmi/ipmi_kcs.h @@ -23,6 +23,9 @@ #define IPMI_BMC_GET_DEVICE_ID 0x01 #define IPMI_IPMI_VERSION_MINOR(x) ((x) >> 4) #define IPMI_IPMI_VERSION_MAJOR(x) ((x) & 0xf) +#define IPMI_BMC_RESET_WDG_TIMER 0x22 +#define IPMI_BMC_SET_WDG_TIMER 0x24 +#define IPMI_BMC_GET_WDG_TIMER 0x25
#define IPMI_NETFN_FIRMWARE 0x08 #define IPMI_NETFN_STORAGE 0x0a @@ -33,6 +36,13 @@ extern int ipmi_kcs_message(int port, int netfn, int lun, int cmd, const unsigned char *inmsg, int inlen, unsigned char *outmsg, int outlen); +/* + * Initialize and start BMC FRB2 watchdog timer with the + * provided timer countdown and action values. + */ +int init_and_start_ipmi_bmc_wdt(int port, uint16_t countdown, + uint8_t action); +int stop_ipmi_bmc_wdt(int port);
struct ipmi_rsp { uint8_t lun; @@ -53,4 +63,18 @@ uint8_t product_id[2]; } __packed;
+/* BMC Watchdog timer */ +struct ipmi_wdt_req { + uint8_t timer_use; + uint8_t timer_actions; + uint8_t pretimeout_interval; + uint8_t timer_use_expiration_flags_clr; + uint16_t initial_countdown_val; +} __packed; + +struct ipmi_wdt_rsp { + struct ipmi_rsp resp; + struct ipmi_wdt_req data; + uint16_t present_countdown_val; +} __packed; #endif