aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Stanley <joel@jms.id.au>2015-01-29 14:47:54 +1030
committerJeremy Kerr <jk@ozlabs.org>2015-03-04 16:01:23 +0800
commitd6fb45e3b29df30e30ac400cfb8b030719207213 (patch)
treed3072e29af542d8815d7a7fa33e179ac5d207bbc
parentf51aeaa4fa5074f747684643bf6ebff3e0884f67 (diff)
downloadskiboot-d6fb45e3b29df30e30ac400cfb8b030719207213.zip
skiboot-d6fb45e3b29df30e30ac400cfb8b030719207213.tar.gz
skiboot-d6fb45e3b29df30e30ac400cfb8b030719207213.tar.bz2
hw/ipmi: Disable flash access when requested
BMC based systems contain a PNOR to provide flash storage. The host normally has exclusive access to the PNOR, however the BMC may use IPMI to request access to perform functions such as update the firmware. Indicate to users of the flash that the device is busy by taking the lock, and setting a per-flash busy flag, which causes flash operations to return OPAL_BUSY. Minor changes from Jeremy Kerr Signed-off-by: Joel Stanley <joel@jms.id.au> Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
-rw-r--r--core/flash.c58
-rw-r--r--hw/ipmi/ipmi-sel.c36
-rw-r--r--include/ipmi.h5
-rw-r--r--include/skiboot.h3
4 files changed, 94 insertions, 8 deletions
diff --git a/core/flash.c b/core/flash.c
index 3a06d1d..9912add 100644
--- a/core/flash.c
+++ b/core/flash.c
@@ -26,6 +26,7 @@
struct flash {
bool registered;
+ bool busy;
struct flash_chip *chip;
uint32_t size;
uint32_t block_size;
@@ -42,12 +43,39 @@ static struct lock flash_lock;
static struct flash *nvram_flash;
static u32 nvram_offset, nvram_size;
+bool flash_reserve(void)
+{
+ bool rc = false;
+
+ if (!try_lock(&flash_lock))
+ return false;
+
+ if (!system_flash->busy) {
+ system_flash->busy = true;
+ rc = true;
+ }
+ unlock(&flash_lock);
+
+ return rc;
+}
+
+void flash_release(void)
+{
+ lock(&flash_lock);
+ system_flash->busy = false;
+ unlock(&flash_lock);
+}
+
static int flash_nvram_info(uint32_t *total_size)
{
- int rc = OPAL_HARDWARE;
+ int rc;
lock(&flash_lock);
- if (nvram_flash) {
+ if (!nvram_flash) {
+ rc = OPAL_HARDWARE;
+ } else if (nvram_flash->busy) {
+ rc = OPAL_BUSY;
+ } else {
*total_size = nvram_size;
rc = OPAL_SUCCESS;
}
@@ -60,13 +88,19 @@ static int flash_nvram_start_read(void *dst, uint32_t src, uint32_t len)
{
int rc;
- lock(&flash_lock);
+ if (!try_lock(&flash_lock))
+ return OPAL_BUSY;
if (!nvram_flash) {
rc = OPAL_HARDWARE;
goto out;
}
+ if (nvram_flash->busy) {
+ rc = OPAL_BUSY;
+ goto out;
+ }
+
if ((src + len) > nvram_size) {
prerror("FLASH_NVRAM: read out of bound (0x%x,0x%x)\n",
src, len);
@@ -87,7 +121,13 @@ static int flash_nvram_write(uint32_t dst, void *src, uint32_t len)
{
int rc;
- lock(&flash_lock);
+ if (try_lock(&flash_lock))
+ return OPAL_BUSY;
+
+ if (nvram_flash->busy) {
+ rc = OPAL_BUSY;
+ goto out;
+ }
/* TODO: When we have async jobs for PRD, turn this into one */
@@ -235,6 +275,7 @@ int flash_register(struct flash_chip *chip, bool is_system_flash)
flash = &flashes[i];
flash->registered = true;
+ flash->busy = false;
flash->chip = chip;
flash->size = size;
flash->block_size = block_size;
@@ -286,6 +327,12 @@ static int64_t opal_flash_op(enum flash_op op, uint64_t id, uint64_t offset,
return OPAL_BUSY;
flash = &flashes[id];
+
+ if (flash->busy) {
+ rc = OPAL_BUSY;
+ goto err;
+ }
+
if (!flash->registered) {
rc = OPAL_PARAMETER;
goto err;
@@ -493,6 +540,9 @@ bool flash_load_resource(enum resource_id id, uint32_t subid,
flash = system_flash;
+ if (flash->busy)
+ goto out_unlock;
+
for (i = 0, name = NULL; i < ARRAY_SIZE(part_name_map); i++) {
if (part_name_map[i].id == id) {
name = part_name_map[i].name;
diff --git a/hw/ipmi/ipmi-sel.c b/hw/ipmi/ipmi-sel.c
index 173b7be..c86c2c9 100644
--- a/hw/ipmi/ipmi-sel.c
+++ b/hw/ipmi/ipmi-sel.c
@@ -41,6 +41,9 @@
#define SOFT_OFF 0x00
#define SOFT_REBOOT 0x01
+#define RELEASE_PNOR 0x00
+#define REQUEST_PNOR 0x01
+
struct oem_sel {
/* SEL header */
uint8_t id[2];
@@ -180,6 +183,33 @@ int ipmi_elog_commit(struct errorlog *elog_buf)
return 0;
}
+#define ACCESS_DENIED 0x00
+#define ACCESS_GRANTED 0x01
+
+static void sel_pnor(uint8_t access)
+{
+ struct ipmi_msg *msg;
+ uint8_t granted = ACCESS_GRANTED;
+
+ switch (access) {
+ case REQUEST_PNOR:
+ prlog(PR_NOTICE, "IPMI: PNOR access requested\n");
+ granted = flash_reserve();
+
+ /* Ack the request */
+ msg = ipmi_mkmsg_simple(IPMI_PNOR_ACCESS_STATUS, &granted, 1);
+ ipmi_queue_msg(msg);
+ break;
+ case RELEASE_PNOR:
+ prlog(PR_NOTICE, "IPMI: PNOR access released\n");
+ flash_release();
+ break;
+ default:
+ prlog(PR_ERR, "IPMI: invalid PNOR access requested: %02x\n",
+ access);
+ }
+}
+
static void sel_power(uint8_t power)
{
switch (power) {
@@ -271,9 +301,11 @@ void ipmi_parse_sel(struct ipmi_msg *msg)
sel_occ_reset(sel.data[0]);
break;
case CMD_AMI_PNOR_ACCESS:
+ sel_pnor(sel.data[0]);
break;
default:
- printf("IPMI: unknown OEM SEL command %02x received\n",
- sel.cmd);
+ prlog(PR_WARNING,
+ "IPMI: unknown OEM SEL command %02x received\n",
+ sel.cmd);
}
}
diff --git a/include/ipmi.h b/include/ipmi.h
index 9e52916..de5a61b 100644
--- a/include/ipmi.h
+++ b/include/ipmi.h
@@ -91,7 +91,6 @@
#define IPMI_NETFN_CHASSIS 0x00
#define IPMI_NETFN_STORAGE 0x0a
#define IPMI_NETFN_APP 0x06
-#define IPMI_NETFN_OEM 0x32
#define IPMI_WRITE_FRU IPMI_CODE(IPMI_NETFN_STORAGE, 0x12)
#define IPMI_GET_SEL_INFO IPMI_CODE(IPMI_NETFN_STORAGE, 0x40)
@@ -110,7 +109,9 @@
#define IPMI_GET_MESSAGE IPMI_CODE(IPMI_NETFN_APP, 0x33)
#define IPMI_READ_EVENT IPMI_CODE(IPMI_NETFN_APP, 0x35)
-#define IPMI_PARTIAL_ADD_ESEL IPMI_CODE(IPMI_NETFN_OEM, 0xf0)
+/* AMI OEM comamnds. AMI uses NETFN 0x3a and 0x32 */
+#define IPMI_PARTIAL_ADD_ESEL IPMI_CODE(0x32, 0xf0)
+#define IPMI_PNOR_ACCESS_STATUS IPMI_CODE(0x3a, 0x07)
/*
* IPMI response codes.
diff --git a/include/skiboot.h b/include/skiboot.h
index 9dfe0e7..beaa7db 100644
--- a/include/skiboot.h
+++ b/include/skiboot.h
@@ -201,6 +201,9 @@ struct flash_chip;
extern int flash_register(struct flash_chip *chip, bool is_system_flash);
extern bool flash_load_resource(enum resource_id id, uint32_t subid,
void *buf, size_t *len);
+extern bool flash_reserve(void);
+extern void flash_release(void);
+
/* NVRAM support */
extern void nvram_init(void);