mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
perf/cxl: Unfreeze counters after handling an overflow interrupt
The counters run with Freeze on Overflow set, so one overflow freezes every
counter in the block (CXL r4.0 8.2.7.2.1), and a frozen counter "remains
frozen until explicitly unfrozen by software" (8.2.7.1.3, Table 8-183).
cxl_pmu_irq() reads the overflowed counters and clears the overflow status
but never unfreezes, so everything stays frozen until the next pmu_enable()
and events in that window are lost.
Unfreeze after clearing the status, unless the PMU has been disabled in the
meantime - cxl_pmu_disable() freezes the block deliberately. Track the
enabled state and leave it frozen in that case.
Fixes: 5d7107c727 ("perf: CXL Performance Monitoring Unit driver")
Reported-by: sashiko-bot@kernel.org
Closes: https://sashiko.dev/#/patchset/20260715191454.459673-1-dave@stgolabs.net?part=1
Assisted-by: Claude:claude-opus-4-8
Reviewed-by: Jonathan Cameron <jonathan.cameron@oss.qualcomm.com>
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Signed-off-by: Will Deacon <will@kernel.org>
This commit is contained in:
parent
b899fd3487
commit
2e4fe234c7
|
|
@ -113,6 +113,8 @@ struct cxl_pmu_info {
|
|||
bool filter_crb;
|
||||
int msi_vec;
|
||||
int irq;
|
||||
/* Set between pmu_enable() and pmu_disable(), read by the IRQ handler */
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
#define pmu_to_cxl_pmu_info(_pmu) container_of(_pmu, struct cxl_pmu_info, pmu)
|
||||
|
|
@ -701,6 +703,7 @@ static void cxl_pmu_enable(struct pmu *pmu)
|
|||
void __iomem *base = info->base;
|
||||
|
||||
/* Can assume frozen at this stage */
|
||||
WRITE_ONCE(info->enabled, true);
|
||||
writeq(0, base + CXL_PMU_FREEZE_REG);
|
||||
}
|
||||
|
||||
|
|
@ -709,6 +712,7 @@ static void cxl_pmu_disable(struct pmu *pmu)
|
|||
struct cxl_pmu_info *info = pmu_to_cxl_pmu_info(pmu);
|
||||
void __iomem *base = info->base;
|
||||
|
||||
WRITE_ONCE(info->enabled, false);
|
||||
/*
|
||||
* Whilst bits above number of counters are RsvdZ
|
||||
* they are unlikely to be repurposed given
|
||||
|
|
@ -915,6 +919,21 @@ static irqreturn_t cxl_pmu_irq(int irq, void *data)
|
|||
|
||||
writeq(overflowed, base + CXL_PMU_OVERFLOW_REG);
|
||||
|
||||
/*
|
||||
* An overflow freezes every counter in the CPMU, so unfreeze once the
|
||||
* overflowed ones have been read and their status cleared. Otherwise
|
||||
* they stay frozen until the next pmu_enable() and events are lost.
|
||||
*
|
||||
* Not while the PMU is disabled, so as not to undo an intentional freeze.
|
||||
* The check is advisory, not exclusive: pmu_disable() normally runs on
|
||||
* info->on_cpu with interrupts off, where the pinned handler cannot
|
||||
* preempt it. In the one window where it does not - the migration in
|
||||
* cxl_pmu_offline_cpu() - the counters are legitimately running again,
|
||||
* so unfreezing is correct there anyway.
|
||||
*/
|
||||
if (READ_ONCE(info->enabled))
|
||||
writeq(0, base + CXL_PMU_FREEZE_REG);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user