From patchwork Mon Aug 17 06:49:53 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeremy Kerr X-Patchwork-Id: 507772 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [103.22.144.68]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 00F49140293 for ; Mon, 17 Aug 2015 16:50:08 +1000 (AEST) Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id DC61A1A1DAA for ; Mon, 17 Aug 2015 16:50:07 +1000 (AEST) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Received: from ozlabs.org (ozlabs.org [103.22.144.67]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id B06D81A1DE3 for ; Mon, 17 Aug 2015 16:49:57 +1000 (AEST) Received: by ozlabs.org (Postfix, from userid 1023) id 9148F1402A0; Mon, 17 Aug 2015 16:49:57 +1000 (AEST) MIME-Version: 1.0 Message-Id: <1439794193.542347.800306660215.1.gpush@pudge> In-Reply-To: <1439794193.542192.340390056346.0.gpush@pudge> To: skiboot@lists.ozlabs.org From: Jeremy Kerr Date: Mon, 17 Aug 2015 14:49:53 +0800 Subject: [Skiboot] [PATCH 1/7 v3] external/opal-prd: Allow instance numbers for PRD ranges X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.20 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" We have a provision for multiple instances of the same PRD range. For example, multiple-socket systems may have a PRD range per socket. This change adds an 'int instance' argument to the get_reserved_mem() call, allowing HBRT to request a specific instance of a range. We bump the hinterface version in indicate that this new parameter is present. These ranges can be provided by ibm,prd-instance properties in the reserved-memory nodes. If these are provided, they'll be used, otherwise opal-prd will number the instances automatically, based on increading physical addreses. Signed-off-by: Jeremy Kerr --- external/opal-prd/hostboot-interface.h | 3 external/opal-prd/opal-prd.c | 145 ++++++++++++++++++++++--- 2 files changed, 130 insertions(+), 18 deletions(-) diff --git a/external/opal-prd/hostboot-interface.h b/external/opal-prd/hostboot-interface.h index a518f50..3c162aa 100644 --- a/external/opal-prd/hostboot-interface.h +++ b/external/opal-prd/hostboot-interface.h @@ -117,10 +117,11 @@ struct host_interfaces { * name. * * @param[in] Devtree name (ex. "ibm,hbrt-vpd-image") + * @param[in] Devtree instance * @return physical address of region (or NULL). * @platform FSP,OpenPOWER */ - uint64_t (*get_reserved_mem)(const char*); + uint64_t (*get_reserved_mem)(const char *name, uint32_t instance); /** * @brief Force a core to be awake, or clear the force diff --git a/external/opal-prd/opal-prd.c b/external/opal-prd/opal-prd.c index 82d9901..ed173ac 100644 --- a/external/opal-prd/opal-prd.c +++ b/external/opal-prd/opal-prd.c @@ -61,6 +61,8 @@ struct prd_range { uint64_t physaddr; uint64_t size; void *buf; + bool multiple; + uint32_t instance; }; struct opal_prd_ctx { @@ -69,6 +71,7 @@ struct opal_prd_ctx { struct opal_prd_info info; struct prd_range *ranges; int n_ranges; + bool fw_range_instances; long page_size; void *code_addr; size_t code_size; @@ -128,7 +131,7 @@ struct func_desc { void *toc; } hbrt_entry; -static struct prd_range *find_range(const char *name) +static struct prd_range *find_range(const char *name, uint32_t instance) { struct prd_range *range; unsigned int i; @@ -136,8 +139,13 @@ static struct prd_range *find_range(const char *name) for (i = 0; i < ctx->n_ranges; i++) { range = &ctx->ranges[i]; - if (!strcmp(range->name, name)) - return range; + if (strcmp(range->name, name)) + continue; + + if (range->multiple && range->instance != instance) + continue; + + return range; } return NULL; @@ -274,13 +282,13 @@ int hservice_scom_write(uint64_t chip_id, uint64_t addr, return 0; } -uint64_t hservice_get_reserved_mem(const char *name) +uint64_t hservice_get_reserved_mem(const char *name, uint32_t instance) { struct prd_range *range; - pr_debug("IMAGE: hservice_get_reserved_mem: %s", name); + pr_debug("IMAGE: hservice_get_reserved_mem: %s, %d", name, instance); - range = find_range(name); + range = find_range(name, instance); if (!range) { pr_log(LOG_WARNING, "IMAGE: get_reserved_mem: " "no such range %s", name); @@ -290,8 +298,9 @@ uint64_t hservice_get_reserved_mem(const char *name) if (!range->buf) { uint64_t align_physaddr, offset; - pr_debug("IMAGE: Mapping 0x%016lx 0x%08lx %s", - range->physaddr, range->size, range->name); + pr_debug("IMAGE: Mapping 0x%016lx 0x%08lx %s[%d]", + range->physaddr, range->size, + range->name, range->instance); align_physaddr = range->physaddr & ~(ctx->page_size-1); offset = range->physaddr & (ctx->page_size-1); @@ -300,20 +309,23 @@ uint64_t hservice_get_reserved_mem(const char *name) if (range->buf == MAP_FAILED) pr_log(LOG_ERR, - "IMAGE: mmap of %s(0x%016lx) failed: %m", - name, range->physaddr); + "IMAGE: mmap of %s[%d](0x%016lx) failed: %m", + name, instance, range->physaddr); else range->buf += offset; } if (range->buf == MAP_FAILED) { - pr_log(LOG_WARNING, "IMAGE: get_reserved_mem: %s has no vaddr", - name); + pr_log(LOG_WARNING, + "IMAGE: get_reserved_mem: %s[%d] has no vaddr", + name, instance); return 0; } - pr_debug("IMAGE: hservice_get_reserved_mem: %s(0x%016lx) address %p", - name, range->physaddr, range->buf); + pr_debug( + "IMAGE: hservice_get_reserved_mem: %s[%d](0x%016lx) address %p", + name, range->instance, range->physaddr, + range->buf); return (uint64_t)range->buf; } @@ -682,7 +694,7 @@ static int map_hbrt_physmem(struct opal_prd_ctx *ctx, const char *name) struct prd_range *range; void *buf; - range = find_range(name); + range = find_range(name, 0); if (!range) { pr_log(LOG_ERR, "IMAGE: can't find code region %s", name); return -1; @@ -780,11 +792,11 @@ static int open_and_read(const char *path, void **bufp, int *lenp) static int prd_init_one_range(struct opal_prd_ctx *ctx, const char *path, struct dirent *dirent) { - char *label_path, *reg_path; + char *label_path, *reg_path, *instance_path; struct prd_range *range; int label_len, len, rc; - char *label; __be64 *reg; + char *label; void *buf; rc = asprintf(&label_path, "%s/%s/ibm,prd-label", path, dirent->d_name); @@ -793,6 +805,13 @@ static int prd_init_one_range(struct opal_prd_ctx *ctx, const char *path, "node: %m"); return -1; } + rc = asprintf(&instance_path, "%s/%s/ibm,prd-instance", + path, dirent->d_name); + if (rc < 0) { + pr_log(LOG_ERR, "FW: error creating 'ibm,prd-instance' path " + "node: %m"); + return -1; + } rc = asprintf(®_path, "%s/%s/reg", path, dirent->d_name); if (rc < 0) { pr_log(LOG_ERR, "FW: error creating 'reg' path " @@ -834,16 +853,99 @@ static int prd_init_one_range(struct opal_prd_ctx *ctx, const char *path, range->physaddr = be64toh(reg[0]); range->size = be64toh(reg[1]); range->buf = NULL; + range->multiple = false; + range->instance = 0; + + /* optional instance */ + rc = open_and_read(instance_path, &buf, &len); + if (!rc && len == sizeof(uint32_t)) { + range->multiple = true; + range->instance = be32toh(*(uint32_t *)buf); + ctx->fw_range_instances = true; + } rc = 0; out_free: free(reg); free(label); + free(instance_path); free(reg_path); free(label_path); return rc; } +static int compare_ranges(const void *ap, const void *bp) +{ + const struct prd_range *a = ap, *b = bp; + int rc; + + rc = strcmp(a->name, b->name); + if (rc) + return rc; + + if (a->physaddr < b->physaddr) + return -1; + else if (a->physaddr > b->physaddr) + return 1; + + return 0; +} + +static void assign_range_instances(struct opal_prd_ctx *ctx) +{ + int i; + + if (!ctx->n_ranges) + return; + + ctx->ranges[0].multiple = false; + ctx->ranges[0].instance = 0; + + for (i = 1; i < ctx->n_ranges; i++) { + struct prd_range *cur, *prev; + + cur = &ctx->ranges[i]; + prev = &ctx->ranges[i-1]; + + if (!strcmp(cur->name, prev->name)) { + prev->multiple = true; + cur->multiple = true; + cur->instance = prev->instance + 1; + } else { + cur->multiple = false; + cur->instance = 0; + } + } +} + +static void print_ranges(struct opal_prd_ctx *ctx) +{ + int i; + + if (ctx->n_ranges == 0) + pr_log(LOG_INFO, "FW: No PRD ranges"); + + pr_log(LOG_DEBUG, "FW: %d PRD ranges, instances assigned by %s", + ctx->n_ranges, + ctx->fw_range_instances ? "firmware" : "userspace"); + + for (i = 0; i < ctx->n_ranges; i++) { + struct prd_range *range = &ctx->ranges[i]; + char instance_str[20]; + + if (range->multiple) + snprintf(instance_str, sizeof(instance_str), + " [%d]", range->instance); + else + instance_str[0] = '\0'; + + pr_log(LOG_DEBUG, "FW: %016lx-%016lx %s%s", range->physaddr, + range->physaddr + range->size - 1, + range->name, + instance_str); + } +} + static int prd_init_ranges(struct opal_prd_ctx *ctx) { struct dirent *dirent; @@ -876,6 +978,15 @@ static int prd_init_ranges(struct opal_prd_ctx *ctx) } rc = 0; + /* sort ranges and assign instance numbers for duplicates (if the + * firmware doesn't number instances for us) */ + qsort(ctx->ranges, ctx->n_ranges, sizeof(struct prd_range), + compare_ranges); + + if (!ctx->fw_range_instances) + assign_range_instances(ctx); + + print_ranges(ctx); out_free: free(path);