diff mbox series

[v1,8/9] RISC-V: enable extension detection from new properties

Message ID 20230626-unfasten-guidance-eac4d71d8876@wendy (mailing list archive)
State Superseded
Headers show
Series RISC-V: Probe DT extension support using riscv,isa-extensions & riscv,isa-base | expand

Checks

Context Check Description
conchuod/cover_letter success Series has a cover letter
conchuod/tree_selection success Guessed tree name to be for-next at HEAD 488833ccdcac
conchuod/fixes_present success Fixes tag not required for -next series
conchuod/maintainers_pattern success MAINTAINERS pattern errors before the patch: 6 and now 6
conchuod/verify_signedoff success Signed-off-by tag matches author and committer
conchuod/kdoc success Errors and warnings before: 0 this patch: 0
conchuod/build_rv64_clang_allmodconfig success Errors and warnings before: 2838 this patch: 2832
conchuod/module_param success Was 0 now: 0
conchuod/build_rv64_gcc_allmodconfig success Errors and warnings before: 16516 this patch: 16511
conchuod/build_rv32_defconfig success Build OK
conchuod/dtb_warn_rv64 success Errors and warnings before: 20 this patch: 20
conchuod/header_inline success No static functions without inline keyword in header files
conchuod/checkpatch success total: 0 errors, 0 warnings, 0 checks, 110 lines checked
conchuod/build_rv64_nommu_k210_defconfig success Build OK
conchuod/verify_fixes success No Fixes tag
conchuod/build_rv64_nommu_virt_defconfig success Build OK

Commit Message

Conor Dooley June 26, 2023, 11:19 a.m. UTC
Add support for parsing the new riscv,isa-extensions property in
riscv_fill_hwcap(), by means of a new "property" member of the
riscv_isa_ext_data struct. For now, this shadows the name of the
extension, however this may not be the case for all extensions.
For the sake of backwards compatibility, fall back to the old scheme
if the new properties are not detected. For now, just inform, rather
than warn, when that happens.

Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
---
Naming things is hard, didn't know what to call the new function...
---
 arch/riscv/include/asm/hwcap.h |  1 +
 arch/riscv/kernel/cpufeature.c | 80 ++++++++++++++++++++++++++++++----
 2 files changed, 72 insertions(+), 9 deletions(-)

Comments

Andrew Jones June 26, 2023, 4:24 p.m. UTC | #1
On Mon, Jun 26, 2023 at 12:19:46PM +0100, Conor Dooley wrote:
> Add support for parsing the new riscv,isa-extensions property in
> riscv_fill_hwcap(), by means of a new "property" member of the
> riscv_isa_ext_data struct. For now, this shadows the name of the
> extension, however this may not be the case for all extensions.
> For the sake of backwards compatibility, fall back to the old scheme
> if the new properties are not detected. For now, just inform, rather
> than warn, when that happens.
> 
> Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
> ---
> Naming things is hard, didn't know what to call the new function...

riscv_fill_hwcap_from_isa_extensions() ?

_new() won't age well.

> ---
>  arch/riscv/include/asm/hwcap.h |  1 +
>  arch/riscv/kernel/cpufeature.c | 80 ++++++++++++++++++++++++++++++----
>  2 files changed, 72 insertions(+), 9 deletions(-)
> 
> diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
> index 6ad896dc4342..e7f235868aa2 100644
> --- a/arch/riscv/include/asm/hwcap.h
> +++ b/arch/riscv/include/asm/hwcap.h
> @@ -77,6 +77,7 @@ unsigned long riscv_get_elf_hwcap(void);
>  struct riscv_isa_ext_data {
>  	const unsigned int id;
>  	const char *name;
> +	const char *property;
>  	const bool multi_letter;
>  };
>  
> diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> index 366477ba1eea..72eb757ad871 100644
> --- a/arch/riscv/kernel/cpufeature.c
> +++ b/arch/riscv/kernel/cpufeature.c
> @@ -101,6 +101,7 @@ static bool riscv_isa_extension_check(int id)
>  
>  #define __RISCV_ISA_EXT_DATA(_name, _id, _multi) {	\
>  	.name = #_name,					\
> +	.property = #_name,				\
>  	.id = _id,					\
>  	.multi_letter = _multi,				\
>  }
> @@ -416,16 +417,66 @@ static void __init riscv_fill_hwcap_from_isa_string(unsigned long *isa2hwcap)
>  		acpi_put_table((struct acpi_table_header *)rhct);
>  }
>  
> +static int __init riscv_fill_hwcap_new(unsigned long *isa2hwcap)
> +{
> +	unsigned int cpu;
> +
> +	for_each_possible_cpu(cpu) {
> +		unsigned long this_hwcap = 0;
> +		struct device_node *cpu_node;
> +		DECLARE_BITMAP(this_isa, RISCV_ISA_EXT_MAX);
> +
> +		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"))
> +			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].name) < 0)
> +				continue;
> +
> +			if (!riscv_isa_extension_check(riscv_isa_ext[i].id))
> +				continue;
> +
> +			if (!riscv_isa_ext[i].multi_letter)
> +				this_hwcap |= isa2hwcap[riscv_isa_ext[i].id];
> +
> +			set_bit(riscv_isa_ext[i].id, this_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, this_isa, RISCV_ISA_EXT_MAX);
> +		else
> +			bitmap_and(riscv_isa, riscv_isa, this_isa, RISCV_ISA_EXT_MAX);
> +	}
> +
> +	if (bitmap_empty(riscv_isa, RISCV_ISA_EXT_MAX))
> +		return -ENOENT;
> +
> +	return 0;
> +}
> +
>  void __init riscv_fill_hwcap(void)
>  {
> -	struct device_node *node;
> -	const char *isa;
>  	char print_str[NUM_ALPHA_EXTS + 1];
> -	int i, j, rc;
>  	unsigned long isa2hwcap[26] = {0};
> -	struct acpi_table_header *rhct;
> -	acpi_status status;
> -	unsigned int cpu;
> +	int i, j;
>  
>  	isa2hwcap['i' - 'a'] = COMPAT_HWCAP_ISA_I;
>  	isa2hwcap['m' - 'a'] = COMPAT_HWCAP_ISA_M;
> @@ -435,10 +486,21 @@ void __init riscv_fill_hwcap(void)
>  	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_new(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;
> -- 
> 2.40.1
>

Other than the name and moving the removal of the unused declarations to
the previous patch,

Reviewed-by: Andrew Jones <ajones@ventanamicro.com>

Thanks,
drew
diff mbox series

Patch

diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
index 6ad896dc4342..e7f235868aa2 100644
--- a/arch/riscv/include/asm/hwcap.h
+++ b/arch/riscv/include/asm/hwcap.h
@@ -77,6 +77,7 @@  unsigned long riscv_get_elf_hwcap(void);
 struct riscv_isa_ext_data {
 	const unsigned int id;
 	const char *name;
+	const char *property;
 	const bool multi_letter;
 };
 
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index 366477ba1eea..72eb757ad871 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -101,6 +101,7 @@  static bool riscv_isa_extension_check(int id)
 
 #define __RISCV_ISA_EXT_DATA(_name, _id, _multi) {	\
 	.name = #_name,					\
+	.property = #_name,				\
 	.id = _id,					\
 	.multi_letter = _multi,				\
 }
@@ -416,16 +417,66 @@  static void __init riscv_fill_hwcap_from_isa_string(unsigned long *isa2hwcap)
 		acpi_put_table((struct acpi_table_header *)rhct);
 }
 
+static int __init riscv_fill_hwcap_new(unsigned long *isa2hwcap)
+{
+	unsigned int cpu;
+
+	for_each_possible_cpu(cpu) {
+		unsigned long this_hwcap = 0;
+		struct device_node *cpu_node;
+		DECLARE_BITMAP(this_isa, RISCV_ISA_EXT_MAX);
+
+		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"))
+			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].name) < 0)
+				continue;
+
+			if (!riscv_isa_extension_check(riscv_isa_ext[i].id))
+				continue;
+
+			if (!riscv_isa_ext[i].multi_letter)
+				this_hwcap |= isa2hwcap[riscv_isa_ext[i].id];
+
+			set_bit(riscv_isa_ext[i].id, this_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, this_isa, RISCV_ISA_EXT_MAX);
+		else
+			bitmap_and(riscv_isa, riscv_isa, this_isa, RISCV_ISA_EXT_MAX);
+	}
+
+	if (bitmap_empty(riscv_isa, RISCV_ISA_EXT_MAX))
+		return -ENOENT;
+
+	return 0;
+}
+
 void __init riscv_fill_hwcap(void)
 {
-	struct device_node *node;
-	const char *isa;
 	char print_str[NUM_ALPHA_EXTS + 1];
-	int i, j, rc;
 	unsigned long isa2hwcap[26] = {0};
-	struct acpi_table_header *rhct;
-	acpi_status status;
-	unsigned int cpu;
+	int i, j;
 
 	isa2hwcap['i' - 'a'] = COMPAT_HWCAP_ISA_I;
 	isa2hwcap['m' - 'a'] = COMPAT_HWCAP_ISA_M;
@@ -435,10 +486,21 @@  void __init riscv_fill_hwcap(void)
 	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_new(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;