]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
of: reserved_mem: only support one <base size> entry in reg property
authorWandun Chen <chenwandun@lixiang.com>
Mon, 25 May 2026 12:17:00 +0000 (20:17 +0800)
committerRob Herring (Arm) <robh@kernel.org>
Tue, 2 Jun 2026 15:17:39 +0000 (10:17 -0500)
A /reserved-memory child node may have multiple <base size> tuples in
'reg' property, but multiple entries in 'reg' have never been fully
functional:
 - fdt_scan_reserved_mem() in the early pass loops over every
   tuple and reserves them all.

 - fdt_scan_reserved_mem_late() reads 'reg' by
   of_flat_dt_get_addr_size(), which returns false if entries != 1.
   So 'reg' property with multiple <base size> entries will be
   skipped, no reserved_mem entry is created in reserved_mem[].

Supporting multiple <base size> tuples is not a good idea:
  - It requires reserved_mem_ops->node_init support. Currently,
    CMA(rmem_cma_setup) and DMA(rmem_dma_setup) are not supported.

  - of_reserved_mem_lookup() is name-based, only the first entry in
    multiple <base size> tuples will be found.

So change to support one <base size> entry in 'reg' property.

Also update dt binding:
  https://github.com/devicetree-org/dt-schema/pull/197

Suggested-by: Rob Herring <robh@kernel.org>
Signed-off-by: Wandun Chen <chenwandun@lixiang.com>
Tested-by: Meijing Zhao <zhaomeijing@lixiang.com>
Link: https://lore.kernel.org/all/20260506014752.GA280279-robh@kernel.org/
Link: https://patch.msgid.link/20260525121700.2706141-1-chenwandun1@gmail.com
Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
drivers/of/of_reserved_mem.c

index 8d5777cb5d1b3dfbd844c25e5529b1a02c7d504a..ce1d5530ec0fbd7b1140ab168d5144fbdd49e03b 100644 (file)
@@ -128,42 +128,43 @@ static int __init early_init_dt_reserve_memory(phys_addr_t base,
 }
 
 /*
- * __reserved_mem_reserve_reg() - reserve all memory described in 'reg' property
+ * __reserved_mem_reserve_reg() - reserve memory described in the
+ * first entry in 'reg' property
  */
 static int __init __reserved_mem_reserve_reg(unsigned long node,
                                             const char *uname)
 {
        phys_addr_t base, size;
-       int i, len, err;
+       int len, err;
        const __be32 *prop;
        bool nomap;
+       u64 b, s;
 
        prop = of_flat_dt_get_addr_size_prop(node, "reg", &len);
-       if (!prop)
+       if (!prop || !len)
                return -ENOENT;
 
+       if (len > 1)
+               pr_warn("Reserved memory: node '%s' has %d <base size> entries, only the first is used\n",
+                       uname, len);
+
        nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;
 
        err = fdt_validate_reserved_mem_node(node, NULL);
        if (err && err != -ENODEV)
                return err;
 
-       for (i = 0; i < len; i++) {
-               u64 b, s;
-
-               of_flat_dt_read_addr_size(prop, i, &b, &s);
-
-               base = b;
-               size = s;
+       of_flat_dt_read_addr_size(prop, 0, &b, &s);
+       base = b;
+       size = s;
 
-               if (size && early_init_dt_reserve_memory(base, size, nomap) == 0) {
-                       fdt_fixup_reserved_mem_node(node, base, size);
-                       pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %lu MiB\n",
-                               uname, &base, (unsigned long)(size / SZ_1M));
-               } else {
-                       pr_err("Reserved memory: failed to reserve memory for node '%s': base %pa, size %lu MiB\n",
-                              uname, &base, (unsigned long)(size / SZ_1M));
-               }
+       if (size && early_init_dt_reserve_memory(base, size, nomap) == 0) {
+               fdt_fixup_reserved_mem_node(node, base, size);
+               pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %lu MiB\n",
+                        uname, &base, (unsigned long)(size / SZ_1M));
+       } else {
+               pr_err("Reserved memory: failed to reserve memory for node '%s': base %pa, size %lu MiB\n",
+                      uname, &base, (unsigned long)(size / SZ_1M));
        }
        return 0;
 }
@@ -274,20 +275,24 @@ void __init fdt_scan_reserved_mem_late(void)
        }
 
        fdt_for_each_subnode(child, fdt, node) {
+               const __be32 *prop;
                const char *uname;
                u64 b, s;
                int ret;
+               int len;
 
                if (!of_fdt_device_is_available(fdt, child))
                        continue;
 
-               if (!of_flat_dt_get_addr_size(child, "reg", &b, &s))
+               prop = of_flat_dt_get_addr_size_prop(child, "reg", &len);
+               if (!prop || !len)
                        continue;
 
                ret = fdt_validate_reserved_mem_node(child, NULL);
                if (ret && ret != -ENODEV)
                        continue;
 
+               of_flat_dt_read_addr_size(prop, 0, &b, &s);
                base = b;
                size = s;