Hi Frank, > -----Original Message----- > From: Frank Li <frank.li@xxxxxxx> > Sent: Monday, November 27, 2023 11:25 PM > To: Xu Yang <xu.yang_2@xxxxxxx>; will@xxxxxxxxxx; mark.rutland@xxxxxxx; robh+dt@xxxxxxxxxx; > krzysztof.kozlowski+dt@xxxxxxxxxx; conor+dt@xxxxxxxxxx; shawnguo@xxxxxxxxxx; s.hauer@xxxxxxxxxxxxxx; > kernel@xxxxxxxxxxxxxx; festevam@xxxxxxxxx; irogers@xxxxxxxxxx; namhyung@xxxxxxxxxx; acme@xxxxxxxxxx; > john.g.garry@xxxxxxxxxx > Cc: james.clark@xxxxxxx; mike.leach@xxxxxxxxxx; leo.yan@xxxxxxxxxx; peterz@xxxxxxxxxxxxx; mingo@xxxxxxxxxx; > alexander.shishkin@xxxxxxxxxxxxxxx; linux-arm-kernel@xxxxxxxxxxxxxxxxxxx; devicetree@xxxxxxxxxxxxxxx; linux-perf- > users@xxxxxxxxxxxxxxx; linux-kernel@xxxxxxxxxxxxxxx > Subject: RE: [PATCH 2/3] perf: imx_perf: add support for i.MX95 platform > > > > > -----Original Message----- > > From: Xu Yang <xu.yang_2@xxxxxxx> > > Sent: Monday, November 27, 2023 1:32 AM > > To: Frank Li <frank.li@xxxxxxx>; will@xxxxxxxxxx; mark.rutland@xxxxxxx; > > robh+dt@xxxxxxxxxx; krzysztof.kozlowski+dt@xxxxxxxxxx; > > conor+dt@xxxxxxxxxx; shawnguo@xxxxxxxxxx; s.hauer@xxxxxxxxxxxxxx; > > kernel@xxxxxxxxxxxxxx; festevam@xxxxxxxxx; irogers@xxxxxxxxxx; > > namhyung@xxxxxxxxxx; acme@xxxxxxxxxx; john.g.garry@xxxxxxxxxx > > Cc: james.clark@xxxxxxx; mike.leach@xxxxxxxxxx; leo.yan@xxxxxxxxxx; > > peterz@xxxxxxxxxxxxx; mingo@xxxxxxxxxx; > > alexander.shishkin@xxxxxxxxxxxxxxx; linux-arm-kernel@xxxxxxxxxxxxxxxxxxx; > > devicetree@xxxxxxxxxxxxxxx; linux-perf-users@xxxxxxxxxxxxxxx; linux- > > kernel@xxxxxxxxxxxxxxx > > Subject: [PATCH 2/3] 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,counter=3,axi_mask=ID_MASK,axi_id > > =ID/ > > ~# perf stat -a -I 1000 -e > > imx9_ddr0/eddrtq_pm_rd_beat_filt1,counter=4,axi_mask=ID_MASK,axi_id > > =ID/ > > ~# perf stat -a -I 1000 -e > > imx9_ddr0/eddrtq_pm_rd_beat_filt0,counter=5,axi_mask=ID_MASK,axi_id > > =ID/ > > eg: For edma2: perf stat -a -I 1000 -e > > imx9_ddr0/eddrtq_pm_rd_beat_filt0,counter=5,axi_mask=0x00f,axi_id=0x0 > > 0c/ > > > > For write beat: > > ~# perf stat -a -I 1000 -e > > imx9_ddr0/eddrtq_pm_wr_beat_filt,counter=2,axi_mask=ID_MASK,axi_id= > > ID/ > > eg: For edma2: perf stat -a -I 1000 -e > > imx9_ddr0/eddrtq_pm_wr_beat_filt,counter=2,axi_mask=0x00f,axi_id=0x00 > > c/ > > > > Signed-off-by: Xu Yang <xu.yang_2@xxxxxxx> > > --- > > drivers/perf/fsl_imx9_ddr_perf.c | 187 +++++++++++++++++++++++++++-- > > -- > > 1 file changed, 164 insertions(+), 23 deletions(-) > > > > diff --git a/drivers/perf/fsl_imx9_ddr_perf.c > > b/drivers/perf/fsl_imx9_ddr_perf.c > > index 5cf770a1bc31..5e531d94cf3b 100644 > > --- a/drivers/perf/fsl_imx9_ddr_perf.c > > +++ b/drivers/perf/fsl_imx9_ddr_perf.c > > @@ -11,14 +11,24 @@ > > #include <linux/perf_event.h> > > > > /* Performance monitor configuration */ > > -#define PMCFG1 0x00 > > -#define PMCFG1_RD_TRANS_FILT_EN BIT(31) > > -#define PMCFG1_WR_TRANS_FILT_EN BIT(30) > > -#define PMCFG1_RD_BT_FILT_EN BIT(29) > > -#define PMCFG1_ID_MASK GENMASK(17, 0) > > +#define PMCFG1 0x00 > > +#define MX93_PMCFG1_RD_TRANS_FILT_EN BIT(31) > > +#define MX93_PMCFG1_WR_TRANS_FILT_EN BIT(30) > > +#define MX93_PMCFG1_RD_BT_FILT_EN BIT(29) > > +#define MX93_PMCFG1_ID_MASK GENMASK(17, 0) > > > > -#define PMCFG2 0x04 > > -#define PMCFG2_ID GENMASK(17, 0) > > +#define MX95_PMCFG1_WR_BEAT_FILT_EN BIT(31) > > +#define MX95_PMCFG1_RD_BEAT_FILT_EN BIT(30) > > + > > +#define PMCFG2 0x04 > > +#define MX93_PMCFG2_ID GENMASK(17, 0) > > + > > +#define PMCFG3 0x08 > > +#define PMCFG4 0x0C > > +#define PMCFG5 0x10 > > +#define PMCFG6 0x14 > > +#define MX95_PMCFG_ID_MASK GENMASK(9, 0) > > +#define MX95_PMCFG_ID GENMASK(25, 16) > > > > /* Global control register affects all counters and takes priority over local > > control registers */ > > #define PMGC0 0x40 > > @@ -71,12 +81,22 @@ static const struct imx_ddr_devtype_data > > imx93_devtype_data = { > > .identifier = "imx93", > > }; > > > > +static const struct imx_ddr_devtype_data imx95_devtype_data = { > > + .identifier = "imx95", > > +}; > > + > > static const struct of_device_id imx_ddr_pmu_dt_ids[] = { > > {.compatible = "fsl,imx93-ddr-pmu", .data = &imx93_devtype_data}, > > + {.compatible = "fsl,imx95-ddr-pmu", .data = &imx95_devtype_data}, > > { /* sentinel */ } > > }; > > MODULE_DEVICE_TABLE(of, imx_ddr_pmu_dt_ids); > > > > +static inline bool is_imx93(struct ddr_pmu *pmu) > > +{ > > + return pmu->devtype_data == &imx93_devtype_data; > > +} > > + > > static ssize_t ddr_perf_identifier_show(struct device *dev, > > struct device_attribute *attr, > > char *page) > > @@ -178,7 +198,6 @@ static struct attribute *ddr_perf_events_attrs[] = { > > IMX9_DDR_PMU_EVENT_ATTR(ddrc_ld_wiq_6, 70), > > IMX9_DDR_PMU_EVENT_ATTR(ddrc_ld_wiq_7, 71), > > IMX9_DDR_PMU_EVENT_ATTR(eddrtq_pmon_empty, 72), > > - IMX9_DDR_PMU_EVENT_ATTR(eddrtq_pm_rd_trans_filt, 73), > > > > /* counter3 specific events */ > > IMX9_DDR_PMU_EVENT_ATTR(ddrc_qx_row_collision_0, 64), > > @@ -190,7 +209,6 @@ static struct attribute *ddr_perf_events_attrs[] = { > > IMX9_DDR_PMU_EVENT_ATTR(ddrc_qx_row_collision_6, 70), > > IMX9_DDR_PMU_EVENT_ATTR(ddrc_qx_row_collision_7, 71), > > IMX9_DDR_PMU_EVENT_ATTR(eddrtq_pmon_full, 72), > > - IMX9_DDR_PMU_EVENT_ATTR(eddrtq_pm_wr_trans_filt, 73), > > > > /* counter4 specific events */ > > IMX9_DDR_PMU_EVENT_ATTR(ddrc_qx_row_open_0, 64), > > @@ -202,7 +220,6 @@ static struct attribute *ddr_perf_events_attrs[] = { > > IMX9_DDR_PMU_EVENT_ATTR(ddrc_qx_row_open_6, 70), > > IMX9_DDR_PMU_EVENT_ATTR(ddrc_qx_row_open_7, 71), > > IMX9_DDR_PMU_EVENT_ATTR(eddrtq_pmon_ld_rdq2_rmw, 72), > > - IMX9_DDR_PMU_EVENT_ATTR(eddrtq_pm_rd_beat_filt, 73), > > > > /* counter5 specific events */ > > IMX9_DDR_PMU_EVENT_ATTR(ddrc_qx_valid_start_0, 64), > > @@ -242,6 +259,26 @@ static const struct attribute_group > > ddr_perf_events_attr_group = { > > .attrs = ddr_perf_events_attrs, > > }; > > > > +static struct attribute *imx93_ddr_perf_events_attrs[] = { > > + /* counter2 specific events */ > > + IMX9_DDR_PMU_EVENT_ATTR(eddrtq_pm_rd_trans_filt, 73), > > + /* counter3 specific events */ > > + IMX9_DDR_PMU_EVENT_ATTR(eddrtq_pm_wr_trans_filt, 73), > > + /* counter4 specific events */ > > + IMX9_DDR_PMU_EVENT_ATTR(eddrtq_pm_rd_beat_filt, 73), > > +}; > > + > > +static struct attribute *imx95_ddr_perf_events_attrs[] = { > > + /* counter2 specific events */ > > + IMX9_DDR_PMU_EVENT_ATTR(eddrtq_pm_wr_beat_filt, 73), > > + /* counter3 specific events */ > > + IMX9_DDR_PMU_EVENT_ATTR(eddrtq_pm_rd_beat_filt2, 73), > > + /* counter4 specific events */ > > + IMX9_DDR_PMU_EVENT_ATTR(eddrtq_pm_rd_beat_filt1, 73), > > + /* counter5 specific events */ > > + IMX9_DDR_PMU_EVENT_ATTR(eddrtq_pm_rd_beat_filt0, 73), > > +}; > > + > > PMU_FORMAT_ATTR(event, "config:0-7"); > > PMU_FORMAT_ATTR(counter, "config:8-15"); > > PMU_FORMAT_ATTR(axi_id, "config1:0-17"); > > @@ -361,7 +398,7 @@ static void ddr_perf_counter_local_config(struct > > ddr_pmu *pmu, int config, > > } > > } > > > > -static void ddr_perf_monitor_config(struct ddr_pmu *pmu, int cfg, int cfg1, > > int cfg2) > > +static void imx93_ddr_perf_monitor_config(struct ddr_pmu *pmu, int cfg, > > int cfg1, int cfg2) > > { > > u32 pmcfg1, pmcfg2; > > int event, counter; > > @@ -372,30 +409,80 @@ static void ddr_perf_monitor_config(struct > > ddr_pmu *pmu, int cfg, int cfg1, int > > pmcfg1 = readl_relaxed(pmu->base + PMCFG1); > > > > if (counter == 2 && event == 73) > > - pmcfg1 |= PMCFG1_RD_TRANS_FILT_EN; > > + pmcfg1 |= MX93_PMCFG1_RD_TRANS_FILT_EN; > > else if (counter == 2 && event != 73) > > - pmcfg1 &= ~PMCFG1_RD_TRANS_FILT_EN; > > + pmcfg1 &= ~MX93_PMCFG1_RD_TRANS_FILT_EN; > > > > if (counter == 3 && event == 73) > > - pmcfg1 |= PMCFG1_WR_TRANS_FILT_EN; > > + pmcfg1 |= MX93_PMCFG1_WR_TRANS_FILT_EN; > > else if (counter == 3 && event != 73) > > - pmcfg1 &= ~PMCFG1_WR_TRANS_FILT_EN; > > + pmcfg1 &= ~MX93_PMCFG1_WR_TRANS_FILT_EN; > > > > if (counter == 4 && event == 73) > > - pmcfg1 |= PMCFG1_RD_BT_FILT_EN; > > + pmcfg1 |= MX93_PMCFG1_RD_BT_FILT_EN; > > else if (counter == 4 && event != 73) > > - pmcfg1 &= ~PMCFG1_RD_BT_FILT_EN; > > + pmcfg1 &= ~MX93_PMCFG1_RD_BT_FILT_EN; > > > > - pmcfg1 &= ~FIELD_PREP(PMCFG1_ID_MASK, 0x3FFFF); > > - pmcfg1 |= FIELD_PREP(PMCFG1_ID_MASK, cfg2); > > + pmcfg1 &= ~FIELD_PREP(MX93_PMCFG1_ID_MASK, 0x3FFFF); > > + pmcfg1 |= FIELD_PREP(MX93_PMCFG1_ID_MASK, cfg2); > > writel(pmcfg1, pmu->base + PMCFG1); > > > > pmcfg2 = readl_relaxed(pmu->base + PMCFG2); > > - pmcfg2 &= ~FIELD_PREP(PMCFG2_ID, 0x3FFFF); > > - pmcfg2 |= FIELD_PREP(PMCFG2_ID, cfg1); > > + pmcfg2 &= ~FIELD_PREP(MX93_PMCFG2_ID, 0x3FFFF); > > + pmcfg2 |= FIELD_PREP(MX93_PMCFG2_ID, cfg1); > > Suggest created a sperate rename patch, which prepare for IMX95. > > Frank > > > writel(pmcfg2, pmu->base + PMCFG2); > > } > > > > +static void imx95_ddr_perf_monitor_config(struct ddr_pmu *pmu, int cfg, > > int cfg1, int cfg2) > > +{ > > + u32 pmcfg1, pmcfg, offset = 0; > > + int event, counter; > > + > > + event = cfg & 0x000000FF; > > + counter = (cfg & 0x0000FF00) >> 8; > > + > > + pmcfg1 = readl_relaxed(pmu->base + PMCFG1); > > + > > + if (counter == 2 && event == 73) { > > + pmcfg1 |= MX95_PMCFG1_WR_BEAT_FILT_EN; > > + offset = PMCFG3; > > + } else if (counter == 2 && event != 73) { > > + pmcfg1 &= ~MX95_PMCFG1_WR_BEAT_FILT_EN; > > + } > > + > > + if (counter == 3 && event == 73) { > > + pmcfg1 |= MX95_PMCFG1_RD_BEAT_FILT_EN; > > + offset = PMCFG4; > > + } else if (counter == 3 && event != 73) { > > + pmcfg1 &= ~MX95_PMCFG1_RD_BEAT_FILT_EN; > > + } > > + > > + if (counter == 4 && event == 73) { > > + pmcfg1 |= MX95_PMCFG1_RD_BEAT_FILT_EN; > > + offset = PMCFG5; > > + } else if (counter == 4 && event != 73) { > > + pmcfg1 &= ~MX95_PMCFG1_RD_BEAT_FILT_EN; > > + } > > + > > + if (counter == 5 && event == 73) { > > + pmcfg1 |= MX95_PMCFG1_RD_BEAT_FILT_EN; > > + offset = PMCFG6; > > + } else if (counter == 5 && event != 73) { > > + pmcfg1 &= ~MX95_PMCFG1_RD_BEAT_FILT_EN; > > + } > > + > > + writel(pmcfg1, pmu->base + PMCFG1); > > + > > + if (offset) { > > + pmcfg = readl_relaxed(pmu->base + offset); > > + pmcfg &= ~FIELD_PREP(MX95_PMCFG_ID_MASK, 0x3FF); > > + pmcfg |= FIELD_PREP(MX95_PMCFG_ID_MASK, cfg2); > > + pmcfg &= ~FIELD_PREP(MX95_PMCFG_ID, 0x3FF); > > It should be reductant. Okay, will change this. > > > + pmcfg |= FIELD_PREP(MX95_PMCFG_ID, cfg1); > > + writel(pmcfg, pmu->base + offset); > > + } > > +} > > + > > static void ddr_perf_event_update(struct perf_event *event) > > { > > struct ddr_pmu *pmu = to_ddr_pmu(event->pmu); > > @@ -479,8 +566,13 @@ static int ddr_perf_event_add(struct perf_event > > *event, int flags) > > if (flags & PERF_EF_START) > > ddr_perf_event_start(event, flags); > > > > - /* read trans, write trans, read beat */ > > - ddr_perf_monitor_config(pmu, cfg, cfg1, cfg2); > > + if (is_imx93(pmu)) { > > + /* read trans, write trans, read beat */ > > + imx93_ddr_perf_monitor_config(pmu, cfg, cfg1, cfg2); > > + } else { > > + /* write beat, read beat2, read beat1, read beat */ > > + imx95_ddr_perf_monitor_config(pmu, cfg, cfg1, cfg2); > > + } > > Did you run checkpatch? no "{" need?, not sure have comments case. No warning about this when run checkpatch. > > > > return 0; > > } > > @@ -596,6 +688,49 @@ static int ddr_perf_offline_cpu(unsigned int cpu, > > struct hlist_node *node) > > return 0; > > } > > > > +static int ddr_perf_add_events(struct ddr_pmu *pmu) > > +{ > > + int i, ret, events; > > + struct attribute **attrs; > > + struct device *pmu_dev = pmu->pmu.dev; > > + > > + if (is_imx93(pmu)) { > > + events = sizeof(imx93_ddr_perf_events_attrs)/sizeof(struct > > attribute *); > > + attrs = imx93_ddr_perf_events_attrs; > > + } else { > > + events = sizeof(imx95_ddr_perf_events_attrs)/sizeof(struct > > attribute *); > > + attrs = imx95_ddr_perf_events_attrs; > > + } > > Can you put "attrs" and "events" into drvdata? Okay. Will try it. > > > + > > + for (i = 0; i < events; i++) { > > + ret = sysfs_add_file_to_group(&pmu_dev->kobj, attrs[i], > > "events"); > > + if (ret) { > > + dev_warn(pmu->dev, "i.MX9 DDR Perf add events > > failed (%d)\n", ret); > > + return ret; > > + } > > + } > > + > > + return 0; > > +} > > + > > +static void ddr_perf_remove_events(struct ddr_pmu *pmu) > > +{ > > + int i, events; > > + struct attribute **attrs; > > + struct device *pmu_dev = pmu->pmu.dev; > > + > > + if (is_imx93(pmu)) { > > + events = sizeof(imx93_ddr_perf_events_attrs)/sizeof(struct > > attribute *); > > + attrs = imx93_ddr_perf_events_attrs; > > + } else { > > + events = sizeof(imx95_ddr_perf_events_attrs)/sizeof(struct > > attribute *); > > + attrs = imx95_ddr_perf_events_attrs; > > + } > > Can you put "attrs" and "events" into drvdata? Okay. Thanks, Xu Yang > > > + > > + for (i = 0; i < events; i++) > > + sysfs_remove_file_from_group(&pmu_dev->kobj, attrs[i], > > "events"); > > +} > > + > > static int ddr_perf_probe(struct platform_device *pdev) > > { > > struct ddr_pmu *pmu; > > @@ -666,6 +801,10 @@ static int ddr_perf_probe(struct platform_device > > *pdev) > > if (ret) > > goto ddr_perf_err; > > > > + ret = ddr_perf_add_events(pmu); > > + if (ret) > > + dev_warn(&pdev->dev, "i.MX9 DDR Perf filter events are > > missing\n"); > > + > > return 0; > > > > ddr_perf_err: > > @@ -683,6 +822,8 @@ static int ddr_perf_remove(struct platform_device > > *pdev) > > { > > struct ddr_pmu *pmu = platform_get_drvdata(pdev); > > > > + ddr_perf_remove_events(pmu); > > + > > cpuhp_state_remove_instance_nocalls(pmu->cpuhp_state, &pmu- > > >node); > > cpuhp_remove_multi_state(pmu->cpuhp_state); > > > > -- > > 2.34.1