[Skiboot] [RFC PATCH 6/6] libflash: add blocklevel_raw_prepare()
Stewart Smith
stewart at linux.ibm.com
Thu Feb 28 17:18:26 AEDT 2019
The logic of a prepare call is to move the window (or at least start the
process of moving the window) so that when a read/write/erase call is
made, we don't have to wait for a IPMI round trip.
For non-hiomap backends, one could use similar logic.
---
Not Signed-off-by yet as I'm totally not convinced
---
core/flash.c | 9 +++++++--
libflash/blocklevel.c | 22 +++++++++++++++++++++
libflash/blocklevel.h | 2 ++
libflash/ipmi-hiomap.c | 44 ++++++++++++++++++++++++++++++++++++++++--
4 files changed, 73 insertions(+), 4 deletions(-)
diff --git a/core/flash.c b/core/flash.c
index 04d99348515e..e267aaa0373d 100644
--- a/core/flash.c
+++ b/core/flash.c
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 IBM Corp.
+/* Copyright 2013-2019 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -239,7 +239,7 @@ static void flash_poll(struct timer *t __unused, void *data, uint64_t now __unus
{
struct flash *flash = data;
uint64_t offset, buf, len;
- int rc;
+ int rc = 0;
offset = flash->async.pos;
buf = flash->async.buf;
@@ -254,6 +254,10 @@ static void flash_poll(struct timer *t __unused, void *data, uint64_t now __unus
len = MIN(flash->async.len, flash->block_size);
prlog(PR_TRACE, "Flash poll op %d len %llu\n", flash->async.op, len);
+ /* If we've done work to prepare, come back later */
+ if (blocklevel_raw_prepare(flash->bl, (flash->async.op!=FLASH_OP_READ), offset, len))
+ goto schedule;
+
switch (flash->async.op) {
case FLASH_OP_READ:
rc = blocklevel_raw_read(flash->bl, offset, (void *)buf, len);
@@ -274,6 +278,7 @@ static void flash_poll(struct timer *t __unused, void *data, uint64_t now __unus
flash->async.pos += len;
flash->async.buf += len;
flash->async.len -= len;
+schedule:
if (!rc && flash->async.len) {
/*
* We want to get called pretty much straight away, just have
diff --git a/libflash/blocklevel.c b/libflash/blocklevel.c
index 5b57d3c6194f..9659c7fd68af 100644
--- a/libflash/blocklevel.c
+++ b/libflash/blocklevel.c
@@ -92,6 +92,28 @@ static int release(struct blocklevel_device *bl)
return rc;
}
+int blocklevel_raw_prepare(struct blocklevel_device *bl, bool rw, uint64_t pos, uint64_t len)
+{
+ int rc = 0;
+
+ FL_DBG("%s: 0x%" PRIx64 "\t0x%" PRIx64 "\n", __func__, pos, len);
+ if (!bl) {
+ errno = EINVAL;
+ return FLASH_ERR_PARM_ERROR;
+ }
+
+ rc = reacquire(bl);
+ if (rc)
+ return rc;
+
+ if (bl->prepare)
+ rc = bl->prepare(bl, rw, pos, len);
+
+ release(bl);
+
+ return rc;
+}
+
int blocklevel_raw_read(struct blocklevel_device *bl, uint64_t pos, void *buf, uint64_t len)
{
int rc;
diff --git a/libflash/blocklevel.h b/libflash/blocklevel.h
index ba42c83d003d..d4ce68cb5752 100644
--- a/libflash/blocklevel.h
+++ b/libflash/blocklevel.h
@@ -42,6 +42,7 @@ struct blocklevel_device {
void *priv;
int (*reacquire)(struct blocklevel_device *bl);
int (*release)(struct blocklevel_device *bl);
+ int (*prepare)(struct blocklevel_device *bl, bool rw, uint64_t pos, uint64_t len);
int (*read)(struct blocklevel_device *bl, uint64_t pos, void *buf, uint64_t len);
int (*write)(struct blocklevel_device *bl, uint64_t pos, const void *buf, uint64_t len);
int (*erase)(struct blocklevel_device *bl, uint64_t pos, uint64_t len);
@@ -57,6 +58,7 @@ struct blocklevel_device {
struct blocklevel_range ecc_prot;
};
+int blocklevel_raw_prepare(struct blocklevel_device *bl, bool rw, uint64_t pos, uint64_t len);
int blocklevel_raw_read(struct blocklevel_device *bl, uint64_t pos, void *buf, uint64_t len);
int blocklevel_read(struct blocklevel_device *bl, uint64_t pos, void *buf, uint64_t len);
int blocklevel_raw_write(struct blocklevel_device *bl, uint64_t pos, const void *buf, uint64_t len);
diff --git a/libflash/ipmi-hiomap.c b/libflash/ipmi-hiomap.c
index 56492fa87067..8bd9d1762ce9 100644
--- a/libflash/ipmi-hiomap.c
+++ b/libflash/ipmi-hiomap.c
@@ -94,8 +94,6 @@ static int hiomap_window_valid(struct ipmi_hiomap *ctx, uint64_t pos,
return FLASH_ERR_AGAIN;
if (ctx->bmc_state & HIOMAP_E_WINDOW_RESET)
return FLASH_ERR_AGAIN;
- if (ctx->window_state == closed_window)
- return FLASH_ERR_PARM_ERROR;
if (pos < ctx->current.cur_pos)
return FLASH_ERR_PARM_ERROR;
if ((pos + len) > (ctx->current.cur_pos + ctx->current.size))
@@ -707,6 +705,47 @@ restore:
return rc;
}
+static int ipmi_hiomap_prepare(struct blocklevel_device *bl, bool rw,
+ uint64_t pos, uint64_t len)
+{
+ struct ipmi_hiomap *ctx;
+ enum lpc_window_state want_state;
+ uint64_t size;
+ uint8_t command = HIOMAP_C_CREATE_READ_WINDOW;
+ bool valid_state;
+ bool is_read;
+ int rc = 0;
+
+ /* LPC is only 32bit */
+ if (pos > UINT_MAX || len > UINT_MAX)
+ return FLASH_ERR_PARM_ERROR;
+
+ if (rw)
+ command = HIOMAP_C_CREATE_WRITE_WINDOW;
+
+ ctx = container_of(bl, struct ipmi_hiomap, bl);
+
+ is_read = (command == HIOMAP_C_CREATE_READ_WINDOW);
+ want_state = is_read ? read_window : write_window;
+
+ lock(&ctx->lock);
+ valid_state = want_state == ctx->window_state;
+ rc = hiomap_window_valid(ctx, pos, len);
+ if (valid_state && !rc) {
+ unlock(&ctx->lock);
+ return 0;
+ }
+ unlock(&ctx->lock);
+
+ rc = ipmi_hiomap_handle_events(ctx);
+ if (rc)
+ return rc;
+
+ rc = hiomap_window_move(ctx, command, pos, len, &size);
+
+ return (rc==0)? 1 : -(rc);
+}
+
static int ipmi_hiomap_read(struct blocklevel_device *bl, uint64_t pos,
void *buf, uint64_t len)
{
@@ -900,6 +939,7 @@ int ipmi_hiomap_init(struct blocklevel_device **bl)
init_lock(&ctx->lock);
+ ctx->bl.prepare = &ipmi_hiomap_prepare;
ctx->bl.read = &ipmi_hiomap_read;
ctx->bl.write = &ipmi_hiomap_write;
ctx->bl.erase = &ipmi_hiomap_erase;
--
2.20.1
More information about the Skiboot
mailing list