[Skiboot] [PATCH 1/7 v3] external/opal-prd: Allow instance numbers for PRD ranges

Jeremy Kerr jk at ozlabs.org
Mon Aug 17 16:49:53 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           |  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(&reg_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);


More information about the Skiboot mailing list