Linux CXL
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Dave Jiang" <dave.jiang@intel.com>
Cc: linux-cxl@vger.kernel.org, linux-perf-users@vger.kernel.org
Subject: Re: [PATCH v3 2/9] perf/cxl: Clear stale event fields before reprogramming a counter
Date: Fri, 31 Jul 2026 23:40:28 +0000	[thread overview]
Message-ID: <20260731234028.77A111F00AC4@smtp.kernel.org> (raw)
In-Reply-To: <20260731232827.401447-3-dave.jiang@intel.com>

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

Pre-existing issues:
- [High] writeq() used on 32-bit CXL PMU Filter Config registers clobbers the adjacent Filter 1 configuration with zeros.
- [High] Pending hardware overflows from stopped events are erroneously attributed to newly started events on the same counter, causing massive spurious counts.
- [High] Two's complement arithmetic misunderstanding causes the driver to overcount by exactly 2^width on almost every overflow interrupt.
--

--- Patch [2]: [PATCH v3 2/9] perf/cxl: Clear stale event fields before reprogramming a counter ---
commit e2d9388d1e46f8effd5efea9988cf263ff2efd2c
Author: Dave Jiang <dave.jiang@intel.com>

perf/cxl: Clear stale event fields before reprogramming a counter

cxl_pmu_event_start() ORs the event group id, event mask, edge and invert
selections into a configurable counter's config register without clearing
them first, and cxl_pmu_event_stop() leaves them set. Reuse the counter for
another event and the new selection lands on top of the old one, so the
counter counts the wrong events with stale edge and invert behaviour.

Closes: https://sashiko.dev/#/patchset/20260715191454.459673-1-dave@stgolabs.net?part=1

> diff --git a/drivers/perf/cxl_pmu.c b/drivers/perf/cxl_pmu.c
> index ff01b658e1b45..b16e2e4090a39 100644
> --- a/drivers/perf/cxl_pmu.c
> +++ b/drivers/perf/cxl_pmu.c
> @@ -646,17 +646,17 @@ static void cxl_pmu_event_start(struct perf_event *event, int flags)

[Severity: High]
This is a pre-existing issue, but I noticed a potential problem earlier in
cxl_pmu_event_start():

drivers/perf/cxl_pmu.c:cxl_pmu_event_start() {
    ...
    if (info->filter_hdm) {
        if (cxl_pmu_config1_hdm_filter_en(event))
            cfg = cxl_pmu_config2_get_hdm_decoder(event);
        else
            cfg = GENMASK(31, 0);
        writeq(cfg, base + CXL_PMU_FILTER_CFG_REG(hwc->idx, 0));
    ...
}

Does using the 64-bit writeq() here overwrite the adjacent Filter 1
configuration register at offset +4 with the upper 32 bits of cfg (which are
zeros)? This might cause the PMU hardware to silently drop events that do not
match 0 for Filter 1's property, breaking PMU counting for this counter.

>  	cfg |= FIELD_PREP(CXL_PMU_COUNTER_CFG_INT_ON_OVRFLW, 1);
>  	cfg |= FIELD_PREP(CXL_PMU_COUNTER_CFG_FREEZE_ON_OVRFLW, 1);
>  	cfg |= FIELD_PREP(CXL_PMU_COUNTER_CFG_ENABLE, 1);
> -	cfg |= FIELD_PREP(CXL_PMU_COUNTER_CFG_EDGE,
> -			  cxl_pmu_config1_get_edge(event) ? 1 : 0);
> -	cfg |= FIELD_PREP(CXL_PMU_COUNTER_CFG_INVERT,
> -			  cxl_pmu_config1_get_invert(event) ? 1 : 0);
> +	FIELD_MODIFY(CXL_PMU_COUNTER_CFG_EDGE, &cfg,
> +		     cxl_pmu_config1_get_edge(event) ? 1 : 0);
> +	FIELD_MODIFY(CXL_PMU_COUNTER_CFG_INVERT, &cfg,
> +		     cxl_pmu_config1_get_invert(event) ? 1 : 0);
>  
>  	/* Fixed purpose counters have next two fields RO */
>  	if (test_bit(hwc->idx, info->conf_counter_bm)) {
> -		cfg |= FIELD_PREP(CXL_PMU_COUNTER_CFG_EVENT_GRP_ID_IDX_MSK,
> -				  hwc->event_base);
> -		cfg |= FIELD_PREP(CXL_PMU_COUNTER_CFG_EVENTS_MSK,
> -				  cxl_pmu_config_get_mask(event));
> +		FIELD_MODIFY(CXL_PMU_COUNTER_CFG_EVENT_GRP_ID_IDX_MSK, &cfg,
> +			     hwc->event_base);
> +		FIELD_MODIFY(CXL_PMU_COUNTER_CFG_EVENTS_MSK, &cfg,
> +			     cxl_pmu_config_get_mask(event));
>  	}
>  	cfg &= ~CXL_PMU_COUNTER_CFG_THRESHOLD_MSK;
>  	/*

[Severity: High]
This isn't a bug introduced by this patch, but I spotted a potential issue with
hardware overflow attribution when stopping and starting events.

If a counter overflows right before being stopped, the hardware sets the
overflow bit and raises an interrupt, but the pending overflow bit in
CXL_PMU_OVERFLOW_REG is not cleared:

drivers/perf/cxl_pmu.c:cxl_pmu_event_stop() {
    ...
    cfg &= ~(FIELD_PREP(CXL_PMU_COUNTER_CFG_INT_ON_OVRFLW, 1) |
             FIELD_PREP(CXL_PMU_COUNTER_CFG_ENABLE, 1));
    writeq(cfg, base + CXL_PMU_COUNTER_CFG_REG(hwc->idx));
    ...
}

When a new event is scheduled onto the same counter via cxl_pmu_event_start()
and the interrupt fires, will the ISR attribute the overflow to the newly
started event?

drivers/perf/cxl_pmu.c:cxl_pmu_irq() {
    ...
    for_each_set_bit(i, overflowedbm, info->num_counters) {
        struct perf_event *event = info->hw_events[i];
        if (!event)
            continue;
        __cxl_pmu_read(event, true);
    }
    ...
}

Could this cause massive spurious event counts to be falsely attributed to new
events during normal perf multiplexing?


[Severity: High]
This is a pre-existing issue, but does __cxl_pmu_read() overcount on overflow
interrupts?

drivers/perf/cxl_pmu.c:__cxl_pmu_read() {
    ...
    delta = (new_cnt - prev_cnt) & GENMASK_ULL(info->counter_width - 1, 0);
    if (overflow && delta < GENMASK_ULL(info->counter_width - 1, 0))
        delta += (1UL << info->counter_width);
    ...
}

Because these are unsigned 64-bit integers, the masked subtraction natively
accounts for exactly one counter wrap, yielding the correct positive event
delta. 

Since delta is already correct, does adding (1UL << info->counter_width) on top
of it cause the driver to overcount by exactly 2^width on almost every overflow
interrupt?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260731232827.401447-1-dave.jiang@intel.com?part=2

  reply	other threads:[~2026-07-31 23:40 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-31 23:28 [PATCH v3 0/9] perf/cxlpmu: Misc sashiko raised issues fixes Dave Jiang
2026-07-31 23:28 ` [PATCH v3 1/9] perf/cxl: Program the requested event group on configurable counters Dave Jiang
2026-07-31 23:38   ` sashiko-bot
2026-07-31 23:28 ` [PATCH v3 2/9] perf/cxl: Clear stale event fields before reprogramming a counter Dave Jiang
2026-07-31 23:40   ` sashiko-bot [this message]
2026-07-31 23:28 ` [PATCH v3 3/9] perf/cxl: Fix the counter overflow delta fixup Dave Jiang
2026-07-31 23:37   ` sashiko-bot
2026-07-31 23:28 ` [PATCH v3 4/9] perf/cxl: Split the MSI vector out of info->irq Dave Jiang
2026-07-31 23:45   ` sashiko-bot
2026-07-31 23:28 ` [PATCH v3 5/9] perf/cxl: Accept an overflow interrupt on MSI message number 0 Dave Jiang
2026-07-31 23:28 ` [PATCH v3 6/9] perf/cxl: Don't share the overflow interrupt, and keep it pinned Dave Jiang
2026-07-31 23:50   ` sashiko-bot
2026-07-31 23:28 ` [PATCH v3 7/9] perf/cxl: Unfreeze counters after handling an overflow interrupt Dave Jiang
2026-07-31 23:40   ` sashiko-bot
2026-07-31 23:28 ` [PATCH v3 8/9] perf/cxl: Validate the hardware-reported counter width Dave Jiang
2026-07-31 23:28 ` [PATCH v3 9/9] perf/cxl: Don't log through pmu.dev in the overflow interrupt handler Dave Jiang
2026-07-31 23:46   ` 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=20260731234028.77A111F00AC4@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=dave.jiang@intel.com \
    --cc=linux-cxl@vger.kernel.org \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /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