[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251117180435.GB225586-robh@kernel.org>
Date: Mon, 17 Nov 2025 12:04:35 -0600
From: Rob Herring <robh@...nel.org>
To: Gregory CLEMENT <gregory.clement@...tlin.com>
Cc: Saravana Kannan <saravanak@...gle.com>,
Linus Walleij <linus.walleij@...aro.org>,
Miquel Raynal <miquel.raynal@...tlin.com>,
Richard Weinberger <richard@....at>,
Vignesh Raghavendra <vigneshr@...com>,
Krzysztof Kozlowski <krzk+dt@...nel.org>,
Conor Dooley <conor+dt@...nel.org>,
Thomas Petazzoni <thomas.petazzoni@...tlin.com>,
Vladimir Kondratiev <vladimir.kondratiev@...ileye.com>,
Benoît Monin <benoit.monin@...tlin.com>,
Théo Lebrun <theo.lebrun@...tlin.com>,
devicetree@...r.kernel.org, linux-kernel@...r.kernel.org,
linux-arm-kernel@...ts.infradead.org, linux-mtd@...ts.infradead.org
Subject: Re: [PATCH 1/3] of: reserved_mem: Support multiple 'reg' entries for
memory-region
On Mon, Nov 17, 2025 at 06:00:14PM +0100, Gregory CLEMENT wrote:
> 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@...tlin.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);
FYI, there's some changes around this code in flight.
> -
> - 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);
Do you need this function? I'm trying to do away with drivers using
struct reserved_mem in favor of the resource functions.
> +
> /**
> * 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);
Do you have a user?
Rob
Powered by blists - more mailing lists