summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/drivers/ipmi/Makefile.inc1
-rw-r--r--src/drivers/ipmi/ipmi_ops.c106
-rw-r--r--src/drivers/ipmi/ipmi_ops.h57
3 files changed, 164 insertions, 0 deletions
diff --git a/src/drivers/ipmi/Makefile.inc b/src/drivers/ipmi/Makefile.inc
index a29c2e2d0e..9d5b3d418f 100644
--- a/src/drivers/ipmi/Makefile.inc
+++ b/src/drivers/ipmi/Makefile.inc
@@ -1,2 +1,3 @@
ramstage-$(CONFIG_IPMI_KCS) += ipmi_kcs.c
ramstage-$(CONFIG_IPMI_KCS) += ipmi_kcs_ops.c
+ramstage-$(CONFIG_IPMI_KCS) += ipmi_ops.c
diff --git a/src/drivers/ipmi/ipmi_ops.c b/src/drivers/ipmi/ipmi_ops.c
new file mode 100644
index 0000000000..784daeb1fb
--- /dev/null
+++ b/src/drivers/ipmi/ipmi_ops.c
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2019 Wiwynn Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of
+ * the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <console/console.h>
+#include "ipmi_ops.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;
+}
diff --git a/src/drivers/ipmi/ipmi_ops.h b/src/drivers/ipmi/ipmi_ops.h
new file mode 100644
index 0000000000..f293075e90
--- /dev/null
+++ b/src/drivers/ipmi/ipmi_ops.h
@@ -0,0 +1,57 @@
+#ifndef __IPMI_OPS_H
+#define __IPMI_OPS_H
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2019 Wiwynn Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of
+ * the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <types.h>
+#include "ipmi_kcs.h"
+#define IPMI_BMC_RESET_WDG_TIMER 0x22
+#define IPMI_BMC_SET_WDG_TIMER 0x24
+#define IPMI_BMC_GET_WDG_TIMER 0x25
+
+/* BMC watchdog timeout action */
+enum ipmi_bmc_timeout_action_type {
+ TIMEOUT_NO_ACTION = 0x00,
+ TIMEOUT_HARD_RESET = 0x01,
+ TIMEOUT_POWER_DOWN = 0x02,
+ TIMEOUT_POWER_CYCLE = 0x03,
+};
+/* 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;
+
+/*
+ * Initialize and start BMC FRB2 watchdog timer with the
+ * provided timer countdown and action values.
+ * Returns CB_SUCCESS on success and CB_ERR if an error occurred
+ */
+enum cb_err ipmi_init_and_start_bmc_wdt(const int port, uint16_t countdown,
+ uint8_t action);
+/* Returns CB_SUCCESS on success and CB_ERR if an error occurred */
+enum cb_err ipmi_stop_bmc_wdt(const int port);
+
+#endif