From: Gregory CLEMENT <gregory.clement@bootlin.com>
To: Rob Herring <robh@kernel.org>,
Saravana Kannan <saravanak@google.com>,
Linus Walleij <linus.walleij@linaro.org>,
Miquel Raynal <miquel.raynal@bootlin.com>,
Richard Weinberger <richard@nod.at>,
Vignesh Raghavendra <vigneshr@ti.com>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>
Cc: "Thomas Petazzoni" <thomas.petazzoni@bootlin.com>,
"Vladimir Kondratiev" <vladimir.kondratiev@mobileye.com>,
"Benoît Monin" <benoit.monin@bootlin.com>,
"Théo Lebrun" <theo.lebrun@bootlin.com>,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-mtd@lists.infradead.org,
"Gregory CLEMENT" <gregory.clement@bootlin.com>
Subject: [PATCH 1/3] of: reserved_mem: Support multiple 'reg' entries for memory-region
Date: Mon, 17 Nov 2025 18:00:14 +0100 [thread overview]
Message-ID: <20251117-mtd-memregion-v1-1-7b35611c79a6@bootlin.com> (raw)
In-Reply-To: <20251117-mtd-memregion-v1-0-7b35611c79a6@bootlin.com>
The Device Tree specification allows a "memory-region" node to have
multiple 'reg' entries, but the current kernel implementation only
processes the first entry. This can lead to drivers not being able to
access all the reserved memory regions specified in the Device Tree.
This patch extends the reserved memory handling to support multiple
'reg' entries for a single "memory-region" node. The existing exported
functions remain unchanged for backward compatibility, but new APIs
are introduced to allow drivers to access all reserved memory regions.
Signed-off-by: Gregory CLEMENT <gregory.clement@bootlin.com>
---
drivers/of/of_reserved_mem.c | 141 ++++++++++++++++++++++++++++++++++++----
include/linux/of_reserved_mem.h | 4 ++
2 files changed, 133 insertions(+), 12 deletions(-)
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
index 2e9ea751ed2df..2477933883903 100644
--- a/drivers/of/of_reserved_mem.c
+++ b/drivers/of/of_reserved_mem.c
@@ -159,6 +159,7 @@ static int __init __reserved_mem_reserve_reg(unsigned long node,
int len;
const __be32 *prop;
bool nomap;
+ int count = 0;
prop = of_get_flat_dt_prop(node, "reg", &len);
if (!prop)
@@ -183,6 +184,7 @@ static int __init __reserved_mem_reserve_reg(unsigned long node,
dma_contiguous_early_fixup(base, size);
pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %lu MiB\n",
uname, &base, (unsigned long)(size / SZ_1M));
+ count++;
} 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));
@@ -190,7 +192,7 @@ static int __init __reserved_mem_reserve_reg(unsigned long node,
len -= t_len;
}
- return 0;
+ return count;
}
/*
@@ -235,7 +237,7 @@ void __init fdt_scan_reserved_mem_reg_nodes(void)
phys_addr_t base, size;
const __be32 *prop;
int node, child;
- int len;
+ int len, i;
if (!fdt)
return;
@@ -273,12 +275,12 @@ void __init fdt_scan_reserved_mem_reg_nodes(void)
if (len > t_len)
pr_warn("%s() ignores %d regions in node '%s'\n",
__func__, len / t_len - 1, uname);
-
- base = dt_mem_next_cell(dt_root_addr_cells, &prop);
- size = dt_mem_next_cell(dt_root_size_cells, &prop);
-
- if (size)
- fdt_reserved_mem_save_node(child, uname, base, size);
+ for (i = 0; i < len; i += t_len) {
+ base = dt_mem_next_cell(dt_root_addr_cells, &prop);
+ size = dt_mem_next_cell(dt_root_size_cells, &prop);
+ if (size)
+ fdt_reserved_mem_save_node(child, uname, base, size);
+ }
}
/* check for overlapping reserved regions */
@@ -308,16 +310,16 @@ int __init fdt_scan_reserved_mem(void)
fdt_for_each_subnode(child, fdt, node) {
const char *uname;
- int err;
+ int err, ret;
if (!of_fdt_device_is_available(fdt, child))
continue;
uname = fdt_get_name(fdt, child, NULL);
- err = __reserved_mem_reserve_reg(child, uname);
- if (!err)
- count++;
+ ret = __reserved_mem_reserve_reg(child, uname);
+ if (ret > 0)
+ count += ret;
/*
* Save the nodes for the dynamically-placed regions
* into an array which will be used for allocation right
@@ -750,6 +752,37 @@ struct reserved_mem *of_reserved_mem_lookup(struct device_node *np)
}
EXPORT_SYMBOL_GPL(of_reserved_mem_lookup);
+/**
+ * of_reserved_mem_array_lookup() - acquire reserved_mem array from a device node
+ * @np: node pointer of the desired reserved-memory region
+ * @rmrm: pointer to the first elemennt of the reserved_mem struct of the memory region
+ *
+ * This function allows drivers to acquire a reference to the array of the
+ * reserved_mem struct based on a device node handle.
+ *
+ * Returns the number reserved_mem elements
+ */
+int of_reserved_mem_array_lookup(struct device_node *np,
+ struct reserved_mem **rmem)
+{
+ const char *name;
+ int i, count = 0;
+
+ if (!np->full_name)
+ return 0;
+
+ name = kbasename(np->full_name);
+ for (i = 0; i < reserved_mem_count; i++)
+ if (!strcmp(reserved_mem[i].name, name)) {
+ if (!count)
+ *rmem = &reserved_mem[i];
+ count++;
+ }
+
+ return count;
+}
+EXPORT_SYMBOL_GPL(of_reserved_mem_array_lookup);
+
/**
* of_reserved_mem_region_to_resource() - Get a reserved memory region as a resource
* @np: node containing 'memory-region' property
@@ -785,6 +818,49 @@ int of_reserved_mem_region_to_resource(const struct device_node *np,
}
EXPORT_SYMBOL_GPL(of_reserved_mem_region_to_resource);
+/**
+ * of_reserved_mem_region_to_resource_array() - Get a reserved memory region as a resources
+ * @dev: device associated to the node
+ * @np: node containing 'memory-region' property
+ * @idx: index of 'memory-region' property to lookup
+ * @res: Pointer to an array of struct resource pointers to fill in with reserved regions
+ *
+ * This function allows drivers to lookup a node's 'memory-region' property
+ * entries by index and fill an array of struct resource pointers for the entries.
+ *
+ * Returns the number of resources filled in @res on success.
+ * Returns -ENODEV if 'memory-region' is missing or unavailable,
+ * -EINVAL for any other error.
+ */
+int of_reserved_mem_region_to_resource_array(struct device *dev, const struct device_node *np,
+ unsigned int idx, struct resource **res)
+{
+ struct reserved_mem *rmem;
+ int count, i;
+ struct resource *r;
+
+ if (!np)
+ return -EINVAL;
+
+ struct device_node __free(device_node) *target = of_parse_phandle(np, "memory-region", idx);
+ if (!target || !of_device_is_available(target))
+ return -ENODEV;
+
+ count = of_reserved_mem_array_lookup(target, &rmem);
+ if (count <= 0)
+ return -EINVAL;
+
+ *res = devm_kzalloc(dev, count * sizeof(struct resource), GFP_KERNEL);
+ r = res[0];
+ for (i = 0; i < count; i++) {
+ resource_set_range(&r[i], rmem[i].base, rmem[i].size);
+ r[i].flags = IORESOURCE_MEM;
+ r[i].name = rmem[i].name;
+ }
+ return count;
+}
+EXPORT_SYMBOL_GPL(of_reserved_mem_region_to_resource_array);
+
/**
* of_reserved_mem_region_to_resource_byname() - Get a reserved memory region as a resource
* @np: node containing 'memory-region' property
@@ -829,3 +905,44 @@ int of_reserved_mem_region_count(const struct device_node *np)
return of_count_phandle_with_args(np, "memory-region", NULL);
}
EXPORT_SYMBOL_GPL(of_reserved_mem_region_count);
+
+/**
+ * of_reserved_mem_region_count() - Return the total number of reserved memory regions
+ * @np: node containing 'memory-region' property
+ *
+ * This function counts the total number of reserved memory regions referenced
+ * by a node's 'memory-region' property. It iterates over each phandle and sums
+ * the number of regions found in each referenced reserved memory node.
+ *
+ * Returns the total number of reserved memory regions on success.
+ * This function allows drivers to retrieve the number of entries for a node's
+ * 'memory-region' property.
+ *
+ * Returns total number of reserved memory regions on success, or negative error
+ * code on a malformed property.
+ */
+int of_reserved_mem_region_total_count(const struct device_node *np)
+{
+ int nregion = of_count_phandle_with_args(np, "memory-region", NULL);
+ struct device_node *target;
+ int i, nregs = 0;
+
+ for (i = 0; i < nregion; i++) {
+ struct reserved_mem *rmem;
+
+ target = of_parse_phandle(np, "memory-region", i);
+ if (!target)
+ return -ENODEV;
+
+ if (!of_device_is_available(target)) {
+ of_node_put(target);
+ return 0;
+ }
+
+ nregs += of_reserved_mem_array_lookup(target, &rmem);
+
+ of_node_put(target);
+ };
+ return nregs;
+}
+EXPORT_SYMBOL_GPL(of_reserved_mem_region_total_count);
diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h
index f573423359f48..1e0c6afddd812 100644
--- a/include/linux/of_reserved_mem.h
+++ b/include/linux/of_reserved_mem.h
@@ -40,11 +40,15 @@ int of_reserved_mem_device_init_by_name(struct device *dev,
void of_reserved_mem_device_release(struct device *dev);
struct reserved_mem *of_reserved_mem_lookup(struct device_node *np);
+int of_reserved_mem_array_lookup(struct device_node *np, struct reserved_mem **rmem);
int of_reserved_mem_region_to_resource(const struct device_node *np,
unsigned int idx, struct resource *res);
+int of_reserved_mem_region_to_resource_array(struct device *dev, const struct device_node *np,
+ unsigned int idx, struct resource **res);
int of_reserved_mem_region_to_resource_byname(const struct device_node *np,
const char *name, struct resource *res);
int of_reserved_mem_region_count(const struct device_node *np);
+int of_reserved_mem_region_total_count(const struct device_node *np);
#else
--
2.51.0
next prev parent reply other threads:[~2025-11-17 17:00 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-17 17:00 [PATCH 0/3] MTD physmap: Adding reserved RAM support and fixing reserved_mem limitations Gregory CLEMENT
2025-11-17 17:00 ` Gregory CLEMENT [this message]
2025-11-17 18:04 ` [PATCH 1/3] of: reserved_mem: Support multiple 'reg' entries for memory-region Rob Herring
2025-11-17 17:00 ` [PATCH 2/3] dt-bindings: mtd: physmap: Allow using memory-region to access memory resources Gregory CLEMENT
2025-11-17 17:59 ` Rob Herring
2025-11-19 9:47 ` Gregory CLEMENT
2025-11-17 17:00 ` [PATCH 3/3] mtd: physmap: Add support for RAM reserved memory regions Gregory CLEMENT
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251117-mtd-memregion-v1-1-7b35611c79a6@bootlin.com \
--to=gregory.clement@bootlin.com \
--cc=benoit.monin@bootlin.com \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=krzk+dt@kernel.org \
--cc=linus.walleij@linaro.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mtd@lists.infradead.org \
--cc=miquel.raynal@bootlin.com \
--cc=richard@nod.at \
--cc=robh@kernel.org \
--cc=saravanak@google.com \
--cc=theo.lebrun@bootlin.com \
--cc=thomas.petazzoni@bootlin.com \
--cc=vigneshr@ti.com \
--cc=vladimir.kondratiev@mobileye.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).