Re: [PATCH v4 02/11] perf/cxl: Clear stale event fields before reprogramming a counter
[email protected] Wed, 05 Aug 2026 16:07:49 +0000
| Newsgroups | org.kernel.vger.linux-perf-users |
|---|---|
| Message-ID | <[email protected]> |
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: Pre-existing issues: - [High] Writing to the 32-bit filter configuration register with `writeq` (64-bit) overwrites the adjacent filter register, causing silent event drops on hardware with multiple filters. - [High] The overflow calculation in `__cxl_pmu_read()` double-counts events by erroneously adding `2^width` to a correctly computed delta. -- --- Patch [2]: [PATCH v4 02/11] perf/cxl: Clear stale event fields before reprogramming a counter --- commit 54f01a971c5fe0d0d8f7face1960b3232e30fafb Author: Dave Jiang <[email protected]> perf/cxl: Clear stale event fields before reprogramming a counter This commit uses FIELD_MODIFY() to clear stale event fields before reprogramming a counter. This ensures new selections don't land on top of old ones when reusing counters. Link: https://sashiko.dev/#/patchset/[email protected]?part=1 > diff --git a/drivers/perf/cxl_pmu.c b/drivers/perf/cxl_pmu.c > --- a/drivers/perf/cxl_pmu.c > +++ b/drivers/perf/cxl_pmu.c [ ... ] > @@ -638,30 +638,30 @@ static void cxl_pmu_event_start(struct perf_event *event, int flags) > 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); /* No filtering if 0xFFFF_FFFF */ > writeq(cfg, base + CXL_PMU_FILTER_CFG_REG(hwc->idx, 0)); [Severity: High] This isn't a bug introduced by this patch, but could this writeq() unintentionally overwrite the adjacent filter register? Since CXL_PMU_FILTER_CFG_REG is a 32-bit register and writeq() performs a 64-bit write, the variable cfg (which has 0 in its upper 32 bits) will inadvertently zero out the adjacent 32 bits corresponding to Filter 1. Because writing 0 enables a filter and forces an exact match of 0, any hardware implementing Filter 1 will logically AND it with Filter 0, effectively dropping all non-zero events. > } > > cfg = readq(base + CXL_PMU_COUNTER_CFG_REG(hwc->idx)); > 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); [ ... ] > @@ -700,10 +700,10 @@ static void __cxl_pmu_read(struct perf_event *event, bool overflow) > /* > * If we know an overflow occur then take that into account. > * Note counter is not reset as that would lose events > */ > 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); [Severity: High] This is a pre-existing issue, but is it possible this addition double-counts events? The 2's complement arithmetic delta = (new_cnt - prev_cnt) & GENMASK_ULL(...) already naturally calculates the delta across a single wrap-around. For example, with a 32-bit counter, 0x10 - 0xFFFFFFF0 masked strictly yields 0x20. If this condition evaluates to true, it injects an additional 2^width into the delta, reporting billions of extraneous events per normal overflow. Additionally, if info->counter_width is 64, does 1UL << 64 result in undefined behavior in C? > local64_add(delta, &event->count); > } -- Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=2