#define __RISCV_ISA_EXT_DATA(_name, _id) {     \
        .name = #_name,                         \
+       .property = #_name,                     \
        .id = _id,                              \
 }
 
                acpi_put_table((struct acpi_table_header *)rhct);
 }
 
+static int __init riscv_fill_hwcap_from_ext_list(unsigned long *isa2hwcap)
+{
+       unsigned int cpu;
+
+       for_each_possible_cpu(cpu) {
+               unsigned long this_hwcap = 0;
+               struct device_node *cpu_node;
+               struct riscv_isainfo *isainfo = &hart_isa[cpu];
+
+               cpu_node = of_cpu_device_node_get(cpu);
+               if (!cpu_node) {
+                       pr_warn("Unable to find cpu node\n");
+                       continue;
+               }
+
+               if (!of_property_present(cpu_node, "riscv,isa-extensions")) {
+                       of_node_put(cpu_node);
+                       continue;
+               }
+
+               for (int i = 0; i < riscv_isa_ext_count; i++) {
+                       if (of_property_match_string(cpu_node, "riscv,isa-extensions",
+                                                    riscv_isa_ext[i].property) < 0)
+                               continue;
+
+                       if (!riscv_isa_extension_check(riscv_isa_ext[i].id))
+                               continue;
+
+                       /* Only single letter extensions get set in hwcap */
+                       if (strnlen(riscv_isa_ext[i].name, 2) == 1)
+                               this_hwcap |= isa2hwcap[riscv_isa_ext[i].id];
+
+                       set_bit(riscv_isa_ext[i].id, isainfo->isa);
+               }
+
+               of_node_put(cpu_node);
+
+               /*
+                * All "okay" harts should have same isa. Set HWCAP based on
+                * common capabilities of every "okay" hart, in case they don't.
+                */
+               if (elf_hwcap)
+                       elf_hwcap &= this_hwcap;
+               else
+                       elf_hwcap = this_hwcap;
+
+               if (bitmap_empty(riscv_isa, RISCV_ISA_EXT_MAX))
+                       bitmap_copy(riscv_isa, isainfo->isa, RISCV_ISA_EXT_MAX);
+               else
+                       bitmap_and(riscv_isa, riscv_isa, isainfo->isa, RISCV_ISA_EXT_MAX);
+       }
+
+       if (bitmap_empty(riscv_isa, RISCV_ISA_EXT_MAX))
+               return -ENOENT;
+
+       return 0;
+}
+
 void __init riscv_fill_hwcap(void)
 {
        char print_str[NUM_ALPHA_EXTS + 1];
-       int i, j;
        unsigned long isa2hwcap[26] = {0};
+       int i, j;
 
        isa2hwcap['i' - 'a'] = COMPAT_HWCAP_ISA_I;
        isa2hwcap['m' - 'a'] = COMPAT_HWCAP_ISA_M;
        isa2hwcap['c' - 'a'] = COMPAT_HWCAP_ISA_C;
        isa2hwcap['v' - 'a'] = COMPAT_HWCAP_ISA_V;
 
-       riscv_fill_hwcap_from_isa_string(isa2hwcap);
+       if (!acpi_disabled) {
+               riscv_fill_hwcap_from_isa_string(isa2hwcap);
+       } else {
+               int ret = riscv_fill_hwcap_from_ext_list(isa2hwcap);
 
-       /* We don't support systems with F but without D, so mask those out
-        * here. */
+               if (ret) {
+                       pr_info("Falling back to deprecated \"riscv,isa\"\n");
+                       riscv_fill_hwcap_from_isa_string(isa2hwcap);
+               }
+       }
+
+       /*
+        * We don't support systems with F but without D, so mask those out
+        * here.
+        */
        if ((elf_hwcap & COMPAT_HWCAP_ISA_F) && !(elf_hwcap & COMPAT_HWCAP_ISA_D)) {
                pr_info("This kernel does not support systems with F but not D\n");
                elf_hwcap &= ~COMPAT_HWCAP_ISA_F;