* [PATCH 0/2] perf/cxlpmu: Misc updates
@ 2026-06-30 23:50 Davidlohr Bueso
2026-06-30 23:50 ` [PATCH v2 1/2] perf/cxlpmu: Support Channel/Rank/Bank filter Davidlohr Bueso
2026-06-30 23:50 ` [PATCH 2/2] perf/cxlpmu: Add missing CXL 4.0 events Davidlohr Bueso
0 siblings, 2 replies; 5+ messages in thread
From: Davidlohr Bueso @ 2026-06-30 23:50 UTC (permalink / raw)
To: jic23, will, mark.rutland
Cc: harshal.t, linux-cxl, linux-perf-users, Davidlohr Bueso
Hello,
Two patches for the CXL PMU driver.
Patch 1 adds support for new filters and is a v2 of
https://lore.kernel.org/all/20260611010409.2776635-1-dave@stgolabs.net/
Patch 2 adds the CXL 4.0 events that hardware exposes but
the driver did not.
Both have been tested on real hardware.
Thanks!
Davidlohr
Harshal Thakkar (2):
perf/cxlpmu: Support Channel/Rank/Bank filter
perf/cxlpmu: Add missing CXL 4.0 events
drivers/perf/cxl_pmu.c | 91 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 88 insertions(+), 3 deletions(-)
--
2.39.5
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2 1/2] perf/cxlpmu: Support Channel/Rank/Bank filter
2026-06-30 23:50 [PATCH 0/2] perf/cxlpmu: Misc updates Davidlohr Bueso
@ 2026-06-30 23:50 ` Davidlohr Bueso
2026-07-01 1:55 ` sashiko-bot
2026-07-09 9:16 ` Richard Cheng
2026-06-30 23:50 ` [PATCH 2/2] perf/cxlpmu: Add missing CXL 4.0 events Davidlohr Bueso
1 sibling, 2 replies; 5+ messages in thread
From: Davidlohr Bueso @ 2026-06-30 23:50 UTC (permalink / raw)
To: jic23, will, mark.rutland
Cc: harshal.t, linux-cxl, linux-perf-users, Davidlohr Bueso
From: Harshal Thakkar <harshal.t@samsung.com>
Implement CRB filtering per CXL 4.0 8.2.7.2.2, and extend the
current filtering support beyond HDM. These filters are only for
DDR Interface events.
Placing the 32-bit CRB value at config2:32-63 leaves the
existing HDM value at config2:0-15 untouched and avoids needing
a new config3.
Signed-off-by: Harshal Thakkar <harshal.t@samsung.com>
Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
---
drivers/perf/cxl_pmu.c | 47 +++++++++++++++++++++++++++++++++++++++---
1 file changed, 44 insertions(+), 3 deletions(-)
diff --git a/drivers/perf/cxl_pmu.c b/drivers/perf/cxl_pmu.c
index 68a54d97d2a8..58c15680f299 100644
--- a/drivers/perf/cxl_pmu.c
+++ b/drivers/perf/cxl_pmu.c
@@ -106,6 +106,7 @@ struct cxl_pmu_info {
int on_cpu;
struct hlist_node node;
bool filter_hdm;
+ bool filter_chan_rank_bank;
int irq;
};
@@ -142,6 +143,8 @@ static int cxl_pmu_parse_caps(struct device *dev, struct cxl_pmu_info *info)
info->num_event_capabilities = FIELD_GET(CXL_PMU_CAP_NUM_EVN_CAP_REG_SUP_MSK, val) + 1;
info->filter_hdm = FIELD_GET(CXL_PMU_CAP_FILTERS_SUP_MSK, val) & CXL_PMU_FILTER_HDM;
+ info->filter_chan_rank_bank = FIELD_GET(CXL_PMU_CAP_FILTERS_SUP_MSK, val) &
+ CXL_PMU_FILTER_CHAN_RANK_BANK;
if (FIELD_GET(CXL_PMU_CAP_INT, val))
info->irq = FIELD_GET(CXL_PMU_CAP_MSI_N_MSK, val);
else
@@ -225,6 +228,8 @@ enum {
cxl_pmu_edge_attr,
cxl_pmu_hdm_filter_en_attr,
cxl_pmu_hdm_attr,
+ cxl_pmu_crb_filter_en_attr,
+ cxl_pmu_crb_attr,
};
static struct attribute *cxl_pmu_format_attr[] = {
@@ -236,6 +241,8 @@ static struct attribute *cxl_pmu_format_attr[] = {
[cxl_pmu_edge_attr] = CXL_PMU_FORMAT_ATTR(edge, "config1:17"),
[cxl_pmu_hdm_filter_en_attr] = CXL_PMU_FORMAT_ATTR(hdm_filter_en, "config1:18"),
[cxl_pmu_hdm_attr] = CXL_PMU_FORMAT_ATTR(hdm, "config2:0-15"),
+ [cxl_pmu_crb_filter_en_attr] = CXL_PMU_FORMAT_ATTR(crb_filter_en, "config1:19"),
+ [cxl_pmu_crb_attr] = CXL_PMU_FORMAT_ATTR(crb, "config2:32-63"),
NULL
};
@@ -246,7 +253,9 @@ static struct attribute *cxl_pmu_format_attr[] = {
#define CXL_PMU_ATTR_CONFIG1_INVERT_MSK BIT(16)
#define CXL_PMU_ATTR_CONFIG1_EDGE_MSK BIT(17)
#define CXL_PMU_ATTR_CONFIG1_FILTER_EN_MSK BIT(18)
+#define CXL_PMU_ATTR_CONFIG1_CRB_FILTER_EN_MSK BIT(19)
#define CXL_PMU_ATTR_CONFIG2_HDM_MSK GENMASK(15, 0)
+#define CXL_PMU_ATTR_CONFIG2_CRB_MSK GENMASK_ULL(63, 32)
static umode_t cxl_pmu_format_is_visible(struct kobject *kobj,
struct attribute *attr, int a)
@@ -263,6 +272,11 @@ static umode_t cxl_pmu_format_is_visible(struct kobject *kobj,
attr == cxl_pmu_format_attr[cxl_pmu_hdm_attr]))
return 0;
+ if (!info->filter_chan_rank_bank &&
+ (attr == cxl_pmu_format_attr[cxl_pmu_crb_filter_en_attr] ||
+ attr == cxl_pmu_format_attr[cxl_pmu_crb_attr]))
+ return 0;
+
return attr->mode;
}
@@ -319,6 +333,17 @@ static u16 cxl_pmu_config2_get_hdm_decoder(struct perf_event *event)
return FIELD_GET(CXL_PMU_ATTR_CONFIG2_HDM_MSK, event->attr.config2);
}
+static u16 cxl_pmu_config1_crb_filter_en(struct perf_event *event)
+{
+ return FIELD_GET(CXL_PMU_ATTR_CONFIG1_CRB_FILTER_EN_MSK,
+ event->attr.config1);
+}
+
+static u32 cxl_pmu_config2_get_crb(struct perf_event *event)
+{
+ return FIELD_GET(CXL_PMU_ATTR_CONFIG2_CRB_MSK, event->attr.config2);
+}
+
static ssize_t cxl_pmu_event_sysfs_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -571,6 +596,14 @@ static int cxl_pmu_event_init(struct perf_event *event)
return -EOPNOTSUPP;
/* TODO: Validation of any filter */
+ if (cxl_pmu_config1_crb_filter_en(event)) {
+ if (!info->filter_chan_rank_bank)
+ return -EINVAL;
+ /* only valid for DDR Interface events */
+ if (cxl_pmu_config_get_gid(event) != CXL_PMU_GID_DDR)
+ return -EINVAL;
+ }
+
/*
* Verify that it is possible to count what was requested. Either must
* be a fixed counter that is a precise match or a configurable counter
@@ -627,15 +660,23 @@ static void cxl_pmu_event_start(struct perf_event *event, int flags)
hwc->state = 0;
/*
- * Currently only hdm filter control is implemented, this code will
- * want generalizing when more filters are added.
+ * Filter ID=0: HDM decoder filter
+ * Filter ID=1: Channel/Rank/Bank (CRB) filter
*/
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));
+ writel(cfg, base + CXL_PMU_FILTER_CFG_REG(hwc->idx, 0));
+ }
+
+ if (info->filter_chan_rank_bank) {
+ if (cxl_pmu_config1_crb_filter_en(event))
+ cfg = cxl_pmu_config2_get_crb(event);
+ else
+ cfg = GENMASK(31, 0); /* no filtering if 0xFFFF_FFFF */
+ writel(cfg, base + CXL_PMU_FILTER_CFG_REG(hwc->idx, 1));
}
cfg = readq(base + CXL_PMU_COUNTER_CFG_REG(hwc->idx));
--
2.39.5
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/2] perf/cxlpmu: Add missing CXL 4.0 events
2026-06-30 23:50 [PATCH 0/2] perf/cxlpmu: Misc updates Davidlohr Bueso
2026-06-30 23:50 ` [PATCH v2 1/2] perf/cxlpmu: Support Channel/Rank/Bank filter Davidlohr Bueso
@ 2026-06-30 23:50 ` Davidlohr Bueso
1 sibling, 0 replies; 5+ messages in thread
From: Davidlohr Bueso @ 2026-06-30 23:50 UTC (permalink / raw)
To: jic23, will, mark.rutland
Cc: harshal.t, linux-cxl, linux-perf-users, Davidlohr Bueso
From: Harshal Thakkar <harshal.t@samsung.com>
Add support for CXL 4.0 events that are exposed by the CPMU hardware
but not present in the driver. Such events are defined in Table 13-5
of the spec.
Signed-off-by: Harshal Thakkar <harshal.t@samsung.com>
Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
---
drivers/perf/cxl_pmu.c | 44 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/drivers/perf/cxl_pmu.c b/drivers/perf/cxl_pmu.c
index 58c15680f299..f3ac36c6a02f 100644
--- a/drivers/perf/cxl_pmu.c
+++ b/drivers/perf/cxl_pmu.c
@@ -77,6 +77,9 @@
#define CXL_PMU_GID_S2M_NDR 0x0024
#define CXL_PMU_GID_S2M_DRS 0x0025
#define CXL_PMU_GID_DDR 0x8000
+#define CXL_PMU_GID_QUEUE_OCC 0x8001
+#define CXL_PMU_GID_QUEUE_RESID 0x8002
+#define CXL_PMU_GID_RETRY_EVENTS 0x8003
static int cxl_pmu_cpuhp_state_num;
@@ -410,13 +413,23 @@ static struct attribute *cxl_pmu_event_attrs[] = {
CXL_PMU_EVENT_CXL_ATTR(m2s_req_memwrfwd, CXL_PMU_GID_M2S_REQ, BIT(4)),
CXL_PMU_EVENT_CXL_ATTR(m2s_req_memrdtee, CXL_PMU_GID_M2S_REQ, BIT(5)),
CXL_PMU_EVENT_CXL_ATTR(m2s_req_memrddatatee, CXL_PMU_GID_M2S_REQ, BIT(6)),
+ CXL_PMU_EVENT_CXL_ATTR(m2s_req_meminvtee, CXL_PMU_GID_M2S_REQ, BIT(7)),
CXL_PMU_EVENT_CXL_ATTR(m2s_req_memspecrd, CXL_PMU_GID_M2S_REQ, BIT(8)),
CXL_PMU_EVENT_CXL_ATTR(m2s_req_meminvnt, CXL_PMU_GID_M2S_REQ, BIT(9)),
CXL_PMU_EVENT_CXL_ATTR(m2s_req_memcleanevict, CXL_PMU_GID_M2S_REQ, BIT(10)),
+ CXL_PMU_EVENT_CXL_ATTR(m2s_req_meminvptee, CXL_PMU_GID_M2S_REQ, BIT(11)),
+ CXL_PMU_EVENT_CXL_ATTR(m2s_req_memspecrdtee, CXL_PMU_GID_M2S_REQ, BIT(12)),
+ CXL_PMU_EVENT_CXL_ATTR(m2s_req_teupdate, CXL_PMU_GID_M2S_REQ, BIT(13)),
+ CXL_PMU_EVENT_CXL_ATTR(m2s_req_memclnevcttee, CXL_PMU_GID_M2S_REQ, BIT(14)),
+ CXL_PMU_EVENT_CXL_ATTR(m2s_req_memclnevctu, CXL_PMU_GID_M2S_REQ, BIT(15)),
/* CXL rev 3.0 Table 3-35 M2S RwD Memory Opcodes */
CXL_PMU_EVENT_CXL_ATTR(m2s_rwd_memwr, CXL_PMU_GID_M2S_RWD, BIT(1)),
CXL_PMU_EVENT_CXL_ATTR(m2s_rwd_memwrptl, CXL_PMU_GID_M2S_RWD, BIT(2)),
CXL_PMU_EVENT_CXL_ATTR(m2s_rwd_biconflict, CXL_PMU_GID_M2S_RWD, BIT(4)),
+ CXL_PMU_EVENT_CXL_ATTR(m2s_rwd_memrdfill, CXL_PMU_GID_M2S_RWD, BIT(5)),
+ CXL_PMU_EVENT_CXL_ATTR(m2s_rwd_memwrtee, CXL_PMU_GID_M2S_RWD, BIT(9)),
+ CXL_PMU_EVENT_CXL_ATTR(m2s_rwd_memwrptltee, CXL_PMU_GID_M2S_RWD, BIT(10)),
+ CXL_PMU_EVENT_CXL_ATTR(m2s_rwd_memrdfilltee, CXL_PMU_GID_M2S_RWD, BIT(13)),
/* CXL rev 3.0 Table 3-38 M2S BIRsp Memory Opcodes */
CXL_PMU_EVENT_CXL_ATTR(m2s_birsp_i, CXL_PMU_GID_M2S_BIRSP, BIT(0)),
CXL_PMU_EVENT_CXL_ATTR(m2s_birsp_s, CXL_PMU_GID_M2S_BIRSP, BIT(1)),
@@ -431,15 +444,25 @@ static struct attribute *cxl_pmu_event_attrs[] = {
CXL_PMU_EVENT_CXL_ATTR(s2m_bisnp_curblk, CXL_PMU_GID_S2M_BISNP, BIT(4)),
CXL_PMU_EVENT_CXL_ATTR(s2m_bisnp_datblk, CXL_PMU_GID_S2M_BISNP, BIT(5)),
CXL_PMU_EVENT_CXL_ATTR(s2m_bisnp_invblk, CXL_PMU_GID_S2M_BISNP, BIT(6)),
+ CXL_PMU_EVENT_CXL_ATTR(s2m_bisnp_curtee, CXL_PMU_GID_S2M_BISNP, BIT(8)),
+ CXL_PMU_EVENT_CXL_ATTR(s2m_bisnp_datatee, CXL_PMU_GID_S2M_BISNP, BIT(9)),
+ CXL_PMU_EVENT_CXL_ATTR(s2m_bisnp_invtee, CXL_PMU_GID_S2M_BISNP, BIT(10)),
+ CXL_PMU_EVENT_CXL_ATTR(s2m_bisnp_curblktee, CXL_PMU_GID_S2M_BISNP, BIT(12)),
+ CXL_PMU_EVENT_CXL_ATTR(s2m_bisnp_datablktee, CXL_PMU_GID_S2M_BISNP, BIT(13)),
+ CXL_PMU_EVENT_CXL_ATTR(s2m_bisnp_invblktee, CXL_PMU_GID_S2M_BISNP, BIT(14)),
/* CXL rev 3.1 Table 3-50 S2M NDR Opcodes */
CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_cmp, CXL_PMU_GID_S2M_NDR, BIT(0)),
CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_cmps, CXL_PMU_GID_S2M_NDR, BIT(1)),
CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_cmpe, CXL_PMU_GID_S2M_NDR, BIT(2)),
CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_cmpm, CXL_PMU_GID_S2M_NDR, BIT(3)),
CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_biconflictack, CXL_PMU_GID_S2M_NDR, BIT(4)),
+ CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_cmptee, CXL_PMU_GID_S2M_NDR, BIT(5)),
+ CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_cmptee_s, CXL_PMU_GID_S2M_NDR, BIT(6)),
+ CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_cmptee_e, CXL_PMU_GID_S2M_NDR, BIT(7)),
/* CXL rev 3.0 Table 3-46 S2M DRS opcodes */
CXL_PMU_EVENT_CXL_ATTR(s2m_drs_memdata, CXL_PMU_GID_S2M_DRS, BIT(0)),
CXL_PMU_EVENT_CXL_ATTR(s2m_drs_memdatanxm, CXL_PMU_GID_S2M_DRS, BIT(1)),
+ CXL_PMU_EVENT_CXL_ATTR(s2m_drs_memdatatee, CXL_PMU_GID_S2M_DRS, BIT(2)),
/* CXL rev 3.0 Table 13-5 directly lists these */
CXL_PMU_EVENT_CXL_ATTR(ddr_act, CXL_PMU_GID_DDR, BIT(0)),
CXL_PMU_EVENT_CXL_ATTR(ddr_pre, CXL_PMU_GID_DDR, BIT(1)),
@@ -448,6 +471,27 @@ static struct attribute *cxl_pmu_event_attrs[] = {
CXL_PMU_EVENT_CXL_ATTR(ddr_refresh, CXL_PMU_GID_DDR, BIT(4)),
CXL_PMU_EVENT_CXL_ATTR(ddr_selfrefreshent, CXL_PMU_GID_DDR, BIT(5)),
CXL_PMU_EVENT_CXL_ATTR(ddr_rfm, CXL_PMU_GID_DDR, BIT(6)),
+ /* CXL rev 3.2 Table 13-5 DDR add-on events opcodes */
+ CXL_PMU_EVENT_CXL_ATTR(ddr_cas_rd_ap, CXL_PMU_GID_DDR, BIT(7)),
+ CXL_PMU_EVENT_CXL_ATTR(ddr_cas_wr_ap, CXL_PMU_GID_DDR, BIT(8)),
+ CXL_PMU_EVENT_CXL_ATTR(ddr_refresh_all_banks, CXL_PMU_GID_DDR, BIT(9)),
+ CXL_PMU_EVENT_CXL_ATTR(ddr_refresh_same_bank, CXL_PMU_GID_DDR, BIT(10)),
+ CXL_PMU_EVENT_CXL_ATTR(ddr_pwrdn_entry, CXL_PMU_GID_DDR, BIT(11)),
+ CXL_PMU_EVENT_CXL_ATTR(ddr_pwrdn_exit, CXL_PMU_GID_DDR, BIT(12)),
+ CXL_PMU_EVENT_CXL_ATTR(ddr_rd_wr_ddr_bus_switching, CXL_PMU_GID_DDR, BIT(13)),
+ CXL_PMU_EVENT_CXL_ATTR(ddr_incoming_rd_req, CXL_PMU_GID_DDR, BIT(14)),
+ CXL_PMU_EVENT_CXL_ATTR(ddr_incoming_wr_req, CXL_PMU_GID_DDR, BIT(15)),
+ /* CXL rev 3.2 Table 13-5 QUEUE OCCUPANCY events opcodes */
+ CXL_PMU_EVENT_CXL_ATTR(rd_queue_occ, CXL_PMU_GID_QUEUE_OCC, BIT(0)),
+ CXL_PMU_EVENT_CXL_ATTR(wr_queue_occ, CXL_PMU_GID_QUEUE_OCC, BIT(1)),
+ /* CXL rev 3.2 Table 13-5 QUEUE RESIDENCY events opcodes */
+ CXL_PMU_EVENT_CXL_ATTR(mc_rd_resid_cnt, CXL_PMU_GID_QUEUE_RESID, BIT(0)),
+ CXL_PMU_EVENT_CXL_ATTR(mc_wr_resid_cnt, CXL_PMU_GID_QUEUE_RESID, BIT(1)),
+ /* CXL rev 3.2 Table 13-5 RETRY events opcodes */
+ CXL_PMU_EVENT_CXL_ATTR(retry_event_trig_by_rd_crc, CXL_PMU_GID_RETRY_EVENTS, BIT(0)),
+ CXL_PMU_EVENT_CXL_ATTR(retry_event_trig_by_wr_crc, CXL_PMU_GID_RETRY_EVENTS, BIT(1)),
+ CXL_PMU_EVENT_CXL_ATTR(retry_event_trig_by_ca_parity, CXL_PMU_GID_RETRY_EVENTS, BIT(2)),
+ CXL_PMU_EVENT_CXL_ATTR(retry_event_trig_by_ecc, CXL_PMU_GID_RETRY_EVENTS, BIT(3)),
NULL
};
--
2.39.5
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2 1/2] perf/cxlpmu: Support Channel/Rank/Bank filter
2026-06-30 23:50 ` [PATCH v2 1/2] perf/cxlpmu: Support Channel/Rank/Bank filter Davidlohr Bueso
@ 2026-07-01 1:55 ` sashiko-bot
2026-07-09 9:16 ` Richard Cheng
1 sibling, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-07-01 1:55 UTC (permalink / raw)
To: Davidlohr Bueso; +Cc: linux-cxl, linux-perf-users
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] PMU filters (like the newly added CRB filter) are silently ignored if the requested event is assigned to a fixed counter.
--
commit efebea58e23a015bdb87cae3df5f0d067aa37706
Author: Harshal Thakkar <harshal.t@samsung.com>
perf/cxlpmu: Support Channel/Rank/Bank filter
Implement CRB filtering per CXL 4.0 8.2.7.2.2, and extend the current
filtering support beyond HDM. These filters are only for DDR Interface
events.
> 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
[ ... ]
> @@ -627,15 +660,23 @@ static void cxl_pmu_event_start(struct perf_event *event, int flags)
> hwc->state = 0;
>
> /*
> - * Currently only hdm filter control is implemented, this code will
> - * want generalizing when more filters are added.
> + * Filter ID=0: HDM decoder filter
> + * Filter ID=1: Channel/Rank/Bank (CRB) filter
> */
> 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));
> + writel(cfg, base + CXL_PMU_FILTER_CFG_REG(hwc->idx, 0));
> + }
> +
> + if (info->filter_chan_rank_bank) {
> + if (cxl_pmu_config1_crb_filter_en(event))
> + cfg = cxl_pmu_config2_get_crb(event);
> + else
> + cfg = GENMASK(31, 0); /* no filtering if 0xFFFF_FFFF */
> + writel(cfg, base + CXL_PMU_FILTER_CFG_REG(hwc->idx, 1));
[Severity: Medium]
Will this filter configuration be silently ignored if the event is assigned
to a fixed counter?
In cxl_pmu_get_event_idx(), fixed counters are prioritized for assignment
without checking if PMU filters were requested:
cxl_pmu_get_event_idx() {
...
pmu_ev = cxl_pmu_find_fixed_counter_ev_cap(info, vid, gid, mask);
if (!IS_ERR(pmu_ev)) {
if (!counter_idx)
return 0;
if (!test_bit(pmu_ev->counter_idx, info->used_counter_bm)) {
*counter_idx = pmu_ev->counter_idx;
return 0;
}
}
...
}
Since fixed counters do not support filtering per the CXL specification, does
writing the CRB filter configuration to a fixed counter's register result
in the hardware silently ignoring it? This could lead to unfiltered counts
being returned to the user when they expected filtered statistics.
> }
>
> cfg = readq(base + CXL_PMU_COUNTER_CFG_REG(hwc->idx));
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260630235002.253297-1-dave@stgolabs.net?part=1
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2 1/2] perf/cxlpmu: Support Channel/Rank/Bank filter
2026-06-30 23:50 ` [PATCH v2 1/2] perf/cxlpmu: Support Channel/Rank/Bank filter Davidlohr Bueso
2026-07-01 1:55 ` sashiko-bot
@ 2026-07-09 9:16 ` Richard Cheng
1 sibling, 0 replies; 5+ messages in thread
From: Richard Cheng @ 2026-07-09 9:16 UTC (permalink / raw)
To: Davidlohr Bueso
Cc: jic23, will, mark.rutland, harshal.t, linux-cxl, linux-perf-users
On Tue, Jun 30, 2026 at 04:50:01PM +0800, Davidlohr Bueso wrote:
> From: Harshal Thakkar <harshal.t@samsung.com>
>
> Implement CRB filtering per CXL 4.0 8.2.7.2.2, and extend the
> current filtering support beyond HDM. These filters are only for
> DDR Interface events.
>
> Placing the 32-bit CRB value at config2:32-63 leaves the
> existing HDM value at config2:0-15 untouched and avoids needing
> a new config3.
>
> Signed-off-by: Harshal Thakkar <harshal.t@samsung.com>
> Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
> ---
> drivers/perf/cxl_pmu.c | 47 +++++++++++++++++++++++++++++++++++++++---
> 1 file changed, 44 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/perf/cxl_pmu.c b/drivers/perf/cxl_pmu.c
> index 68a54d97d2a8..58c15680f299 100644
> --- a/drivers/perf/cxl_pmu.c
> +++ b/drivers/perf/cxl_pmu.c
> @@ -106,6 +106,7 @@ struct cxl_pmu_info {
> int on_cpu;
> struct hlist_node node;
> bool filter_hdm;
> + bool filter_chan_rank_bank;
> int irq;
> };
>
> @@ -142,6 +143,8 @@ static int cxl_pmu_parse_caps(struct device *dev, struct cxl_pmu_info *info)
> info->num_event_capabilities = FIELD_GET(CXL_PMU_CAP_NUM_EVN_CAP_REG_SUP_MSK, val) + 1;
>
> info->filter_hdm = FIELD_GET(CXL_PMU_CAP_FILTERS_SUP_MSK, val) & CXL_PMU_FILTER_HDM;
> + info->filter_chan_rank_bank = FIELD_GET(CXL_PMU_CAP_FILTERS_SUP_MSK, val) &
> + CXL_PMU_FILTER_CHAN_RANK_BANK;
> if (FIELD_GET(CXL_PMU_CAP_INT, val))
> info->irq = FIELD_GET(CXL_PMU_CAP_MSI_N_MSK, val);
> else
> @@ -225,6 +228,8 @@ enum {
> cxl_pmu_edge_attr,
> cxl_pmu_hdm_filter_en_attr,
> cxl_pmu_hdm_attr,
> + cxl_pmu_crb_filter_en_attr,
> + cxl_pmu_crb_attr,
> };
>
> static struct attribute *cxl_pmu_format_attr[] = {
> @@ -236,6 +241,8 @@ static struct attribute *cxl_pmu_format_attr[] = {
> [cxl_pmu_edge_attr] = CXL_PMU_FORMAT_ATTR(edge, "config1:17"),
> [cxl_pmu_hdm_filter_en_attr] = CXL_PMU_FORMAT_ATTR(hdm_filter_en, "config1:18"),
> [cxl_pmu_hdm_attr] = CXL_PMU_FORMAT_ATTR(hdm, "config2:0-15"),
> + [cxl_pmu_crb_filter_en_attr] = CXL_PMU_FORMAT_ATTR(crb_filter_en, "config1:19"),
> + [cxl_pmu_crb_attr] = CXL_PMU_FORMAT_ATTR(crb, "config2:32-63"),
> NULL
> };
>
> @@ -246,7 +253,9 @@ static struct attribute *cxl_pmu_format_attr[] = {
> #define CXL_PMU_ATTR_CONFIG1_INVERT_MSK BIT(16)
> #define CXL_PMU_ATTR_CONFIG1_EDGE_MSK BIT(17)
> #define CXL_PMU_ATTR_CONFIG1_FILTER_EN_MSK BIT(18)
> +#define CXL_PMU_ATTR_CONFIG1_CRB_FILTER_EN_MSK BIT(19)
> #define CXL_PMU_ATTR_CONFIG2_HDM_MSK GENMASK(15, 0)
> +#define CXL_PMU_ATTR_CONFIG2_CRB_MSK GENMASK_ULL(63, 32)
>
> static umode_t cxl_pmu_format_is_visible(struct kobject *kobj,
> struct attribute *attr, int a)
> @@ -263,6 +272,11 @@ static umode_t cxl_pmu_format_is_visible(struct kobject *kobj,
> attr == cxl_pmu_format_attr[cxl_pmu_hdm_attr]))
> return 0;
>
> + if (!info->filter_chan_rank_bank &&
> + (attr == cxl_pmu_format_attr[cxl_pmu_crb_filter_en_attr] ||
> + attr == cxl_pmu_format_attr[cxl_pmu_crb_attr]))
> + return 0;
> +
> return attr->mode;
> }
>
> @@ -319,6 +333,17 @@ static u16 cxl_pmu_config2_get_hdm_decoder(struct perf_event *event)
> return FIELD_GET(CXL_PMU_ATTR_CONFIG2_HDM_MSK, event->attr.config2);
> }
>
> +static u16 cxl_pmu_config1_crb_filter_en(struct perf_event *event)
> +{
> + return FIELD_GET(CXL_PMU_ATTR_CONFIG1_CRB_FILTER_EN_MSK,
> + event->attr.config1);
> +}
> +
> +static u32 cxl_pmu_config2_get_crb(struct perf_event *event)
> +{
> + return FIELD_GET(CXL_PMU_ATTR_CONFIG2_CRB_MSK, event->attr.config2);
> +}
> +
> static ssize_t cxl_pmu_event_sysfs_show(struct device *dev,
> struct device_attribute *attr, char *buf)
> {
> @@ -571,6 +596,14 @@ static int cxl_pmu_event_init(struct perf_event *event)
> return -EOPNOTSUPP;
> /* TODO: Validation of any filter */
>
> + if (cxl_pmu_config1_crb_filter_en(event)) {
> + if (!info->filter_chan_rank_bank)
> + return -EINVAL;
> + /* only valid for DDR Interface events */
> + if (cxl_pmu_config_get_gid(event) != CXL_PMU_GID_DDR)
> + return -EINVAL;
> + }
> +
Hi Davidlohr,
Would this be too strict ?
In CXL 4.0, Table 13-5 "Events under CXL Vendor ID", Section 13.2 "Performance Monitoring"
Filter ID 1 is also permitted for Queue Occupancy (8001h), Queue Residency (8002h)
and Retry Events (8003h).
With this change, when we do something like
"""
perf stat -e cxl_pmu/rd_queue_occ,crb_filter_en=1,crb=0x5/
"""
It will fail with -EINVAL, even though the sepc allows Filter ID 1 for that
event group.
> /*
> * Verify that it is possible to count what was requested. Either must
> * be a fixed counter that is a precise match or a configurable counter
> @@ -627,15 +660,23 @@ static void cxl_pmu_event_start(struct perf_event *event, int flags)
> hwc->state = 0;
>
> /*
> - * Currently only hdm filter control is implemented, this code will
> - * want generalizing when more filters are added.
> + * Filter ID=0: HDM decoder filter
> + * Filter ID=1: Channel/Rank/Bank (CRB) filter
> */
> 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));
> + writel(cfg, base + CXL_PMU_FILTER_CFG_REG(hwc->idx, 0));
> + }
This is a real bug fix on its own.
The old 64-bit write also wrote 0 into the Filter ID 1 register at offset+4,
and per Table 8-186 0 there means "filter to hannel/rank/bank 0", not disable.
So on hardware that supports both filters, current kernel silently undercount.
Woth splitting into its own patch so it can be backported without the new
feature.
Best regards,
Richard Cheng.
> +
> + if (info->filter_chan_rank_bank) {
> + if (cxl_pmu_config1_crb_filter_en(event))
> + cfg = cxl_pmu_config2_get_crb(event);
> + else
> + cfg = GENMASK(31, 0); /* no filtering if 0xFFFF_FFFF */
> + writel(cfg, base + CXL_PMU_FILTER_CFG_REG(hwc->idx, 1));
> }
>
> cfg = readq(base + CXL_PMU_COUNTER_CFG_REG(hwc->idx));
> --
> 2.39.5
>
>
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-07-09 9:17 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-30 23:50 [PATCH 0/2] perf/cxlpmu: Misc updates Davidlohr Bueso
2026-06-30 23:50 ` [PATCH v2 1/2] perf/cxlpmu: Support Channel/Rank/Bank filter Davidlohr Bueso
2026-07-01 1:55 ` sashiko-bot
2026-07-09 9:16 ` Richard Cheng
2026-06-30 23:50 ` [PATCH 2/2] perf/cxlpmu: Add missing CXL 4.0 events Davidlohr Bueso
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox