lib: utils: Improve fdt_cpu_fixup() implementation
authorAnup Patel <anup.patel@wdc.com>
Thu, 19 Mar 2020 05:53:41 +0000 (11:23 +0530)
committerAnup Patel <anup@brainfault.org>
Sat, 28 Mar 2020 08:01:50 +0000 (13:31 +0530)
Currently, the fdt_cpu_fixup() implementation assumes:
1. We have one CPU DT for each HART under /cpus DT node
2. The CPU DT nodes are named sequentially (i.e cpu@0,
   cpu@1, ...) which is not true for discontinuous and
   sparse HART ids (i.e. cpu@0, cpu@4, cpu@5). Generally,
   CPU DT node are named based on HART id and not HART
   index

If any of the above assumptions are violated then the
fdt_cpu_fixup() will not work.

This improves fdt_cpu_fixup() implementation and makes
it independent of above assumptions.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
lib/utils/fdt/fdt_fixup.c

index b91e95f..d6e4cc1 100644 (file)
 #include <sbi/sbi_console.h>
 #include <sbi/sbi_platform.h>
 #include <sbi/sbi_scratch.h>
+#include <sbi/sbi_string.h>
 
 void fdt_cpu_fixup(void *fdt)
 {
        struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
        const struct sbi_platform *plat = sbi_platform_ptr(scratch);
-       char cpu_node[32] = "";
-       int cpu_offset;
-       int err;
-       u32 i;
+       int err, len, cpu_offset, cpus_offset;
+       const fdt32_t *val;
+       const void *prop;
+       u32 hartid;
 
        err = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 32);
        if (err < 0)
                return;
 
-       /* assume hart ids are continuous */
-       for (i = 0; i < sbi_platform_hart_count(plat); i++) {
-               sbi_sprintf(cpu_node, "/cpus/cpu@%d", i);
-               cpu_offset = fdt_path_offset(fdt, cpu_node);
+       cpus_offset = fdt_path_offset(fdt, "/cpus");
+       if (cpus_offset < 0)
+               return;
+
+       fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
+               prop = fdt_getprop(fdt, cpu_offset, "device_type", &len);
+               if (!prop || !len)
+                       continue;
+               if (sbi_strcmp(prop, "cpu"))
+                       continue;
 
-               if (sbi_platform_hart_invalid(plat, i))
+               val = fdt_getprop(fdt, cpu_offset, "reg", &len);
+               if (!val || len < sizeof(fdt32_t))
+                       continue;
+
+               if (len > sizeof(fdt32_t))
+                       val++;
+               hartid = fdt32_to_cpu(*val);
+
+               if (sbi_platform_hart_invalid(plat, hartid))
                        fdt_setprop_string(fdt, cpu_offset, "status",
                                           "disabled");
-
-               memset(cpu_node, 0, sizeof(cpu_node));
        }
 }