RISC-V updates for v7.3-rc3

- Revert a bad fix, likely LLM-generated, in the pointer masking code
   that confused the RISC-V hardware pointer masking implementation
   with the Linux kernel tagged address feature
 
 - Fix unexpected faults caused by kprobe instruction slot writes when
   !CONFIG_STRICT_MODULE_RWX
 
 - Fix unexpected faults on minimal configurations during runtime code
   patching on !CONFIG_STRICT_MODULE_RWX systems
 
 - Fix a misplaced variable clear causing incorrect reuse of previous
   values in the RISC-V hardware feature probing code
 
 - Fix two bugs in the PMU SBI perf code on rv32: use BIT_ULL rather
   than BIT on 64-bit masks; and use a bitmap rather than an unsigned
   long on a quantity that can exceed 32 bits
 
 And a few miscellaneous cleanups:
 
 - Avoid a potential dereference-before-NULL-pointer-check bug in the
   PMU SBI perf driver
 
 - Simplify the rv32 bug table code by using
   CONFIG_GENERIC_BUG_RELATIVE_POINTERS (following x86 and PPC)
 
 - Report the RISC-V standard ISA extensions Z[v]fhmin when support is
   claimed for the superset RISC-V standard ISA extensions Z[v]fh; and
   simplify our FPU test code to only check for the presence of the D
   extension
 
 - Use an existing kernel string helper in place of some open-coded
   code in kernel/usercfi.c
 
 - Fix some yamllint issues in the RISC-V DT bindings for CPUs
 
 - Convert one use of __ASSEMBLY__ to __ASSEMBLER__ that snuck into the
   RISC-V CFI selftest code
 
 - Update the translation for the simplified Chinese translation of the
   RISC-V kernel patch acceptance policy
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEElRDoIDdEz9/svf2Kx4+xDQu9KksFAmqghcoACgkQx4+xDQu9
 KkvmEQ/7BVmPFuoR6OLNk2Eu8Exqen6a41KxdM/B91NJBEbBM60GAyejjWDXWmm0
 K21yhRu58RGbfg2kKUJMvawzwIfuDswxCS31VtpDKnTrmP4HQz1Yvnh2M7jH9D2d
 /wJCIYcJ0hJx0yDIZOUhU24aoy63ZXRygp8nTOgjkAxhkF31w+MJxTPDD0Ir7Eai
 y4sRMTCabMonmyA0qozfnMoXaO3FkPv9l7pw/LHfqUYjaLNQyMHiiDPrRj1oNZPD
 GQFUWykRgMccMW6kIgTJrjmzn7+vEJ7UZ/fvOD97+rGeaoyE19vcW8owUQWp6Hgb
 Jq3WyS9HImrpCBTr079ht5lhu3ZucpAEP6sK5v/m4GOlBv1HdYHUS6JH0qo4DnXZ
 aFrxg7WXxaFZ8dD3P8ErZkXy5Vid3+ZlpK//AOfWAqxX7q6c4K1w3lJm4bPKyNBX
 vh3ASQr5oEj3KpGbihsrX2lVB/5LVP3pWTcH5f6rBBYiVFMMhWKLJXA3pjiRFN7v
 ZXClKh5MznvS6ycMp5pXVYpVn2Kk+Y/mywsDqNRUigHwppkxI9MTJBq8+qcOiM9I
 a7mHna4XHVVu0+B4/JMhkWgnGYRjFD6bsGzxPZODLFcmBUxmsoa5+HOENLAGdQ1w
 s/Z2HmDO8yL37DxLq5O2aF3KNPSkXNBl+upQwj5lTTzR/bmghjc=
 =oMU+
 -----END PGP SIGNATURE-----

Merge tag 'riscv-for-linus-7.3-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux

Pull RISC-V fixes from Paul Walmsley:
 "From a RISC-V point of view, there's one notable fix here, reverting
  an earlier bogus fix to the pointer masking code. Fortunately the
  practical impact appears to be small.

   - Revert a bad fix, likely LLM-generated, in the pointer masking code
     that confused the RISC-V hardware pointer masking implementation
     with the Linux kernel tagged address feature

   - Fix unexpected faults caused by kprobe instruction slot writes when
     !CONFIG_STRICT_MODULE_RWX

   - Fix unexpected faults on minimal configurations during runtime code
     patching on !CONFIG_STRICT_MODULE_RWX systems

   - Fix a misplaced variable clear causing incorrect reuse of previous
     values in the RISC-V hardware feature probing code

   - Fix two bugs in the PMU SBI perf code on rv32: use BIT_ULL rather
     than BIT on 64-bit masks; and use a bitmap rather than an unsigned
     long on a quantity that can exceed 32 bits

  And a few miscellaneous cleanups:

   - Avoid a potential dereference-before-NULL-pointer-check bug in the
     PMU SBI perf driver

   - Use CONFIG_GENERIC_BUG_RELATIVE_POINTERS to simplify the rv32 bug
     table code (like x86 and PPC)

   - Report the RISC-V standard ISA extensions Z[v]fhmin when support is
     claimed for the superset RISC-V standard ISA extensions Z[v]fh; and
     simplify our FPU test code to only check for the presence of the D
     extension

   - Use an existing kernel string helper in place of some open-coded
     code in kernel/usercfi.c

   - Fix some yamllint issues in the RISC-V DT bindings for CPUs

   - Convert one use of __ASSEMBLY__ to __ASSEMBLER__ that snuck into
     the RISC-V CFI selftest code

   - Update the translation for the simplified Chinese translation of
     the RISC-V kernel patch acceptance policy"

* tag 'riscv-for-linus-7.3-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux:
  riscv: skip software algning code for HAVE_EFFICIENT_UNALIGNED_ACCESS
  kselftest/riscv: Replace __ASSEMBLY__ with __ASSEMBLER__
  docs/zh_CN: Update arch/riscv/patch-acceptance.rst translation
  dt-bindings: riscv: cpus: Fix yamllint style issues
  riscv: hwprobe: simplify has_fpu() to check D extension only
  perf: RISC-V: check cpu_hw_evt before dereference in overflow IRQ
  riscv: report Zfhmin/Zvfhmin when Zfh/Zvfh are present
  perf: RISC-V: store available counter mask as bitmap
  perf: RISC-V: use BIT_ULL for u64 overflow masks
  riscv: bug: Make RV32 use GENERIC_BUG_RELATIVE_POINTERS
  riscv: hwprobe: initialize pair->value in hwprobe_one_pair()
  riscv: use string helper in setup_global_riscv_enable()
  Revert "riscv: Reset pmm when PR_TAGGED_ADDR_ENABLE is not set"
  riscv: patch: skip fixmap mapping when kernel text is already writable
  riscv: mm: make EXECMEM_KPROBES writable without CONFIG_STRICT_MODULE_RWX
This commit is contained in:
Linus Torvalds 2026-09-11 13:15:13 -07:00
commit 827751b699
18 changed files with 169 additions and 74 deletions

View File

@ -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

View File

@ -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

View File

@ -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 基金会的规范,这意味着“已冻结”或“已批准”,对于
UEFI 论坛的规范,这意味着已发布的 ECR。开发者当然可以维护自己的 Linux 内核树,
其中包含他们所需的任何扩展草案的代码。)
此外RISC-V规范允许爱好者创建自己的自定义扩展。这些自定义拓展不需要通过RISC-V
基金会的任何审核或批准。为了避免将爱好者一些特别的RISC-V拓展添加进内核代码带来
的维护复杂性和对性能的潜在影响我们将只接受RISC-V基金会正式冻结或批准的的扩展
补丁。开发者当然可以维护自己的Linux内核树其中包含他们想要的任何自定义扩展
的代码。)
此外RISC-V 规范允许实现者创建自己的自定义扩展。这些自定义扩展不需要通过 RISC-V
基金会的任何审核或批准流程。为了避免因添加实现者特定的 RISC-V 扩展带来的维护复杂
性和对性能的潜在影响,我们将只考虑符合以下任一条件的扩展补丁:
- 已由 RISC-V 基金会正式冻结或批准
- 已按照标准 Linux 惯例,在广泛可用的硬件中实现
(实现者当然可以维护自己的 Linux 内核树,其中包含他们所需的任何自定义扩展的代码。)

View File

@ -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

View File

@ -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) \

View File

@ -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; }

View File

@ -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),

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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:
/*

View File

@ -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] = {

View File

@ -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;

View File

@ -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 @@ static int pmu_sbi_check_event_info(void)
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;

View File

@ -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);

View File

@ -56,7 +56,7 @@
#define CSR_SSP 0x011
#ifdef __ASSEMBLY__
#ifdef __ASSEMBLER__
#define __ASM_STR(x) x
#else
#define __ASM_STR(x) #x

View File

@ -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();
}