Linux Perf Users
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Zhanpeng Zhang" <zhangzhanpeng.jasper@bytedance.com>
Cc: linux-perf-users@vger.kernel.org
Subject: Re: [PATCH v10 7/9] perf: RISC-V: add support for SSE event
Date: Fri, 11 Sep 2026 12:37:59 +0000	[thread overview]
Message-ID: <20260911123800.577FE1F00893@smtp.kernel.org> (raw)
In-Reply-To: <20260911121456.33223-8-zhangzhanpeng.jasper@bytedance.com>

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

New issues:
- [High] The SSE overflow handler early bailout checks `events[fidx]` where `fidx` is the lowest active counter in `used_hw_ctrs`. Because `used_hw_ctrs` is updated non-atomically relative to `events[]` during event addition and deletion, an SSE NMI arriving in this window observes a NULL event and permanently stops all PMU counters.
- [High] Synchronously calling `riscv_pmu_stop` from `pmu_sbi_fail_sse` in NMI context corrupts PMU state if it interrupts perf core operations.
- [Medium] Overloaded use of `ret == 0` causes `irq_requested` to be true even when SSE setup succeeds (which does not request an IRQ). This leads to an invalid `free_percpu_irq` on IRQ 0 in the probe error path.

Pre-existing issues:
- [High] On 32-bit RISC-V architectures, the driver uses a 32-bit `unsigned long` for `cmask` and invokes `BIT(i)` in a loop up to `RISCV_MAX_COUNTERS` (64). This causes undefined behavior when `i >= 32` and fails to track or stop PMU counters with IDs >= 32.
--

commit 9148146c03e3720e4a1ce81cb1e6c77ab87c87df
Author: Clément Léger <cleger@rivosinc.com>
Subject: perf: RISC-V: add support for SSE event

This commit adds support for the local PMU overflow SSE event so that RISC-V
perf can receive overflows even when normal S-mode interrupts are masked. It
selects the delivery mechanism during PMU probe and configures SSE event
masking across CPU power management transitions.

> diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
> index 50220f7b46d9b..7e971b47730c4 100644
> --- a/drivers/perf/riscv_pmu_sbi.c
> +++ b/drivers/perf/riscv_pmu_sbi.c
> @@ -896,14 +898,24 @@ static int pmu_sbi_get_ctrinfo(int nctr, unsigned long *mask)
>  	return 0;
>  }
>  
> -static inline void pmu_sbi_stop_all(struct riscv_pmu *pmu)
> +static inline void pmu_sbi_stop_all_mask(unsigned long ctr_mask)
>  {
>  	/*
>  	 * 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);
> +		  0, ctr_mask, SBI_PMU_STOP_FLAG_RESET, 0, 0, 0);
> +}

[Severity: High]
This is a pre-existing issue, but on 32-bit RISC-V architectures, cmask is
an unsigned long, which truncates to 32 bits on RV32. In pmu_sbi_get_ctrinfo(),
the driver also invokes BIT(i) in a loop up to RISCV_MAX_COUNTERS (64). Does
this cause undefined behavior and fail to track or stop firmware/hardware PMU
counters with IDs >= 32 during PMU teardown or SSE early-exit paths?

[ ... ]

> +#ifdef CONFIG_RISCV_PMU_SBI_SSE
> +/*
> + * A local SSE delivery failure makes the current PMU state unsafe to resume.
> + * Latch the failure before stopping mapped events so the SSE transition and
> + * overflow restart paths cannot undo the fail-safe while they are quiesced.
> + */
> +static void pmu_sbi_fail_sse(struct riscv_pmu *pmu, const char *op, int ret)
> +{
> +	struct cpu_hw_events *cpu_hw_evt = this_cpu_ptr(pmu->hw_events);
> +	struct perf_event *event;
> +	int idx;
> +
> +	if (READ_ONCE(cpu_hw_evt->sse_failed))
> +		return;
> +
> +	WRITE_ONCE(cpu_hw_evt->sse_failed, true);
> +	pr_err_ratelimited("failed to %s local PMU SSE event: %d; stopping counters\n",
> +			   op, ret);
> +
> +	for (idx = 0; idx < RISCV_MAX_COUNTERS; idx++) {
> +		event = cpu_hw_evt->events[idx];
> +		if (event)
> +			riscv_pmu_stop(event, PERF_EF_UPDATE);

[Severity: High]
Can calling riscv_pmu_stop() synchronously from pmu_sbi_fail_sse() corrupt
PMU state if executed in NMI context? 

When pmu_sbi_ovf_sse_handler() receives a NULL regs pointer, it calls
pmu_sbi_fail_sse(). If this NMI interrupts perf core operations like
riscv_pmu_start(), the software state could become desynchronized from the
hardware counter state.

> +	}
> +}

[ ... ]

> @@ -1048,28 +1154,38 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
>  	struct perf_event *event;
>  	u64 overflow;
>  	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;
>  
>  	if (WARN_ON_ONCE(!cpu_hw_evt))
>  		return IRQ_NONE;
>  
> -	/* Firmware counter don't support overflow yet */
> +	/*
> +	 * SSE can arrive before perf installs an event. The early exits below
> +	 * must stop the PMU source before firmware completes the SSE.
> +	 */
>  	fidx = find_first_bit(cpu_hw_evt->used_hw_ctrs, RISCV_MAX_COUNTERS);
>  	if (fidx == RISCV_MAX_COUNTERS) {
> -		csr_clear(CSR_SIP, BIT(riscv_pmu_irq_num));
> +		if (from_sse)
> +			pmu_sbi_stop_all_mask(cmask);
> +		else
> +			csr_clear(CSR_SIP, BIT(riscv_pmu_irq_num));
>  		return IRQ_NONE;
>  	}
>  
>  	event = cpu_hw_evt->events[fidx];
>  	if (!event) {
> -		ALT_SBI_PMU_OVF_CLEAR_PENDING(riscv_pmu_irq_mask);
> +		if (from_sse)
> +			pmu_sbi_stop_all_mask(cmask);
> +		else
> +			ALT_SBI_PMU_OVF_CLEAR_PENDING(riscv_pmu_irq_mask);
>  		return IRQ_NONE;
>  	}

[Severity: High]
Does this early bailout race with concurrent event addition or deletion?

The used_hw_ctrs bit is set inside riscv_pmu_add() via ctr_get_idx(), which
exposes a window where events[fidx] is NULL while the bit is active. If an
SSE NMI arrives in this window, it observes a NULL event and triggers the
!event fallback path, permanently stopping all PMU counters via
pmu_sbi_stop_all_mask().

[ ... ]

> @@ -1453,6 +1806,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))
>  		goto out_free;
> +	pmu->cmask = cmask;
>  
>  	ret = pmu_sbi_setup_irqs(pmu, pdev);
>  	if (ret < 0) {
> @@ -1462,9 +1816,15 @@ static int pmu_sbi_device_probe(struct platform_device *pdev)
>  	}
>  	irq_requested = (ret == 0);

[Severity: Medium]
Could this attempt to free an unallocated IRQ on the error path?

Because pmu_sbi_setup_irqs() now returns 0 when SSE setup succeeds,
irq_requested is set to true even when no IRQ was requested. If a subsequent
initialization step fails, the out_destroy error path would call
free_percpu_irq() for IRQ 0.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260911121456.33223-1-zhangzhanpeng.jasper@bytedance.com?part=7

  reply	other threads:[~2026-09-11 12:38 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-11 12:14 [PATCH v10 0/9] riscv: add SBI Supervisor Software Events support Zhanpeng Zhang
2026-09-11 12:14 ` [PATCH v10 1/9] riscv: add SBI SSE extension definitions Zhanpeng Zhang
2026-09-11 12:20   ` sashiko-bot
2026-09-11 12:14 ` [PATCH v10 2/9] riscv: add support for SBI Supervisor Software Events extension Zhanpeng Zhang
2026-09-11 12:34   ` sashiko-bot
2026-09-11 12:14 ` [PATCH v10 3/9] riscv: sse: mask events during shutdown and kexec Zhanpeng Zhang
2026-09-11 12:30   ` sashiko-bot
2026-09-11 12:14 ` [PATCH v10 4/9] drivers: firmware: add riscv SSE support Zhanpeng Zhang
2026-09-11 12:35   ` sashiko-bot
2026-09-11 12:14 ` [PATCH v10 5/9] riscv: mm: avoid enabling interrupts for nofault page faults Zhanpeng Zhang
2026-09-11 12:28   ` sashiko-bot
2026-09-11 12:14 ` [PATCH v10 6/9] perf: RISC-V: support callchains with SSE delivery Zhanpeng Zhang
2026-09-11 12:35   ` sashiko-bot
2026-09-11 12:14 ` [PATCH v10 7/9] perf: RISC-V: add support for SSE event Zhanpeng Zhang
2026-09-11 12:37   ` sashiko-bot [this message]
2026-09-11 12:14 ` [PATCH v10 8/9] selftests/riscv: add SSE test module Zhanpeng Zhang
2026-09-11 12:40   ` sashiko-bot
2026-09-11 12:14 ` [PATCH v10 9/9] selftests/riscv: add perf user-stack SSE copy regression test Zhanpeng Zhang
2026-09-11 12:33   ` sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260911123800.577FE1F00893@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=zhangzhanpeng.jasper@bytedance.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox