summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-09-07 12:56:36 +0100
committerMark Brown <broonie@kernel.org>2026-09-07 12:56:36 +0100
commit3ec149afb5ada29fdbaa3f492594eec160e226b5 (patch)
treeb2955f4a2dcb0146cda5c876dab05365032952d0
parent54410e995582140f1ef933ea68a95b8a37a06826 (diff)
parentb94cec5761d22624d109d859467d7d4ce0a1b88b (diff)
downloadlinux-next-3ec149afb5ada29fdbaa3f492594eec160e226b5.tar.gz
linux-next-3ec149afb5ada29fdbaa3f492594eec160e226b5.zip
Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git
-rw-r--r--Documentation/arch/riscv/hwprobe.rst8
-rw-r--r--Documentation/devicetree/bindings/riscv/cpus.yaml8
-rw-r--r--Documentation/translations/zh_CN/arch/riscv/patch-acceptance.rst46
-rw-r--r--arch/riscv/Kconfig2
-rw-r--r--arch/riscv/include/asm/bug.h5
-rw-r--r--arch/riscv/include/asm/switch_to.h4
-rw-r--r--arch/riscv/kernel/cpufeature.c20
-rw-r--r--arch/riscv/kernel/patch.c2
-rw-r--r--arch/riscv/kernel/process.c4
-rw-r--r--arch/riscv/kernel/sys_hwprobe.c5
-rw-r--r--arch/riscv/kernel/usercfi.c5
-rw-r--r--arch/riscv/lib/uaccess.S5
-rw-r--r--arch/riscv/mm/init.c4
-rw-r--r--drivers/perf/riscv_pmu_legacy.c5
-rw-r--r--drivers/perf/riscv_pmu_sbi.c98
-rw-r--r--include/linux/perf/riscv_pmu.h2
-rw-r--r--tools/testing/selftests/riscv/cfi/cfi_rv_test.h2
-rw-r--r--tools/testing/selftests/riscv/hwprobe/hwprobe.c20
18 files changed, 170 insertions, 75 deletions
diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst
index 893e1a1215d2..bb1e0cbab36f 100644
--- a/Documentation/arch/riscv/hwprobe.rst
+++ b/Documentation/arch/riscv/hwprobe.rst
@@ -155,7 +155,8 @@ The following keys are defined:
defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
* :c:macro:`RISCV_HWPROBE_EXT_ZFH`: The Zfh extension version 1.0 is supported
- as defined in the RISC-V ISA manual.
+ as defined in the RISC-V ISA manual. Zfh is a superset of Zfhmin, so
+ RISCV_HWPROBE_EXT_ZFHMIN is reported whenever RISCV_HWPROBE_EXT_ZFH is.
* :c:macro:`RISCV_HWPROBE_EXT_ZFHMIN`: The Zfhmin extension version 1.0 is
supported as defined in the RISC-V ISA manual.
@@ -164,8 +165,9 @@ The following keys are defined:
is supported as defined in the RISC-V ISA manual.
* :c:macro:`RISCV_HWPROBE_EXT_ZVFH`: The Zvfh extension is supported as
- defined in the RISC-V Vector manual starting from commit e2ccd0548d6c
- ("Remove draft warnings from Zvfh[min]").
+ defined in the RISC-V Vector manual starting from commit e2ccd0548d6c
+ ("Remove draft warnings from Zvfh[min]"). Zvfh is a superset of Zvfhmin,
+ so RISCV_HWPROBE_EXT_ZVFHMIN is reported whenever RISCV_HWPROBE_EXT_ZVFH is.
* :c:macro:`RISCV_HWPROBE_EXT_ZVFHMIN`: The Zvfhmin extension is supported as
defined in the RISC-V Vector manual starting from commit e2ccd0548d6c
diff --git a/Documentation/devicetree/bindings/riscv/cpus.yaml b/Documentation/devicetree/bindings/riscv/cpus.yaml
index 5feeb2203050..0da219ae6769 100644
--- a/Documentation/devicetree/bindings/riscv/cpus.yaml
+++ b/Documentation/devicetree/bindings/riscv/cpus.yaml
@@ -117,8 +117,8 @@ properties:
$ref: /schemas/types.yaml#/definitions/uint32
description:
VLEN/8, the vector register length in bytes. This property is required on
- thead systems where the vector register length is not identical on all harts, or
- the vlenb CSR is not available.
+ thead systems where the vector register length is not identical on all
+ harts, or the vlenb CSR is not available.
# RISC-V has multiple properties for cache op block sizes as the sizes
# differ between individual CBO extensions
@@ -151,8 +151,8 @@ anyOf:
- riscv,isa-base
dependencies:
- riscv,isa-base: [ "riscv,isa-extensions" ]
- riscv,isa-extensions: [ "riscv,isa-base" ]
+ riscv,isa-base: ["riscv,isa-extensions"]
+ riscv,isa-extensions: ["riscv,isa-base"]
required:
- interrupt-controller
diff --git a/Documentation/translations/zh_CN/arch/riscv/patch-acceptance.rst b/Documentation/translations/zh_CN/arch/riscv/patch-acceptance.rst
index c8eb230ca8ee..20b91d0433a9 100644
--- a/Documentation/translations/zh_CN/arch/riscv/patch-acceptance.rst
+++ b/Documentation/translations/zh_CN/arch/riscv/patch-acceptance.rst
@@ -15,19 +15,41 @@ arch/riscv 开发者维护指南
概述
----
-RISC-V指令集体系结构是公开开发的:
+RISC-V 指令集体系结构是公开开发的:
正在进行的草案可供所有人查看和测试实现。新模块或者扩展草案可能会在开发过程中发
-生更改---有时以不兼容的方式对以前的草案进行更改。这种灵活性可能会给RISC-V Linux
-维护者带来挑战。Linux开发过程更喜欢经过良好检查和测试的代码,而不是试验代码。我
-们希望推广同样的规则到即将被内核合并的RISC-V相关代码。
+生更改 --- 有时以不兼容的方式对以前的草案进行更改。这种灵活性可能会给 RISC-V
+Linux 维护者带来挑战。Linux 维护者不赞成频繁的变更,且 Linux 开发过程更喜欢经过
+良好检查和测试的代码,而不是试验代码。我们希望推广同样的规则到即将被内核合并的
+RISC-V 相关代码。
+
+Patchwork
+---------
+
+RISC-V 有一个 patchwork 实例,可以在那里查看补丁的状态:
+
+ https://patchwork.kernel.org/project/linux-riscv/list/
+
+如果你的补丁不在默认视图中出现,那么 RISC-V 维护者很有可能已要求修改,或者希望
+将其应用到另一个代码树上。
+
+自动化流程会在该 patchwork 实例上运行,在每个补丁到达时立刻对其进行构建/测试。
+自动化流程会根据补丁是否被识别为修复,选用 RISC-V `for-next` 或 `fixes` 分支
+当前的 HEAD;若上述均应用失败,则使用 RISC-V `master` 分支。补丁系列被应用到的具
+体提交将标注在 patchwork 上。任何检查未通过的补丁通常不会被应用,并且在大多数情
+况下将需要重新提交。
附加的提交检查单
----------------
-我们仅接受相关标准已经被RISC-V基金会标准为“已批准”或“已冻结”的扩展或模块的补丁。
-(开发者当然可以维护自己的Linux内核树,其中包含所需代码扩展草案的代码。)
-
-此外,RISC-V规范允许爱好者创建自己的自定义扩展。这些自定义拓展不需要通过RISC-V
-基金会的任何审核或批准。为了避免将爱好者一些特别的RISC-V拓展添加进内核代码带来
-的维护复杂性和对性能的潜在影响,我们将只接受RISC-V基金会正式冻结或批准的的扩展
-补丁。(开发者当然可以维护自己的Linux内核树,其中包含他们想要的任何自定义扩展
-的代码。)
+我们仅接受针对新模块或扩展的补丁,前提是这些模块或扩展的规范被列为未来不太可能发
+生不兼容的变更。对于来自 RISC-V 基金会的规范,这意味着“已冻结”或“已批准”,对于
+UEFI 论坛的规范,这意味着已发布的 ECR。(开发者当然可以维护自己的 Linux 内核树,
+其中包含他们所需的任何扩展草案的代码。)
+
+此外,RISC-V 规范允许实现者创建自己的自定义扩展。这些自定义扩展不需要通过 RISC-V
+基金会的任何审核或批准流程。为了避免因添加实现者特定的 RISC-V 扩展带来的维护复杂
+性和对性能的潜在影响,我们将只考虑符合以下任一条件的扩展补丁:
+
+- 已由 RISC-V 基金会正式冻结或批准
+- 已按照标准 Linux 惯例,在广泛可用的硬件中实现
+
+(实现者当然可以维护自己的 Linux 内核树,其中包含他们所需的任何自定义扩展的代码。)
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index f8e26c4bed2b..d6c2dbf8455c 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -326,7 +326,7 @@ config STACKTRACE_SUPPORT
config GENERIC_BUG
def_bool y
depends on BUG
- select GENERIC_BUG_RELATIVE_POINTERS if 64BIT
+ select GENERIC_BUG_RELATIVE_POINTERS
config GENERIC_BUG_RELATIVE_POINTERS
bool
diff --git a/arch/riscv/include/asm/bug.h b/arch/riscv/include/asm/bug.h
index 6f581b84d8fc..699c0cf3e4ef 100644
--- a/arch/riscv/include/asm/bug.h
+++ b/arch/riscv/include/asm/bug.h
@@ -29,13 +29,8 @@
typedef u32 bug_insn_t;
-#ifdef CONFIG_GENERIC_BUG_RELATIVE_POINTERS
#define __BUG_ENTRY_ADDR RISCV_INT " 1b - ."
#define __BUG_ENTRY_FILE(file) RISCV_INT " " file " - ."
-#else
-#define __BUG_ENTRY_ADDR RISCV_PTR " 1b"
-#define __BUG_ENTRY_FILE(file) RISCV_PTR " " file
-#endif
#ifdef CONFIG_DEBUG_BUGVERBOSE
#define __BUG_ENTRY(file, line, flags) \
diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h
index 04f10a949066..123c89b694e8 100644
--- a/arch/riscv/include/asm/switch_to.h
+++ b/arch/riscv/include/asm/switch_to.h
@@ -61,8 +61,8 @@ static inline void __switch_to_fpu(struct task_struct *prev,
static __always_inline bool has_fpu(void)
{
- return riscv_has_extension_likely(RISCV_ISA_EXT_F) ||
- riscv_has_extension_likely(RISCV_ISA_EXT_D);
+ /* D extension depends on F, so checking D alone is sufficient. */
+ return riscv_has_extension_likely(RISCV_ISA_EXT_D);
}
#else
static __always_inline bool has_fpu(void) { return false; }
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index d2ec96843456..61d21f714830 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -412,6 +412,19 @@ static const unsigned int riscv_zvbb_exts[] = {
RISCV_ISA_EXT_ZVKB
};
+/*
+ * The RISC-V ISA manual specifies that Zfh implies Zfhmin and Zvfh implies
+ * Zvfhmin. Report the implied subset extensions whenever the supersets are
+ * detected (see https://github.com/riscv/riscv-isa-manual/pull/3070).
+ */
+static const unsigned int riscv_zfh_exts[] = {
+ RISCV_ISA_EXT_ZFHMIN
+};
+
+static const unsigned int riscv_zvfh_exts[] = {
+ RISCV_ISA_EXT_ZVFHMIN
+};
+
#define RISCV_ISA_EXT_ZVE64F_IMPLY_LIST \
RISCV_ISA_EXT_ZVE64X, \
RISCV_ISA_EXT_ZVE32F, \
@@ -550,7 +563,8 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
__RISCV_ISA_EXT_DATA(zawrs, RISCV_ISA_EXT_ZAWRS),
__RISCV_ISA_EXT_DATA_VALIDATE(zfa, RISCV_ISA_EXT_ZFA, riscv_ext_f_depends),
__RISCV_ISA_EXT_DATA_VALIDATE(zfbfmin, RISCV_ISA_EXT_ZFBFMIN, riscv_ext_f_depends),
- __RISCV_ISA_EXT_DATA_VALIDATE(zfh, RISCV_ISA_EXT_ZFH, riscv_ext_f_depends),
+ __RISCV_ISA_EXT_SUPERSET_VALIDATE(zfh, RISCV_ISA_EXT_ZFH,
+ riscv_zfh_exts, riscv_ext_f_depends),
__RISCV_ISA_EXT_DATA_VALIDATE(zfhmin, RISCV_ISA_EXT_ZFHMIN, riscv_ext_f_depends),
__RISCV_ISA_EXT_DATA(zca, RISCV_ISA_EXT_ZCA),
__RISCV_ISA_EXT_DATA_VALIDATE(zcb, RISCV_ISA_EXT_ZCB, riscv_ext_zca_depends),
@@ -586,7 +600,9 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
__RISCV_ISA_EXT_SUPERSET_VALIDATE(zve64x, RISCV_ISA_EXT_ZVE64X, riscv_zve64x_exts, riscv_ext_vector_x_validate),
__RISCV_ISA_EXT_DATA_VALIDATE(zvfbfmin, RISCV_ISA_EXT_ZVFBFMIN, riscv_vector_f_validate),
__RISCV_ISA_EXT_DATA_VALIDATE(zvfbfwma, RISCV_ISA_EXT_ZVFBFWMA, riscv_ext_zvfbfwma_validate),
- __RISCV_ISA_EXT_DATA(zvfh, RISCV_ISA_EXT_ZVFH),
+ __RISCV_ISA_EXT_SUPERSET_VALIDATE(zvfh, RISCV_ISA_EXT_ZVFH,
+ riscv_zvfh_exts,
+ riscv_ext_vector_float_validate),
__RISCV_ISA_EXT_DATA(zvfhmin, RISCV_ISA_EXT_ZVFHMIN),
__RISCV_ISA_EXT_DATA_VALIDATE(zvkb, RISCV_ISA_EXT_ZVKB, riscv_ext_vector_crypto_validate),
__RISCV_ISA_EXT_DATA_VALIDATE(zvkg, RISCV_ISA_EXT_ZVKG, riscv_ext_vector_crypto_validate),
diff --git a/arch/riscv/kernel/patch.c b/arch/riscv/kernel/patch.c
index 16b243376f36..2239c28981bc 100644
--- a/arch/riscv/kernel/patch.c
+++ b/arch/riscv/kernel/patch.c
@@ -45,6 +45,8 @@ static __always_inline void *patch_map(void *addr, const unsigned int fixmap)
phys_addr_t phys;
if (core_kernel_text(uintaddr) || is_kernel_exittext(uintaddr)) {
+ if (!IS_ENABLED(CONFIG_STRICT_KERNEL_RWX))
+ return addr;
phys = __pa_symbol(addr);
} else if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX)) {
struct page *page = vmalloc_to_page(addr);
diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c
index b2df7f72241a..7cc5a6a5c020 100644
--- a/arch/riscv/kernel/process.c
+++ b/arch/riscv/kernel/process.c
@@ -349,10 +349,8 @@ long set_tagged_addr_ctrl(struct task_struct *task, unsigned long arg)
if (arg & PR_TAGGED_ADDR_ENABLE && (tagged_addr_disabled || !pmlen))
return -EINVAL;
- if (!(arg & PR_TAGGED_ADDR_ENABLE)) {
+ if (!(arg & PR_TAGGED_ADDR_ENABLE))
pmlen = PMLEN_0;
- pmm = ENVCFG_PMM_PMLEN_0;
- }
if (mmap_write_lock_killable(mm))
return -EINTR;
diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c
index bd6ca7d769da..7818e1d32622 100644
--- a/arch/riscv/kernel/sys_hwprobe.c
+++ b/arch/riscv/kernel/sys_hwprobe.c
@@ -297,6 +297,8 @@ static u64 hwprobe_vec_misaligned(const struct cpumask *cpus)
static void hwprobe_one_pair(struct riscv_hwprobe *pair,
const struct cpumask *cpus)
{
+ pair->value = 0;
+
switch (pair->key) {
case RISCV_HWPROBE_KEY_MVENDORID:
case RISCV_HWPROBE_KEY_MARCHID:
@@ -331,17 +333,14 @@ static void hwprobe_one_pair(struct riscv_hwprobe *pair,
break;
case RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE:
- pair->value = 0;
if (hwprobe_ext0_has(cpus, RISCV_HWPROBE_EXT_ZICBOZ))
pair->value = riscv_cboz_block_size;
break;
case RISCV_HWPROBE_KEY_ZICBOM_BLOCK_SIZE:
- pair->value = 0;
if (hwprobe_ext0_has(cpus, RISCV_HWPROBE_EXT_ZICBOM))
pair->value = riscv_cbom_block_size;
break;
case RISCV_HWPROBE_KEY_ZICBOP_BLOCK_SIZE:
- pair->value = 0;
if (hwprobe_ext0_has(cpus, RISCV_HWPROBE_EXT_ZICBOP))
pair->value = riscv_cbop_block_size;
break;
diff --git a/arch/riscv/kernel/usercfi.c b/arch/riscv/kernel/usercfi.c
index f027e6e05251..dec0ba5eff5e 100644
--- a/arch/riscv/kernel/usercfi.c
+++ b/arch/riscv/kernel/usercfi.c
@@ -525,9 +525,8 @@ static int __init setup_global_riscv_enable(char *str)
if (riscv_nousercfi)
pr_info("RISC-V user CFI disabled via cmdline - shadow stack status : %s, landing pad status : %s\n",
- (riscv_nousercfi & CMDLINE_DISABLE_RISCV_USERCFI_BCFI) ? "disabled" :
- "enabled", (riscv_nousercfi & CMDLINE_DISABLE_RISCV_USERCFI_FCFI) ?
- "disabled" : "enabled");
+ str_disabled_enabled(riscv_nousercfi & CMDLINE_DISABLE_RISCV_USERCFI_BCFI),
+ str_disabled_enabled(riscv_nousercfi & CMDLINE_DISABLE_RISCV_USERCFI_FCFI));
return 1;
}
diff --git a/arch/riscv/lib/uaccess.S b/arch/riscv/lib/uaccess.S
index 4efea1b3326c..cf8586a937de 100644
--- a/arch/riscv/lib/uaccess.S
+++ b/arch/riscv/lib/uaccess.S
@@ -76,6 +76,7 @@ SYM_FUNC_START(fallback_scalar_usercopy_sum_enabled)
li a3, 9*SZREG-1 /* size must >= (word_copy stride + SZREG-1) */
bltu a2, a3, .Lbyte_copy_tail
+#if !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
/*
* Copy first bytes until dst is aligned to word boundary.
* a0 - start of dst
@@ -103,7 +104,7 @@ SYM_FUNC_START(fallback_scalar_usercopy_sum_enabled)
/* a1 - start of src */
andi a3, a1, SZREG-1
bnez a3, .Lshift_copy
-
+#endif
.Lword_copy:
/*
* Both src and dst are aligned, unrolled word copy
@@ -137,6 +138,7 @@ SYM_FUNC_START(fallback_scalar_usercopy_sum_enabled)
addi t0, t0, 8*SZREG /* revert to original value */
j .Lbyte_copy_tail
+#if !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
.Lshift_copy:
/*
@@ -189,6 +191,7 @@ SYM_FUNC_START(fallback_scalar_usercopy_sum_enabled)
/* Revert src to original unaligned value */
add a1, a1, a3
+#endif
.Lbyte_copy_tail:
/*
diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index f8994caefc70..fb37b0b67efe 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -1465,7 +1465,9 @@ struct execmem_info __init *execmem_arch_setup(void)
[EXECMEM_KPROBES] = {
.start = VMALLOC_START,
.end = VMALLOC_END,
- .pgprot = PAGE_KERNEL_READ_EXEC,
+ .pgprot = IS_ENABLED(CONFIG_STRICT_MODULE_RWX) ?
+ PAGE_KERNEL_READ_EXEC :
+ PAGE_KERNEL_EXEC,
.alignment = 1,
},
[EXECMEM_BPF] = {
diff --git a/drivers/perf/riscv_pmu_legacy.c b/drivers/perf/riscv_pmu_legacy.c
index 4d6461d6a74f..1b8e4789cb3c 100644
--- a/drivers/perf/riscv_pmu_legacy.c
+++ b/drivers/perf/riscv_pmu_legacy.c
@@ -110,8 +110,9 @@ static void pmu_legacy_init(struct riscv_pmu *pmu)
{
pr_info("Legacy PMU implementation is available\n");
- pmu->cmask = BIT(RISCV_PMU_LEGACY_CYCLE) |
- BIT(RISCV_PMU_LEGACY_INSTRET);
+ bitmap_zero(pmu->cmask, RISCV_MAX_COUNTERS);
+ set_bit(RISCV_PMU_LEGACY_CYCLE, pmu->cmask);
+ set_bit(RISCV_PMU_LEGACY_INSTRET, pmu->cmask);
pmu->ctr_start = pmu_legacy_ctr_start;
pmu->ctr_stop = NULL;
pmu->event_map = pmu_legacy_event_map;
diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
index 50220f7b46d9..2991dd92def2 100644
--- a/drivers/perf/riscv_pmu_sbi.c
+++ b/drivers/perf/riscv_pmu_sbi.c
@@ -97,7 +97,7 @@ static unsigned int riscv_pmu_irq_mask;
static unsigned int riscv_pmu_irq;
/* Cache the available counters in a bitmask */
-static unsigned long cmask;
+static DECLARE_BITMAP(cmask, RISCV_MAX_COUNTERS);
static int pmu_event_find_cache(u64 config);
struct sbi_pmu_event_data {
@@ -359,16 +359,38 @@ free_mem:
return result;
}
+static struct sbiret pmu_sbi_ctr_cfg_match(unsigned long cbase,
+ unsigned long ctr_mask,
+ unsigned long cflags,
+ unsigned long event_idx,
+ u64 config)
+{
+#if defined(CONFIG_32BIT)
+ return sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_CFG_MATCH, cbase,
+ ctr_mask, cflags, event_idx, config, config >> 32);
+#else
+ return sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_CFG_MATCH, cbase,
+ ctr_mask, cflags, event_idx, config, 0);
+#endif
+}
+
static void pmu_sbi_check_event(struct sbi_pmu_event_data *edata)
{
- struct sbiret ret;
+ struct sbiret ret = { .error = SBI_ERR_NOT_SUPPORTED };
+ int i;
- ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_CFG_MATCH,
- 0, cmask, 0, edata->event_idx, 0, 0);
- if (!ret.error) {
- sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_STOP,
- ret.value, 0x1, SBI_PMU_STOP_FLAG_RESET, 0, 0, 0);
- } else if (ret.error == SBI_ERR_NOT_SUPPORTED) {
+ for (i = 0; i < BITS_TO_LONGS(RISCV_MAX_COUNTERS); i++) {
+ if (!cmask[i])
+ continue;
+ ret = pmu_sbi_ctr_cfg_match(i * BITS_PER_LONG, cmask[i], 0,
+ edata->event_idx, 0);
+ if (!ret.error) {
+ sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_STOP,
+ ret.value, 0x1, SBI_PMU_STOP_FLAG_RESET, 0, 0, 0);
+ return;
+ }
+ }
+ if (ret.error == SBI_ERR_NOT_SUPPORTED) {
/* This event cannot be monitored by any counter */
edata->event_idx = -ENOENT;
}
@@ -488,10 +510,10 @@ int riscv_pmu_get_hpm_info(u32 *hw_ctr_width, u32 *num_hw_ctr)
union sbi_pmu_ctr_info *info;
u32 hpm_width = 0, hpm_count = 0;
- if (!cmask)
+ if (bitmap_empty(cmask, RISCV_MAX_COUNTERS))
return -EINVAL;
- for_each_set_bit(i, &cmask, RISCV_MAX_COUNTERS) {
+ for_each_set_bit(i, cmask, RISCV_MAX_COUNTERS) {
info = &pmu_ctr_list[i];
if (!info)
continue;
@@ -540,8 +562,8 @@ static int pmu_sbi_ctr_get_idx(struct perf_event *event)
struct riscv_pmu *rvpmu = to_riscv_pmu(event->pmu);
struct cpu_hw_events *cpuc = this_cpu_ptr(rvpmu->hw_events);
struct sbiret ret;
- int idx;
- uint64_t cbase = 0, cmask = rvpmu->cmask;
+ int idx, i;
+ u64 cbase = 0, cmask = 0;
unsigned long cflags = 0;
cflags = pmu_sbi_get_filter_flags(event);
@@ -562,14 +584,21 @@ static int pmu_sbi_ctr_get_idx(struct perf_event *event)
}
/* retrieve the available counter index */
-#if defined(CONFIG_32BIT)
- ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_CFG_MATCH, cbase,
- cmask, cflags, hwc->event_base, hwc->config,
- hwc->config >> 32);
-#else
- ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_CFG_MATCH, cbase,
- cmask, cflags, hwc->event_base, hwc->config, 0);
-#endif
+ if (cmask) {
+ ret = pmu_sbi_ctr_cfg_match(cbase, cmask, cflags, hwc->event_base,
+ hwc->config);
+ } else {
+ ret.error = SBI_ERR_NOT_SUPPORTED;
+ for (i = 0; i < BITS_TO_LONGS(RISCV_MAX_COUNTERS); i++) {
+ if (!rvpmu->cmask[i])
+ continue;
+ cbase = i * BITS_PER_LONG;
+ ret = pmu_sbi_ctr_cfg_match(cbase, rvpmu->cmask[i], cflags,
+ hwc->event_base, hwc->config);
+ if (!ret.error)
+ break;
+ }
+ }
if (ret.error) {
pr_debug("Not able to find a counter for event %lx config %llx\n",
hwc->event_base, hwc->config);
@@ -577,7 +606,7 @@ static int pmu_sbi_ctr_get_idx(struct perf_event *event)
}
idx = ret.value;
- if (!test_bit(idx, &rvpmu->cmask) || !pmu_ctr_list[idx].value)
+ if (!test_bit(idx, rvpmu->cmask) || !pmu_ctr_list[idx].value)
return -ENOENT;
/* Additional sanity check for the counter id */
@@ -881,7 +910,7 @@ static int pmu_sbi_get_ctrinfo(int nctr, unsigned long *mask)
/* The logical counter ids are not expected to be contiguous */
continue;
- *mask |= BIT(i);
+ set_bit(i, mask);
cinfo.value = ret.value;
if (cinfo.type == SBI_PMU_CTR_TYPE_FW)
@@ -898,12 +927,19 @@ static int pmu_sbi_get_ctrinfo(int nctr, unsigned long *mask)
static inline void pmu_sbi_stop_all(struct riscv_pmu *pmu)
{
+ int i;
+
/*
* No need to check the error because we are disabling all the counters
* which may include counters that are not enabled yet.
*/
- sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_STOP,
- 0, pmu->cmask, SBI_PMU_STOP_FLAG_RESET, 0, 0, 0);
+ for (i = 0; i < BITS_TO_LONGS(RISCV_MAX_COUNTERS); i++) {
+ if (!pmu->cmask[i])
+ continue;
+ sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_STOP,
+ i * BITS_PER_LONG, pmu->cmask[i],
+ SBI_PMU_STOP_FLAG_RESET, 0, 0, 0);
+ }
}
static inline void pmu_sbi_stop_hw_ctrs(struct riscv_pmu *pmu)
@@ -1002,7 +1038,7 @@ static inline void pmu_sbi_start_ovf_ctrs_snapshot(struct cpu_hw_events *cpu_hw_
struct riscv_pmu_snapshot_data *sdata = cpu_hw_evt->snapshot_addr;
for_each_set_bit(idx, cpu_hw_evt->used_hw_ctrs, RISCV_MAX_COUNTERS) {
- if (ctr_ovf_mask & BIT(idx)) {
+ if (ctr_ovf_mask & BIT_ULL(idx)) {
event = cpu_hw_evt->events[idx];
hwc = &event->hw;
max_period = riscv_pmu_ctr_get_width_mask(event);
@@ -1050,11 +1086,13 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
u64 overflowed_ctrs = 0;
struct cpu_hw_events *cpu_hw_evt = dev;
u64 start_clock = sched_clock();
- struct riscv_pmu_snapshot_data *sdata = cpu_hw_evt->snapshot_addr;
+ struct riscv_pmu_snapshot_data *sdata;
if (WARN_ON_ONCE(!cpu_hw_evt))
return IRQ_NONE;
+ sdata = cpu_hw_evt->snapshot_addr;
+
/* Firmware counter don't support overflow yet */
fidx = find_first_bit(cpu_hw_evt->used_hw_ctrs, RISCV_MAX_COUNTERS);
if (fidx == RISCV_MAX_COUNTERS) {
@@ -1109,14 +1147,14 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
hidx = info->csr - CSR_CYCLE;
/* check if the corresponding bit is set in scountovf or overflow mask in shmem */
- if (!(overflow & BIT(hidx)))
+ if (!(overflow & BIT_ULL(hidx)))
continue;
/*
* Keep a track of overflowed counters so that they can be started
* with updated initial value.
*/
- overflowed_ctrs |= BIT(lidx);
+ overflowed_ctrs |= BIT_ULL(lidx);
hw_evt = &event->hw;
/* Update the event states here so that we know the state while reading */
hw_evt->state |= PERF_HES_STOPPED;
@@ -1451,7 +1489,7 @@ static int pmu_sbi_device_probe(struct platform_device *pdev)
}
/* cache all the information about counters now */
- if (pmu_sbi_get_ctrinfo(num_counters, &cmask))
+ if (pmu_sbi_get_ctrinfo(num_counters, cmask))
goto out_free;
ret = pmu_sbi_setup_irqs(pmu, pdev);
@@ -1464,7 +1502,7 @@ static int pmu_sbi_device_probe(struct platform_device *pdev)
pmu->pmu.attr_groups = riscv_pmu_attr_groups;
pmu->pmu.parent = &pdev->dev;
- pmu->cmask = cmask;
+ bitmap_copy(pmu->cmask, cmask, RISCV_MAX_COUNTERS);
pmu->ctr_start = pmu_sbi_ctr_start;
pmu->ctr_stop = pmu_sbi_ctr_stop;
pmu->event_map = pmu_sbi_event_map;
diff --git a/include/linux/perf/riscv_pmu.h b/include/linux/perf/riscv_pmu.h
index f82a28040594..ecaa40370830 100644
--- a/include/linux/perf/riscv_pmu.h
+++ b/include/linux/perf/riscv_pmu.h
@@ -55,7 +55,7 @@ struct riscv_pmu {
irqreturn_t (*handle_irq)(int irq_num, void *dev);
- unsigned long cmask;
+ DECLARE_BITMAP(cmask, RISCV_MAX_COUNTERS);
u64 (*ctr_read)(struct perf_event *event);
int (*ctr_get_idx)(struct perf_event *event);
int (*ctr_get_width)(int idx);
diff --git a/tools/testing/selftests/riscv/cfi/cfi_rv_test.h b/tools/testing/selftests/riscv/cfi/cfi_rv_test.h
index 1c8043f2b778..184df6903d01 100644
--- a/tools/testing/selftests/riscv/cfi/cfi_rv_test.h
+++ b/tools/testing/selftests/riscv/cfi/cfi_rv_test.h
@@ -56,7 +56,7 @@
#define CSR_SSP 0x011
-#ifdef __ASSEMBLY__
+#ifdef __ASSEMBLER__
#define __ASM_STR(x) x
#else
#define __ASM_STR(x) #x
diff --git a/tools/testing/selftests/riscv/hwprobe/hwprobe.c b/tools/testing/selftests/riscv/hwprobe/hwprobe.c
index 54c435af9923..eca4441ee77f 100644
--- a/tools/testing/selftests/riscv/hwprobe/hwprobe.c
+++ b/tools/testing/selftests/riscv/hwprobe/hwprobe.c
@@ -9,7 +9,7 @@ int main(int argc, char **argv)
long out;
ksft_print_header();
- ksft_set_plan(5);
+ ksft_set_plan(6);
/* Fake the CPU_SET ops. */
cpus = -1;
@@ -62,5 +62,23 @@ int main(int argc, char **argv)
pairs[1].key == 1 && pairs[1].value != 0xAAAA,
"Unknown key overwritten with -1 and doesn't block other elements\n");
+ pairs[0].key = RISCV_HWPROBE_KEY_IMA_EXT_0;
+ out = riscv_hwprobe(pairs, 1, 0, 0, 0);
+ if (out != 0)
+ ksft_exit_fail_msg("hwprobe(IMA_EXT_0) failed with %ld\n", out);
+
+ /*
+ * The RISC-V ISA manual specifies that Zfh implies Zfhmin and Zvfh
+ * implies Zvfhmin, so hwprobe must report the implied subset
+ * extensions whenever the supersets are present.
+ */
+ if ((pairs[0].value & RISCV_HWPROBE_EXT_ZFH) &&
+ !(pairs[0].value & RISCV_HWPROBE_EXT_ZFHMIN))
+ ksft_exit_fail_msg("Zfh reported without implied Zfhmin\n");
+ if ((pairs[0].value & RISCV_HWPROBE_EXT_ZVFH) &&
+ !(pairs[0].value & RISCV_HWPROBE_EXT_ZVFHMIN))
+ ksft_exit_fail_msg("Zvfh reported without implied Zvfhmin\n");
+ ksft_test_result_pass("Zfh/Zvfh imply Zfhmin/Zvfhmin\n");
+
ksft_finished();
}