[Skiboot] [PATCH] external/opal-prd: Only map each PRD range once

Jeremy Kerr jk at ozlabs.org
Thu Aug 6 13:32:47 AEST 2015


Currently, opal-prd will create a new mapping (via mmap()) on every call
to get_reserved_mem().

HBRT may end up calling this many times for the same range, which will
consume virtual address space. There's no interface to unmap memory, so
we may fail after too many calls.

Instead, store the mapping in struct prd_range on first
get_reserved_mem. Subsequent calls will re-use the same mapping.

Signed-off-by: Jeremy Kerr <jk at ozlabs.org>

---
 external/opal-prd/opal-prd.c |   35 +++++++++++++++++++++++------------
 1 file changed, 23 insertions(+), 12 deletions(-)

diff --git a/external/opal-prd/opal-prd.c b/external/opal-prd/opal-prd.c
index 9f686c5..82d9901 100644
--- a/external/opal-prd/opal-prd.c
+++ b/external/opal-prd/opal-prd.c
@@ -60,6 +60,7 @@ struct prd_range {
 	const char		*name;
 	uint64_t		physaddr;
 	uint64_t		size;
+	void			*buf;
 };
 
 struct opal_prd_ctx {
@@ -275,9 +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 prd_range *range;
-	void *addr;
 
 	pr_debug("IMAGE: hservice_get_reserved_mem: %s", name);
 
@@ -288,24 +287,35 @@ uint64_t hservice_get_reserved_mem(const char *name)
 		return 0;
 	}
 
-	pr_debug("IMAGE: Mapping 0x%016lx 0x%08lx %s",
-			range->physaddr, range->size, range->name);
+	if (!range->buf) {
+		uint64_t align_physaddr, offset;
+
+		pr_debug("IMAGE: Mapping 0x%016lx 0x%08lx %s",
+				range->physaddr, range->size, range->name);
 
-	align_physaddr = range->physaddr & ~(ctx->page_size-1);
-	offset = range->physaddr & (ctx->page_size-1);
-	addr = mmap(NULL, range->size, PROT_WRITE | PROT_READ,
-				MAP_SHARED, ctx->fd, align_physaddr);
+		align_physaddr = range->physaddr & ~(ctx->page_size-1);
+		offset = range->physaddr & (ctx->page_size-1);
+		range->buf = mmap(NULL, range->size, PROT_WRITE | PROT_READ,
+					MAP_SHARED, ctx->fd, align_physaddr);
 
-	if (addr == MAP_FAILED) {
-		pr_log(LOG_ERR, "IMAGE: mmap of %s(0x%016lx) failed: %m",
+		if (range->buf == MAP_FAILED)
+			pr_log(LOG_ERR,
+				"IMAGE: mmap of %s(0x%016lx) failed: %m",
 				name, range->physaddr);
+		else
+			range->buf += offset;
+	}
+
+	if (range->buf == MAP_FAILED) {
+		pr_log(LOG_WARNING, "IMAGE: get_reserved_mem: %s has no vaddr",
+				name);
 		return 0;
 	}
 
 	pr_debug("IMAGE: hservice_get_reserved_mem: %s(0x%016lx) address %p",
-			name, range->physaddr, addr);
+			name, range->physaddr, range->buf);
 
-	return (uint64_t)addr + offset;
+	return (uint64_t)range->buf;
 }
 
 void hservice_nanosleep(uint64_t i_seconds, uint64_t i_nano_seconds)
@@ -823,6 +833,7 @@ 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]);
+	range->buf = NULL;
 	rc = 0;
 
 out_free:


More information about the Skiboot mailing list