*
  * NOTE: If isa_bitmap is NULL then Host ISA bitmap will be used.
  */
-bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, int bit)
+bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, unsigned int bit)
 {
        const unsigned long *bmap = (isa_bitmap) ? isa_bitmap : riscv_isa;
 
                        return false;
                }
                return true;
+       case RISCV_ISA_EXT_INVALID:
+               return false;
        }
 
        return true;
 }
 
-#define __RISCV_ISA_EXT_DATA(_name, _id) {     \
-       .name = #_name,                         \
-       .property = #_name,                     \
-       .id = _id,                              \
+#define _RISCV_ISA_EXT_DATA(_name, _id, _subset_exts, _subset_exts_size) {     \
+       .name = #_name,                                                         \
+       .property = #_name,                                                     \
+       .id = _id,                                                              \
+       .subset_ext_ids = _subset_exts,                                         \
+       .subset_ext_size = _subset_exts_size                                    \
 }
 
+#define __RISCV_ISA_EXT_DATA(_name, _id) _RISCV_ISA_EXT_DATA(_name, _id, NULL, 0)
+
+/* Used to declare pure "lasso" extension (Zk for instance) */
+#define __RISCV_ISA_EXT_BUNDLE(_name, _bundled_exts) \
+       _RISCV_ISA_EXT_DATA(_name, RISCV_ISA_EXT_INVALID, _bundled_exts, ARRAY_SIZE(_bundled_exts))
+
+static const unsigned int riscv_zk_bundled_exts[] = {
+       RISCV_ISA_EXT_ZBKB,
+       RISCV_ISA_EXT_ZBKC,
+       RISCV_ISA_EXT_ZBKX,
+       RISCV_ISA_EXT_ZKND,
+       RISCV_ISA_EXT_ZKNE,
+       RISCV_ISA_EXT_ZKR,
+       RISCV_ISA_EXT_ZKT,
+};
+
+static const unsigned int riscv_zkn_bundled_exts[] = {
+       RISCV_ISA_EXT_ZBKB,
+       RISCV_ISA_EXT_ZBKC,
+       RISCV_ISA_EXT_ZBKX,
+       RISCV_ISA_EXT_ZKND,
+       RISCV_ISA_EXT_ZKNE,
+       RISCV_ISA_EXT_ZKNH,
+};
+
+static const unsigned int riscv_zks_bundled_exts[] = {
+       RISCV_ISA_EXT_ZBKB,
+       RISCV_ISA_EXT_ZBKC,
+       RISCV_ISA_EXT_ZKSED,
+       RISCV_ISA_EXT_ZKSH
+};
+
 /*
  * The canonical order of ISA extension names in the ISA string is defined in
  * chapter 27 of the unprivileged specification.
        __RISCV_ISA_EXT_DATA(zba, RISCV_ISA_EXT_ZBA),
        __RISCV_ISA_EXT_DATA(zbb, RISCV_ISA_EXT_ZBB),
        __RISCV_ISA_EXT_DATA(zbc, RISCV_ISA_EXT_ZBC),
+       __RISCV_ISA_EXT_DATA(zbkb, RISCV_ISA_EXT_ZBKB),
+       __RISCV_ISA_EXT_DATA(zbkc, RISCV_ISA_EXT_ZBKC),
+       __RISCV_ISA_EXT_DATA(zbkx, RISCV_ISA_EXT_ZBKX),
        __RISCV_ISA_EXT_DATA(zbs, RISCV_ISA_EXT_ZBS),
+       __RISCV_ISA_EXT_BUNDLE(zk, riscv_zk_bundled_exts),
+       __RISCV_ISA_EXT_BUNDLE(zkn, riscv_zkn_bundled_exts),
+       __RISCV_ISA_EXT_DATA(zknd, RISCV_ISA_EXT_ZKND),
+       __RISCV_ISA_EXT_DATA(zkne, RISCV_ISA_EXT_ZKNE),
+       __RISCV_ISA_EXT_DATA(zknh, RISCV_ISA_EXT_ZKNH),
+       __RISCV_ISA_EXT_DATA(zkr, RISCV_ISA_EXT_ZKR),
+       __RISCV_ISA_EXT_BUNDLE(zks, riscv_zks_bundled_exts),
+       __RISCV_ISA_EXT_DATA(zkt, RISCV_ISA_EXT_ZKT),
+       __RISCV_ISA_EXT_DATA(zksed, RISCV_ISA_EXT_ZKSED),
+       __RISCV_ISA_EXT_DATA(zksh, RISCV_ISA_EXT_ZKSH),
        __RISCV_ISA_EXT_DATA(smaia, RISCV_ISA_EXT_SMAIA),
        __RISCV_ISA_EXT_DATA(smstateen, RISCV_ISA_EXT_SMSTATEEN),
        __RISCV_ISA_EXT_DATA(ssaia, RISCV_ISA_EXT_SSAIA),
 
 const size_t riscv_isa_ext_count = ARRAY_SIZE(riscv_isa_ext);
 
+static void __init match_isa_ext(const struct riscv_isa_ext_data *ext, const char *name,
+                                const char *name_end, struct riscv_isainfo *isainfo)
+{
+       if ((name_end - name == strlen(ext->name)) &&
+            !strncasecmp(name, ext->name, name_end - name)) {
+               /*
+                * If this is a bundle, enable all the ISA extensions that
+                * comprise the bundle.
+                */
+               if (ext->subset_ext_size) {
+                       for (int i = 0; i < ext->subset_ext_size; i++) {
+                               if (riscv_isa_extension_check(ext->subset_ext_ids[i]))
+                                       set_bit(ext->subset_ext_ids[i], isainfo->isa);
+                       }
+               }
+
+               /*
+                * This is valid even for bundle extensions which uses the RISCV_ISA_EXT_INVALID id
+                * (rejected by riscv_isa_extension_check()).
+                */
+               if (riscv_isa_extension_check(ext->id))
+                       set_bit(ext->id, isainfo->isa);
+       }
+}
+
 static void __init riscv_parse_isa_string(unsigned long *this_hwcap, struct riscv_isainfo *isainfo,
                                          unsigned long *isa2hwcap, const char *isa)
 {
                if (*isa == '_')
                        ++isa;
 
-#define SET_ISA_EXT_MAP(name, bit)                                             \
-               do {                                                            \
-                       if ((ext_end - ext == strlen(name)) &&                  \
-                            !strncasecmp(ext, name, strlen(name)) &&           \
-                            riscv_isa_extension_check(bit))                    \
-                               set_bit(bit, isainfo->isa);                     \
-               } while (false)                                                 \
-
                if (unlikely(ext_err))
                        continue;
                if (!ext_long) {
                        }
                } else {
                        for (int i = 0; i < riscv_isa_ext_count; i++)
-                               SET_ISA_EXT_MAP(riscv_isa_ext[i].name,
-                                               riscv_isa_ext[i].id);
+                               match_isa_ext(&riscv_isa_ext[i], ext, ext_end, isainfo);
                }
-#undef SET_ISA_EXT_MAP
        }
 }
 
                }
 
                for (int i = 0; i < riscv_isa_ext_count; i++) {
+                       const struct riscv_isa_ext_data *ext = &riscv_isa_ext[i];
+
                        if (of_property_match_string(cpu_node, "riscv,isa-extensions",
-                                                    riscv_isa_ext[i].property) < 0)
+                                                    ext->property) < 0)
                                continue;
 
-                       if (!riscv_isa_extension_check(riscv_isa_ext[i].id))
-                               continue;
+                       if (ext->subset_ext_size) {
+                               for (int j = 0; j < ext->subset_ext_size; j++) {
+                                       if (riscv_isa_extension_check(ext->subset_ext_ids[i]))
+                                               set_bit(ext->subset_ext_ids[j], isainfo->isa);
+                               }
+                       }
 
-                       /* 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];
+                       if (riscv_isa_extension_check(ext->id)) {
+                               set_bit(ext->id, isainfo->isa);
 
-                       set_bit(riscv_isa_ext[i].id, isainfo->isa);
+                               /* 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];
+                       }
                }
 
                of_node_put(cpu_node);