aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Jeffery <andrew@aj.id.au>2018-10-09 00:32:27 -0700
committerStewart Smith <stewart@linux.ibm.com>2018-10-31 16:49:21 +1100
commitc1208aee6955630f9c2d9dbb149b89633c9a91bd (patch)
tree11ac06ac97057dd0b5f6c1340c91c336a0459640
parent79c821bcfc4b629f633fed9744300ae7dd4fb5fc (diff)
downloadskiboot-c1208aee6955630f9c2d9dbb149b89633c9a91bd.zip
skiboot-c1208aee6955630f9c2d9dbb149b89633c9a91bd.tar.gz
skiboot-c1208aee6955630f9c2d9dbb149b89633c9a91bd.tar.bz2
ipmi: Introduce registration for SEL command handlers
[ Upstream commit d4048420962097ce5b46167b2715b458142d394f ] Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Signed-off-by: Stewart Smith <stewart@linux.ibm.com>
-rw-r--r--hw/ipmi/ipmi-sel.c118
-rw-r--r--include/ipmi.h5
2 files changed, 94 insertions, 29 deletions
diff --git a/hw/ipmi/ipmi-sel.c b/hw/ipmi/ipmi-sel.c
index 3386854..8862722 100644
--- a/hw/ipmi/ipmi-sel.c
+++ b/hw/ipmi/ipmi-sel.c
@@ -15,6 +15,10 @@
*/
#define pr_fmt(fmt) "IPMI: " fmt
+#include <ccan/list/list.h>
+#include <ccan/str/str.h>
+#include <compiler.h>
+#include <errno.h>
#include <skiboot.h>
#include <stdlib.h>
#include <string.h>
@@ -35,10 +39,14 @@
#define SEL_NETFN_IBM 0x3a
/* OEM SEL Commands */
+/* TODO: Move these to their respective source files */
#define CMD_AMI_POWER 0x04
#define CMD_AMI_PNOR_ACCESS 0x07
#define CMD_AMI_OCC_RESET 0x0e
+/* XXX: Listed here for completeness, registered in libflash/ipmi-flash.c */
+#define CMD_OP_HIOMAP_EVENT 0x0f
+
#define SOFT_OFF 0x00
#define SOFT_REBOOT 0x01
@@ -135,21 +143,11 @@ struct ipmi_sel_panic_msg {
};
static struct ipmi_sel_panic_msg ipmi_sel_panic_msg;
+static LIST_HEAD(sel_handlers);
+
/* Forward declaration */
static void ipmi_elog_poll(struct ipmi_msg *msg);
-void ipmi_sel_init(void)
-{
- /* Already done */
- if (ipmi_sel_panic_msg.msg != NULL)
- return;
-
- memset(&ipmi_sel_panic_msg, 0, sizeof(struct ipmi_sel_panic_msg));
- ipmi_sel_panic_msg.msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE,
- IPMI_RESERVE_SEL, ipmi_elog_poll,
- NULL, NULL, IPMI_MAX_REQ_SIZE, 2);
-}
-
/*
* Allocate IPMI message:
* For normal event, allocate memory using ipmi_mkmsg and for PANIC
@@ -456,7 +454,7 @@ int ipmi_elog_commit(struct errorlog *elog_buf)
#define ACCESS_DENIED 0x00
#define ACCESS_GRANTED 0x01
-static void sel_pnor(uint8_t access)
+static void sel_pnor(uint8_t access, void *context __unused)
{
struct ipmi_msg *msg;
uint8_t granted = ACCESS_GRANTED;
@@ -499,7 +497,7 @@ static void sel_pnor(uint8_t access)
}
}
-static void sel_power(uint8_t power)
+static void sel_power(uint8_t power, void *context __unused)
{
switch (power) {
case SOFT_OFF:
@@ -562,7 +560,7 @@ static uint32_t occ_sensor_id_to_chip(uint8_t sensor, uint32_t *chip)
return 0;
}
-static void sel_occ_reset(uint8_t sensor)
+static void sel_occ_reset(uint8_t sensor, void *context __unused)
{
uint32_t chip;
int rc;
@@ -581,8 +579,77 @@ static void sel_occ_reset(uint8_t sensor)
prd_occ_reset(chip);
}
+struct ipmi_sel_handler {
+ uint8_t oem_cmd;
+ void (*fn)(uint8_t data, void *context);
+ void *context;
+ struct list_node node;
+};
+
+int ipmi_sel_register(uint8_t oem_cmd,
+ void (*fn)(uint8_t data, void *context),
+ void *context)
+{
+ struct ipmi_sel_handler *handler;
+
+ list_for_each(&sel_handlers, handler, node) {
+ if (handler->oem_cmd == oem_cmd) {
+ prerror("Handler for SEL command 0x%02x already registered\n",
+ oem_cmd);
+ return -EINVAL;
+ }
+ }
+
+ handler = malloc(sizeof(*handler));
+ if (!handler)
+ return -ENOMEM;
+
+ handler->oem_cmd = oem_cmd;
+ handler->fn = fn;
+ handler->context = context;
+
+ list_add(&sel_handlers, &handler->node);
+
+ return 0;
+}
+
+void ipmi_sel_init(void)
+{
+ int rc;
+
+ /* Already done */
+ if (ipmi_sel_panic_msg.msg != NULL)
+ return;
+
+ memset(&ipmi_sel_panic_msg, 0, sizeof(struct ipmi_sel_panic_msg));
+ ipmi_sel_panic_msg.msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE,
+ IPMI_RESERVE_SEL, ipmi_elog_poll,
+ NULL, NULL, IPMI_MAX_REQ_SIZE, 2);
+
+ /* Hackishly register these old-style handlers here for now */
+ /* TODO: Move them to their appropriate source files */
+ rc = ipmi_sel_register(CMD_AMI_POWER, sel_power, NULL);
+ if (rc < 0) {
+ prerror("Failed to register SEL handler for %s",
+ stringify(CMD_AMI_POWER));
+ }
+
+ rc = ipmi_sel_register(CMD_AMI_OCC_RESET, sel_occ_reset, NULL);
+ if (rc < 0) {
+ prerror("Failed to register SEL handler for %s",
+ stringify(CMD_AMI_OCC_RESET));
+ }
+
+ rc = ipmi_sel_register(CMD_AMI_PNOR_ACCESS, sel_pnor, NULL);
+ if (rc < 0) {
+ prerror("Failed to register SEL handler for %s",
+ stringify(CMD_AMI_PNOR_ACCESS));
+ }
+}
+
void ipmi_parse_sel(struct ipmi_msg *msg)
{
+ struct ipmi_sel_handler *handler;
struct oem_sel sel;
assert(msg->resp_size <= 16);
@@ -606,19 +673,12 @@ void ipmi_parse_sel(struct ipmi_msg *msg)
return;
}
- switch (sel.cmd) {
- case CMD_AMI_POWER:
- sel_power(sel.data[0]);
- break;
- case CMD_AMI_OCC_RESET:
- sel_occ_reset(sel.data[0]);
- break;
- case CMD_AMI_PNOR_ACCESS:
- sel_pnor(sel.data[0]);
- break;
- default:
- prlog(PR_WARNING,
- "unknown OEM SEL command %02x received\n",
- sel.cmd);
+ list_for_each(&sel_handlers, handler, node) {
+ if (handler->oem_cmd == sel.cmd) {
+ handler->fn(sel.data[0], handler->context);
+ return;
+ }
}
+
+ prlog(PR_WARNING, "unknown OEM SEL command %02x received\n", sel.cmd);
}
diff --git a/include/ipmi.h b/include/ipmi.h
index 0acfbf5..a2735f1 100644
--- a/include/ipmi.h
+++ b/include/ipmi.h
@@ -241,6 +241,11 @@ void ipmi_register_backend(struct ipmi_backend *backend);
/* Allocate IPMI SEL panic message */
void ipmi_sel_init(void);
+/* Register SEL handler with IPMI core */
+int ipmi_sel_register(uint8_t oem_cmd,
+ void (*handler)(uint8_t data, void *context),
+ void *context);
+
/* Register rtc ipmi commands with as opal callbacks. */
void ipmi_rtc_init(void);