All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/4] unified way to use static key and optimize pgtable_l4_enabled
@ 2022-05-08 16:07 ` Jisheng Zhang
  0 siblings, 0 replies; 36+ messages in thread
From: Jisheng Zhang @ 2022-05-08 16:07 UTC (permalink / raw)
  To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Andrey Ryabinin,
	Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
	Vincenzo Frascino, Alexandre Ghiti
  Cc: linux-riscv, linux-kernel, kasan-dev

Currently, riscv has several features which may not be supported on all
riscv platforms, for example, FPU, SV48, SV57 and so on. To support
unified kernel Image style, we need to check whether the feature is
suportted or not. If the check sits at hot code path, then performance
will be impacted a lot. static key can be used to solve the issue. In
the past, FPU support has been converted to use static key mechanism.
I believe we will have similar cases in the future. For example, the
SV48 support can take advantage of static key[1].

patch1 is a simple W=1 warning fix.
patch2 introduces an unified mechanism to use static key for riscv cpu
features.
patch3 converts has_cpu() to use the mechanism.
patch4 uses the mechanism to optimize pgtable_l4|[l5]_enabled.

[1] http://lists.infradead.org/pipermail/linux-riscv/2021-December/011164.html

Since v1:
 - Add a W=1 warning fix
 - Fix W=1 error
 - Based on v5.18-rcN, since SV57 support is added, so convert
   pgtable_l5_enabled as well.

Jisheng Zhang (4):
  riscv: mm: init: make pt_ops_set_[early|late|fixmap] static
  riscv: introduce unified static key mechanism for CPU features
  riscv: replace has_fpu() with system_supports_fpu()
  riscv: convert pgtable_l4|[l5]_enabled to static key

 arch/riscv/Makefile                 |   3 +
 arch/riscv/include/asm/cpufeature.h | 110 ++++++++++++++++++++++++++++
 arch/riscv/include/asm/pgalloc.h    |  16 ++--
 arch/riscv/include/asm/pgtable-64.h |  40 +++++-----
 arch/riscv/include/asm/pgtable.h    |   5 +-
 arch/riscv/include/asm/switch_to.h  |   9 +--
 arch/riscv/kernel/cpu.c             |   4 +-
 arch/riscv/kernel/cpufeature.c      |  29 ++++++--
 arch/riscv/kernel/process.c         |   2 +-
 arch/riscv/kernel/signal.c          |   4 +-
 arch/riscv/mm/init.c                |  52 ++++++-------
 arch/riscv/mm/kasan_init.c          |  16 ++--
 arch/riscv/tools/Makefile           |  22 ++++++
 arch/riscv/tools/cpucaps            |   7 ++
 arch/riscv/tools/gen-cpucaps.awk    |  40 ++++++++++
 15 files changed, 274 insertions(+), 85 deletions(-)
 create mode 100644 arch/riscv/include/asm/cpufeature.h
 create mode 100644 arch/riscv/tools/Makefile
 create mode 100644 arch/riscv/tools/cpucaps
 create mode 100755 arch/riscv/tools/gen-cpucaps.awk

-- 
2.34.1


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v2 0/4] unified way to use static key and optimize pgtable_l4_enabled
@ 2022-05-08 16:07 ` Jisheng Zhang
  0 siblings, 0 replies; 36+ messages in thread
From: Jisheng Zhang @ 2022-05-08 16:07 UTC (permalink / raw)
  To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Andrey Ryabinin,
	Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
	Vincenzo Frascino, Alexandre Ghiti
  Cc: linux-riscv, linux-kernel, kasan-dev

Currently, riscv has several features which may not be supported on all
riscv platforms, for example, FPU, SV48, SV57 and so on. To support
unified kernel Image style, we need to check whether the feature is
suportted or not. If the check sits at hot code path, then performance
will be impacted a lot. static key can be used to solve the issue. In
the past, FPU support has been converted to use static key mechanism.
I believe we will have similar cases in the future. For example, the
SV48 support can take advantage of static key[1].

patch1 is a simple W=1 warning fix.
patch2 introduces an unified mechanism to use static key for riscv cpu
features.
patch3 converts has_cpu() to use the mechanism.
patch4 uses the mechanism to optimize pgtable_l4|[l5]_enabled.

[1] http://lists.infradead.org/pipermail/linux-riscv/2021-December/011164.html

Since v1:
 - Add a W=1 warning fix
 - Fix W=1 error
 - Based on v5.18-rcN, since SV57 support is added, so convert
   pgtable_l5_enabled as well.

Jisheng Zhang (4):
  riscv: mm: init: make pt_ops_set_[early|late|fixmap] static
  riscv: introduce unified static key mechanism for CPU features
  riscv: replace has_fpu() with system_supports_fpu()
  riscv: convert pgtable_l4|[l5]_enabled to static key

 arch/riscv/Makefile                 |   3 +
 arch/riscv/include/asm/cpufeature.h | 110 ++++++++++++++++++++++++++++
 arch/riscv/include/asm/pgalloc.h    |  16 ++--
 arch/riscv/include/asm/pgtable-64.h |  40 +++++-----
 arch/riscv/include/asm/pgtable.h    |   5 +-
 arch/riscv/include/asm/switch_to.h  |   9 +--
 arch/riscv/kernel/cpu.c             |   4 +-
 arch/riscv/kernel/cpufeature.c      |  29 ++++++--
 arch/riscv/kernel/process.c         |   2 +-
 arch/riscv/kernel/signal.c          |   4 +-
 arch/riscv/mm/init.c                |  52 ++++++-------
 arch/riscv/mm/kasan_init.c          |  16 ++--
 arch/riscv/tools/Makefile           |  22 ++++++
 arch/riscv/tools/cpucaps            |   7 ++
 arch/riscv/tools/gen-cpucaps.awk    |  40 ++++++++++
 15 files changed, 274 insertions(+), 85 deletions(-)
 create mode 100644 arch/riscv/include/asm/cpufeature.h
 create mode 100644 arch/riscv/tools/Makefile
 create mode 100644 arch/riscv/tools/cpucaps
 create mode 100755 arch/riscv/tools/gen-cpucaps.awk

-- 
2.34.1


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

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v2 1/4] riscv: mm: init: make pt_ops_set_[early|late|fixmap] static
  2022-05-08 16:07 ` Jisheng Zhang
@ 2022-05-08 16:07   ` Jisheng Zhang
  -1 siblings, 0 replies; 36+ messages in thread
From: Jisheng Zhang @ 2022-05-08 16:07 UTC (permalink / raw)
  To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Andrey Ryabinin,
	Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
	Vincenzo Frascino, Alexandre Ghiti
  Cc: linux-riscv, linux-kernel, kasan-dev

These three functions are only used in init.c, so make them static.
Fix W=1 warnings like below:

arch/riscv/mm/init.c:721:13: warning: no previous prototype for function
'pt_ops_set_early' [-Wmissing-prototypes]
   void __init pt_ops_set_early(void)
               ^

Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
---
 arch/riscv/mm/init.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index 05ed641a1134..5f3f26dd9f21 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -849,7 +849,7 @@ static void __init create_fdt_early_page_table(pgd_t *pgdir, uintptr_t dtb_pa)
  * MMU is not enabled, the page tables are allocated directly using
  * early_pmd/pud/p4d and the address returned is the physical one.
  */
-void __init pt_ops_set_early(void)
+static void __init pt_ops_set_early(void)
 {
 	pt_ops.alloc_pte = alloc_pte_early;
 	pt_ops.get_pte_virt = get_pte_virt_early;
@@ -871,7 +871,7 @@ void __init pt_ops_set_early(void)
  * Note that this is called with MMU disabled, hence kernel_mapping_pa_to_va,
  * but it will be used as described above.
  */
-void __init pt_ops_set_fixmap(void)
+static void __init pt_ops_set_fixmap(void)
 {
 	pt_ops.alloc_pte = kernel_mapping_pa_to_va((uintptr_t)alloc_pte_fixmap);
 	pt_ops.get_pte_virt = kernel_mapping_pa_to_va((uintptr_t)get_pte_virt_fixmap);
@@ -889,7 +889,7 @@ void __init pt_ops_set_fixmap(void)
  * MMU is enabled and page table setup is complete, so from now, we can use
  * generic page allocation functions to setup page table.
  */
-void __init pt_ops_set_late(void)
+static void __init pt_ops_set_late(void)
 {
 	pt_ops.alloc_pte = alloc_pte_late;
 	pt_ops.get_pte_virt = get_pte_virt_late;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 1/4] riscv: mm: init: make pt_ops_set_[early|late|fixmap] static
@ 2022-05-08 16:07   ` Jisheng Zhang
  0 siblings, 0 replies; 36+ messages in thread
From: Jisheng Zhang @ 2022-05-08 16:07 UTC (permalink / raw)
  To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Andrey Ryabinin,
	Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
	Vincenzo Frascino, Alexandre Ghiti
  Cc: linux-riscv, linux-kernel, kasan-dev

These three functions are only used in init.c, so make them static.
Fix W=1 warnings like below:

arch/riscv/mm/init.c:721:13: warning: no previous prototype for function
'pt_ops_set_early' [-Wmissing-prototypes]
   void __init pt_ops_set_early(void)
               ^

Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
---
 arch/riscv/mm/init.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index 05ed641a1134..5f3f26dd9f21 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -849,7 +849,7 @@ static void __init create_fdt_early_page_table(pgd_t *pgdir, uintptr_t dtb_pa)
  * MMU is not enabled, the page tables are allocated directly using
  * early_pmd/pud/p4d and the address returned is the physical one.
  */
-void __init pt_ops_set_early(void)
+static void __init pt_ops_set_early(void)
 {
 	pt_ops.alloc_pte = alloc_pte_early;
 	pt_ops.get_pte_virt = get_pte_virt_early;
@@ -871,7 +871,7 @@ void __init pt_ops_set_early(void)
  * Note that this is called with MMU disabled, hence kernel_mapping_pa_to_va,
  * but it will be used as described above.
  */
-void __init pt_ops_set_fixmap(void)
+static void __init pt_ops_set_fixmap(void)
 {
 	pt_ops.alloc_pte = kernel_mapping_pa_to_va((uintptr_t)alloc_pte_fixmap);
 	pt_ops.get_pte_virt = kernel_mapping_pa_to_va((uintptr_t)get_pte_virt_fixmap);
@@ -889,7 +889,7 @@ void __init pt_ops_set_fixmap(void)
  * MMU is enabled and page table setup is complete, so from now, we can use
  * generic page allocation functions to setup page table.
  */
-void __init pt_ops_set_late(void)
+static void __init pt_ops_set_late(void)
 {
 	pt_ops.alloc_pte = alloc_pte_late;
 	pt_ops.get_pte_virt = get_pte_virt_late;
-- 
2.34.1


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

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 2/4] riscv: introduce unified static key mechanism for CPU features
  2022-05-08 16:07 ` Jisheng Zhang
@ 2022-05-08 16:07   ` Jisheng Zhang
  -1 siblings, 0 replies; 36+ messages in thread
From: Jisheng Zhang @ 2022-05-08 16:07 UTC (permalink / raw)
  To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Andrey Ryabinin,
	Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
	Vincenzo Frascino, Alexandre Ghiti
  Cc: linux-riscv, linux-kernel, kasan-dev

Currently, riscv has several features why may not be supported on all
riscv platforms, for example, FPU, SV48 and so on. To support unified
kernel Image style, we need to check whether the feature is suportted
or not. If the check sits at hot code path, then performance will be
impacted a lot. static key can be used to solve the issue. In the past
FPU support has been converted to use static key mechanism. I believe
we will have similar cases in the future.

Similar as arm64 does(in fact, some code is borrowed from arm64), this
patch tries to add an unified mechanism to use static keys for all
the cpu features by implementing an array of default-false static keys
and enabling them when detected. The cpus_have_*_cap() check uses the
static keys if riscv_const_caps_ready is finalized, otherwise the
compiler generates the bitmap test.

Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
---
 arch/riscv/Makefile                 |  3 +
 arch/riscv/include/asm/cpufeature.h | 94 +++++++++++++++++++++++++++++
 arch/riscv/kernel/cpufeature.c      | 23 +++++++
 arch/riscv/tools/Makefile           | 22 +++++++
 arch/riscv/tools/cpucaps            |  5 ++
 arch/riscv/tools/gen-cpucaps.awk    | 40 ++++++++++++
 6 files changed, 187 insertions(+)
 create mode 100644 arch/riscv/include/asm/cpufeature.h
 create mode 100644 arch/riscv/tools/Makefile
 create mode 100644 arch/riscv/tools/cpucaps
 create mode 100755 arch/riscv/tools/gen-cpucaps.awk

diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
index 7d81102cffd4..f4df67369d84 100644
--- a/arch/riscv/Makefile
+++ b/arch/riscv/Makefile
@@ -154,3 +154,6 @@ PHONY += rv64_randconfig
 rv64_randconfig:
 	$(Q)$(MAKE) KCONFIG_ALLCONFIG=$(srctree)/arch/riscv/configs/64-bit.config \
 		-f $(srctree)/Makefile randconfig
+
+archprepare:
+	$(Q)$(MAKE) $(build)=arch/riscv/tools kapi
diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
new file mode 100644
index 000000000000..d80ddd2f3b49
--- /dev/null
+++ b/arch/riscv/include/asm/cpufeature.h
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
+ * Copyright (C) 2022 Jisheng Zhang <jszhang@kernel.org>
+ */
+
+#ifndef __ASM_CPUFEATURE_H
+#define __ASM_CPUFEATURE_H
+
+#include <asm/cpucaps.h>
+
+#include <linux/bug.h>
+#include <linux/jump_label.h>
+#include <linux/kernel.h>
+
+extern DECLARE_BITMAP(cpu_hwcaps, RISCV_NCAPS);
+extern struct static_key_false cpu_hwcap_keys[RISCV_NCAPS];
+extern struct static_key_false riscv_const_caps_ready;
+
+static __always_inline bool system_capabilities_finalized(void)
+{
+	return static_branch_likely(&riscv_const_caps_ready);
+}
+
+/*
+ * Test for a capability with a runtime check.
+ *
+ * Before the capability is detected, this returns false.
+ */
+static inline bool cpus_have_cap(unsigned int num)
+{
+	if (num >= RISCV_NCAPS)
+		return false;
+	return test_bit(num, cpu_hwcaps);
+}
+
+/*
+ * Test for a capability without a runtime check.
+ *
+ * Before capabilities are finalized, this returns false.
+ * After capabilities are finalized, this is patched to avoid a runtime check.
+ *
+ * @num must be a compile-time constant.
+ */
+static __always_inline bool __cpus_have_const_cap(int num)
+{
+	if (num >= RISCV_NCAPS)
+		return false;
+	return static_branch_unlikely(&cpu_hwcap_keys[num]);
+}
+
+/*
+ * Test for a capability without a runtime check.
+ *
+ * Before capabilities are finalized, this will BUG().
+ * After capabilities are finalized, this is patched to avoid a runtime check.
+ *
+ * @num must be a compile-time constant.
+ */
+static __always_inline bool cpus_have_final_cap(int num)
+{
+	if (system_capabilities_finalized())
+		return __cpus_have_const_cap(num);
+	else
+		BUG();
+}
+
+/*
+ * Test for a capability, possibly with a runtime check.
+ *
+ * Before capabilities are finalized, this behaves as cpus_have_cap().
+ * After capabilities are finalized, this is patched to avoid a runtime check.
+ *
+ * @num must be a compile-time constant.
+ */
+static __always_inline bool cpus_have_const_cap(int num)
+{
+	if (system_capabilities_finalized())
+		return __cpus_have_const_cap(num);
+	else
+		return cpus_have_cap(num);
+}
+
+static inline void cpus_set_cap(unsigned int num)
+{
+	if (num >= RISCV_NCAPS) {
+		pr_warn("Attempt to set an illegal CPU capability (%d >= %d)\n",
+			num, RISCV_NCAPS);
+	} else {
+		__set_bit(num, cpu_hwcaps);
+	}
+}
+
+#endif
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index 1b2d42d7f589..e6c72cad0c1c 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -9,6 +9,7 @@
 #include <linux/bitmap.h>
 #include <linux/ctype.h>
 #include <linux/of.h>
+#include <asm/cpufeature.h>
 #include <asm/processor.h>
 #include <asm/hwcap.h>
 #include <asm/smp.h>
@@ -25,6 +26,15 @@ static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
 __ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_fpu);
 #endif
 
+DECLARE_BITMAP(cpu_hwcaps, RISCV_NCAPS);
+EXPORT_SYMBOL(cpu_hwcaps);
+
+DEFINE_STATIC_KEY_ARRAY_FALSE(cpu_hwcap_keys, RISCV_NCAPS);
+EXPORT_SYMBOL(cpu_hwcap_keys);
+
+DEFINE_STATIC_KEY_FALSE(riscv_const_caps_ready);
+EXPORT_SYMBOL(riscv_const_caps_ready);
+
 /**
  * riscv_isa_extension_base() - Get base extension word
  *
@@ -62,6 +72,17 @@ bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, int bit)
 }
 EXPORT_SYMBOL_GPL(__riscv_isa_extension_available);
 
+static void __init enable_cpu_capabilities(void)
+{
+	int i;
+
+	for (i = 0; i < RISCV_NCAPS; i++) {
+		if (!cpus_have_cap(i))
+			continue;
+		static_branch_enable(&cpu_hwcap_keys[i]);
+	}
+}
+
 void __init riscv_fill_hwcap(void)
 {
 	struct device_node *node;
@@ -236,4 +257,6 @@ void __init riscv_fill_hwcap(void)
 	if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D))
 		static_branch_enable(&cpu_hwcap_fpu);
 #endif
+	enable_cpu_capabilities();
+	static_branch_enable(&riscv_const_caps_ready);
 }
diff --git a/arch/riscv/tools/Makefile b/arch/riscv/tools/Makefile
new file mode 100644
index 000000000000..932b4fe5c768
--- /dev/null
+++ b/arch/riscv/tools/Makefile
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: GPL-2.0
+
+gen := arch/$(ARCH)/include/generated
+kapi := $(gen)/asm
+
+kapi-hdrs-y := $(kapi)/cpucaps.h
+
+targets += $(addprefix ../../../,$(gen-y) $(kapi-hdrs-y))
+
+PHONY += kapi
+
+kapi:   $(kapi-hdrs-y) $(gen-y)
+
+# Create output directory if not already present
+_dummy := $(shell [ -d '$(kapi)' ] || mkdir -p '$(kapi)')
+
+quiet_cmd_gen_cpucaps = GEN     $@
+      cmd_gen_cpucaps = mkdir -p $(dir $@) && \
+                     $(AWK) -f $(filter-out $(PHONY),$^) > $@
+
+$(kapi)/cpucaps.h: $(src)/gen-cpucaps.awk $(src)/cpucaps FORCE
+	$(call if_changed,gen_cpucaps)
diff --git a/arch/riscv/tools/cpucaps b/arch/riscv/tools/cpucaps
new file mode 100644
index 000000000000..cb1ff2747859
--- /dev/null
+++ b/arch/riscv/tools/cpucaps
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Internal CPU capabilities constants, keep this list sorted
+
+HAS_NO_FPU
diff --git a/arch/riscv/tools/gen-cpucaps.awk b/arch/riscv/tools/gen-cpucaps.awk
new file mode 100755
index 000000000000..52a1e1b064ad
--- /dev/null
+++ b/arch/riscv/tools/gen-cpucaps.awk
@@ -0,0 +1,40 @@
+#!/bin/awk -f
+# SPDX-License-Identifier: GPL-2.0
+# gen-cpucaps.awk: riscv cpucaps header generator
+#
+# Usage: awk -f gen-cpucaps.awk cpucaps.txt
+
+# Log an error and terminate
+function fatal(msg) {
+	print "Error at line " NR ": " msg > "/dev/stderr"
+	exit 1
+}
+
+# skip blank lines and comment lines
+/^$/ { next }
+/^#/ { next }
+
+BEGIN {
+	print "#ifndef __ASM_CPUCAPS_H"
+	print "#define __ASM_CPUCAPS_H"
+	print ""
+	print "/* Generated file - do not edit */"
+	cap_num = 0
+	print ""
+}
+
+/^[vA-Z0-9_]+$/ {
+	printf("#define RISCV_%-30s\t%d\n", $0, cap_num++)
+	next
+}
+
+END {
+	printf("#define RISCV_NCAPS\t\t\t\t%d\n", cap_num)
+	print ""
+	print "#endif /* __ASM_CPUCAPS_H */"
+}
+
+# Any lines not handled by previous rules are unexpected
+{
+	fatal("unhandled statement")
+}
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 2/4] riscv: introduce unified static key mechanism for CPU features
@ 2022-05-08 16:07   ` Jisheng Zhang
  0 siblings, 0 replies; 36+ messages in thread
From: Jisheng Zhang @ 2022-05-08 16:07 UTC (permalink / raw)
  To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Andrey Ryabinin,
	Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
	Vincenzo Frascino, Alexandre Ghiti
  Cc: linux-riscv, linux-kernel, kasan-dev

Currently, riscv has several features why may not be supported on all
riscv platforms, for example, FPU, SV48 and so on. To support unified
kernel Image style, we need to check whether the feature is suportted
or not. If the check sits at hot code path, then performance will be
impacted a lot. static key can be used to solve the issue. In the past
FPU support has been converted to use static key mechanism. I believe
we will have similar cases in the future.

Similar as arm64 does(in fact, some code is borrowed from arm64), this
patch tries to add an unified mechanism to use static keys for all
the cpu features by implementing an array of default-false static keys
and enabling them when detected. The cpus_have_*_cap() check uses the
static keys if riscv_const_caps_ready is finalized, otherwise the
compiler generates the bitmap test.

Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
---
 arch/riscv/Makefile                 |  3 +
 arch/riscv/include/asm/cpufeature.h | 94 +++++++++++++++++++++++++++++
 arch/riscv/kernel/cpufeature.c      | 23 +++++++
 arch/riscv/tools/Makefile           | 22 +++++++
 arch/riscv/tools/cpucaps            |  5 ++
 arch/riscv/tools/gen-cpucaps.awk    | 40 ++++++++++++
 6 files changed, 187 insertions(+)
 create mode 100644 arch/riscv/include/asm/cpufeature.h
 create mode 100644 arch/riscv/tools/Makefile
 create mode 100644 arch/riscv/tools/cpucaps
 create mode 100755 arch/riscv/tools/gen-cpucaps.awk

diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
index 7d81102cffd4..f4df67369d84 100644
--- a/arch/riscv/Makefile
+++ b/arch/riscv/Makefile
@@ -154,3 +154,6 @@ PHONY += rv64_randconfig
 rv64_randconfig:
 	$(Q)$(MAKE) KCONFIG_ALLCONFIG=$(srctree)/arch/riscv/configs/64-bit.config \
 		-f $(srctree)/Makefile randconfig
+
+archprepare:
+	$(Q)$(MAKE) $(build)=arch/riscv/tools kapi
diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
new file mode 100644
index 000000000000..d80ddd2f3b49
--- /dev/null
+++ b/arch/riscv/include/asm/cpufeature.h
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
+ * Copyright (C) 2022 Jisheng Zhang <jszhang@kernel.org>
+ */
+
+#ifndef __ASM_CPUFEATURE_H
+#define __ASM_CPUFEATURE_H
+
+#include <asm/cpucaps.h>
+
+#include <linux/bug.h>
+#include <linux/jump_label.h>
+#include <linux/kernel.h>
+
+extern DECLARE_BITMAP(cpu_hwcaps, RISCV_NCAPS);
+extern struct static_key_false cpu_hwcap_keys[RISCV_NCAPS];
+extern struct static_key_false riscv_const_caps_ready;
+
+static __always_inline bool system_capabilities_finalized(void)
+{
+	return static_branch_likely(&riscv_const_caps_ready);
+}
+
+/*
+ * Test for a capability with a runtime check.
+ *
+ * Before the capability is detected, this returns false.
+ */
+static inline bool cpus_have_cap(unsigned int num)
+{
+	if (num >= RISCV_NCAPS)
+		return false;
+	return test_bit(num, cpu_hwcaps);
+}
+
+/*
+ * Test for a capability without a runtime check.
+ *
+ * Before capabilities are finalized, this returns false.
+ * After capabilities are finalized, this is patched to avoid a runtime check.
+ *
+ * @num must be a compile-time constant.
+ */
+static __always_inline bool __cpus_have_const_cap(int num)
+{
+	if (num >= RISCV_NCAPS)
+		return false;
+	return static_branch_unlikely(&cpu_hwcap_keys[num]);
+}
+
+/*
+ * Test for a capability without a runtime check.
+ *
+ * Before capabilities are finalized, this will BUG().
+ * After capabilities are finalized, this is patched to avoid a runtime check.
+ *
+ * @num must be a compile-time constant.
+ */
+static __always_inline bool cpus_have_final_cap(int num)
+{
+	if (system_capabilities_finalized())
+		return __cpus_have_const_cap(num);
+	else
+		BUG();
+}
+
+/*
+ * Test for a capability, possibly with a runtime check.
+ *
+ * Before capabilities are finalized, this behaves as cpus_have_cap().
+ * After capabilities are finalized, this is patched to avoid a runtime check.
+ *
+ * @num must be a compile-time constant.
+ */
+static __always_inline bool cpus_have_const_cap(int num)
+{
+	if (system_capabilities_finalized())
+		return __cpus_have_const_cap(num);
+	else
+		return cpus_have_cap(num);
+}
+
+static inline void cpus_set_cap(unsigned int num)
+{
+	if (num >= RISCV_NCAPS) {
+		pr_warn("Attempt to set an illegal CPU capability (%d >= %d)\n",
+			num, RISCV_NCAPS);
+	} else {
+		__set_bit(num, cpu_hwcaps);
+	}
+}
+
+#endif
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index 1b2d42d7f589..e6c72cad0c1c 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -9,6 +9,7 @@
 #include <linux/bitmap.h>
 #include <linux/ctype.h>
 #include <linux/of.h>
+#include <asm/cpufeature.h>
 #include <asm/processor.h>
 #include <asm/hwcap.h>
 #include <asm/smp.h>
@@ -25,6 +26,15 @@ static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
 __ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_fpu);
 #endif
 
+DECLARE_BITMAP(cpu_hwcaps, RISCV_NCAPS);
+EXPORT_SYMBOL(cpu_hwcaps);
+
+DEFINE_STATIC_KEY_ARRAY_FALSE(cpu_hwcap_keys, RISCV_NCAPS);
+EXPORT_SYMBOL(cpu_hwcap_keys);
+
+DEFINE_STATIC_KEY_FALSE(riscv_const_caps_ready);
+EXPORT_SYMBOL(riscv_const_caps_ready);
+
 /**
  * riscv_isa_extension_base() - Get base extension word
  *
@@ -62,6 +72,17 @@ bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, int bit)
 }
 EXPORT_SYMBOL_GPL(__riscv_isa_extension_available);
 
+static void __init enable_cpu_capabilities(void)
+{
+	int i;
+
+	for (i = 0; i < RISCV_NCAPS; i++) {
+		if (!cpus_have_cap(i))
+			continue;
+		static_branch_enable(&cpu_hwcap_keys[i]);
+	}
+}
+
 void __init riscv_fill_hwcap(void)
 {
 	struct device_node *node;
@@ -236,4 +257,6 @@ void __init riscv_fill_hwcap(void)
 	if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D))
 		static_branch_enable(&cpu_hwcap_fpu);
 #endif
+	enable_cpu_capabilities();
+	static_branch_enable(&riscv_const_caps_ready);
 }
diff --git a/arch/riscv/tools/Makefile b/arch/riscv/tools/Makefile
new file mode 100644
index 000000000000..932b4fe5c768
--- /dev/null
+++ b/arch/riscv/tools/Makefile
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: GPL-2.0
+
+gen := arch/$(ARCH)/include/generated
+kapi := $(gen)/asm
+
+kapi-hdrs-y := $(kapi)/cpucaps.h
+
+targets += $(addprefix ../../../,$(gen-y) $(kapi-hdrs-y))
+
+PHONY += kapi
+
+kapi:   $(kapi-hdrs-y) $(gen-y)
+
+# Create output directory if not already present
+_dummy := $(shell [ -d '$(kapi)' ] || mkdir -p '$(kapi)')
+
+quiet_cmd_gen_cpucaps = GEN     $@
+      cmd_gen_cpucaps = mkdir -p $(dir $@) && \
+                     $(AWK) -f $(filter-out $(PHONY),$^) > $@
+
+$(kapi)/cpucaps.h: $(src)/gen-cpucaps.awk $(src)/cpucaps FORCE
+	$(call if_changed,gen_cpucaps)
diff --git a/arch/riscv/tools/cpucaps b/arch/riscv/tools/cpucaps
new file mode 100644
index 000000000000..cb1ff2747859
--- /dev/null
+++ b/arch/riscv/tools/cpucaps
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Internal CPU capabilities constants, keep this list sorted
+
+HAS_NO_FPU
diff --git a/arch/riscv/tools/gen-cpucaps.awk b/arch/riscv/tools/gen-cpucaps.awk
new file mode 100755
index 000000000000..52a1e1b064ad
--- /dev/null
+++ b/arch/riscv/tools/gen-cpucaps.awk
@@ -0,0 +1,40 @@
+#!/bin/awk -f
+# SPDX-License-Identifier: GPL-2.0
+# gen-cpucaps.awk: riscv cpucaps header generator
+#
+# Usage: awk -f gen-cpucaps.awk cpucaps.txt
+
+# Log an error and terminate
+function fatal(msg) {
+	print "Error at line " NR ": " msg > "/dev/stderr"
+	exit 1
+}
+
+# skip blank lines and comment lines
+/^$/ { next }
+/^#/ { next }
+
+BEGIN {
+	print "#ifndef __ASM_CPUCAPS_H"
+	print "#define __ASM_CPUCAPS_H"
+	print ""
+	print "/* Generated file - do not edit */"
+	cap_num = 0
+	print ""
+}
+
+/^[vA-Z0-9_]+$/ {
+	printf("#define RISCV_%-30s\t%d\n", $0, cap_num++)
+	next
+}
+
+END {
+	printf("#define RISCV_NCAPS\t\t\t\t%d\n", cap_num)
+	print ""
+	print "#endif /* __ASM_CPUCAPS_H */"
+}
+
+# Any lines not handled by previous rules are unexpected
+{
+	fatal("unhandled statement")
+}
-- 
2.34.1


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

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 3/4] riscv: replace has_fpu() with system_supports_fpu()
  2022-05-08 16:07 ` Jisheng Zhang
@ 2022-05-08 16:07   ` Jisheng Zhang
  -1 siblings, 0 replies; 36+ messages in thread
From: Jisheng Zhang @ 2022-05-08 16:07 UTC (permalink / raw)
  To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Andrey Ryabinin,
	Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
	Vincenzo Frascino, Alexandre Ghiti
  Cc: linux-riscv, linux-kernel, kasan-dev

This is to use the unified cpus_have_{final|const}_cap() instead of
putting static key related here and there.

Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
---
 arch/riscv/include/asm/cpufeature.h | 5 +++++
 arch/riscv/include/asm/switch_to.h  | 9 ++-------
 arch/riscv/kernel/cpufeature.c      | 8 ++------
 arch/riscv/kernel/process.c         | 2 +-
 arch/riscv/kernel/signal.c          | 4 ++--
 5 files changed, 12 insertions(+), 16 deletions(-)

diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
index d80ddd2f3b49..634a653c7fa2 100644
--- a/arch/riscv/include/asm/cpufeature.h
+++ b/arch/riscv/include/asm/cpufeature.h
@@ -91,4 +91,9 @@ static inline void cpus_set_cap(unsigned int num)
 	}
 }
 
+static inline bool system_supports_fpu(void)
+{
+	return IS_ENABLED(CONFIG_FPU) && !cpus_have_final_cap(RISCV_HAS_NO_FPU);
+}
+
 #endif
diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h
index 0a3f4f95c555..362cb18d12d5 100644
--- a/arch/riscv/include/asm/switch_to.h
+++ b/arch/riscv/include/asm/switch_to.h
@@ -8,6 +8,7 @@
 
 #include <linux/jump_label.h>
 #include <linux/sched/task_stack.h>
+#include <asm/cpufeature.h>
 #include <asm/processor.h>
 #include <asm/ptrace.h>
 #include <asm/csr.h>
@@ -56,13 +57,7 @@ static inline void __switch_to_aux(struct task_struct *prev,
 	fstate_restore(next, task_pt_regs(next));
 }
 
-extern struct static_key_false cpu_hwcap_fpu;
-static __always_inline bool has_fpu(void)
-{
-	return static_branch_likely(&cpu_hwcap_fpu);
-}
 #else
-static __always_inline bool has_fpu(void) { return false; }
 #define fstate_save(task, regs) do { } while (0)
 #define fstate_restore(task, regs) do { } while (0)
 #define __switch_to_aux(__prev, __next) do { } while (0)
@@ -75,7 +70,7 @@ extern struct task_struct *__switch_to(struct task_struct *,
 do {							\
 	struct task_struct *__prev = (prev);		\
 	struct task_struct *__next = (next);		\
-	if (has_fpu())					\
+	if (system_supports_fpu())					\
 		__switch_to_aux(__prev, __next);	\
 	((last) = __switch_to(__prev, __next));		\
 } while (0)
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index e6c72cad0c1c..1edf3c3f8f62 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -22,10 +22,6 @@ unsigned long elf_hwcap __read_mostly;
 /* Host ISA bitmap */
 static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
 
-#ifdef CONFIG_FPU
-__ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_fpu);
-#endif
-
 DECLARE_BITMAP(cpu_hwcaps, RISCV_NCAPS);
 EXPORT_SYMBOL(cpu_hwcaps);
 
@@ -254,8 +250,8 @@ void __init riscv_fill_hwcap(void)
 	pr_info("riscv: ELF capabilities %s\n", print_str);
 
 #ifdef CONFIG_FPU
-	if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D))
-		static_branch_enable(&cpu_hwcap_fpu);
+	if (!(elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D)))
+		cpus_set_cap(RISCV_HAS_NO_FPU);
 #endif
 	enable_cpu_capabilities();
 	static_branch_enable(&riscv_const_caps_ready);
diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c
index 504b496787aa..c9cd0b42299e 100644
--- a/arch/riscv/kernel/process.c
+++ b/arch/riscv/kernel/process.c
@@ -88,7 +88,7 @@ void start_thread(struct pt_regs *regs, unsigned long pc,
 	unsigned long sp)
 {
 	regs->status = SR_PIE;
-	if (has_fpu()) {
+	if (system_supports_fpu()) {
 		regs->status |= SR_FS_INITIAL;
 		/*
 		 * Restore the initial value to the FP register
diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c
index 9f4e59f80551..96aa593a989e 100644
--- a/arch/riscv/kernel/signal.c
+++ b/arch/riscv/kernel/signal.c
@@ -90,7 +90,7 @@ static long restore_sigcontext(struct pt_regs *regs,
 	/* sc_regs is structured the same as the start of pt_regs */
 	err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs));
 	/* Restore the floating-point state. */
-	if (has_fpu())
+	if (system_supports_fpu())
 		err |= restore_fp_state(regs, &sc->sc_fpregs);
 	return err;
 }
@@ -143,7 +143,7 @@ static long setup_sigcontext(struct rt_sigframe __user *frame,
 	/* sc_regs is structured the same as the start of pt_regs */
 	err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs));
 	/* Save the floating-point state. */
-	if (has_fpu())
+	if (system_supports_fpu())
 		err |= save_fp_state(regs, &sc->sc_fpregs);
 	return err;
 }
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 3/4] riscv: replace has_fpu() with system_supports_fpu()
@ 2022-05-08 16:07   ` Jisheng Zhang
  0 siblings, 0 replies; 36+ messages in thread
From: Jisheng Zhang @ 2022-05-08 16:07 UTC (permalink / raw)
  To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Andrey Ryabinin,
	Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
	Vincenzo Frascino, Alexandre Ghiti
  Cc: linux-riscv, linux-kernel, kasan-dev

This is to use the unified cpus_have_{final|const}_cap() instead of
putting static key related here and there.

Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
---
 arch/riscv/include/asm/cpufeature.h | 5 +++++
 arch/riscv/include/asm/switch_to.h  | 9 ++-------
 arch/riscv/kernel/cpufeature.c      | 8 ++------
 arch/riscv/kernel/process.c         | 2 +-
 arch/riscv/kernel/signal.c          | 4 ++--
 5 files changed, 12 insertions(+), 16 deletions(-)

diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
index d80ddd2f3b49..634a653c7fa2 100644
--- a/arch/riscv/include/asm/cpufeature.h
+++ b/arch/riscv/include/asm/cpufeature.h
@@ -91,4 +91,9 @@ static inline void cpus_set_cap(unsigned int num)
 	}
 }
 
+static inline bool system_supports_fpu(void)
+{
+	return IS_ENABLED(CONFIG_FPU) && !cpus_have_final_cap(RISCV_HAS_NO_FPU);
+}
+
 #endif
diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h
index 0a3f4f95c555..362cb18d12d5 100644
--- a/arch/riscv/include/asm/switch_to.h
+++ b/arch/riscv/include/asm/switch_to.h
@@ -8,6 +8,7 @@
 
 #include <linux/jump_label.h>
 #include <linux/sched/task_stack.h>
+#include <asm/cpufeature.h>
 #include <asm/processor.h>
 #include <asm/ptrace.h>
 #include <asm/csr.h>
@@ -56,13 +57,7 @@ static inline void __switch_to_aux(struct task_struct *prev,
 	fstate_restore(next, task_pt_regs(next));
 }
 
-extern struct static_key_false cpu_hwcap_fpu;
-static __always_inline bool has_fpu(void)
-{
-	return static_branch_likely(&cpu_hwcap_fpu);
-}
 #else
-static __always_inline bool has_fpu(void) { return false; }
 #define fstate_save(task, regs) do { } while (0)
 #define fstate_restore(task, regs) do { } while (0)
 #define __switch_to_aux(__prev, __next) do { } while (0)
@@ -75,7 +70,7 @@ extern struct task_struct *__switch_to(struct task_struct *,
 do {							\
 	struct task_struct *__prev = (prev);		\
 	struct task_struct *__next = (next);		\
-	if (has_fpu())					\
+	if (system_supports_fpu())					\
 		__switch_to_aux(__prev, __next);	\
 	((last) = __switch_to(__prev, __next));		\
 } while (0)
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index e6c72cad0c1c..1edf3c3f8f62 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -22,10 +22,6 @@ unsigned long elf_hwcap __read_mostly;
 /* Host ISA bitmap */
 static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
 
-#ifdef CONFIG_FPU
-__ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_fpu);
-#endif
-
 DECLARE_BITMAP(cpu_hwcaps, RISCV_NCAPS);
 EXPORT_SYMBOL(cpu_hwcaps);
 
@@ -254,8 +250,8 @@ void __init riscv_fill_hwcap(void)
 	pr_info("riscv: ELF capabilities %s\n", print_str);
 
 #ifdef CONFIG_FPU
-	if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D))
-		static_branch_enable(&cpu_hwcap_fpu);
+	if (!(elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D)))
+		cpus_set_cap(RISCV_HAS_NO_FPU);
 #endif
 	enable_cpu_capabilities();
 	static_branch_enable(&riscv_const_caps_ready);
diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c
index 504b496787aa..c9cd0b42299e 100644
--- a/arch/riscv/kernel/process.c
+++ b/arch/riscv/kernel/process.c
@@ -88,7 +88,7 @@ void start_thread(struct pt_regs *regs, unsigned long pc,
 	unsigned long sp)
 {
 	regs->status = SR_PIE;
-	if (has_fpu()) {
+	if (system_supports_fpu()) {
 		regs->status |= SR_FS_INITIAL;
 		/*
 		 * Restore the initial value to the FP register
diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c
index 9f4e59f80551..96aa593a989e 100644
--- a/arch/riscv/kernel/signal.c
+++ b/arch/riscv/kernel/signal.c
@@ -90,7 +90,7 @@ static long restore_sigcontext(struct pt_regs *regs,
 	/* sc_regs is structured the same as the start of pt_regs */
 	err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs));
 	/* Restore the floating-point state. */
-	if (has_fpu())
+	if (system_supports_fpu())
 		err |= restore_fp_state(regs, &sc->sc_fpregs);
 	return err;
 }
@@ -143,7 +143,7 @@ static long setup_sigcontext(struct rt_sigframe __user *frame,
 	/* sc_regs is structured the same as the start of pt_regs */
 	err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs));
 	/* Save the floating-point state. */
-	if (has_fpu())
+	if (system_supports_fpu())
 		err |= save_fp_state(regs, &sc->sc_fpregs);
 	return err;
 }
-- 
2.34.1


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

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 4/4] riscv: convert pgtable_l4|[l5]_enabled to static key
  2022-05-08 16:07 ` Jisheng Zhang
@ 2022-05-08 16:07   ` Jisheng Zhang
  -1 siblings, 0 replies; 36+ messages in thread
From: Jisheng Zhang @ 2022-05-08 16:07 UTC (permalink / raw)
  To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Andrey Ryabinin,
	Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
	Vincenzo Frascino, Alexandre Ghiti
  Cc: linux-riscv, linux-kernel, kasan-dev

On a specific HW platform, pgtable_l4|[l5]_enabled won't change after
boot, and the check sits at hot code path, this characteristic makes it
suitable for optimization with static key.

Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
---
 arch/riscv/include/asm/cpufeature.h | 11 +++++++
 arch/riscv/include/asm/pgalloc.h    | 16 +++++-----
 arch/riscv/include/asm/pgtable-64.h | 40 ++++++++++++-------------
 arch/riscv/include/asm/pgtable.h    |  5 ++--
 arch/riscv/kernel/cpu.c             |  4 +--
 arch/riscv/mm/init.c                | 46 +++++++++++++----------------
 arch/riscv/mm/kasan_init.c          | 16 +++++-----
 arch/riscv/tools/cpucaps            |  2 ++
 8 files changed, 73 insertions(+), 67 deletions(-)

diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
index 634a653c7fa2..a51f2602a0e3 100644
--- a/arch/riscv/include/asm/cpufeature.h
+++ b/arch/riscv/include/asm/cpufeature.h
@@ -96,4 +96,15 @@ static inline bool system_supports_fpu(void)
 	return IS_ENABLED(CONFIG_FPU) && !cpus_have_final_cap(RISCV_HAS_NO_FPU);
 }
 
+static inline bool system_supports_sv48(void)
+{
+	return IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_XIP_KERNEL) &&
+		!cpus_have_const_cap(RISCV_HAS_NO_SV48);
+}
+
+static inline bool system_supports_sv57(void)
+{
+	return IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_XIP_KERNEL) &&
+		!cpus_have_const_cap(RISCV_HAS_NO_SV57);
+}
 #endif
diff --git a/arch/riscv/include/asm/pgalloc.h b/arch/riscv/include/asm/pgalloc.h
index 947f23d7b6af..f49233ca696a 100644
--- a/arch/riscv/include/asm/pgalloc.h
+++ b/arch/riscv/include/asm/pgalloc.h
@@ -41,7 +41,7 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
 
 static inline void p4d_populate(struct mm_struct *mm, p4d_t *p4d, pud_t *pud)
 {
-	if (pgtable_l4_enabled) {
+	if (system_supports_sv48()) {
 		unsigned long pfn = virt_to_pfn(pud);
 
 		set_p4d(p4d, __p4d((pfn << _PAGE_PFN_SHIFT) | _PAGE_TABLE));
@@ -51,7 +51,7 @@ static inline void p4d_populate(struct mm_struct *mm, p4d_t *p4d, pud_t *pud)
 static inline void p4d_populate_safe(struct mm_struct *mm, p4d_t *p4d,
 				     pud_t *pud)
 {
-	if (pgtable_l4_enabled) {
+	if (system_supports_sv48()) {
 		unsigned long pfn = virt_to_pfn(pud);
 
 		set_p4d_safe(p4d,
@@ -61,7 +61,7 @@ static inline void p4d_populate_safe(struct mm_struct *mm, p4d_t *p4d,
 
 static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, p4d_t *p4d)
 {
-	if (pgtable_l5_enabled) {
+	if (system_supports_sv57()) {
 		unsigned long pfn = virt_to_pfn(p4d);
 
 		set_pgd(pgd, __pgd((pfn << _PAGE_PFN_SHIFT) | _PAGE_TABLE));
@@ -71,7 +71,7 @@ static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, p4d_t *p4d)
 static inline void pgd_populate_safe(struct mm_struct *mm, pgd_t *pgd,
 				     p4d_t *p4d)
 {
-	if (pgtable_l5_enabled) {
+	if (system_supports_sv57()) {
 		unsigned long pfn = virt_to_pfn(p4d);
 
 		set_pgd_safe(pgd,
@@ -82,7 +82,7 @@ static inline void pgd_populate_safe(struct mm_struct *mm, pgd_t *pgd,
 #define pud_alloc_one pud_alloc_one
 static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
 {
-	if (pgtable_l4_enabled)
+	if (system_supports_sv48())
 		return __pud_alloc_one(mm, addr);
 
 	return NULL;
@@ -91,7 +91,7 @@ static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
 #define pud_free pud_free
 static inline void pud_free(struct mm_struct *mm, pud_t *pud)
 {
-	if (pgtable_l4_enabled)
+	if (system_supports_sv48())
 		__pud_free(mm, pud);
 }
 
@@ -100,7 +100,7 @@ static inline void pud_free(struct mm_struct *mm, pud_t *pud)
 #define p4d_alloc_one p4d_alloc_one
 static inline p4d_t *p4d_alloc_one(struct mm_struct *mm, unsigned long addr)
 {
-	if (pgtable_l5_enabled) {
+	if (system_supports_sv57()) {
 		gfp_t gfp = GFP_PGTABLE_USER;
 
 		if (mm == &init_mm)
@@ -120,7 +120,7 @@ static inline void __p4d_free(struct mm_struct *mm, p4d_t *p4d)
 #define p4d_free p4d_free
 static inline void p4d_free(struct mm_struct *mm, p4d_t *p4d)
 {
-	if (pgtable_l5_enabled)
+	if (system_supports_sv57())
 		__p4d_free(mm, p4d);
 }
 
diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h
index 7e246e9f8d70..9ee4abf0f528 100644
--- a/arch/riscv/include/asm/pgtable-64.h
+++ b/arch/riscv/include/asm/pgtable-64.h
@@ -7,17 +7,15 @@
 #define _ASM_RISCV_PGTABLE_64_H
 
 #include <linux/const.h>
-
-extern bool pgtable_l4_enabled;
-extern bool pgtable_l5_enabled;
+#include <asm/cpufeature.h>
 
 #define PGDIR_SHIFT_L3  30
 #define PGDIR_SHIFT_L4  39
 #define PGDIR_SHIFT_L5  48
 #define PGDIR_SIZE_L3   (_AC(1, UL) << PGDIR_SHIFT_L3)
 
-#define PGDIR_SHIFT     (pgtable_l5_enabled ? PGDIR_SHIFT_L5 : \
-		(pgtable_l4_enabled ? PGDIR_SHIFT_L4 : PGDIR_SHIFT_L3))
+#define PGDIR_SHIFT     (system_supports_sv57() ? PGDIR_SHIFT_L5 : \
+		(system_supports_sv48() ? PGDIR_SHIFT_L4 : PGDIR_SHIFT_L3))
 /* Size of region mapped by a page global directory */
 #define PGDIR_SIZE      (_AC(1, UL) << PGDIR_SHIFT)
 #define PGDIR_MASK      (~(PGDIR_SIZE - 1))
@@ -119,7 +117,7 @@ static inline struct page *pud_page(pud_t pud)
 #define mm_p4d_folded  mm_p4d_folded
 static inline bool mm_p4d_folded(struct mm_struct *mm)
 {
-	if (pgtable_l5_enabled)
+	if (system_supports_sv57())
 		return false;
 
 	return true;
@@ -128,7 +126,7 @@ static inline bool mm_p4d_folded(struct mm_struct *mm)
 #define mm_pud_folded  mm_pud_folded
 static inline bool mm_pud_folded(struct mm_struct *mm)
 {
-	if (pgtable_l4_enabled)
+	if (system_supports_sv48())
 		return false;
 
 	return true;
@@ -159,7 +157,7 @@ static inline unsigned long _pmd_pfn(pmd_t pmd)
 
 static inline void set_p4d(p4d_t *p4dp, p4d_t p4d)
 {
-	if (pgtable_l4_enabled)
+	if (system_supports_sv48())
 		*p4dp = p4d;
 	else
 		set_pud((pud_t *)p4dp, (pud_t){ p4d_val(p4d) });
@@ -167,7 +165,7 @@ static inline void set_p4d(p4d_t *p4dp, p4d_t p4d)
 
 static inline int p4d_none(p4d_t p4d)
 {
-	if (pgtable_l4_enabled)
+	if (system_supports_sv48())
 		return (p4d_val(p4d) == 0);
 
 	return 0;
@@ -175,7 +173,7 @@ static inline int p4d_none(p4d_t p4d)
 
 static inline int p4d_present(p4d_t p4d)
 {
-	if (pgtable_l4_enabled)
+	if (system_supports_sv48())
 		return (p4d_val(p4d) & _PAGE_PRESENT);
 
 	return 1;
@@ -183,7 +181,7 @@ static inline int p4d_present(p4d_t p4d)
 
 static inline int p4d_bad(p4d_t p4d)
 {
-	if (pgtable_l4_enabled)
+	if (system_supports_sv48())
 		return !p4d_present(p4d);
 
 	return 0;
@@ -191,7 +189,7 @@ static inline int p4d_bad(p4d_t p4d)
 
 static inline void p4d_clear(p4d_t *p4d)
 {
-	if (pgtable_l4_enabled)
+	if (system_supports_sv48())
 		set_p4d(p4d, __p4d(0));
 }
 
@@ -207,7 +205,7 @@ static inline unsigned long _p4d_pfn(p4d_t p4d)
 
 static inline pud_t *p4d_pgtable(p4d_t p4d)
 {
-	if (pgtable_l4_enabled)
+	if (system_supports_sv48())
 		return (pud_t *)pfn_to_virt(p4d_val(p4d) >> _PAGE_PFN_SHIFT);
 
 	return (pud_t *)pud_pgtable((pud_t) { p4d_val(p4d) });
@@ -224,7 +222,7 @@ static inline struct page *p4d_page(p4d_t p4d)
 #define pud_offset pud_offset
 static inline pud_t *pud_offset(p4d_t *p4d, unsigned long address)
 {
-	if (pgtable_l4_enabled)
+	if (system_supports_sv48())
 		return p4d_pgtable(*p4d) + pud_index(address);
 
 	return (pud_t *)p4d;
@@ -232,7 +230,7 @@ static inline pud_t *pud_offset(p4d_t *p4d, unsigned long address)
 
 static inline void set_pgd(pgd_t *pgdp, pgd_t pgd)
 {
-	if (pgtable_l5_enabled)
+	if (system_supports_sv57())
 		*pgdp = pgd;
 	else
 		set_p4d((p4d_t *)pgdp, (p4d_t){ pgd_val(pgd) });
@@ -240,7 +238,7 @@ static inline void set_pgd(pgd_t *pgdp, pgd_t pgd)
 
 static inline int pgd_none(pgd_t pgd)
 {
-	if (pgtable_l5_enabled)
+	if (system_supports_sv57())
 		return (pgd_val(pgd) == 0);
 
 	return 0;
@@ -248,7 +246,7 @@ static inline int pgd_none(pgd_t pgd)
 
 static inline int pgd_present(pgd_t pgd)
 {
-	if (pgtable_l5_enabled)
+	if (system_supports_sv57())
 		return (pgd_val(pgd) & _PAGE_PRESENT);
 
 	return 1;
@@ -256,7 +254,7 @@ static inline int pgd_present(pgd_t pgd)
 
 static inline int pgd_bad(pgd_t pgd)
 {
-	if (pgtable_l5_enabled)
+	if (system_supports_sv57())
 		return !pgd_present(pgd);
 
 	return 0;
@@ -264,13 +262,13 @@ static inline int pgd_bad(pgd_t pgd)
 
 static inline void pgd_clear(pgd_t *pgd)
 {
-	if (pgtable_l5_enabled)
+	if (system_supports_sv57())
 		set_pgd(pgd, __pgd(0));
 }
 
 static inline p4d_t *pgd_pgtable(pgd_t pgd)
 {
-	if (pgtable_l5_enabled)
+	if (system_supports_sv57())
 		return (p4d_t *)pfn_to_virt(pgd_val(pgd) >> _PAGE_PFN_SHIFT);
 
 	return (p4d_t *)p4d_pgtable((p4d_t) { pgd_val(pgd) });
@@ -288,7 +286,7 @@ static inline struct page *pgd_page(pgd_t pgd)
 #define p4d_offset p4d_offset
 static inline p4d_t *p4d_offset(pgd_t *pgd, unsigned long address)
 {
-	if (pgtable_l5_enabled)
+	if (system_supports_sv57())
 		return pgd_pgtable(*pgd) + p4d_index(address);
 
 	return (p4d_t *)pgd;
diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
index 046b44225623..ef2a1654100a 100644
--- a/arch/riscv/include/asm/pgtable.h
+++ b/arch/riscv/include/asm/pgtable.h
@@ -63,8 +63,8 @@
  * position vmemmap directly below the VMALLOC region.
  */
 #ifdef CONFIG_64BIT
-#define VA_BITS		(pgtable_l5_enabled ? \
-				57 : (pgtable_l4_enabled ? 48 : 39))
+#define VA_BITS		(system_supports_sv57() ? \
+				57 : (system_supports_sv48() ? 48 : 39))
 #else
 #define VA_BITS		32
 #endif
@@ -738,7 +738,6 @@ extern uintptr_t _dtb_early_pa;
 #define dtb_early_pa	_dtb_early_pa
 #endif /* CONFIG_XIP_KERNEL */
 extern u64 satp_mode;
-extern bool pgtable_l4_enabled;
 
 void paging_init(void);
 void misc_mem_init(void);
diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c
index ccb617791e56..c8f3989b08f3 100644
--- a/arch/riscv/kernel/cpu.c
+++ b/arch/riscv/kernel/cpu.c
@@ -141,9 +141,9 @@ static void print_mmu(struct seq_file *f)
 #if defined(CONFIG_32BIT)
 	strncpy(sv_type, "sv32", 5);
 #elif defined(CONFIG_64BIT)
-	if (pgtable_l5_enabled)
+	if (system_supports_sv57())
 		strncpy(sv_type, "sv57", 5);
-	else if (pgtable_l4_enabled)
+	else if (system_supports_sv48())
 		strncpy(sv_type, "sv48", 5);
 	else
 		strncpy(sv_type, "sv39", 5);
diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index 5f3f26dd9f21..b6a59a5d1a7f 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -21,6 +21,7 @@
 #include <linux/crash_dump.h>
 #include <linux/hugetlb.h>
 
+#include <asm/cpufeature.h>
 #include <asm/fixmap.h>
 #include <asm/tlbflush.h>
 #include <asm/sections.h>
@@ -44,11 +45,6 @@ u64 satp_mode __ro_after_init = SATP_MODE_32;
 #endif
 EXPORT_SYMBOL(satp_mode);
 
-bool pgtable_l4_enabled = IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_XIP_KERNEL);
-bool pgtable_l5_enabled = IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_XIP_KERNEL);
-EXPORT_SYMBOL(pgtable_l4_enabled);
-EXPORT_SYMBOL(pgtable_l5_enabled);
-
 phys_addr_t phys_ram_base __ro_after_init;
 EXPORT_SYMBOL(phys_ram_base);
 
@@ -555,26 +551,26 @@ static void __init create_p4d_mapping(p4d_t *p4dp,
 }
 
 #define pgd_next_t		p4d_t
-#define alloc_pgd_next(__va)	(pgtable_l5_enabled ?			\
-		pt_ops.alloc_p4d(__va) : (pgtable_l4_enabled ?		\
+#define alloc_pgd_next(__va)	(system_supports_sv57() ?		\
+		pt_ops.alloc_p4d(__va) : (system_supports_sv48() ?	\
 		pt_ops.alloc_pud(__va) : pt_ops.alloc_pmd(__va)))
-#define get_pgd_next_virt(__pa)	(pgtable_l5_enabled ?			\
-		pt_ops.get_p4d_virt(__pa) : (pgd_next_t *)(pgtable_l4_enabled ?	\
+#define get_pgd_next_virt(__pa)	(system_supports_sv57() ?		\
+		pt_ops.get_p4d_virt(__pa) : (pgd_next_t *)(system_supports_sv48() ?	\
 		pt_ops.get_pud_virt(__pa) : (pud_t *)pt_ops.get_pmd_virt(__pa)))
 #define create_pgd_next_mapping(__nextp, __va, __pa, __sz, __prot)	\
-				(pgtable_l5_enabled ?			\
+				(system_supports_sv57() ?		\
 		create_p4d_mapping(__nextp, __va, __pa, __sz, __prot) : \
-				(pgtable_l4_enabled ?			\
+				(system_supports_sv48() ?		\
 		create_pud_mapping((pud_t *)__nextp, __va, __pa, __sz, __prot) :	\
 		create_pmd_mapping((pmd_t *)__nextp, __va, __pa, __sz, __prot)))
-#define fixmap_pgd_next		(pgtable_l5_enabled ?			\
-		(uintptr_t)fixmap_p4d : (pgtable_l4_enabled ?		\
+#define fixmap_pgd_next		(system_supports_sv57() ?		\
+		(uintptr_t)fixmap_p4d : (system_supports_sv48() ?	\
 		(uintptr_t)fixmap_pud : (uintptr_t)fixmap_pmd))
-#define trampoline_pgd_next	(pgtable_l5_enabled ?			\
-		(uintptr_t)trampoline_p4d : (pgtable_l4_enabled ?	\
+#define trampoline_pgd_next	(system_supports_sv57() ?		\
+		(uintptr_t)trampoline_p4d : (system_supports_sv48() ?	\
 		(uintptr_t)trampoline_pud : (uintptr_t)trampoline_pmd))
-#define early_dtb_pgd_next	(pgtable_l5_enabled ?			\
-		(uintptr_t)early_dtb_p4d : (pgtable_l4_enabled ?	\
+#define early_dtb_pgd_next	(system_supports_sv57() ?		\
+		(uintptr_t)early_dtb_p4d : (system_supports_sv48() ?	\
 		(uintptr_t)early_dtb_pud : (uintptr_t)early_dtb_pmd))
 #else
 #define pgd_next_t		pte_t
@@ -680,14 +676,14 @@ static __init pgprot_t pgprot_from_va(uintptr_t va)
 #ifdef CONFIG_64BIT
 static void __init disable_pgtable_l5(void)
 {
-	pgtable_l5_enabled = false;
+	cpus_set_cap(RISCV_HAS_NO_SV57);
 	kernel_map.page_offset = PAGE_OFFSET_L4;
 	satp_mode = SATP_MODE_48;
 }
 
 static void __init disable_pgtable_l4(void)
 {
-	pgtable_l4_enabled = false;
+	cpus_set_cap(RISCV_HAS_NO_SV48);
 	kernel_map.page_offset = PAGE_OFFSET_L3;
 	satp_mode = SATP_MODE_39;
 }
@@ -816,11 +812,11 @@ static void __init create_fdt_early_page_table(pgd_t *pgdir, uintptr_t dtb_pa)
 			   PGDIR_SIZE,
 			   IS_ENABLED(CONFIG_64BIT) ? PAGE_TABLE : PAGE_KERNEL);
 
-	if (pgtable_l5_enabled)
+	if (system_supports_sv57())
 		create_p4d_mapping(early_dtb_p4d, DTB_EARLY_BASE_VA,
 				   (uintptr_t)early_dtb_pud, P4D_SIZE, PAGE_TABLE);
 
-	if (pgtable_l4_enabled)
+	if (system_supports_sv48())
 		create_pud_mapping(early_dtb_pud, DTB_EARLY_BASE_VA,
 				   (uintptr_t)early_dtb_pmd, PUD_SIZE, PAGE_TABLE);
 
@@ -961,11 +957,11 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
 
 #ifndef __PAGETABLE_PMD_FOLDED
 	/* Setup fixmap P4D and PUD */
-	if (pgtable_l5_enabled)
+	if (system_supports_sv57())
 		create_p4d_mapping(fixmap_p4d, FIXADDR_START,
 				   (uintptr_t)fixmap_pud, P4D_SIZE, PAGE_TABLE);
 	/* Setup fixmap PUD and PMD */
-	if (pgtable_l4_enabled)
+	if (system_supports_sv48())
 		create_pud_mapping(fixmap_pud, FIXADDR_START,
 				   (uintptr_t)fixmap_pmd, PUD_SIZE, PAGE_TABLE);
 	create_pmd_mapping(fixmap_pmd, FIXADDR_START,
@@ -973,10 +969,10 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
 	/* Setup trampoline PGD and PMD */
 	create_pgd_mapping(trampoline_pg_dir, kernel_map.virt_addr,
 			   trampoline_pgd_next, PGDIR_SIZE, PAGE_TABLE);
-	if (pgtable_l5_enabled)
+	if (system_supports_sv57())
 		create_p4d_mapping(trampoline_p4d, kernel_map.virt_addr,
 				   (uintptr_t)trampoline_pud, P4D_SIZE, PAGE_TABLE);
-	if (pgtable_l4_enabled)
+	if (system_supports_sv48())
 		create_pud_mapping(trampoline_pud, kernel_map.virt_addr,
 				   (uintptr_t)trampoline_pmd, PUD_SIZE, PAGE_TABLE);
 #ifdef CONFIG_XIP_KERNEL
diff --git a/arch/riscv/mm/kasan_init.c b/arch/riscv/mm/kasan_init.c
index a22e418dbd82..7b662661f7a9 100644
--- a/arch/riscv/mm/kasan_init.c
+++ b/arch/riscv/mm/kasan_init.c
@@ -209,15 +209,15 @@ static void __init kasan_populate_p4d(pgd_t *pgd,
 		set_pgd(pgd, pfn_pgd(PFN_DOWN(__pa(base_p4d)), PAGE_TABLE));
 }
 
-#define kasan_early_shadow_pgd_next			(pgtable_l5_enabled ?	\
+#define kasan_early_shadow_pgd_next		(system_supports_sv57() ?	\
 				(uintptr_t)kasan_early_shadow_p4d :		\
-							(pgtable_l4_enabled ?	\
+						(system_supports_sv48() ?	\
 				(uintptr_t)kasan_early_shadow_pud :		\
 				(uintptr_t)kasan_early_shadow_pmd))
 #define kasan_populate_pgd_next(pgdp, vaddr, next, early)			\
-		(pgtable_l5_enabled ?						\
+		(system_supports_sv57() ?					\
 		kasan_populate_p4d(pgdp, vaddr, next, early) :			\
-		(pgtable_l4_enabled ?						\
+		(system_supports_sv48() ?					\
 			kasan_populate_pud(pgdp, vaddr, next, early) :		\
 			kasan_populate_pmd((pud_t *)pgdp, vaddr, next)))
 
@@ -274,7 +274,7 @@ asmlinkage void __init kasan_early_init(void)
 				(__pa((uintptr_t)kasan_early_shadow_pte)),
 				PAGE_TABLE));
 
-	if (pgtable_l4_enabled) {
+	if (system_supports_sv48()) {
 		for (i = 0; i < PTRS_PER_PUD; ++i)
 			set_pud(kasan_early_shadow_pud + i,
 				pfn_pud(PFN_DOWN
@@ -282,7 +282,7 @@ asmlinkage void __init kasan_early_init(void)
 					PAGE_TABLE));
 	}
 
-	if (pgtable_l5_enabled) {
+	if (system_supports_sv57()) {
 		for (i = 0; i < PTRS_PER_P4D; ++i)
 			set_p4d(kasan_early_shadow_p4d + i,
 				pfn_p4d(PFN_DOWN
@@ -393,9 +393,9 @@ static void __init kasan_shallow_populate_p4d(pgd_t *pgdp,
 }
 
 #define kasan_shallow_populate_pgd_next(pgdp, vaddr, next)			\
-		(pgtable_l5_enabled ?						\
+		(system_supports_sv57() ?					\
 		kasan_shallow_populate_p4d(pgdp, vaddr, next) :			\
-		(pgtable_l4_enabled ?						\
+		(system_supports_sv48() ?					\
 		kasan_shallow_populate_pud(pgdp, vaddr, next) :			\
 		kasan_shallow_populate_pmd(pgdp, vaddr, next)))
 
diff --git a/arch/riscv/tools/cpucaps b/arch/riscv/tools/cpucaps
index cb1ff2747859..0b9e19ec8371 100644
--- a/arch/riscv/tools/cpucaps
+++ b/arch/riscv/tools/cpucaps
@@ -3,3 +3,5 @@
 # Internal CPU capabilities constants, keep this list sorted
 
 HAS_NO_FPU
+HAS_NO_SV48
+HAS_NO_SV57
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 4/4] riscv: convert pgtable_l4|[l5]_enabled to static key
@ 2022-05-08 16:07   ` Jisheng Zhang
  0 siblings, 0 replies; 36+ messages in thread
From: Jisheng Zhang @ 2022-05-08 16:07 UTC (permalink / raw)
  To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Andrey Ryabinin,
	Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
	Vincenzo Frascino, Alexandre Ghiti
  Cc: linux-riscv, linux-kernel, kasan-dev

On a specific HW platform, pgtable_l4|[l5]_enabled won't change after
boot, and the check sits at hot code path, this characteristic makes it
suitable for optimization with static key.

Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
---
 arch/riscv/include/asm/cpufeature.h | 11 +++++++
 arch/riscv/include/asm/pgalloc.h    | 16 +++++-----
 arch/riscv/include/asm/pgtable-64.h | 40 ++++++++++++-------------
 arch/riscv/include/asm/pgtable.h    |  5 ++--
 arch/riscv/kernel/cpu.c             |  4 +--
 arch/riscv/mm/init.c                | 46 +++++++++++++----------------
 arch/riscv/mm/kasan_init.c          | 16 +++++-----
 arch/riscv/tools/cpucaps            |  2 ++
 8 files changed, 73 insertions(+), 67 deletions(-)

diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
index 634a653c7fa2..a51f2602a0e3 100644
--- a/arch/riscv/include/asm/cpufeature.h
+++ b/arch/riscv/include/asm/cpufeature.h
@@ -96,4 +96,15 @@ static inline bool system_supports_fpu(void)
 	return IS_ENABLED(CONFIG_FPU) && !cpus_have_final_cap(RISCV_HAS_NO_FPU);
 }
 
+static inline bool system_supports_sv48(void)
+{
+	return IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_XIP_KERNEL) &&
+		!cpus_have_const_cap(RISCV_HAS_NO_SV48);
+}
+
+static inline bool system_supports_sv57(void)
+{
+	return IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_XIP_KERNEL) &&
+		!cpus_have_const_cap(RISCV_HAS_NO_SV57);
+}
 #endif
diff --git a/arch/riscv/include/asm/pgalloc.h b/arch/riscv/include/asm/pgalloc.h
index 947f23d7b6af..f49233ca696a 100644
--- a/arch/riscv/include/asm/pgalloc.h
+++ b/arch/riscv/include/asm/pgalloc.h
@@ -41,7 +41,7 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
 
 static inline void p4d_populate(struct mm_struct *mm, p4d_t *p4d, pud_t *pud)
 {
-	if (pgtable_l4_enabled) {
+	if (system_supports_sv48()) {
 		unsigned long pfn = virt_to_pfn(pud);
 
 		set_p4d(p4d, __p4d((pfn << _PAGE_PFN_SHIFT) | _PAGE_TABLE));
@@ -51,7 +51,7 @@ static inline void p4d_populate(struct mm_struct *mm, p4d_t *p4d, pud_t *pud)
 static inline void p4d_populate_safe(struct mm_struct *mm, p4d_t *p4d,
 				     pud_t *pud)
 {
-	if (pgtable_l4_enabled) {
+	if (system_supports_sv48()) {
 		unsigned long pfn = virt_to_pfn(pud);
 
 		set_p4d_safe(p4d,
@@ -61,7 +61,7 @@ static inline void p4d_populate_safe(struct mm_struct *mm, p4d_t *p4d,
 
 static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, p4d_t *p4d)
 {
-	if (pgtable_l5_enabled) {
+	if (system_supports_sv57()) {
 		unsigned long pfn = virt_to_pfn(p4d);
 
 		set_pgd(pgd, __pgd((pfn << _PAGE_PFN_SHIFT) | _PAGE_TABLE));
@@ -71,7 +71,7 @@ static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, p4d_t *p4d)
 static inline void pgd_populate_safe(struct mm_struct *mm, pgd_t *pgd,
 				     p4d_t *p4d)
 {
-	if (pgtable_l5_enabled) {
+	if (system_supports_sv57()) {
 		unsigned long pfn = virt_to_pfn(p4d);
 
 		set_pgd_safe(pgd,
@@ -82,7 +82,7 @@ static inline void pgd_populate_safe(struct mm_struct *mm, pgd_t *pgd,
 #define pud_alloc_one pud_alloc_one
 static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
 {
-	if (pgtable_l4_enabled)
+	if (system_supports_sv48())
 		return __pud_alloc_one(mm, addr);
 
 	return NULL;
@@ -91,7 +91,7 @@ static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
 #define pud_free pud_free
 static inline void pud_free(struct mm_struct *mm, pud_t *pud)
 {
-	if (pgtable_l4_enabled)
+	if (system_supports_sv48())
 		__pud_free(mm, pud);
 }
 
@@ -100,7 +100,7 @@ static inline void pud_free(struct mm_struct *mm, pud_t *pud)
 #define p4d_alloc_one p4d_alloc_one
 static inline p4d_t *p4d_alloc_one(struct mm_struct *mm, unsigned long addr)
 {
-	if (pgtable_l5_enabled) {
+	if (system_supports_sv57()) {
 		gfp_t gfp = GFP_PGTABLE_USER;
 
 		if (mm == &init_mm)
@@ -120,7 +120,7 @@ static inline void __p4d_free(struct mm_struct *mm, p4d_t *p4d)
 #define p4d_free p4d_free
 static inline void p4d_free(struct mm_struct *mm, p4d_t *p4d)
 {
-	if (pgtable_l5_enabled)
+	if (system_supports_sv57())
 		__p4d_free(mm, p4d);
 }
 
diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h
index 7e246e9f8d70..9ee4abf0f528 100644
--- a/arch/riscv/include/asm/pgtable-64.h
+++ b/arch/riscv/include/asm/pgtable-64.h
@@ -7,17 +7,15 @@
 #define _ASM_RISCV_PGTABLE_64_H
 
 #include <linux/const.h>
-
-extern bool pgtable_l4_enabled;
-extern bool pgtable_l5_enabled;
+#include <asm/cpufeature.h>
 
 #define PGDIR_SHIFT_L3  30
 #define PGDIR_SHIFT_L4  39
 #define PGDIR_SHIFT_L5  48
 #define PGDIR_SIZE_L3   (_AC(1, UL) << PGDIR_SHIFT_L3)
 
-#define PGDIR_SHIFT     (pgtable_l5_enabled ? PGDIR_SHIFT_L5 : \
-		(pgtable_l4_enabled ? PGDIR_SHIFT_L4 : PGDIR_SHIFT_L3))
+#define PGDIR_SHIFT     (system_supports_sv57() ? PGDIR_SHIFT_L5 : \
+		(system_supports_sv48() ? PGDIR_SHIFT_L4 : PGDIR_SHIFT_L3))
 /* Size of region mapped by a page global directory */
 #define PGDIR_SIZE      (_AC(1, UL) << PGDIR_SHIFT)
 #define PGDIR_MASK      (~(PGDIR_SIZE - 1))
@@ -119,7 +117,7 @@ static inline struct page *pud_page(pud_t pud)
 #define mm_p4d_folded  mm_p4d_folded
 static inline bool mm_p4d_folded(struct mm_struct *mm)
 {
-	if (pgtable_l5_enabled)
+	if (system_supports_sv57())
 		return false;
 
 	return true;
@@ -128,7 +126,7 @@ static inline bool mm_p4d_folded(struct mm_struct *mm)
 #define mm_pud_folded  mm_pud_folded
 static inline bool mm_pud_folded(struct mm_struct *mm)
 {
-	if (pgtable_l4_enabled)
+	if (system_supports_sv48())
 		return false;
 
 	return true;
@@ -159,7 +157,7 @@ static inline unsigned long _pmd_pfn(pmd_t pmd)
 
 static inline void set_p4d(p4d_t *p4dp, p4d_t p4d)
 {
-	if (pgtable_l4_enabled)
+	if (system_supports_sv48())
 		*p4dp = p4d;
 	else
 		set_pud((pud_t *)p4dp, (pud_t){ p4d_val(p4d) });
@@ -167,7 +165,7 @@ static inline void set_p4d(p4d_t *p4dp, p4d_t p4d)
 
 static inline int p4d_none(p4d_t p4d)
 {
-	if (pgtable_l4_enabled)
+	if (system_supports_sv48())
 		return (p4d_val(p4d) == 0);
 
 	return 0;
@@ -175,7 +173,7 @@ static inline int p4d_none(p4d_t p4d)
 
 static inline int p4d_present(p4d_t p4d)
 {
-	if (pgtable_l4_enabled)
+	if (system_supports_sv48())
 		return (p4d_val(p4d) & _PAGE_PRESENT);
 
 	return 1;
@@ -183,7 +181,7 @@ static inline int p4d_present(p4d_t p4d)
 
 static inline int p4d_bad(p4d_t p4d)
 {
-	if (pgtable_l4_enabled)
+	if (system_supports_sv48())
 		return !p4d_present(p4d);
 
 	return 0;
@@ -191,7 +189,7 @@ static inline int p4d_bad(p4d_t p4d)
 
 static inline void p4d_clear(p4d_t *p4d)
 {
-	if (pgtable_l4_enabled)
+	if (system_supports_sv48())
 		set_p4d(p4d, __p4d(0));
 }
 
@@ -207,7 +205,7 @@ static inline unsigned long _p4d_pfn(p4d_t p4d)
 
 static inline pud_t *p4d_pgtable(p4d_t p4d)
 {
-	if (pgtable_l4_enabled)
+	if (system_supports_sv48())
 		return (pud_t *)pfn_to_virt(p4d_val(p4d) >> _PAGE_PFN_SHIFT);
 
 	return (pud_t *)pud_pgtable((pud_t) { p4d_val(p4d) });
@@ -224,7 +222,7 @@ static inline struct page *p4d_page(p4d_t p4d)
 #define pud_offset pud_offset
 static inline pud_t *pud_offset(p4d_t *p4d, unsigned long address)
 {
-	if (pgtable_l4_enabled)
+	if (system_supports_sv48())
 		return p4d_pgtable(*p4d) + pud_index(address);
 
 	return (pud_t *)p4d;
@@ -232,7 +230,7 @@ static inline pud_t *pud_offset(p4d_t *p4d, unsigned long address)
 
 static inline void set_pgd(pgd_t *pgdp, pgd_t pgd)
 {
-	if (pgtable_l5_enabled)
+	if (system_supports_sv57())
 		*pgdp = pgd;
 	else
 		set_p4d((p4d_t *)pgdp, (p4d_t){ pgd_val(pgd) });
@@ -240,7 +238,7 @@ static inline void set_pgd(pgd_t *pgdp, pgd_t pgd)
 
 static inline int pgd_none(pgd_t pgd)
 {
-	if (pgtable_l5_enabled)
+	if (system_supports_sv57())
 		return (pgd_val(pgd) == 0);
 
 	return 0;
@@ -248,7 +246,7 @@ static inline int pgd_none(pgd_t pgd)
 
 static inline int pgd_present(pgd_t pgd)
 {
-	if (pgtable_l5_enabled)
+	if (system_supports_sv57())
 		return (pgd_val(pgd) & _PAGE_PRESENT);
 
 	return 1;
@@ -256,7 +254,7 @@ static inline int pgd_present(pgd_t pgd)
 
 static inline int pgd_bad(pgd_t pgd)
 {
-	if (pgtable_l5_enabled)
+	if (system_supports_sv57())
 		return !pgd_present(pgd);
 
 	return 0;
@@ -264,13 +262,13 @@ static inline int pgd_bad(pgd_t pgd)
 
 static inline void pgd_clear(pgd_t *pgd)
 {
-	if (pgtable_l5_enabled)
+	if (system_supports_sv57())
 		set_pgd(pgd, __pgd(0));
 }
 
 static inline p4d_t *pgd_pgtable(pgd_t pgd)
 {
-	if (pgtable_l5_enabled)
+	if (system_supports_sv57())
 		return (p4d_t *)pfn_to_virt(pgd_val(pgd) >> _PAGE_PFN_SHIFT);
 
 	return (p4d_t *)p4d_pgtable((p4d_t) { pgd_val(pgd) });
@@ -288,7 +286,7 @@ static inline struct page *pgd_page(pgd_t pgd)
 #define p4d_offset p4d_offset
 static inline p4d_t *p4d_offset(pgd_t *pgd, unsigned long address)
 {
-	if (pgtable_l5_enabled)
+	if (system_supports_sv57())
 		return pgd_pgtable(*pgd) + p4d_index(address);
 
 	return (p4d_t *)pgd;
diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
index 046b44225623..ef2a1654100a 100644
--- a/arch/riscv/include/asm/pgtable.h
+++ b/arch/riscv/include/asm/pgtable.h
@@ -63,8 +63,8 @@
  * position vmemmap directly below the VMALLOC region.
  */
 #ifdef CONFIG_64BIT
-#define VA_BITS		(pgtable_l5_enabled ? \
-				57 : (pgtable_l4_enabled ? 48 : 39))
+#define VA_BITS		(system_supports_sv57() ? \
+				57 : (system_supports_sv48() ? 48 : 39))
 #else
 #define VA_BITS		32
 #endif
@@ -738,7 +738,6 @@ extern uintptr_t _dtb_early_pa;
 #define dtb_early_pa	_dtb_early_pa
 #endif /* CONFIG_XIP_KERNEL */
 extern u64 satp_mode;
-extern bool pgtable_l4_enabled;
 
 void paging_init(void);
 void misc_mem_init(void);
diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c
index ccb617791e56..c8f3989b08f3 100644
--- a/arch/riscv/kernel/cpu.c
+++ b/arch/riscv/kernel/cpu.c
@@ -141,9 +141,9 @@ static void print_mmu(struct seq_file *f)
 #if defined(CONFIG_32BIT)
 	strncpy(sv_type, "sv32", 5);
 #elif defined(CONFIG_64BIT)
-	if (pgtable_l5_enabled)
+	if (system_supports_sv57())
 		strncpy(sv_type, "sv57", 5);
-	else if (pgtable_l4_enabled)
+	else if (system_supports_sv48())
 		strncpy(sv_type, "sv48", 5);
 	else
 		strncpy(sv_type, "sv39", 5);
diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index 5f3f26dd9f21..b6a59a5d1a7f 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -21,6 +21,7 @@
 #include <linux/crash_dump.h>
 #include <linux/hugetlb.h>
 
+#include <asm/cpufeature.h>
 #include <asm/fixmap.h>
 #include <asm/tlbflush.h>
 #include <asm/sections.h>
@@ -44,11 +45,6 @@ u64 satp_mode __ro_after_init = SATP_MODE_32;
 #endif
 EXPORT_SYMBOL(satp_mode);
 
-bool pgtable_l4_enabled = IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_XIP_KERNEL);
-bool pgtable_l5_enabled = IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_XIP_KERNEL);
-EXPORT_SYMBOL(pgtable_l4_enabled);
-EXPORT_SYMBOL(pgtable_l5_enabled);
-
 phys_addr_t phys_ram_base __ro_after_init;
 EXPORT_SYMBOL(phys_ram_base);
 
@@ -555,26 +551,26 @@ static void __init create_p4d_mapping(p4d_t *p4dp,
 }
 
 #define pgd_next_t		p4d_t
-#define alloc_pgd_next(__va)	(pgtable_l5_enabled ?			\
-		pt_ops.alloc_p4d(__va) : (pgtable_l4_enabled ?		\
+#define alloc_pgd_next(__va)	(system_supports_sv57() ?		\
+		pt_ops.alloc_p4d(__va) : (system_supports_sv48() ?	\
 		pt_ops.alloc_pud(__va) : pt_ops.alloc_pmd(__va)))
-#define get_pgd_next_virt(__pa)	(pgtable_l5_enabled ?			\
-		pt_ops.get_p4d_virt(__pa) : (pgd_next_t *)(pgtable_l4_enabled ?	\
+#define get_pgd_next_virt(__pa)	(system_supports_sv57() ?		\
+		pt_ops.get_p4d_virt(__pa) : (pgd_next_t *)(system_supports_sv48() ?	\
 		pt_ops.get_pud_virt(__pa) : (pud_t *)pt_ops.get_pmd_virt(__pa)))
 #define create_pgd_next_mapping(__nextp, __va, __pa, __sz, __prot)	\
-				(pgtable_l5_enabled ?			\
+				(system_supports_sv57() ?		\
 		create_p4d_mapping(__nextp, __va, __pa, __sz, __prot) : \
-				(pgtable_l4_enabled ?			\
+				(system_supports_sv48() ?		\
 		create_pud_mapping((pud_t *)__nextp, __va, __pa, __sz, __prot) :	\
 		create_pmd_mapping((pmd_t *)__nextp, __va, __pa, __sz, __prot)))
-#define fixmap_pgd_next		(pgtable_l5_enabled ?			\
-		(uintptr_t)fixmap_p4d : (pgtable_l4_enabled ?		\
+#define fixmap_pgd_next		(system_supports_sv57() ?		\
+		(uintptr_t)fixmap_p4d : (system_supports_sv48() ?	\
 		(uintptr_t)fixmap_pud : (uintptr_t)fixmap_pmd))
-#define trampoline_pgd_next	(pgtable_l5_enabled ?			\
-		(uintptr_t)trampoline_p4d : (pgtable_l4_enabled ?	\
+#define trampoline_pgd_next	(system_supports_sv57() ?		\
+		(uintptr_t)trampoline_p4d : (system_supports_sv48() ?	\
 		(uintptr_t)trampoline_pud : (uintptr_t)trampoline_pmd))
-#define early_dtb_pgd_next	(pgtable_l5_enabled ?			\
-		(uintptr_t)early_dtb_p4d : (pgtable_l4_enabled ?	\
+#define early_dtb_pgd_next	(system_supports_sv57() ?		\
+		(uintptr_t)early_dtb_p4d : (system_supports_sv48() ?	\
 		(uintptr_t)early_dtb_pud : (uintptr_t)early_dtb_pmd))
 #else
 #define pgd_next_t		pte_t
@@ -680,14 +676,14 @@ static __init pgprot_t pgprot_from_va(uintptr_t va)
 #ifdef CONFIG_64BIT
 static void __init disable_pgtable_l5(void)
 {
-	pgtable_l5_enabled = false;
+	cpus_set_cap(RISCV_HAS_NO_SV57);
 	kernel_map.page_offset = PAGE_OFFSET_L4;
 	satp_mode = SATP_MODE_48;
 }
 
 static void __init disable_pgtable_l4(void)
 {
-	pgtable_l4_enabled = false;
+	cpus_set_cap(RISCV_HAS_NO_SV48);
 	kernel_map.page_offset = PAGE_OFFSET_L3;
 	satp_mode = SATP_MODE_39;
 }
@@ -816,11 +812,11 @@ static void __init create_fdt_early_page_table(pgd_t *pgdir, uintptr_t dtb_pa)
 			   PGDIR_SIZE,
 			   IS_ENABLED(CONFIG_64BIT) ? PAGE_TABLE : PAGE_KERNEL);
 
-	if (pgtable_l5_enabled)
+	if (system_supports_sv57())
 		create_p4d_mapping(early_dtb_p4d, DTB_EARLY_BASE_VA,
 				   (uintptr_t)early_dtb_pud, P4D_SIZE, PAGE_TABLE);
 
-	if (pgtable_l4_enabled)
+	if (system_supports_sv48())
 		create_pud_mapping(early_dtb_pud, DTB_EARLY_BASE_VA,
 				   (uintptr_t)early_dtb_pmd, PUD_SIZE, PAGE_TABLE);
 
@@ -961,11 +957,11 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
 
 #ifndef __PAGETABLE_PMD_FOLDED
 	/* Setup fixmap P4D and PUD */
-	if (pgtable_l5_enabled)
+	if (system_supports_sv57())
 		create_p4d_mapping(fixmap_p4d, FIXADDR_START,
 				   (uintptr_t)fixmap_pud, P4D_SIZE, PAGE_TABLE);
 	/* Setup fixmap PUD and PMD */
-	if (pgtable_l4_enabled)
+	if (system_supports_sv48())
 		create_pud_mapping(fixmap_pud, FIXADDR_START,
 				   (uintptr_t)fixmap_pmd, PUD_SIZE, PAGE_TABLE);
 	create_pmd_mapping(fixmap_pmd, FIXADDR_START,
@@ -973,10 +969,10 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
 	/* Setup trampoline PGD and PMD */
 	create_pgd_mapping(trampoline_pg_dir, kernel_map.virt_addr,
 			   trampoline_pgd_next, PGDIR_SIZE, PAGE_TABLE);
-	if (pgtable_l5_enabled)
+	if (system_supports_sv57())
 		create_p4d_mapping(trampoline_p4d, kernel_map.virt_addr,
 				   (uintptr_t)trampoline_pud, P4D_SIZE, PAGE_TABLE);
-	if (pgtable_l4_enabled)
+	if (system_supports_sv48())
 		create_pud_mapping(trampoline_pud, kernel_map.virt_addr,
 				   (uintptr_t)trampoline_pmd, PUD_SIZE, PAGE_TABLE);
 #ifdef CONFIG_XIP_KERNEL
diff --git a/arch/riscv/mm/kasan_init.c b/arch/riscv/mm/kasan_init.c
index a22e418dbd82..7b662661f7a9 100644
--- a/arch/riscv/mm/kasan_init.c
+++ b/arch/riscv/mm/kasan_init.c
@@ -209,15 +209,15 @@ static void __init kasan_populate_p4d(pgd_t *pgd,
 		set_pgd(pgd, pfn_pgd(PFN_DOWN(__pa(base_p4d)), PAGE_TABLE));
 }
 
-#define kasan_early_shadow_pgd_next			(pgtable_l5_enabled ?	\
+#define kasan_early_shadow_pgd_next		(system_supports_sv57() ?	\
 				(uintptr_t)kasan_early_shadow_p4d :		\
-							(pgtable_l4_enabled ?	\
+						(system_supports_sv48() ?	\
 				(uintptr_t)kasan_early_shadow_pud :		\
 				(uintptr_t)kasan_early_shadow_pmd))
 #define kasan_populate_pgd_next(pgdp, vaddr, next, early)			\
-		(pgtable_l5_enabled ?						\
+		(system_supports_sv57() ?					\
 		kasan_populate_p4d(pgdp, vaddr, next, early) :			\
-		(pgtable_l4_enabled ?						\
+		(system_supports_sv48() ?					\
 			kasan_populate_pud(pgdp, vaddr, next, early) :		\
 			kasan_populate_pmd((pud_t *)pgdp, vaddr, next)))
 
@@ -274,7 +274,7 @@ asmlinkage void __init kasan_early_init(void)
 				(__pa((uintptr_t)kasan_early_shadow_pte)),
 				PAGE_TABLE));
 
-	if (pgtable_l4_enabled) {
+	if (system_supports_sv48()) {
 		for (i = 0; i < PTRS_PER_PUD; ++i)
 			set_pud(kasan_early_shadow_pud + i,
 				pfn_pud(PFN_DOWN
@@ -282,7 +282,7 @@ asmlinkage void __init kasan_early_init(void)
 					PAGE_TABLE));
 	}
 
-	if (pgtable_l5_enabled) {
+	if (system_supports_sv57()) {
 		for (i = 0; i < PTRS_PER_P4D; ++i)
 			set_p4d(kasan_early_shadow_p4d + i,
 				pfn_p4d(PFN_DOWN
@@ -393,9 +393,9 @@ static void __init kasan_shallow_populate_p4d(pgd_t *pgdp,
 }
 
 #define kasan_shallow_populate_pgd_next(pgdp, vaddr, next)			\
-		(pgtable_l5_enabled ?						\
+		(system_supports_sv57() ?					\
 		kasan_shallow_populate_p4d(pgdp, vaddr, next) :			\
-		(pgtable_l4_enabled ?						\
+		(system_supports_sv48() ?					\
 		kasan_shallow_populate_pud(pgdp, vaddr, next) :			\
 		kasan_shallow_populate_pmd(pgdp, vaddr, next)))
 
diff --git a/arch/riscv/tools/cpucaps b/arch/riscv/tools/cpucaps
index cb1ff2747859..0b9e19ec8371 100644
--- a/arch/riscv/tools/cpucaps
+++ b/arch/riscv/tools/cpucaps
@@ -3,3 +3,5 @@
 # Internal CPU capabilities constants, keep this list sorted
 
 HAS_NO_FPU
+HAS_NO_SV48
+HAS_NO_SV57
-- 
2.34.1


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

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 2/4] riscv: introduce unified static key mechanism for CPU features
  2022-05-08 16:07   ` Jisheng Zhang
@ 2022-05-09  3:47     ` Anup Patel
  -1 siblings, 0 replies; 36+ messages in thread
From: Anup Patel @ 2022-05-09  3:47 UTC (permalink / raw)
  To: Jisheng Zhang
  Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Andrey Ryabinin,
	Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
	Vincenzo Frascino, Alexandre Ghiti, linux-riscv,
	linux-kernel@vger.kernel.org List, kasan-dev

On Sun, May 8, 2022 at 9:47 PM Jisheng Zhang <jszhang@kernel.org> wrote:
>
> Currently, riscv has several features why may not be supported on all
> riscv platforms, for example, FPU, SV48 and so on. To support unified
> kernel Image style, we need to check whether the feature is suportted
> or not. If the check sits at hot code path, then performance will be
> impacted a lot. static key can be used to solve the issue. In the past
> FPU support has been converted to use static key mechanism. I believe
> we will have similar cases in the future.

It's not just FPU and Sv48. There are several others such as Svinval,
Vector, Svnapot, Svpbmt, and many many others.

Overall, I agree with the approach of using static key array but I
disagree with the semantics and the duplicate stuff being added.

Please see more comments below ..

>
> Similar as arm64 does(in fact, some code is borrowed from arm64), this
> patch tries to add an unified mechanism to use static keys for all
> the cpu features by implementing an array of default-false static keys
> and enabling them when detected. The cpus_have_*_cap() check uses the
> static keys if riscv_const_caps_ready is finalized, otherwise the
> compiler generates the bitmap test.

First of all, we should stop calling this a feature (like ARM does). Rather,
we should call these as isa extensions ("isaext") to align with the RISC-V
priv spec and RISC-V profiles spec. For all the ISA optionalities which do
not have distinct extension name, the RISC-V profiles spec is assigning
names to all such optionalities.

Another issue with semantics is that this patch assumes all features are
enabled by default and we selectively disable it. This contrary to the
approach taken by existing arch/riscv/kernel/cpufeature.c which assumes
nothing is enabled by default and we selectively enable it.

>
> Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
> ---
>  arch/riscv/Makefile                 |  3 +
>  arch/riscv/include/asm/cpufeature.h | 94 +++++++++++++++++++++++++++++
>  arch/riscv/kernel/cpufeature.c      | 23 +++++++
>  arch/riscv/tools/Makefile           | 22 +++++++
>  arch/riscv/tools/cpucaps            |  5 ++
>  arch/riscv/tools/gen-cpucaps.awk    | 40 ++++++++++++
>  6 files changed, 187 insertions(+)
>  create mode 100644 arch/riscv/include/asm/cpufeature.h
>  create mode 100644 arch/riscv/tools/Makefile
>  create mode 100644 arch/riscv/tools/cpucaps
>  create mode 100755 arch/riscv/tools/gen-cpucaps.awk
>
> diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
> index 7d81102cffd4..f4df67369d84 100644
> --- a/arch/riscv/Makefile
> +++ b/arch/riscv/Makefile
> @@ -154,3 +154,6 @@ PHONY += rv64_randconfig
>  rv64_randconfig:
>         $(Q)$(MAKE) KCONFIG_ALLCONFIG=$(srctree)/arch/riscv/configs/64-bit.config \
>                 -f $(srctree)/Makefile randconfig
> +
> +archprepare:
> +       $(Q)$(MAKE) $(build)=arch/riscv/tools kapi
> diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
> new file mode 100644
> index 000000000000..d80ddd2f3b49
> --- /dev/null
> +++ b/arch/riscv/include/asm/cpufeature.h

We don't need a separate header for this.

All this belongs to arch/riscv/include/asm/hwcap.h

> @@ -0,0 +1,94 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
> + * Copyright (C) 2022 Jisheng Zhang <jszhang@kernel.org>
> + */
> +
> +#ifndef __ASM_CPUFEATURE_H
> +#define __ASM_CPUFEATURE_H
> +
> +#include <asm/cpucaps.h>
> +
> +#include <linux/bug.h>
> +#include <linux/jump_label.h>
> +#include <linux/kernel.h>
> +
> +extern DECLARE_BITMAP(cpu_hwcaps, RISCV_NCAPS);

This is a redundant bitmap. Please re-use "riscv_isa" bitmap for this
the ISA extensions.

> +extern struct static_key_false cpu_hwcap_keys[RISCV_NCAPS];

This should be called "riscv_isa_keys"

> +extern struct static_key_false riscv_const_caps_ready;

This should be called "riscv_isa_keys_ready".

> +
> +static __always_inline bool system_capabilities_finalized(void)

Another misaligned name. This should be called
"riscv_isa_keys_finalized()".

> +{
> +       return static_branch_likely(&riscv_const_caps_ready);
> +}
> +
> +/*
> + * Test for a capability with a runtime check.
> + *
> + * Before the capability is detected, this returns false.
> + */
> +static inline bool cpus_have_cap(unsigned int num)
> +{
> +       if (num >= RISCV_NCAPS)
> +               return false;
> +       return test_bit(num, cpu_hwcaps);
> +}

This should be called riscv_isa_have_extension() and it should
internally call "__riscv_isa_extension_available(NULL, num)".

> +
> +/*
> + * Test for a capability without a runtime check.
> + *
> + * Before capabilities are finalized, this returns false.
> + * After capabilities are finalized, this is patched to avoid a runtime check.
> + *
> + * @num must be a compile-time constant.
> + */
> +static __always_inline bool __cpus_have_const_cap(int num)

This should be named "__riscv_isa_have_const_extension()"

> +{
> +       if (num >= RISCV_NCAPS)
> +               return false;
> +       return static_branch_unlikely(&cpu_hwcap_keys[num]);
> +}
> +
> +/*
> + * Test for a capability without a runtime check.
> + *
> + * Before capabilities are finalized, this will BUG().
> + * After capabilities are finalized, this is patched to avoid a runtime check.
> + *
> + * @num must be a compile-time constant.
> + */
> +static __always_inline bool cpus_have_final_cap(int num)

This should be called "riscv_isa_have_final_extension()"

> +{
> +       if (system_capabilities_finalized())
> +               return __cpus_have_const_cap(num);
> +       else
> +               BUG();
> +}
> +
> +/*
> + * Test for a capability, possibly with a runtime check.
> + *
> + * Before capabilities are finalized, this behaves as cpus_have_cap().
> + * After capabilities are finalized, this is patched to avoid a runtime check.
> + *
> + * @num must be a compile-time constant.
> + */
> +static __always_inline bool cpus_have_const_cap(int num)

Same comment as above.

> +{
> +       if (system_capabilities_finalized())
> +               return __cpus_have_const_cap(num);
> +       else
> +               return cpus_have_cap(num);
> +}
> +
> +static inline void cpus_set_cap(unsigned int num)

Same comment as above.

> +{
> +       if (num >= RISCV_NCAPS) {
> +               pr_warn("Attempt to set an illegal CPU capability (%d >= %d)\n",
> +                       num, RISCV_NCAPS);
> +       } else {
> +               __set_bit(num, cpu_hwcaps);
> +       }
> +}
> +
> +#endif
> diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> index 1b2d42d7f589..e6c72cad0c1c 100644
> --- a/arch/riscv/kernel/cpufeature.c
> +++ b/arch/riscv/kernel/cpufeature.c
> @@ -9,6 +9,7 @@
>  #include <linux/bitmap.h>
>  #include <linux/ctype.h>
>  #include <linux/of.h>
> +#include <asm/cpufeature.h>
>  #include <asm/processor.h>
>  #include <asm/hwcap.h>
>  #include <asm/smp.h>
> @@ -25,6 +26,15 @@ static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
>  __ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_fpu);
>  #endif
>
> +DECLARE_BITMAP(cpu_hwcaps, RISCV_NCAPS);
> +EXPORT_SYMBOL(cpu_hwcaps);

Just like the previous comment. This is a redundant bitmap.
Please use "riscv_isa" bitmap for this purpose.

> +
> +DEFINE_STATIC_KEY_ARRAY_FALSE(cpu_hwcap_keys, RISCV_NCAPS);
> +EXPORT_SYMBOL(cpu_hwcap_keys);
> +
> +DEFINE_STATIC_KEY_FALSE(riscv_const_caps_ready);
> +EXPORT_SYMBOL(riscv_const_caps_ready);

Please see comments above.

> +
>  /**
>   * riscv_isa_extension_base() - Get base extension word
>   *
> @@ -62,6 +72,17 @@ bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, int bit)
>  }
>  EXPORT_SYMBOL_GPL(__riscv_isa_extension_available);
>
> +static void __init enable_cpu_capabilities(void)
> +{
> +       int i;
> +
> +       for (i = 0; i < RISCV_NCAPS; i++) {
> +               if (!cpus_have_cap(i))
> +                       continue;
> +               static_branch_enable(&cpu_hwcap_keys[i]);
> +       }
> +}
> +
>  void __init riscv_fill_hwcap(void)
>  {
>         struct device_node *node;
> @@ -236,4 +257,6 @@ void __init riscv_fill_hwcap(void)
>         if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D))
>                 static_branch_enable(&cpu_hwcap_fpu);
>  #endif
> +       enable_cpu_capabilities();
> +       static_branch_enable(&riscv_const_caps_ready);
>  }
> diff --git a/arch/riscv/tools/Makefile b/arch/riscv/tools/Makefile
> new file mode 100644
> index 000000000000..932b4fe5c768
> --- /dev/null
> +++ b/arch/riscv/tools/Makefile
> @@ -0,0 +1,22 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +gen := arch/$(ARCH)/include/generated
> +kapi := $(gen)/asm
> +
> +kapi-hdrs-y := $(kapi)/cpucaps.h
> +
> +targets += $(addprefix ../../../,$(gen-y) $(kapi-hdrs-y))
> +
> +PHONY += kapi
> +
> +kapi:   $(kapi-hdrs-y) $(gen-y)
> +
> +# Create output directory if not already present
> +_dummy := $(shell [ -d '$(kapi)' ] || mkdir -p '$(kapi)')
> +
> +quiet_cmd_gen_cpucaps = GEN     $@
> +      cmd_gen_cpucaps = mkdir -p $(dir $@) && \
> +                     $(AWK) -f $(filter-out $(PHONY),$^) > $@
> +
> +$(kapi)/cpucaps.h: $(src)/gen-cpucaps.awk $(src)/cpucaps FORCE
> +       $(call if_changed,gen_cpucaps)
> diff --git a/arch/riscv/tools/cpucaps b/arch/riscv/tools/cpucaps
> new file mode 100644
> index 000000000000..cb1ff2747859
> --- /dev/null
> +++ b/arch/riscv/tools/cpucaps
> @@ -0,0 +1,5 @@
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# Internal CPU capabilities constants, keep this list sorted
> +
> +HAS_NO_FPU

How can "No FPU" be a CPU capability ?

We have ISA extensions 'F' and 'D' which tells us whether an FPU is available
or not.

I think this file should be a table with two columns
"<lower_case_extension_name> <parsed_from_isa_string_yes_no>"
I this this file should look like this:

i yes
m yes
a yes
c yes
f yes
d yes
h yes
sv48 no
sv57 no
sstc yes
svinval yes
svpbmt yes
svnapot yes
sscofpmf yes
...

> diff --git a/arch/riscv/tools/gen-cpucaps.awk b/arch/riscv/tools/gen-cpucaps.awk
> new file mode 100755
> index 000000000000..52a1e1b064ad
> --- /dev/null
> +++ b/arch/riscv/tools/gen-cpucaps.awk
> @@ -0,0 +1,40 @@
> +#!/bin/awk -f
> +# SPDX-License-Identifier: GPL-2.0
> +# gen-cpucaps.awk: riscv cpucaps header generator
> +#
> +# Usage: awk -f gen-cpucaps.awk cpucaps.txt
> +
> +# Log an error and terminate
> +function fatal(msg) {
> +       print "Error at line " NR ": " msg > "/dev/stderr"
> +       exit 1
> +}
> +
> +# skip blank lines and comment lines
> +/^$/ { next }
> +/^#/ { next }
> +
> +BEGIN {
> +       print "#ifndef __ASM_CPUCAPS_H"
> +       print "#define __ASM_CPUCAPS_H"
> +       print ""
> +       print "/* Generated file - do not edit */"
> +       cap_num = 0
> +       print ""
> +}
> +
> +/^[vA-Z0-9_]+$/ {
> +       printf("#define RISCV_%-30s\t%d\n", $0, cap_num++)
> +       next
> +}
> +
> +END {
> +       printf("#define RISCV_NCAPS\t\t\t\t%d\n", cap_num)
> +       print ""
> +       print "#endif /* __ASM_CPUCAPS_H */"
> +}

This script need to change refer capabilities as extensions.

For every extension, there should be two defines.
For e.g. "sstc" extension should have following defines
#define RISCV_ISA_EXT_sstc <#num>
#define RISCV_ISA_EXT_FROMSTR_sstc <1|0>

> +
> +# Any lines not handled by previous rules are unexpected
> +{
> +       fatal("unhandled statement")
> +}
> --
> 2.34.1
>

Regards,
Anup

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

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 2/4] riscv: introduce unified static key mechanism for CPU features
@ 2022-05-09  3:47     ` Anup Patel
  0 siblings, 0 replies; 36+ messages in thread
From: Anup Patel @ 2022-05-09  3:47 UTC (permalink / raw)
  To: Jisheng Zhang
  Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Andrey Ryabinin,
	Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
	Vincenzo Frascino, Alexandre Ghiti, linux-riscv,
	linux-kernel@vger.kernel.org List, kasan-dev

On Sun, May 8, 2022 at 9:47 PM Jisheng Zhang <jszhang@kernel.org> wrote:
>
> Currently, riscv has several features why may not be supported on all
> riscv platforms, for example, FPU, SV48 and so on. To support unified
> kernel Image style, we need to check whether the feature is suportted
> or not. If the check sits at hot code path, then performance will be
> impacted a lot. static key can be used to solve the issue. In the past
> FPU support has been converted to use static key mechanism. I believe
> we will have similar cases in the future.

It's not just FPU and Sv48. There are several others such as Svinval,
Vector, Svnapot, Svpbmt, and many many others.

Overall, I agree with the approach of using static key array but I
disagree with the semantics and the duplicate stuff being added.

Please see more comments below ..

>
> Similar as arm64 does(in fact, some code is borrowed from arm64), this
> patch tries to add an unified mechanism to use static keys for all
> the cpu features by implementing an array of default-false static keys
> and enabling them when detected. The cpus_have_*_cap() check uses the
> static keys if riscv_const_caps_ready is finalized, otherwise the
> compiler generates the bitmap test.

First of all, we should stop calling this a feature (like ARM does). Rather,
we should call these as isa extensions ("isaext") to align with the RISC-V
priv spec and RISC-V profiles spec. For all the ISA optionalities which do
not have distinct extension name, the RISC-V profiles spec is assigning
names to all such optionalities.

Another issue with semantics is that this patch assumes all features are
enabled by default and we selectively disable it. This contrary to the
approach taken by existing arch/riscv/kernel/cpufeature.c which assumes
nothing is enabled by default and we selectively enable it.

>
> Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
> ---
>  arch/riscv/Makefile                 |  3 +
>  arch/riscv/include/asm/cpufeature.h | 94 +++++++++++++++++++++++++++++
>  arch/riscv/kernel/cpufeature.c      | 23 +++++++
>  arch/riscv/tools/Makefile           | 22 +++++++
>  arch/riscv/tools/cpucaps            |  5 ++
>  arch/riscv/tools/gen-cpucaps.awk    | 40 ++++++++++++
>  6 files changed, 187 insertions(+)
>  create mode 100644 arch/riscv/include/asm/cpufeature.h
>  create mode 100644 arch/riscv/tools/Makefile
>  create mode 100644 arch/riscv/tools/cpucaps
>  create mode 100755 arch/riscv/tools/gen-cpucaps.awk
>
> diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
> index 7d81102cffd4..f4df67369d84 100644
> --- a/arch/riscv/Makefile
> +++ b/arch/riscv/Makefile
> @@ -154,3 +154,6 @@ PHONY += rv64_randconfig
>  rv64_randconfig:
>         $(Q)$(MAKE) KCONFIG_ALLCONFIG=$(srctree)/arch/riscv/configs/64-bit.config \
>                 -f $(srctree)/Makefile randconfig
> +
> +archprepare:
> +       $(Q)$(MAKE) $(build)=arch/riscv/tools kapi
> diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
> new file mode 100644
> index 000000000000..d80ddd2f3b49
> --- /dev/null
> +++ b/arch/riscv/include/asm/cpufeature.h

We don't need a separate header for this.

All this belongs to arch/riscv/include/asm/hwcap.h

> @@ -0,0 +1,94 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
> + * Copyright (C) 2022 Jisheng Zhang <jszhang@kernel.org>
> + */
> +
> +#ifndef __ASM_CPUFEATURE_H
> +#define __ASM_CPUFEATURE_H
> +
> +#include <asm/cpucaps.h>
> +
> +#include <linux/bug.h>
> +#include <linux/jump_label.h>
> +#include <linux/kernel.h>
> +
> +extern DECLARE_BITMAP(cpu_hwcaps, RISCV_NCAPS);

This is a redundant bitmap. Please re-use "riscv_isa" bitmap for this
the ISA extensions.

> +extern struct static_key_false cpu_hwcap_keys[RISCV_NCAPS];

This should be called "riscv_isa_keys"

> +extern struct static_key_false riscv_const_caps_ready;

This should be called "riscv_isa_keys_ready".

> +
> +static __always_inline bool system_capabilities_finalized(void)

Another misaligned name. This should be called
"riscv_isa_keys_finalized()".

> +{
> +       return static_branch_likely(&riscv_const_caps_ready);
> +}
> +
> +/*
> + * Test for a capability with a runtime check.
> + *
> + * Before the capability is detected, this returns false.
> + */
> +static inline bool cpus_have_cap(unsigned int num)
> +{
> +       if (num >= RISCV_NCAPS)
> +               return false;
> +       return test_bit(num, cpu_hwcaps);
> +}

This should be called riscv_isa_have_extension() and it should
internally call "__riscv_isa_extension_available(NULL, num)".

> +
> +/*
> + * Test for a capability without a runtime check.
> + *
> + * Before capabilities are finalized, this returns false.
> + * After capabilities are finalized, this is patched to avoid a runtime check.
> + *
> + * @num must be a compile-time constant.
> + */
> +static __always_inline bool __cpus_have_const_cap(int num)

This should be named "__riscv_isa_have_const_extension()"

> +{
> +       if (num >= RISCV_NCAPS)
> +               return false;
> +       return static_branch_unlikely(&cpu_hwcap_keys[num]);
> +}
> +
> +/*
> + * Test for a capability without a runtime check.
> + *
> + * Before capabilities are finalized, this will BUG().
> + * After capabilities are finalized, this is patched to avoid a runtime check.
> + *
> + * @num must be a compile-time constant.
> + */
> +static __always_inline bool cpus_have_final_cap(int num)

This should be called "riscv_isa_have_final_extension()"

> +{
> +       if (system_capabilities_finalized())
> +               return __cpus_have_const_cap(num);
> +       else
> +               BUG();
> +}
> +
> +/*
> + * Test for a capability, possibly with a runtime check.
> + *
> + * Before capabilities are finalized, this behaves as cpus_have_cap().
> + * After capabilities are finalized, this is patched to avoid a runtime check.
> + *
> + * @num must be a compile-time constant.
> + */
> +static __always_inline bool cpus_have_const_cap(int num)

Same comment as above.

> +{
> +       if (system_capabilities_finalized())
> +               return __cpus_have_const_cap(num);
> +       else
> +               return cpus_have_cap(num);
> +}
> +
> +static inline void cpus_set_cap(unsigned int num)

Same comment as above.

> +{
> +       if (num >= RISCV_NCAPS) {
> +               pr_warn("Attempt to set an illegal CPU capability (%d >= %d)\n",
> +                       num, RISCV_NCAPS);
> +       } else {
> +               __set_bit(num, cpu_hwcaps);
> +       }
> +}
> +
> +#endif
> diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> index 1b2d42d7f589..e6c72cad0c1c 100644
> --- a/arch/riscv/kernel/cpufeature.c
> +++ b/arch/riscv/kernel/cpufeature.c
> @@ -9,6 +9,7 @@
>  #include <linux/bitmap.h>
>  #include <linux/ctype.h>
>  #include <linux/of.h>
> +#include <asm/cpufeature.h>
>  #include <asm/processor.h>
>  #include <asm/hwcap.h>
>  #include <asm/smp.h>
> @@ -25,6 +26,15 @@ static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
>  __ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_fpu);
>  #endif
>
> +DECLARE_BITMAP(cpu_hwcaps, RISCV_NCAPS);
> +EXPORT_SYMBOL(cpu_hwcaps);

Just like the previous comment. This is a redundant bitmap.
Please use "riscv_isa" bitmap for this purpose.

> +
> +DEFINE_STATIC_KEY_ARRAY_FALSE(cpu_hwcap_keys, RISCV_NCAPS);
> +EXPORT_SYMBOL(cpu_hwcap_keys);
> +
> +DEFINE_STATIC_KEY_FALSE(riscv_const_caps_ready);
> +EXPORT_SYMBOL(riscv_const_caps_ready);

Please see comments above.

> +
>  /**
>   * riscv_isa_extension_base() - Get base extension word
>   *
> @@ -62,6 +72,17 @@ bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, int bit)
>  }
>  EXPORT_SYMBOL_GPL(__riscv_isa_extension_available);
>
> +static void __init enable_cpu_capabilities(void)
> +{
> +       int i;
> +
> +       for (i = 0; i < RISCV_NCAPS; i++) {
> +               if (!cpus_have_cap(i))
> +                       continue;
> +               static_branch_enable(&cpu_hwcap_keys[i]);
> +       }
> +}
> +
>  void __init riscv_fill_hwcap(void)
>  {
>         struct device_node *node;
> @@ -236,4 +257,6 @@ void __init riscv_fill_hwcap(void)
>         if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D))
>                 static_branch_enable(&cpu_hwcap_fpu);
>  #endif
> +       enable_cpu_capabilities();
> +       static_branch_enable(&riscv_const_caps_ready);
>  }
> diff --git a/arch/riscv/tools/Makefile b/arch/riscv/tools/Makefile
> new file mode 100644
> index 000000000000..932b4fe5c768
> --- /dev/null
> +++ b/arch/riscv/tools/Makefile
> @@ -0,0 +1,22 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +gen := arch/$(ARCH)/include/generated
> +kapi := $(gen)/asm
> +
> +kapi-hdrs-y := $(kapi)/cpucaps.h
> +
> +targets += $(addprefix ../../../,$(gen-y) $(kapi-hdrs-y))
> +
> +PHONY += kapi
> +
> +kapi:   $(kapi-hdrs-y) $(gen-y)
> +
> +# Create output directory if not already present
> +_dummy := $(shell [ -d '$(kapi)' ] || mkdir -p '$(kapi)')
> +
> +quiet_cmd_gen_cpucaps = GEN     $@
> +      cmd_gen_cpucaps = mkdir -p $(dir $@) && \
> +                     $(AWK) -f $(filter-out $(PHONY),$^) > $@
> +
> +$(kapi)/cpucaps.h: $(src)/gen-cpucaps.awk $(src)/cpucaps FORCE
> +       $(call if_changed,gen_cpucaps)
> diff --git a/arch/riscv/tools/cpucaps b/arch/riscv/tools/cpucaps
> new file mode 100644
> index 000000000000..cb1ff2747859
> --- /dev/null
> +++ b/arch/riscv/tools/cpucaps
> @@ -0,0 +1,5 @@
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# Internal CPU capabilities constants, keep this list sorted
> +
> +HAS_NO_FPU

How can "No FPU" be a CPU capability ?

We have ISA extensions 'F' and 'D' which tells us whether an FPU is available
or not.

I think this file should be a table with two columns
"<lower_case_extension_name> <parsed_from_isa_string_yes_no>"
I this this file should look like this:

i yes
m yes
a yes
c yes
f yes
d yes
h yes
sv48 no
sv57 no
sstc yes
svinval yes
svpbmt yes
svnapot yes
sscofpmf yes
...

> diff --git a/arch/riscv/tools/gen-cpucaps.awk b/arch/riscv/tools/gen-cpucaps.awk
> new file mode 100755
> index 000000000000..52a1e1b064ad
> --- /dev/null
> +++ b/arch/riscv/tools/gen-cpucaps.awk
> @@ -0,0 +1,40 @@
> +#!/bin/awk -f
> +# SPDX-License-Identifier: GPL-2.0
> +# gen-cpucaps.awk: riscv cpucaps header generator
> +#
> +# Usage: awk -f gen-cpucaps.awk cpucaps.txt
> +
> +# Log an error and terminate
> +function fatal(msg) {
> +       print "Error at line " NR ": " msg > "/dev/stderr"
> +       exit 1
> +}
> +
> +# skip blank lines and comment lines
> +/^$/ { next }
> +/^#/ { next }
> +
> +BEGIN {
> +       print "#ifndef __ASM_CPUCAPS_H"
> +       print "#define __ASM_CPUCAPS_H"
> +       print ""
> +       print "/* Generated file - do not edit */"
> +       cap_num = 0
> +       print ""
> +}
> +
> +/^[vA-Z0-9_]+$/ {
> +       printf("#define RISCV_%-30s\t%d\n", $0, cap_num++)
> +       next
> +}
> +
> +END {
> +       printf("#define RISCV_NCAPS\t\t\t\t%d\n", cap_num)
> +       print ""
> +       print "#endif /* __ASM_CPUCAPS_H */"
> +}

This script need to change refer capabilities as extensions.

For every extension, there should be two defines.
For e.g. "sstc" extension should have following defines
#define RISCV_ISA_EXT_sstc <#num>
#define RISCV_ISA_EXT_FROMSTR_sstc <1|0>

> +
> +# Any lines not handled by previous rules are unexpected
> +{
> +       fatal("unhandled statement")
> +}
> --
> 2.34.1
>

Regards,
Anup

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 1/4] riscv: mm: init: make pt_ops_set_[early|late|fixmap] static
  2022-05-08 16:07   ` Jisheng Zhang
@ 2022-05-09  3:51     ` Anup Patel
  -1 siblings, 0 replies; 36+ messages in thread
From: Anup Patel @ 2022-05-09  3:51 UTC (permalink / raw)
  To: Jisheng Zhang
  Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Andrey Ryabinin,
	Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
	Vincenzo Frascino, Alexandre Ghiti, linux-riscv,
	linux-kernel@vger.kernel.org List, kasan-dev

On Sun, May 8, 2022 at 9:46 PM Jisheng Zhang <jszhang@kernel.org> wrote:
>
> These three functions are only used in init.c, so make them static.
> Fix W=1 warnings like below:
>
> arch/riscv/mm/init.c:721:13: warning: no previous prototype for function
> 'pt_ops_set_early' [-Wmissing-prototypes]
>    void __init pt_ops_set_early(void)
>                ^
>
> Signed-off-by: Jisheng Zhang <jszhang@kernel.org>

Looks good to me.

Reviewed-by: Anup Patel <anup@brainfault.org>

Regards,
Anup

> ---
>  arch/riscv/mm/init.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
> index 05ed641a1134..5f3f26dd9f21 100644
> --- a/arch/riscv/mm/init.c
> +++ b/arch/riscv/mm/init.c
> @@ -849,7 +849,7 @@ static void __init create_fdt_early_page_table(pgd_t *pgdir, uintptr_t dtb_pa)
>   * MMU is not enabled, the page tables are allocated directly using
>   * early_pmd/pud/p4d and the address returned is the physical one.
>   */
> -void __init pt_ops_set_early(void)
> +static void __init pt_ops_set_early(void)
>  {
>         pt_ops.alloc_pte = alloc_pte_early;
>         pt_ops.get_pte_virt = get_pte_virt_early;
> @@ -871,7 +871,7 @@ void __init pt_ops_set_early(void)
>   * Note that this is called with MMU disabled, hence kernel_mapping_pa_to_va,
>   * but it will be used as described above.
>   */
> -void __init pt_ops_set_fixmap(void)
> +static void __init pt_ops_set_fixmap(void)
>  {
>         pt_ops.alloc_pte = kernel_mapping_pa_to_va((uintptr_t)alloc_pte_fixmap);
>         pt_ops.get_pte_virt = kernel_mapping_pa_to_va((uintptr_t)get_pte_virt_fixmap);
> @@ -889,7 +889,7 @@ void __init pt_ops_set_fixmap(void)
>   * MMU is enabled and page table setup is complete, so from now, we can use
>   * generic page allocation functions to setup page table.
>   */
> -void __init pt_ops_set_late(void)
> +static void __init pt_ops_set_late(void)
>  {
>         pt_ops.alloc_pte = alloc_pte_late;
>         pt_ops.get_pte_virt = get_pte_virt_late;
> --
> 2.34.1
>

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

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 1/4] riscv: mm: init: make pt_ops_set_[early|late|fixmap] static
@ 2022-05-09  3:51     ` Anup Patel
  0 siblings, 0 replies; 36+ messages in thread
From: Anup Patel @ 2022-05-09  3:51 UTC (permalink / raw)
  To: Jisheng Zhang
  Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Andrey Ryabinin,
	Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
	Vincenzo Frascino, Alexandre Ghiti, linux-riscv,
	linux-kernel@vger.kernel.org List, kasan-dev

On Sun, May 8, 2022 at 9:46 PM Jisheng Zhang <jszhang@kernel.org> wrote:
>
> These three functions are only used in init.c, so make them static.
> Fix W=1 warnings like below:
>
> arch/riscv/mm/init.c:721:13: warning: no previous prototype for function
> 'pt_ops_set_early' [-Wmissing-prototypes]
>    void __init pt_ops_set_early(void)
>                ^
>
> Signed-off-by: Jisheng Zhang <jszhang@kernel.org>

Looks good to me.

Reviewed-by: Anup Patel <anup@brainfault.org>

Regards,
Anup

> ---
>  arch/riscv/mm/init.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
> index 05ed641a1134..5f3f26dd9f21 100644
> --- a/arch/riscv/mm/init.c
> +++ b/arch/riscv/mm/init.c
> @@ -849,7 +849,7 @@ static void __init create_fdt_early_page_table(pgd_t *pgdir, uintptr_t dtb_pa)
>   * MMU is not enabled, the page tables are allocated directly using
>   * early_pmd/pud/p4d and the address returned is the physical one.
>   */
> -void __init pt_ops_set_early(void)
> +static void __init pt_ops_set_early(void)
>  {
>         pt_ops.alloc_pte = alloc_pte_early;
>         pt_ops.get_pte_virt = get_pte_virt_early;
> @@ -871,7 +871,7 @@ void __init pt_ops_set_early(void)
>   * Note that this is called with MMU disabled, hence kernel_mapping_pa_to_va,
>   * but it will be used as described above.
>   */
> -void __init pt_ops_set_fixmap(void)
> +static void __init pt_ops_set_fixmap(void)
>  {
>         pt_ops.alloc_pte = kernel_mapping_pa_to_va((uintptr_t)alloc_pte_fixmap);
>         pt_ops.get_pte_virt = kernel_mapping_pa_to_va((uintptr_t)get_pte_virt_fixmap);
> @@ -889,7 +889,7 @@ void __init pt_ops_set_fixmap(void)
>   * MMU is enabled and page table setup is complete, so from now, we can use
>   * generic page allocation functions to setup page table.
>   */
> -void __init pt_ops_set_late(void)
> +static void __init pt_ops_set_late(void)
>  {
>         pt_ops.alloc_pte = alloc_pte_late;
>         pt_ops.get_pte_virt = get_pte_virt_late;
> --
> 2.34.1
>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 4/4] riscv: convert pgtable_l4|[l5]_enabled to static key
  2022-05-08 16:07   ` Jisheng Zhang
@ 2022-05-09  3:59     ` Anup Patel
  -1 siblings, 0 replies; 36+ messages in thread
From: Anup Patel @ 2022-05-09  3:59 UTC (permalink / raw)
  To: Jisheng Zhang
  Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Andrey Ryabinin,
	Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
	Vincenzo Frascino, Alexandre Ghiti, linux-riscv,
	linux-kernel@vger.kernel.org List, kasan-dev

On Sun, May 8, 2022 at 9:47 PM Jisheng Zhang <jszhang@kernel.org> wrote:
>
> On a specific HW platform, pgtable_l4|[l5]_enabled won't change after
> boot, and the check sits at hot code path, this characteristic makes it
> suitable for optimization with static key.
>
> Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
> ---
>  arch/riscv/include/asm/cpufeature.h | 11 +++++++
>  arch/riscv/include/asm/pgalloc.h    | 16 +++++-----
>  arch/riscv/include/asm/pgtable-64.h | 40 ++++++++++++-------------
>  arch/riscv/include/asm/pgtable.h    |  5 ++--
>  arch/riscv/kernel/cpu.c             |  4 +--
>  arch/riscv/mm/init.c                | 46 +++++++++++++----------------
>  arch/riscv/mm/kasan_init.c          | 16 +++++-----
>  arch/riscv/tools/cpucaps            |  2 ++
>  8 files changed, 73 insertions(+), 67 deletions(-)
>
> diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
> index 634a653c7fa2..a51f2602a0e3 100644
> --- a/arch/riscv/include/asm/cpufeature.h
> +++ b/arch/riscv/include/asm/cpufeature.h
> @@ -96,4 +96,15 @@ static inline bool system_supports_fpu(void)
>         return IS_ENABLED(CONFIG_FPU) && !cpus_have_final_cap(RISCV_HAS_NO_FPU);
>  }
>
> +static inline bool system_supports_sv48(void)
> +{
> +       return IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_XIP_KERNEL) &&
> +               !cpus_have_const_cap(RISCV_HAS_NO_SV48);
> +}
> +
> +static inline bool system_supports_sv57(void)
> +{
> +       return IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_XIP_KERNEL) &&
> +               !cpus_have_const_cap(RISCV_HAS_NO_SV57);
> +}
>  #endif
> diff --git a/arch/riscv/include/asm/pgalloc.h b/arch/riscv/include/asm/pgalloc.h
> index 947f23d7b6af..f49233ca696a 100644
> --- a/arch/riscv/include/asm/pgalloc.h
> +++ b/arch/riscv/include/asm/pgalloc.h
> @@ -41,7 +41,7 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
>
>  static inline void p4d_populate(struct mm_struct *mm, p4d_t *p4d, pud_t *pud)
>  {
> -       if (pgtable_l4_enabled) {
> +       if (system_supports_sv48()) {
>                 unsigned long pfn = virt_to_pfn(pud);
>
>                 set_p4d(p4d, __p4d((pfn << _PAGE_PFN_SHIFT) | _PAGE_TABLE));
> @@ -51,7 +51,7 @@ static inline void p4d_populate(struct mm_struct *mm, p4d_t *p4d, pud_t *pud)
>  static inline void p4d_populate_safe(struct mm_struct *mm, p4d_t *p4d,
>                                      pud_t *pud)
>  {
> -       if (pgtable_l4_enabled) {
> +       if (system_supports_sv48()) {
>                 unsigned long pfn = virt_to_pfn(pud);
>
>                 set_p4d_safe(p4d,
> @@ -61,7 +61,7 @@ static inline void p4d_populate_safe(struct mm_struct *mm, p4d_t *p4d,
>
>  static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, p4d_t *p4d)
>  {
> -       if (pgtable_l5_enabled) {
> +       if (system_supports_sv57()) {
>                 unsigned long pfn = virt_to_pfn(p4d);
>
>                 set_pgd(pgd, __pgd((pfn << _PAGE_PFN_SHIFT) | _PAGE_TABLE));
> @@ -71,7 +71,7 @@ static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, p4d_t *p4d)
>  static inline void pgd_populate_safe(struct mm_struct *mm, pgd_t *pgd,
>                                      p4d_t *p4d)
>  {
> -       if (pgtable_l5_enabled) {
> +       if (system_supports_sv57()) {
>                 unsigned long pfn = virt_to_pfn(p4d);
>
>                 set_pgd_safe(pgd,
> @@ -82,7 +82,7 @@ static inline void pgd_populate_safe(struct mm_struct *mm, pgd_t *pgd,
>  #define pud_alloc_one pud_alloc_one
>  static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
>  {
> -       if (pgtable_l4_enabled)
> +       if (system_supports_sv48())
>                 return __pud_alloc_one(mm, addr);
>
>         return NULL;
> @@ -91,7 +91,7 @@ static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
>  #define pud_free pud_free
>  static inline void pud_free(struct mm_struct *mm, pud_t *pud)
>  {
> -       if (pgtable_l4_enabled)
> +       if (system_supports_sv48())
>                 __pud_free(mm, pud);
>  }
>
> @@ -100,7 +100,7 @@ static inline void pud_free(struct mm_struct *mm, pud_t *pud)
>  #define p4d_alloc_one p4d_alloc_one
>  static inline p4d_t *p4d_alloc_one(struct mm_struct *mm, unsigned long addr)
>  {
> -       if (pgtable_l5_enabled) {
> +       if (system_supports_sv57()) {
>                 gfp_t gfp = GFP_PGTABLE_USER;
>
>                 if (mm == &init_mm)
> @@ -120,7 +120,7 @@ static inline void __p4d_free(struct mm_struct *mm, p4d_t *p4d)
>  #define p4d_free p4d_free
>  static inline void p4d_free(struct mm_struct *mm, p4d_t *p4d)
>  {
> -       if (pgtable_l5_enabled)
> +       if (system_supports_sv57())
>                 __p4d_free(mm, p4d);
>  }
>
> diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h
> index 7e246e9f8d70..9ee4abf0f528 100644
> --- a/arch/riscv/include/asm/pgtable-64.h
> +++ b/arch/riscv/include/asm/pgtable-64.h
> @@ -7,17 +7,15 @@
>  #define _ASM_RISCV_PGTABLE_64_H
>
>  #include <linux/const.h>
> -
> -extern bool pgtable_l4_enabled;
> -extern bool pgtable_l5_enabled;
> +#include <asm/cpufeature.h>
>
>  #define PGDIR_SHIFT_L3  30
>  #define PGDIR_SHIFT_L4  39
>  #define PGDIR_SHIFT_L5  48
>  #define PGDIR_SIZE_L3   (_AC(1, UL) << PGDIR_SHIFT_L3)
>
> -#define PGDIR_SHIFT     (pgtable_l5_enabled ? PGDIR_SHIFT_L5 : \
> -               (pgtable_l4_enabled ? PGDIR_SHIFT_L4 : PGDIR_SHIFT_L3))
> +#define PGDIR_SHIFT     (system_supports_sv57() ? PGDIR_SHIFT_L5 : \
> +               (system_supports_sv48() ? PGDIR_SHIFT_L4 : PGDIR_SHIFT_L3))
>  /* Size of region mapped by a page global directory */
>  #define PGDIR_SIZE      (_AC(1, UL) << PGDIR_SHIFT)
>  #define PGDIR_MASK      (~(PGDIR_SIZE - 1))
> @@ -119,7 +117,7 @@ static inline struct page *pud_page(pud_t pud)
>  #define mm_p4d_folded  mm_p4d_folded
>  static inline bool mm_p4d_folded(struct mm_struct *mm)
>  {
> -       if (pgtable_l5_enabled)
> +       if (system_supports_sv57())
>                 return false;
>
>         return true;
> @@ -128,7 +126,7 @@ static inline bool mm_p4d_folded(struct mm_struct *mm)
>  #define mm_pud_folded  mm_pud_folded
>  static inline bool mm_pud_folded(struct mm_struct *mm)
>  {
> -       if (pgtable_l4_enabled)
> +       if (system_supports_sv48())
>                 return false;
>
>         return true;
> @@ -159,7 +157,7 @@ static inline unsigned long _pmd_pfn(pmd_t pmd)
>
>  static inline void set_p4d(p4d_t *p4dp, p4d_t p4d)
>  {
> -       if (pgtable_l4_enabled)
> +       if (system_supports_sv48())
>                 *p4dp = p4d;
>         else
>                 set_pud((pud_t *)p4dp, (pud_t){ p4d_val(p4d) });
> @@ -167,7 +165,7 @@ static inline void set_p4d(p4d_t *p4dp, p4d_t p4d)
>
>  static inline int p4d_none(p4d_t p4d)
>  {
> -       if (pgtable_l4_enabled)
> +       if (system_supports_sv48())
>                 return (p4d_val(p4d) == 0);
>
>         return 0;
> @@ -175,7 +173,7 @@ static inline int p4d_none(p4d_t p4d)
>
>  static inline int p4d_present(p4d_t p4d)
>  {
> -       if (pgtable_l4_enabled)
> +       if (system_supports_sv48())
>                 return (p4d_val(p4d) & _PAGE_PRESENT);
>
>         return 1;
> @@ -183,7 +181,7 @@ static inline int p4d_present(p4d_t p4d)
>
>  static inline int p4d_bad(p4d_t p4d)
>  {
> -       if (pgtable_l4_enabled)
> +       if (system_supports_sv48())
>                 return !p4d_present(p4d);
>
>         return 0;
> @@ -191,7 +189,7 @@ static inline int p4d_bad(p4d_t p4d)
>
>  static inline void p4d_clear(p4d_t *p4d)
>  {
> -       if (pgtable_l4_enabled)
> +       if (system_supports_sv48())
>                 set_p4d(p4d, __p4d(0));
>  }
>
> @@ -207,7 +205,7 @@ static inline unsigned long _p4d_pfn(p4d_t p4d)
>
>  static inline pud_t *p4d_pgtable(p4d_t p4d)
>  {
> -       if (pgtable_l4_enabled)
> +       if (system_supports_sv48())
>                 return (pud_t *)pfn_to_virt(p4d_val(p4d) >> _PAGE_PFN_SHIFT);
>
>         return (pud_t *)pud_pgtable((pud_t) { p4d_val(p4d) });
> @@ -224,7 +222,7 @@ static inline struct page *p4d_page(p4d_t p4d)
>  #define pud_offset pud_offset
>  static inline pud_t *pud_offset(p4d_t *p4d, unsigned long address)
>  {
> -       if (pgtable_l4_enabled)
> +       if (system_supports_sv48())
>                 return p4d_pgtable(*p4d) + pud_index(address);
>
>         return (pud_t *)p4d;
> @@ -232,7 +230,7 @@ static inline pud_t *pud_offset(p4d_t *p4d, unsigned long address)
>
>  static inline void set_pgd(pgd_t *pgdp, pgd_t pgd)
>  {
> -       if (pgtable_l5_enabled)
> +       if (system_supports_sv57())
>                 *pgdp = pgd;
>         else
>                 set_p4d((p4d_t *)pgdp, (p4d_t){ pgd_val(pgd) });
> @@ -240,7 +238,7 @@ static inline void set_pgd(pgd_t *pgdp, pgd_t pgd)
>
>  static inline int pgd_none(pgd_t pgd)
>  {
> -       if (pgtable_l5_enabled)
> +       if (system_supports_sv57())
>                 return (pgd_val(pgd) == 0);
>
>         return 0;
> @@ -248,7 +246,7 @@ static inline int pgd_none(pgd_t pgd)
>
>  static inline int pgd_present(pgd_t pgd)
>  {
> -       if (pgtable_l5_enabled)
> +       if (system_supports_sv57())
>                 return (pgd_val(pgd) & _PAGE_PRESENT);
>
>         return 1;
> @@ -256,7 +254,7 @@ static inline int pgd_present(pgd_t pgd)
>
>  static inline int pgd_bad(pgd_t pgd)
>  {
> -       if (pgtable_l5_enabled)
> +       if (system_supports_sv57())
>                 return !pgd_present(pgd);
>
>         return 0;
> @@ -264,13 +262,13 @@ static inline int pgd_bad(pgd_t pgd)
>
>  static inline void pgd_clear(pgd_t *pgd)
>  {
> -       if (pgtable_l5_enabled)
> +       if (system_supports_sv57())
>                 set_pgd(pgd, __pgd(0));
>  }
>
>  static inline p4d_t *pgd_pgtable(pgd_t pgd)
>  {
> -       if (pgtable_l5_enabled)
> +       if (system_supports_sv57())
>                 return (p4d_t *)pfn_to_virt(pgd_val(pgd) >> _PAGE_PFN_SHIFT);
>
>         return (p4d_t *)p4d_pgtable((p4d_t) { pgd_val(pgd) });
> @@ -288,7 +286,7 @@ static inline struct page *pgd_page(pgd_t pgd)
>  #define p4d_offset p4d_offset
>  static inline p4d_t *p4d_offset(pgd_t *pgd, unsigned long address)
>  {
> -       if (pgtable_l5_enabled)
> +       if (system_supports_sv57())
>                 return pgd_pgtable(*pgd) + p4d_index(address);
>
>         return (p4d_t *)pgd;
> diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
> index 046b44225623..ef2a1654100a 100644
> --- a/arch/riscv/include/asm/pgtable.h
> +++ b/arch/riscv/include/asm/pgtable.h
> @@ -63,8 +63,8 @@
>   * position vmemmap directly below the VMALLOC region.
>   */
>  #ifdef CONFIG_64BIT
> -#define VA_BITS                (pgtable_l5_enabled ? \
> -                               57 : (pgtable_l4_enabled ? 48 : 39))
> +#define VA_BITS                (system_supports_sv57() ? \
> +                               57 : (system_supports_sv48() ? 48 : 39))
>  #else
>  #define VA_BITS                32
>  #endif
> @@ -738,7 +738,6 @@ extern uintptr_t _dtb_early_pa;
>  #define dtb_early_pa   _dtb_early_pa
>  #endif /* CONFIG_XIP_KERNEL */
>  extern u64 satp_mode;
> -extern bool pgtable_l4_enabled;
>
>  void paging_init(void);
>  void misc_mem_init(void);
> diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c
> index ccb617791e56..c8f3989b08f3 100644
> --- a/arch/riscv/kernel/cpu.c
> +++ b/arch/riscv/kernel/cpu.c
> @@ -141,9 +141,9 @@ static void print_mmu(struct seq_file *f)
>  #if defined(CONFIG_32BIT)
>         strncpy(sv_type, "sv32", 5);
>  #elif defined(CONFIG_64BIT)
> -       if (pgtable_l5_enabled)
> +       if (system_supports_sv57())
>                 strncpy(sv_type, "sv57", 5);
> -       else if (pgtable_l4_enabled)
> +       else if (system_supports_sv48())
>                 strncpy(sv_type, "sv48", 5);
>         else
>                 strncpy(sv_type, "sv39", 5);
> diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
> index 5f3f26dd9f21..b6a59a5d1a7f 100644
> --- a/arch/riscv/mm/init.c
> +++ b/arch/riscv/mm/init.c
> @@ -21,6 +21,7 @@
>  #include <linux/crash_dump.h>
>  #include <linux/hugetlb.h>
>
> +#include <asm/cpufeature.h>
>  #include <asm/fixmap.h>
>  #include <asm/tlbflush.h>
>  #include <asm/sections.h>
> @@ -44,11 +45,6 @@ u64 satp_mode __ro_after_init = SATP_MODE_32;
>  #endif
>  EXPORT_SYMBOL(satp_mode);
>
> -bool pgtable_l4_enabled = IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_XIP_KERNEL);
> -bool pgtable_l5_enabled = IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_XIP_KERNEL);
> -EXPORT_SYMBOL(pgtable_l4_enabled);
> -EXPORT_SYMBOL(pgtable_l5_enabled);
> -
>  phys_addr_t phys_ram_base __ro_after_init;
>  EXPORT_SYMBOL(phys_ram_base);
>
> @@ -555,26 +551,26 @@ static void __init create_p4d_mapping(p4d_t *p4dp,
>  }
>
>  #define pgd_next_t             p4d_t
> -#define alloc_pgd_next(__va)   (pgtable_l5_enabled ?                   \
> -               pt_ops.alloc_p4d(__va) : (pgtable_l4_enabled ?          \
> +#define alloc_pgd_next(__va)   (system_supports_sv57() ?               \
> +               pt_ops.alloc_p4d(__va) : (system_supports_sv48() ?      \
>                 pt_ops.alloc_pud(__va) : pt_ops.alloc_pmd(__va)))
> -#define get_pgd_next_virt(__pa)        (pgtable_l5_enabled ?                   \
> -               pt_ops.get_p4d_virt(__pa) : (pgd_next_t *)(pgtable_l4_enabled ? \
> +#define get_pgd_next_virt(__pa)        (system_supports_sv57() ?               \
> +               pt_ops.get_p4d_virt(__pa) : (pgd_next_t *)(system_supports_sv48() ?     \
>                 pt_ops.get_pud_virt(__pa) : (pud_t *)pt_ops.get_pmd_virt(__pa)))
>  #define create_pgd_next_mapping(__nextp, __va, __pa, __sz, __prot)     \
> -                               (pgtable_l5_enabled ?                   \
> +                               (system_supports_sv57() ?               \
>                 create_p4d_mapping(__nextp, __va, __pa, __sz, __prot) : \
> -                               (pgtable_l4_enabled ?                   \
> +                               (system_supports_sv48() ?               \
>                 create_pud_mapping((pud_t *)__nextp, __va, __pa, __sz, __prot) :        \
>                 create_pmd_mapping((pmd_t *)__nextp, __va, __pa, __sz, __prot)))
> -#define fixmap_pgd_next                (pgtable_l5_enabled ?                   \
> -               (uintptr_t)fixmap_p4d : (pgtable_l4_enabled ?           \
> +#define fixmap_pgd_next                (system_supports_sv57() ?               \
> +               (uintptr_t)fixmap_p4d : (system_supports_sv48() ?       \
>                 (uintptr_t)fixmap_pud : (uintptr_t)fixmap_pmd))
> -#define trampoline_pgd_next    (pgtable_l5_enabled ?                   \
> -               (uintptr_t)trampoline_p4d : (pgtable_l4_enabled ?       \
> +#define trampoline_pgd_next    (system_supports_sv57() ?               \
> +               (uintptr_t)trampoline_p4d : (system_supports_sv48() ?   \
>                 (uintptr_t)trampoline_pud : (uintptr_t)trampoline_pmd))
> -#define early_dtb_pgd_next     (pgtable_l5_enabled ?                   \
> -               (uintptr_t)early_dtb_p4d : (pgtable_l4_enabled ?        \
> +#define early_dtb_pgd_next     (system_supports_sv57() ?               \
> +               (uintptr_t)early_dtb_p4d : (system_supports_sv48() ?    \
>                 (uintptr_t)early_dtb_pud : (uintptr_t)early_dtb_pmd))
>  #else
>  #define pgd_next_t             pte_t
> @@ -680,14 +676,14 @@ static __init pgprot_t pgprot_from_va(uintptr_t va)
>  #ifdef CONFIG_64BIT
>  static void __init disable_pgtable_l5(void)
>  {
> -       pgtable_l5_enabled = false;
> +       cpus_set_cap(RISCV_HAS_NO_SV57);

Similar to the comments on PATCH2, clear the Sv57 ISA extension here
of setting "No Sv57" capability.

>         kernel_map.page_offset = PAGE_OFFSET_L4;
>         satp_mode = SATP_MODE_48;
>  }
>
>  static void __init disable_pgtable_l4(void)
>  {
> -       pgtable_l4_enabled = false;
> +       cpus_set_cap(RISCV_HAS_NO_SV48);

Same as above.

>         kernel_map.page_offset = PAGE_OFFSET_L3;
>         satp_mode = SATP_MODE_39;
>  }
> @@ -816,11 +812,11 @@ static void __init create_fdt_early_page_table(pgd_t *pgdir, uintptr_t dtb_pa)
>                            PGDIR_SIZE,
>                            IS_ENABLED(CONFIG_64BIT) ? PAGE_TABLE : PAGE_KERNEL);
>
> -       if (pgtable_l5_enabled)
> +       if (system_supports_sv57())
>                 create_p4d_mapping(early_dtb_p4d, DTB_EARLY_BASE_VA,
>                                    (uintptr_t)early_dtb_pud, P4D_SIZE, PAGE_TABLE);
>
> -       if (pgtable_l4_enabled)
> +       if (system_supports_sv48())
>                 create_pud_mapping(early_dtb_pud, DTB_EARLY_BASE_VA,
>                                    (uintptr_t)early_dtb_pmd, PUD_SIZE, PAGE_TABLE);
>
> @@ -961,11 +957,11 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)

At start of setup_vm() for RV64, enable "Sv57" and "Sv48" ISA extensions
which will be cleared by disable_pgtable_l5() or disable_pgtable_l4().

>
>  #ifndef __PAGETABLE_PMD_FOLDED
>         /* Setup fixmap P4D and PUD */
> -       if (pgtable_l5_enabled)
> +       if (system_supports_sv57())
>                 create_p4d_mapping(fixmap_p4d, FIXADDR_START,
>                                    (uintptr_t)fixmap_pud, P4D_SIZE, PAGE_TABLE);
>         /* Setup fixmap PUD and PMD */
> -       if (pgtable_l4_enabled)
> +       if (system_supports_sv48())
>                 create_pud_mapping(fixmap_pud, FIXADDR_START,
>                                    (uintptr_t)fixmap_pmd, PUD_SIZE, PAGE_TABLE);
>         create_pmd_mapping(fixmap_pmd, FIXADDR_START,
> @@ -973,10 +969,10 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
>         /* Setup trampoline PGD and PMD */
>         create_pgd_mapping(trampoline_pg_dir, kernel_map.virt_addr,
>                            trampoline_pgd_next, PGDIR_SIZE, PAGE_TABLE);
> -       if (pgtable_l5_enabled)
> +       if (system_supports_sv57())
>                 create_p4d_mapping(trampoline_p4d, kernel_map.virt_addr,
>                                    (uintptr_t)trampoline_pud, P4D_SIZE, PAGE_TABLE);
> -       if (pgtable_l4_enabled)
> +       if (system_supports_sv48())
>                 create_pud_mapping(trampoline_pud, kernel_map.virt_addr,
>                                    (uintptr_t)trampoline_pmd, PUD_SIZE, PAGE_TABLE);
>  #ifdef CONFIG_XIP_KERNEL
> diff --git a/arch/riscv/mm/kasan_init.c b/arch/riscv/mm/kasan_init.c
> index a22e418dbd82..7b662661f7a9 100644
> --- a/arch/riscv/mm/kasan_init.c
> +++ b/arch/riscv/mm/kasan_init.c
> @@ -209,15 +209,15 @@ static void __init kasan_populate_p4d(pgd_t *pgd,
>                 set_pgd(pgd, pfn_pgd(PFN_DOWN(__pa(base_p4d)), PAGE_TABLE));
>  }
>
> -#define kasan_early_shadow_pgd_next                    (pgtable_l5_enabled ?   \
> +#define kasan_early_shadow_pgd_next            (system_supports_sv57() ?       \
>                                 (uintptr_t)kasan_early_shadow_p4d :             \
> -                                                       (pgtable_l4_enabled ?   \
> +                                               (system_supports_sv48() ?       \
>                                 (uintptr_t)kasan_early_shadow_pud :             \
>                                 (uintptr_t)kasan_early_shadow_pmd))
>  #define kasan_populate_pgd_next(pgdp, vaddr, next, early)                      \
> -               (pgtable_l5_enabled ?                                           \
> +               (system_supports_sv57() ?                                       \
>                 kasan_populate_p4d(pgdp, vaddr, next, early) :                  \
> -               (pgtable_l4_enabled ?                                           \
> +               (system_supports_sv48() ?                                       \
>                         kasan_populate_pud(pgdp, vaddr, next, early) :          \
>                         kasan_populate_pmd((pud_t *)pgdp, vaddr, next)))
>
> @@ -274,7 +274,7 @@ asmlinkage void __init kasan_early_init(void)
>                                 (__pa((uintptr_t)kasan_early_shadow_pte)),
>                                 PAGE_TABLE));
>
> -       if (pgtable_l4_enabled) {
> +       if (system_supports_sv48()) {
>                 for (i = 0; i < PTRS_PER_PUD; ++i)
>                         set_pud(kasan_early_shadow_pud + i,
>                                 pfn_pud(PFN_DOWN
> @@ -282,7 +282,7 @@ asmlinkage void __init kasan_early_init(void)
>                                         PAGE_TABLE));
>         }
>
> -       if (pgtable_l5_enabled) {
> +       if (system_supports_sv57()) {
>                 for (i = 0; i < PTRS_PER_P4D; ++i)
>                         set_p4d(kasan_early_shadow_p4d + i,
>                                 pfn_p4d(PFN_DOWN
> @@ -393,9 +393,9 @@ static void __init kasan_shallow_populate_p4d(pgd_t *pgdp,
>  }
>
>  #define kasan_shallow_populate_pgd_next(pgdp, vaddr, next)                     \
> -               (pgtable_l5_enabled ?                                           \
> +               (system_supports_sv57() ?                                       \
>                 kasan_shallow_populate_p4d(pgdp, vaddr, next) :                 \
> -               (pgtable_l4_enabled ?                                           \
> +               (system_supports_sv48() ?                                       \
>                 kasan_shallow_populate_pud(pgdp, vaddr, next) :                 \
>                 kasan_shallow_populate_pmd(pgdp, vaddr, next)))
>
> diff --git a/arch/riscv/tools/cpucaps b/arch/riscv/tools/cpucaps
> index cb1ff2747859..0b9e19ec8371 100644
> --- a/arch/riscv/tools/cpucaps
> +++ b/arch/riscv/tools/cpucaps
> @@ -3,3 +3,5 @@
>  # Internal CPU capabilities constants, keep this list sorted
>
>  HAS_NO_FPU
> +HAS_NO_SV48
> +HAS_NO_SV57
> --
> 2.34.1
>

Regards,
Anup

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

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 4/4] riscv: convert pgtable_l4|[l5]_enabled to static key
@ 2022-05-09  3:59     ` Anup Patel
  0 siblings, 0 replies; 36+ messages in thread
From: Anup Patel @ 2022-05-09  3:59 UTC (permalink / raw)
  To: Jisheng Zhang
  Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Andrey Ryabinin,
	Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
	Vincenzo Frascino, Alexandre Ghiti, linux-riscv,
	linux-kernel@vger.kernel.org List, kasan-dev

On Sun, May 8, 2022 at 9:47 PM Jisheng Zhang <jszhang@kernel.org> wrote:
>
> On a specific HW platform, pgtable_l4|[l5]_enabled won't change after
> boot, and the check sits at hot code path, this characteristic makes it
> suitable for optimization with static key.
>
> Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
> ---
>  arch/riscv/include/asm/cpufeature.h | 11 +++++++
>  arch/riscv/include/asm/pgalloc.h    | 16 +++++-----
>  arch/riscv/include/asm/pgtable-64.h | 40 ++++++++++++-------------
>  arch/riscv/include/asm/pgtable.h    |  5 ++--
>  arch/riscv/kernel/cpu.c             |  4 +--
>  arch/riscv/mm/init.c                | 46 +++++++++++++----------------
>  arch/riscv/mm/kasan_init.c          | 16 +++++-----
>  arch/riscv/tools/cpucaps            |  2 ++
>  8 files changed, 73 insertions(+), 67 deletions(-)
>
> diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
> index 634a653c7fa2..a51f2602a0e3 100644
> --- a/arch/riscv/include/asm/cpufeature.h
> +++ b/arch/riscv/include/asm/cpufeature.h
> @@ -96,4 +96,15 @@ static inline bool system_supports_fpu(void)
>         return IS_ENABLED(CONFIG_FPU) && !cpus_have_final_cap(RISCV_HAS_NO_FPU);
>  }
>
> +static inline bool system_supports_sv48(void)
> +{
> +       return IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_XIP_KERNEL) &&
> +               !cpus_have_const_cap(RISCV_HAS_NO_SV48);
> +}
> +
> +static inline bool system_supports_sv57(void)
> +{
> +       return IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_XIP_KERNEL) &&
> +               !cpus_have_const_cap(RISCV_HAS_NO_SV57);
> +}
>  #endif
> diff --git a/arch/riscv/include/asm/pgalloc.h b/arch/riscv/include/asm/pgalloc.h
> index 947f23d7b6af..f49233ca696a 100644
> --- a/arch/riscv/include/asm/pgalloc.h
> +++ b/arch/riscv/include/asm/pgalloc.h
> @@ -41,7 +41,7 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
>
>  static inline void p4d_populate(struct mm_struct *mm, p4d_t *p4d, pud_t *pud)
>  {
> -       if (pgtable_l4_enabled) {
> +       if (system_supports_sv48()) {
>                 unsigned long pfn = virt_to_pfn(pud);
>
>                 set_p4d(p4d, __p4d((pfn << _PAGE_PFN_SHIFT) | _PAGE_TABLE));
> @@ -51,7 +51,7 @@ static inline void p4d_populate(struct mm_struct *mm, p4d_t *p4d, pud_t *pud)
>  static inline void p4d_populate_safe(struct mm_struct *mm, p4d_t *p4d,
>                                      pud_t *pud)
>  {
> -       if (pgtable_l4_enabled) {
> +       if (system_supports_sv48()) {
>                 unsigned long pfn = virt_to_pfn(pud);
>
>                 set_p4d_safe(p4d,
> @@ -61,7 +61,7 @@ static inline void p4d_populate_safe(struct mm_struct *mm, p4d_t *p4d,
>
>  static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, p4d_t *p4d)
>  {
> -       if (pgtable_l5_enabled) {
> +       if (system_supports_sv57()) {
>                 unsigned long pfn = virt_to_pfn(p4d);
>
>                 set_pgd(pgd, __pgd((pfn << _PAGE_PFN_SHIFT) | _PAGE_TABLE));
> @@ -71,7 +71,7 @@ static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, p4d_t *p4d)
>  static inline void pgd_populate_safe(struct mm_struct *mm, pgd_t *pgd,
>                                      p4d_t *p4d)
>  {
> -       if (pgtable_l5_enabled) {
> +       if (system_supports_sv57()) {
>                 unsigned long pfn = virt_to_pfn(p4d);
>
>                 set_pgd_safe(pgd,
> @@ -82,7 +82,7 @@ static inline void pgd_populate_safe(struct mm_struct *mm, pgd_t *pgd,
>  #define pud_alloc_one pud_alloc_one
>  static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
>  {
> -       if (pgtable_l4_enabled)
> +       if (system_supports_sv48())
>                 return __pud_alloc_one(mm, addr);
>
>         return NULL;
> @@ -91,7 +91,7 @@ static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
>  #define pud_free pud_free
>  static inline void pud_free(struct mm_struct *mm, pud_t *pud)
>  {
> -       if (pgtable_l4_enabled)
> +       if (system_supports_sv48())
>                 __pud_free(mm, pud);
>  }
>
> @@ -100,7 +100,7 @@ static inline void pud_free(struct mm_struct *mm, pud_t *pud)
>  #define p4d_alloc_one p4d_alloc_one
>  static inline p4d_t *p4d_alloc_one(struct mm_struct *mm, unsigned long addr)
>  {
> -       if (pgtable_l5_enabled) {
> +       if (system_supports_sv57()) {
>                 gfp_t gfp = GFP_PGTABLE_USER;
>
>                 if (mm == &init_mm)
> @@ -120,7 +120,7 @@ static inline void __p4d_free(struct mm_struct *mm, p4d_t *p4d)
>  #define p4d_free p4d_free
>  static inline void p4d_free(struct mm_struct *mm, p4d_t *p4d)
>  {
> -       if (pgtable_l5_enabled)
> +       if (system_supports_sv57())
>                 __p4d_free(mm, p4d);
>  }
>
> diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h
> index 7e246e9f8d70..9ee4abf0f528 100644
> --- a/arch/riscv/include/asm/pgtable-64.h
> +++ b/arch/riscv/include/asm/pgtable-64.h
> @@ -7,17 +7,15 @@
>  #define _ASM_RISCV_PGTABLE_64_H
>
>  #include <linux/const.h>
> -
> -extern bool pgtable_l4_enabled;
> -extern bool pgtable_l5_enabled;
> +#include <asm/cpufeature.h>
>
>  #define PGDIR_SHIFT_L3  30
>  #define PGDIR_SHIFT_L4  39
>  #define PGDIR_SHIFT_L5  48
>  #define PGDIR_SIZE_L3   (_AC(1, UL) << PGDIR_SHIFT_L3)
>
> -#define PGDIR_SHIFT     (pgtable_l5_enabled ? PGDIR_SHIFT_L5 : \
> -               (pgtable_l4_enabled ? PGDIR_SHIFT_L4 : PGDIR_SHIFT_L3))
> +#define PGDIR_SHIFT     (system_supports_sv57() ? PGDIR_SHIFT_L5 : \
> +               (system_supports_sv48() ? PGDIR_SHIFT_L4 : PGDIR_SHIFT_L3))
>  /* Size of region mapped by a page global directory */
>  #define PGDIR_SIZE      (_AC(1, UL) << PGDIR_SHIFT)
>  #define PGDIR_MASK      (~(PGDIR_SIZE - 1))
> @@ -119,7 +117,7 @@ static inline struct page *pud_page(pud_t pud)
>  #define mm_p4d_folded  mm_p4d_folded
>  static inline bool mm_p4d_folded(struct mm_struct *mm)
>  {
> -       if (pgtable_l5_enabled)
> +       if (system_supports_sv57())
>                 return false;
>
>         return true;
> @@ -128,7 +126,7 @@ static inline bool mm_p4d_folded(struct mm_struct *mm)
>  #define mm_pud_folded  mm_pud_folded
>  static inline bool mm_pud_folded(struct mm_struct *mm)
>  {
> -       if (pgtable_l4_enabled)
> +       if (system_supports_sv48())
>                 return false;
>
>         return true;
> @@ -159,7 +157,7 @@ static inline unsigned long _pmd_pfn(pmd_t pmd)
>
>  static inline void set_p4d(p4d_t *p4dp, p4d_t p4d)
>  {
> -       if (pgtable_l4_enabled)
> +       if (system_supports_sv48())
>                 *p4dp = p4d;
>         else
>                 set_pud((pud_t *)p4dp, (pud_t){ p4d_val(p4d) });
> @@ -167,7 +165,7 @@ static inline void set_p4d(p4d_t *p4dp, p4d_t p4d)
>
>  static inline int p4d_none(p4d_t p4d)
>  {
> -       if (pgtable_l4_enabled)
> +       if (system_supports_sv48())
>                 return (p4d_val(p4d) == 0);
>
>         return 0;
> @@ -175,7 +173,7 @@ static inline int p4d_none(p4d_t p4d)
>
>  static inline int p4d_present(p4d_t p4d)
>  {
> -       if (pgtable_l4_enabled)
> +       if (system_supports_sv48())
>                 return (p4d_val(p4d) & _PAGE_PRESENT);
>
>         return 1;
> @@ -183,7 +181,7 @@ static inline int p4d_present(p4d_t p4d)
>
>  static inline int p4d_bad(p4d_t p4d)
>  {
> -       if (pgtable_l4_enabled)
> +       if (system_supports_sv48())
>                 return !p4d_present(p4d);
>
>         return 0;
> @@ -191,7 +189,7 @@ static inline int p4d_bad(p4d_t p4d)
>
>  static inline void p4d_clear(p4d_t *p4d)
>  {
> -       if (pgtable_l4_enabled)
> +       if (system_supports_sv48())
>                 set_p4d(p4d, __p4d(0));
>  }
>
> @@ -207,7 +205,7 @@ static inline unsigned long _p4d_pfn(p4d_t p4d)
>
>  static inline pud_t *p4d_pgtable(p4d_t p4d)
>  {
> -       if (pgtable_l4_enabled)
> +       if (system_supports_sv48())
>                 return (pud_t *)pfn_to_virt(p4d_val(p4d) >> _PAGE_PFN_SHIFT);
>
>         return (pud_t *)pud_pgtable((pud_t) { p4d_val(p4d) });
> @@ -224,7 +222,7 @@ static inline struct page *p4d_page(p4d_t p4d)
>  #define pud_offset pud_offset
>  static inline pud_t *pud_offset(p4d_t *p4d, unsigned long address)
>  {
> -       if (pgtable_l4_enabled)
> +       if (system_supports_sv48())
>                 return p4d_pgtable(*p4d) + pud_index(address);
>
>         return (pud_t *)p4d;
> @@ -232,7 +230,7 @@ static inline pud_t *pud_offset(p4d_t *p4d, unsigned long address)
>
>  static inline void set_pgd(pgd_t *pgdp, pgd_t pgd)
>  {
> -       if (pgtable_l5_enabled)
> +       if (system_supports_sv57())
>                 *pgdp = pgd;
>         else
>                 set_p4d((p4d_t *)pgdp, (p4d_t){ pgd_val(pgd) });
> @@ -240,7 +238,7 @@ static inline void set_pgd(pgd_t *pgdp, pgd_t pgd)
>
>  static inline int pgd_none(pgd_t pgd)
>  {
> -       if (pgtable_l5_enabled)
> +       if (system_supports_sv57())
>                 return (pgd_val(pgd) == 0);
>
>         return 0;
> @@ -248,7 +246,7 @@ static inline int pgd_none(pgd_t pgd)
>
>  static inline int pgd_present(pgd_t pgd)
>  {
> -       if (pgtable_l5_enabled)
> +       if (system_supports_sv57())
>                 return (pgd_val(pgd) & _PAGE_PRESENT);
>
>         return 1;
> @@ -256,7 +254,7 @@ static inline int pgd_present(pgd_t pgd)
>
>  static inline int pgd_bad(pgd_t pgd)
>  {
> -       if (pgtable_l5_enabled)
> +       if (system_supports_sv57())
>                 return !pgd_present(pgd);
>
>         return 0;
> @@ -264,13 +262,13 @@ static inline int pgd_bad(pgd_t pgd)
>
>  static inline void pgd_clear(pgd_t *pgd)
>  {
> -       if (pgtable_l5_enabled)
> +       if (system_supports_sv57())
>                 set_pgd(pgd, __pgd(0));
>  }
>
>  static inline p4d_t *pgd_pgtable(pgd_t pgd)
>  {
> -       if (pgtable_l5_enabled)
> +       if (system_supports_sv57())
>                 return (p4d_t *)pfn_to_virt(pgd_val(pgd) >> _PAGE_PFN_SHIFT);
>
>         return (p4d_t *)p4d_pgtable((p4d_t) { pgd_val(pgd) });
> @@ -288,7 +286,7 @@ static inline struct page *pgd_page(pgd_t pgd)
>  #define p4d_offset p4d_offset
>  static inline p4d_t *p4d_offset(pgd_t *pgd, unsigned long address)
>  {
> -       if (pgtable_l5_enabled)
> +       if (system_supports_sv57())
>                 return pgd_pgtable(*pgd) + p4d_index(address);
>
>         return (p4d_t *)pgd;
> diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
> index 046b44225623..ef2a1654100a 100644
> --- a/arch/riscv/include/asm/pgtable.h
> +++ b/arch/riscv/include/asm/pgtable.h
> @@ -63,8 +63,8 @@
>   * position vmemmap directly below the VMALLOC region.
>   */
>  #ifdef CONFIG_64BIT
> -#define VA_BITS                (pgtable_l5_enabled ? \
> -                               57 : (pgtable_l4_enabled ? 48 : 39))
> +#define VA_BITS                (system_supports_sv57() ? \
> +                               57 : (system_supports_sv48() ? 48 : 39))
>  #else
>  #define VA_BITS                32
>  #endif
> @@ -738,7 +738,6 @@ extern uintptr_t _dtb_early_pa;
>  #define dtb_early_pa   _dtb_early_pa
>  #endif /* CONFIG_XIP_KERNEL */
>  extern u64 satp_mode;
> -extern bool pgtable_l4_enabled;
>
>  void paging_init(void);
>  void misc_mem_init(void);
> diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c
> index ccb617791e56..c8f3989b08f3 100644
> --- a/arch/riscv/kernel/cpu.c
> +++ b/arch/riscv/kernel/cpu.c
> @@ -141,9 +141,9 @@ static void print_mmu(struct seq_file *f)
>  #if defined(CONFIG_32BIT)
>         strncpy(sv_type, "sv32", 5);
>  #elif defined(CONFIG_64BIT)
> -       if (pgtable_l5_enabled)
> +       if (system_supports_sv57())
>                 strncpy(sv_type, "sv57", 5);
> -       else if (pgtable_l4_enabled)
> +       else if (system_supports_sv48())
>                 strncpy(sv_type, "sv48", 5);
>         else
>                 strncpy(sv_type, "sv39", 5);
> diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
> index 5f3f26dd9f21..b6a59a5d1a7f 100644
> --- a/arch/riscv/mm/init.c
> +++ b/arch/riscv/mm/init.c
> @@ -21,6 +21,7 @@
>  #include <linux/crash_dump.h>
>  #include <linux/hugetlb.h>
>
> +#include <asm/cpufeature.h>
>  #include <asm/fixmap.h>
>  #include <asm/tlbflush.h>
>  #include <asm/sections.h>
> @@ -44,11 +45,6 @@ u64 satp_mode __ro_after_init = SATP_MODE_32;
>  #endif
>  EXPORT_SYMBOL(satp_mode);
>
> -bool pgtable_l4_enabled = IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_XIP_KERNEL);
> -bool pgtable_l5_enabled = IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_XIP_KERNEL);
> -EXPORT_SYMBOL(pgtable_l4_enabled);
> -EXPORT_SYMBOL(pgtable_l5_enabled);
> -
>  phys_addr_t phys_ram_base __ro_after_init;
>  EXPORT_SYMBOL(phys_ram_base);
>
> @@ -555,26 +551,26 @@ static void __init create_p4d_mapping(p4d_t *p4dp,
>  }
>
>  #define pgd_next_t             p4d_t
> -#define alloc_pgd_next(__va)   (pgtable_l5_enabled ?                   \
> -               pt_ops.alloc_p4d(__va) : (pgtable_l4_enabled ?          \
> +#define alloc_pgd_next(__va)   (system_supports_sv57() ?               \
> +               pt_ops.alloc_p4d(__va) : (system_supports_sv48() ?      \
>                 pt_ops.alloc_pud(__va) : pt_ops.alloc_pmd(__va)))
> -#define get_pgd_next_virt(__pa)        (pgtable_l5_enabled ?                   \
> -               pt_ops.get_p4d_virt(__pa) : (pgd_next_t *)(pgtable_l4_enabled ? \
> +#define get_pgd_next_virt(__pa)        (system_supports_sv57() ?               \
> +               pt_ops.get_p4d_virt(__pa) : (pgd_next_t *)(system_supports_sv48() ?     \
>                 pt_ops.get_pud_virt(__pa) : (pud_t *)pt_ops.get_pmd_virt(__pa)))
>  #define create_pgd_next_mapping(__nextp, __va, __pa, __sz, __prot)     \
> -                               (pgtable_l5_enabled ?                   \
> +                               (system_supports_sv57() ?               \
>                 create_p4d_mapping(__nextp, __va, __pa, __sz, __prot) : \
> -                               (pgtable_l4_enabled ?                   \
> +                               (system_supports_sv48() ?               \
>                 create_pud_mapping((pud_t *)__nextp, __va, __pa, __sz, __prot) :        \
>                 create_pmd_mapping((pmd_t *)__nextp, __va, __pa, __sz, __prot)))
> -#define fixmap_pgd_next                (pgtable_l5_enabled ?                   \
> -               (uintptr_t)fixmap_p4d : (pgtable_l4_enabled ?           \
> +#define fixmap_pgd_next                (system_supports_sv57() ?               \
> +               (uintptr_t)fixmap_p4d : (system_supports_sv48() ?       \
>                 (uintptr_t)fixmap_pud : (uintptr_t)fixmap_pmd))
> -#define trampoline_pgd_next    (pgtable_l5_enabled ?                   \
> -               (uintptr_t)trampoline_p4d : (pgtable_l4_enabled ?       \
> +#define trampoline_pgd_next    (system_supports_sv57() ?               \
> +               (uintptr_t)trampoline_p4d : (system_supports_sv48() ?   \
>                 (uintptr_t)trampoline_pud : (uintptr_t)trampoline_pmd))
> -#define early_dtb_pgd_next     (pgtable_l5_enabled ?                   \
> -               (uintptr_t)early_dtb_p4d : (pgtable_l4_enabled ?        \
> +#define early_dtb_pgd_next     (system_supports_sv57() ?               \
> +               (uintptr_t)early_dtb_p4d : (system_supports_sv48() ?    \
>                 (uintptr_t)early_dtb_pud : (uintptr_t)early_dtb_pmd))
>  #else
>  #define pgd_next_t             pte_t
> @@ -680,14 +676,14 @@ static __init pgprot_t pgprot_from_va(uintptr_t va)
>  #ifdef CONFIG_64BIT
>  static void __init disable_pgtable_l5(void)
>  {
> -       pgtable_l5_enabled = false;
> +       cpus_set_cap(RISCV_HAS_NO_SV57);

Similar to the comments on PATCH2, clear the Sv57 ISA extension here
of setting "No Sv57" capability.

>         kernel_map.page_offset = PAGE_OFFSET_L4;
>         satp_mode = SATP_MODE_48;
>  }
>
>  static void __init disable_pgtable_l4(void)
>  {
> -       pgtable_l4_enabled = false;
> +       cpus_set_cap(RISCV_HAS_NO_SV48);

Same as above.

>         kernel_map.page_offset = PAGE_OFFSET_L3;
>         satp_mode = SATP_MODE_39;
>  }
> @@ -816,11 +812,11 @@ static void __init create_fdt_early_page_table(pgd_t *pgdir, uintptr_t dtb_pa)
>                            PGDIR_SIZE,
>                            IS_ENABLED(CONFIG_64BIT) ? PAGE_TABLE : PAGE_KERNEL);
>
> -       if (pgtable_l5_enabled)
> +       if (system_supports_sv57())
>                 create_p4d_mapping(early_dtb_p4d, DTB_EARLY_BASE_VA,
>                                    (uintptr_t)early_dtb_pud, P4D_SIZE, PAGE_TABLE);
>
> -       if (pgtable_l4_enabled)
> +       if (system_supports_sv48())
>                 create_pud_mapping(early_dtb_pud, DTB_EARLY_BASE_VA,
>                                    (uintptr_t)early_dtb_pmd, PUD_SIZE, PAGE_TABLE);
>
> @@ -961,11 +957,11 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)

At start of setup_vm() for RV64, enable "Sv57" and "Sv48" ISA extensions
which will be cleared by disable_pgtable_l5() or disable_pgtable_l4().

>
>  #ifndef __PAGETABLE_PMD_FOLDED
>         /* Setup fixmap P4D and PUD */
> -       if (pgtable_l5_enabled)
> +       if (system_supports_sv57())
>                 create_p4d_mapping(fixmap_p4d, FIXADDR_START,
>                                    (uintptr_t)fixmap_pud, P4D_SIZE, PAGE_TABLE);
>         /* Setup fixmap PUD and PMD */
> -       if (pgtable_l4_enabled)
> +       if (system_supports_sv48())
>                 create_pud_mapping(fixmap_pud, FIXADDR_START,
>                                    (uintptr_t)fixmap_pmd, PUD_SIZE, PAGE_TABLE);
>         create_pmd_mapping(fixmap_pmd, FIXADDR_START,
> @@ -973,10 +969,10 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
>         /* Setup trampoline PGD and PMD */
>         create_pgd_mapping(trampoline_pg_dir, kernel_map.virt_addr,
>                            trampoline_pgd_next, PGDIR_SIZE, PAGE_TABLE);
> -       if (pgtable_l5_enabled)
> +       if (system_supports_sv57())
>                 create_p4d_mapping(trampoline_p4d, kernel_map.virt_addr,
>                                    (uintptr_t)trampoline_pud, P4D_SIZE, PAGE_TABLE);
> -       if (pgtable_l4_enabled)
> +       if (system_supports_sv48())
>                 create_pud_mapping(trampoline_pud, kernel_map.virt_addr,
>                                    (uintptr_t)trampoline_pmd, PUD_SIZE, PAGE_TABLE);
>  #ifdef CONFIG_XIP_KERNEL
> diff --git a/arch/riscv/mm/kasan_init.c b/arch/riscv/mm/kasan_init.c
> index a22e418dbd82..7b662661f7a9 100644
> --- a/arch/riscv/mm/kasan_init.c
> +++ b/arch/riscv/mm/kasan_init.c
> @@ -209,15 +209,15 @@ static void __init kasan_populate_p4d(pgd_t *pgd,
>                 set_pgd(pgd, pfn_pgd(PFN_DOWN(__pa(base_p4d)), PAGE_TABLE));
>  }
>
> -#define kasan_early_shadow_pgd_next                    (pgtable_l5_enabled ?   \
> +#define kasan_early_shadow_pgd_next            (system_supports_sv57() ?       \
>                                 (uintptr_t)kasan_early_shadow_p4d :             \
> -                                                       (pgtable_l4_enabled ?   \
> +                                               (system_supports_sv48() ?       \
>                                 (uintptr_t)kasan_early_shadow_pud :             \
>                                 (uintptr_t)kasan_early_shadow_pmd))
>  #define kasan_populate_pgd_next(pgdp, vaddr, next, early)                      \
> -               (pgtable_l5_enabled ?                                           \
> +               (system_supports_sv57() ?                                       \
>                 kasan_populate_p4d(pgdp, vaddr, next, early) :                  \
> -               (pgtable_l4_enabled ?                                           \
> +               (system_supports_sv48() ?                                       \
>                         kasan_populate_pud(pgdp, vaddr, next, early) :          \
>                         kasan_populate_pmd((pud_t *)pgdp, vaddr, next)))
>
> @@ -274,7 +274,7 @@ asmlinkage void __init kasan_early_init(void)
>                                 (__pa((uintptr_t)kasan_early_shadow_pte)),
>                                 PAGE_TABLE));
>
> -       if (pgtable_l4_enabled) {
> +       if (system_supports_sv48()) {
>                 for (i = 0; i < PTRS_PER_PUD; ++i)
>                         set_pud(kasan_early_shadow_pud + i,
>                                 pfn_pud(PFN_DOWN
> @@ -282,7 +282,7 @@ asmlinkage void __init kasan_early_init(void)
>                                         PAGE_TABLE));
>         }
>
> -       if (pgtable_l5_enabled) {
> +       if (system_supports_sv57()) {
>                 for (i = 0; i < PTRS_PER_P4D; ++i)
>                         set_p4d(kasan_early_shadow_p4d + i,
>                                 pfn_p4d(PFN_DOWN
> @@ -393,9 +393,9 @@ static void __init kasan_shallow_populate_p4d(pgd_t *pgdp,
>  }
>
>  #define kasan_shallow_populate_pgd_next(pgdp, vaddr, next)                     \
> -               (pgtable_l5_enabled ?                                           \
> +               (system_supports_sv57() ?                                       \
>                 kasan_shallow_populate_p4d(pgdp, vaddr, next) :                 \
> -               (pgtable_l4_enabled ?                                           \
> +               (system_supports_sv48() ?                                       \
>                 kasan_shallow_populate_pud(pgdp, vaddr, next) :                 \
>                 kasan_shallow_populate_pmd(pgdp, vaddr, next)))
>
> diff --git a/arch/riscv/tools/cpucaps b/arch/riscv/tools/cpucaps
> index cb1ff2747859..0b9e19ec8371 100644
> --- a/arch/riscv/tools/cpucaps
> +++ b/arch/riscv/tools/cpucaps
> @@ -3,3 +3,5 @@
>  # Internal CPU capabilities constants, keep this list sorted
>
>  HAS_NO_FPU
> +HAS_NO_SV48
> +HAS_NO_SV57
> --
> 2.34.1
>

Regards,
Anup

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 3/4] riscv: replace has_fpu() with system_supports_fpu()
  2022-05-08 16:07   ` Jisheng Zhang
@ 2022-05-09  4:01     ` Anup Patel
  -1 siblings, 0 replies; 36+ messages in thread
From: Anup Patel @ 2022-05-09  4:01 UTC (permalink / raw)
  To: Jisheng Zhang
  Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Andrey Ryabinin,
	Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
	Vincenzo Frascino, Alexandre Ghiti, linux-riscv,
	linux-kernel@vger.kernel.org List, kasan-dev

On Sun, May 8, 2022 at 9:46 PM Jisheng Zhang <jszhang@kernel.org> wrote:
>
> This is to use the unified cpus_have_{final|const}_cap() instead of
> putting static key related here and there.
>
> Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
> ---
>  arch/riscv/include/asm/cpufeature.h | 5 +++++
>  arch/riscv/include/asm/switch_to.h  | 9 ++-------
>  arch/riscv/kernel/cpufeature.c      | 8 ++------
>  arch/riscv/kernel/process.c         | 2 +-
>  arch/riscv/kernel/signal.c          | 4 ++--
>  5 files changed, 12 insertions(+), 16 deletions(-)
>
> diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
> index d80ddd2f3b49..634a653c7fa2 100644
> --- a/arch/riscv/include/asm/cpufeature.h
> +++ b/arch/riscv/include/asm/cpufeature.h
> @@ -91,4 +91,9 @@ static inline void cpus_set_cap(unsigned int num)
>         }
>  }
>
> +static inline bool system_supports_fpu(void)
> +{
> +       return IS_ENABLED(CONFIG_FPU) && !cpus_have_final_cap(RISCV_HAS_NO_FPU);

This should be checking for "f" and "d" ISA extensions since "FPU" is
not an ISA extension name.

> +}
> +
>  #endif
> diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h
> index 0a3f4f95c555..362cb18d12d5 100644
> --- a/arch/riscv/include/asm/switch_to.h
> +++ b/arch/riscv/include/asm/switch_to.h
> @@ -8,6 +8,7 @@
>
>  #include <linux/jump_label.h>
>  #include <linux/sched/task_stack.h>
> +#include <asm/cpufeature.h>
>  #include <asm/processor.h>
>  #include <asm/ptrace.h>
>  #include <asm/csr.h>
> @@ -56,13 +57,7 @@ static inline void __switch_to_aux(struct task_struct *prev,
>         fstate_restore(next, task_pt_regs(next));
>  }
>
> -extern struct static_key_false cpu_hwcap_fpu;
> -static __always_inline bool has_fpu(void)
> -{
> -       return static_branch_likely(&cpu_hwcap_fpu);
> -}
>  #else
> -static __always_inline bool has_fpu(void) { return false; }
>  #define fstate_save(task, regs) do { } while (0)
>  #define fstate_restore(task, regs) do { } while (0)
>  #define __switch_to_aux(__prev, __next) do { } while (0)
> @@ -75,7 +70,7 @@ extern struct task_struct *__switch_to(struct task_struct *,
>  do {                                                   \
>         struct task_struct *__prev = (prev);            \
>         struct task_struct *__next = (next);            \
> -       if (has_fpu())                                  \
> +       if (system_supports_fpu())                                      \
>                 __switch_to_aux(__prev, __next);        \
>         ((last) = __switch_to(__prev, __next));         \
>  } while (0)
> diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> index e6c72cad0c1c..1edf3c3f8f62 100644
> --- a/arch/riscv/kernel/cpufeature.c
> +++ b/arch/riscv/kernel/cpufeature.c
> @@ -22,10 +22,6 @@ unsigned long elf_hwcap __read_mostly;
>  /* Host ISA bitmap */
>  static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
>
> -#ifdef CONFIG_FPU
> -__ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_fpu);
> -#endif
> -
>  DECLARE_BITMAP(cpu_hwcaps, RISCV_NCAPS);
>  EXPORT_SYMBOL(cpu_hwcaps);
>
> @@ -254,8 +250,8 @@ void __init riscv_fill_hwcap(void)
>         pr_info("riscv: ELF capabilities %s\n", print_str);
>
>  #ifdef CONFIG_FPU
> -       if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D))
> -               static_branch_enable(&cpu_hwcap_fpu);
> +       if (!(elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D)))
> +               cpus_set_cap(RISCV_HAS_NO_FPU);
>  #endif
>         enable_cpu_capabilities();
>         static_branch_enable(&riscv_const_caps_ready);
> diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c
> index 504b496787aa..c9cd0b42299e 100644
> --- a/arch/riscv/kernel/process.c
> +++ b/arch/riscv/kernel/process.c
> @@ -88,7 +88,7 @@ void start_thread(struct pt_regs *regs, unsigned long pc,
>         unsigned long sp)
>  {
>         regs->status = SR_PIE;
> -       if (has_fpu()) {
> +       if (system_supports_fpu()) {
>                 regs->status |= SR_FS_INITIAL;
>                 /*
>                  * Restore the initial value to the FP register
> diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c
> index 9f4e59f80551..96aa593a989e 100644
> --- a/arch/riscv/kernel/signal.c
> +++ b/arch/riscv/kernel/signal.c
> @@ -90,7 +90,7 @@ static long restore_sigcontext(struct pt_regs *regs,
>         /* sc_regs is structured the same as the start of pt_regs */
>         err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs));
>         /* Restore the floating-point state. */
> -       if (has_fpu())
> +       if (system_supports_fpu())
>                 err |= restore_fp_state(regs, &sc->sc_fpregs);
>         return err;
>  }
> @@ -143,7 +143,7 @@ static long setup_sigcontext(struct rt_sigframe __user *frame,
>         /* sc_regs is structured the same as the start of pt_regs */
>         err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs));
>         /* Save the floating-point state. */
> -       if (has_fpu())
> +       if (system_supports_fpu())
>                 err |= save_fp_state(regs, &sc->sc_fpregs);
>         return err;
>  }
> --
> 2.34.1
>
>
> _______________________________________________
> linux-riscv mailing list
> linux-riscv@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv

Regards,
Anup

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

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 3/4] riscv: replace has_fpu() with system_supports_fpu()
@ 2022-05-09  4:01     ` Anup Patel
  0 siblings, 0 replies; 36+ messages in thread
From: Anup Patel @ 2022-05-09  4:01 UTC (permalink / raw)
  To: Jisheng Zhang
  Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Andrey Ryabinin,
	Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
	Vincenzo Frascino, Alexandre Ghiti, linux-riscv,
	linux-kernel@vger.kernel.org List, kasan-dev

On Sun, May 8, 2022 at 9:46 PM Jisheng Zhang <jszhang@kernel.org> wrote:
>
> This is to use the unified cpus_have_{final|const}_cap() instead of
> putting static key related here and there.
>
> Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
> ---
>  arch/riscv/include/asm/cpufeature.h | 5 +++++
>  arch/riscv/include/asm/switch_to.h  | 9 ++-------
>  arch/riscv/kernel/cpufeature.c      | 8 ++------
>  arch/riscv/kernel/process.c         | 2 +-
>  arch/riscv/kernel/signal.c          | 4 ++--
>  5 files changed, 12 insertions(+), 16 deletions(-)
>
> diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
> index d80ddd2f3b49..634a653c7fa2 100644
> --- a/arch/riscv/include/asm/cpufeature.h
> +++ b/arch/riscv/include/asm/cpufeature.h
> @@ -91,4 +91,9 @@ static inline void cpus_set_cap(unsigned int num)
>         }
>  }
>
> +static inline bool system_supports_fpu(void)
> +{
> +       return IS_ENABLED(CONFIG_FPU) && !cpus_have_final_cap(RISCV_HAS_NO_FPU);

This should be checking for "f" and "d" ISA extensions since "FPU" is
not an ISA extension name.

> +}
> +
>  #endif
> diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h
> index 0a3f4f95c555..362cb18d12d5 100644
> --- a/arch/riscv/include/asm/switch_to.h
> +++ b/arch/riscv/include/asm/switch_to.h
> @@ -8,6 +8,7 @@
>
>  #include <linux/jump_label.h>
>  #include <linux/sched/task_stack.h>
> +#include <asm/cpufeature.h>
>  #include <asm/processor.h>
>  #include <asm/ptrace.h>
>  #include <asm/csr.h>
> @@ -56,13 +57,7 @@ static inline void __switch_to_aux(struct task_struct *prev,
>         fstate_restore(next, task_pt_regs(next));
>  }
>
> -extern struct static_key_false cpu_hwcap_fpu;
> -static __always_inline bool has_fpu(void)
> -{
> -       return static_branch_likely(&cpu_hwcap_fpu);
> -}
>  #else
> -static __always_inline bool has_fpu(void) { return false; }
>  #define fstate_save(task, regs) do { } while (0)
>  #define fstate_restore(task, regs) do { } while (0)
>  #define __switch_to_aux(__prev, __next) do { } while (0)
> @@ -75,7 +70,7 @@ extern struct task_struct *__switch_to(struct task_struct *,
>  do {                                                   \
>         struct task_struct *__prev = (prev);            \
>         struct task_struct *__next = (next);            \
> -       if (has_fpu())                                  \
> +       if (system_supports_fpu())                                      \
>                 __switch_to_aux(__prev, __next);        \
>         ((last) = __switch_to(__prev, __next));         \
>  } while (0)
> diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> index e6c72cad0c1c..1edf3c3f8f62 100644
> --- a/arch/riscv/kernel/cpufeature.c
> +++ b/arch/riscv/kernel/cpufeature.c
> @@ -22,10 +22,6 @@ unsigned long elf_hwcap __read_mostly;
>  /* Host ISA bitmap */
>  static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
>
> -#ifdef CONFIG_FPU
> -__ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_fpu);
> -#endif
> -
>  DECLARE_BITMAP(cpu_hwcaps, RISCV_NCAPS);
>  EXPORT_SYMBOL(cpu_hwcaps);
>
> @@ -254,8 +250,8 @@ void __init riscv_fill_hwcap(void)
>         pr_info("riscv: ELF capabilities %s\n", print_str);
>
>  #ifdef CONFIG_FPU
> -       if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D))
> -               static_branch_enable(&cpu_hwcap_fpu);
> +       if (!(elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D)))
> +               cpus_set_cap(RISCV_HAS_NO_FPU);
>  #endif
>         enable_cpu_capabilities();
>         static_branch_enable(&riscv_const_caps_ready);
> diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c
> index 504b496787aa..c9cd0b42299e 100644
> --- a/arch/riscv/kernel/process.c
> +++ b/arch/riscv/kernel/process.c
> @@ -88,7 +88,7 @@ void start_thread(struct pt_regs *regs, unsigned long pc,
>         unsigned long sp)
>  {
>         regs->status = SR_PIE;
> -       if (has_fpu()) {
> +       if (system_supports_fpu()) {
>                 regs->status |= SR_FS_INITIAL;
>                 /*
>                  * Restore the initial value to the FP register
> diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c
> index 9f4e59f80551..96aa593a989e 100644
> --- a/arch/riscv/kernel/signal.c
> +++ b/arch/riscv/kernel/signal.c
> @@ -90,7 +90,7 @@ static long restore_sigcontext(struct pt_regs *regs,
>         /* sc_regs is structured the same as the start of pt_regs */
>         err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs));
>         /* Restore the floating-point state. */
> -       if (has_fpu())
> +       if (system_supports_fpu())
>                 err |= restore_fp_state(regs, &sc->sc_fpregs);
>         return err;
>  }
> @@ -143,7 +143,7 @@ static long setup_sigcontext(struct rt_sigframe __user *frame,
>         /* sc_regs is structured the same as the start of pt_regs */
>         err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs));
>         /* Save the floating-point state. */
> -       if (has_fpu())
> +       if (system_supports_fpu())
>                 err |= save_fp_state(regs, &sc->sc_fpregs);
>         return err;
>  }
> --
> 2.34.1
>
>
> _______________________________________________
> linux-riscv mailing list
> linux-riscv@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv

Regards,
Anup

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 0/4] unified way to use static key and optimize pgtable_l4_enabled
  2022-05-08 16:07 ` Jisheng Zhang
@ 2022-05-09  4:37   ` Anup Patel
  -1 siblings, 0 replies; 36+ messages in thread
From: Anup Patel @ 2022-05-09  4:37 UTC (permalink / raw)
  To: Jisheng Zhang
  Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Andrey Ryabinin,
	Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
	Vincenzo Frascino, Alexandre Ghiti, linux-riscv,
	linux-kernel@vger.kernel.org List, kasan-dev

On Sun, May 8, 2022 at 9:46 PM Jisheng Zhang <jszhang@kernel.org> wrote:
>
> Currently, riscv has several features which may not be supported on all
> riscv platforms, for example, FPU, SV48, SV57 and so on. To support
> unified kernel Image style, we need to check whether the feature is
> suportted or not. If the check sits at hot code path, then performance
> will be impacted a lot. static key can be used to solve the issue. In
> the past, FPU support has been converted to use static key mechanism.
> I believe we will have similar cases in the future. For example, the
> SV48 support can take advantage of static key[1].
>
> patch1 is a simple W=1 warning fix.
> patch2 introduces an unified mechanism to use static key for riscv cpu
> features.
> patch3 converts has_cpu() to use the mechanism.
> patch4 uses the mechanism to optimize pgtable_l4|[l5]_enabled.
>
> [1] http://lists.infradead.org/pipermail/linux-riscv/2021-December/011164.html

Overall, using a script to generate CPU capabilities seems a bit
over-engineered to me. We already have RISC-V ISA extension
parsing infrastructure which can be easily extended to support
static key arrays.

Regards,
Anup

>
> Since v1:
>  - Add a W=1 warning fix
>  - Fix W=1 error
>  - Based on v5.18-rcN, since SV57 support is added, so convert
>    pgtable_l5_enabled as well.
>
> Jisheng Zhang (4):
>   riscv: mm: init: make pt_ops_set_[early|late|fixmap] static
>   riscv: introduce unified static key mechanism for CPU features
>   riscv: replace has_fpu() with system_supports_fpu()
>   riscv: convert pgtable_l4|[l5]_enabled to static key
>
>  arch/riscv/Makefile                 |   3 +
>  arch/riscv/include/asm/cpufeature.h | 110 ++++++++++++++++++++++++++++
>  arch/riscv/include/asm/pgalloc.h    |  16 ++--
>  arch/riscv/include/asm/pgtable-64.h |  40 +++++-----
>  arch/riscv/include/asm/pgtable.h    |   5 +-
>  arch/riscv/include/asm/switch_to.h  |   9 +--
>  arch/riscv/kernel/cpu.c             |   4 +-
>  arch/riscv/kernel/cpufeature.c      |  29 ++++++--
>  arch/riscv/kernel/process.c         |   2 +-
>  arch/riscv/kernel/signal.c          |   4 +-
>  arch/riscv/mm/init.c                |  52 ++++++-------
>  arch/riscv/mm/kasan_init.c          |  16 ++--
>  arch/riscv/tools/Makefile           |  22 ++++++
>  arch/riscv/tools/cpucaps            |   7 ++
>  arch/riscv/tools/gen-cpucaps.awk    |  40 ++++++++++
>  15 files changed, 274 insertions(+), 85 deletions(-)
>  create mode 100644 arch/riscv/include/asm/cpufeature.h
>  create mode 100644 arch/riscv/tools/Makefile
>  create mode 100644 arch/riscv/tools/cpucaps
>  create mode 100755 arch/riscv/tools/gen-cpucaps.awk
>
> --
> 2.34.1
>

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

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 0/4] unified way to use static key and optimize pgtable_l4_enabled
@ 2022-05-09  4:37   ` Anup Patel
  0 siblings, 0 replies; 36+ messages in thread
From: Anup Patel @ 2022-05-09  4:37 UTC (permalink / raw)
  To: Jisheng Zhang
  Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Andrey Ryabinin,
	Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
	Vincenzo Frascino, Alexandre Ghiti, linux-riscv,
	linux-kernel@vger.kernel.org List, kasan-dev

On Sun, May 8, 2022 at 9:46 PM Jisheng Zhang <jszhang@kernel.org> wrote:
>
> Currently, riscv has several features which may not be supported on all
> riscv platforms, for example, FPU, SV48, SV57 and so on. To support
> unified kernel Image style, we need to check whether the feature is
> suportted or not. If the check sits at hot code path, then performance
> will be impacted a lot. static key can be used to solve the issue. In
> the past, FPU support has been converted to use static key mechanism.
> I believe we will have similar cases in the future. For example, the
> SV48 support can take advantage of static key[1].
>
> patch1 is a simple W=1 warning fix.
> patch2 introduces an unified mechanism to use static key for riscv cpu
> features.
> patch3 converts has_cpu() to use the mechanism.
> patch4 uses the mechanism to optimize pgtable_l4|[l5]_enabled.
>
> [1] http://lists.infradead.org/pipermail/linux-riscv/2021-December/011164.html

Overall, using a script to generate CPU capabilities seems a bit
over-engineered to me. We already have RISC-V ISA extension
parsing infrastructure which can be easily extended to support
static key arrays.

Regards,
Anup

>
> Since v1:
>  - Add a W=1 warning fix
>  - Fix W=1 error
>  - Based on v5.18-rcN, since SV57 support is added, so convert
>    pgtable_l5_enabled as well.
>
> Jisheng Zhang (4):
>   riscv: mm: init: make pt_ops_set_[early|late|fixmap] static
>   riscv: introduce unified static key mechanism for CPU features
>   riscv: replace has_fpu() with system_supports_fpu()
>   riscv: convert pgtable_l4|[l5]_enabled to static key
>
>  arch/riscv/Makefile                 |   3 +
>  arch/riscv/include/asm/cpufeature.h | 110 ++++++++++++++++++++++++++++
>  arch/riscv/include/asm/pgalloc.h    |  16 ++--
>  arch/riscv/include/asm/pgtable-64.h |  40 +++++-----
>  arch/riscv/include/asm/pgtable.h    |   5 +-
>  arch/riscv/include/asm/switch_to.h  |   9 +--
>  arch/riscv/kernel/cpu.c             |   4 +-
>  arch/riscv/kernel/cpufeature.c      |  29 ++++++--
>  arch/riscv/kernel/process.c         |   2 +-
>  arch/riscv/kernel/signal.c          |   4 +-
>  arch/riscv/mm/init.c                |  52 ++++++-------
>  arch/riscv/mm/kasan_init.c          |  16 ++--
>  arch/riscv/tools/Makefile           |  22 ++++++
>  arch/riscv/tools/cpucaps            |   7 ++
>  arch/riscv/tools/gen-cpucaps.awk    |  40 ++++++++++
>  15 files changed, 274 insertions(+), 85 deletions(-)
>  create mode 100644 arch/riscv/include/asm/cpufeature.h
>  create mode 100644 arch/riscv/tools/Makefile
>  create mode 100644 arch/riscv/tools/cpucaps
>  create mode 100755 arch/riscv/tools/gen-cpucaps.awk
>
> --
> 2.34.1
>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 0/4] unified way to use static key and optimize pgtable_l4_enabled
  2022-05-09  4:37   ` Anup Patel
@ 2022-05-09 14:26     ` Jisheng Zhang
  -1 siblings, 0 replies; 36+ messages in thread
From: Jisheng Zhang @ 2022-05-09 14:26 UTC (permalink / raw)
  To: Anup Patel
  Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Andrey Ryabinin,
	Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
	Vincenzo Frascino, Alexandre Ghiti, linux-riscv,
	linux-kernel@vger.kernel.org List, kasan-dev

On Mon, May 09, 2022 at 10:07:16AM +0530, Anup Patel wrote:
> On Sun, May 8, 2022 at 9:46 PM Jisheng Zhang <jszhang@kernel.org> wrote:
> >
> > Currently, riscv has several features which may not be supported on all
> > riscv platforms, for example, FPU, SV48, SV57 and so on. To support
> > unified kernel Image style, we need to check whether the feature is
> > suportted or not. If the check sits at hot code path, then performance
> > will be impacted a lot. static key can be used to solve the issue. In
> > the past, FPU support has been converted to use static key mechanism.
> > I believe we will have similar cases in the future. For example, the
> > SV48 support can take advantage of static key[1].
> >
> > patch1 is a simple W=1 warning fix.
> > patch2 introduces an unified mechanism to use static key for riscv cpu
> > features.
> > patch3 converts has_cpu() to use the mechanism.
> > patch4 uses the mechanism to optimize pgtable_l4|[l5]_enabled.
> >
> > [1] http://lists.infradead.org/pipermail/linux-riscv/2021-December/011164.html
> 
> Overall, using a script to generate CPU capabilities seems a bit
> over-engineered to me. We already have RISC-V ISA extension

Not all riscv features are *ISA* extensions. For example, SV48 and SV57
are not ISA extensions. IIRC, I asked this question before, here are
Atish's comments:

https://lore.kernel.org/linux-riscv/CAHBxVyF65jC_wvxcD6bueqpCY8-Kbahu1yxsSoBmO1s15dGkSQ@mail.gmail.com/

> parsing infrastructure which can be easily extended to support
> static key arrays.
> 


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 0/4] unified way to use static key and optimize pgtable_l4_enabled
@ 2022-05-09 14:26     ` Jisheng Zhang
  0 siblings, 0 replies; 36+ messages in thread
From: Jisheng Zhang @ 2022-05-09 14:26 UTC (permalink / raw)
  To: Anup Patel
  Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Andrey Ryabinin,
	Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
	Vincenzo Frascino, Alexandre Ghiti, linux-riscv,
	linux-kernel@vger.kernel.org List, kasan-dev

On Mon, May 09, 2022 at 10:07:16AM +0530, Anup Patel wrote:
> On Sun, May 8, 2022 at 9:46 PM Jisheng Zhang <jszhang@kernel.org> wrote:
> >
> > Currently, riscv has several features which may not be supported on all
> > riscv platforms, for example, FPU, SV48, SV57 and so on. To support
> > unified kernel Image style, we need to check whether the feature is
> > suportted or not. If the check sits at hot code path, then performance
> > will be impacted a lot. static key can be used to solve the issue. In
> > the past, FPU support has been converted to use static key mechanism.
> > I believe we will have similar cases in the future. For example, the
> > SV48 support can take advantage of static key[1].
> >
> > patch1 is a simple W=1 warning fix.
> > patch2 introduces an unified mechanism to use static key for riscv cpu
> > features.
> > patch3 converts has_cpu() to use the mechanism.
> > patch4 uses the mechanism to optimize pgtable_l4|[l5]_enabled.
> >
> > [1] http://lists.infradead.org/pipermail/linux-riscv/2021-December/011164.html
> 
> Overall, using a script to generate CPU capabilities seems a bit
> over-engineered to me. We already have RISC-V ISA extension

Not all riscv features are *ISA* extensions. For example, SV48 and SV57
are not ISA extensions. IIRC, I asked this question before, here are
Atish's comments:

https://lore.kernel.org/linux-riscv/CAHBxVyF65jC_wvxcD6bueqpCY8-Kbahu1yxsSoBmO1s15dGkSQ@mail.gmail.com/

> parsing infrastructure which can be easily extended to support
> static key arrays.
> 


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

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 2/4] riscv: introduce unified static key mechanism for CPU features
  2022-05-09  3:47     ` Anup Patel
@ 2022-05-09 14:41       ` Jisheng Zhang
  -1 siblings, 0 replies; 36+ messages in thread
From: Jisheng Zhang @ 2022-05-09 14:41 UTC (permalink / raw)
  To: Anup Patel
  Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Andrey Ryabinin,
	Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
	Vincenzo Frascino, Alexandre Ghiti, linux-riscv,
	linux-kernel@vger.kernel.org List, kasan-dev

On Mon, May 09, 2022 at 09:17:10AM +0530, Anup Patel wrote:
> On Sun, May 8, 2022 at 9:47 PM Jisheng Zhang <jszhang@kernel.org> wrote:
> >
> > Currently, riscv has several features why may not be supported on all
> > riscv platforms, for example, FPU, SV48 and so on. To support unified
> > kernel Image style, we need to check whether the feature is suportted
> > or not. If the check sits at hot code path, then performance will be
> > impacted a lot. static key can be used to solve the issue. In the past
> > FPU support has been converted to use static key mechanism. I believe
> > we will have similar cases in the future.
> 
> It's not just FPU and Sv48. There are several others such as Svinval,
> Vector, Svnapot, Svpbmt, and many many others.
> 
> Overall, I agree with the approach of using static key array but I
> disagree with the semantics and the duplicate stuff being added.
> 
> Please see more comments below ..
> 
> >
> > Similar as arm64 does(in fact, some code is borrowed from arm64), this
> > patch tries to add an unified mechanism to use static keys for all
> > the cpu features by implementing an array of default-false static keys
> > and enabling them when detected. The cpus_have_*_cap() check uses the
> > static keys if riscv_const_caps_ready is finalized, otherwise the
> > compiler generates the bitmap test.
> 
> First of all, we should stop calling this a feature (like ARM does). Rather,
> we should call these as isa extensions ("isaext") to align with the RISC-V
> priv spec and RISC-V profiles spec. For all the ISA optionalities which do
> not have distinct extension name, the RISC-V profiles spec is assigning
> names to all such optionalities.

Same as the reply a few minutes ago, the key problem here is do all
CPU features belong to *ISA* extensions? For example, SV48, SV57 etc.
I agree with Atish's comments here:

"I think the cpu feature is a superset of the ISA extension.
cpu feature != ISA extension"

https://lore.kernel.org/linux-riscv/CAHBxVyF65jC_wvxcD6bueqpCY8-Kbahu1yxsSoBmO1s15dGkSQ@mail.gmail.com/

> 
> Another issue with semantics is that this patch assumes all features are
> enabled by default and we selectively disable it. This contrary to the
> approach taken by existing arch/riscv/kernel/cpufeature.c which assumes
> nothing is enabled by default and we selectively enable it.

This is implementation related, can be modified in next version. From
another side, assuming some feature enabled by default can result in
trivial performance improvement for most platforms. For example, if
most platforms are FPU capable, we'd better assume FPU enabled by default.

> 
> >
> > Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
> > ---
> >  arch/riscv/Makefile                 |  3 +
> >  arch/riscv/include/asm/cpufeature.h | 94 +++++++++++++++++++++++++++++
> >  arch/riscv/kernel/cpufeature.c      | 23 +++++++
> >  arch/riscv/tools/Makefile           | 22 +++++++
> >  arch/riscv/tools/cpucaps            |  5 ++
> >  arch/riscv/tools/gen-cpucaps.awk    | 40 ++++++++++++
> >  6 files changed, 187 insertions(+)
> >  create mode 100644 arch/riscv/include/asm/cpufeature.h
> >  create mode 100644 arch/riscv/tools/Makefile
> >  create mode 100644 arch/riscv/tools/cpucaps
> >  create mode 100755 arch/riscv/tools/gen-cpucaps.awk
> >
> > diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
> > index 7d81102cffd4..f4df67369d84 100644
> > --- a/arch/riscv/Makefile
> > +++ b/arch/riscv/Makefile
> > @@ -154,3 +154,6 @@ PHONY += rv64_randconfig
> >  rv64_randconfig:
> >         $(Q)$(MAKE) KCONFIG_ALLCONFIG=$(srctree)/arch/riscv/configs/64-bit.config \
> >                 -f $(srctree)/Makefile randconfig
> > +
> > +archprepare:
> > +       $(Q)$(MAKE) $(build)=arch/riscv/tools kapi
> > diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
> > new file mode 100644
> > index 000000000000..d80ddd2f3b49
> > --- /dev/null
> > +++ b/arch/riscv/include/asm/cpufeature.h
> 
> We don't need a separate header for this.
> 
> All this belongs to arch/riscv/include/asm/hwcap.h
> 
> > @@ -0,0 +1,94 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +/*
> > + * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
> > + * Copyright (C) 2022 Jisheng Zhang <jszhang@kernel.org>
> > + */
> > +
> > +#ifndef __ASM_CPUFEATURE_H
> > +#define __ASM_CPUFEATURE_H
> > +
> > +#include <asm/cpucaps.h>
> > +
> > +#include <linux/bug.h>
> > +#include <linux/jump_label.h>
> > +#include <linux/kernel.h>
> > +
> > +extern DECLARE_BITMAP(cpu_hwcaps, RISCV_NCAPS);
> 
> This is a redundant bitmap. Please re-use "riscv_isa" bitmap for this
> the ISA extensions.
> 
> > +extern struct static_key_false cpu_hwcap_keys[RISCV_NCAPS];
> 
> This should be called "riscv_isa_keys"
> 
> > +extern struct static_key_false riscv_const_caps_ready;
> 
> This should be called "riscv_isa_keys_ready".
> 
> > +
> > +static __always_inline bool system_capabilities_finalized(void)
> 
> Another misaligned name. This should be called
> "riscv_isa_keys_finalized()".
> 
> > +{
> > +       return static_branch_likely(&riscv_const_caps_ready);
> > +}
> > +
> > +/*
> > + * Test for a capability with a runtime check.
> > + *
> > + * Before the capability is detected, this returns false.
> > + */
> > +static inline bool cpus_have_cap(unsigned int num)
> > +{
> > +       if (num >= RISCV_NCAPS)
> > +               return false;
> > +       return test_bit(num, cpu_hwcaps);
> > +}
> 
> This should be called riscv_isa_have_extension() and it should
> internally call "__riscv_isa_extension_available(NULL, num)".
> 
> > +
> > +/*
> > + * Test for a capability without a runtime check.
> > + *
> > + * Before capabilities are finalized, this returns false.
> > + * After capabilities are finalized, this is patched to avoid a runtime check.
> > + *
> > + * @num must be a compile-time constant.
> > + */
> > +static __always_inline bool __cpus_have_const_cap(int num)
> 
> This should be named "__riscv_isa_have_const_extension()"
> 
> > +{
> > +       if (num >= RISCV_NCAPS)
> > +               return false;
> > +       return static_branch_unlikely(&cpu_hwcap_keys[num]);
> > +}
> > +
> > +/*
> > + * Test for a capability without a runtime check.
> > + *
> > + * Before capabilities are finalized, this will BUG().
> > + * After capabilities are finalized, this is patched to avoid a runtime check.
> > + *
> > + * @num must be a compile-time constant.
> > + */
> > +static __always_inline bool cpus_have_final_cap(int num)
> 
> This should be called "riscv_isa_have_final_extension()"
> 
> > +{
> > +       if (system_capabilities_finalized())
> > +               return __cpus_have_const_cap(num);
> > +       else
> > +               BUG();
> > +}
> > +
> > +/*
> > + * Test for a capability, possibly with a runtime check.
> > + *
> > + * Before capabilities are finalized, this behaves as cpus_have_cap().
> > + * After capabilities are finalized, this is patched to avoid a runtime check.
> > + *
> > + * @num must be a compile-time constant.
> > + */
> > +static __always_inline bool cpus_have_const_cap(int num)
> 
> Same comment as above.
> 
> > +{
> > +       if (system_capabilities_finalized())
> > +               return __cpus_have_const_cap(num);
> > +       else
> > +               return cpus_have_cap(num);
> > +}
> > +
> > +static inline void cpus_set_cap(unsigned int num)
> 
> Same comment as above.
> 
> > +{
> > +       if (num >= RISCV_NCAPS) {
> > +               pr_warn("Attempt to set an illegal CPU capability (%d >= %d)\n",
> > +                       num, RISCV_NCAPS);
> > +       } else {
> > +               __set_bit(num, cpu_hwcaps);
> > +       }
> > +}
> > +
> > +#endif
> > diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> > index 1b2d42d7f589..e6c72cad0c1c 100644
> > --- a/arch/riscv/kernel/cpufeature.c
> > +++ b/arch/riscv/kernel/cpufeature.c
> > @@ -9,6 +9,7 @@
> >  #include <linux/bitmap.h>
> >  #include <linux/ctype.h>
> >  #include <linux/of.h>
> > +#include <asm/cpufeature.h>
> >  #include <asm/processor.h>
> >  #include <asm/hwcap.h>
> >  #include <asm/smp.h>
> > @@ -25,6 +26,15 @@ static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
> >  __ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_fpu);
> >  #endif
> >
> > +DECLARE_BITMAP(cpu_hwcaps, RISCV_NCAPS);
> > +EXPORT_SYMBOL(cpu_hwcaps);
> 
> Just like the previous comment. This is a redundant bitmap.
> Please use "riscv_isa" bitmap for this purpose.
> 
> > +
> > +DEFINE_STATIC_KEY_ARRAY_FALSE(cpu_hwcap_keys, RISCV_NCAPS);
> > +EXPORT_SYMBOL(cpu_hwcap_keys);
> > +
> > +DEFINE_STATIC_KEY_FALSE(riscv_const_caps_ready);
> > +EXPORT_SYMBOL(riscv_const_caps_ready);
> 
> Please see comments above.
> 
> > +
> >  /**
> >   * riscv_isa_extension_base() - Get base extension word
> >   *
> > @@ -62,6 +72,17 @@ bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, int bit)
> >  }
> >  EXPORT_SYMBOL_GPL(__riscv_isa_extension_available);
> >
> > +static void __init enable_cpu_capabilities(void)
> > +{
> > +       int i;
> > +
> > +       for (i = 0; i < RISCV_NCAPS; i++) {
> > +               if (!cpus_have_cap(i))
> > +                       continue;
> > +               static_branch_enable(&cpu_hwcap_keys[i]);
> > +       }
> > +}
> > +
> >  void __init riscv_fill_hwcap(void)
> >  {
> >         struct device_node *node;
> > @@ -236,4 +257,6 @@ void __init riscv_fill_hwcap(void)
> >         if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D))
> >                 static_branch_enable(&cpu_hwcap_fpu);
> >  #endif
> > +       enable_cpu_capabilities();
> > +       static_branch_enable(&riscv_const_caps_ready);
> >  }
> > diff --git a/arch/riscv/tools/Makefile b/arch/riscv/tools/Makefile
> > new file mode 100644
> > index 000000000000..932b4fe5c768
> > --- /dev/null
> > +++ b/arch/riscv/tools/Makefile
> > @@ -0,0 +1,22 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +
> > +gen := arch/$(ARCH)/include/generated
> > +kapi := $(gen)/asm
> > +
> > +kapi-hdrs-y := $(kapi)/cpucaps.h
> > +
> > +targets += $(addprefix ../../../,$(gen-y) $(kapi-hdrs-y))
> > +
> > +PHONY += kapi
> > +
> > +kapi:   $(kapi-hdrs-y) $(gen-y)
> > +
> > +# Create output directory if not already present
> > +_dummy := $(shell [ -d '$(kapi)' ] || mkdir -p '$(kapi)')
> > +
> > +quiet_cmd_gen_cpucaps = GEN     $@
> > +      cmd_gen_cpucaps = mkdir -p $(dir $@) && \
> > +                     $(AWK) -f $(filter-out $(PHONY),$^) > $@
> > +
> > +$(kapi)/cpucaps.h: $(src)/gen-cpucaps.awk $(src)/cpucaps FORCE
> > +       $(call if_changed,gen_cpucaps)
> > diff --git a/arch/riscv/tools/cpucaps b/arch/riscv/tools/cpucaps
> > new file mode 100644
> > index 000000000000..cb1ff2747859
> > --- /dev/null
> > +++ b/arch/riscv/tools/cpucaps
> > @@ -0,0 +1,5 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +#
> > +# Internal CPU capabilities constants, keep this list sorted
> > +
> > +HAS_NO_FPU
> 
> How can "No FPU" be a CPU capability ?
> 
> We have ISA extensions 'F' and 'D' which tells us whether an FPU is available
> or not.
> 
> I think this file should be a table with two columns
> "<lower_case_extension_name> <parsed_from_isa_string_yes_no>"
> I this this file should look like this:
> 
> i yes
> m yes
> a yes
> c yes
> f yes
> d yes
> h yes
> sv48 no
> sv57 no
> sstc yes
> svinval yes
> svpbmt yes
> svnapot yes
> sscofpmf yes
> ...
> 
> > diff --git a/arch/riscv/tools/gen-cpucaps.awk b/arch/riscv/tools/gen-cpucaps.awk
> > new file mode 100755
> > index 000000000000..52a1e1b064ad
> > --- /dev/null
> > +++ b/arch/riscv/tools/gen-cpucaps.awk
> > @@ -0,0 +1,40 @@
> > +#!/bin/awk -f
> > +# SPDX-License-Identifier: GPL-2.0
> > +# gen-cpucaps.awk: riscv cpucaps header generator
> > +#
> > +# Usage: awk -f gen-cpucaps.awk cpucaps.txt
> > +
> > +# Log an error and terminate
> > +function fatal(msg) {
> > +       print "Error at line " NR ": " msg > "/dev/stderr"
> > +       exit 1
> > +}
> > +
> > +# skip blank lines and comment lines
> > +/^$/ { next }
> > +/^#/ { next }
> > +
> > +BEGIN {
> > +       print "#ifndef __ASM_CPUCAPS_H"
> > +       print "#define __ASM_CPUCAPS_H"
> > +       print ""
> > +       print "/* Generated file - do not edit */"
> > +       cap_num = 0
> > +       print ""
> > +}
> > +
> > +/^[vA-Z0-9_]+$/ {
> > +       printf("#define RISCV_%-30s\t%d\n", $0, cap_num++)
> > +       next
> > +}
> > +
> > +END {
> > +       printf("#define RISCV_NCAPS\t\t\t\t%d\n", cap_num)
> > +       print ""
> > +       print "#endif /* __ASM_CPUCAPS_H */"
> > +}
> 
> This script need to change refer capabilities as extensions.
> 
> For every extension, there should be two defines.
> For e.g. "sstc" extension should have following defines
> #define RISCV_ISA_EXT_sstc <#num>
> #define RISCV_ISA_EXT_FROMSTR_sstc <1|0>
> 
> > +
> > +# Any lines not handled by previous rules are unexpected
> > +{
> > +       fatal("unhandled statement")
> > +}
> > --
> > 2.34.1
> >
> 
> Regards,
> Anup

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 2/4] riscv: introduce unified static key mechanism for CPU features
@ 2022-05-09 14:41       ` Jisheng Zhang
  0 siblings, 0 replies; 36+ messages in thread
From: Jisheng Zhang @ 2022-05-09 14:41 UTC (permalink / raw)
  To: Anup Patel
  Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Andrey Ryabinin,
	Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
	Vincenzo Frascino, Alexandre Ghiti, linux-riscv,
	linux-kernel@vger.kernel.org List, kasan-dev

On Mon, May 09, 2022 at 09:17:10AM +0530, Anup Patel wrote:
> On Sun, May 8, 2022 at 9:47 PM Jisheng Zhang <jszhang@kernel.org> wrote:
> >
> > Currently, riscv has several features why may not be supported on all
> > riscv platforms, for example, FPU, SV48 and so on. To support unified
> > kernel Image style, we need to check whether the feature is suportted
> > or not. If the check sits at hot code path, then performance will be
> > impacted a lot. static key can be used to solve the issue. In the past
> > FPU support has been converted to use static key mechanism. I believe
> > we will have similar cases in the future.
> 
> It's not just FPU and Sv48. There are several others such as Svinval,
> Vector, Svnapot, Svpbmt, and many many others.
> 
> Overall, I agree with the approach of using static key array but I
> disagree with the semantics and the duplicate stuff being added.
> 
> Please see more comments below ..
> 
> >
> > Similar as arm64 does(in fact, some code is borrowed from arm64), this
> > patch tries to add an unified mechanism to use static keys for all
> > the cpu features by implementing an array of default-false static keys
> > and enabling them when detected. The cpus_have_*_cap() check uses the
> > static keys if riscv_const_caps_ready is finalized, otherwise the
> > compiler generates the bitmap test.
> 
> First of all, we should stop calling this a feature (like ARM does). Rather,
> we should call these as isa extensions ("isaext") to align with the RISC-V
> priv spec and RISC-V profiles spec. For all the ISA optionalities which do
> not have distinct extension name, the RISC-V profiles spec is assigning
> names to all such optionalities.

Same as the reply a few minutes ago, the key problem here is do all
CPU features belong to *ISA* extensions? For example, SV48, SV57 etc.
I agree with Atish's comments here:

"I think the cpu feature is a superset of the ISA extension.
cpu feature != ISA extension"

https://lore.kernel.org/linux-riscv/CAHBxVyF65jC_wvxcD6bueqpCY8-Kbahu1yxsSoBmO1s15dGkSQ@mail.gmail.com/

> 
> Another issue with semantics is that this patch assumes all features are
> enabled by default and we selectively disable it. This contrary to the
> approach taken by existing arch/riscv/kernel/cpufeature.c which assumes
> nothing is enabled by default and we selectively enable it.

This is implementation related, can be modified in next version. From
another side, assuming some feature enabled by default can result in
trivial performance improvement for most platforms. For example, if
most platforms are FPU capable, we'd better assume FPU enabled by default.

> 
> >
> > Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
> > ---
> >  arch/riscv/Makefile                 |  3 +
> >  arch/riscv/include/asm/cpufeature.h | 94 +++++++++++++++++++++++++++++
> >  arch/riscv/kernel/cpufeature.c      | 23 +++++++
> >  arch/riscv/tools/Makefile           | 22 +++++++
> >  arch/riscv/tools/cpucaps            |  5 ++
> >  arch/riscv/tools/gen-cpucaps.awk    | 40 ++++++++++++
> >  6 files changed, 187 insertions(+)
> >  create mode 100644 arch/riscv/include/asm/cpufeature.h
> >  create mode 100644 arch/riscv/tools/Makefile
> >  create mode 100644 arch/riscv/tools/cpucaps
> >  create mode 100755 arch/riscv/tools/gen-cpucaps.awk
> >
> > diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
> > index 7d81102cffd4..f4df67369d84 100644
> > --- a/arch/riscv/Makefile
> > +++ b/arch/riscv/Makefile
> > @@ -154,3 +154,6 @@ PHONY += rv64_randconfig
> >  rv64_randconfig:
> >         $(Q)$(MAKE) KCONFIG_ALLCONFIG=$(srctree)/arch/riscv/configs/64-bit.config \
> >                 -f $(srctree)/Makefile randconfig
> > +
> > +archprepare:
> > +       $(Q)$(MAKE) $(build)=arch/riscv/tools kapi
> > diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
> > new file mode 100644
> > index 000000000000..d80ddd2f3b49
> > --- /dev/null
> > +++ b/arch/riscv/include/asm/cpufeature.h
> 
> We don't need a separate header for this.
> 
> All this belongs to arch/riscv/include/asm/hwcap.h
> 
> > @@ -0,0 +1,94 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +/*
> > + * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
> > + * Copyright (C) 2022 Jisheng Zhang <jszhang@kernel.org>
> > + */
> > +
> > +#ifndef __ASM_CPUFEATURE_H
> > +#define __ASM_CPUFEATURE_H
> > +
> > +#include <asm/cpucaps.h>
> > +
> > +#include <linux/bug.h>
> > +#include <linux/jump_label.h>
> > +#include <linux/kernel.h>
> > +
> > +extern DECLARE_BITMAP(cpu_hwcaps, RISCV_NCAPS);
> 
> This is a redundant bitmap. Please re-use "riscv_isa" bitmap for this
> the ISA extensions.
> 
> > +extern struct static_key_false cpu_hwcap_keys[RISCV_NCAPS];
> 
> This should be called "riscv_isa_keys"
> 
> > +extern struct static_key_false riscv_const_caps_ready;
> 
> This should be called "riscv_isa_keys_ready".
> 
> > +
> > +static __always_inline bool system_capabilities_finalized(void)
> 
> Another misaligned name. This should be called
> "riscv_isa_keys_finalized()".
> 
> > +{
> > +       return static_branch_likely(&riscv_const_caps_ready);
> > +}
> > +
> > +/*
> > + * Test for a capability with a runtime check.
> > + *
> > + * Before the capability is detected, this returns false.
> > + */
> > +static inline bool cpus_have_cap(unsigned int num)
> > +{
> > +       if (num >= RISCV_NCAPS)
> > +               return false;
> > +       return test_bit(num, cpu_hwcaps);
> > +}
> 
> This should be called riscv_isa_have_extension() and it should
> internally call "__riscv_isa_extension_available(NULL, num)".
> 
> > +
> > +/*
> > + * Test for a capability without a runtime check.
> > + *
> > + * Before capabilities are finalized, this returns false.
> > + * After capabilities are finalized, this is patched to avoid a runtime check.
> > + *
> > + * @num must be a compile-time constant.
> > + */
> > +static __always_inline bool __cpus_have_const_cap(int num)
> 
> This should be named "__riscv_isa_have_const_extension()"
> 
> > +{
> > +       if (num >= RISCV_NCAPS)
> > +               return false;
> > +       return static_branch_unlikely(&cpu_hwcap_keys[num]);
> > +}
> > +
> > +/*
> > + * Test for a capability without a runtime check.
> > + *
> > + * Before capabilities are finalized, this will BUG().
> > + * After capabilities are finalized, this is patched to avoid a runtime check.
> > + *
> > + * @num must be a compile-time constant.
> > + */
> > +static __always_inline bool cpus_have_final_cap(int num)
> 
> This should be called "riscv_isa_have_final_extension()"
> 
> > +{
> > +       if (system_capabilities_finalized())
> > +               return __cpus_have_const_cap(num);
> > +       else
> > +               BUG();
> > +}
> > +
> > +/*
> > + * Test for a capability, possibly with a runtime check.
> > + *
> > + * Before capabilities are finalized, this behaves as cpus_have_cap().
> > + * After capabilities are finalized, this is patched to avoid a runtime check.
> > + *
> > + * @num must be a compile-time constant.
> > + */
> > +static __always_inline bool cpus_have_const_cap(int num)
> 
> Same comment as above.
> 
> > +{
> > +       if (system_capabilities_finalized())
> > +               return __cpus_have_const_cap(num);
> > +       else
> > +               return cpus_have_cap(num);
> > +}
> > +
> > +static inline void cpus_set_cap(unsigned int num)
> 
> Same comment as above.
> 
> > +{
> > +       if (num >= RISCV_NCAPS) {
> > +               pr_warn("Attempt to set an illegal CPU capability (%d >= %d)\n",
> > +                       num, RISCV_NCAPS);
> > +       } else {
> > +               __set_bit(num, cpu_hwcaps);
> > +       }
> > +}
> > +
> > +#endif
> > diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> > index 1b2d42d7f589..e6c72cad0c1c 100644
> > --- a/arch/riscv/kernel/cpufeature.c
> > +++ b/arch/riscv/kernel/cpufeature.c
> > @@ -9,6 +9,7 @@
> >  #include <linux/bitmap.h>
> >  #include <linux/ctype.h>
> >  #include <linux/of.h>
> > +#include <asm/cpufeature.h>
> >  #include <asm/processor.h>
> >  #include <asm/hwcap.h>
> >  #include <asm/smp.h>
> > @@ -25,6 +26,15 @@ static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
> >  __ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_fpu);
> >  #endif
> >
> > +DECLARE_BITMAP(cpu_hwcaps, RISCV_NCAPS);
> > +EXPORT_SYMBOL(cpu_hwcaps);
> 
> Just like the previous comment. This is a redundant bitmap.
> Please use "riscv_isa" bitmap for this purpose.
> 
> > +
> > +DEFINE_STATIC_KEY_ARRAY_FALSE(cpu_hwcap_keys, RISCV_NCAPS);
> > +EXPORT_SYMBOL(cpu_hwcap_keys);
> > +
> > +DEFINE_STATIC_KEY_FALSE(riscv_const_caps_ready);
> > +EXPORT_SYMBOL(riscv_const_caps_ready);
> 
> Please see comments above.
> 
> > +
> >  /**
> >   * riscv_isa_extension_base() - Get base extension word
> >   *
> > @@ -62,6 +72,17 @@ bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, int bit)
> >  }
> >  EXPORT_SYMBOL_GPL(__riscv_isa_extension_available);
> >
> > +static void __init enable_cpu_capabilities(void)
> > +{
> > +       int i;
> > +
> > +       for (i = 0; i < RISCV_NCAPS; i++) {
> > +               if (!cpus_have_cap(i))
> > +                       continue;
> > +               static_branch_enable(&cpu_hwcap_keys[i]);
> > +       }
> > +}
> > +
> >  void __init riscv_fill_hwcap(void)
> >  {
> >         struct device_node *node;
> > @@ -236,4 +257,6 @@ void __init riscv_fill_hwcap(void)
> >         if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D))
> >                 static_branch_enable(&cpu_hwcap_fpu);
> >  #endif
> > +       enable_cpu_capabilities();
> > +       static_branch_enable(&riscv_const_caps_ready);
> >  }
> > diff --git a/arch/riscv/tools/Makefile b/arch/riscv/tools/Makefile
> > new file mode 100644
> > index 000000000000..932b4fe5c768
> > --- /dev/null
> > +++ b/arch/riscv/tools/Makefile
> > @@ -0,0 +1,22 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +
> > +gen := arch/$(ARCH)/include/generated
> > +kapi := $(gen)/asm
> > +
> > +kapi-hdrs-y := $(kapi)/cpucaps.h
> > +
> > +targets += $(addprefix ../../../,$(gen-y) $(kapi-hdrs-y))
> > +
> > +PHONY += kapi
> > +
> > +kapi:   $(kapi-hdrs-y) $(gen-y)
> > +
> > +# Create output directory if not already present
> > +_dummy := $(shell [ -d '$(kapi)' ] || mkdir -p '$(kapi)')
> > +
> > +quiet_cmd_gen_cpucaps = GEN     $@
> > +      cmd_gen_cpucaps = mkdir -p $(dir $@) && \
> > +                     $(AWK) -f $(filter-out $(PHONY),$^) > $@
> > +
> > +$(kapi)/cpucaps.h: $(src)/gen-cpucaps.awk $(src)/cpucaps FORCE
> > +       $(call if_changed,gen_cpucaps)
> > diff --git a/arch/riscv/tools/cpucaps b/arch/riscv/tools/cpucaps
> > new file mode 100644
> > index 000000000000..cb1ff2747859
> > --- /dev/null
> > +++ b/arch/riscv/tools/cpucaps
> > @@ -0,0 +1,5 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +#
> > +# Internal CPU capabilities constants, keep this list sorted
> > +
> > +HAS_NO_FPU
> 
> How can "No FPU" be a CPU capability ?
> 
> We have ISA extensions 'F' and 'D' which tells us whether an FPU is available
> or not.
> 
> I think this file should be a table with two columns
> "<lower_case_extension_name> <parsed_from_isa_string_yes_no>"
> I this this file should look like this:
> 
> i yes
> m yes
> a yes
> c yes
> f yes
> d yes
> h yes
> sv48 no
> sv57 no
> sstc yes
> svinval yes
> svpbmt yes
> svnapot yes
> sscofpmf yes
> ...
> 
> > diff --git a/arch/riscv/tools/gen-cpucaps.awk b/arch/riscv/tools/gen-cpucaps.awk
> > new file mode 100755
> > index 000000000000..52a1e1b064ad
> > --- /dev/null
> > +++ b/arch/riscv/tools/gen-cpucaps.awk
> > @@ -0,0 +1,40 @@
> > +#!/bin/awk -f
> > +# SPDX-License-Identifier: GPL-2.0
> > +# gen-cpucaps.awk: riscv cpucaps header generator
> > +#
> > +# Usage: awk -f gen-cpucaps.awk cpucaps.txt
> > +
> > +# Log an error and terminate
> > +function fatal(msg) {
> > +       print "Error at line " NR ": " msg > "/dev/stderr"
> > +       exit 1
> > +}
> > +
> > +# skip blank lines and comment lines
> > +/^$/ { next }
> > +/^#/ { next }
> > +
> > +BEGIN {
> > +       print "#ifndef __ASM_CPUCAPS_H"
> > +       print "#define __ASM_CPUCAPS_H"
> > +       print ""
> > +       print "/* Generated file - do not edit */"
> > +       cap_num = 0
> > +       print ""
> > +}
> > +
> > +/^[vA-Z0-9_]+$/ {
> > +       printf("#define RISCV_%-30s\t%d\n", $0, cap_num++)
> > +       next
> > +}
> > +
> > +END {
> > +       printf("#define RISCV_NCAPS\t\t\t\t%d\n", cap_num)
> > +       print ""
> > +       print "#endif /* __ASM_CPUCAPS_H */"
> > +}
> 
> This script need to change refer capabilities as extensions.
> 
> For every extension, there should be two defines.
> For e.g. "sstc" extension should have following defines
> #define RISCV_ISA_EXT_sstc <#num>
> #define RISCV_ISA_EXT_FROMSTR_sstc <1|0>
> 
> > +
> > +# Any lines not handled by previous rules are unexpected
> > +{
> > +       fatal("unhandled statement")
> > +}
> > --
> > 2.34.1
> >
> 
> Regards,
> Anup

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

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 2/4] riscv: introduce unified static key mechanism for CPU features
  2022-05-09 14:41       ` Jisheng Zhang
@ 2022-05-12  6:29         ` Atish Patra
  -1 siblings, 0 replies; 36+ messages in thread
From: Atish Patra @ 2022-05-12  6:29 UTC (permalink / raw)
  To: Jisheng Zhang
  Cc: Anup Patel, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Andrey Ryabinin, Alexander Potapenko, Andrey Konovalov,
	Dmitry Vyukov, Vincenzo Frascino, Alexandre Ghiti, linux-riscv,
	linux-kernel@vger.kernel.org List, kasan-dev

On Mon, May 9, 2022 at 7:50 AM Jisheng Zhang <jszhang@kernel.org> wrote:
>
> On Mon, May 09, 2022 at 09:17:10AM +0530, Anup Patel wrote:
> > On Sun, May 8, 2022 at 9:47 PM Jisheng Zhang <jszhang@kernel.org> wrote:
> > >
> > > Currently, riscv has several features why may not be supported on all
> > > riscv platforms, for example, FPU, SV48 and so on. To support unified
> > > kernel Image style, we need to check whether the feature is suportted
> > > or not. If the check sits at hot code path, then performance will be
> > > impacted a lot. static key can be used to solve the issue. In the past
> > > FPU support has been converted to use static key mechanism. I believe
> > > we will have similar cases in the future.
> >
> > It's not just FPU and Sv48. There are several others such as Svinval,
> > Vector, Svnapot, Svpbmt, and many many others.
> >
> > Overall, I agree with the approach of using static key array but I
> > disagree with the semantics and the duplicate stuff being added.
> >
> > Please see more comments below ..
> >
> > >
> > > Similar as arm64 does(in fact, some code is borrowed from arm64), this
> > > patch tries to add an unified mechanism to use static keys for all
> > > the cpu features by implementing an array of default-false static keys
> > > and enabling them when detected. The cpus_have_*_cap() check uses the
> > > static keys if riscv_const_caps_ready is finalized, otherwise the
> > > compiler generates the bitmap test.
> >
> > First of all, we should stop calling this a feature (like ARM does). Rather,
> > we should call these as isa extensions ("isaext") to align with the RISC-V
> > priv spec and RISC-V profiles spec. For all the ISA optionalities which do
> > not have distinct extension name, the RISC-V profiles spec is assigning
> > names to all such optionalities.
>
> Same as the reply a few minutes ago, the key problem here is do all
> CPU features belong to *ISA* extensions? For example, SV48, SV57 etc.
> I agree with Atish's comments here:
>
> "I think the cpu feature is a superset of the ISA extension.
> cpu feature != ISA extension"
>

It seems to be accurate at that point in time. However, the latest
profile spec seems to
define everything as an extension including sv48.

https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc#623-rva22s64-supported-optional-extensions

It may be a redundant effort and confusing to create two sets i.e.
feature and extension in this case.
But this specification is not frozen yet and may change in the future.
We at least know that that is the current intention.

Array of static keys is definitely useful and should be used for all
well defined ISA extensions by the ratified priv spec.
This will simplify this patch as well. For any feature/extensions
(i.e. sv48/sv57) which was never defined as an extension
in the priv spec but profile seems to define it now, I would leave it
alone for the time being. Converting the existing code
to static key probably has value but please do not include it in the
static key array setup.

Once the profile spec is frozen, we can decide which direction the
Linux kernel should go.

> https://lore.kernel.org/linux-riscv/CAHBxVyF65jC_wvxcD6bueqpCY8-Kbahu1yxsSoBmO1s15dGkSQ@mail.gmail.com/
>
> >
> > Another issue with semantics is that this patch assumes all features are
> > enabled by default and we selectively disable it. This contrary to the
> > approach taken by existing arch/riscv/kernel/cpufeature.c which assumes
> > nothing is enabled by default and we selectively enable it.
>
> This is implementation related, can be modified in next version. From
> another side, assuming some feature enabled by default can result in
> trivial performance improvement for most platforms. For example, if
> most platforms are FPU capable, we'd better assume FPU enabled by default.
>
> >
> > >
> > > Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
> > > ---
> > >  arch/riscv/Makefile                 |  3 +
> > >  arch/riscv/include/asm/cpufeature.h | 94 +++++++++++++++++++++++++++++
> > >  arch/riscv/kernel/cpufeature.c      | 23 +++++++
> > >  arch/riscv/tools/Makefile           | 22 +++++++
> > >  arch/riscv/tools/cpucaps            |  5 ++
> > >  arch/riscv/tools/gen-cpucaps.awk    | 40 ++++++++++++
> > >  6 files changed, 187 insertions(+)
> > >  create mode 100644 arch/riscv/include/asm/cpufeature.h
> > >  create mode 100644 arch/riscv/tools/Makefile
> > >  create mode 100644 arch/riscv/tools/cpucaps
> > >  create mode 100755 arch/riscv/tools/gen-cpucaps.awk
> > >
> > > diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
> > > index 7d81102cffd4..f4df67369d84 100644
> > > --- a/arch/riscv/Makefile
> > > +++ b/arch/riscv/Makefile
> > > @@ -154,3 +154,6 @@ PHONY += rv64_randconfig
> > >  rv64_randconfig:
> > >         $(Q)$(MAKE) KCONFIG_ALLCONFIG=$(srctree)/arch/riscv/configs/64-bit.config \
> > >                 -f $(srctree)/Makefile randconfig
> > > +
> > > +archprepare:
> > > +       $(Q)$(MAKE) $(build)=arch/riscv/tools kapi
> > > diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
> > > new file mode 100644
> > > index 000000000000..d80ddd2f3b49
> > > --- /dev/null
> > > +++ b/arch/riscv/include/asm/cpufeature.h
> >
> > We don't need a separate header for this.
> >
> > All this belongs to arch/riscv/include/asm/hwcap.h
> >
> > > @@ -0,0 +1,94 @@
> > > +/* SPDX-License-Identifier: GPL-2.0-only */
> > > +/*
> > > + * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
> > > + * Copyright (C) 2022 Jisheng Zhang <jszhang@kernel.org>
> > > + */
> > > +
> > > +#ifndef __ASM_CPUFEATURE_H
> > > +#define __ASM_CPUFEATURE_H
> > > +
> > > +#include <asm/cpucaps.h>
> > > +
> > > +#include <linux/bug.h>
> > > +#include <linux/jump_label.h>
> > > +#include <linux/kernel.h>
> > > +
> > > +extern DECLARE_BITMAP(cpu_hwcaps, RISCV_NCAPS);
> >
> > This is a redundant bitmap. Please re-use "riscv_isa" bitmap for this
> > the ISA extensions.
> >
> > > +extern struct static_key_false cpu_hwcap_keys[RISCV_NCAPS];
> >
> > This should be called "riscv_isa_keys"
> >
> > > +extern struct static_key_false riscv_const_caps_ready;
> >
> > This should be called "riscv_isa_keys_ready".
> >
> > > +
> > > +static __always_inline bool system_capabilities_finalized(void)
> >
> > Another misaligned name. This should be called
> > "riscv_isa_keys_finalized()".
> >
> > > +{
> > > +       return static_branch_likely(&riscv_const_caps_ready);
> > > +}
> > > +
> > > +/*
> > > + * Test for a capability with a runtime check.
> > > + *
> > > + * Before the capability is detected, this returns false.
> > > + */
> > > +static inline bool cpus_have_cap(unsigned int num)
> > > +{
> > > +       if (num >= RISCV_NCAPS)
> > > +               return false;
> > > +       return test_bit(num, cpu_hwcaps);
> > > +}
> >
> > This should be called riscv_isa_have_extension() and it should
> > internally call "__riscv_isa_extension_available(NULL, num)".
> >
> > > +
> > > +/*
> > > + * Test for a capability without a runtime check.
> > > + *
> > > + * Before capabilities are finalized, this returns false.
> > > + * After capabilities are finalized, this is patched to avoid a runtime check.
> > > + *
> > > + * @num must be a compile-time constant.
> > > + */
> > > +static __always_inline bool __cpus_have_const_cap(int num)
> >
> > This should be named "__riscv_isa_have_const_extension()"
> >
> > > +{
> > > +       if (num >= RISCV_NCAPS)
> > > +               return false;
> > > +       return static_branch_unlikely(&cpu_hwcap_keys[num]);
> > > +}
> > > +
> > > +/*
> > > + * Test for a capability without a runtime check.
> > > + *
> > > + * Before capabilities are finalized, this will BUG().
> > > + * After capabilities are finalized, this is patched to avoid a runtime check.
> > > + *
> > > + * @num must be a compile-time constant.
> > > + */
> > > +static __always_inline bool cpus_have_final_cap(int num)
> >
> > This should be called "riscv_isa_have_final_extension()"
> >
> > > +{
> > > +       if (system_capabilities_finalized())
> > > +               return __cpus_have_const_cap(num);
> > > +       else
> > > +               BUG();
> > > +}
> > > +
> > > +/*
> > > + * Test for a capability, possibly with a runtime check.
> > > + *
> > > + * Before capabilities are finalized, this behaves as cpus_have_cap().
> > > + * After capabilities are finalized, this is patched to avoid a runtime check.
> > > + *
> > > + * @num must be a compile-time constant.
> > > + */
> > > +static __always_inline bool cpus_have_const_cap(int num)
> >
> > Same comment as above.
> >
> > > +{
> > > +       if (system_capabilities_finalized())
> > > +               return __cpus_have_const_cap(num);
> > > +       else
> > > +               return cpus_have_cap(num);
> > > +}
> > > +
> > > +static inline void cpus_set_cap(unsigned int num)
> >
> > Same comment as above.
> >
> > > +{
> > > +       if (num >= RISCV_NCAPS) {
> > > +               pr_warn("Attempt to set an illegal CPU capability (%d >= %d)\n",
> > > +                       num, RISCV_NCAPS);
> > > +       } else {
> > > +               __set_bit(num, cpu_hwcaps);
> > > +       }
> > > +}
> > > +
> > > +#endif
> > > diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> > > index 1b2d42d7f589..e6c72cad0c1c 100644
> > > --- a/arch/riscv/kernel/cpufeature.c
> > > +++ b/arch/riscv/kernel/cpufeature.c
> > > @@ -9,6 +9,7 @@
> > >  #include <linux/bitmap.h>
> > >  #include <linux/ctype.h>
> > >  #include <linux/of.h>
> > > +#include <asm/cpufeature.h>
> > >  #include <asm/processor.h>
> > >  #include <asm/hwcap.h>
> > >  #include <asm/smp.h>
> > > @@ -25,6 +26,15 @@ static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
> > >  __ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_fpu);
> > >  #endif
> > >
> > > +DECLARE_BITMAP(cpu_hwcaps, RISCV_NCAPS);
> > > +EXPORT_SYMBOL(cpu_hwcaps);
> >
> > Just like the previous comment. This is a redundant bitmap.
> > Please use "riscv_isa" bitmap for this purpose.
> >
> > > +
> > > +DEFINE_STATIC_KEY_ARRAY_FALSE(cpu_hwcap_keys, RISCV_NCAPS);
> > > +EXPORT_SYMBOL(cpu_hwcap_keys);
> > > +
> > > +DEFINE_STATIC_KEY_FALSE(riscv_const_caps_ready);
> > > +EXPORT_SYMBOL(riscv_const_caps_ready);
> >
> > Please see comments above.
> >
> > > +
> > >  /**
> > >   * riscv_isa_extension_base() - Get base extension word
> > >   *
> > > @@ -62,6 +72,17 @@ bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, int bit)
> > >  }
> > >  EXPORT_SYMBOL_GPL(__riscv_isa_extension_available);
> > >
> > > +static void __init enable_cpu_capabilities(void)
> > > +{
> > > +       int i;
> > > +
> > > +       for (i = 0; i < RISCV_NCAPS; i++) {
> > > +               if (!cpus_have_cap(i))
> > > +                       continue;
> > > +               static_branch_enable(&cpu_hwcap_keys[i]);
> > > +       }
> > > +}
> > > +
> > >  void __init riscv_fill_hwcap(void)
> > >  {
> > >         struct device_node *node;
> > > @@ -236,4 +257,6 @@ void __init riscv_fill_hwcap(void)
> > >         if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D))
> > >                 static_branch_enable(&cpu_hwcap_fpu);
> > >  #endif
> > > +       enable_cpu_capabilities();
> > > +       static_branch_enable(&riscv_const_caps_ready);
> > >  }
> > > diff --git a/arch/riscv/tools/Makefile b/arch/riscv/tools/Makefile
> > > new file mode 100644
> > > index 000000000000..932b4fe5c768
> > > --- /dev/null
> > > +++ b/arch/riscv/tools/Makefile
> > > @@ -0,0 +1,22 @@
> > > +# SPDX-License-Identifier: GPL-2.0
> > > +
> > > +gen := arch/$(ARCH)/include/generated
> > > +kapi := $(gen)/asm
> > > +
> > > +kapi-hdrs-y := $(kapi)/cpucaps.h
> > > +
> > > +targets += $(addprefix ../../../,$(gen-y) $(kapi-hdrs-y))
> > > +
> > > +PHONY += kapi
> > > +
> > > +kapi:   $(kapi-hdrs-y) $(gen-y)
> > > +
> > > +# Create output directory if not already present
> > > +_dummy := $(shell [ -d '$(kapi)' ] || mkdir -p '$(kapi)')
> > > +
> > > +quiet_cmd_gen_cpucaps = GEN     $@
> > > +      cmd_gen_cpucaps = mkdir -p $(dir $@) && \
> > > +                     $(AWK) -f $(filter-out $(PHONY),$^) > $@
> > > +
> > > +$(kapi)/cpucaps.h: $(src)/gen-cpucaps.awk $(src)/cpucaps FORCE
> > > +       $(call if_changed,gen_cpucaps)
> > > diff --git a/arch/riscv/tools/cpucaps b/arch/riscv/tools/cpucaps
> > > new file mode 100644
> > > index 000000000000..cb1ff2747859
> > > --- /dev/null
> > > +++ b/arch/riscv/tools/cpucaps
> > > @@ -0,0 +1,5 @@
> > > +# SPDX-License-Identifier: GPL-2.0
> > > +#
> > > +# Internal CPU capabilities constants, keep this list sorted
> > > +
> > > +HAS_NO_FPU
> >
> > How can "No FPU" be a CPU capability ?
> >
> > We have ISA extensions 'F' and 'D' which tells us whether an FPU is available
> > or not.
> >
> > I think this file should be a table with two columns
> > "<lower_case_extension_name> <parsed_from_isa_string_yes_no>"
> > I this this file should look like this:
> >
> > i yes
> > m yes
> > a yes
> > c yes
> > f yes
> > d yes
> > h yes
> > sv48 no
> > sv57 no
> > sstc yes
> > svinval yes
> > svpbmt yes
> > svnapot yes
> > sscofpmf yes
> > ...
> >
> > > diff --git a/arch/riscv/tools/gen-cpucaps.awk b/arch/riscv/tools/gen-cpucaps.awk
> > > new file mode 100755
> > > index 000000000000..52a1e1b064ad
> > > --- /dev/null
> > > +++ b/arch/riscv/tools/gen-cpucaps.awk
> > > @@ -0,0 +1,40 @@
> > > +#!/bin/awk -f
> > > +# SPDX-License-Identifier: GPL-2.0
> > > +# gen-cpucaps.awk: riscv cpucaps header generator
> > > +#
> > > +# Usage: awk -f gen-cpucaps.awk cpucaps.txt
> > > +
> > > +# Log an error and terminate
> > > +function fatal(msg) {
> > > +       print "Error at line " NR ": " msg > "/dev/stderr"
> > > +       exit 1
> > > +}
> > > +
> > > +# skip blank lines and comment lines
> > > +/^$/ { next }
> > > +/^#/ { next }
> > > +
> > > +BEGIN {
> > > +       print "#ifndef __ASM_CPUCAPS_H"
> > > +       print "#define __ASM_CPUCAPS_H"
> > > +       print ""
> > > +       print "/* Generated file - do not edit */"
> > > +       cap_num = 0
> > > +       print ""
> > > +}
> > > +
> > > +/^[vA-Z0-9_]+$/ {
> > > +       printf("#define RISCV_%-30s\t%d\n", $0, cap_num++)
> > > +       next
> > > +}
> > > +
> > > +END {
> > > +       printf("#define RISCV_NCAPS\t\t\t\t%d\n", cap_num)
> > > +       print ""
> > > +       print "#endif /* __ASM_CPUCAPS_H */"
> > > +}
> >
> > This script need to change refer capabilities as extensions.
> >
> > For every extension, there should be two defines.
> > For e.g. "sstc" extension should have following defines
> > #define RISCV_ISA_EXT_sstc <#num>
> > #define RISCV_ISA_EXT_FROMSTR_sstc <1|0>
> >
> > > +
> > > +# Any lines not handled by previous rules are unexpected
> > > +{
> > > +       fatal("unhandled statement")
> > > +}
> > > --
> > > 2.34.1
> > >
> >
> > Regards,
> > Anup
>
> _______________________________________________
> linux-riscv mailing list
> linux-riscv@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv



-- 
Regards,
Atish

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 2/4] riscv: introduce unified static key mechanism for CPU features
@ 2022-05-12  6:29         ` Atish Patra
  0 siblings, 0 replies; 36+ messages in thread
From: Atish Patra @ 2022-05-12  6:29 UTC (permalink / raw)
  To: Jisheng Zhang
  Cc: Anup Patel, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Andrey Ryabinin, Alexander Potapenko, Andrey Konovalov,
	Dmitry Vyukov, Vincenzo Frascino, Alexandre Ghiti, linux-riscv,
	linux-kernel@vger.kernel.org List, kasan-dev

On Mon, May 9, 2022 at 7:50 AM Jisheng Zhang <jszhang@kernel.org> wrote:
>
> On Mon, May 09, 2022 at 09:17:10AM +0530, Anup Patel wrote:
> > On Sun, May 8, 2022 at 9:47 PM Jisheng Zhang <jszhang@kernel.org> wrote:
> > >
> > > Currently, riscv has several features why may not be supported on all
> > > riscv platforms, for example, FPU, SV48 and so on. To support unified
> > > kernel Image style, we need to check whether the feature is suportted
> > > or not. If the check sits at hot code path, then performance will be
> > > impacted a lot. static key can be used to solve the issue. In the past
> > > FPU support has been converted to use static key mechanism. I believe
> > > we will have similar cases in the future.
> >
> > It's not just FPU and Sv48. There are several others such as Svinval,
> > Vector, Svnapot, Svpbmt, and many many others.
> >
> > Overall, I agree with the approach of using static key array but I
> > disagree with the semantics and the duplicate stuff being added.
> >
> > Please see more comments below ..
> >
> > >
> > > Similar as arm64 does(in fact, some code is borrowed from arm64), this
> > > patch tries to add an unified mechanism to use static keys for all
> > > the cpu features by implementing an array of default-false static keys
> > > and enabling them when detected. The cpus_have_*_cap() check uses the
> > > static keys if riscv_const_caps_ready is finalized, otherwise the
> > > compiler generates the bitmap test.
> >
> > First of all, we should stop calling this a feature (like ARM does). Rather,
> > we should call these as isa extensions ("isaext") to align with the RISC-V
> > priv spec and RISC-V profiles spec. For all the ISA optionalities which do
> > not have distinct extension name, the RISC-V profiles spec is assigning
> > names to all such optionalities.
>
> Same as the reply a few minutes ago, the key problem here is do all
> CPU features belong to *ISA* extensions? For example, SV48, SV57 etc.
> I agree with Atish's comments here:
>
> "I think the cpu feature is a superset of the ISA extension.
> cpu feature != ISA extension"
>

It seems to be accurate at that point in time. However, the latest
profile spec seems to
define everything as an extension including sv48.

https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc#623-rva22s64-supported-optional-extensions

It may be a redundant effort and confusing to create two sets i.e.
feature and extension in this case.
But this specification is not frozen yet and may change in the future.
We at least know that that is the current intention.

Array of static keys is definitely useful and should be used for all
well defined ISA extensions by the ratified priv spec.
This will simplify this patch as well. For any feature/extensions
(i.e. sv48/sv57) which was never defined as an extension
in the priv spec but profile seems to define it now, I would leave it
alone for the time being. Converting the existing code
to static key probably has value but please do not include it in the
static key array setup.

Once the profile spec is frozen, we can decide which direction the
Linux kernel should go.

> https://lore.kernel.org/linux-riscv/CAHBxVyF65jC_wvxcD6bueqpCY8-Kbahu1yxsSoBmO1s15dGkSQ@mail.gmail.com/
>
> >
> > Another issue with semantics is that this patch assumes all features are
> > enabled by default and we selectively disable it. This contrary to the
> > approach taken by existing arch/riscv/kernel/cpufeature.c which assumes
> > nothing is enabled by default and we selectively enable it.
>
> This is implementation related, can be modified in next version. From
> another side, assuming some feature enabled by default can result in
> trivial performance improvement for most platforms. For example, if
> most platforms are FPU capable, we'd better assume FPU enabled by default.
>
> >
> > >
> > > Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
> > > ---
> > >  arch/riscv/Makefile                 |  3 +
> > >  arch/riscv/include/asm/cpufeature.h | 94 +++++++++++++++++++++++++++++
> > >  arch/riscv/kernel/cpufeature.c      | 23 +++++++
> > >  arch/riscv/tools/Makefile           | 22 +++++++
> > >  arch/riscv/tools/cpucaps            |  5 ++
> > >  arch/riscv/tools/gen-cpucaps.awk    | 40 ++++++++++++
> > >  6 files changed, 187 insertions(+)
> > >  create mode 100644 arch/riscv/include/asm/cpufeature.h
> > >  create mode 100644 arch/riscv/tools/Makefile
> > >  create mode 100644 arch/riscv/tools/cpucaps
> > >  create mode 100755 arch/riscv/tools/gen-cpucaps.awk
> > >
> > > diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
> > > index 7d81102cffd4..f4df67369d84 100644
> > > --- a/arch/riscv/Makefile
> > > +++ b/arch/riscv/Makefile
> > > @@ -154,3 +154,6 @@ PHONY += rv64_randconfig
> > >  rv64_randconfig:
> > >         $(Q)$(MAKE) KCONFIG_ALLCONFIG=$(srctree)/arch/riscv/configs/64-bit.config \
> > >                 -f $(srctree)/Makefile randconfig
> > > +
> > > +archprepare:
> > > +       $(Q)$(MAKE) $(build)=arch/riscv/tools kapi
> > > diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
> > > new file mode 100644
> > > index 000000000000..d80ddd2f3b49
> > > --- /dev/null
> > > +++ b/arch/riscv/include/asm/cpufeature.h
> >
> > We don't need a separate header for this.
> >
> > All this belongs to arch/riscv/include/asm/hwcap.h
> >
> > > @@ -0,0 +1,94 @@
> > > +/* SPDX-License-Identifier: GPL-2.0-only */
> > > +/*
> > > + * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
> > > + * Copyright (C) 2022 Jisheng Zhang <jszhang@kernel.org>
> > > + */
> > > +
> > > +#ifndef __ASM_CPUFEATURE_H
> > > +#define __ASM_CPUFEATURE_H
> > > +
> > > +#include <asm/cpucaps.h>
> > > +
> > > +#include <linux/bug.h>
> > > +#include <linux/jump_label.h>
> > > +#include <linux/kernel.h>
> > > +
> > > +extern DECLARE_BITMAP(cpu_hwcaps, RISCV_NCAPS);
> >
> > This is a redundant bitmap. Please re-use "riscv_isa" bitmap for this
> > the ISA extensions.
> >
> > > +extern struct static_key_false cpu_hwcap_keys[RISCV_NCAPS];
> >
> > This should be called "riscv_isa_keys"
> >
> > > +extern struct static_key_false riscv_const_caps_ready;
> >
> > This should be called "riscv_isa_keys_ready".
> >
> > > +
> > > +static __always_inline bool system_capabilities_finalized(void)
> >
> > Another misaligned name. This should be called
> > "riscv_isa_keys_finalized()".
> >
> > > +{
> > > +       return static_branch_likely(&riscv_const_caps_ready);
> > > +}
> > > +
> > > +/*
> > > + * Test for a capability with a runtime check.
> > > + *
> > > + * Before the capability is detected, this returns false.
> > > + */
> > > +static inline bool cpus_have_cap(unsigned int num)
> > > +{
> > > +       if (num >= RISCV_NCAPS)
> > > +               return false;
> > > +       return test_bit(num, cpu_hwcaps);
> > > +}
> >
> > This should be called riscv_isa_have_extension() and it should
> > internally call "__riscv_isa_extension_available(NULL, num)".
> >
> > > +
> > > +/*
> > > + * Test for a capability without a runtime check.
> > > + *
> > > + * Before capabilities are finalized, this returns false.
> > > + * After capabilities are finalized, this is patched to avoid a runtime check.
> > > + *
> > > + * @num must be a compile-time constant.
> > > + */
> > > +static __always_inline bool __cpus_have_const_cap(int num)
> >
> > This should be named "__riscv_isa_have_const_extension()"
> >
> > > +{
> > > +       if (num >= RISCV_NCAPS)
> > > +               return false;
> > > +       return static_branch_unlikely(&cpu_hwcap_keys[num]);
> > > +}
> > > +
> > > +/*
> > > + * Test for a capability without a runtime check.
> > > + *
> > > + * Before capabilities are finalized, this will BUG().
> > > + * After capabilities are finalized, this is patched to avoid a runtime check.
> > > + *
> > > + * @num must be a compile-time constant.
> > > + */
> > > +static __always_inline bool cpus_have_final_cap(int num)
> >
> > This should be called "riscv_isa_have_final_extension()"
> >
> > > +{
> > > +       if (system_capabilities_finalized())
> > > +               return __cpus_have_const_cap(num);
> > > +       else
> > > +               BUG();
> > > +}
> > > +
> > > +/*
> > > + * Test for a capability, possibly with a runtime check.
> > > + *
> > > + * Before capabilities are finalized, this behaves as cpus_have_cap().
> > > + * After capabilities are finalized, this is patched to avoid a runtime check.
> > > + *
> > > + * @num must be a compile-time constant.
> > > + */
> > > +static __always_inline bool cpus_have_const_cap(int num)
> >
> > Same comment as above.
> >
> > > +{
> > > +       if (system_capabilities_finalized())
> > > +               return __cpus_have_const_cap(num);
> > > +       else
> > > +               return cpus_have_cap(num);
> > > +}
> > > +
> > > +static inline void cpus_set_cap(unsigned int num)
> >
> > Same comment as above.
> >
> > > +{
> > > +       if (num >= RISCV_NCAPS) {
> > > +               pr_warn("Attempt to set an illegal CPU capability (%d >= %d)\n",
> > > +                       num, RISCV_NCAPS);
> > > +       } else {
> > > +               __set_bit(num, cpu_hwcaps);
> > > +       }
> > > +}
> > > +
> > > +#endif
> > > diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> > > index 1b2d42d7f589..e6c72cad0c1c 100644
> > > --- a/arch/riscv/kernel/cpufeature.c
> > > +++ b/arch/riscv/kernel/cpufeature.c
> > > @@ -9,6 +9,7 @@
> > >  #include <linux/bitmap.h>
> > >  #include <linux/ctype.h>
> > >  #include <linux/of.h>
> > > +#include <asm/cpufeature.h>
> > >  #include <asm/processor.h>
> > >  #include <asm/hwcap.h>
> > >  #include <asm/smp.h>
> > > @@ -25,6 +26,15 @@ static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
> > >  __ro_after_init DEFINE_STATIC_KEY_FALSE(cpu_hwcap_fpu);
> > >  #endif
> > >
> > > +DECLARE_BITMAP(cpu_hwcaps, RISCV_NCAPS);
> > > +EXPORT_SYMBOL(cpu_hwcaps);
> >
> > Just like the previous comment. This is a redundant bitmap.
> > Please use "riscv_isa" bitmap for this purpose.
> >
> > > +
> > > +DEFINE_STATIC_KEY_ARRAY_FALSE(cpu_hwcap_keys, RISCV_NCAPS);
> > > +EXPORT_SYMBOL(cpu_hwcap_keys);
> > > +
> > > +DEFINE_STATIC_KEY_FALSE(riscv_const_caps_ready);
> > > +EXPORT_SYMBOL(riscv_const_caps_ready);
> >
> > Please see comments above.
> >
> > > +
> > >  /**
> > >   * riscv_isa_extension_base() - Get base extension word
> > >   *
> > > @@ -62,6 +72,17 @@ bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, int bit)
> > >  }
> > >  EXPORT_SYMBOL_GPL(__riscv_isa_extension_available);
> > >
> > > +static void __init enable_cpu_capabilities(void)
> > > +{
> > > +       int i;
> > > +
> > > +       for (i = 0; i < RISCV_NCAPS; i++) {
> > > +               if (!cpus_have_cap(i))
> > > +                       continue;
> > > +               static_branch_enable(&cpu_hwcap_keys[i]);
> > > +       }
> > > +}
> > > +
> > >  void __init riscv_fill_hwcap(void)
> > >  {
> > >         struct device_node *node;
> > > @@ -236,4 +257,6 @@ void __init riscv_fill_hwcap(void)
> > >         if (elf_hwcap & (COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D))
> > >                 static_branch_enable(&cpu_hwcap_fpu);
> > >  #endif
> > > +       enable_cpu_capabilities();
> > > +       static_branch_enable(&riscv_const_caps_ready);
> > >  }
> > > diff --git a/arch/riscv/tools/Makefile b/arch/riscv/tools/Makefile
> > > new file mode 100644
> > > index 000000000000..932b4fe5c768
> > > --- /dev/null
> > > +++ b/arch/riscv/tools/Makefile
> > > @@ -0,0 +1,22 @@
> > > +# SPDX-License-Identifier: GPL-2.0
> > > +
> > > +gen := arch/$(ARCH)/include/generated
> > > +kapi := $(gen)/asm
> > > +
> > > +kapi-hdrs-y := $(kapi)/cpucaps.h
> > > +
> > > +targets += $(addprefix ../../../,$(gen-y) $(kapi-hdrs-y))
> > > +
> > > +PHONY += kapi
> > > +
> > > +kapi:   $(kapi-hdrs-y) $(gen-y)
> > > +
> > > +# Create output directory if not already present
> > > +_dummy := $(shell [ -d '$(kapi)' ] || mkdir -p '$(kapi)')
> > > +
> > > +quiet_cmd_gen_cpucaps = GEN     $@
> > > +      cmd_gen_cpucaps = mkdir -p $(dir $@) && \
> > > +                     $(AWK) -f $(filter-out $(PHONY),$^) > $@
> > > +
> > > +$(kapi)/cpucaps.h: $(src)/gen-cpucaps.awk $(src)/cpucaps FORCE
> > > +       $(call if_changed,gen_cpucaps)
> > > diff --git a/arch/riscv/tools/cpucaps b/arch/riscv/tools/cpucaps
> > > new file mode 100644
> > > index 000000000000..cb1ff2747859
> > > --- /dev/null
> > > +++ b/arch/riscv/tools/cpucaps
> > > @@ -0,0 +1,5 @@
> > > +# SPDX-License-Identifier: GPL-2.0
> > > +#
> > > +# Internal CPU capabilities constants, keep this list sorted
> > > +
> > > +HAS_NO_FPU
> >
> > How can "No FPU" be a CPU capability ?
> >
> > We have ISA extensions 'F' and 'D' which tells us whether an FPU is available
> > or not.
> >
> > I think this file should be a table with two columns
> > "<lower_case_extension_name> <parsed_from_isa_string_yes_no>"
> > I this this file should look like this:
> >
> > i yes
> > m yes
> > a yes
> > c yes
> > f yes
> > d yes
> > h yes
> > sv48 no
> > sv57 no
> > sstc yes
> > svinval yes
> > svpbmt yes
> > svnapot yes
> > sscofpmf yes
> > ...
> >
> > > diff --git a/arch/riscv/tools/gen-cpucaps.awk b/arch/riscv/tools/gen-cpucaps.awk
> > > new file mode 100755
> > > index 000000000000..52a1e1b064ad
> > > --- /dev/null
> > > +++ b/arch/riscv/tools/gen-cpucaps.awk
> > > @@ -0,0 +1,40 @@
> > > +#!/bin/awk -f
> > > +# SPDX-License-Identifier: GPL-2.0
> > > +# gen-cpucaps.awk: riscv cpucaps header generator
> > > +#
> > > +# Usage: awk -f gen-cpucaps.awk cpucaps.txt
> > > +
> > > +# Log an error and terminate
> > > +function fatal(msg) {
> > > +       print "Error at line " NR ": " msg > "/dev/stderr"
> > > +       exit 1
> > > +}
> > > +
> > > +# skip blank lines and comment lines
> > > +/^$/ { next }
> > > +/^#/ { next }
> > > +
> > > +BEGIN {
> > > +       print "#ifndef __ASM_CPUCAPS_H"
> > > +       print "#define __ASM_CPUCAPS_H"
> > > +       print ""
> > > +       print "/* Generated file - do not edit */"
> > > +       cap_num = 0
> > > +       print ""
> > > +}
> > > +
> > > +/^[vA-Z0-9_]+$/ {
> > > +       printf("#define RISCV_%-30s\t%d\n", $0, cap_num++)
> > > +       next
> > > +}
> > > +
> > > +END {
> > > +       printf("#define RISCV_NCAPS\t\t\t\t%d\n", cap_num)
> > > +       print ""
> > > +       print "#endif /* __ASM_CPUCAPS_H */"
> > > +}
> >
> > This script need to change refer capabilities as extensions.
> >
> > For every extension, there should be two defines.
> > For e.g. "sstc" extension should have following defines
> > #define RISCV_ISA_EXT_sstc <#num>
> > #define RISCV_ISA_EXT_FROMSTR_sstc <1|0>
> >
> > > +
> > > +# Any lines not handled by previous rules are unexpected
> > > +{
> > > +       fatal("unhandled statement")
> > > +}
> > > --
> > > 2.34.1
> > >
> >
> > Regards,
> > Anup
>
> _______________________________________________
> linux-riscv mailing list
> linux-riscv@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv



-- 
Regards,
Atish

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

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 2/4] riscv: introduce unified static key mechanism for CPU features
  2022-05-12  6:29         ` Atish Patra
@ 2022-05-15  7:15           ` Jisheng Zhang
  -1 siblings, 0 replies; 36+ messages in thread
From: Jisheng Zhang @ 2022-05-15  7:15 UTC (permalink / raw)
  To: Atish Patra
  Cc: Anup Patel, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Andrey Ryabinin, Alexander Potapenko, Andrey Konovalov,
	Dmitry Vyukov, Vincenzo Frascino, Alexandre Ghiti, linux-riscv,
	linux-kernel@vger.kernel.org List, kasan-dev

On Wed, May 11, 2022 at 11:29:32PM -0700, Atish Patra wrote:
> On Mon, May 9, 2022 at 7:50 AM Jisheng Zhang <jszhang@kernel.org> wrote:
> >
> > On Mon, May 09, 2022 at 09:17:10AM +0530, Anup Patel wrote:
> > > On Sun, May 8, 2022 at 9:47 PM Jisheng Zhang <jszhang@kernel.org> wrote:
> > > >
> > > > Currently, riscv has several features why may not be supported on all
> > > > riscv platforms, for example, FPU, SV48 and so on. To support unified
> > > > kernel Image style, we need to check whether the feature is suportted
> > > > or not. If the check sits at hot code path, then performance will be
> > > > impacted a lot. static key can be used to solve the issue. In the past
> > > > FPU support has been converted to use static key mechanism. I believe
> > > > we will have similar cases in the future.
> > >
> > > It's not just FPU and Sv48. There are several others such as Svinval,
> > > Vector, Svnapot, Svpbmt, and many many others.
> > >
> > > Overall, I agree with the approach of using static key array but I
> > > disagree with the semantics and the duplicate stuff being added.
> > >
> > > Please see more comments below ..
> > >
> > > >
> > > > Similar as arm64 does(in fact, some code is borrowed from arm64), this
> > > > patch tries to add an unified mechanism to use static keys for all
> > > > the cpu features by implementing an array of default-false static keys
> > > > and enabling them when detected. The cpus_have_*_cap() check uses the
> > > > static keys if riscv_const_caps_ready is finalized, otherwise the
> > > > compiler generates the bitmap test.
> > >
> > > First of all, we should stop calling this a feature (like ARM does). Rather,
> > > we should call these as isa extensions ("isaext") to align with the RISC-V
> > > priv spec and RISC-V profiles spec. For all the ISA optionalities which do
> > > not have distinct extension name, the RISC-V profiles spec is assigning
> > > names to all such optionalities.
> >
> > Same as the reply a few minutes ago, the key problem here is do all
> > CPU features belong to *ISA* extensions? For example, SV48, SV57 etc.
> > I agree with Atish's comments here:
> >
> > "I think the cpu feature is a superset of the ISA extension.
> > cpu feature != ISA extension"
> >
> 
> It seems to be accurate at that point in time. However, the latest
> profile spec seems to
> define everything as an extension including sv48.
> 
> https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc#623-rva22s64-supported-optional-extensions
> 
> It may be a redundant effort and confusing to create two sets i.e.
> feature and extension in this case.
> But this specification is not frozen yet and may change in the future.
> We at least know that that is the current intention.
> 
> Array of static keys is definitely useful and should be used for all
> well defined ISA extensions by the ratified priv spec.
> This will simplify this patch as well. For any feature/extensions
> (i.e. sv48/sv57) which was never defined as an extension
> in the priv spec but profile seems to define it now, I would leave it
> alone for the time being. Converting the existing code
> to static key probably has value but please do not include it in the
> static key array setup.
> 
> Once the profile spec is frozen, we can decide which direction the
> Linux kernel should go.
>

Hi Atish, Anup,

I see your points and thanks for the information of the profile
spec. Now, I have other two points about isa VS features:

1. Not all isa extenstions need static key mechanism, so if we
make a static key array with 1:1 riscv_isa <-> static key relationship
there may be waste.

For example, the 'a', 'c', 'i', 'm' and so on don't have static
key usage.

2.We may need riscv architecture static keys for non-isa, this is
usually related with the linux os itself, for example
a static key for "unmap kernelspace at userspace".
static keys for "spectre CVE mitigations"
etc.

In summary, I can see riscv_isa doesn't cover features which need static
keys, and vice vesa.

Could you please comment?

Thanks in advance,
Jisheng

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 2/4] riscv: introduce unified static key mechanism for CPU features
@ 2022-05-15  7:15           ` Jisheng Zhang
  0 siblings, 0 replies; 36+ messages in thread
From: Jisheng Zhang @ 2022-05-15  7:15 UTC (permalink / raw)
  To: Atish Patra
  Cc: Anup Patel, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Andrey Ryabinin, Alexander Potapenko, Andrey Konovalov,
	Dmitry Vyukov, Vincenzo Frascino, Alexandre Ghiti, linux-riscv,
	linux-kernel@vger.kernel.org List, kasan-dev

On Wed, May 11, 2022 at 11:29:32PM -0700, Atish Patra wrote:
> On Mon, May 9, 2022 at 7:50 AM Jisheng Zhang <jszhang@kernel.org> wrote:
> >
> > On Mon, May 09, 2022 at 09:17:10AM +0530, Anup Patel wrote:
> > > On Sun, May 8, 2022 at 9:47 PM Jisheng Zhang <jszhang@kernel.org> wrote:
> > > >
> > > > Currently, riscv has several features why may not be supported on all
> > > > riscv platforms, for example, FPU, SV48 and so on. To support unified
> > > > kernel Image style, we need to check whether the feature is suportted
> > > > or not. If the check sits at hot code path, then performance will be
> > > > impacted a lot. static key can be used to solve the issue. In the past
> > > > FPU support has been converted to use static key mechanism. I believe
> > > > we will have similar cases in the future.
> > >
> > > It's not just FPU and Sv48. There are several others such as Svinval,
> > > Vector, Svnapot, Svpbmt, and many many others.
> > >
> > > Overall, I agree with the approach of using static key array but I
> > > disagree with the semantics and the duplicate stuff being added.
> > >
> > > Please see more comments below ..
> > >
> > > >
> > > > Similar as arm64 does(in fact, some code is borrowed from arm64), this
> > > > patch tries to add an unified mechanism to use static keys for all
> > > > the cpu features by implementing an array of default-false static keys
> > > > and enabling them when detected. The cpus_have_*_cap() check uses the
> > > > static keys if riscv_const_caps_ready is finalized, otherwise the
> > > > compiler generates the bitmap test.
> > >
> > > First of all, we should stop calling this a feature (like ARM does). Rather,
> > > we should call these as isa extensions ("isaext") to align with the RISC-V
> > > priv spec and RISC-V profiles spec. For all the ISA optionalities which do
> > > not have distinct extension name, the RISC-V profiles spec is assigning
> > > names to all such optionalities.
> >
> > Same as the reply a few minutes ago, the key problem here is do all
> > CPU features belong to *ISA* extensions? For example, SV48, SV57 etc.
> > I agree with Atish's comments here:
> >
> > "I think the cpu feature is a superset of the ISA extension.
> > cpu feature != ISA extension"
> >
> 
> It seems to be accurate at that point in time. However, the latest
> profile spec seems to
> define everything as an extension including sv48.
> 
> https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc#623-rva22s64-supported-optional-extensions
> 
> It may be a redundant effort and confusing to create two sets i.e.
> feature and extension in this case.
> But this specification is not frozen yet and may change in the future.
> We at least know that that is the current intention.
> 
> Array of static keys is definitely useful and should be used for all
> well defined ISA extensions by the ratified priv spec.
> This will simplify this patch as well. For any feature/extensions
> (i.e. sv48/sv57) which was never defined as an extension
> in the priv spec but profile seems to define it now, I would leave it
> alone for the time being. Converting the existing code
> to static key probably has value but please do not include it in the
> static key array setup.
> 
> Once the profile spec is frozen, we can decide which direction the
> Linux kernel should go.
>

Hi Atish, Anup,

I see your points and thanks for the information of the profile
spec. Now, I have other two points about isa VS features:

1. Not all isa extenstions need static key mechanism, so if we
make a static key array with 1:1 riscv_isa <-> static key relationship
there may be waste.

For example, the 'a', 'c', 'i', 'm' and so on don't have static
key usage.

2.We may need riscv architecture static keys for non-isa, this is
usually related with the linux os itself, for example
a static key for "unmap kernelspace at userspace".
static keys for "spectre CVE mitigations"
etc.

In summary, I can see riscv_isa doesn't cover features which need static
keys, and vice vesa.

Could you please comment?

Thanks in advance,
Jisheng

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

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 2/4] riscv: introduce unified static key mechanism for CPU features
  2022-05-15  7:15           ` Jisheng Zhang
@ 2022-05-15 14:49             ` Anup Patel
  -1 siblings, 0 replies; 36+ messages in thread
From: Anup Patel @ 2022-05-15 14:49 UTC (permalink / raw)
  To: Jisheng Zhang
  Cc: Atish Patra, Anup Patel, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Andrey Ryabinin, Alexander Potapenko,
	Andrey Konovalov, Dmitry Vyukov, Vincenzo Frascino,
	Alexandre Ghiti, linux-riscv, linux-kernel@vger.kernel.org List,
	kasan-dev

On Sun, May 15, 2022 at 12:54 PM Jisheng Zhang <jszhang@kernel.org> wrote:
>
> On Wed, May 11, 2022 at 11:29:32PM -0700, Atish Patra wrote:
> > On Mon, May 9, 2022 at 7:50 AM Jisheng Zhang <jszhang@kernel.org> wrote:
> > >
> > > On Mon, May 09, 2022 at 09:17:10AM +0530, Anup Patel wrote:
> > > > On Sun, May 8, 2022 at 9:47 PM Jisheng Zhang <jszhang@kernel.org> wrote:
> > > > >
> > > > > Currently, riscv has several features why may not be supported on all
> > > > > riscv platforms, for example, FPU, SV48 and so on. To support unified
> > > > > kernel Image style, we need to check whether the feature is suportted
> > > > > or not. If the check sits at hot code path, then performance will be
> > > > > impacted a lot. static key can be used to solve the issue. In the past
> > > > > FPU support has been converted to use static key mechanism. I believe
> > > > > we will have similar cases in the future.
> > > >
> > > > It's not just FPU and Sv48. There are several others such as Svinval,
> > > > Vector, Svnapot, Svpbmt, and many many others.
> > > >
> > > > Overall, I agree with the approach of using static key array but I
> > > > disagree with the semantics and the duplicate stuff being added.
> > > >
> > > > Please see more comments below ..
> > > >
> > > > >
> > > > > Similar as arm64 does(in fact, some code is borrowed from arm64), this
> > > > > patch tries to add an unified mechanism to use static keys for all
> > > > > the cpu features by implementing an array of default-false static keys
> > > > > and enabling them when detected. The cpus_have_*_cap() check uses the
> > > > > static keys if riscv_const_caps_ready is finalized, otherwise the
> > > > > compiler generates the bitmap test.
> > > >
> > > > First of all, we should stop calling this a feature (like ARM does). Rather,
> > > > we should call these as isa extensions ("isaext") to align with the RISC-V
> > > > priv spec and RISC-V profiles spec. For all the ISA optionalities which do
> > > > not have distinct extension name, the RISC-V profiles spec is assigning
> > > > names to all such optionalities.
> > >
> > > Same as the reply a few minutes ago, the key problem here is do all
> > > CPU features belong to *ISA* extensions? For example, SV48, SV57 etc.
> > > I agree with Atish's comments here:
> > >
> > > "I think the cpu feature is a superset of the ISA extension.
> > > cpu feature != ISA extension"
> > >
> >
> > It seems to be accurate at that point in time. However, the latest
> > profile spec seems to
> > define everything as an extension including sv48.
> >
> > https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc#623-rva22s64-supported-optional-extensions
> >
> > It may be a redundant effort and confusing to create two sets i.e.
> > feature and extension in this case.
> > But this specification is not frozen yet and may change in the future.
> > We at least know that that is the current intention.
> >
> > Array of static keys is definitely useful and should be used for all
> > well defined ISA extensions by the ratified priv spec.
> > This will simplify this patch as well. For any feature/extensions
> > (i.e. sv48/sv57) which was never defined as an extension
> > in the priv spec but profile seems to define it now, I would leave it
> > alone for the time being. Converting the existing code
> > to static key probably has value but please do not include it in the
> > static key array setup.
> >
> > Once the profile spec is frozen, we can decide which direction the
> > Linux kernel should go.
> >
>
> Hi Atish, Anup,
>
> I see your points and thanks for the information of the profile
> spec. Now, I have other two points about isa VS features:
>
> 1. Not all isa extenstions need static key mechanism, so if we
> make a static key array with 1:1 riscv_isa <-> static key relationship
> there may be waste.
>
> For example, the 'a', 'c', 'i', 'm' and so on don't have static
> key usage.

Not all isa extensions but a large number of them will need a static
key. It's better to always have one static key per ISA extension
defined in cpufeatures.c

For example, F, D, V, Sstc, Svinval, Ssofpmt, Zb*, AIA, etc.

>
> 2.We may need riscv architecture static keys for non-isa, this is
> usually related with the linux os itself, for example
> a static key for "unmap kernelspace at userspace".
> static keys for "spectre CVE mitigations"
> etc.

These things look more like errata or workarounds so better
to use that framework instead of ISA extensions (or features).

Some of these things might even use ALTERNATIVEs instead
of static keys.

>
> In summary, I can see riscv_isa doesn't cover features which need static
> keys, and vice vesa.
>
> Could you please comment?
>
> Thanks in advance,
> Jisheng

Regards,
Anup

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 2/4] riscv: introduce unified static key mechanism for CPU features
@ 2022-05-15 14:49             ` Anup Patel
  0 siblings, 0 replies; 36+ messages in thread
From: Anup Patel @ 2022-05-15 14:49 UTC (permalink / raw)
  To: Jisheng Zhang
  Cc: Atish Patra, Anup Patel, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Andrey Ryabinin, Alexander Potapenko,
	Andrey Konovalov, Dmitry Vyukov, Vincenzo Frascino,
	Alexandre Ghiti, linux-riscv, linux-kernel@vger.kernel.org List,
	kasan-dev

On Sun, May 15, 2022 at 12:54 PM Jisheng Zhang <jszhang@kernel.org> wrote:
>
> On Wed, May 11, 2022 at 11:29:32PM -0700, Atish Patra wrote:
> > On Mon, May 9, 2022 at 7:50 AM Jisheng Zhang <jszhang@kernel.org> wrote:
> > >
> > > On Mon, May 09, 2022 at 09:17:10AM +0530, Anup Patel wrote:
> > > > On Sun, May 8, 2022 at 9:47 PM Jisheng Zhang <jszhang@kernel.org> wrote:
> > > > >
> > > > > Currently, riscv has several features why may not be supported on all
> > > > > riscv platforms, for example, FPU, SV48 and so on. To support unified
> > > > > kernel Image style, we need to check whether the feature is suportted
> > > > > or not. If the check sits at hot code path, then performance will be
> > > > > impacted a lot. static key can be used to solve the issue. In the past
> > > > > FPU support has been converted to use static key mechanism. I believe
> > > > > we will have similar cases in the future.
> > > >
> > > > It's not just FPU and Sv48. There are several others such as Svinval,
> > > > Vector, Svnapot, Svpbmt, and many many others.
> > > >
> > > > Overall, I agree with the approach of using static key array but I
> > > > disagree with the semantics and the duplicate stuff being added.
> > > >
> > > > Please see more comments below ..
> > > >
> > > > >
> > > > > Similar as arm64 does(in fact, some code is borrowed from arm64), this
> > > > > patch tries to add an unified mechanism to use static keys for all
> > > > > the cpu features by implementing an array of default-false static keys
> > > > > and enabling them when detected. The cpus_have_*_cap() check uses the
> > > > > static keys if riscv_const_caps_ready is finalized, otherwise the
> > > > > compiler generates the bitmap test.
> > > >
> > > > First of all, we should stop calling this a feature (like ARM does). Rather,
> > > > we should call these as isa extensions ("isaext") to align with the RISC-V
> > > > priv spec and RISC-V profiles spec. For all the ISA optionalities which do
> > > > not have distinct extension name, the RISC-V profiles spec is assigning
> > > > names to all such optionalities.
> > >
> > > Same as the reply a few minutes ago, the key problem here is do all
> > > CPU features belong to *ISA* extensions? For example, SV48, SV57 etc.
> > > I agree with Atish's comments here:
> > >
> > > "I think the cpu feature is a superset of the ISA extension.
> > > cpu feature != ISA extension"
> > >
> >
> > It seems to be accurate at that point in time. However, the latest
> > profile spec seems to
> > define everything as an extension including sv48.
> >
> > https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc#623-rva22s64-supported-optional-extensions
> >
> > It may be a redundant effort and confusing to create two sets i.e.
> > feature and extension in this case.
> > But this specification is not frozen yet and may change in the future.
> > We at least know that that is the current intention.
> >
> > Array of static keys is definitely useful and should be used for all
> > well defined ISA extensions by the ratified priv spec.
> > This will simplify this patch as well. For any feature/extensions
> > (i.e. sv48/sv57) which was never defined as an extension
> > in the priv spec but profile seems to define it now, I would leave it
> > alone for the time being. Converting the existing code
> > to static key probably has value but please do not include it in the
> > static key array setup.
> >
> > Once the profile spec is frozen, we can decide which direction the
> > Linux kernel should go.
> >
>
> Hi Atish, Anup,
>
> I see your points and thanks for the information of the profile
> spec. Now, I have other two points about isa VS features:
>
> 1. Not all isa extenstions need static key mechanism, so if we
> make a static key array with 1:1 riscv_isa <-> static key relationship
> there may be waste.
>
> For example, the 'a', 'c', 'i', 'm' and so on don't have static
> key usage.

Not all isa extensions but a large number of them will need a static
key. It's better to always have one static key per ISA extension
defined in cpufeatures.c

For example, F, D, V, Sstc, Svinval, Ssofpmt, Zb*, AIA, etc.

>
> 2.We may need riscv architecture static keys for non-isa, this is
> usually related with the linux os itself, for example
> a static key for "unmap kernelspace at userspace".
> static keys for "spectre CVE mitigations"
> etc.

These things look more like errata or workarounds so better
to use that framework instead of ISA extensions (or features).

Some of these things might even use ALTERNATIVEs instead
of static keys.

>
> In summary, I can see riscv_isa doesn't cover features which need static
> keys, and vice vesa.
>
> Could you please comment?
>
> Thanks in advance,
> Jisheng

Regards,
Anup

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

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 2/4] riscv: introduce unified static key mechanism for CPU features
  2022-05-15 14:49             ` Anup Patel
@ 2022-05-16 17:24               ` Jisheng Zhang
  -1 siblings, 0 replies; 36+ messages in thread
From: Jisheng Zhang @ 2022-05-16 17:24 UTC (permalink / raw)
  To: Anup Patel
  Cc: Atish Patra, Anup Patel, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Andrey Ryabinin, Alexander Potapenko,
	Andrey Konovalov, Dmitry Vyukov, Vincenzo Frascino,
	Alexandre Ghiti, linux-riscv, linux-kernel@vger.kernel.org List,
	kasan-dev

On Sun, May 15, 2022 at 08:19:37PM +0530, Anup Patel wrote:
> On Sun, May 15, 2022 at 12:54 PM Jisheng Zhang <jszhang@kernel.org> wrote:
> >
> > On Wed, May 11, 2022 at 11:29:32PM -0700, Atish Patra wrote:
> > > On Mon, May 9, 2022 at 7:50 AM Jisheng Zhang <jszhang@kernel.org> wrote:
> > > >
> > > > On Mon, May 09, 2022 at 09:17:10AM +0530, Anup Patel wrote:
> > > > > On Sun, May 8, 2022 at 9:47 PM Jisheng Zhang <jszhang@kernel.org> wrote:
> > > > > >
> > > > > > Currently, riscv has several features why may not be supported on all
> > > > > > riscv platforms, for example, FPU, SV48 and so on. To support unified
> > > > > > kernel Image style, we need to check whether the feature is suportted
> > > > > > or not. If the check sits at hot code path, then performance will be
> > > > > > impacted a lot. static key can be used to solve the issue. In the past
> > > > > > FPU support has been converted to use static key mechanism. I believe
> > > > > > we will have similar cases in the future.
> > > > >
> > > > > It's not just FPU and Sv48. There are several others such as Svinval,
> > > > > Vector, Svnapot, Svpbmt, and many many others.
> > > > >
> > > > > Overall, I agree with the approach of using static key array but I
> > > > > disagree with the semantics and the duplicate stuff being added.
> > > > >
> > > > > Please see more comments below ..
> > > > >
> > > > > >
> > > > > > Similar as arm64 does(in fact, some code is borrowed from arm64), this
> > > > > > patch tries to add an unified mechanism to use static keys for all
> > > > > > the cpu features by implementing an array of default-false static keys
> > > > > > and enabling them when detected. The cpus_have_*_cap() check uses the
> > > > > > static keys if riscv_const_caps_ready is finalized, otherwise the
> > > > > > compiler generates the bitmap test.
> > > > >
> > > > > First of all, we should stop calling this a feature (like ARM does). Rather,
> > > > > we should call these as isa extensions ("isaext") to align with the RISC-V
> > > > > priv spec and RISC-V profiles spec. For all the ISA optionalities which do
> > > > > not have distinct extension name, the RISC-V profiles spec is assigning
> > > > > names to all such optionalities.
> > > >
> > > > Same as the reply a few minutes ago, the key problem here is do all
> > > > CPU features belong to *ISA* extensions? For example, SV48, SV57 etc.
> > > > I agree with Atish's comments here:
> > > >
> > > > "I think the cpu feature is a superset of the ISA extension.
> > > > cpu feature != ISA extension"
> > > >
> > >
> > > It seems to be accurate at that point in time. However, the latest
> > > profile spec seems to
> > > define everything as an extension including sv48.
> > >
> > > https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc#623-rva22s64-supported-optional-extensions
> > >
> > > It may be a redundant effort and confusing to create two sets i.e.
> > > feature and extension in this case.
> > > But this specification is not frozen yet and may change in the future.
> > > We at least know that that is the current intention.
> > >
> > > Array of static keys is definitely useful and should be used for all
> > > well defined ISA extensions by the ratified priv spec.
> > > This will simplify this patch as well. For any feature/extensions
> > > (i.e. sv48/sv57) which was never defined as an extension
> > > in the priv spec but profile seems to define it now, I would leave it
> > > alone for the time being. Converting the existing code
> > > to static key probably has value but please do not include it in the
> > > static key array setup.
> > >
> > > Once the profile spec is frozen, we can decide which direction the
> > > Linux kernel should go.
> > >
> >
> > Hi Atish, Anup,
> >
> > I see your points and thanks for the information of the profile
> > spec. Now, I have other two points about isa VS features:
> >
> > 1. Not all isa extenstions need static key mechanism, so if we
> > make a static key array with 1:1 riscv_isa <-> static key relationship
> > there may be waste.
> >
> > For example, the 'a', 'c', 'i', 'm' and so on don't have static
> > key usage.
> 
> Not all isa extensions but a large number of them will need a static
> key. It's better to always have one static key per ISA extension
> defined in cpufeatures.c

Currently, RISCV_ISA_EXT_MAX equals to 64 while the base ID is 26.
In those 26 base IDs, only F/D and V need static key, it means
we waste at least 24 static keys.

> 
> For example, F, D, V, Sstc, Svinval, Ssofpmt, Zb*, AIA, etc.
> 
> >
> > 2.We may need riscv architecture static keys for non-isa, this is
> > usually related with the linux os itself, for example
> > a static key for "unmap kernelspace at userspace".
> > static keys for "spectre CVE mitigations"
> > etc.
> 
> These things look more like errata or workarounds so better
> to use that framework instead of ISA extensions (or features).

Currently, the errata workarounds are implemented with ALTERNATIVEs
but I believe sometime we may need static key to implement the
workarounds. However this can be checked later. Now I worried about
the static key waste above.

Thanks

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 2/4] riscv: introduce unified static key mechanism for CPU features
@ 2022-05-16 17:24               ` Jisheng Zhang
  0 siblings, 0 replies; 36+ messages in thread
From: Jisheng Zhang @ 2022-05-16 17:24 UTC (permalink / raw)
  To: Anup Patel
  Cc: Atish Patra, Anup Patel, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Andrey Ryabinin, Alexander Potapenko,
	Andrey Konovalov, Dmitry Vyukov, Vincenzo Frascino,
	Alexandre Ghiti, linux-riscv, linux-kernel@vger.kernel.org List,
	kasan-dev

On Sun, May 15, 2022 at 08:19:37PM +0530, Anup Patel wrote:
> On Sun, May 15, 2022 at 12:54 PM Jisheng Zhang <jszhang@kernel.org> wrote:
> >
> > On Wed, May 11, 2022 at 11:29:32PM -0700, Atish Patra wrote:
> > > On Mon, May 9, 2022 at 7:50 AM Jisheng Zhang <jszhang@kernel.org> wrote:
> > > >
> > > > On Mon, May 09, 2022 at 09:17:10AM +0530, Anup Patel wrote:
> > > > > On Sun, May 8, 2022 at 9:47 PM Jisheng Zhang <jszhang@kernel.org> wrote:
> > > > > >
> > > > > > Currently, riscv has several features why may not be supported on all
> > > > > > riscv platforms, for example, FPU, SV48 and so on. To support unified
> > > > > > kernel Image style, we need to check whether the feature is suportted
> > > > > > or not. If the check sits at hot code path, then performance will be
> > > > > > impacted a lot. static key can be used to solve the issue. In the past
> > > > > > FPU support has been converted to use static key mechanism. I believe
> > > > > > we will have similar cases in the future.
> > > > >
> > > > > It's not just FPU and Sv48. There are several others such as Svinval,
> > > > > Vector, Svnapot, Svpbmt, and many many others.
> > > > >
> > > > > Overall, I agree with the approach of using static key array but I
> > > > > disagree with the semantics and the duplicate stuff being added.
> > > > >
> > > > > Please see more comments below ..
> > > > >
> > > > > >
> > > > > > Similar as arm64 does(in fact, some code is borrowed from arm64), this
> > > > > > patch tries to add an unified mechanism to use static keys for all
> > > > > > the cpu features by implementing an array of default-false static keys
> > > > > > and enabling them when detected. The cpus_have_*_cap() check uses the
> > > > > > static keys if riscv_const_caps_ready is finalized, otherwise the
> > > > > > compiler generates the bitmap test.
> > > > >
> > > > > First of all, we should stop calling this a feature (like ARM does). Rather,
> > > > > we should call these as isa extensions ("isaext") to align with the RISC-V
> > > > > priv spec and RISC-V profiles spec. For all the ISA optionalities which do
> > > > > not have distinct extension name, the RISC-V profiles spec is assigning
> > > > > names to all such optionalities.
> > > >
> > > > Same as the reply a few minutes ago, the key problem here is do all
> > > > CPU features belong to *ISA* extensions? For example, SV48, SV57 etc.
> > > > I agree with Atish's comments here:
> > > >
> > > > "I think the cpu feature is a superset of the ISA extension.
> > > > cpu feature != ISA extension"
> > > >
> > >
> > > It seems to be accurate at that point in time. However, the latest
> > > profile spec seems to
> > > define everything as an extension including sv48.
> > >
> > > https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc#623-rva22s64-supported-optional-extensions
> > >
> > > It may be a redundant effort and confusing to create two sets i.e.
> > > feature and extension in this case.
> > > But this specification is not frozen yet and may change in the future.
> > > We at least know that that is the current intention.
> > >
> > > Array of static keys is definitely useful and should be used for all
> > > well defined ISA extensions by the ratified priv spec.
> > > This will simplify this patch as well. For any feature/extensions
> > > (i.e. sv48/sv57) which was never defined as an extension
> > > in the priv spec but profile seems to define it now, I would leave it
> > > alone for the time being. Converting the existing code
> > > to static key probably has value but please do not include it in the
> > > static key array setup.
> > >
> > > Once the profile spec is frozen, we can decide which direction the
> > > Linux kernel should go.
> > >
> >
> > Hi Atish, Anup,
> >
> > I see your points and thanks for the information of the profile
> > spec. Now, I have other two points about isa VS features:
> >
> > 1. Not all isa extenstions need static key mechanism, so if we
> > make a static key array with 1:1 riscv_isa <-> static key relationship
> > there may be waste.
> >
> > For example, the 'a', 'c', 'i', 'm' and so on don't have static
> > key usage.
> 
> Not all isa extensions but a large number of them will need a static
> key. It's better to always have one static key per ISA extension
> defined in cpufeatures.c

Currently, RISCV_ISA_EXT_MAX equals to 64 while the base ID is 26.
In those 26 base IDs, only F/D and V need static key, it means
we waste at least 24 static keys.

> 
> For example, F, D, V, Sstc, Svinval, Ssofpmt, Zb*, AIA, etc.
> 
> >
> > 2.We may need riscv architecture static keys for non-isa, this is
> > usually related with the linux os itself, for example
> > a static key for "unmap kernelspace at userspace".
> > static keys for "spectre CVE mitigations"
> > etc.
> 
> These things look more like errata or workarounds so better
> to use that framework instead of ISA extensions (or features).

Currently, the errata workarounds are implemented with ALTERNATIVEs
but I believe sometime we may need static key to implement the
workarounds. However this can be checked later. Now I worried about
the static key waste above.

Thanks

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

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 2/4] riscv: introduce unified static key mechanism for CPU features
  2022-05-16 17:24               ` Jisheng Zhang
@ 2022-05-17  4:01                 ` Anup Patel
  -1 siblings, 0 replies; 36+ messages in thread
From: Anup Patel @ 2022-05-17  4:01 UTC (permalink / raw)
  To: Jisheng Zhang
  Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Andrey Ryabinin, Alexander Potapenko,
	Andrey Konovalov, Dmitry Vyukov, Vincenzo Frascino,
	Alexandre Ghiti, linux-riscv, linux-kernel@vger.kernel.org List,
	kasan-dev

On Mon, May 16, 2022 at 11:02 PM Jisheng Zhang <jszhang@kernel.org> wrote:
>
> On Sun, May 15, 2022 at 08:19:37PM +0530, Anup Patel wrote:
> > On Sun, May 15, 2022 at 12:54 PM Jisheng Zhang <jszhang@kernel.org> wrote:
> > >
> > > On Wed, May 11, 2022 at 11:29:32PM -0700, Atish Patra wrote:
> > > > On Mon, May 9, 2022 at 7:50 AM Jisheng Zhang <jszhang@kernel.org> wrote:
> > > > >
> > > > > On Mon, May 09, 2022 at 09:17:10AM +0530, Anup Patel wrote:
> > > > > > On Sun, May 8, 2022 at 9:47 PM Jisheng Zhang <jszhang@kernel.org> wrote:
> > > > > > >
> > > > > > > Currently, riscv has several features why may not be supported on all
> > > > > > > riscv platforms, for example, FPU, SV48 and so on. To support unified
> > > > > > > kernel Image style, we need to check whether the feature is suportted
> > > > > > > or not. If the check sits at hot code path, then performance will be
> > > > > > > impacted a lot. static key can be used to solve the issue. In the past
> > > > > > > FPU support has been converted to use static key mechanism. I believe
> > > > > > > we will have similar cases in the future.
> > > > > >
> > > > > > It's not just FPU and Sv48. There are several others such as Svinval,
> > > > > > Vector, Svnapot, Svpbmt, and many many others.
> > > > > >
> > > > > > Overall, I agree with the approach of using static key array but I
> > > > > > disagree with the semantics and the duplicate stuff being added.
> > > > > >
> > > > > > Please see more comments below ..
> > > > > >
> > > > > > >
> > > > > > > Similar as arm64 does(in fact, some code is borrowed from arm64), this
> > > > > > > patch tries to add an unified mechanism to use static keys for all
> > > > > > > the cpu features by implementing an array of default-false static keys
> > > > > > > and enabling them when detected. The cpus_have_*_cap() check uses the
> > > > > > > static keys if riscv_const_caps_ready is finalized, otherwise the
> > > > > > > compiler generates the bitmap test.
> > > > > >
> > > > > > First of all, we should stop calling this a feature (like ARM does). Rather,
> > > > > > we should call these as isa extensions ("isaext") to align with the RISC-V
> > > > > > priv spec and RISC-V profiles spec. For all the ISA optionalities which do
> > > > > > not have distinct extension name, the RISC-V profiles spec is assigning
> > > > > > names to all such optionalities.
> > > > >
> > > > > Same as the reply a few minutes ago, the key problem here is do all
> > > > > CPU features belong to *ISA* extensions? For example, SV48, SV57 etc.
> > > > > I agree with Atish's comments here:
> > > > >
> > > > > "I think the cpu feature is a superset of the ISA extension.
> > > > > cpu feature != ISA extension"
> > > > >
> > > >
> > > > It seems to be accurate at that point in time. However, the latest
> > > > profile spec seems to
> > > > define everything as an extension including sv48.
> > > >
> > > > https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc#623-rva22s64-supported-optional-extensions
> > > >
> > > > It may be a redundant effort and confusing to create two sets i.e.
> > > > feature and extension in this case.
> > > > But this specification is not frozen yet and may change in the future.
> > > > We at least know that that is the current intention.
> > > >
> > > > Array of static keys is definitely useful and should be used for all
> > > > well defined ISA extensions by the ratified priv spec.
> > > > This will simplify this patch as well. For any feature/extensions
> > > > (i.e. sv48/sv57) which was never defined as an extension
> > > > in the priv spec but profile seems to define it now, I would leave it
> > > > alone for the time being. Converting the existing code
> > > > to static key probably has value but please do not include it in the
> > > > static key array setup.
> > > >
> > > > Once the profile spec is frozen, we can decide which direction the
> > > > Linux kernel should go.
> > > >
> > >
> > > Hi Atish, Anup,
> > >
> > > I see your points and thanks for the information of the profile
> > > spec. Now, I have other two points about isa VS features:
> > >
> > > 1. Not all isa extenstions need static key mechanism, so if we
> > > make a static key array with 1:1 riscv_isa <-> static key relationship
> > > there may be waste.
> > >
> > > For example, the 'a', 'c', 'i', 'm' and so on don't have static
> > > key usage.
> >
> > Not all isa extensions but a large number of them will need a static
> > key. It's better to always have one static key per ISA extension
> > defined in cpufeatures.c
>
> Currently, RISCV_ISA_EXT_MAX equals to 64 while the base ID is 26.
> In those 26 base IDs, only F/D and V need static key, it means
> we waste at least 24 static keys.

If you want to save space of unused static keys then there are other
ways.

For example, you can create a small static key array which has
many-to-one relation with the ISA extension numbers. For ISA extension
which are always ON or always OFF, we can use fixed FALSE and
TRUE keys. Something like below.

enum riscv_isa_ext_key {
    RISCV_ISA_EXT_KEY_FALSE = 0,
    RISCV_ISA_EXT_KEY_TRUE,
    RISCV_ISA_EXT_KEY_FLOAD, /* For 'F' and 'D' */
    RISCV_ISA_EXT_KEY_VECTOR, /* For all vector extensions */
    RISCV_ISA_EXT_KEY_SVINVAL,
    RISCV_ISA_EXT_KEY_SSCOFPMT,
    RISCV_ISA_EXT_KEY_MAX,
};

extern unsigned char __riscv_isa_ext_id2key[RISCV_ISA_EXT_ID_MAX];
extern struct static_key_false __riscv_isa_ext_keys[RISCV_ISA_EXT_KEY_MAX];

static __always_inline bool __riscv_isa_extension_keycheck(unsigned int ext)
{
    if (RISCV_ISA_EXT_ID_MAX <= ext)
        return false;
    return static_branch_unlikely(&__riscv_isa_ext_keys[__riscv_isa_ext_id2key[ext]]);
}
#define riscv_isa_extension_keycheck(ext)    \
    __riscv_isa_extension_keycheck(RISCV_ISA_EXT_##ext)

>
> >
> > For example, F, D, V, Sstc, Svinval, Ssofpmt, Zb*, AIA, etc.
> >
> > >
> > > 2.We may need riscv architecture static keys for non-isa, this is
> > > usually related with the linux os itself, for example
> > > a static key for "unmap kernelspace at userspace".
> > > static keys for "spectre CVE mitigations"
> > > etc.
> >
> > These things look more like errata or workarounds so better
> > to use that framework instead of ISA extensions (or features).
>
> Currently, the errata workarounds are implemented with ALTERNATIVEs
> but I believe sometime we may need static key to implement the
> workarounds. However this can be checked later. Now I worried about
> the static key waste above.

That's a separate topic and for now what we need is a simple
and extensible approach to have static keys for ISA extensions.

Regards,
Anup

>
> Thanks

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 2/4] riscv: introduce unified static key mechanism for CPU features
@ 2022-05-17  4:01                 ` Anup Patel
  0 siblings, 0 replies; 36+ messages in thread
From: Anup Patel @ 2022-05-17  4:01 UTC (permalink / raw)
  To: Jisheng Zhang
  Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Andrey Ryabinin, Alexander Potapenko,
	Andrey Konovalov, Dmitry Vyukov, Vincenzo Frascino,
	Alexandre Ghiti, linux-riscv, linux-kernel@vger.kernel.org List,
	kasan-dev

On Mon, May 16, 2022 at 11:02 PM Jisheng Zhang <jszhang@kernel.org> wrote:
>
> On Sun, May 15, 2022 at 08:19:37PM +0530, Anup Patel wrote:
> > On Sun, May 15, 2022 at 12:54 PM Jisheng Zhang <jszhang@kernel.org> wrote:
> > >
> > > On Wed, May 11, 2022 at 11:29:32PM -0700, Atish Patra wrote:
> > > > On Mon, May 9, 2022 at 7:50 AM Jisheng Zhang <jszhang@kernel.org> wrote:
> > > > >
> > > > > On Mon, May 09, 2022 at 09:17:10AM +0530, Anup Patel wrote:
> > > > > > On Sun, May 8, 2022 at 9:47 PM Jisheng Zhang <jszhang@kernel.org> wrote:
> > > > > > >
> > > > > > > Currently, riscv has several features why may not be supported on all
> > > > > > > riscv platforms, for example, FPU, SV48 and so on. To support unified
> > > > > > > kernel Image style, we need to check whether the feature is suportted
> > > > > > > or not. If the check sits at hot code path, then performance will be
> > > > > > > impacted a lot. static key can be used to solve the issue. In the past
> > > > > > > FPU support has been converted to use static key mechanism. I believe
> > > > > > > we will have similar cases in the future.
> > > > > >
> > > > > > It's not just FPU and Sv48. There are several others such as Svinval,
> > > > > > Vector, Svnapot, Svpbmt, and many many others.
> > > > > >
> > > > > > Overall, I agree with the approach of using static key array but I
> > > > > > disagree with the semantics and the duplicate stuff being added.
> > > > > >
> > > > > > Please see more comments below ..
> > > > > >
> > > > > > >
> > > > > > > Similar as arm64 does(in fact, some code is borrowed from arm64), this
> > > > > > > patch tries to add an unified mechanism to use static keys for all
> > > > > > > the cpu features by implementing an array of default-false static keys
> > > > > > > and enabling them when detected. The cpus_have_*_cap() check uses the
> > > > > > > static keys if riscv_const_caps_ready is finalized, otherwise the
> > > > > > > compiler generates the bitmap test.
> > > > > >
> > > > > > First of all, we should stop calling this a feature (like ARM does). Rather,
> > > > > > we should call these as isa extensions ("isaext") to align with the RISC-V
> > > > > > priv spec and RISC-V profiles spec. For all the ISA optionalities which do
> > > > > > not have distinct extension name, the RISC-V profiles spec is assigning
> > > > > > names to all such optionalities.
> > > > >
> > > > > Same as the reply a few minutes ago, the key problem here is do all
> > > > > CPU features belong to *ISA* extensions? For example, SV48, SV57 etc.
> > > > > I agree with Atish's comments here:
> > > > >
> > > > > "I think the cpu feature is a superset of the ISA extension.
> > > > > cpu feature != ISA extension"
> > > > >
> > > >
> > > > It seems to be accurate at that point in time. However, the latest
> > > > profile spec seems to
> > > > define everything as an extension including sv48.
> > > >
> > > > https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc#623-rva22s64-supported-optional-extensions
> > > >
> > > > It may be a redundant effort and confusing to create two sets i.e.
> > > > feature and extension in this case.
> > > > But this specification is not frozen yet and may change in the future.
> > > > We at least know that that is the current intention.
> > > >
> > > > Array of static keys is definitely useful and should be used for all
> > > > well defined ISA extensions by the ratified priv spec.
> > > > This will simplify this patch as well. For any feature/extensions
> > > > (i.e. sv48/sv57) which was never defined as an extension
> > > > in the priv spec but profile seems to define it now, I would leave it
> > > > alone for the time being. Converting the existing code
> > > > to static key probably has value but please do not include it in the
> > > > static key array setup.
> > > >
> > > > Once the profile spec is frozen, we can decide which direction the
> > > > Linux kernel should go.
> > > >
> > >
> > > Hi Atish, Anup,
> > >
> > > I see your points and thanks for the information of the profile
> > > spec. Now, I have other two points about isa VS features:
> > >
> > > 1. Not all isa extenstions need static key mechanism, so if we
> > > make a static key array with 1:1 riscv_isa <-> static key relationship
> > > there may be waste.
> > >
> > > For example, the 'a', 'c', 'i', 'm' and so on don't have static
> > > key usage.
> >
> > Not all isa extensions but a large number of them will need a static
> > key. It's better to always have one static key per ISA extension
> > defined in cpufeatures.c
>
> Currently, RISCV_ISA_EXT_MAX equals to 64 while the base ID is 26.
> In those 26 base IDs, only F/D and V need static key, it means
> we waste at least 24 static keys.

If you want to save space of unused static keys then there are other
ways.

For example, you can create a small static key array which has
many-to-one relation with the ISA extension numbers. For ISA extension
which are always ON or always OFF, we can use fixed FALSE and
TRUE keys. Something like below.

enum riscv_isa_ext_key {
    RISCV_ISA_EXT_KEY_FALSE = 0,
    RISCV_ISA_EXT_KEY_TRUE,
    RISCV_ISA_EXT_KEY_FLOAD, /* For 'F' and 'D' */
    RISCV_ISA_EXT_KEY_VECTOR, /* For all vector extensions */
    RISCV_ISA_EXT_KEY_SVINVAL,
    RISCV_ISA_EXT_KEY_SSCOFPMT,
    RISCV_ISA_EXT_KEY_MAX,
};

extern unsigned char __riscv_isa_ext_id2key[RISCV_ISA_EXT_ID_MAX];
extern struct static_key_false __riscv_isa_ext_keys[RISCV_ISA_EXT_KEY_MAX];

static __always_inline bool __riscv_isa_extension_keycheck(unsigned int ext)
{
    if (RISCV_ISA_EXT_ID_MAX <= ext)
        return false;
    return static_branch_unlikely(&__riscv_isa_ext_keys[__riscv_isa_ext_id2key[ext]]);
}
#define riscv_isa_extension_keycheck(ext)    \
    __riscv_isa_extension_keycheck(RISCV_ISA_EXT_##ext)

>
> >
> > For example, F, D, V, Sstc, Svinval, Ssofpmt, Zb*, AIA, etc.
> >
> > >
> > > 2.We may need riscv architecture static keys for non-isa, this is
> > > usually related with the linux os itself, for example
> > > a static key for "unmap kernelspace at userspace".
> > > static keys for "spectre CVE mitigations"
> > > etc.
> >
> > These things look more like errata or workarounds so better
> > to use that framework instead of ISA extensions (or features).
>
> Currently, the errata workarounds are implemented with ALTERNATIVEs
> but I believe sometime we may need static key to implement the
> workarounds. However this can be checked later. Now I worried about
> the static key waste above.

That's a separate topic and for now what we need is a simple
and extensible approach to have static keys for ISA extensions.

Regards,
Anup

>
> Thanks

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

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 2/4] riscv: introduce unified static key mechanism for CPU features
  2022-05-17  4:01                 ` Anup Patel
@ 2022-05-17 16:33                   ` Jisheng Zhang
  -1 siblings, 0 replies; 36+ messages in thread
From: Jisheng Zhang @ 2022-05-17 16:33 UTC (permalink / raw)
  To: Anup Patel
  Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Andrey Ryabinin, Alexander Potapenko,
	Andrey Konovalov, Dmitry Vyukov, Vincenzo Frascino,
	Alexandre Ghiti, linux-riscv, linux-kernel@vger.kernel.org List,
	kasan-dev

On Tue, May 17, 2022 at 09:31:50AM +0530, Anup Patel wrote:
> On Mon, May 16, 2022 at 11:02 PM Jisheng Zhang <jszhang@kernel.org> wrote:
> >
...
> > Currently, RISCV_ISA_EXT_MAX equals to 64 while the base ID is 26.
> > In those 26 base IDs, only F/D and V need static key, it means
> > we waste at least 24 static keys.
> 
> If you want to save space of unused static keys then there are other
> ways.
> 
> For example, you can create a small static key array which has
> many-to-one relation with the ISA extension numbers. For ISA extension

"any problem in computer science can be solved with another layer of
indirection" ;)
I see your points, thanks very much! But I think the array should
be a static inline function to make use of compiler optimization to
avoid the array references for performance. And the static key check
maybe used in modules, I want to export less vars.
I'm cooking the patches, will send out for review soon.

> which are always ON or always OFF, we can use fixed FALSE and
> TRUE keys. Something like below.
> 
> enum riscv_isa_ext_key {
>     RISCV_ISA_EXT_KEY_FALSE = 0,
>     RISCV_ISA_EXT_KEY_TRUE,
>     RISCV_ISA_EXT_KEY_FLOAD, /* For 'F' and 'D' */
>     RISCV_ISA_EXT_KEY_VECTOR, /* For all vector extensions */
>     RISCV_ISA_EXT_KEY_SVINVAL,
>     RISCV_ISA_EXT_KEY_SSCOFPMT,
>     RISCV_ISA_EXT_KEY_MAX,
> };
> 
> extern unsigned char __riscv_isa_ext_id2key[RISCV_ISA_EXT_ID_MAX];
> extern struct static_key_false __riscv_isa_ext_keys[RISCV_ISA_EXT_KEY_MAX];
> 
> static __always_inline bool __riscv_isa_extension_keycheck(unsigned int ext)
> {
>     if (RISCV_ISA_EXT_ID_MAX <= ext)
>         return false;
>     return static_branch_unlikely(&__riscv_isa_ext_keys[__riscv_isa_ext_id2key[ext]]);
> }
> #define riscv_isa_extension_keycheck(ext)    \
>     __riscv_isa_extension_keycheck(RISCV_ISA_EXT_##ext)
> 


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 2/4] riscv: introduce unified static key mechanism for CPU features
@ 2022-05-17 16:33                   ` Jisheng Zhang
  0 siblings, 0 replies; 36+ messages in thread
From: Jisheng Zhang @ 2022-05-17 16:33 UTC (permalink / raw)
  To: Anup Patel
  Cc: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Andrey Ryabinin, Alexander Potapenko,
	Andrey Konovalov, Dmitry Vyukov, Vincenzo Frascino,
	Alexandre Ghiti, linux-riscv, linux-kernel@vger.kernel.org List,
	kasan-dev

On Tue, May 17, 2022 at 09:31:50AM +0530, Anup Patel wrote:
> On Mon, May 16, 2022 at 11:02 PM Jisheng Zhang <jszhang@kernel.org> wrote:
> >
...
> > Currently, RISCV_ISA_EXT_MAX equals to 64 while the base ID is 26.
> > In those 26 base IDs, only F/D and V need static key, it means
> > we waste at least 24 static keys.
> 
> If you want to save space of unused static keys then there are other
> ways.
> 
> For example, you can create a small static key array which has
> many-to-one relation with the ISA extension numbers. For ISA extension

"any problem in computer science can be solved with another layer of
indirection" ;)
I see your points, thanks very much! But I think the array should
be a static inline function to make use of compiler optimization to
avoid the array references for performance. And the static key check
maybe used in modules, I want to export less vars.
I'm cooking the patches, will send out for review soon.

> which are always ON or always OFF, we can use fixed FALSE and
> TRUE keys. Something like below.
> 
> enum riscv_isa_ext_key {
>     RISCV_ISA_EXT_KEY_FALSE = 0,
>     RISCV_ISA_EXT_KEY_TRUE,
>     RISCV_ISA_EXT_KEY_FLOAD, /* For 'F' and 'D' */
>     RISCV_ISA_EXT_KEY_VECTOR, /* For all vector extensions */
>     RISCV_ISA_EXT_KEY_SVINVAL,
>     RISCV_ISA_EXT_KEY_SSCOFPMT,
>     RISCV_ISA_EXT_KEY_MAX,
> };
> 
> extern unsigned char __riscv_isa_ext_id2key[RISCV_ISA_EXT_ID_MAX];
> extern struct static_key_false __riscv_isa_ext_keys[RISCV_ISA_EXT_KEY_MAX];
> 
> static __always_inline bool __riscv_isa_extension_keycheck(unsigned int ext)
> {
>     if (RISCV_ISA_EXT_ID_MAX <= ext)
>         return false;
>     return static_branch_unlikely(&__riscv_isa_ext_keys[__riscv_isa_ext_id2key[ext]]);
> }
> #define riscv_isa_extension_keycheck(ext)    \
>     __riscv_isa_extension_keycheck(RISCV_ISA_EXT_##ext)
> 


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

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2022-05-17 16:42 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-08 16:07 [PATCH v2 0/4] unified way to use static key and optimize pgtable_l4_enabled Jisheng Zhang
2022-05-08 16:07 ` Jisheng Zhang
2022-05-08 16:07 ` [PATCH v2 1/4] riscv: mm: init: make pt_ops_set_[early|late|fixmap] static Jisheng Zhang
2022-05-08 16:07   ` Jisheng Zhang
2022-05-09  3:51   ` Anup Patel
2022-05-09  3:51     ` Anup Patel
2022-05-08 16:07 ` [PATCH v2 2/4] riscv: introduce unified static key mechanism for CPU features Jisheng Zhang
2022-05-08 16:07   ` Jisheng Zhang
2022-05-09  3:47   ` Anup Patel
2022-05-09  3:47     ` Anup Patel
2022-05-09 14:41     ` Jisheng Zhang
2022-05-09 14:41       ` Jisheng Zhang
2022-05-12  6:29       ` Atish Patra
2022-05-12  6:29         ` Atish Patra
2022-05-15  7:15         ` Jisheng Zhang
2022-05-15  7:15           ` Jisheng Zhang
2022-05-15 14:49           ` Anup Patel
2022-05-15 14:49             ` Anup Patel
2022-05-16 17:24             ` Jisheng Zhang
2022-05-16 17:24               ` Jisheng Zhang
2022-05-17  4:01               ` Anup Patel
2022-05-17  4:01                 ` Anup Patel
2022-05-17 16:33                 ` Jisheng Zhang
2022-05-17 16:33                   ` Jisheng Zhang
2022-05-08 16:07 ` [PATCH v2 3/4] riscv: replace has_fpu() with system_supports_fpu() Jisheng Zhang
2022-05-08 16:07   ` Jisheng Zhang
2022-05-09  4:01   ` Anup Patel
2022-05-09  4:01     ` Anup Patel
2022-05-08 16:07 ` [PATCH v2 4/4] riscv: convert pgtable_l4|[l5]_enabled to static key Jisheng Zhang
2022-05-08 16:07   ` Jisheng Zhang
2022-05-09  3:59   ` Anup Patel
2022-05-09  3:59     ` Anup Patel
2022-05-09  4:37 ` [PATCH v2 0/4] unified way to use static key and optimize pgtable_l4_enabled Anup Patel
2022-05-09  4:37   ` Anup Patel
2022-05-09 14:26   ` Jisheng Zhang
2022-05-09 14:26     ` Jisheng Zhang

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.