[v2,02/19] riscv: add ISA extension parsing for scalar crypto

Message ID 20231017131456.2053396-3-cleger@rivosinc.com
State New
Headers
Series riscv: report more ISA extensions through hwprobe |

Commit Message

Clément Léger Oct. 17, 2023, 1:14 p.m. UTC
  From: Evan Green <evan@rivosinc.com>

The Scalar Crypto specification defines Zk as a shorthand for the
Zkn, Zkr and Zkt extensions. The same follows for both Zkn, Zks and Zbk,
which are all shorthands for various other extensions. The detailed
breakdown can be found in their dt-binding entries.

Since Zkn also implies the Zbkb, Zbkc and Zbkx extensions, simply passing
"zk" through a DT should enable all of Zbkb, Zbkc, Zbkx, Zkn, Zkr and Zkt.
For example, setting the "riscv,isa" DT property to "rv64imafdc_zk"
should generate the following cpuinfo output:
"rv64imafdc_zicntr_zicsr_zifencei_zihpm_zbkb_zbkc_zbkx_zknd_zkne_zknh_zkr_zkt"

riscv_isa_ext_data grows a pair of new members, to permit setting the
relevant bits for "bundled" extensions, both while parsing the ISA string
and the new dedicated extension properties

Co-developed-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Evan Green <evan@rivosinc.com>
Signed-off-by: Clément Léger <cleger@rivosinc.com>
---
 arch/riscv/include/asm/hwcap.h |  13 +++++
 arch/riscv/kernel/cpufeature.c | 103 ++++++++++++++++++++++++++-------
 2 files changed, 96 insertions(+), 20 deletions(-)
  

Comments

Evan Green Oct. 23, 2023, 4:21 p.m. UTC | #1
On Tue, Oct 17, 2023 at 6:15 AM Clément Léger <cleger@rivosinc.com> wrote:
>
> From: Evan Green <evan@rivosinc.com>
>
> The Scalar Crypto specification defines Zk as a shorthand for the
> Zkn, Zkr and Zkt extensions. The same follows for both Zkn, Zks and Zbk,
> which are all shorthands for various other extensions. The detailed
> breakdown can be found in their dt-binding entries.
>
> Since Zkn also implies the Zbkb, Zbkc and Zbkx extensions, simply passing
> "zk" through a DT should enable all of Zbkb, Zbkc, Zbkx, Zkn, Zkr and Zkt.
> For example, setting the "riscv,isa" DT property to "rv64imafdc_zk"
> should generate the following cpuinfo output:
> "rv64imafdc_zicntr_zicsr_zifencei_zihpm_zbkb_zbkc_zbkx_zknd_zkne_zknh_zkr_zkt"
>
> riscv_isa_ext_data grows a pair of new members, to permit setting the
> relevant bits for "bundled" extensions, both while parsing the ISA string
> and the new dedicated extension properties
>
> Co-developed-by: Conor Dooley <conor.dooley@microchip.com>
> Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
> Signed-off-by: Evan Green <evan@rivosinc.com>
> Signed-off-by: Clément Léger <cleger@rivosinc.com>

My tree might be out of sync, but in my search for riscv_isa_ext, I
also found a use in print_isa() (cpu.c) where we're reaching into
riscv_isa_ext[].id and assuming it's always valid. If that's still in
there we'll want to fix up that spot too, since now with bundles .id
may or may not be valid.

-Evan
  
Clément Léger Oct. 24, 2023, 7:18 a.m. UTC | #2
On 23/10/2023 18:21, Evan Green wrote:
> On Tue, Oct 17, 2023 at 6:15 AM Clément Léger <cleger@rivosinc.com> wrote:
>>
>> From: Evan Green <evan@rivosinc.com>
>>
>> The Scalar Crypto specification defines Zk as a shorthand for the
>> Zkn, Zkr and Zkt extensions. The same follows for both Zkn, Zks and Zbk,
>> which are all shorthands for various other extensions. The detailed
>> breakdown can be found in their dt-binding entries.
>>
>> Since Zkn also implies the Zbkb, Zbkc and Zbkx extensions, simply passing
>> "zk" through a DT should enable all of Zbkb, Zbkc, Zbkx, Zkn, Zkr and Zkt.
>> For example, setting the "riscv,isa" DT property to "rv64imafdc_zk"
>> should generate the following cpuinfo output:
>> "rv64imafdc_zicntr_zicsr_zifencei_zihpm_zbkb_zbkc_zbkx_zknd_zkne_zknh_zkr_zkt"
>>
>> riscv_isa_ext_data grows a pair of new members, to permit setting the
>> relevant bits for "bundled" extensions, both while parsing the ISA string
>> and the new dedicated extension properties
>>
>> Co-developed-by: Conor Dooley <conor.dooley@microchip.com>
>> Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
>> Signed-off-by: Evan Green <evan@rivosinc.com>
>> Signed-off-by: Clément Léger <cleger@rivosinc.com>
> 
> My tree might be out of sync, but in my search for riscv_isa_ext, I
> also found a use in print_isa() (cpu.c) where we're reaching into
> riscv_isa_ext[].id and assuming it's always valid. If that's still in
> there we'll want to fix up that spot too, since now with bundles .id
> may or may not be valid.

Oh indeed, the array is visible outside of this compilation unit :/.
I'll check that before sending V3.

Clément

> 
> -Evan
  
Clément Léger Oct. 24, 2023, 9:30 a.m. UTC | #3
On 24/10/2023 09:18, Clément Léger wrote:
> 
> 
> On 23/10/2023 18:21, Evan Green wrote:
>> On Tue, Oct 17, 2023 at 6:15 AM Clément Léger <cleger@rivosinc.com> wrote:
>>>
>>> From: Evan Green <evan@rivosinc.com>
>>>
>>> The Scalar Crypto specification defines Zk as a shorthand for the
>>> Zkn, Zkr and Zkt extensions. The same follows for both Zkn, Zks and Zbk,
>>> which are all shorthands for various other extensions. The detailed
>>> breakdown can be found in their dt-binding entries.
>>>
>>> Since Zkn also implies the Zbkb, Zbkc and Zbkx extensions, simply passing
>>> "zk" through a DT should enable all of Zbkb, Zbkc, Zbkx, Zkn, Zkr and Zkt.
>>> For example, setting the "riscv,isa" DT property to "rv64imafdc_zk"
>>> should generate the following cpuinfo output:
>>> "rv64imafdc_zicntr_zicsr_zifencei_zihpm_zbkb_zbkc_zbkx_zknd_zkne_zknh_zkr_zkt"
>>>
>>> riscv_isa_ext_data grows a pair of new members, to permit setting the
>>> relevant bits for "bundled" extensions, both while parsing the ISA string
>>> and the new dedicated extension properties
>>>
>>> Co-developed-by: Conor Dooley <conor.dooley@microchip.com>
>>> Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
>>> Signed-off-by: Evan Green <evan@rivosinc.com>
>>> Signed-off-by: Clément Léger <cleger@rivosinc.com>
>>
>> My tree might be out of sync, but in my search for riscv_isa_ext, I
>> also found a use in print_isa() (cpu.c) where we're reaching into
>> riscv_isa_ext[].id and assuming it's always valid. If that's still in
>> there we'll want to fix up that spot too, since now with bundles .id
>> may or may not be valid.
> 
> Oh indeed, the array is visible outside of this compilation unit :/.
> I'll check that before sending V3.

After looking a bit more at that, it actually seems that id is used in
cpuinfo to determine which extensions are present which means you are
right, bundle_size needs to be accounted for.

Looking at it also raises the question (again) of exposing the "bundles"
extensions themselves or not in cpuinfo output. With the current setup,
the bundles extensions won't be visible in cpuinfo output. For instance
if Zk was in the isa string, then it will not be visible in the cpuinfo
output, only the child extensions. One solution would be to always have
a valid id for each extension. So we would have one for Zk for instance.

We would then have a similar setup for all "bundles" or "subset"
extensions, they would have a id for all of them. For instance, Zk would
become:

__RISCV_ISA_EXT_DATA_BUNDLE(zk, RISCV_ISA_EXT_ZK, riscv_zk_bundled_exts)

Same would go for zvbb (riscv_zvbb_subset_exts would only contain Zvkb):

__RISCV_ISA_EXT_DATA_BUNDLE(zk, RISCV_ISA_EXT_ZVBB, riscv_zvbb_subset_exts)

For the sake of completeness, I feel like it would be good to have all
the extensions (bundles or not) visible in the riscv_isa_ext.

Any objection ?

Clément

> 
> Clément
> 
>>
>> -Evan
  
Evan Green Oct. 24, 2023, 4:37 p.m. UTC | #4
On Tue, Oct 24, 2023 at 2:30 AM Clément Léger <cleger@rivosinc.com> wrote:
>
>
>
> On 24/10/2023 09:18, Clément Léger wrote:
> >
> >
> > On 23/10/2023 18:21, Evan Green wrote:
> >> On Tue, Oct 17, 2023 at 6:15 AM Clément Léger <cleger@rivosinc.com> wrote:
> >>>
> >>> From: Evan Green <evan@rivosinc.com>
> >>>
> >>> The Scalar Crypto specification defines Zk as a shorthand for the
> >>> Zkn, Zkr and Zkt extensions. The same follows for both Zkn, Zks and Zbk,
> >>> which are all shorthands for various other extensions. The detailed
> >>> breakdown can be found in their dt-binding entries.
> >>>
> >>> Since Zkn also implies the Zbkb, Zbkc and Zbkx extensions, simply passing
> >>> "zk" through a DT should enable all of Zbkb, Zbkc, Zbkx, Zkn, Zkr and Zkt.
> >>> For example, setting the "riscv,isa" DT property to "rv64imafdc_zk"
> >>> should generate the following cpuinfo output:
> >>> "rv64imafdc_zicntr_zicsr_zifencei_zihpm_zbkb_zbkc_zbkx_zknd_zkne_zknh_zkr_zkt"
> >>>
> >>> riscv_isa_ext_data grows a pair of new members, to permit setting the
> >>> relevant bits for "bundled" extensions, both while parsing the ISA string
> >>> and the new dedicated extension properties
> >>>
> >>> Co-developed-by: Conor Dooley <conor.dooley@microchip.com>
> >>> Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
> >>> Signed-off-by: Evan Green <evan@rivosinc.com>
> >>> Signed-off-by: Clément Léger <cleger@rivosinc.com>
> >>
> >> My tree might be out of sync, but in my search for riscv_isa_ext, I
> >> also found a use in print_isa() (cpu.c) where we're reaching into
> >> riscv_isa_ext[].id and assuming it's always valid. If that's still in
> >> there we'll want to fix up that spot too, since now with bundles .id
> >> may or may not be valid.
> >
> > Oh indeed, the array is visible outside of this compilation unit :/.
> > I'll check that before sending V3.
>
> After looking a bit more at that, it actually seems that id is used in
> cpuinfo to determine which extensions are present which means you are
> right, bundle_size needs to be accounted for.
>
> Looking at it also raises the question (again) of exposing the "bundles"
> extensions themselves or not in cpuinfo output. With the current setup,
> the bundles extensions won't be visible in cpuinfo output. For instance
> if Zk was in the isa string, then it will not be visible in the cpuinfo
> output, only the child extensions. One solution would be to always have
> a valid id for each extension. So we would have one for Zk for instance.
>
> We would then have a similar setup for all "bundles" or "subset"
> extensions, they would have a id for all of them. For instance, Zk would
> become:
>
> __RISCV_ISA_EXT_DATA_BUNDLE(zk, RISCV_ISA_EXT_ZK, riscv_zk_bundled_exts)
>
> Same would go for zvbb (riscv_zvbb_subset_exts would only contain Zvkb):
>
> __RISCV_ISA_EXT_DATA_BUNDLE(zk, RISCV_ISA_EXT_ZVBB, riscv_zvbb_subset_exts)
>
> For the sake of completeness, I feel like it would be good to have all
> the extensions (bundles or not) visible in the riscv_isa_ext.
>
> Any objection ?

I could be persuaded that it's a good idea, but there are arguments to
be made for not defining them as separate bits:

1. Having two (sets of) bits that mean the same thing means usermode
now has to decide which one to query, or query both. Multiple values
that mean the same thing is always something that makes me nervous.
2. To avoid these two sets having different answers, we'd have to
solve the reverse problem too: If all of the bundled extensions that
make up Zk are on, we'd need to detect that and turn Zk on as well.
That code would also need to know the difference between a pure lasso
like Zk, where you should flip it on if its components are on, and the
loose change variant we were discussing on the other thread (Zvkb?),
where you cannot.

Pretending pure lasso extensions didn't exist on their own was a way
to sidestep the problem.
-Evan
  
Clément Léger Oct. 24, 2023, 6:11 p.m. UTC | #5
On 24/10/2023 18:37, Evan Green wrote:
> On Tue, Oct 24, 2023 at 2:30 AM Clément Léger <cleger@rivosinc.com> wrote:
>>
>>
>>
>> On 24/10/2023 09:18, Clément Léger wrote:
>>>
>>>
>>> On 23/10/2023 18:21, Evan Green wrote:
>>>> On Tue, Oct 17, 2023 at 6:15 AM Clément Léger <cleger@rivosinc.com> wrote:
>>>>>
>>>>> From: Evan Green <evan@rivosinc.com>
>>>>>
>>>>> The Scalar Crypto specification defines Zk as a shorthand for the
>>>>> Zkn, Zkr and Zkt extensions. The same follows for both Zkn, Zks and Zbk,
>>>>> which are all shorthands for various other extensions. The detailed
>>>>> breakdown can be found in their dt-binding entries.
>>>>>
>>>>> Since Zkn also implies the Zbkb, Zbkc and Zbkx extensions, simply passing
>>>>> "zk" through a DT should enable all of Zbkb, Zbkc, Zbkx, Zkn, Zkr and Zkt.
>>>>> For example, setting the "riscv,isa" DT property to "rv64imafdc_zk"
>>>>> should generate the following cpuinfo output:
>>>>> "rv64imafdc_zicntr_zicsr_zifencei_zihpm_zbkb_zbkc_zbkx_zknd_zkne_zknh_zkr_zkt"
>>>>>
>>>>> riscv_isa_ext_data grows a pair of new members, to permit setting the
>>>>> relevant bits for "bundled" extensions, both while parsing the ISA string
>>>>> and the new dedicated extension properties
>>>>>
>>>>> Co-developed-by: Conor Dooley <conor.dooley@microchip.com>
>>>>> Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
>>>>> Signed-off-by: Evan Green <evan@rivosinc.com>
>>>>> Signed-off-by: Clément Léger <cleger@rivosinc.com>
>>>>
>>>> My tree might be out of sync, but in my search for riscv_isa_ext, I
>>>> also found a use in print_isa() (cpu.c) where we're reaching into
>>>> riscv_isa_ext[].id and assuming it's always valid. If that's still in
>>>> there we'll want to fix up that spot too, since now with bundles .id
>>>> may or may not be valid.
>>>
>>> Oh indeed, the array is visible outside of this compilation unit :/.
>>> I'll check that before sending V3.
>>
>> After looking a bit more at that, it actually seems that id is used in
>> cpuinfo to determine which extensions are present which means you are
>> right, bundle_size needs to be accounted for.
>>
>> Looking at it also raises the question (again) of exposing the "bundles"
>> extensions themselves or not in cpuinfo output. With the current setup,
>> the bundles extensions won't be visible in cpuinfo output. For instance
>> if Zk was in the isa string, then it will not be visible in the cpuinfo
>> output, only the child extensions. One solution would be to always have
>> a valid id for each extension. So we would have one for Zk for instance.
>>
>> We would then have a similar setup for all "bundles" or "subset"
>> extensions, they would have a id for all of them. For instance, Zk would
>> become:
>>
>> __RISCV_ISA_EXT_DATA_BUNDLE(zk, RISCV_ISA_EXT_ZK, riscv_zk_bundled_exts)
>>
>> Same would go for zvbb (riscv_zvbb_subset_exts would only contain Zvkb):
>>
>> __RISCV_ISA_EXT_DATA_BUNDLE(zk, RISCV_ISA_EXT_ZVBB, riscv_zvbb_subset_exts)
>>
>> For the sake of completeness, I feel like it would be good to have all
>> the extensions (bundles or not) visible in the riscv_isa_ext.
>>
>> Any objection ?
> 
> I could be persuaded that it's a good idea, but there are arguments to
> be made for not defining them as separate bits:
> 
> 1. Having two (sets of) bits that mean the same thing means usermode
> now has to decide which one to query, or query both. Multiple values
> that mean the same thing is always something that makes me nervous.

That is indeed an acceptable cons.

> 2. To avoid these two sets having different answers, we'd have to
> solve the reverse problem too: If all of the bundled extensions that
> make up Zk are on, we'd need to detect that and turn Zk on as well.

Oh yes, sorry, already forgot that point :/ Well, I guess things sorted
out by themselves. Let's do what you proposed:

- Pure lasso extensions (Zk) will simply result in all the sub
extensions being enable, there won't be any .id specified for these
ones, simply a bundle of extensions.

- "Superset" extensions (Zvbb for instance) will have their own .id as
well as a bundle made of subsets extensions.

Clément

> That code would also need to know the difference between a pure lasso
> like Zk, where you should flip it on if its components are on, and the
> loose change variant we were discussing on the other thread (Zvkb?),
> where you cannot.
> 
> Pretending pure lasso extensions didn't exist on their own was a way
> to sidestep the problem.
> -Evan
  

Patch

diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
index b7b58258f6c7..ab80d822c847 100644
--- a/arch/riscv/include/asm/hwcap.h
+++ b/arch/riscv/include/asm/hwcap.h
@@ -58,6 +58,17 @@ 
 #define RISCV_ISA_EXT_ZICSR		40
 #define RISCV_ISA_EXT_ZIFENCEI		41
 #define RISCV_ISA_EXT_ZIHPM		42
+#define RISCV_ISA_EXT_ZBC		43
+#define RISCV_ISA_EXT_ZBKB		44
+#define RISCV_ISA_EXT_ZBKC		45
+#define RISCV_ISA_EXT_ZBKX		46
+#define RISCV_ISA_EXT_ZKND		47
+#define RISCV_ISA_EXT_ZKNE		48
+#define RISCV_ISA_EXT_ZKNH		49
+#define RISCV_ISA_EXT_ZKR		50
+#define RISCV_ISA_EXT_ZKSED		51
+#define RISCV_ISA_EXT_ZKSH		52
+#define RISCV_ISA_EXT_ZKT		53
 
 #define RISCV_ISA_EXT_MAX		64
 
@@ -77,6 +88,8 @@  struct riscv_isa_ext_data {
 	const unsigned int id;
 	const char *name;
 	const char *property;
+	const unsigned int *bundle_ids;
+	const unsigned int bundle_size;
 };
 
 extern const struct riscv_isa_ext_data riscv_isa_ext[];
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index 1cfbba65d11a..d3682fdfd9f1 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -111,6 +111,39 @@  static bool riscv_isa_extension_check(int id)
 	.id = _id,				\
 }
 
+#define __RISCV_ISA_EXT_BUNDLE(_name, _bundled_exts) {	\
+	.name = #_name,					\
+	.property = #_name,				\
+	.bundle_ids = _bundled_exts,			\
+	.bundle_size = 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.
@@ -173,7 +206,21 @@  const struct riscv_isa_ext_data riscv_isa_ext[] = {
 	__RISCV_ISA_EXT_DATA(zihpm, RISCV_ISA_EXT_ZIHPM),
 	__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(ssaia, RISCV_ISA_EXT_SSAIA),
 	__RISCV_ISA_EXT_DATA(sscofpmf, RISCV_ISA_EXT_SSCOFPMF),
@@ -185,6 +232,26 @@  const struct riscv_isa_ext_data riscv_isa_ext[] = {
 
 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->bundle_size) {
+			for (int i = 0; i < ext->bundle_size; i++) {
+				if (riscv_isa_extension_check(ext->bundle_ids[i]))
+					set_bit(ext->bundle_ids[i], isainfo->isa);
+			}
+		} else 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)
 {
@@ -316,14 +383,6 @@  static void __init riscv_parse_isa_string(unsigned long *this_hwcap, struct risc
 		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) {
@@ -335,10 +394,8 @@  static void __init riscv_parse_isa_string(unsigned long *this_hwcap, struct risc
 			}
 		} 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
 	}
 }
 
@@ -437,18 +494,24 @@  static int __init riscv_fill_hwcap_from_ext_list(unsigned long *isa2hwcap)
 		}
 
 		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;
+			const struct riscv_isa_ext_data ext = riscv_isa_ext[i];
 
-			if (!riscv_isa_extension_check(riscv_isa_ext[i].id))
+			if (of_property_match_string(cpu_node, "riscv,isa-extensions",
+						     ext.property) < 0)
 				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);
+			if (ext.bundle_size) {
+				for (int j = 0; j < ext.bundle_size; j++) {
+					if (riscv_isa_extension_check(ext.bundle_ids[i]))
+						set_bit(ext.bundle_ids[j], isainfo->isa);
+				}
+			} else if (riscv_isa_extension_check(ext.id)) {
+				set_bit(ext.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);