From patchwork Tue May 19 09:05:38 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeremy Kerr X-Patchwork-Id: 473790 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 6C057140D4D for ; Tue, 19 May 2015 19:06:09 +1000 (AEST) Received: from ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 461C01A05E3 for ; Tue, 19 May 2015 19:06:09 +1000 (AEST) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Received: from ozlabs.org (ozlabs.org [IPv6:2401:3900:2:1::2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 0C4B81A0211 for ; Tue, 19 May 2015 19:05:44 +1000 (AEST) Received: by ozlabs.org (Postfix, from userid 1023) id E35DD140D15; Tue, 19 May 2015 19:05:43 +1000 (AEST) MIME-Version: 1.0 Message-Id: <1432026338.127156.120334223297.7.gpush@pablo> In-Reply-To: <1432026338.124852.77854388738.0.gpush@pablo> To: skiboot@lists.ozlabs.org From: Jeremy Kerr Date: Tue, 19 May 2015 17:05:38 +0800 Subject: [Skiboot] [PATCH 7/7 v3] external/opal-prd: Update for new PRD userspace interface X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" Previous updates to the opal-prd firmare interface have 1) added the message size into struct opal_prd_msg 2) split opal_prd_msg into a separate header struct 3) exposed the PRD ranges through the device-tree This update to the opal-prd binary will accommodate these interface changes. Signed-off-by: Jeremy Kerr --- external/opal-prd/opal-prd.c | 190 ++++++++++++++++++++++++++++++++--- 1 file changed, 178 insertions(+), 12 deletions(-) diff --git a/external/opal-prd/opal-prd.c b/external/opal-prd/opal-prd.c index f06a2f7..fcb8ee1 100644 --- a/external/opal-prd/opal-prd.c +++ b/external/opal-prd/opal-prd.c @@ -14,6 +14,8 @@ * imitations under the License. */ +#define _GNU_SOURCE + #include #include #include @@ -31,6 +33,7 @@ #include #include #include +#include #include @@ -43,7 +46,9 @@ #include #include -#include + +#include +#include #include "opal-prd.h" #include "hostboot-interface.h" @@ -51,11 +56,18 @@ #include "pnor.h" #include "i2c.h" +struct prd_range { + const char *name; + uint64_t physaddr; + uint64_t size; +}; struct opal_prd_ctx { int fd; int socket; struct opal_prd_info info; + struct prd_range *ranges; + int n_ranges; long page_size; void *code_addr; size_t code_size; @@ -89,6 +101,9 @@ static const uint64_t opal_prd_ipoll = 0xf000000000000000; static const char *ipmi_devnode = "/dev/ipmi0"; static const int ipmi_timeout_ms = 2000; +static const char *devicetree_base = + "/sys/firmware/devicetree/base"; + /* Memory error handling */ static const char *mem_offline_soft = "/sys/devices/system/memory/soft_offline_page"; @@ -112,15 +127,15 @@ struct func_desc { void *toc; } hbrt_entry; -static struct opal_prd_range *find_range(const char *name) +static struct prd_range *find_range(const char *name) { - struct opal_prd_range *range; + struct prd_range *range; unsigned int i; - for (i = 0; i < OPAL_PRD_MAX_RANGES; i++) { - range = &ctx->info.ranges[i]; + for (i = 0; i < ctx->n_ranges; i++) { + range = &ctx->ranges[i]; - if (!strncmp(range->name, name, sizeof(range->name))) + if (!strcmp(range->name, name)) return range; } @@ -261,7 +276,7 @@ int hservice_scom_write(uint64_t chip_id, uint64_t addr, uint64_t hservice_get_reserved_mem(const char *name) { uint64_t align_physaddr, offset; - struct opal_prd_range *range; + struct prd_range *range; void *addr; pr_debug("IMAGE: hservice_get_reserved_mem: %s", name); @@ -654,7 +669,7 @@ static int map_hbrt_file(struct opal_prd_ctx *ctx, const char *name) static int map_hbrt_physmem(struct opal_prd_ctx *ctx, const char *name) { - struct opal_prd_range *range; + struct prd_range *range; void *buf; range = find_range(name); @@ -702,6 +717,139 @@ static void dump_hbrt_map(struct opal_prd_ctx *ctx) pr_debug("IMAGE: dumped HBRT binary to %s", dump_name); } +static int open_and_read(const char *path, void **bufp, int *lenp) +{ + struct stat statbuf; + int fd, rc, bytes; + void *buf; + + fd = open(path, O_RDONLY); + if (fd < 0) + return -1; + + rc = fstat(fd, &statbuf); + if (rc) { + close(fd); + return -1; + } + + buf = malloc(statbuf.st_size); + + for (rc = bytes = 0; bytes < statbuf.st_size; bytes += rc) { + rc = read(fd, buf + bytes, statbuf.st_size - bytes); + if (rc < 0) { + if (errno == EINTR) + continue; + break; + } else if (rc == 0) + break; + } + + if (bytes == statbuf.st_size) + rc = 0; + + if (rc == 0) { + if (lenp) + *lenp = bytes; + if (bufp) + *bufp = buf; + } else { + free(buf); + } + + close(fd); + + return rc == 0 ? 0 : -1; +} + +static int prd_init_one_range(struct opal_prd_ctx *ctx, const char *path, + struct dirent *dirent) +{ + char *label_path, *reg_path; + struct prd_range *range; + int label_len, len, rc; + char *label; + __be64 *reg; + void *buf; + + asprintf(&label_path, "%s/%s/ibm,prd-label", path, dirent->d_name); + asprintf(®_path, "%s/%s/reg", path, dirent->d_name); + + reg = NULL; + label = NULL; + rc = -1; + + rc = open_and_read(label_path, &buf, &label_len); + if (rc) + goto out_free; + + label = buf; + + if (label[label_len-1] != '\0') + pr_log(LOG_INFO, "FW: node %s has invalid ibm,prd-label - " + "not nul-terminated", + dirent->d_name); + + rc = open_and_read(reg_path, &buf, &len); + if (rc) + goto out_free; + + reg = buf; + + if (len != 2 * sizeof(*reg)) { + pr_log(LOG_ERR, "FW: node %s has invalid 'reg' size: %d", + dirent->d_name, len); + goto out_free; + } + + + ctx->ranges = realloc(ctx->ranges, ++ctx->n_ranges * sizeof(*range)); + range = &ctx->ranges[ctx->n_ranges - 1]; + range->name = strndup(label, label_len); + range->physaddr = be64toh(reg[0]); + range->size = be64toh(reg[1]); + rc = 0; + +out_free: + free(reg); + free(label); + free(reg_path); + free(label_path); + return rc; +} + +static int prd_init_ranges(struct opal_prd_ctx *ctx) +{ + struct dirent *dirent; + char *path; + DIR *dir; + int rc = -1; + + asprintf(&path, "%s/reserved-memory", devicetree_base); + + dir = opendir(path); + if (!dir) { + pr_log(LOG_ERR, "FW: can't open reserved-memory device-tree " + "node: %m"); + goto out_free; + } + + for (;;) { + dirent = readdir(dir); + if (!dirent) + break; + + prd_init_one_range(ctx, path, dirent); + } + + rc = 0; + +out_free: + free(path); + closedir(dir); + return rc; +} + static int prd_init(struct opal_prd_ctx *ctx) { int rc; @@ -722,6 +870,12 @@ static int prd_init(struct opal_prd_ctx *ctx) return -1; } + rc = prd_init_ranges(ctx); + if (rc) { + pr_log(LOG_ERR, "FW: can't parse PRD memory information"); + return -1; + } + return 0; } @@ -747,7 +901,8 @@ static int handle_msg_attn(struct opal_prd_ctx *ctx, struct opal_prd_msg *msg) } /* send the response */ - msg->type = OPAL_PRD_MSG_TYPE_ATTN_ACK; + msg->hdr.type = OPAL_PRD_MSG_TYPE_ATTN_ACK; + msg->hdr.size = htobe16(sizeof(*msg)); msg->attn_ack.proc = htobe64(proc); msg->attn_ack.ipoll_ack = htobe64(ipoll_status); rc = write(ctx->fd, msg, sizeof(*msg)); @@ -795,6 +950,7 @@ static int handle_msg_occ_reset(struct opal_prd_ctx *ctx, static int handle_prd_msg(struct opal_prd_ctx *ctx) { struct opal_prd_msg msg; + int size; int rc; rc = read(ctx->fd, &msg, sizeof(msg)); @@ -806,7 +962,16 @@ static int handle_prd_msg(struct opal_prd_ctx *ctx) return -1; } - switch (msg.type) { + size = htobe16(msg.hdr.size); + if (size < sizeof(msg)) { + pr_log(LOG_ERR, "FW: Mismatched message size " + "between opal-prd and firmware " + "(%d from FW, %zd expected)", + size, sizeof(msg)); + return -1; + } + + switch (msg.hdr.type) { case OPAL_PRD_MSG_TYPE_ATTN: rc = handle_msg_attn(ctx, &msg); break; @@ -818,7 +983,7 @@ static int handle_prd_msg(struct opal_prd_ctx *ctx) break; default: pr_log(LOG_WARNING, "Invalid incoming message type 0x%x", - msg.type); + msg.hdr.type); return -1; } @@ -907,7 +1072,8 @@ static int run_attn_loop(struct opal_prd_ctx *ctx) } /* send init message, to unmask interrupts */ - msg.type = OPAL_PRD_MSG_TYPE_INIT; + msg.hdr.type = OPAL_PRD_MSG_TYPE_INIT; + msg.hdr.size = htobe16(sizeof(msg)); msg.init.version = htobe64(opal_prd_version); msg.init.ipoll = htobe64(opal_prd_ipoll);