[Skiboot] [PATCH 3/7] core: Add node-style memory reservation to device tree

Jeremy Kerr jk at ozlabs.org
Tue May 19 15:20:15 AEST 2015


Linux supports a newer memory reservation layout in the device-tree,
where each reservation is represented by a subnode under a top-level
"reserved-memory" node.

This change adds these nodes, using the mem_region names as the property
names (minus any cell addresses). The reserved-memory node looks like
this:

/ {
	name = "reserved-memory";
	ranges;
	#address-cells = <0x2>;
	#size-cells = <0x2>;

	ibm,firmware-code at 30000000 {
		reg = <0x0 0x30000000 0x0 0x200000>;
	};

	ibm,firmware-data at 30e00000 {
		reg = <0x0 0x30e00000 0x0 0xc00000>;
	};

	ibm,firmware-stacks at 31a00000 {
		reg = <0x0 0x31a00000 0x0 0x8000000>;
	};

	ibm,firmware-allocs-memory at 39a00000 {
		reg = <0x0 0x39a00000 0x0 0x1c0200>;
	};

	ibm,firmware-heap at 30200000 {
		reg = <0x0 0x30200000 0x0 0xc00000>;
	};
};

We also store a pointer to the reservation nodes in struct mem_region,
so they can be used by other skiboot code.

We keep the property-style reservation information (reserved-names and
reserved-ranges) unchanged.

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

---
 core/mem_region.c                       |   27 ++++++
 core/test/run-mem_region_reservations.c |  108 +++++++++++++++++-------
 doc/device-tree/reserved-memory.txt     |   27 ++++++
 3 files changed, 132 insertions(+), 30 deletions(-)

diff --git a/core/mem_region.c b/core/mem_region.c
index b3f7dc4..40f3293 100644
--- a/core/mem_region.c
+++ b/core/mem_region.c
@@ -971,11 +971,30 @@ void mem_region_release_unused(void)
 	unlock(&mem_region_lock);
 }
 
+static void mem_region_add_dt_reserved_node(struct dt_node *parent,
+		struct mem_region *region)
+{
+	char *name, *p;
+
+	name = strdup(region->name);
+
+	/* remove any cell addresses in the region name; we have our own cell
+	 * addresses here */
+	p = strchr(name, '@');
+	if (p)
+		*p = '\0';
+
+	region->node = dt_new_addr(parent, name, region->start);
+	dt_add_property_u64s(region->node, "reg", region->start, region->len);
+	free(name);
+}
+
 void mem_region_add_dt_reserved(void)
 {
 	int names_len, ranges_len, len;
 	struct mem_region *region;
 	void *names, *ranges;
+	struct dt_node *node;
 	uint64_t *range;
 	char *name;
 
@@ -988,6 +1007,12 @@ void mem_region_add_dt_reserved(void)
 	lock(&mem_region_lock);
 	mem_regions_finalised = true;
 
+	/* establish top-level reservation node */
+	node = dt_new(dt_root, "reserved-memory");
+	dt_add_property_cells(node, "#address-cells", 2);
+	dt_add_property_cells(node, "#size-cells", 2);
+	dt_add_property(node, "ranges", NULL, 0);
+
 	/* First pass: calculate length of property data */
 	list_for_each(&regions, region, list) {
 		if (!region_is_reserved(region))
@@ -1013,6 +1038,8 @@ void mem_region_add_dt_reserved(void)
 		       (long long)(region->start + region->len - 1),
 		       region->name);
 
+		mem_region_add_dt_reserved_node(node, region);
+
 		range[0] = cpu_to_fdt64(region->start);
 		range[1] = cpu_to_fdt64(region->len);
 		range += 2;
diff --git a/core/test/run-mem_region_reservations.c b/core/test/run-mem_region_reservations.c
index 3288432..fcde110 100644
--- a/core/test/run-mem_region_reservations.c
+++ b/core/test/run-mem_region_reservations.c
@@ -112,13 +112,83 @@ static struct {
 	{ "test.3", 0x4000, false },
 };
 
-int main(void)
+static void check_property_reservations(void)
 {
 	const struct dt_property *names, *ranges;
-	struct mem_region *r;
-	unsigned int i, l, c;
-	uint64_t *rangep;
+	unsigned int i, l;
 	const char *name;
+	uint64_t *rangep;
+
+	/* check dt properties */
+	names = dt_find_property(dt_root, "reserved-names");
+	ranges = dt_find_property(dt_root, "reserved-ranges");
+
+	assert(names && ranges);
+
+	/* walk through names & ranges properies, ensuring that the test
+	 * regions are all present */
+	for (name = names->prop, rangep = (uint64_t *)ranges->prop;
+			name < names->prop + names->len;
+			name += l, rangep += 2) {
+		uint64_t addr;
+
+		addr = dt_get_number(rangep, 2);
+		l = strlen(name) + 1;
+
+		for (i = 0; i < ARRAY_SIZE(test_regions); i++) {
+			if (strcmp(test_regions[i].name, name))
+				continue;
+			assert(test_regions[i].addr == addr);
+			assert(!test_regions[i].found);
+			test_regions[i].found = true;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(test_regions); i++) {
+		assert(test_regions[i].found);
+		test_regions[i].found = false;
+	}
+}
+
+static void check_node_reservations(void)
+{
+	struct dt_node *parent, *node;
+	unsigned int i;
+
+	parent = dt_find_by_name(dt_root, "reserved-memory");
+	assert(parent);
+
+	assert(dt_prop_get_cell(parent, "#address-cells", 0) == 2);
+	assert(dt_prop_get_cell(parent, "#size-cells", 0) == 2);
+	dt_require_property(parent, "ranges", 0);
+
+	dt_for_each_child(parent, node) {
+		uint64_t addr, size;
+
+		addr = dt_get_address(node, 0, &size);
+
+		for (i = 0; i < ARRAY_SIZE(test_regions); i++) {
+			if (strncmp(test_regions[i].name, node->name,
+						strlen(test_regions[i].name)))
+				continue;
+
+			assert(!test_regions[i].found);
+			assert(test_regions[i].addr == addr);
+			assert(size = 0x1000);
+			test_regions[i].found = true;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(test_regions); i++) {
+		assert(test_regions[i].found);
+		test_regions[i].found = false;
+	}
+}
+
+int main(void)
+{
+	struct mem_region *r;
+	unsigned int i;
 	void *buf;
 
 	/* Use malloc for the heap, so valgrind can find issues. */
@@ -150,33 +220,11 @@ int main(void)
 	r = new_region("test.4", 0x5000, 0x1000, NULL, REGION_RESERVED);
 	assert(!add_region(r));
 
-	/* check dt properties */
-	names = dt_find_property(dt_root, "reserved-names");
-	ranges = dt_find_property(dt_root, "reserved-ranges");
-
-	assert(names && ranges);
-
-	/* walk through names & ranges properies, ensuring that the test
-	 * regions are all present */
-	for (name = names->prop, rangep = (uint64_t *)ranges->prop, c = 0;
-			name < names->prop + names->len;
-			name += l, rangep += 2) {
-		uint64_t addr;
-
-		addr = dt_get_number(rangep, 2);
-		l = strlen(name) + 1;
-
-		for (i = 0; i < ARRAY_SIZE(test_regions); i++) {
-			if (strcmp(test_regions[i].name, name))
-				continue;
-			assert(test_regions[i].addr == addr);
-			assert(!test_regions[i].found);
-			test_regions[i].found = true;
-			c++;
-		}
-	}
+	/* check old property-style reservations */
+	check_property_reservations();
 
-	assert(c == ARRAY_SIZE(test_regions));
+	/* and new node-style reservations */
+	check_node_reservations();
 
 	dt_free(dt_root);
 	real_free(buf);
diff --git a/doc/device-tree/reserved-memory.txt b/doc/device-tree/reserved-memory.txt
new file mode 100644
index 0000000..0f6002d
--- /dev/null
+++ b/doc/device-tree/reserved-memory.txt
@@ -0,0 +1,27 @@
+reserved-memory device tree nodes
+
+OPAL exposes reserved memory through a top-level reserved-memory node,
+containing subnodes that represent each reserved memory region.
+
+This follows the Linux specification for the /reserved-memory node,
+described in the kernel source tree, in:
+
+  Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt
+
+The top-level /reserved-memory node contains:
+
+  #size-cells = <2>
+  #address-cells = <2>
+   - addresses and sizes are all 64-bits
+
+  ranges;
+   - the empty ranges node indicates no translation of physical
+     addresses in the subnodes.
+
+The sub-nodes under the /reserved-memory node contain:
+
+ reg = <address size>
+  - the address and size of the reserved memory region. The address
+    and size values are two cells each, as signified by the top-level
+    #{address,size}-cells
+


More information about the Skiboot mailing list