From bdc46e507b59ac44c8e1dab505121f18c2add1ab Mon Sep 17 00:00:00 2001 From: Xiaofeng Yuan Date: Mon, 31 Aug 2026 19:11:22 -0600 Subject: [PATCH 01/15] riscv: mm: make EXECMEM_KPROBES writable without CONFIG_STRICT_MODULE_RWX When CONFIG_STRICT_MODULE_RWX is not set, execmem cannot create temporary writable mappings for read-only executable pages. In this case, the execmem ranges must already have writable permissions. Currently EXECMEM_KPROBES unconditionally uses PAGE_KERNEL_READ_EXEC, which causes kprobe instruction slot writes to trigger page faults on systems where CONFIG_STRICT_MODULE_RWX is not enabled. Fix this by using PAGE_KERNEL_EXEC when CONFIG_STRICT_MODULE_RWX is not available. Signed-off-by: Xiaofeng Yuan Tested-by: Lad Prabhakar Reviewed-by: Nam Cao Link: https://patch.msgid.link/20260814082742.148403-2-xiaofengmian@163.com Signed-off-by: Paul Walmsley --- arch/riscv/mm/init.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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] = { From 8718e5a3090bbfd759801d088b700aab21e8e989 Mon Sep 17 00:00:00 2001 From: Xiaofeng Yuan Date: Mon, 31 Aug 2026 19:11:23 -0600 Subject: [PATCH 02/15] riscv: patch: skip fixmap mapping when kernel text is already writable patch_map() always creates a temporary writable mapping via fixmap for kernel text addresses, even when CONFIG_STRICT_KERNEL_RWX is disabled and the kernel text is already mapped with _PAGE_WRITE. This is unnecessary overhead at best, and on minimal configurations it can cause page faults. Skip the fixmap path for kernel text when CONFIG_STRICT_KERNEL_RWX is not enabled, since the text pages are already writable in that case. The module text path is already gated on CONFIG_STRICT_MODULE_RWX and is kept unchanged. Reported-by: Klara Modin Closes: https://lore.kernel.org/all/ant_8TaBbov_GS4i@soda.int.kasm.eu/ Reported-by: Lad Prabhakar Closes: https://lore.kernel.org/all/CA+V-a8tQK8rih9SGGTyqrEBGpNkx4H0eX2YccCRrgkVAPr+EBg@mail.gmail.com/ Tested-by: Klara Modin Tested-by: Lad Prabhakar Link: https://patch.msgid.link/20260814082742.148403-3-xiaofengmian@163.com Signed-off-by: Paul Walmsley --- arch/riscv/kernel/patch.c | 2 ++ 1 file changed, 2 insertions(+) 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); From 2d2184ac90365a4af3274e23c98d469f09f91749 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Mon, 31 Aug 2026 19:11:23 -0600 Subject: [PATCH 03/15] Revert "riscv: Reset pmm when PR_TAGGED_ADDR_ENABLE is not set" This reverts commit 3033b2b1e3949274f33a140e2a97571b5a307298. The reverted patch is userspace-visible behavior change, not a bug fix. The two variables here (pmm and pmlen) control two independent features: pmm is the _hardware_ pointer masking mode that applies while executing in userspace. pmlen is the shift amount that the _kernel_ uses when untagging addresses; PMLEN_0 means no untagging occurs, so the kernel does not accept tagged addresses in syscall arguments. It is valid (as documented and tested by the self test) to enable pointer masking without enabling the tagged address ABI. This separation is necessary to allow userspace to create an execution environment similar to what the kernel supports on arm64 by default, where TBI is enabled but the tagged address ABI is not. (On arm64, there is no equivalent to PR_PMLEN_MASK because TBI is always enabled.) Signed-off-by: Samuel Holland Link: https://patch.msgid.link/20260820014551.1979772-1-samuel.holland@sifive.com Cc: stable@vger.kernel.org Fixes: 3033b2b1e394 ("riscv: Reset pmm when PR_TAGGED_ADDR_ENABLE is not set") Signed-off-by: Paul Walmsley --- arch/riscv/kernel/process.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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; From 12381af01024f4a59cd3f673fb3644bbe2ca3aad Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Mon, 31 Aug 2026 19:11:23 -0600 Subject: [PATCH 04/15] riscv: use string helper in setup_global_riscv_enable() Prefer the convenient string choice 'str_disabled_enabled()' helper over hardcoded strings in 'setup_global_riscv_enable()'. Signed-off-by: Dmitry Antipov Link: https://patch.msgid.link/20260819160546.3219942-1-dmantipov@yandex.ru Signed-off-by: Paul Walmsley --- arch/riscv/kernel/usercfi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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; } From d0fc6fab20460add1f27402cd8b945d094a56b21 Mon Sep 17 00:00:00 2001 From: Andy Chiu Date: Mon, 31 Aug 2026 19:11:23 -0600 Subject: [PATCH 05/15] riscv: hwprobe: initialize pair->value in hwprobe_one_pair() The vendor-extension handlers reached from hwprobe_one_pair() (hwprobe_isa_vendor_ext_thead_0() and friends) only OR the present bits into pair->value via VENDOR_EXTENSION_SUPPORTED() and clear their own missing bits; they assume the caller has already zeroed pair->value. That holds for hwprobe_get_values() (it zeroes each pair) and hwprobe_get_cpus() (it re-initializes its scratch pair per key), but not for complete_hwprobe_vdso_data(), which reuses a single pair across all keys without re-zeroing. A vendor key therefore inherits stale bits from the previously probed key, and the wrong value is cached in the vDSO all_cpu_hwprobe_values[] and handed to userspace on the fast patih. Zero pair->value once at the top of hwprobe_one_pair() so every handler starts from a clean value regardless of the caller, and drop the now redundant zeroing in the *_BLOCK_SIZE cases. hwprobe_isa_ext0() keeps its own zeroing because hwprobe_ext0_has() calls it directly, bypassing hwprobe_one_pair(). Fixes: a5ea53da65c5 ("riscv: hwprobe: Add thead vendor extension probing") Signed-off-by: Andy Chiu Reviewed-by: Jesse Taube Link: https://patch.msgid.link/20260725001614.2578617-2-tchiu@tenstorrent.com Cc: stable@vger.kernel.org Signed-off-by: Paul Walmsley --- arch/riscv/kernel/sys_hwprobe.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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; From ddeaa39406c4cf680643412cd1f75bb98a641f6c Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Mon, 31 Aug 2026 19:11:23 -0600 Subject: [PATCH 06/15] riscv: bug: Make RV32 use GENERIC_BUG_RELATIVE_POINTERS x86 did this in commit b0a848f4a47a ("x86/bugs: Make i386 use GENERIC_BUG_RELATIVE_POINTERS") powerpc did this in commit 1baa1f70ef77 ("powerpc: Allow relative pointers in bug table entries") Similar as x86 and powerpc does, make RV32 use GENERIC_BUG_RELATIVE_POINTERS for "there is only one code path." and "less #ifdef is more better". Signed-off-by: Jisheng Zhang Link: https://patch.msgid.link/20260221024255.3552-1-jszhang@kernel.org Signed-off-by: Paul Walmsley --- arch/riscv/Kconfig | 2 +- arch/riscv/include/asm/bug.h | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) 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) \ From 6693171c8c540b3a54e671992f0561613076fc3b Mon Sep 17 00:00:00 2001 From: Xixin Liu Date: Tue, 18 Aug 2026 17:10:00 +0800 Subject: [PATCH 07/15] perf: RISC-V: use BIT_ULL for u64 overflow masks Overflow status and restart masks are u64, but bits were built with BIT(). On RV32 that is an unsigned long shift, so indices >= 32 truncate or wrap and corrupt the mask. Use BIT_ULL() for those u64 bitops. Fixes: a8625217a054 ("drivers/perf: riscv: Implement SBI PMU snapshot function") Assisted-by: DeepSeek:deepseek-v3 Signed-off-by: Xixin Liu Link: https://patch.msgid.link/prpmask01bitul.v2.1786434000.git.liuxixin@kylinos.cn Cc: stable@vger.kernel.org [pjw@kernel.org: updated to apply] Signed-off-by: Paul Walmsley --- drivers/perf/riscv_pmu_sbi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c index 50220f7b46d9..8ea5ae617347 100644 --- a/drivers/perf/riscv_pmu_sbi.c +++ b/drivers/perf/riscv_pmu_sbi.c @@ -1002,7 +1002,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); @@ -1109,14 +1109,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; From 6809da6e9c08ccc9a09cb0a48c61471679274aaa Mon Sep 17 00:00:00 2001 From: Xixin Liu Date: Tue, 18 Aug 2026 17:10:00 +0800 Subject: [PATCH 08/15] perf: RISC-V: store available counter mask as bitmap The available-counter mask was a single unsigned long, but iteration uses RISCV_MAX_COUNTERS, which is 64. On RV32 that reads past the object. Filling with an unsigned-long bit at index 32 and above is also wrong. Use DECLARE_BITMAP and set_bit/bitmap helpers. Walk each bitmap word into CFG_MATCH when checking events, when allocating an index, and when stopping all counters. Set the counter base to i times BITS_PER_LONG. Share the CFG_MATCH ecall through a small helper so the 32-bit argument split is not duplicated. On qemu-system-riscv32 the probe bitmap has bits above XLEN set, so the first word alone is not enough. Fixes: e9991434596f ("RISC-V: Add perf platform driver based on SBI PMU extension") Assisted-by: DeepSeek:deepseek-v3 Signed-off-by: Xixin Liu Link: https://patch.msgid.link/prpmask02cmap.v2.1786434000.git.liuxixin@kylinos.cn Cc: stable@kernel.org [pjw@kernel.org: updated to apply; fixed checkpatch.pl issues] Signed-off-by: Paul Walmsley --- drivers/perf/riscv_pmu_legacy.c | 5 +- drivers/perf/riscv_pmu_sbi.c | 88 +++++++++++++++++++++++---------- include/linux/perf/riscv_pmu.h | 2 +- 3 files changed, 66 insertions(+), 29 deletions(-) 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 8ea5ae617347..2c50a6ba2a80 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 @@ 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) @@ -1451,7 +1487,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 +1500,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); From 248dbaf7770c0843702355a9fb724a882c669062 Mon Sep 17 00:00:00 2001 From: JinRui Date: Tue, 11 Aug 2026 08:15:13 +0000 Subject: [PATCH 09/15] riscv: report Zfhmin/Zvfhmin when Zfh/Zvfh are present The RISC-V ISA manual specifies that Zfh implies Zfhmin, a normative rule clarified in https://github.com/riscv/riscv-isa-manual/pull/3070. Zvfh likewise implies Zvfhmin, as stated by the vector extension specification. The kernel currently reports ZFH and ZFHMIN (and ZVFH and ZVFHMIN) as independent hwprobe bits derived only from what the device tree declares. Platforms that declare just "zfh" (Zfh being a superset that already contains all Zfhmin instructions) therefore report RISCV_HWPROBE_EXT_ZFHMIN=0, which breaks userspace RVA23 conformance checks (e.g. snapd installing core26 on riscv64). Use the existing superset mechanism to set the implied subset bits: - zfh implies zfhmin - zvfh implies zvfhmin Add a hwprobe selftest asserting the implication holds and update the hwprobe documentation accordingly. This is complementary to the rva23u64 base behavior discussion: the RVA23 conformance query proposed there is derived from the per-extension bits fixed here, so correct EXT_0 reporting is a prerequisite for it to work on harts whose device tree declares only "zfh". Tested on a RISC-V QEMU VM whose device tree only declares "zfh" and "zvfh": with this change both /proc/cpuinfo and the hwprobe RISCV_HWPROBE_KEY_IMA_EXT_0 bitmap report ZFHMIN and ZVFHMIN, and the hwprobe selftest (including the new implication check) passes. Link: https://lore.kernel.org/kvm-riscv/20260206002349.96740-1-andrew.jones@oss.qualcomm.com/ Signed-off-by: JinRui Link: https://patch.msgid.link/7190E4DB338251C3+20260811081513.2849980-1-jinrui@haiwei.tech [pjw@kernel.org: trimmed superfluous blank line in tags] Signed-off-by: Paul Walmsley --- Documentation/arch/riscv/hwprobe.rst | 8 +++++--- arch/riscv/kernel/cpufeature.c | 20 +++++++++++++++++-- .../testing/selftests/riscv/hwprobe/hwprobe.c | 20 ++++++++++++++++++- 3 files changed, 42 insertions(+), 6 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/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/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(); } From f643f520c4c6998fa27dce90dd3b3ff6414e0bae Mon Sep 17 00:00:00 2001 From: Xixin Liu Date: Tue, 11 Aug 2026 11:51:00 +0800 Subject: [PATCH 10/15] perf: RISC-V: check cpu_hw_evt before dereference in overflow IRQ The overflow IRQ handler dereferences cpu_hw_evt before the null check. Move the check first. Defensive only; the cookie is valid on the normal path today. Fixes: a8625217a054 ("drivers/perf: riscv: Implement SBI PMU snapshot function") Assisted-by: DeepSeek:deepseek-v3 Signed-off-by: Xixin Liu Link: https://patch.msgid.link/fdd42c791752.v2.1786420235.git.liuxixin@kylinos.cn Signed-off-by: Paul Walmsley --- drivers/perf/riscv_pmu_sbi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c index 2c50a6ba2a80..2991dd92def2 100644 --- a/drivers/perf/riscv_pmu_sbi.c +++ b/drivers/perf/riscv_pmu_sbi.c @@ -1086,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) { From 93a27367bacdc32e2cdb478597102175db3fb80c Mon Sep 17 00:00:00 2001 From: Ivy Lopez Date: Mon, 31 Aug 2026 19:37:46 -0600 Subject: [PATCH 11/15] riscv: hwprobe: simplify has_fpu() to check D extension only The kernel never supports D without F, since D depends on F. The D-extension flag is cleared during devicetree/ACPI parsing whenever F is not present, so has_fpu() checking either extension with '||' never actually produces a different result than checking D alone - F without D cannot occur in practice, and there is no observable impact on RISCV_HWPROBE_IMA_FD or userspace. Simplify has_fpu() to check D only, matching the expectations set elsewhere in the kernel for this dependency, rather than relying on a redundant OR condition. sys_hwprobe.c already calls has_fpu() and needs no changes. Link: https://bugzilla.kernel.org/show_bug.cgi?id=221874 Suggested-by: Conor Dooley Suggested-by: Andreas Schwab Signed-off-by: Ivy Lopez Reviewed-by: Conor Dooley Link: https://patch.msgid.link/20260901013746.19386-1-skunkolee@gmail.com [pjw@kernel.org: updated to apply] Signed-off-by: Paul Walmsley --- arch/riscv/include/asm/switch_to.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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; } From 817ecd588fa5820527ee3affa43b5116276d2520 Mon Sep 17 00:00:00 2001 From: Jia Wang Date: Mon, 24 Aug 2026 13:54:14 +0800 Subject: [PATCH 12/15] dt-bindings: riscv: cpus: Fix yamllint style issues Wrap an overlong description line and normalize the inline dependency lists to satisfy yamllint. Signed-off-by: Jia Wang Acked-by: Conor Dooley Link: https://patch.msgid.link/20260824-ultrarisc-dts-v1-1-61ab7aebe9e5@ultrarisc.com Signed-off-by: Paul Walmsley --- Documentation/devicetree/bindings/riscv/cpus.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 From 74e26c692c40565448b8a1d1398c69e221a299cf Mon Sep 17 00:00:00 2001 From: Yukai Wu Date: Sat, 29 Aug 2026 10:23:27 +0800 Subject: [PATCH 13/15] docs/zh_CN: Update arch/riscv/patch-acceptance.rst translation Update Documentation/arch/riscv/patch-acceptance.rst translation. Update the translation through commit ed843ae947f8 ("docs: move riscv under arch") Signed-off-by: Yukai Wu Reviewed-by: Dongliang Mu Acked-by: Weijie Yuan Link: https://patch.msgid.link/20260829022344.192491-1-xiaoyewuz.Ruster@gmail.com Signed-off-by: Paul Walmsley --- .../zh_CN/arch/riscv/patch-acceptance.rst | 44 ++++++++++++++----- 1 file changed, 33 insertions(+), 11 deletions(-) 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 基金会的规范,这意味着“已冻结”或“已批准”,对于 +UEFI 论坛的规范,这意味着已发布的 ECR。(开发者当然可以维护自己的 Linux 内核树, +其中包含他们所需的任何扩展草案的代码。) -此外,RISC-V规范允许爱好者创建自己的自定义扩展。这些自定义拓展不需要通过RISC-V -基金会的任何审核或批准。为了避免将爱好者一些特别的RISC-V拓展添加进内核代码带来 -的维护复杂性和对性能的潜在影响,我们将只接受RISC-V基金会正式冻结或批准的的扩展 -补丁。(开发者当然可以维护自己的Linux内核树,其中包含他们想要的任何自定义扩展 -的代码。) +此外,RISC-V 规范允许实现者创建自己的自定义扩展。这些自定义扩展不需要通过 RISC-V +基金会的任何审核或批准流程。为了避免因添加实现者特定的 RISC-V 扩展带来的维护复杂 +性和对性能的潜在影响,我们将只考虑符合以下任一条件的扩展补丁: + +- 已由 RISC-V 基金会正式冻结或批准 +- 已按照标准 Linux 惯例,在广泛可用的硬件中实现 + +(实现者当然可以维护自己的 Linux 内核树,其中包含他们所需的任何自定义扩展的代码。) From 2464ac8a6ff8d8a18b50088eb1d1d638f9cee2f1 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 13 Aug 2026 09:53:04 +0200 Subject: [PATCH 14/15] kselftest/riscv: Replace __ASSEMBLY__ with __ASSEMBLER__ While the GCC and Clang compilers already define __ASSEMBLER__ automatically when compiling assembly code, __ASSEMBLY__ is a macro that only gets defined by the Makefiles in the kernel. This can be very confusing when switching between userspace and kernelspace coding, or when dealing with uapi headers that rather should use __ASSEMBLER__ instead. So let's standardize now on the __ASSEMBLER__ macro that is provided by the compilers. Signed-off-by: Thomas Huth Reviewed-by: Nick Desaulniers Link: https://patch.msgid.link/20260813075304.75988-1-thuth@redhat.com Signed-off-by: Paul Walmsley --- tools/testing/selftests/riscv/cfi/cfi_rv_test.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From b94cec5761d22624d109d859467d7d4ce0a1b88b Mon Sep 17 00:00:00 2001 From: Andy Chiu Date: Tue, 1 Sep 2026 14:23:32 -0500 Subject: [PATCH 15/15] riscv: skip software algning code for HAVE_EFFICIENT_UNALIGNED_ACCESS We can jump straight into the copy loop if the kernel is compiled for a hardware that natively supports misaligned access. The user copy bandwidth improvement on K3 and Ascaolon is shown as below: Misaligned user copy, size: 512B (offset: [0:15] except 0, 8) BW Improvement | Write | Read | K3 | 6.19% | 3.43% | Ascalon | 10.0% | 11.4% | Aligned user copy, size: 512B (offset: 0, 8) BW Improvement | Write | Read | K3 | 1.69% | 0.90% | Ascalon | 1.25% | 3.32% | Suggested-by: Anton Blanchard Signed-off-by: Andy Chiu Link: https://patch.msgid.link/20260901192334.3543340-1-tchiu@tenstorrent.com Signed-off-by: Paul Walmsley --- arch/riscv/lib/uaccess.S | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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: /*