aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Jeffery <andrew@aj.id.au>2018-11-01 23:17:25 +1030
committerStewart Smith <stewart@linux.ibm.com>2018-11-02 18:17:00 +1100
commit3f49e5220086d0b247f3ab148199450eee80c78a (patch)
tree26d717851b5b9bfde8fa3794022112db5ce8e421
parentf145626d62274470c620e3bd8a9ac27d2c6a4762 (diff)
downloadskiboot-3f49e5220086d0b247f3ab148199450eee80c78a.zip
skiboot-3f49e5220086d0b247f3ab148199450eee80c78a.tar.gz
skiboot-3f49e5220086d0b247f3ab148199450eee80c78a.tar.bz2
libflash/ipmi-hiomap: Restore window state on window/protocol reset
[ Upstream commit f47fbc97d421231cecff806a3d0bfcd1a27f4a66 ] The initial implementation of ipmi-hiomap left a bit to be desired when it came to event handling: it didn't completely restore the state of the system to what it was before events like a hiomap protocol or window reset take place. The result is the host cannot recover from e.g. the BMC being rebooted underneath it. Take the only step required in the event of window reset, or the final step after performing the handshake in the event of a protocol reset, and re-open the previously active window if there was one. Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Signed-off-by: Stewart Smith <stewart@linux.ibm.com>
-rw-r--r--libflash/ipmi-hiomap.c42
1 files changed, 39 insertions, 3 deletions
diff --git a/libflash/ipmi-hiomap.c b/libflash/ipmi-hiomap.c
index 856d827..a7bd6af 100644
--- a/libflash/ipmi-hiomap.c
+++ b/libflash/ipmi-hiomap.c
@@ -561,6 +561,29 @@ static int lpc_window_write(struct ipmi_hiomap *ctx, uint32_t pos,
return 0;
}
+/* Try to restore the window state */
+static bool ipmi_hiomap_restore_window(struct ipmi_hiomap *ctx)
+{
+ uint64_t size;
+ uint8_t cmd;
+
+ lock(&ctx->lock);
+ if (ctx->window_state == closed_window) {
+ unlock(&ctx->lock);
+ return true;
+ }
+
+ cmd = ctx->window_state == read_window ?
+ HIOMAP_C_CREATE_READ_WINDOW :
+ HIOMAP_C_CREATE_WRITE_WINDOW;
+
+ ctx->window_state = closed_window;
+ unlock(&ctx->lock);
+
+ return hiomap_window_move(ctx, cmd, ctx->current.cur_pos,
+ ctx->current.size, &size);
+}
+
/* Best-effort asynchronous event handling by blocklevel callbacks */
static int ipmi_hiomap_handle_events(struct ipmi_hiomap *ctx)
{
@@ -599,6 +622,8 @@ static int ipmi_hiomap_handle_events(struct ipmi_hiomap *ctx)
}
if (status & HIOMAP_E_PROTOCOL_RESET) {
+ prlog(PR_INFO, "Protocol was reset\n");
+
if (!hiomap_get_info(ctx)) {
prerror("Failure to renegotiate after protocol reset\n");
return FLASH_ERR_DEVICE_GONE;
@@ -609,13 +634,24 @@ static int ipmi_hiomap_handle_events(struct ipmi_hiomap *ctx)
return FLASH_ERR_DEVICE_GONE;
}
- prlog(PR_INFO, "Renegotiated protocol after reset\n");
- return FLASH_ERR_AGAIN;
+ if (!ipmi_hiomap_restore_window(ctx)) {
+ prerror("Failure to restore window state after protocol reset\n");
+ return FLASH_ERR_DEVICE_GONE;
+ }
+
+ prlog(PR_INFO, "Restored window state after protocol reset\n");
+ return 0;
}
if (status & HIOMAP_E_WINDOW_RESET) {
prlog(PR_INFO, "Window was reset\n");
- return FLASH_ERR_AGAIN;
+
+ if (!ipmi_hiomap_restore_window(ctx)) {
+ prerror("Failed to restore previous window parameters after protocol reset\n");
+ return FLASH_ERR_DEVICE_GONE;
+ }
+
+ prlog(PR_INFO, "Restored window state after window reset\n");
}
return 0;