aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/ipmi/ipmi-attn.c14
-rw-r--r--hw/sbe-p9.c63
2 files changed, 74 insertions, 3 deletions
diff --git a/hw/ipmi/ipmi-attn.c b/hw/ipmi/ipmi-attn.c
index 03ea4f9..3a61518 100644
--- a/hw/ipmi/ipmi-attn.c
+++ b/hw/ipmi/ipmi-attn.c
@@ -10,6 +10,7 @@
#include <pel.h>
#include <platform.h>
#include <processor.h>
+#include <sbe-p9.h>
#include <skiboot.h>
#include <stack.h>
#include <timebase.h>
@@ -56,6 +57,16 @@ static void ipmi_log_terminate_event(const char *msg)
void __attribute__((noreturn)) ipmi_terminate(const char *msg)
{
+ /* Log eSEL event */
+ if (ipmi_present())
+ ipmi_log_terminate_event(msg);
+
+ /*
+ * If mpipl is supported then trigger SBE interrupt
+ * to initiate mpipl
+ */
+ p9_sbe_terminate();
+
/* Terminate called before initializing IPMI (early abort) */
if (!ipmi_present()) {
if (platform.cec_reboot)
@@ -63,9 +74,6 @@ void __attribute__((noreturn)) ipmi_terminate(const char *msg)
goto out;
}
- /* Log eSEL event */
- ipmi_log_terminate_event(msg);
-
/* Reboot call */
if (platform.cec_reboot)
platform.cec_reboot();
diff --git a/hw/sbe-p9.c b/hw/sbe-p9.c
index 786351a..a9810a1 100644
--- a/hw/sbe-p9.c
+++ b/hw/sbe-p9.c
@@ -938,3 +938,66 @@ void p9_sbe_init(void)
/* Initiate SBE timeout poller */
opal_add_poller(p9_sbe_timeout_poll, NULL);
}
+
+/* Terminate and initiate MPIPL */
+void p9_sbe_terminate(void)
+{
+ uint32_t primary_chip = -1;
+ int rc;
+ u64 wait_tb;
+ struct proc_chip *chip;
+
+ /* Return if MPIPL is not supported */
+ if (!dt_find_by_path(opal_node, "dump"))
+ return;
+
+ /*
+ * Send S0 interrupt to all SBE. Sequence:
+ * - S0 interrupt on secondary chip SBE
+ * - S0 interrupt on Primary chip SBE
+ */
+ for_each_chip(chip) {
+ if (dt_has_node_property(chip->devnode, "primary", NULL)) {
+ primary_chip = chip->id;
+ continue;
+ }
+
+ rc = xscom_write(chip->id,
+ SBE_CONTROL_REG_RW, SBE_CONTROL_REG_S0);
+ /* Initiate normal reboot */
+ if (rc) {
+ prlog(PR_ERR, "Failed to write S0 interrupt [chip id = %x]\n",
+ chip->id);
+ return;
+ }
+ }
+
+ /* Initiate normal reboot */
+ if (primary_chip == -1) {
+ prlog(PR_ERR, "Primary chip ID not found.\n");
+ return;
+ }
+
+ rc = xscom_write(primary_chip,
+ SBE_CONTROL_REG_RW, SBE_CONTROL_REG_S0);
+ if (rc) {
+ prlog(PR_ERR, "Failed to write S0 interrupt [chip id = %x]\n",
+ primary_chip);
+ return;
+ }
+
+ /* XXX We expect SBE to act on interrupt, quiesce the system and start
+ * MPIPL flow. Currently we do not have a way to detect SBE state.
+ * Hence wait for max time SBE takes to respond and then trigger
+ * normal reboot.
+ */
+ prlog(PR_NOTICE, "Initiated MPIPL, waiting for SBE to respond...\n");
+ wait_tb = mftb() + msecs_to_tb(SBE_CMD_TIMEOUT_MAX);
+ while (mftb() < wait_tb) {
+ cpu_relax();
+ }
+
+ prlog(PR_ERR, "SBE did not respond within timeout period (%d secs).\n",
+ SBE_CMD_TIMEOUT_MAX / 1000);
+ prlog(PR_ERR, "Falling back to normal reboot\n");
+}