lib: utils/fdt: Allow to use reg-names when parsing ACLINT
authorInochi Amaoto <inochiama@outlook.com>
Fri, 17 Nov 2023 12:13:09 +0000 (20:13 +0800)
committerAnup Patel <anup@brainfault.org>
Mon, 11 Dec 2023 05:05:32 +0000 (10:35 +0530)
Currently, the fdt_parse_aclint_node() follows a fixed order to parse
ACLINT timer. This may cause the undesirable result when the ACLINT
device does not support mtime without adding an empty entry for it in
the DT.

To be robust, make fdt_parse_aclint_node() support "reg-names" property,
so it can parse the DT in an order independent way. For compatibility,
fdt_parse_aclint_node() only use "reg-names" when parsing ACLINT timer,
and will fallback to the old way if "reg-names" property is not found.

Link: https://lore.kernel.org/all/20231114-skedaddle-precinct-66c8897227bb@squawk/
Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
Reviewed-by: Anup patel <anup@brainfault.org>
include/sbi_utils/fdt/fdt_helper.h
lib/utils/fdt/fdt_helper.c

index 5c928ffd72cc96dc87fd108c03c74de2b83560a7..430d8180a9be4bd6748168b997b7f1f8f7b5f35e 100644 (file)
@@ -48,6 +48,9 @@ int fdt_parse_phandle_with_args(void *fdt, int nodeoff,
 int fdt_get_node_addr_size(void *fdt, int node, int index,
                           uint64_t *addr, uint64_t *size);
 
+int fdt_get_node_addr_size_by_name(void *fdt, int node, const char *name,
+                                  uint64_t *addr, uint64_t *size);
+
 bool fdt_node_is_enabled(void *fdt, int nodeoff);
 
 int fdt_parse_hart_id(void *fdt, int cpu_offset, u32 *hartid);
index 35be7baba444eba531fb7103e0cddfa93deb6aef..78c1f380793823923f2c4c00d51b74b35bb8adbd 100644 (file)
@@ -216,6 +216,32 @@ int fdt_get_node_addr_size(void *fdt, int node, int index,
        return 0;
 }
 
+int fdt_get_node_addr_size_by_name(void *fdt, int node, const char *name,
+                                  uint64_t *addr, uint64_t *size)
+{
+       int i, j, count;
+       const char *val;
+       const char *regname;
+
+       if (!fdt || node < 0 || !name)
+               return SBI_EINVAL;
+
+       val = fdt_getprop(fdt, node, "reg-names", &count);
+       if (!val)
+               return SBI_ENODEV;
+
+       for (i = 0, j = 0; i < count; i++, j++) {
+               regname = val + i;
+
+               if (strcmp(name, regname) == 0)
+                       return fdt_get_node_addr_size(fdt, node, j, addr, size);
+
+               i += strlen(regname);
+       }
+
+       return SBI_ENODEV;
+}
+
 bool fdt_node_is_enabled(void *fdt, int nodeoff)
 {
        int len;
@@ -874,21 +900,40 @@ int fdt_parse_plic(void *fdt, struct plic_data *plic, const char *compat)
        return fdt_parse_plic_node(fdt, nodeoffset, plic);
 }
 
-int fdt_parse_aclint_node(void *fdt, int nodeoffset, bool for_timer,
-                         unsigned long *out_addr1, unsigned long *out_size1,
-                         unsigned long *out_addr2, unsigned long *out_size2,
-                         u32 *out_first_hartid, u32 *out_hart_count)
+static int fdt_get_aclint_addr_size_by_name(void *fdt, int nodeoffset,
+                                           unsigned long *out_addr1,
+                                           unsigned long *out_size1,
+                                           unsigned long *out_addr2,
+                                           unsigned long *out_size2)
 {
-       const fdt32_t *val;
+       int rc;
        uint64_t reg_addr, reg_size;
-       int i, rc, count, cpu_offset, cpu_intc_offset;
-       u32 phandle, hwirq, hartid, first_hartid, last_hartid, hart_count;
-       u32 match_hwirq = (for_timer) ? IRQ_M_TIMER : IRQ_M_SOFT;
 
-       if (nodeoffset < 0 || !fdt ||
-           !out_addr1 || !out_size1 ||
-           !out_first_hartid || !out_hart_count)
-               return SBI_EINVAL;
+       rc = fdt_get_node_addr_size_by_name(fdt, nodeoffset, "mtime",
+                                           &reg_addr, &reg_size);
+       if (rc < 0 || !reg_size)
+               reg_addr = reg_size = 0;
+       *out_addr1 = reg_addr;
+       *out_size1 = reg_size;
+
+       rc = fdt_get_node_addr_size_by_name(fdt, nodeoffset, "mtimecmp",
+                                           &reg_addr, &reg_size);
+       if (rc < 0 || !reg_size)
+               return SBI_ENODEV;
+       *out_addr2 = reg_addr;
+       *out_size2 = reg_size;
+
+       return 0;
+}
+
+static int fdt_get_aclint_addr_size(void *fdt, int nodeoffset,
+                                   unsigned long *out_addr1,
+                                   unsigned long *out_size1,
+                                   unsigned long *out_addr2,
+                                   unsigned long *out_size2)
+{
+       int rc;
+       uint64_t reg_addr, reg_size;
 
        rc = fdt_get_node_addr_size(fdt, nodeoffset, 0,
                                    &reg_addr, &reg_size);
@@ -906,6 +951,36 @@ int fdt_parse_aclint_node(void *fdt, int nodeoffset, bool for_timer,
        if (out_size2)
                *out_size2 = reg_size;
 
+       return 0;
+}
+
+int fdt_parse_aclint_node(void *fdt, int nodeoffset, bool for_timer,
+                         unsigned long *out_addr1, unsigned long *out_size1,
+                         unsigned long *out_addr2, unsigned long *out_size2,
+                         u32 *out_first_hartid, u32 *out_hart_count)
+{
+       const fdt32_t *val;
+       int i, rc, count, cpu_offset, cpu_intc_offset;
+       u32 phandle, hwirq, hartid, first_hartid, last_hartid, hart_count;
+       u32 match_hwirq = (for_timer) ? IRQ_M_TIMER : IRQ_M_SOFT;
+
+       if (nodeoffset < 0 || !fdt ||
+           !out_addr1 || !out_size1 ||
+           !out_first_hartid || !out_hart_count)
+               return SBI_EINVAL;
+
+       if (for_timer && out_addr2 && out_size2 &&
+           fdt_getprop(fdt, nodeoffset, "reg-names", NULL))
+               rc = fdt_get_aclint_addr_size_by_name(fdt, nodeoffset,
+                                                     out_addr1, out_size1,
+                                                     out_addr2, out_size2);
+       else
+               rc = fdt_get_aclint_addr_size(fdt, nodeoffset,
+                                             out_addr1, out_size1,
+                                             out_addr2, out_size2);
+       if (rc)
+               return rc;
+
        *out_first_hartid = 0;
        *out_hart_count = 0;