[Skiboot] [PATCH] core: Add node-style memory reservation to device tree
Jeremy Kerr
jk at ozlabs.org
Thu May 7 19:26:37 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 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 | 26 +++++
3 files changed, 131 insertions(+), 30 deletions(-)
diff --git a/core/mem_region.c b/core/mem_region.c
index 3cc8ae0..56601e0 100644
--- a/core/mem_region.c
+++ b/core/mem_region.c
@@ -918,11 +918,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)
+{
+ struct dt_node *node;
+ 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';
+
+ node = dt_new_addr(parent, name, region->start);
+ dt_add_property_u64s(node, "reg", region->start, region->len);
+}
+
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;
@@ -936,6 +955,12 @@ void mem_region_add_dt_reserved(void)
mem_regions_finalised = true;
unlock(&mem_region_lock);
+ /* 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(®ions, region, list) {
if (!region_is_reserved(region))
@@ -961,6 +986,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 b33827f..8be3e67 100644
--- a/core/test/run-mem_region_reservations.c
+++ b/core/test/run-mem_region_reservations.c
@@ -108,13 +108,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. */
@@ -146,33 +216,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);
free((void *)(long)skiboot_heap.start);
diff --git a/doc/device-tree/reserved-memory.txt b/doc/device-tree/reserved-memory.txt
new file mode 100644
index 0000000..48e32d4
--- /dev/null
+++ b/doc/device-tree/reserved-memory.txt
@@ -0,0 +1,26 @@
+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 sig
+
More information about the Skiboot
mailing list