diff options
-rw-r--r-- | hw/fsp/fsp-op-panel.c | 8 | ||||
-rw-r--r-- | hw/fsp/fsp.c | 31 | ||||
-rw-r--r-- | include/fsp.h | 7 |
3 files changed, 45 insertions, 1 deletions
diff --git a/hw/fsp/fsp-op-panel.c b/hw/fsp/fsp-op-panel.c index eb61e8d6..7063cbb3 100644 --- a/hw/fsp/fsp-op-panel.c +++ b/hw/fsp/fsp-op-panel.c @@ -40,7 +40,13 @@ static void fsp_op_display_fatal(uint32_t w0, uint32_t w1) fsp_fillmsg(&op_msg, FSP_CMD_DISP_SRC_DIRECT, 3, 1, w0, w1); - fsp_sync_msg(&op_msg, false); + /* + * A special way to send a message: it doesn't run pollers. + * This means we can call it while in a poller, which we may + * well be in when we're terminating (and thus displaying a *fatal* + * message on the op-panel). + */ + fsp_fatal_msg(&op_msg); } void op_display(enum op_severity sev, enum op_module mod, uint16_t code) diff --git a/hw/fsp/fsp.c b/hw/fsp/fsp.c index 58219a0a..c25e42c8 100644 --- a/hw/fsp/fsp.c +++ b/hw/fsp/fsp.c @@ -1689,6 +1689,7 @@ void fsp_interrupt(void) unlock(&fsp_lock); } + int fsp_sync_msg(struct fsp_msg *msg, bool autofree) { int rc; @@ -1977,6 +1978,36 @@ static void fsp_opal_poll(void *data __unused) } } +int fsp_fatal_msg(struct fsp_msg *msg) +{ + int rc = 0; + + rc = fsp_queue_msg(msg, NULL); + if (rc) + return rc; + + while(fsp_msg_busy(msg)) { + cpu_relax(); + fsp_opal_poll(NULL); + } + + switch(msg->state) { + case fsp_msg_done: + rc = 0; + break; + case fsp_msg_timeout: + rc = -1; /* XXX to improve */ + break; + default: + rc = -1; /* Should not happen... (assert ?) */ + } + + if (msg->resp) + rc = (msg->resp->word1 >> 8) & 0xff; + + return rc; +} + static bool fsp_init_one(const char *compat) { struct dt_node *fsp_node; diff --git a/include/fsp.h b/include/fsp.h index 7ea162db..6142ca39 100644 --- a/include/fsp.h +++ b/include/fsp.h @@ -697,6 +697,13 @@ extern void fsp_cancelmsg(struct fsp_msg *msg); extern int fsp_queue_msg(struct fsp_msg *msg, void (*comp)(struct fsp_msg *msg)) __warn_unused_result; +/* Send a fatal message to FSP + * + * This will *not* run pollers. + * Use only when attempting to get the word out about how we died. + */ +extern int fsp_fatal_msg(struct fsp_msg *msg); + /* Synchronously send a command. If there's a response, the status is * returned as a positive number. A negative result means an error * sending the message. |