Skip to content

Commit

Permalink
ipmi: Introduce registration for SEL command handlers
Browse files Browse the repository at this point in the history
[ Upstream commit d404842 ]

Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Signed-off-by: Stewart Smith <stewart@linux.ibm.com>
  • Loading branch information
amboar authored and stewartsmith committed Oct 31, 2018
1 parent 79c821b commit c1208ae
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 29 deletions.
118 changes: 89 additions & 29 deletions hw/ipmi/ipmi-sel.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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);
}
5 changes: 5 additions & 0 deletions include/ipmi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit c1208ae

Please sign in to comment.