All the mail mirrored from lore.kernel.org
 help / color / mirror / Atom feed
From: Conor Dooley <conor@kernel.org>
To: Charlie Jenkins <charlie@rivosinc.com>
Cc: "Rob Herring" <robh@kernel.org>,
	"Krzysztof Kozlowski" <krzysztof.kozlowski+dt@linaro.org>,
	"Paul Walmsley" <paul.walmsley@sifive.com>,
	"Palmer Dabbelt" <palmer@dabbelt.com>,
	"Albert Ou" <aou@eecs.berkeley.edu>,
	"Guo Ren" <guoren@kernel.org>,
	"Conor Dooley" <conor+dt@kernel.org>,
	"Chen-Yu Tsai" <wens@csie.org>,
	"Jernej Skrabec" <jernej.skrabec@gmail.com>,
	"Samuel Holland" <samuel@sholland.org>,
	"Conor Dooley" <conor.dooley@microchip.com>,
	"Evan Green" <evan@rivosinc.com>,
	"Clément Léger" <cleger@rivosinc.com>,
	"Jonathan Corbet" <corbet@lwn.net>,
	"Shuah Khan" <shuah@kernel.org>,
	linux-riscv@lists.infradead.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	"Palmer Dabbelt" <palmer@rivosinc.com>,
	linux-arm-kernel@lists.infradead.org,
	linux-sunxi@lists.linux.dev, linux-doc@vger.kernel.org,
	linux-kselftest@vger.kernel.org
Subject: Re: [PATCH v3 08/17] riscv: Introduce vendor variants of extension helpers
Date: Fri, 26 Apr 2024 17:19:59 +0100	[thread overview]
Message-ID: <20240426-myself-crowbar-99dc0a080cd9@spud> (raw)
In-Reply-To: <20240420-dev-charlie-support_thead_vector_6_9-v3-8-67cff4271d1d@rivosinc.com>

[-- Attachment #1: Type: text/plain, Size: 13642 bytes --]

On Sat, Apr 20, 2024 at 06:04:40PM -0700, Charlie Jenkins wrote:
> Vendor extensions are maintained in per-vendor structs (separate from
> standard extensions which live in riscv_isa). Create vendor variants for
> the existing extension helpers to interface with the riscv_isa_vendor
> bitmaps.

> There is a good amount of overlap between these functions, so
> the alternative checking code can be factored out.

Can you please split this out?

> 
> Signed-off-by: Charlie Jenkins <charlie@rivosinc.com>
> ---
>  arch/riscv/errata/sifive/errata.c          |  3 ++
>  arch/riscv/errata/thead/errata.c           |  3 ++
>  arch/riscv/include/asm/cpufeature.h        | 86 +++++++++++++++++-------------
>  arch/riscv/include/asm/vendor_extensions.h | 56 +++++++++++++++++++
>  arch/riscv/kernel/cpufeature.c             | 20 ++++---
>  arch/riscv/kernel/vendor_extensions.c      | 40 ++++++++++++++
>  6 files changed, 164 insertions(+), 44 deletions(-)
> 
> diff --git a/arch/riscv/errata/sifive/errata.c b/arch/riscv/errata/sifive/errata.c
> index 3d9a32d791f7..b29b6e405ff2 100644
> --- a/arch/riscv/errata/sifive/errata.c
> +++ b/arch/riscv/errata/sifive/errata.c
> @@ -12,6 +12,7 @@
>  #include <asm/alternative.h>
>  #include <asm/vendorid_list.h>
>  #include <asm/errata_list.h>
> +#include <asm/vendor_extensions.h>
>  
>  struct errata_info_t {
>  	char name[32];
> @@ -99,6 +100,8 @@ void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
>  	for (alt = begin; alt < end; alt++) {
>  		if (alt->vendor_id != SIFIVE_VENDOR_ID)
>  			continue;
> +		if (alt->patch_id >= RISCV_VENDOR_EXT_ALTERNATIVES_BASE)
> +			continue;
>  		if (alt->patch_id >= ERRATA_SIFIVE_NUMBER) {
>  			WARN(1, "This errata id:%d is not in kernel errata list", alt->patch_id);
>  			continue;
> diff --git a/arch/riscv/errata/thead/errata.c b/arch/riscv/errata/thead/errata.c
> index b1c410bbc1ae..d8e78cc687bc 100644
> --- a/arch/riscv/errata/thead/errata.c
> +++ b/arch/riscv/errata/thead/errata.c
> @@ -18,6 +18,7 @@
>  #include <asm/io.h>
>  #include <asm/patch.h>
>  #include <asm/vendorid_list.h>
> +#include <asm/vendor_extensions.h>
>  
>  static bool errata_probe_pbmt(unsigned int stage,
>  			      unsigned long arch_id, unsigned long impid)
> @@ -163,6 +164,8 @@ void thead_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
>  	for (alt = begin; alt < end; alt++) {
>  		if (alt->vendor_id != THEAD_VENDOR_ID)
>  			continue;
> +		if (alt->patch_id >= RISCV_VENDOR_EXT_ALTERNATIVES_BASE)
> +			continue;

>  		if (alt->patch_id >= ERRATA_THEAD_NUMBER)

This number is 2, how does the patching actually work for vendor stuff
when the base is always greater than 2?

>  			continue;
>  
> diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
> index db6a6d7d6b2e..83e1143db9ad 100644
> --- a/arch/riscv/include/asm/cpufeature.h
> +++ b/arch/riscv/include/asm/cpufeature.h
> @@ -103,22 +103,13 @@ bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, unsigned i
>  	__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_##ext)
>  
>  static __always_inline bool
> -riscv_has_extension_likely(const unsigned long ext)
> +__riscv_has_extension_likely_alternatives(const unsigned long vendor, const unsigned long ext)
>  {
> -	compiletime_assert(ext < RISCV_ISA_EXT_MAX,
> -			   "ext must be < RISCV_ISA_EXT_MAX");
> -
> -	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) {
> -		asm goto(
> -		ALTERNATIVE("j	%l[l_no]", "nop", 0, %[ext], 1)
> -		:
> -		: [ext] "i" (ext)
> -		:
> -		: l_no);
> -	} else {
> -		if (!__riscv_isa_extension_available(NULL, ext))
> -			goto l_no;
> -	}
> +	asm goto(ALTERNATIVE("j	%l[l_no]", "nop", %[vendor], %[ext], 1)
> +	:
> +	: [vendor] "i" (vendor), [ext] "i" (ext)
> +	:
> +	: l_no);
>  
>  	return true;
>  l_no:
> @@ -126,42 +117,65 @@ riscv_has_extension_likely(const unsigned long ext)
>  }
>  
>  static __always_inline bool
> -riscv_has_extension_unlikely(const unsigned long ext)
> +__riscv_has_extension_unlikely_alternatives(const unsigned long vendor, const unsigned long ext)

ngl, I think you could drop the _alternatives from these - the
likely/unlikely is only actually a thing because of the alternatives in
the first place & just retain the __ as a differentiator. That'd help
you with some of the long-line wrangling you've been doing below.

>  {
> -	compiletime_assert(ext < RISCV_ISA_EXT_MAX,
> -			   "ext must be < RISCV_ISA_EXT_MAX");
> -
> -	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) {
> -		asm goto(
> -		ALTERNATIVE("nop", "j	%l[l_yes]", 0, %[ext], 1)
> -		:
> -		: [ext] "i" (ext)
> -		:
> -		: l_yes);
> -	} else {
> -		if (__riscv_isa_extension_available(NULL, ext))
> -			goto l_yes;
> -	}
> +	asm goto(ALTERNATIVE("nop", "j	%l[l_yes]", %[vendor], %[ext], 1)
> +	:
> +	: [vendor] "i" (vendor), [ext] "i" (ext)
> +	:
> +	: l_yes);
>  
>  	return false;
>  l_yes:
>  	return true;
>  }
>  
> +static __always_inline bool
> +riscv_has_extension_likely(const unsigned long ext)

Can you format this so that its on one line & wrap the arguments if
needs be?

> +{
> +	compiletime_assert(ext < RISCV_ISA_EXT_MAX,
> +			   "ext must be < RISCV_ISA_EXT_MAX");
> +
> +	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE))
> +		return __riscv_has_extension_likely_alternatives(0, ext);
> +	else

I'm almost certain I said this before, but none of the else branches are
needed here, there's a return in the if branch, so the remainder of the
function becomes unconditionally executed.

> +		return __riscv_isa_extension_available(NULL, ext);
> +}
> +
> +static __always_inline bool
> +riscv_has_extension_unlikely(const unsigned long ext)
> +{
> +	compiletime_assert(ext < RISCV_ISA_EXT_MAX,
> +			   "ext must be < RISCV_ISA_EXT_MAX");
> +
> +	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE))
> +		return __riscv_has_extension_unlikely_alternatives(0, ext);
> +	else
> +		return __riscv_isa_extension_available(NULL, ext);
> +}
> +
>  static __always_inline bool riscv_cpu_has_extension_likely(int cpu, const unsigned long ext)
>  {
> -	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) && riscv_has_extension_likely(ext))
> -		return true;
> +	compiletime_assert(ext < RISCV_ISA_EXT_MAX,
> +			   "ext must be < RISCV_ISA_EXT_MAX");
>  
> -	return __riscv_isa_extension_available(hart_isa[cpu].isa, ext);
> +	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) &&
> +	    __riscv_has_extension_likely_alternatives(0, ext))

0 is meaningless, please make this more understandable using a define of
some sort.

> +		return true;
> +	else
> +		return __riscv_isa_extension_available(hart_isa[cpu].isa, ext);
>  }
>  
>  static __always_inline bool riscv_cpu_has_extension_unlikely(int cpu, const unsigned long ext)
>  {
> -	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) && riscv_has_extension_unlikely(ext))
> -		return true;
> +	compiletime_assert(ext < RISCV_ISA_EXT_MAX,
> +			   "ext must be < RISCV_ISA_EXT_MAX");
>  
> -	return __riscv_isa_extension_available(hart_isa[cpu].isa, ext);
> +	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) &&
> +	    __riscv_has_extension_unlikely_alternatives(0, ext))
> +		return true;
> +	else
> +		return __riscv_isa_extension_available(hart_isa[cpu].isa, ext);
>  }
>  
>  #endif
> diff --git a/arch/riscv/include/asm/vendor_extensions.h b/arch/riscv/include/asm/vendor_extensions.h
> index 0af1ddd0af70..3e676a96016e 100644
> --- a/arch/riscv/include/asm/vendor_extensions.h
> +++ b/arch/riscv/include/asm/vendor_extensions.h
> @@ -23,4 +23,60 @@ extern const struct riscv_isa_vendor_ext_data_list *riscv_isa_vendor_ext_list[];
>  
>  extern const size_t riscv_isa_vendor_ext_list_size;
>  
> +/*
> + * The alternatives need some way of distinguishing between vendor extensions
> + * and errata. Incrementing all of the vendor extension keys so they are at
> + * least 0x8000 accomplishes that.
> + */
> +#define RISCV_VENDOR_EXT_ALTERNATIVES_BASE	0x8000
> +
> +bool __riscv_isa_vendor_extension_available(int cpu, unsigned long vendor, unsigned int bit);
> +#define riscv_cpu_isa_vendor_extension_available(cpu, vendor, ext)	\
> +	__riscv_isa_vendor_extension_available(cpu, vendor, RISCV_ISA_VENDOR_EXT_##ext)
> +#define riscv_isa_vendor_extension_available(vendor, ext)	\
> +	__riscv_isa_vendor_extension_available(-1, vendor, RISCV_ISA_VENDOR_EXT_##ext)
> +
> +static __always_inline bool
> +riscv_has_vendor_extension_likely(const unsigned long vendor, const unsigned long ext)
> +{
> +	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE))
> +		return __riscv_has_extension_likely_alternatives(vendor,
> +								 ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE);
> +	else
> +		return __riscv_isa_vendor_extension_available(-1, vendor, ext);
> +}
> +
> +static __always_inline bool
> +riscv_has_vendor_extension_unlikely(const unsigned long vendor, const unsigned long ext)
> +{
> +	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE))
> +		return __riscv_has_extension_unlikely_alternatives(vendor,
> +								   ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE);
> +	else
> +		return __riscv_isa_vendor_extension_available(-1, vendor, ext);
> +}
> +
> +static __always_inline bool riscv_cpu_has_vendor_extension_likely(const unsigned long vendor,
> +								  int cpu, const unsigned long ext)
> +{
> +	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) &&
> +	    __riscv_has_extension_likely_alternatives(vendor,
> +						      ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE))
> +		return true;
> +	else
> +		return __riscv_isa_vendor_extension_available(cpu, vendor, ext);
> +}
> +
> +static __always_inline bool riscv_cpu_has_vendor_extension_unlikely(const unsigned long vendor,
> +								    int cpu,
> +								    const unsigned long ext)
> +{
> +	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) &&
> +	    __riscv_has_extension_unlikely_alternatives(vendor,
> +							ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE))
> +		return true;
> +	else
> +		return __riscv_isa_vendor_extension_available(cpu, vendor, ext);
> +}
> +
>  #endif /* _ASM_VENDOR_EXTENSIONS_H */
> diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> index c9f36822e337..17371887abcc 100644
> --- a/arch/riscv/kernel/cpufeature.c
> +++ b/arch/riscv/kernel/cpufeature.c
> @@ -833,25 +833,29 @@ void __init_or_module riscv_cpufeature_patch_func(struct alt_entry *begin,
>  {
>  	struct alt_entry *alt;
>  	void *oldptr, *altptr;
> -	u16 id, value;
> +	u16 id, value, vendor;
>  
>  	if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
>  		return;
>  
>  	for (alt = begin; alt < end; alt++) {
> -		if (alt->vendor_id != 0)
> -			continue;
> -
>  		id = PATCH_ID_CPUFEATURE_ID(alt->patch_id);
> +		vendor = PATCH_ID_CPUFEATURE_ID(alt->vendor_id);
>  
> -		if (id >= RISCV_ISA_EXT_MAX) {
> +		if (id < RISCV_ISA_EXT_MAX) {

I think any reliance on the standard ext max requires a comment
explaining what the interaction is between it and the vendor stuff.

> +			if (alt->vendor_id != 0)
> +				continue;

If this happens, it's a bug, should we be continuing silently?

Cheers,
Conor.

> +
> +			if (!__riscv_isa_extension_available(NULL, id))
> +				continue;
> +		} else if (id >= RISCV_VENDOR_EXT_ALTERNATIVES_BASE) {
> +			if (!__riscv_isa_vendor_extension_available(-1, vendor, id))
> +				continue;
> +		} else {
>  			WARN(1, "This extension id:%d is not in ISA extension list", id);
>  			continue;
>  		}
>  
> -		if (!__riscv_isa_extension_available(NULL, id))
> -			continue;
> -
>  		value = PATCH_ID_CPUFEATURE_VALUE(alt->patch_id);
>  		if (!riscv_cpufeature_patch_check(id, value))
>  			continue;
> diff --git a/arch/riscv/kernel/vendor_extensions.c b/arch/riscv/kernel/vendor_extensions.c
> index f76cb3013c2d..eced93eec5a6 100644
> --- a/arch/riscv/kernel/vendor_extensions.c
> +++ b/arch/riscv/kernel/vendor_extensions.c
> @@ -3,6 +3,7 @@
>   * Copyright 2024 Rivos, Inc
>   */
>  
> +#include <asm/vendorid_list.h>
>  #include <asm/vendor_extensions.h>
>  #include <asm/vendor_extensions/thead.h>
>  
> @@ -16,3 +17,42 @@ const struct riscv_isa_vendor_ext_data_list *riscv_isa_vendor_ext_list[] = {
>  };
>  
>  const size_t riscv_isa_vendor_ext_list_size = ARRAY_SIZE(riscv_isa_vendor_ext_list);
> +
> +/**
> + * __riscv_isa_vendor_extension_available() - Check whether given vendor
> + * extension is available or not.
> + *
> + * @cpu: check if extension is available on this cpu
> + * @vendor: vendor that the extension is a member of
> + * @bit: bit position of the desired extension
> + * Return: true or false
> + *
> + * NOTE: When cpu is -1, will check if extension is available on all cpus
> + */
> +bool __riscv_isa_vendor_extension_available(int cpu, unsigned long vendor, unsigned int bit)
> +{
> +	unsigned long *bmap;
> +	struct riscv_isainfo *cpu_bmap;
> +	size_t bmap_size;
> +
> +	switch (vendor) {
> +#ifdef CONFIG_RISCV_ISA_VENDOR_EXT_THEAD
> +	case THEAD_VENDOR_ID:
> +		bmap = riscv_isa_vendor_ext_list_thead.vendor_bitmap;
> +		cpu_bmap = riscv_isa_vendor_ext_list_thead.per_hart_vendor_bitmap;
> +		bmap_size = riscv_isa_vendor_ext_list_thead.bitmap_size;
> +		break;
> +#endif
> +	default:
> +		return false;
> +	}
> +
> +	if (cpu != -1)
> +		bmap = cpu_bmap[cpu].isa;
> +
> +	if (bit >= bmap_size)
> +		return false;
> +
> +	return test_bit(bit, bmap) ? true : false;
> +}
> +EXPORT_SYMBOL_GPL(__riscv_isa_vendor_extension_available);
> 
> -- 
> 2.44.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

WARNING: multiple messages have this Message-ID (diff)
From: Conor Dooley <conor@kernel.org>
To: Charlie Jenkins <charlie@rivosinc.com>
Cc: "Rob Herring" <robh@kernel.org>,
	"Krzysztof Kozlowski" <krzysztof.kozlowski+dt@linaro.org>,
	"Paul Walmsley" <paul.walmsley@sifive.com>,
	"Palmer Dabbelt" <palmer@dabbelt.com>,
	"Albert Ou" <aou@eecs.berkeley.edu>,
	"Guo Ren" <guoren@kernel.org>,
	"Conor Dooley" <conor+dt@kernel.org>,
	"Chen-Yu Tsai" <wens@csie.org>,
	"Jernej Skrabec" <jernej.skrabec@gmail.com>,
	"Samuel Holland" <samuel@sholland.org>,
	"Conor Dooley" <conor.dooley@microchip.com>,
	"Evan Green" <evan@rivosinc.com>,
	"Clément Léger" <cleger@rivosinc.com>,
	"Jonathan Corbet" <corbet@lwn.net>,
	"Shuah Khan" <shuah@kernel.org>,
	linux-riscv@lists.infradead.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	"Palmer Dabbelt" <palmer@rivosinc.com>,
	linux-arm-kernel@lists.infradead.org,
	linux-sunxi@lists.linux.dev, linux-doc@vger.kernel.org,
	linux-kselftest@vger.kernel.org
Subject: Re: [PATCH v3 08/17] riscv: Introduce vendor variants of extension helpers
Date: Fri, 26 Apr 2024 17:19:59 +0100	[thread overview]
Message-ID: <20240426-myself-crowbar-99dc0a080cd9@spud> (raw)
In-Reply-To: <20240420-dev-charlie-support_thead_vector_6_9-v3-8-67cff4271d1d@rivosinc.com>


[-- Attachment #1.1: Type: text/plain, Size: 13642 bytes --]

On Sat, Apr 20, 2024 at 06:04:40PM -0700, Charlie Jenkins wrote:
> Vendor extensions are maintained in per-vendor structs (separate from
> standard extensions which live in riscv_isa). Create vendor variants for
> the existing extension helpers to interface with the riscv_isa_vendor
> bitmaps.

> There is a good amount of overlap between these functions, so
> the alternative checking code can be factored out.

Can you please split this out?

> 
> Signed-off-by: Charlie Jenkins <charlie@rivosinc.com>
> ---
>  arch/riscv/errata/sifive/errata.c          |  3 ++
>  arch/riscv/errata/thead/errata.c           |  3 ++
>  arch/riscv/include/asm/cpufeature.h        | 86 +++++++++++++++++-------------
>  arch/riscv/include/asm/vendor_extensions.h | 56 +++++++++++++++++++
>  arch/riscv/kernel/cpufeature.c             | 20 ++++---
>  arch/riscv/kernel/vendor_extensions.c      | 40 ++++++++++++++
>  6 files changed, 164 insertions(+), 44 deletions(-)
> 
> diff --git a/arch/riscv/errata/sifive/errata.c b/arch/riscv/errata/sifive/errata.c
> index 3d9a32d791f7..b29b6e405ff2 100644
> --- a/arch/riscv/errata/sifive/errata.c
> +++ b/arch/riscv/errata/sifive/errata.c
> @@ -12,6 +12,7 @@
>  #include <asm/alternative.h>
>  #include <asm/vendorid_list.h>
>  #include <asm/errata_list.h>
> +#include <asm/vendor_extensions.h>
>  
>  struct errata_info_t {
>  	char name[32];
> @@ -99,6 +100,8 @@ void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
>  	for (alt = begin; alt < end; alt++) {
>  		if (alt->vendor_id != SIFIVE_VENDOR_ID)
>  			continue;
> +		if (alt->patch_id >= RISCV_VENDOR_EXT_ALTERNATIVES_BASE)
> +			continue;
>  		if (alt->patch_id >= ERRATA_SIFIVE_NUMBER) {
>  			WARN(1, "This errata id:%d is not in kernel errata list", alt->patch_id);
>  			continue;
> diff --git a/arch/riscv/errata/thead/errata.c b/arch/riscv/errata/thead/errata.c
> index b1c410bbc1ae..d8e78cc687bc 100644
> --- a/arch/riscv/errata/thead/errata.c
> +++ b/arch/riscv/errata/thead/errata.c
> @@ -18,6 +18,7 @@
>  #include <asm/io.h>
>  #include <asm/patch.h>
>  #include <asm/vendorid_list.h>
> +#include <asm/vendor_extensions.h>
>  
>  static bool errata_probe_pbmt(unsigned int stage,
>  			      unsigned long arch_id, unsigned long impid)
> @@ -163,6 +164,8 @@ void thead_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
>  	for (alt = begin; alt < end; alt++) {
>  		if (alt->vendor_id != THEAD_VENDOR_ID)
>  			continue;
> +		if (alt->patch_id >= RISCV_VENDOR_EXT_ALTERNATIVES_BASE)
> +			continue;

>  		if (alt->patch_id >= ERRATA_THEAD_NUMBER)

This number is 2, how does the patching actually work for vendor stuff
when the base is always greater than 2?

>  			continue;
>  
> diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
> index db6a6d7d6b2e..83e1143db9ad 100644
> --- a/arch/riscv/include/asm/cpufeature.h
> +++ b/arch/riscv/include/asm/cpufeature.h
> @@ -103,22 +103,13 @@ bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, unsigned i
>  	__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_##ext)
>  
>  static __always_inline bool
> -riscv_has_extension_likely(const unsigned long ext)
> +__riscv_has_extension_likely_alternatives(const unsigned long vendor, const unsigned long ext)
>  {
> -	compiletime_assert(ext < RISCV_ISA_EXT_MAX,
> -			   "ext must be < RISCV_ISA_EXT_MAX");
> -
> -	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) {
> -		asm goto(
> -		ALTERNATIVE("j	%l[l_no]", "nop", 0, %[ext], 1)
> -		:
> -		: [ext] "i" (ext)
> -		:
> -		: l_no);
> -	} else {
> -		if (!__riscv_isa_extension_available(NULL, ext))
> -			goto l_no;
> -	}
> +	asm goto(ALTERNATIVE("j	%l[l_no]", "nop", %[vendor], %[ext], 1)
> +	:
> +	: [vendor] "i" (vendor), [ext] "i" (ext)
> +	:
> +	: l_no);
>  
>  	return true;
>  l_no:
> @@ -126,42 +117,65 @@ riscv_has_extension_likely(const unsigned long ext)
>  }
>  
>  static __always_inline bool
> -riscv_has_extension_unlikely(const unsigned long ext)
> +__riscv_has_extension_unlikely_alternatives(const unsigned long vendor, const unsigned long ext)

ngl, I think you could drop the _alternatives from these - the
likely/unlikely is only actually a thing because of the alternatives in
the first place & just retain the __ as a differentiator. That'd help
you with some of the long-line wrangling you've been doing below.

>  {
> -	compiletime_assert(ext < RISCV_ISA_EXT_MAX,
> -			   "ext must be < RISCV_ISA_EXT_MAX");
> -
> -	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) {
> -		asm goto(
> -		ALTERNATIVE("nop", "j	%l[l_yes]", 0, %[ext], 1)
> -		:
> -		: [ext] "i" (ext)
> -		:
> -		: l_yes);
> -	} else {
> -		if (__riscv_isa_extension_available(NULL, ext))
> -			goto l_yes;
> -	}
> +	asm goto(ALTERNATIVE("nop", "j	%l[l_yes]", %[vendor], %[ext], 1)
> +	:
> +	: [vendor] "i" (vendor), [ext] "i" (ext)
> +	:
> +	: l_yes);
>  
>  	return false;
>  l_yes:
>  	return true;
>  }
>  
> +static __always_inline bool
> +riscv_has_extension_likely(const unsigned long ext)

Can you format this so that its on one line & wrap the arguments if
needs be?

> +{
> +	compiletime_assert(ext < RISCV_ISA_EXT_MAX,
> +			   "ext must be < RISCV_ISA_EXT_MAX");
> +
> +	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE))
> +		return __riscv_has_extension_likely_alternatives(0, ext);
> +	else

I'm almost certain I said this before, but none of the else branches are
needed here, there's a return in the if branch, so the remainder of the
function becomes unconditionally executed.

> +		return __riscv_isa_extension_available(NULL, ext);
> +}
> +
> +static __always_inline bool
> +riscv_has_extension_unlikely(const unsigned long ext)
> +{
> +	compiletime_assert(ext < RISCV_ISA_EXT_MAX,
> +			   "ext must be < RISCV_ISA_EXT_MAX");
> +
> +	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE))
> +		return __riscv_has_extension_unlikely_alternatives(0, ext);
> +	else
> +		return __riscv_isa_extension_available(NULL, ext);
> +}
> +
>  static __always_inline bool riscv_cpu_has_extension_likely(int cpu, const unsigned long ext)
>  {
> -	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) && riscv_has_extension_likely(ext))
> -		return true;
> +	compiletime_assert(ext < RISCV_ISA_EXT_MAX,
> +			   "ext must be < RISCV_ISA_EXT_MAX");
>  
> -	return __riscv_isa_extension_available(hart_isa[cpu].isa, ext);
> +	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) &&
> +	    __riscv_has_extension_likely_alternatives(0, ext))

0 is meaningless, please make this more understandable using a define of
some sort.

> +		return true;
> +	else
> +		return __riscv_isa_extension_available(hart_isa[cpu].isa, ext);
>  }
>  
>  static __always_inline bool riscv_cpu_has_extension_unlikely(int cpu, const unsigned long ext)
>  {
> -	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) && riscv_has_extension_unlikely(ext))
> -		return true;
> +	compiletime_assert(ext < RISCV_ISA_EXT_MAX,
> +			   "ext must be < RISCV_ISA_EXT_MAX");
>  
> -	return __riscv_isa_extension_available(hart_isa[cpu].isa, ext);
> +	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) &&
> +	    __riscv_has_extension_unlikely_alternatives(0, ext))
> +		return true;
> +	else
> +		return __riscv_isa_extension_available(hart_isa[cpu].isa, ext);
>  }
>  
>  #endif
> diff --git a/arch/riscv/include/asm/vendor_extensions.h b/arch/riscv/include/asm/vendor_extensions.h
> index 0af1ddd0af70..3e676a96016e 100644
> --- a/arch/riscv/include/asm/vendor_extensions.h
> +++ b/arch/riscv/include/asm/vendor_extensions.h
> @@ -23,4 +23,60 @@ extern const struct riscv_isa_vendor_ext_data_list *riscv_isa_vendor_ext_list[];
>  
>  extern const size_t riscv_isa_vendor_ext_list_size;
>  
> +/*
> + * The alternatives need some way of distinguishing between vendor extensions
> + * and errata. Incrementing all of the vendor extension keys so they are at
> + * least 0x8000 accomplishes that.
> + */
> +#define RISCV_VENDOR_EXT_ALTERNATIVES_BASE	0x8000
> +
> +bool __riscv_isa_vendor_extension_available(int cpu, unsigned long vendor, unsigned int bit);
> +#define riscv_cpu_isa_vendor_extension_available(cpu, vendor, ext)	\
> +	__riscv_isa_vendor_extension_available(cpu, vendor, RISCV_ISA_VENDOR_EXT_##ext)
> +#define riscv_isa_vendor_extension_available(vendor, ext)	\
> +	__riscv_isa_vendor_extension_available(-1, vendor, RISCV_ISA_VENDOR_EXT_##ext)
> +
> +static __always_inline bool
> +riscv_has_vendor_extension_likely(const unsigned long vendor, const unsigned long ext)
> +{
> +	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE))
> +		return __riscv_has_extension_likely_alternatives(vendor,
> +								 ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE);
> +	else
> +		return __riscv_isa_vendor_extension_available(-1, vendor, ext);
> +}
> +
> +static __always_inline bool
> +riscv_has_vendor_extension_unlikely(const unsigned long vendor, const unsigned long ext)
> +{
> +	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE))
> +		return __riscv_has_extension_unlikely_alternatives(vendor,
> +								   ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE);
> +	else
> +		return __riscv_isa_vendor_extension_available(-1, vendor, ext);
> +}
> +
> +static __always_inline bool riscv_cpu_has_vendor_extension_likely(const unsigned long vendor,
> +								  int cpu, const unsigned long ext)
> +{
> +	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) &&
> +	    __riscv_has_extension_likely_alternatives(vendor,
> +						      ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE))
> +		return true;
> +	else
> +		return __riscv_isa_vendor_extension_available(cpu, vendor, ext);
> +}
> +
> +static __always_inline bool riscv_cpu_has_vendor_extension_unlikely(const unsigned long vendor,
> +								    int cpu,
> +								    const unsigned long ext)
> +{
> +	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) &&
> +	    __riscv_has_extension_unlikely_alternatives(vendor,
> +							ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE))
> +		return true;
> +	else
> +		return __riscv_isa_vendor_extension_available(cpu, vendor, ext);
> +}
> +
>  #endif /* _ASM_VENDOR_EXTENSIONS_H */
> diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> index c9f36822e337..17371887abcc 100644
> --- a/arch/riscv/kernel/cpufeature.c
> +++ b/arch/riscv/kernel/cpufeature.c
> @@ -833,25 +833,29 @@ void __init_or_module riscv_cpufeature_patch_func(struct alt_entry *begin,
>  {
>  	struct alt_entry *alt;
>  	void *oldptr, *altptr;
> -	u16 id, value;
> +	u16 id, value, vendor;
>  
>  	if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
>  		return;
>  
>  	for (alt = begin; alt < end; alt++) {
> -		if (alt->vendor_id != 0)
> -			continue;
> -
>  		id = PATCH_ID_CPUFEATURE_ID(alt->patch_id);
> +		vendor = PATCH_ID_CPUFEATURE_ID(alt->vendor_id);
>  
> -		if (id >= RISCV_ISA_EXT_MAX) {
> +		if (id < RISCV_ISA_EXT_MAX) {

I think any reliance on the standard ext max requires a comment
explaining what the interaction is between it and the vendor stuff.

> +			if (alt->vendor_id != 0)
> +				continue;

If this happens, it's a bug, should we be continuing silently?

Cheers,
Conor.

> +
> +			if (!__riscv_isa_extension_available(NULL, id))
> +				continue;
> +		} else if (id >= RISCV_VENDOR_EXT_ALTERNATIVES_BASE) {
> +			if (!__riscv_isa_vendor_extension_available(-1, vendor, id))
> +				continue;
> +		} else {
>  			WARN(1, "This extension id:%d is not in ISA extension list", id);
>  			continue;
>  		}
>  
> -		if (!__riscv_isa_extension_available(NULL, id))
> -			continue;
> -
>  		value = PATCH_ID_CPUFEATURE_VALUE(alt->patch_id);
>  		if (!riscv_cpufeature_patch_check(id, value))
>  			continue;
> diff --git a/arch/riscv/kernel/vendor_extensions.c b/arch/riscv/kernel/vendor_extensions.c
> index f76cb3013c2d..eced93eec5a6 100644
> --- a/arch/riscv/kernel/vendor_extensions.c
> +++ b/arch/riscv/kernel/vendor_extensions.c
> @@ -3,6 +3,7 @@
>   * Copyright 2024 Rivos, Inc
>   */
>  
> +#include <asm/vendorid_list.h>
>  #include <asm/vendor_extensions.h>
>  #include <asm/vendor_extensions/thead.h>
>  
> @@ -16,3 +17,42 @@ const struct riscv_isa_vendor_ext_data_list *riscv_isa_vendor_ext_list[] = {
>  };
>  
>  const size_t riscv_isa_vendor_ext_list_size = ARRAY_SIZE(riscv_isa_vendor_ext_list);
> +
> +/**
> + * __riscv_isa_vendor_extension_available() - Check whether given vendor
> + * extension is available or not.
> + *
> + * @cpu: check if extension is available on this cpu
> + * @vendor: vendor that the extension is a member of
> + * @bit: bit position of the desired extension
> + * Return: true or false
> + *
> + * NOTE: When cpu is -1, will check if extension is available on all cpus
> + */
> +bool __riscv_isa_vendor_extension_available(int cpu, unsigned long vendor, unsigned int bit)
> +{
> +	unsigned long *bmap;
> +	struct riscv_isainfo *cpu_bmap;
> +	size_t bmap_size;
> +
> +	switch (vendor) {
> +#ifdef CONFIG_RISCV_ISA_VENDOR_EXT_THEAD
> +	case THEAD_VENDOR_ID:
> +		bmap = riscv_isa_vendor_ext_list_thead.vendor_bitmap;
> +		cpu_bmap = riscv_isa_vendor_ext_list_thead.per_hart_vendor_bitmap;
> +		bmap_size = riscv_isa_vendor_ext_list_thead.bitmap_size;
> +		break;
> +#endif
> +	default:
> +		return false;
> +	}
> +
> +	if (cpu != -1)
> +		bmap = cpu_bmap[cpu].isa;
> +
> +	if (bit >= bmap_size)
> +		return false;
> +
> +	return test_bit(bit, bmap) ? true : false;
> +}
> +EXPORT_SYMBOL_GPL(__riscv_isa_vendor_extension_available);
> 
> -- 
> 2.44.0
> 

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 161 bytes --]

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

WARNING: multiple messages have this Message-ID (diff)
From: Conor Dooley <conor@kernel.org>
To: Charlie Jenkins <charlie@rivosinc.com>
Cc: "Rob Herring" <robh@kernel.org>,
	"Krzysztof Kozlowski" <krzysztof.kozlowski+dt@linaro.org>,
	"Paul Walmsley" <paul.walmsley@sifive.com>,
	"Palmer Dabbelt" <palmer@dabbelt.com>,
	"Albert Ou" <aou@eecs.berkeley.edu>,
	"Guo Ren" <guoren@kernel.org>,
	"Conor Dooley" <conor+dt@kernel.org>,
	"Chen-Yu Tsai" <wens@csie.org>,
	"Jernej Skrabec" <jernej.skrabec@gmail.com>,
	"Samuel Holland" <samuel@sholland.org>,
	"Conor Dooley" <conor.dooley@microchip.com>,
	"Evan Green" <evan@rivosinc.com>,
	"Clément Léger" <cleger@rivosinc.com>,
	"Jonathan Corbet" <corbet@lwn.net>,
	"Shuah Khan" <shuah@kernel.org>,
	linux-riscv@lists.infradead.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	"Palmer Dabbelt" <palmer@rivosinc.com>,
	linux-arm-kernel@lists.infradead.org,
	linux-sunxi@lists.linux.dev, linux-doc@vger.kernel.org,
	linux-kselftest@vger.kernel.org
Subject: Re: [PATCH v3 08/17] riscv: Introduce vendor variants of extension helpers
Date: Fri, 26 Apr 2024 17:19:59 +0100	[thread overview]
Message-ID: <20240426-myself-crowbar-99dc0a080cd9@spud> (raw)
In-Reply-To: <20240420-dev-charlie-support_thead_vector_6_9-v3-8-67cff4271d1d@rivosinc.com>


[-- Attachment #1.1: Type: text/plain, Size: 13642 bytes --]

On Sat, Apr 20, 2024 at 06:04:40PM -0700, Charlie Jenkins wrote:
> Vendor extensions are maintained in per-vendor structs (separate from
> standard extensions which live in riscv_isa). Create vendor variants for
> the existing extension helpers to interface with the riscv_isa_vendor
> bitmaps.

> There is a good amount of overlap between these functions, so
> the alternative checking code can be factored out.

Can you please split this out?

> 
> Signed-off-by: Charlie Jenkins <charlie@rivosinc.com>
> ---
>  arch/riscv/errata/sifive/errata.c          |  3 ++
>  arch/riscv/errata/thead/errata.c           |  3 ++
>  arch/riscv/include/asm/cpufeature.h        | 86 +++++++++++++++++-------------
>  arch/riscv/include/asm/vendor_extensions.h | 56 +++++++++++++++++++
>  arch/riscv/kernel/cpufeature.c             | 20 ++++---
>  arch/riscv/kernel/vendor_extensions.c      | 40 ++++++++++++++
>  6 files changed, 164 insertions(+), 44 deletions(-)
> 
> diff --git a/arch/riscv/errata/sifive/errata.c b/arch/riscv/errata/sifive/errata.c
> index 3d9a32d791f7..b29b6e405ff2 100644
> --- a/arch/riscv/errata/sifive/errata.c
> +++ b/arch/riscv/errata/sifive/errata.c
> @@ -12,6 +12,7 @@
>  #include <asm/alternative.h>
>  #include <asm/vendorid_list.h>
>  #include <asm/errata_list.h>
> +#include <asm/vendor_extensions.h>
>  
>  struct errata_info_t {
>  	char name[32];
> @@ -99,6 +100,8 @@ void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
>  	for (alt = begin; alt < end; alt++) {
>  		if (alt->vendor_id != SIFIVE_VENDOR_ID)
>  			continue;
> +		if (alt->patch_id >= RISCV_VENDOR_EXT_ALTERNATIVES_BASE)
> +			continue;
>  		if (alt->patch_id >= ERRATA_SIFIVE_NUMBER) {
>  			WARN(1, "This errata id:%d is not in kernel errata list", alt->patch_id);
>  			continue;
> diff --git a/arch/riscv/errata/thead/errata.c b/arch/riscv/errata/thead/errata.c
> index b1c410bbc1ae..d8e78cc687bc 100644
> --- a/arch/riscv/errata/thead/errata.c
> +++ b/arch/riscv/errata/thead/errata.c
> @@ -18,6 +18,7 @@
>  #include <asm/io.h>
>  #include <asm/patch.h>
>  #include <asm/vendorid_list.h>
> +#include <asm/vendor_extensions.h>
>  
>  static bool errata_probe_pbmt(unsigned int stage,
>  			      unsigned long arch_id, unsigned long impid)
> @@ -163,6 +164,8 @@ void thead_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
>  	for (alt = begin; alt < end; alt++) {
>  		if (alt->vendor_id != THEAD_VENDOR_ID)
>  			continue;
> +		if (alt->patch_id >= RISCV_VENDOR_EXT_ALTERNATIVES_BASE)
> +			continue;

>  		if (alt->patch_id >= ERRATA_THEAD_NUMBER)

This number is 2, how does the patching actually work for vendor stuff
when the base is always greater than 2?

>  			continue;
>  
> diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
> index db6a6d7d6b2e..83e1143db9ad 100644
> --- a/arch/riscv/include/asm/cpufeature.h
> +++ b/arch/riscv/include/asm/cpufeature.h
> @@ -103,22 +103,13 @@ bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, unsigned i
>  	__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_##ext)
>  
>  static __always_inline bool
> -riscv_has_extension_likely(const unsigned long ext)
> +__riscv_has_extension_likely_alternatives(const unsigned long vendor, const unsigned long ext)
>  {
> -	compiletime_assert(ext < RISCV_ISA_EXT_MAX,
> -			   "ext must be < RISCV_ISA_EXT_MAX");
> -
> -	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) {
> -		asm goto(
> -		ALTERNATIVE("j	%l[l_no]", "nop", 0, %[ext], 1)
> -		:
> -		: [ext] "i" (ext)
> -		:
> -		: l_no);
> -	} else {
> -		if (!__riscv_isa_extension_available(NULL, ext))
> -			goto l_no;
> -	}
> +	asm goto(ALTERNATIVE("j	%l[l_no]", "nop", %[vendor], %[ext], 1)
> +	:
> +	: [vendor] "i" (vendor), [ext] "i" (ext)
> +	:
> +	: l_no);
>  
>  	return true;
>  l_no:
> @@ -126,42 +117,65 @@ riscv_has_extension_likely(const unsigned long ext)
>  }
>  
>  static __always_inline bool
> -riscv_has_extension_unlikely(const unsigned long ext)
> +__riscv_has_extension_unlikely_alternatives(const unsigned long vendor, const unsigned long ext)

ngl, I think you could drop the _alternatives from these - the
likely/unlikely is only actually a thing because of the alternatives in
the first place & just retain the __ as a differentiator. That'd help
you with some of the long-line wrangling you've been doing below.

>  {
> -	compiletime_assert(ext < RISCV_ISA_EXT_MAX,
> -			   "ext must be < RISCV_ISA_EXT_MAX");
> -
> -	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) {
> -		asm goto(
> -		ALTERNATIVE("nop", "j	%l[l_yes]", 0, %[ext], 1)
> -		:
> -		: [ext] "i" (ext)
> -		:
> -		: l_yes);
> -	} else {
> -		if (__riscv_isa_extension_available(NULL, ext))
> -			goto l_yes;
> -	}
> +	asm goto(ALTERNATIVE("nop", "j	%l[l_yes]", %[vendor], %[ext], 1)
> +	:
> +	: [vendor] "i" (vendor), [ext] "i" (ext)
> +	:
> +	: l_yes);
>  
>  	return false;
>  l_yes:
>  	return true;
>  }
>  
> +static __always_inline bool
> +riscv_has_extension_likely(const unsigned long ext)

Can you format this so that its on one line & wrap the arguments if
needs be?

> +{
> +	compiletime_assert(ext < RISCV_ISA_EXT_MAX,
> +			   "ext must be < RISCV_ISA_EXT_MAX");
> +
> +	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE))
> +		return __riscv_has_extension_likely_alternatives(0, ext);
> +	else

I'm almost certain I said this before, but none of the else branches are
needed here, there's a return in the if branch, so the remainder of the
function becomes unconditionally executed.

> +		return __riscv_isa_extension_available(NULL, ext);
> +}
> +
> +static __always_inline bool
> +riscv_has_extension_unlikely(const unsigned long ext)
> +{
> +	compiletime_assert(ext < RISCV_ISA_EXT_MAX,
> +			   "ext must be < RISCV_ISA_EXT_MAX");
> +
> +	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE))
> +		return __riscv_has_extension_unlikely_alternatives(0, ext);
> +	else
> +		return __riscv_isa_extension_available(NULL, ext);
> +}
> +
>  static __always_inline bool riscv_cpu_has_extension_likely(int cpu, const unsigned long ext)
>  {
> -	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) && riscv_has_extension_likely(ext))
> -		return true;
> +	compiletime_assert(ext < RISCV_ISA_EXT_MAX,
> +			   "ext must be < RISCV_ISA_EXT_MAX");
>  
> -	return __riscv_isa_extension_available(hart_isa[cpu].isa, ext);
> +	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) &&
> +	    __riscv_has_extension_likely_alternatives(0, ext))

0 is meaningless, please make this more understandable using a define of
some sort.

> +		return true;
> +	else
> +		return __riscv_isa_extension_available(hart_isa[cpu].isa, ext);
>  }
>  
>  static __always_inline bool riscv_cpu_has_extension_unlikely(int cpu, const unsigned long ext)
>  {
> -	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) && riscv_has_extension_unlikely(ext))
> -		return true;
> +	compiletime_assert(ext < RISCV_ISA_EXT_MAX,
> +			   "ext must be < RISCV_ISA_EXT_MAX");
>  
> -	return __riscv_isa_extension_available(hart_isa[cpu].isa, ext);
> +	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) &&
> +	    __riscv_has_extension_unlikely_alternatives(0, ext))
> +		return true;
> +	else
> +		return __riscv_isa_extension_available(hart_isa[cpu].isa, ext);
>  }
>  
>  #endif
> diff --git a/arch/riscv/include/asm/vendor_extensions.h b/arch/riscv/include/asm/vendor_extensions.h
> index 0af1ddd0af70..3e676a96016e 100644
> --- a/arch/riscv/include/asm/vendor_extensions.h
> +++ b/arch/riscv/include/asm/vendor_extensions.h
> @@ -23,4 +23,60 @@ extern const struct riscv_isa_vendor_ext_data_list *riscv_isa_vendor_ext_list[];
>  
>  extern const size_t riscv_isa_vendor_ext_list_size;
>  
> +/*
> + * The alternatives need some way of distinguishing between vendor extensions
> + * and errata. Incrementing all of the vendor extension keys so they are at
> + * least 0x8000 accomplishes that.
> + */
> +#define RISCV_VENDOR_EXT_ALTERNATIVES_BASE	0x8000
> +
> +bool __riscv_isa_vendor_extension_available(int cpu, unsigned long vendor, unsigned int bit);
> +#define riscv_cpu_isa_vendor_extension_available(cpu, vendor, ext)	\
> +	__riscv_isa_vendor_extension_available(cpu, vendor, RISCV_ISA_VENDOR_EXT_##ext)
> +#define riscv_isa_vendor_extension_available(vendor, ext)	\
> +	__riscv_isa_vendor_extension_available(-1, vendor, RISCV_ISA_VENDOR_EXT_##ext)
> +
> +static __always_inline bool
> +riscv_has_vendor_extension_likely(const unsigned long vendor, const unsigned long ext)
> +{
> +	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE))
> +		return __riscv_has_extension_likely_alternatives(vendor,
> +								 ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE);
> +	else
> +		return __riscv_isa_vendor_extension_available(-1, vendor, ext);
> +}
> +
> +static __always_inline bool
> +riscv_has_vendor_extension_unlikely(const unsigned long vendor, const unsigned long ext)
> +{
> +	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE))
> +		return __riscv_has_extension_unlikely_alternatives(vendor,
> +								   ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE);
> +	else
> +		return __riscv_isa_vendor_extension_available(-1, vendor, ext);
> +}
> +
> +static __always_inline bool riscv_cpu_has_vendor_extension_likely(const unsigned long vendor,
> +								  int cpu, const unsigned long ext)
> +{
> +	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) &&
> +	    __riscv_has_extension_likely_alternatives(vendor,
> +						      ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE))
> +		return true;
> +	else
> +		return __riscv_isa_vendor_extension_available(cpu, vendor, ext);
> +}
> +
> +static __always_inline bool riscv_cpu_has_vendor_extension_unlikely(const unsigned long vendor,
> +								    int cpu,
> +								    const unsigned long ext)
> +{
> +	if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) &&
> +	    __riscv_has_extension_unlikely_alternatives(vendor,
> +							ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE))
> +		return true;
> +	else
> +		return __riscv_isa_vendor_extension_available(cpu, vendor, ext);
> +}
> +
>  #endif /* _ASM_VENDOR_EXTENSIONS_H */
> diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> index c9f36822e337..17371887abcc 100644
> --- a/arch/riscv/kernel/cpufeature.c
> +++ b/arch/riscv/kernel/cpufeature.c
> @@ -833,25 +833,29 @@ void __init_or_module riscv_cpufeature_patch_func(struct alt_entry *begin,
>  {
>  	struct alt_entry *alt;
>  	void *oldptr, *altptr;
> -	u16 id, value;
> +	u16 id, value, vendor;
>  
>  	if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
>  		return;
>  
>  	for (alt = begin; alt < end; alt++) {
> -		if (alt->vendor_id != 0)
> -			continue;
> -
>  		id = PATCH_ID_CPUFEATURE_ID(alt->patch_id);
> +		vendor = PATCH_ID_CPUFEATURE_ID(alt->vendor_id);
>  
> -		if (id >= RISCV_ISA_EXT_MAX) {
> +		if (id < RISCV_ISA_EXT_MAX) {

I think any reliance on the standard ext max requires a comment
explaining what the interaction is between it and the vendor stuff.

> +			if (alt->vendor_id != 0)
> +				continue;

If this happens, it's a bug, should we be continuing silently?

Cheers,
Conor.

> +
> +			if (!__riscv_isa_extension_available(NULL, id))
> +				continue;
> +		} else if (id >= RISCV_VENDOR_EXT_ALTERNATIVES_BASE) {
> +			if (!__riscv_isa_vendor_extension_available(-1, vendor, id))
> +				continue;
> +		} else {
>  			WARN(1, "This extension id:%d is not in ISA extension list", id);
>  			continue;
>  		}
>  
> -		if (!__riscv_isa_extension_available(NULL, id))
> -			continue;
> -
>  		value = PATCH_ID_CPUFEATURE_VALUE(alt->patch_id);
>  		if (!riscv_cpufeature_patch_check(id, value))
>  			continue;
> diff --git a/arch/riscv/kernel/vendor_extensions.c b/arch/riscv/kernel/vendor_extensions.c
> index f76cb3013c2d..eced93eec5a6 100644
> --- a/arch/riscv/kernel/vendor_extensions.c
> +++ b/arch/riscv/kernel/vendor_extensions.c
> @@ -3,6 +3,7 @@
>   * Copyright 2024 Rivos, Inc
>   */
>  
> +#include <asm/vendorid_list.h>
>  #include <asm/vendor_extensions.h>
>  #include <asm/vendor_extensions/thead.h>
>  
> @@ -16,3 +17,42 @@ const struct riscv_isa_vendor_ext_data_list *riscv_isa_vendor_ext_list[] = {
>  };
>  
>  const size_t riscv_isa_vendor_ext_list_size = ARRAY_SIZE(riscv_isa_vendor_ext_list);
> +
> +/**
> + * __riscv_isa_vendor_extension_available() - Check whether given vendor
> + * extension is available or not.
> + *
> + * @cpu: check if extension is available on this cpu
> + * @vendor: vendor that the extension is a member of
> + * @bit: bit position of the desired extension
> + * Return: true or false
> + *
> + * NOTE: When cpu is -1, will check if extension is available on all cpus
> + */
> +bool __riscv_isa_vendor_extension_available(int cpu, unsigned long vendor, unsigned int bit)
> +{
> +	unsigned long *bmap;
> +	struct riscv_isainfo *cpu_bmap;
> +	size_t bmap_size;
> +
> +	switch (vendor) {
> +#ifdef CONFIG_RISCV_ISA_VENDOR_EXT_THEAD
> +	case THEAD_VENDOR_ID:
> +		bmap = riscv_isa_vendor_ext_list_thead.vendor_bitmap;
> +		cpu_bmap = riscv_isa_vendor_ext_list_thead.per_hart_vendor_bitmap;
> +		bmap_size = riscv_isa_vendor_ext_list_thead.bitmap_size;
> +		break;
> +#endif
> +	default:
> +		return false;
> +	}
> +
> +	if (cpu != -1)
> +		bmap = cpu_bmap[cpu].isa;
> +
> +	if (bit >= bmap_size)
> +		return false;
> +
> +	return test_bit(bit, bmap) ? true : false;
> +}
> +EXPORT_SYMBOL_GPL(__riscv_isa_vendor_extension_available);
> 
> -- 
> 2.44.0
> 

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  reply	other threads:[~2024-04-26 16:20 UTC|newest]

Thread overview: 105+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-04-21  1:04 [PATCH v3 00/17] riscv: Support vendor extensions and xtheadvector Charlie Jenkins
2024-04-21  1:04 ` Charlie Jenkins
2024-04-21  1:04 ` Charlie Jenkins
2024-04-21  1:04 ` [PATCH v3 01/17] riscv: cpufeature: Fix thead vector hwcap removal Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-26  8:15   ` Guo Ren
2024-04-26  8:15     ` Guo Ren
2024-04-26  8:15     ` Guo Ren
2024-04-21  1:04 ` [PATCH v3 02/17] dt-bindings: riscv: Add xtheadvector ISA extension description Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-21  1:04 ` [PATCH v3 03/17] dt-bindings: riscv: cpus: add a vlen register length property Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-21  1:04 ` [PATCH v3 04/17] riscv: vector: Use vlenb from DT Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-26 15:17   ` Conor Dooley
2024-04-26 15:17     ` Conor Dooley
2024-04-26 15:17     ` Conor Dooley
2024-04-26 16:21     ` Conor Dooley
2024-04-26 16:21       ` Conor Dooley
2024-04-26 16:21       ` Conor Dooley
2024-04-26 17:03       ` Charlie Jenkins
2024-04-26 17:03         ` Charlie Jenkins
2024-04-26 17:03         ` Charlie Jenkins
2024-04-21  1:04 ` [PATCH v3 05/17] riscv: dts: allwinner: Add xtheadvector to the D1/D1s devicetree Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-21  1:04 ` [PATCH v3 06/17] riscv: Fix extension subset checking Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-24 14:22   ` Alexandre Ghiti
2024-04-24 14:22     ` Alexandre Ghiti
2024-04-24 14:22     ` Alexandre Ghiti
2024-04-24 14:51     ` Conor Dooley
2024-04-24 14:51       ` Conor Dooley
2024-04-24 14:51       ` Conor Dooley
2024-04-24 15:13       ` Charlie Jenkins
2024-04-24 15:13         ` Charlie Jenkins
2024-04-24 15:13         ` Charlie Jenkins
2024-04-24 15:21         ` Conor Dooley
2024-04-24 15:21           ` Conor Dooley
2024-04-24 15:21           ` Conor Dooley
2024-04-24 15:36           ` Charlie Jenkins
2024-04-24 15:36             ` Charlie Jenkins
2024-04-24 15:36             ` Charlie Jenkins
2024-04-21  1:04 ` [PATCH v3 07/17] riscv: Extend cpufeature.c to detect vendor extensions Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-26 16:00   ` Conor Dooley
2024-04-26 16:00     ` Conor Dooley
2024-04-26 16:00     ` Conor Dooley
2024-04-26 18:00     ` Charlie Jenkins
2024-04-26 18:00       ` Charlie Jenkins
2024-04-26 18:00       ` Charlie Jenkins
2024-04-21  1:04 ` [PATCH v3 08/17] riscv: Introduce vendor variants of extension helpers Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-26 16:19   ` Conor Dooley [this message]
2024-04-26 16:19     ` Conor Dooley
2024-04-26 16:19     ` Conor Dooley
2024-04-26 20:01     ` Charlie Jenkins
2024-04-26 20:01       ` Charlie Jenkins
2024-04-26 20:01       ` Charlie Jenkins
2024-04-26 20:37       ` Conor Dooley
2024-04-26 20:37         ` Conor Dooley
2024-04-26 20:37         ` Conor Dooley
2024-04-21  1:04 ` [PATCH v3 09/17] riscv: drivers: Convert xandespmu to use the vendor extension framework Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-26 16:25   ` Conor Dooley
2024-04-26 16:25     ` Conor Dooley
2024-04-26 16:25     ` Conor Dooley
2024-04-26 20:34     ` Charlie Jenkins
2024-04-26 20:34       ` Charlie Jenkins
2024-04-26 20:34       ` Charlie Jenkins
2024-04-26 20:46       ` Conor Dooley
2024-04-26 20:46         ` Conor Dooley
2024-04-26 20:46         ` Conor Dooley
2024-04-21  1:04 ` [PATCH v3 10/17] RISC-V: define the elements of the VCSR vector CSR Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-21  1:04 ` [PATCH v3 11/17] riscv: csr: Add CSR encodings for VCSR_VXRM/VCSR_VXSAT Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-21  1:04 ` [PATCH v3 12/17] riscv: Add xtheadvector instruction definitions Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-21  1:04 ` [PATCH v3 13/17] riscv: vector: Support xtheadvector save/restore Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-21  1:04 ` [PATCH v3 14/17] riscv: hwprobe: Add thead vendor extension probing Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-21  1:04 ` [PATCH v3 15/17] riscv: hwprobe: Document thead vendor extensions and xtheadvector extension Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-21  1:04 ` [PATCH v3 16/17] selftests: riscv: Fix vector tests Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-21  1:04 ` [PATCH v3 17/17] selftests: riscv: Support xtheadvector in " Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins
2024-04-21  1:04   ` Charlie Jenkins

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240426-myself-crowbar-99dc0a080cd9@spud \
    --to=conor@kernel.org \
    --cc=aou@eecs.berkeley.edu \
    --cc=charlie@rivosinc.com \
    --cc=cleger@rivosinc.com \
    --cc=conor+dt@kernel.org \
    --cc=conor.dooley@microchip.com \
    --cc=corbet@lwn.net \
    --cc=devicetree@vger.kernel.org \
    --cc=evan@rivosinc.com \
    --cc=guoren@kernel.org \
    --cc=jernej.skrabec@gmail.com \
    --cc=krzysztof.kozlowski+dt@linaro.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=linux-riscv@lists.infradead.org \
    --cc=linux-sunxi@lists.linux.dev \
    --cc=palmer@dabbelt.com \
    --cc=palmer@rivosinc.com \
    --cc=paul.walmsley@sifive.com \
    --cc=robh@kernel.org \
    --cc=samuel@sholland.org \
    --cc=shuah@kernel.org \
    --cc=wens@csie.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.