[PATCH v6 3/4] of: reserved_mem: Use unflatten_devicetree APIs to scan reserved memory nodes

From: Oreoluwa Babatunde
Date: Tue May 28 2024 - 18:38:06 EST


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.

Signed-off-by: Oreoluwa Babatunde <quic_obabatun@xxxxxxxxxxx>
---
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);
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;
--
2.34.1