Skip to content

Commit

Permalink
opal-prd: Add firmware_request & firmware_notify implementations
Browse files Browse the repository at this point in the history
This change adds the implementation of firmware_request() and
firmware_notify(). To do this, we need to add a message queue, so that
we can properly handle out-of-order messages coming from firmware.

Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
  • Loading branch information
jk-ozlabs authored and stewartsmith committed Jun 6, 2017
1 parent bf06664 commit 43b2485
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 2 deletions.
157 changes: 156 additions & 1 deletion external/opal-prd/opal-prd.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
#include <opal-api.h>
#include <types.h>

#include <ccan/list/list.h>

#include "opal-prd.h"
#include "hostboot-interface.h"
#include "module.h"
Expand All @@ -65,6 +67,11 @@ struct prd_range {
uint32_t instance;
};

struct prd_msgq_item {
struct list_node list;
struct opal_prd_msg msg;
};

struct opal_prd_ctx {
int fd;
int socket;
Expand All @@ -80,6 +87,7 @@ struct opal_prd_ctx {
char *hbrt_file_name;
bool use_syslog;
bool expert_mode;
struct list_head msgq;
struct opal_prd_msg *msg;
size_t msg_alloc_len;
void (*vlog)(int, const char *, va_list);
Expand Down Expand Up @@ -124,6 +132,8 @@ static const char *hbrt_code_region_name = "ibm,hbrt-code-image";
static const int opal_prd_version = 1;
static uint64_t opal_prd_ipoll = 0xf000000000000000;

static const int max_msgq_len = 16;

static const char *ipmi_devnode = "/dev/ipmi0";
static const int ipmi_timeout_ms = 5000;

Expand Down Expand Up @@ -153,6 +163,8 @@ struct func_desc {
void *toc;
} hbrt_entry;

static int read_prd_msg(struct opal_prd_ctx *ctx);

static struct prd_range *find_range(const char *name, uint32_t instance)
{
struct prd_range *range;
Expand Down Expand Up @@ -270,6 +282,7 @@ extern int call_mfg_htmgt_pass_thru(uint16_t i_cmdLength, uint8_t *i_cmdData,
extern int call_apply_attr_override(uint8_t *i_data, size_t size);
extern int call_run_command(int argc, const char **argv, char **o_outString);
extern uint64_t call_get_ipoll_events(void);
extern int call_firmware_notify(uint64_t len, void *data);

void hservice_puts(const char *str)
{
Expand Down Expand Up @@ -691,6 +704,102 @@ uint64_t hservice_get_interface_capabilities(uint64_t set)
return 0;
}

uint64_t hservice_firmware_request(uint64_t req_len, void *req,
uint64_t *resp_lenp, void *resp)
{
struct opal_prd_msg *msg = ctx->msg;
uint64_t resp_len;
size_t size;
int rc, n;

resp_len = be64_to_cpu(*resp_lenp);

pr_log(LOG_DEBUG,
"HBRT: firmware request: %lu bytes req, %lu bytes resp",
req_len, resp_len);

/* sanity check for potential overflows */
if (req_len > 0xffff || resp_len > 0xffff)
return -1;

size = sizeof(msg->hdr) + sizeof(msg->token) +
sizeof(msg->fw_req) + req_len;

/* we need the entire message to fit within the 2-byte size field */
if (size > 0xffff)
return -1;

/* variable sized message, so we may need to expand our buffer */
if (size > ctx->msg_alloc_len) {
msg = realloc(ctx->msg, size);
if (!msg) {
pr_log(LOG_ERR,
"FW: failed to expand message buffer: %m");
return -1;
}
ctx->msg = msg;
ctx->msg_alloc_len = size;
}

memset(msg, 0, size);

/* construct request message... */
msg->hdr.type = OPAL_PRD_MSG_TYPE_FIRMWARE_REQUEST;
msg->hdr.size = htobe16(size);
msg->fw_req.req_len = htobe64(req_len);
msg->fw_req.resp_len = htobe64(resp_len);
memcpy(msg->fw_req.data, req, req_len);

hexdump((void *)msg, size);

/* ... and send to firmware */
rc = write(ctx->fd, msg, size);
if (rc != size) {
pr_log(LOG_WARNING,
"FW: Failed to send FIRMWARE_REQUEST message: %m");
return -1;
}

/* We have an "inner" poll loop here, as we want to ensure that the
* next entry into HBRT is the return from this function. So, only
* read from the prd fd, and queue anything that isn't a response
* to this request
*/
n = 0;
for (;;) {
struct prd_msgq_item *item;

rc = read_prd_msg(ctx);
if (rc)
return -1;

msg = ctx->msg;
if (msg->hdr.type == OPAL_PRD_MSG_TYPE_FIRMWARE_RESPONSE) {
size = be64toh(msg->fw_resp.len);
if (size > resp_len)
return -1;

/* success! a valid response that fits into HBRT's
* resp buffer */
memcpy(resp, msg->fw_resp.data, size);
*resp_lenp = htobe64(size);
return 0;
}

/* not a response? queue up for later consumption */
if (++n > max_msgq_len) {
pr_log(LOG_ERR,
"FW: too many messages queued (%d) while "
"waiting for FIRMWARE_RESPONSE", n);
return -1;
}
size = be16toh(msg->hdr.size);
item = malloc(sizeof(*item) + size);
memcpy(&item->msg, msg, size);
list_add_tail(&ctx->msgq, &item->list);
}
}

int hservices_init(struct opal_prd_ctx *ctx, void *code)
{
uint64_t *s, *d;
Expand Down Expand Up @@ -1239,6 +1348,27 @@ static int handle_msg_occ_reset(struct opal_prd_ctx *ctx,
return 0;
}

static int handle_msg_firmware_notify(struct opal_prd_ctx *ctx,
struct opal_prd_msg *msg)
{
uint64_t len;
void *buf;

len = be64toh(msg->fw_notify.len);
buf = msg->fw_notify.data;

pr_debug("FW: firmware notification, %ld bytes", len);

if (!hservice_runtime->firmware_notify) {
pr_log_nocall("firmware_notify");
return -1;
}

call_firmware_notify(len, buf);

return 0;
}

static int handle_prd_msg(struct opal_prd_ctx *ctx, struct opal_prd_msg *msg)
{
int rc = -1;
Expand All @@ -1253,6 +1383,9 @@ static int handle_prd_msg(struct opal_prd_ctx *ctx, struct opal_prd_msg *msg)
case OPAL_PRD_MSG_TYPE_OCC_ERROR:
rc = handle_msg_occ_error(ctx, msg);
break;
case OPAL_PRD_MSG_TYPE_FIRMWARE_NOTIFY:
rc = handle_msg_firmware_notify(ctx, msg);
break;
default:
pr_log(LOG_WARNING, "Invalid incoming message type 0x%x",
msg->hdr.type);
Expand All @@ -1261,6 +1394,24 @@ static int handle_prd_msg(struct opal_prd_ctx *ctx, struct opal_prd_msg *msg)
return rc;
}

#define list_for_each_pop(h, i, type, member) \
for (i = list_pop((h), type, member); \
i; \
i = list_pop((h), type, member))


static int process_msgq(struct opal_prd_ctx *ctx)
{
struct prd_msgq_item *item;

list_for_each_pop(&ctx->msgq, item, struct prd_msgq_item, list) {
handle_prd_msg(ctx, &item->msg);
free(item);
}

return 0;
}

static int read_prd_msg(struct opal_prd_ctx *ctx)
{
struct opal_prd_msg *msg;
Expand Down Expand Up @@ -1611,6 +1762,9 @@ static int run_attn_loop(struct opal_prd_ctx *ctx)
pollfds[1].events = POLLIN | POLLERR;

for (;;) {
/* run through any pending messages */
process_msgq(ctx);

rc = poll(pollfds, 2, -1);
if (rc < 0) {
pr_log(LOG_ERR, "FW: event poll failed: %m");
Expand Down Expand Up @@ -1702,6 +1856,8 @@ static int run_prd_daemon(struct opal_prd_ctx *ctx)
}


list_head_init(&ctx->msgq);

i2c_init();

#ifdef DEBUG_I2C
Expand Down Expand Up @@ -1731,7 +1887,6 @@ static int run_prd_daemon(struct opal_prd_ctx *ctx)
goto out_close;
}


if (ctx->hbrt_file_name) {
rc = map_hbrt_file(ctx, ctx->hbrt_file_name);
if (rc) {
Expand Down
2 changes: 1 addition & 1 deletion external/opal-prd/thunk.S
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ hinterface:
DISABLED_THUNK(hservice_map_phys_mem)
DISABLED_THUNK(hservice_unmap_phys_mem)
DISABLED_THUNK(hservice_hcode_scom_update)
DISABLED_THUNK(hservice_firmware_request)
CALLBACK_THUNK(hservice_firmware_request)
.globl __hinterface_pad
__hinterface_pad:
/* Reserved space for future growth */
Expand Down
16 changes: 16 additions & 0 deletions include/opal-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -1029,6 +1029,9 @@ enum opal_prd_msg_type {
OPAL_PRD_MSG_TYPE_OCC_ERROR, /* HBRT <-- OPAL */
OPAL_PRD_MSG_TYPE_OCC_RESET, /* HBRT <-- OPAL */
OPAL_PRD_MSG_TYPE_OCC_RESET_NOTIFY, /* HBRT --> OPAL */
OPAL_PRD_MSG_TYPE_FIRMWARE_REQUEST, /* HBRT --> OPAL */
OPAL_PRD_MSG_TYPE_FIRMWARE_RESPONSE, /* HBRT <-- OPAL */
OPAL_PRD_MSG_TYPE_FIRMWARE_NOTIFY, /* HBRT <-- OPAL */
};

struct opal_prd_msg_header {
Expand Down Expand Up @@ -1060,6 +1063,19 @@ struct opal_prd_msg {
struct {
__be64 chip;
} occ_reset;
struct {
__be64 req_len;
__be64 resp_len;
char data[];
} fw_req;
struct {
__be64 len;
char data[];
} fw_resp;
struct {
__be64 len;
char data[];
} fw_notify;
};
};

Expand Down

0 comments on commit 43b2485

Please sign in to comment.