return 0;
}
-static int fdt_get_isa_string(void *fdt, unsigned int hartid,
- const char **isa_string)
-{
- int err, cpu_offset, cpus_offset, len;
- u32 c_hartid;
- const fdt32_t *val;
-
- if (!fdt)
- return SBI_EINVAL;
-
- cpus_offset = fdt_path_offset(fdt, "/cpus");
- if (cpus_offset < 0)
- return cpus_offset;
-
- fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
- err = fdt_parse_hart_id(fdt, cpu_offset, &c_hartid);
- if (err)
- continue;
-
- if (!fdt_node_is_enabled(fdt, cpu_offset))
- continue;
-
- if (c_hartid == hartid) {
- val = fdt_getprop(fdt, cpu_offset, "riscv,isa", &len);
- if (val && len > 0) {
- *isa_string = (const char *)val;
- return 0;
- }
- }
- }
-
- return SBI_EINVAL;
-}
-
#define RISCV_ISA_EXT_NAME_LEN_MAX 32
-int fdt_parse_isa_extensions(void *fdt, unsigned int hartid,
- unsigned long *extensions)
+static unsigned long fdt_isa_bitmap_offset;
+
+static int fdt_parse_isa_one_hart(const char *isa, unsigned long *extensions)
{
size_t i, j, isa_len;
char mstr[RISCV_ISA_EXT_NAME_LEN_MAX];
- const char *isa = NULL;
-
- if (fdt_get_isa_string(fdt, hartid, &isa))
- return SBI_EINVAL;
-
- if (!isa)
- return SBI_EINVAL;
i = 0;
isa_len = strlen(isa);
return 0;
}
+static int fdt_parse_isa_all_harts(void *fdt)
+{
+ u32 hartid;
+ const fdt32_t *val;
+ unsigned long *hart_exts;
+ struct sbi_scratch *scratch;
+ int err, cpu_offset, cpus_offset, len;
+
+ if (!fdt || !fdt_isa_bitmap_offset)
+ return SBI_EINVAL;
+
+ cpus_offset = fdt_path_offset(fdt, "/cpus");
+ if (cpus_offset < 0)
+ return cpus_offset;
+
+ fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
+ err = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
+ if (err)
+ continue;
+
+ if (!fdt_node_is_enabled(fdt, cpu_offset))
+ continue;
+
+ val = fdt_getprop(fdt, cpu_offset, "riscv,isa", &len);
+ if (!val || len <= 0)
+ return SBI_ENOENT;
+
+ scratch = sbi_hartid_to_scratch(hartid);
+ if (!scratch)
+ return SBI_ENOENT;
+
+ hart_exts = sbi_scratch_offset_ptr(scratch,
+ fdt_isa_bitmap_offset);
+ if (!hart_exts)
+ return SBI_ENOENT;
+
+ err = fdt_parse_isa_one_hart((const char *)val, hart_exts);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+int fdt_parse_isa_extensions(void *fdt, unsigned int hartid,
+ unsigned long *extensions)
+{
+ int rc, i;
+ unsigned long *hart_exts;
+ struct sbi_scratch *scratch;
+
+ if (!fdt_isa_bitmap_offset) {
+ fdt_isa_bitmap_offset = sbi_scratch_alloc_offset(
+ sizeof(*hart_exts) *
+ BITS_TO_LONGS(SBI_HART_EXT_MAX));
+ if (!fdt_isa_bitmap_offset)
+ return SBI_ENOMEM;
+
+ rc = fdt_parse_isa_all_harts(fdt);
+ if (rc)
+ return rc;
+ }
+
+ scratch = sbi_hartid_to_scratch(hartid);
+ if (!scratch)
+ return SBI_ENOENT;
+
+ hart_exts = sbi_scratch_offset_ptr(scratch, fdt_isa_bitmap_offset);
+ if (!hart_exts)
+ return SBI_ENOENT;
+
+ for (i = 0; i < BITS_TO_LONGS(SBI_HART_EXT_MAX); i++)
+ extensions[i] |= hart_exts[i];
+ return 0;
+}
+
static int fdt_parse_uart_node_common(void *fdt, int nodeoffset,
struct platform_uart_data *uart,
unsigned long default_freq,