[Skiboot] [RFC, PATCH] external/opal-prd: Allow instance numbers for PRD ranges
Jeremy Kerr
jk at ozlabs.org
Tue Jun 30 18:02:46 AEST 2015
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 <jk at ozlabs.org>
---
external/opal-prd/hostboot-interface.h | 3
external/opal-prd/opal-prd.c | 122 +++++++++++++++++++++++--
external/opal-prd/thunk.S | 2
3 files changed, 117 insertions(+), 10 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 9f686c5..98fd86b 100644
--- a/external/opal-prd/opal-prd.c
+++ b/external/opal-prd/opal-prd.c
@@ -60,6 +60,8 @@ struct prd_range {
const char *name;
uint64_t physaddr;
uint64_t size;
+ bool multiple;
+ uint32_t instance;
};
struct opal_prd_ctx {
@@ -68,6 +70,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;
@@ -127,7 +130,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;
@@ -135,8 +138,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;
@@ -273,7 +281,7 @@ 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)
{
uint64_t align_physaddr, offset;
struct prd_range *range;
@@ -281,7 +289,7 @@ uint64_t hservice_get_reserved_mem(const char *name)
pr_debug("IMAGE: hservice_get_reserved_mem: %s", name);
- range = find_range(name);
+ range = find_range(name, instance);
if (!range) {
pr_log(LOG_WARNING, "IMAGE: get_reserved_mem: "
"no such range %s", name);
@@ -672,7 +680,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;
@@ -770,11 +778,12 @@ 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;
+ __be32 *instance;
__be64 *reg;
+ char *label;
void *buf;
rc = asprintf(&label_path, "%s/%s/ibm,prd-label", path, dirent->d_name);
@@ -783,6 +792,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 "
@@ -823,16 +839,97 @@ static int prd_init_one_range(struct opal_prd_ctx *ctx, const char *path,
range->name = strndup(label, label_len);
range->physaddr = be64toh(reg[0]);
range->size = be64toh(reg[1]);
+
+ /* optional instance */
+ rc = open_and_read(instance_path, &buf, &len);
+ if (!rc && len == sizeof(*instance)) {
+ range->multiple = true;
+ range->instance = be32toh(*instance);
+ 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;
@@ -865,6 +962,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);
diff --git a/external/opal-prd/thunk.S b/external/opal-prd/thunk.S
index ab1e737..bd347f3 100644
--- a/external/opal-prd/thunk.S
+++ b/external/opal-prd/thunk.S
@@ -156,7 +156,7 @@ name##_thunk: ;\
.globl hinterface
hinterface:
/* HBRT interface version */
- .llong 1
+ .llong 2
/* Callout pointers */
CALLBACK_THUNK(hservice_puts)
More information about the Skiboot
mailing list