[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <986361f4-f000-4129-8214-39f2fb4a90da@gmail.com>
Date: Fri, 5 Jul 2024 15:05:12 +0200
From: Klara Modin <klarasmodin@...il.com>
To: Oreoluwa Babatunde <quic_obabatun@...cinc.com>, robh@...nel.org,
saravanak@...gle.com, hch@....de, m.szyprowski@...sung.com,
robin.murphy@....com, will@...nel.org, catalin.marinas@....com
Cc: devicetree@...r.kernel.org, linux-kernel@...r.kernel.org,
iommu@...ts.linux.dev, kernel@...cinc.com
Subject: Re: [PATCH v6 3/4] of: reserved_mem: Use unflatten_devicetree APIs to
scan reserved memory nodes
Hi,
On 2024-05-29 00:36, Oreoluwa Babatunde wrote:
> The unflatten_devicetree APIs have been setup and are available to be
> used by the time the fdt_init_reserved_mem() function is called.
> Since the unflatten_devicetree APIs are a more efficient way of scanning
> through the DT nodes, switch to using these APIs to facilitate the rest
> of the reserved memory processing.
With this patch series, I've observed significantly less memory
available to userspace on my Raspberry Pi 1 and 3.
I see this message on the kernel console:
Jul 4 23:13:49 bonnet kernel: OF: reserved mem: 0x1b000000..0x1effffff
(65536 KiB) map non-reusable linux
where it was previously marked as reusable:
Jul 4 22:23:22 bonnet kernel: OF: reserved mem: 0x1b000000..0x1effffff
(65536 KiB) map reusable linux,cma
If I look at bcm283x.dtsi, it definitely has the reusable property.
I've below pointed out the snippet I think could be suspicous.
>
> Signed-off-by: Oreoluwa Babatunde <quic_obabatun@...cinc.com>
> ---
> drivers/of/of_reserved_mem.c | 93 ++++++++++++++++++++-------------
> include/linux/of_reserved_mem.h | 2 +-
> kernel/dma/coherent.c | 10 ++--
> kernel/dma/contiguous.c | 8 +--
> kernel/dma/swiotlb.c | 10 ++--
> 5 files changed, 72 insertions(+), 51 deletions(-)
>
> diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
> index 113d593ea031..05283cd24c3b 100644
> --- a/drivers/of/of_reserved_mem.c
> +++ b/drivers/of/of_reserved_mem.c
> @@ -14,6 +14,7 @@
> #include <linux/err.h>
> #include <linux/libfdt.h>
> #include <linux/of.h>
> +#include <linux/of_address.h>
> #include <linux/of_fdt.h>
> #include <linux/of_platform.h>
> #include <linux/mm.h>
> @@ -99,7 +100,7 @@ static void __init alloc_reserved_mem_array(void)
> /*
> * fdt_reserved_mem_save_node() - save fdt node for second pass initialization
> */
> -static void __init fdt_reserved_mem_save_node(unsigned long node, const char *uname,
> +static void __init fdt_reserved_mem_save_node(struct device_node *node, const char *uname,
> phys_addr_t base, phys_addr_t size)
> {
> struct reserved_mem *rmem = &reserved_mem[reserved_mem_count];
> @@ -109,7 +110,7 @@ static void __init fdt_reserved_mem_save_node(unsigned long node, const char *un
> return;
> }
>
> - rmem->fdt_node = node;
> + rmem->dev_node = node;
> rmem->name = uname;
> rmem->base = base;
> rmem->size = size;
> @@ -178,11 +179,11 @@ static int __init __reserved_mem_reserve_reg(unsigned long node,
> }
>
> /*
> - * __reserved_mem_check_root() - check if #size-cells, #address-cells provided
> + * __fdt_reserved_mem_check_root() - check if #size-cells, #address-cells provided
> * in /reserved-memory matches the values supported by the current implementation,
> * also check if ranges property has been provided
> */
> -static int __init __reserved_mem_check_root(unsigned long node)
> +static int __init __fdt_reserved_mem_check_root(unsigned long node)
> {
> const __be32 *prop;
>
> @@ -200,6 +201,35 @@ static int __init __reserved_mem_check_root(unsigned long node)
> return 0;
> }
>
> +/*
> + * of_reserved_mem_check_root() - check if #size-cells, #address-cells provided
> + * in /reserved-memory matches the values supported by the current implementation,
> + * also check if ranges property has been provided
> + */
> +static int __init of_reserved_mem_check_root(struct device_node *node)
> +{
> + u32 prop;
> + int ret;
> +
> + ret = of_property_read_u32(node, "#size-cells", &prop);
> + if (ret)
> + return ret;
> +
> + if (prop != dt_root_size_cells)
> + return -EINVAL;
> +
> + ret = of_property_read_u32(node, "#address-cells", &prop);
> + if (ret)
> + return ret;
> +
> + if (prop != dt_root_addr_cells)
> + return -EINVAL;
> +
> + if (!of_property_present(node, "ranges"))
> + return -EINVAL;
> + return 0;
> +}
> +
> /**
> * fdt_scan_reserved_mem_reg_nodes() - Store info for the "reg" defined
> * reserved memory regions.
> @@ -212,41 +242,40 @@ static int __init __reserved_mem_check_root(unsigned long node)
> */
> static void __init fdt_scan_reserved_mem_reg_nodes(void)
> {
> - int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32);
> - const void *fdt = initial_boot_params;
> + struct device_node *node, *child;
> phys_addr_t base, size;
> - const __be32 *prop;
> - int node, child;
> - int len;
>
> - node = fdt_path_offset(fdt, "/reserved-memory");
> - if (node < 0) {
> + node = of_find_node_by_path("/reserved-memory");
> + if (!node) {
> pr_info("Reserved memory: No reserved-memory node in the DT\n");
> return;
> }
>
> - if (__reserved_mem_check_root(node)) {
> + if (of_reserved_mem_check_root(node)) {
> pr_err("Reserved memory: unsupported node format, ignoring\n");
> return;
> }
>
> - fdt_for_each_subnode(child, fdt, node) {
> + for_each_child_of_node(node, child) {
> + int ret = 0;
> const char *uname;
> + struct resource res;
> + struct reserved_mem *rmem;
>
> - prop = of_get_flat_dt_prop(child, "reg", &len);
> - if (!prop)
> - continue;
> - if (!of_fdt_device_is_available(fdt, child))
> + if (!of_device_is_available(child))
> continue;
>
> - uname = fdt_get_name(fdt, child, NULL);
> - if (len && len % t_len != 0) {
> - pr_err("Reserved memory: invalid reg property in '%s', skipping node.\n",
> - uname);
> + ret = of_address_to_resource(child, 0, &res);
> + if (ret) {
> + rmem = of_reserved_mem_lookup(child);
> + if (rmem)
> + rmem->dev_node = child;
> continue;
> }
> - base = dt_mem_next_cell(dt_root_addr_cells, &prop);
> - size = dt_mem_next_cell(dt_root_size_cells, &prop);
> + uname = of_node_full_name(child);
> +
> + base = res.start;
> + size = res.end - res.start + 1;
>
> if (size)
> fdt_reserved_mem_save_node(child, uname, base, size);
> @@ -269,7 +298,7 @@ int __init fdt_scan_reserved_mem(void)
> if (node < 0)
> return -ENODEV;
>
> - if (__reserved_mem_check_root(node) != 0) {
> + if (__fdt_reserved_mem_check_root(node) != 0) {
> pr_err("Reserved memory: unsupported node format, ignoring\n");
> return -EINVAL;
> }
> @@ -447,7 +476,7 @@ static int __init __reserved_mem_alloc_size(unsigned long node, const char *unam
> uname, (unsigned long)(size / SZ_1M));
> return -ENOMEM;
> }
> - fdt_reserved_mem_save_node(node, uname, base, size);
> + fdt_reserved_mem_save_node(NULL, uname, base, size);
This could perhaps be suspicious?
The above message seems to come from of_init_reserved_mem_node when
called from of_reserved_mem_save_node when called from here. This would
mean that the node is not actually saved to rmem and thus not marked
reusable?
> return 0;
> }
>
> @@ -467,7 +496,7 @@ static int __init __reserved_mem_init_node(struct reserved_mem *rmem)
> reservedmem_of_init_fn initfn = i->data;
> const char *compat = i->compatible;
>
> - if (!of_flat_dt_is_compatible(rmem->fdt_node, compat))
> + if (!of_device_is_compatible(rmem->dev_node, compat))
> continue;
>
> ret = initfn(rmem);
> @@ -500,11 +529,6 @@ static int __init __rmem_cmp(const void *a, const void *b)
> if (ra->size > rb->size)
> return 1;
>
> - if (ra->fdt_node < rb->fdt_node)
> - return -1;
> - if (ra->fdt_node > rb->fdt_node)
> - return 1;
> -
> return 0;
> }
>
> @@ -551,11 +575,11 @@ void __init fdt_init_reserved_mem(void)
>
> for (i = 0; i < reserved_mem_count; i++) {
> struct reserved_mem *rmem = &reserved_mem[i];
> - unsigned long node = rmem->fdt_node;
> + struct device_node *node = rmem->dev_node;
> int err = 0;
> bool nomap;
>
> - nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;
> + nomap = of_property_present(node, "no-map");
>
> err = __reserved_mem_init_node(rmem);
> if (err != 0 && err != -ENOENT) {
> @@ -566,8 +590,7 @@ void __init fdt_init_reserved_mem(void)
> memblock_phys_free(rmem->base, rmem->size);
> } else {
> phys_addr_t end = rmem->base + rmem->size - 1;
> - bool reusable =
> - (of_get_flat_dt_prop(node, "reusable", NULL)) != NULL;
> + bool reusable = of_property_present(node, "reusable");
>
> pr_info("%pa..%pa (%lu KiB) %s %s %s\n",
> &rmem->base, &end, (unsigned long)(rmem->size / SZ_1K),
> diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h
> index e338282da652..769b8f67c8d3 100644
> --- a/include/linux/of_reserved_mem.h
> +++ b/include/linux/of_reserved_mem.h
> @@ -10,7 +10,7 @@ struct reserved_mem_ops;
>
> struct reserved_mem {
> const char *name;
> - unsigned long fdt_node;
> + struct device_node *dev_node;
> const struct reserved_mem_ops *ops;
> phys_addr_t base;
> phys_addr_t size;
> diff --git a/kernel/dma/coherent.c b/kernel/dma/coherent.c
> index ff5683a57f77..8f99586204fb 100644
> --- a/kernel/dma/coherent.c
> +++ b/kernel/dma/coherent.c
> @@ -362,20 +362,18 @@ static const struct reserved_mem_ops rmem_dma_ops = {
>
> static int __init rmem_dma_setup(struct reserved_mem *rmem)
> {
> - unsigned long node = rmem->fdt_node;
> + struct device_node *node = rmem->dev_node;
>
> - if (of_get_flat_dt_prop(node, "reusable", NULL))
> + if (of_property_present(node, "reusable"))
> return -EINVAL;
>
> -#ifdef CONFIG_ARM
> - if (!of_get_flat_dt_prop(node, "no-map", NULL)) {
> + if (IS_ENABLED(CONFIG_ARM) && !of_property_present(node, "no-map")) {
> pr_err("Reserved memory: regions without no-map are not yet supported\n");
> return -EINVAL;
> }
> -#endif
>
> #ifdef CONFIG_DMA_GLOBAL_POOL
> - if (of_get_flat_dt_prop(node, "linux,dma-default", NULL)) {
> + if (of_property_present(node, "linux,dma-default")) {
> WARN(dma_reserved_default_memory,
> "Reserved memory: region for default DMA coherent area is redefined\n");
> dma_reserved_default_memory = rmem;
> diff --git a/kernel/dma/contiguous.c b/kernel/dma/contiguous.c
> index 055da410ac71..450e9e4be79c 100644
> --- a/kernel/dma/contiguous.c
> +++ b/kernel/dma/contiguous.c
> @@ -456,8 +456,8 @@ static const struct reserved_mem_ops rmem_cma_ops = {
>
> static int __init rmem_cma_setup(struct reserved_mem *rmem)
> {
> - unsigned long node = rmem->fdt_node;
> - bool default_cma = of_get_flat_dt_prop(node, "linux,cma-default", NULL);
> + struct device_node *node = rmem->dev_node;
> + bool default_cma = of_property_read_bool(node, "linux,cma-default");
> struct cma *cma;
> int err;
>
> @@ -467,8 +467,8 @@ static int __init rmem_cma_setup(struct reserved_mem *rmem)
> return -EBUSY;
> }
>
> - if (!of_get_flat_dt_prop(node, "reusable", NULL) ||
> - of_get_flat_dt_prop(node, "no-map", NULL))
> + if (!of_property_present(node, "reusable") ||
> + of_property_present(node, "no-map"))
> return -EINVAL;
>
> if (!IS_ALIGNED(rmem->base | rmem->size, CMA_MIN_ALIGNMENT_BYTES)) {
> diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c
> index fe1ccb53596f..9949ddc14272 100644
> --- a/kernel/dma/swiotlb.c
> +++ b/kernel/dma/swiotlb.c
> @@ -1859,12 +1859,12 @@ static const struct reserved_mem_ops rmem_swiotlb_ops = {
>
> static int __init rmem_swiotlb_setup(struct reserved_mem *rmem)
> {
> - unsigned long node = rmem->fdt_node;
> + struct device_node *node = rmem->dev_node;
>
> - if (of_get_flat_dt_prop(node, "reusable", NULL) ||
> - of_get_flat_dt_prop(node, "linux,cma-default", NULL) ||
> - of_get_flat_dt_prop(node, "linux,dma-default", NULL) ||
> - of_get_flat_dt_prop(node, "no-map", NULL))
> + if (of_property_present(node, "reusable") ||
> + of_property_present(node, "linux,cma-default") ||
> + of_property_present(node, "linux,dma-default") ||
> + of_property_present(node, "no-map"))
> return -EINVAL;
>
> rmem->ops = &rmem_swiotlb_ops;
Regards,
Klara Modin
Powered by blists - more mailing lists