Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf: imx_perf: add support for i.MX95 platform

i.MX95 has a DDR PMU which is almostly same as i.MX93, it now supports
read beat and write beat filter capabilities. This will add support for
i.MX95 and enhance the driver to support specific filter handling for it.

Usage:

For read beat:
~# perf stat -a -I 1000 -e imx9_ddr0/eddrtq_pm_rd_beat_filt2,axi_mask=ID_MASK,axi_id=ID/
~# perf stat -a -I 1000 -e imx9_ddr0/eddrtq_pm_rd_beat_filt1,axi_mask=ID_MASK,axi_id=ID/
~# perf stat -a -I 1000 -e imx9_ddr0/eddrtq_pm_rd_beat_filt0,axi_mask=ID_MASK,axi_id=ID/
eg: For edma2: perf stat -a -I 1000 -e imx9_ddr0/eddrtq_pm_rd_beat_filt0,axi_mask=0x00f,axi_id=0x00c/

For write beat:
~# perf stat -a -I 1000 -e imx9_ddr0/eddrtq_pm_wr_beat_filt,axi_mask=ID_MASK,axi_id=ID/
eg: For edma2: perf stat -a -I 1000 -e imx9_ddr0/eddrtq_pm_wr_beat_filt,axi_mask=0x00f,axi_id=0x00c/

Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Xu Yang <xu.yang_2@nxp.com>
Link: https://lore.kernel.org/r/20240529080358.703784-6-xu.yang_2@nxp.com
Signed-off-by: Will Deacon <will@kernel.org>

authored by

Xu Yang and committed by
Will Deacon
d0d7c66c ac9aa295

+86 -3
+86 -3
drivers/perf/fsl_imx9_ddr_perf.c
··· 17 17 #define MX93_PMCFG1_RD_BT_FILT_EN BIT(29) 18 18 #define MX93_PMCFG1_ID_MASK GENMASK(17, 0) 19 19 20 + #define MX95_PMCFG1_WR_BEAT_FILT_EN BIT(31) 21 + #define MX95_PMCFG1_RD_BEAT_FILT_EN BIT(30) 22 + 20 23 #define PMCFG2 0x04 21 24 #define MX93_PMCFG2_ID GENMASK(17, 0) 25 + 26 + #define PMCFG3 0x08 27 + #define PMCFG4 0x0C 28 + #define PMCFG5 0x10 29 + #define PMCFG6 0x14 30 + #define MX95_PMCFG_ID_MASK GENMASK(9, 0) 31 + #define MX95_PMCFG_ID GENMASK(25, 16) 22 32 23 33 /* Global control register affects all counters and takes priority over local control registers */ 24 34 #define PMGC0 0x40 ··· 85 75 .identifier = "imx93", 86 76 }; 87 77 78 + static const struct imx_ddr_devtype_data imx95_devtype_data = { 79 + .identifier = "imx95", 80 + }; 81 + 88 82 static inline bool is_imx93(struct ddr_pmu *pmu) 89 83 { 90 84 return pmu->devtype_data == &imx93_devtype_data; 91 85 } 92 86 87 + static inline bool is_imx95(struct ddr_pmu *pmu) 88 + { 89 + return pmu->devtype_data == &imx95_devtype_data; 90 + } 91 + 93 92 static const struct of_device_id imx_ddr_pmu_dt_ids[] = { 94 - {.compatible = "fsl,imx93-ddr-pmu", .data = &imx93_devtype_data}, 93 + { .compatible = "fsl,imx93-ddr-pmu", .data = &imx93_devtype_data }, 94 + { .compatible = "fsl,imx95-ddr-pmu", .data = &imx95_devtype_data }, 95 95 { /* sentinel */ } 96 96 }; 97 97 MODULE_DEVICE_TABLE(of, imx_ddr_pmu_dt_ids); ··· 178 158 #define IMX93_DDR_PMU_EVENT_ATTR(_name, _id) \ 179 159 DDR_PMU_EVENT_ATTR_COMM(_name, _id, &imx93_devtype_data) 180 160 161 + #define IMX95_DDR_PMU_EVENT_ATTR(_name, _id) \ 162 + DDR_PMU_EVENT_ATTR_COMM(_name, _id, &imx95_devtype_data) 163 + 181 164 static struct attribute *ddr_perf_events_attrs[] = { 182 165 /* counter0 cycles event */ 183 166 IMX9_DDR_PMU_EVENT_ATTR(cycles, 0), ··· 227 204 IMX9_DDR_PMU_EVENT_ATTR(ddrc_ld_wiq_7, ID(2, 71)), 228 205 IMX9_DDR_PMU_EVENT_ATTR(eddrtq_pmon_empty, ID(2, 72)), 229 206 IMX93_DDR_PMU_EVENT_ATTR(eddrtq_pm_rd_trans_filt, ID(2, 73)), /* imx93 specific*/ 207 + IMX95_DDR_PMU_EVENT_ATTR(eddrtq_pm_wr_beat_filt, ID(2, 73)), /* imx95 specific*/ 230 208 231 209 /* counter3 specific events */ 232 210 IMX9_DDR_PMU_EVENT_ATTR(ddrc_qx_row_collision_0, ID(3, 64)), ··· 240 216 IMX9_DDR_PMU_EVENT_ATTR(ddrc_qx_row_collision_7, ID(3, 71)), 241 217 IMX9_DDR_PMU_EVENT_ATTR(eddrtq_pmon_full, ID(3, 72)), 242 218 IMX93_DDR_PMU_EVENT_ATTR(eddrtq_pm_wr_trans_filt, ID(3, 73)), /* imx93 specific*/ 219 + IMX95_DDR_PMU_EVENT_ATTR(eddrtq_pm_rd_beat_filt2, ID(3, 73)), /* imx95 specific*/ 243 220 244 221 /* counter4 specific events */ 245 222 IMX9_DDR_PMU_EVENT_ATTR(ddrc_qx_row_open_0, ID(4, 64)), ··· 253 228 IMX9_DDR_PMU_EVENT_ATTR(ddrc_qx_row_open_7, ID(4, 71)), 254 229 IMX9_DDR_PMU_EVENT_ATTR(eddrtq_pmon_ld_rdq2_rmw, ID(4, 72)), 255 230 IMX93_DDR_PMU_EVENT_ATTR(eddrtq_pm_rd_beat_filt, ID(4, 73)), /* imx93 specific*/ 231 + IMX95_DDR_PMU_EVENT_ATTR(eddrtq_pm_rd_beat_filt1, ID(4, 73)), /* imx95 specific*/ 256 232 257 233 /* counter5 specific events */ 258 234 IMX9_DDR_PMU_EVENT_ATTR(ddrc_qx_valid_start_0, ID(5, 64)), ··· 265 239 IMX9_DDR_PMU_EVENT_ATTR(ddrc_qx_valid_start_6, ID(5, 70)), 266 240 IMX9_DDR_PMU_EVENT_ATTR(ddrc_qx_valid_start_7, ID(5, 71)), 267 241 IMX9_DDR_PMU_EVENT_ATTR(eddrtq_pmon_ld_rdq1, ID(5, 72)), 242 + IMX95_DDR_PMU_EVENT_ATTR(eddrtq_pm_rd_beat_filt0, ID(5, 73)), /* imx95 specific*/ 268 243 269 244 /* counter6 specific events */ 270 245 IMX9_DDR_PMU_EVENT_ATTR(ddrc_qx_valid_end_0, ID(6, 64)), ··· 459 432 writel_relaxed(pmcfg2, pmu->base + PMCFG2); 460 433 } 461 434 435 + static void imx95_ddr_perf_monitor_config(struct ddr_pmu *pmu, int event, 436 + int counter, int axi_id, int axi_mask) 437 + { 438 + u32 pmcfg1, pmcfg, offset = 0; 439 + 440 + pmcfg1 = readl_relaxed(pmu->base + PMCFG1); 441 + 442 + if (event == 73) { 443 + switch (counter) { 444 + case 2: 445 + pmcfg1 |= MX95_PMCFG1_WR_BEAT_FILT_EN; 446 + offset = PMCFG3; 447 + break; 448 + case 3: 449 + pmcfg1 |= MX95_PMCFG1_RD_BEAT_FILT_EN; 450 + offset = PMCFG4; 451 + break; 452 + case 4: 453 + pmcfg1 |= MX95_PMCFG1_RD_BEAT_FILT_EN; 454 + offset = PMCFG5; 455 + break; 456 + case 5: 457 + pmcfg1 |= MX95_PMCFG1_RD_BEAT_FILT_EN; 458 + offset = PMCFG6; 459 + break; 460 + } 461 + } else { 462 + switch (counter) { 463 + case 2: 464 + pmcfg1 &= ~MX95_PMCFG1_WR_BEAT_FILT_EN; 465 + break; 466 + case 3: 467 + case 4: 468 + case 5: 469 + pmcfg1 &= ~MX95_PMCFG1_RD_BEAT_FILT_EN; 470 + break; 471 + } 472 + } 473 + 474 + writel_relaxed(pmcfg1, pmu->base + PMCFG1); 475 + 476 + if (offset) { 477 + pmcfg = readl_relaxed(pmu->base + offset); 478 + pmcfg &= ~(FIELD_PREP(MX95_PMCFG_ID_MASK, 0x3FF) | 479 + FIELD_PREP(MX95_PMCFG_ID, 0x3FF)); 480 + pmcfg |= (FIELD_PREP(MX95_PMCFG_ID_MASK, axi_mask) | 481 + FIELD_PREP(MX95_PMCFG_ID, axi_id)); 482 + writel_relaxed(pmcfg, pmu->base + offset); 483 + } 484 + } 485 + 462 486 static void ddr_perf_event_update(struct perf_event *event) 463 487 { 464 488 struct ddr_pmu *pmu = to_ddr_pmu(event->pmu); ··· 619 541 hwc->idx = counter; 620 542 hwc->state |= PERF_HES_STOPPED; 621 543 622 - /* read trans, write trans, read beat */ 623 - imx93_ddr_perf_monitor_config(pmu, event_id, counter, cfg1, cfg2); 544 + if (is_imx93(pmu)) 545 + /* read trans, write trans, read beat */ 546 + imx93_ddr_perf_monitor_config(pmu, event_id, counter, cfg1, cfg2); 547 + 548 + if (is_imx95(pmu)) 549 + /* write beat, read beat2, read beat1, read beat */ 550 + imx95_ddr_perf_monitor_config(pmu, event_id, counter, cfg1, cfg2); 624 551 625 552 if (flags & PERF_EF_START) 626 553 ddr_perf_event_start(event, flags);