[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(&reg_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