aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/init.c8
-rw-r--r--hw/ipmi/ipmi-info.c109
-rw-r--r--include/ipmi.h7
-rw-r--r--include/platform.h5
-rw-r--r--platforms/astbmc/astbmc.h1
-rw-r--r--platforms/astbmc/common.c64
-rw-r--r--platforms/astbmc/garrison.c1
-rw-r--r--platforms/astbmc/habanero.c1
-rw-r--r--platforms/astbmc/p8dnu.c1
-rw-r--r--platforms/astbmc/p8dtu.c2
10 files changed, 196 insertions, 3 deletions
diff --git a/core/init.c b/core/init.c
index 955d299..bca12df 100644
--- a/core/init.c
+++ b/core/init.c
@@ -1190,6 +1190,14 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt)
/* Install the OPAL Console handlers */
init_opal_console();
+ /*
+ * Some platforms set a flag to wait for SBE validation to be
+ * performed by the BMC. If this occurs it leaves the SBE in a
+ * bad state and the system will reboot at this point.
+ */
+ if (platform.seeprom_update)
+ platform.seeprom_update();
+
/* Init SLW related stuff, including fastsleep */
slw_init();
diff --git a/hw/ipmi/ipmi-info.c b/hw/ipmi/ipmi-info.c
index 5637003..be2bd44 100644
--- a/hw/ipmi/ipmi-info.c
+++ b/hw/ipmi/ipmi-info.c
@@ -23,7 +23,7 @@
#include <timebase.h>
/*
- * Respones data from IPMI Get device ID command (As defined in
+ * Response data from IPMI Get device ID command (As defined in
* Section 20.1 Get Device ID Command - IPMI standard spec).
*/
struct ipmi_dev_id {
@@ -39,9 +39,27 @@ struct ipmi_dev_id {
};
static struct ipmi_dev_id *ipmi_dev_id;
+/*
+ * Response data from IPMI Chassis Get System Boot Option (As defined in
+ * Section 28.13 Get System Boot Options Command - IPMI standard spec).
+ */
+struct ipmi_sys_boot_opt {
+ uint8_t param_version;
+ uint8_t param_valid;
+ /*
+ * Fields for OEM parameter 0x62. This parameter does not follow
+ * the normal layout and just has a single byte to signal if it
+ * is active or not.
+ */
+ uint8_t flag_set;
+};
+static struct ipmi_sys_boot_opt *ipmi_sys_boot_opt;
+
/* Got response from BMC? */
static bool bmc_info_waiting = false;
static bool bmc_info_valid = false;
+static bool bmc_boot_opt_waiting = false;
+static bool bmc_boot_opt_valid = false;
/* This will free ipmi_dev_id structure */
void ipmi_dt_add_bmc_info(void)
@@ -79,8 +97,14 @@ static void ipmi_get_bmc_info_resp(struct ipmi_msg *msg)
return;
}
- bmc_info_valid = true;
- memcpy(ipmi_dev_id, msg->data, msg->resp_size);
+ /* ipmi_dev_id has optional fields */
+ if (msg->resp_size <= sizeof(struct ipmi_dev_id)) {
+ bmc_info_valid = true;
+ memcpy(ipmi_dev_id, msg->data, msg->resp_size);
+ } else {
+ prlog(PR_WARNING, "IPMI: IPMI_BMC_GET_DEVICE_ID unexpected response size\n");
+ }
+
ipmi_free_msg(msg);
}
@@ -110,3 +134,82 @@ int ipmi_get_bmc_info_request(void)
bmc_info_waiting = true;
return rc;
}
+
+/* This will free ipmi_sys_boot_opt structure */
+int ipmi_chassis_check_sbe_validation(void)
+{
+ int rc = -1;
+
+ while (bmc_boot_opt_waiting)
+ time_wait_ms(10);
+
+ if (!bmc_boot_opt_valid)
+ goto out;
+
+ if ((ipmi_sys_boot_opt->param_valid & 0x8) != 0)
+ goto out;
+ if (ipmi_sys_boot_opt->param_valid != 0x62)
+ goto out;
+
+ rc = ipmi_sys_boot_opt->flag_set;
+
+out:
+ free(ipmi_sys_boot_opt);
+ return rc;
+}
+
+static void ipmi_get_chassis_boot_opt_resp(struct ipmi_msg *msg)
+{
+ bmc_boot_opt_waiting = false;
+
+ if (msg->cc != IPMI_CC_NO_ERROR) {
+ prlog(PR_INFO, "IPMI: IPMI_CHASSIS_GET_BOOT_OPT cmd returned error"
+ " [rc : 0x%x]\n", msg->data[0]);
+ ipmi_free_msg(msg);
+ return;
+ }
+
+ if (msg->resp_size == sizeof(struct ipmi_sys_boot_opt)) {
+ bmc_boot_opt_valid = true;
+ memcpy(ipmi_sys_boot_opt, msg->data, msg->resp_size);
+ } else {
+ prlog(PR_WARNING, "IPMI: IPMI_CHASSIS_GET_BOOT_OPT unexpected response size\n");
+ }
+
+ ipmi_free_msg(msg);
+}
+
+int ipmi_get_chassis_boot_opt_request(void)
+{
+ int rc;
+ struct ipmi_msg *msg;
+ uint8_t req[] = {
+ 0x62, /* OEM parameter (SBE Validation on astbmc) */
+ 0x00, /* no set selector */
+ 0x00, /* no block selector */
+ };
+
+ ipmi_sys_boot_opt = zalloc(sizeof(struct ipmi_sys_boot_opt));
+ assert(ipmi_sys_boot_opt);
+
+ msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE, IPMI_CHASSIS_GET_BOOT_OPT,
+ ipmi_get_chassis_boot_opt_resp, NULL, req,
+ sizeof(req), sizeof(struct ipmi_sys_boot_opt));
+ if (!msg) {
+ free(ipmi_sys_boot_opt);
+ return OPAL_NO_MEM;
+ }
+
+ msg->error = ipmi_get_chassis_boot_opt_resp;
+ prlog(PR_INFO, "IPMI: Requesting IPMI_CHASSIS_GET_BOOT_OPT\n");
+ rc = ipmi_queue_msg(msg);
+ if (rc) {
+ prlog(PR_ERR, "IPMI: Failed to queue IPMI_CHASSIS_GET_BOOT_OPT\n");
+ free(ipmi_sys_boot_opt);
+ ipmi_free_msg(msg);
+ return rc;
+ }
+
+ bmc_boot_opt_waiting = true;
+ return rc;
+}
diff --git a/include/ipmi.h b/include/ipmi.h
index ac6dd90..b67d7e0 100644
--- a/include/ipmi.h
+++ b/include/ipmi.h
@@ -109,6 +109,7 @@
#define IPMI_GET_SEL_TIME IPMI_CODE(IPMI_NETFN_STORAGE, 0x48)
#define IPMI_SET_SEL_TIME IPMI_CODE(IPMI_NETFN_STORAGE, 0x49)
#define IPMI_CHASSIS_CONTROL IPMI_CODE(IPMI_NETFN_CHASSIS, 0x02)
+#define IPMI_CHASSIS_GET_BOOT_OPT IPMI_CODE(IPMI_NETFN_CHASSIS, 0x09)
#define IPMI_BMC_GET_DEVICE_ID IPMI_CODE(IPMI_NETFN_APP, 0x01)
#define IPMI_SET_POWER_STATE IPMI_CODE(IPMI_NETFN_APP, 0x06)
#define IPMI_GET_POWER_STATE IPMI_CODE(IPMI_NETFN_APP, 0x07)
@@ -300,4 +301,10 @@ extern int ipmi_get_bmc_info_request(void);
/* Add BMC firmware info to device tree */
extern void ipmi_dt_add_bmc_info(void);
+/* Get BMC Boot Options info (specifically OEM param 0x62) */
+int ipmi_get_chassis_boot_opt_request(void);
+
+/* Get OEM Boot Option 0x62 for SBE validation flag */
+int ipmi_chassis_check_sbe_validation(void);
+
#endif
diff --git a/include/platform.h b/include/platform.h
index f63c24a..4f8627a 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -232,6 +232,11 @@ struct platform {
* OPAL terminate
*/
void __attribute__((noreturn)) (*terminate)(const char *msg);
+
+ /*
+ * SEEPROM update routine
+ */
+ void (*seeprom_update)(void);
};
extern struct platform __platforms_start;
diff --git a/platforms/astbmc/astbmc.h b/platforms/astbmc/astbmc.h
index fe358b7..c302b60 100644
--- a/platforms/astbmc/astbmc.h
+++ b/platforms/astbmc/astbmc.h
@@ -103,6 +103,7 @@ extern void astbmc_ext_irq_serirq_cpld(unsigned int chip_id);
extern int pnor_init(void);
extern void check_all_slot_table(void);
extern void astbmc_exit(void);
+extern void astbmc_seeprom_update(void);
extern void slot_table_init(const struct slot_table_entry *top_table);
extern void slot_table_get_slot_info(struct phb *phb, struct pci_device * pd);
diff --git a/platforms/astbmc/common.c b/platforms/astbmc/common.c
index faa73e2..76fa25f 100644
--- a/platforms/astbmc/common.c
+++ b/platforms/astbmc/common.c
@@ -26,6 +26,7 @@
#include <bt.h>
#include <errorlog.h>
#include <lpc.h>
+#include <timebase.h>
#include "astbmc.h"
@@ -168,6 +169,69 @@ int64_t astbmc_ipmi_reboot(void)
return ipmi_chassis_control(IPMI_CHASSIS_HARD_RESET);
}
+void astbmc_seeprom_update(void)
+{
+ int flag_set, counter, rc;
+
+ rc = ipmi_get_chassis_boot_opt_request();
+
+ if (rc) {
+ prlog(PR_WARNING, "Failed to check SBE validation flag\n");
+ return;
+ }
+
+ flag_set = ipmi_chassis_check_sbe_validation();
+
+ if (flag_set <= 0) {
+ prlog(PR_DEBUG, "SBE validation flag unset or invalid\n");
+ return;
+ }
+
+ /*
+ * Flag is set, wait until SBE validation is complete and the flag
+ * has been reset.
+ */
+ prlog(PR_WARNING, "SBE validation required, waiting for completion\n");
+ prlog(PR_WARNING, "System will be powered off if validation fails\n");
+ counter = 0;
+
+ while (flag_set > 0) {
+ time_wait_ms(10000);
+ if (++counter % 3 == 0) {
+ /* Let the user know we're alive every 30s */
+ prlog(PR_WARNING, "waiting for completion...\n");
+ }
+ if (counter == 180) {
+ /* This is longer than expected and we have no way of
+ * checking if it's still running. Apologies if you
+ * ever see this message.
+ */
+ prlog(PR_WARNING, "30 minutes has elapsed, this is longer than expected for verification\n");
+ prlog(PR_WARNING, "If no progress is made a power reset of the BMC and Host may be required\n");
+ counter = 0;
+ }
+
+ /* As above, loop anyway if we fail to check the flag */
+ rc = ipmi_get_chassis_boot_opt_request();
+ if (rc == 0)
+ flag_set = ipmi_chassis_check_sbe_validation();
+ else
+ prlog(PR_WARNING, "Failed to check SBE validation flag\n");
+ }
+
+ /*
+ * The SBE validation can (will) leave the SBE in a bad state,
+ * preventing timers from working properly. Reboot so that we
+ * can boot normally with everything intact.
+ */
+ prlog(PR_WARNING, "SBE validation complete, rebooting\n");
+ if (platform.cec_reboot)
+ platform.cec_reboot();
+ else
+ abort();
+ while(true);
+}
+
static void astbmc_fixup_dt_system_id(void)
{
/* Make sure we don't already have one */
diff --git a/platforms/astbmc/garrison.c b/platforms/astbmc/garrison.c
index 5cbe64b..ddd3372 100644
--- a/platforms/astbmc/garrison.c
+++ b/platforms/astbmc/garrison.c
@@ -305,4 +305,5 @@ DECLARE_PLATFORM(garrison) = {
.resource_loaded = flash_resource_loaded,
.exit = ipmi_wdt_final_reset,
.terminate = ipmi_terminate,
+ .seeprom_update = astbmc_seeprom_update,
};
diff --git a/platforms/astbmc/habanero.c b/platforms/astbmc/habanero.c
index 8e11b81..ab01027 100644
--- a/platforms/astbmc/habanero.c
+++ b/platforms/astbmc/habanero.c
@@ -149,4 +149,5 @@ DECLARE_PLATFORM(habanero) = {
.resource_loaded = flash_resource_loaded,
.exit = ipmi_wdt_final_reset,
.terminate = ipmi_terminate,
+ .seeprom_update = astbmc_seeprom_update,
};
diff --git a/platforms/astbmc/p8dnu.c b/platforms/astbmc/p8dnu.c
index 9d42fc4..391aa7a 100644
--- a/platforms/astbmc/p8dnu.c
+++ b/platforms/astbmc/p8dnu.c
@@ -361,4 +361,5 @@ DECLARE_PLATFORM(p8dnu) = {
.resource_loaded = flash_resource_loaded,
.exit = ipmi_wdt_final_reset,
.terminate = ipmi_terminate,
+ .seeprom_update = astbmc_seeprom_update,
};
diff --git a/platforms/astbmc/p8dtu.c b/platforms/astbmc/p8dtu.c
index 69500ea..6f66dc2 100644
--- a/platforms/astbmc/p8dtu.c
+++ b/platforms/astbmc/p8dtu.c
@@ -262,6 +262,7 @@ DECLARE_PLATFORM(p8dtu1u) = {
.resource_loaded = flash_resource_loaded,
.exit = ipmi_wdt_final_reset,
.terminate = ipmi_terminate,
+ .seeprom_update = astbmc_seeprom_update,
};
DECLARE_PLATFORM(p8dtu2u) = {
@@ -279,5 +280,6 @@ DECLARE_PLATFORM(p8dtu2u) = {
.resource_loaded = flash_resource_loaded,
.exit = ipmi_wdt_final_reset,
.terminate = ipmi_terminate,
+ .seeprom_update = astbmc_seeprom_update,
};