linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH V2] perf: imx8_ddr_perf: add AXI ID filter support
@ 2019-07-25  7:22 Joakim Zhang
  2019-07-25 16:03 ` Frank Li
  0 siblings, 1 reply; 2+ messages in thread
From: Joakim Zhang @ 2019-07-25  7:22 UTC (permalink / raw)
  To: robin.murphy, will, mark.rutland, Frank Li
  Cc: kernel, dl-linux-imx, linux-arm-kernel, Joakim Zhang

AXI filtering is used by CSV modes 0x41 and 0x42 to count reads or
writes with an ARID or AXID matching filter setting. Granularity is at
subsystem level. Implementation does not allow filtring between masters
within a subsystem. Filter is defined with 2 configuration registers.

--AXI_ID defines AxID matching value
--AXI_MASKING defines which bits of AxID are meaningful for the matching

When non-masked bits are matching corresponding AXI_ID bits then counter
is incremented. This filter allows counting read or write access from a
subsystem or multiple subsystems.

Perf counter is incremented if AxID && AXI_MASKING == AXI_ID && AXI_MASKING

AXI_ID and AXI_MASKING are mapped on DPCR1 register in performance counter.

Read and write AXI ID filter can't be specified at the same time as this
filter is shared between counters.

e.g.
perf stat -a -e imx8_ddr0/axi-id-read,axi_id=0xMMMMDDDD/ cmd
MMMM: AXI_MASKING
DDDD: AXI_ID

ChangeLog:
V1 -> V2:
	* add error log if user specifies read/write AXI ID filter at
	the same time.
	* of_device_get_match_data() instead of of_match_device(), and
	remove the check of return value.

Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
---
 drivers/perf/fsl_imx8_ddr_perf.c | 48 ++++++++++++++++++++++++++++++--
 1 file changed, 46 insertions(+), 2 deletions(-)

diff --git a/drivers/perf/fsl_imx8_ddr_perf.c b/drivers/perf/fsl_imx8_ddr_perf.c
index 63fe21600072..da851da74cbd 100644
--- a/drivers/perf/fsl_imx8_ddr_perf.c
+++ b/drivers/perf/fsl_imx8_ddr_perf.c
@@ -42,9 +42,22 @@
 
 static DEFINE_IDA(ddr_ida);
 
+/* DDR Perf hardware feature */
+#define DDR_CAP_AXI_ID_FILTER		0x1	/* support AXI ID filter */
+
+struct fsl_ddr_devtype_data {
+	unsigned int quirks;	/* quirks needed for different DDR Perf core */
+};
+
+static const struct fsl_ddr_devtype_data imx8_devtype_data;
+
+static const struct fsl_ddr_devtype_data imx8m_devtype_data = {
+	.quirks = DDR_CAP_AXI_ID_FILTER,
+};
+
 static const struct of_device_id imx_ddr_pmu_dt_ids[] = {
-	{ .compatible = "fsl,imx8-ddr-pmu",},
-	{ .compatible = "fsl,imx8m-ddr-pmu",},
+	{ .compatible = "fsl,imx8-ddr-pmu", .data = &imx8_devtype_data},
+	{ .compatible = "fsl,imx8m-ddr-pmu", .data = &imx8m_devtype_data},
 	{ /* sentinel */ }
 };
 
@@ -57,6 +70,8 @@ struct ddr_pmu {
 	struct perf_event *events[NUM_COUNTERS];
 	int active_events;
 	enum cpuhp_state cpuhp_state;
+	const struct fsl_ddr_devtype_data *devtype_data;
+	bool axi_id_read, axi_id_write;
 	int irq;
 	int id;
 };
@@ -128,6 +143,8 @@ static struct attribute *ddr_perf_events_attrs[] = {
 	IMX8_DDR_PMU_EVENT_ATTR(refresh, 0x37),
 	IMX8_DDR_PMU_EVENT_ATTR(write, 0x38),
 	IMX8_DDR_PMU_EVENT_ATTR(raw-hazard, 0x39),
+	IMX8_DDR_PMU_EVENT_ATTR(axi-id-read, 0x41),
+	IMX8_DDR_PMU_EVENT_ATTR(axi-id-write, 0x42),
 	NULL,
 };
 
@@ -137,9 +154,11 @@ static struct attribute_group ddr_perf_events_attr_group = {
 };
 
 PMU_FORMAT_ATTR(event, "config:0-7");
+PMU_FORMAT_ATTR(axi_id, "config1:0-31");
 
 static struct attribute *ddr_perf_format_attrs[] = {
 	&format_attr_event.attr,
+	&format_attr_axi_id.attr,
 	NULL,
 };
 
@@ -274,6 +293,22 @@ static void ddr_perf_event_start(struct perf_event *event, int flags)
 	struct hw_perf_event *hwc = &event->hw;
 	int counter = hwc->idx;
 
+	if (pmu->devtype_data->quirks & DDR_CAP_AXI_ID_FILTER) {
+		if (event->attr.config == 0x41)
+			pmu->axi_id_read = true;
+
+		if (event->attr.config == 0x42)
+			pmu->axi_id_write = true;
+
+		if (pmu->axi_id_read && pmu->axi_id_write) {
+			dev_err(pmu->dev, "axi-id-read/write event can't be specified at the same time\n");
+		} else {
+			int val = event->attr.config1;
+
+			writel(val, pmu->base + COUNTER_DPCR1);
+		}
+	}
+
 	local64_set(&hwc->prev_count, 0);
 
 	ddr_perf_counter_enable(pmu, event->attr.config, counter, true);
@@ -316,6 +351,11 @@ static void ddr_perf_event_stop(struct perf_event *event, int flags)
 	ddr_perf_event_update(event);
 
 	hwc->state |= PERF_HES_STOPPED;
+
+	if (pmu->devtype_data->quirks & DDR_CAP_AXI_ID_FILTER) {
+		pmu->axi_id_read = false;
+		pmu->axi_id_write = false;
+	}
 }
 
 static void ddr_perf_event_del(struct perf_event *event, int flags)
@@ -445,6 +485,7 @@ static int ddr_perf_offline_cpu(unsigned int cpu, struct hlist_node *node)
 
 static int ddr_perf_probe(struct platform_device *pdev)
 {
+	const struct fsl_ddr_devtype_data *data;
 	struct ddr_pmu *pmu;
 	struct device_node *np;
 	void __iomem *base;
@@ -472,6 +513,9 @@ static int ddr_perf_probe(struct platform_device *pdev)
 	if (!name)
 		return -ENOMEM;
 
+	data = of_device_get_match_data(&pdev->dev);
+	pmu->devtype_data = data;
+
 	pmu->cpu = raw_smp_processor_id();
 	ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN,
 				      DDR_CPUHP_CB_NAME,
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* RE: [PATCH V2] perf: imx8_ddr_perf: add AXI ID filter support
  2019-07-25  7:22 [PATCH V2] perf: imx8_ddr_perf: add AXI ID filter support Joakim Zhang
@ 2019-07-25 16:03 ` Frank Li
  0 siblings, 0 replies; 2+ messages in thread
From: Frank Li @ 2019-07-25 16:03 UTC (permalink / raw)
  To: Joakim Zhang, robin.murphy, will, mark.rutland
  Cc: kernel, dl-linux-imx, linux-arm-kernel



> -----Original Message-----
> From: Joakim Zhang
> Sent: Thursday, July 25, 2019 2:22 AM
> To: robin.murphy@arm.com; will@kernel.org; mark.rutland@arm.com; Frank Li
> <frank.li@nxp.com>
> Cc: linux-arm-kernel@lists.infradead.org; dl-linux-imx <linux-imx@nxp.com>;
> kernel@pengutronix.de; Joakim Zhang <qiangqing.zhang@nxp.com>
> Subject: [PATCH V2] perf: imx8_ddr_perf: add AXI ID filter support
> 
> AXI filtering is used by CSV modes 0x41 and 0x42 to count reads or writes with
> an ARID or AXID matching filter setting. Granularity is at subsystem level.
> Implementation does not allow filtring between masters within a subsystem.
> Filter is defined with 2 configuration registers.
> 
> --AXI_ID defines AxID matching value
> --AXI_MASKING defines which bits of AxID are meaningful for the matching
> 
> When non-masked bits are matching corresponding AXI_ID bits then counter is
> incremented. This filter allows counting read or write access from a subsystem
> or multiple subsystems.
> 
> Perf counter is incremented if AxID && AXI_MASKING == AXI_ID &&
> AXI_MASKING
> 
> AXI_ID and AXI_MASKING are mapped on DPCR1 register in performance
> counter.
> 
> Read and write AXI ID filter can't be specified at the same time as this filter is
> shared between counters.
> 
> e.g.
> perf stat -a -e imx8_ddr0/axi-id-read,axi_id=0xMMMMDDDD/ cmd
> MMMM: AXI_MASKING
> DDDD: AXI_ID
> 
> ChangeLog:
> V1 -> V2:
> 	* add error log if user specifies read/write AXI ID filter at
> 	the same time.
> 	* of_device_get_match_data() instead of of_match_device(), and
> 	remove the check of return value.
> 
> Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
> ---
>  drivers/perf/fsl_imx8_ddr_perf.c | 48 ++++++++++++++++++++++++++++++--
>  1 file changed, 46 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/perf/fsl_imx8_ddr_perf.c b/drivers/perf/fsl_imx8_ddr_perf.c
> index 63fe21600072..da851da74cbd 100644
> --- a/drivers/perf/fsl_imx8_ddr_perf.c
> +++ b/drivers/perf/fsl_imx8_ddr_perf.c
> @@ -42,9 +42,22 @@
> 
>  static DEFINE_IDA(ddr_ida);
> 
> +/* DDR Perf hardware feature */
> +#define DDR_CAP_AXI_ID_FILTER		0x1	/* support AXI ID filter
> */
> +
> +struct fsl_ddr_devtype_data {
> +	unsigned int quirks;	/* quirks needed for different DDR Perf core */
> +};
> +
> +static const struct fsl_ddr_devtype_data imx8_devtype_data;
> +
> +static const struct fsl_ddr_devtype_data imx8m_devtype_data = {
> +	.quirks = DDR_CAP_AXI_ID_FILTER,
> +};
> +
>  static const struct of_device_id imx_ddr_pmu_dt_ids[] = {
> -	{ .compatible = "fsl,imx8-ddr-pmu",},
> -	{ .compatible = "fsl,imx8m-ddr-pmu",},
> +	{ .compatible = "fsl,imx8-ddr-pmu", .data = &imx8_devtype_data},
> +	{ .compatible = "fsl,imx8m-ddr-pmu", .data = &imx8m_devtype_data},
>  	{ /* sentinel */ }
>  };
> 
> @@ -57,6 +70,8 @@ struct ddr_pmu {
>  	struct perf_event *events[NUM_COUNTERS];
>  	int active_events;
>  	enum cpuhp_state cpuhp_state;
> +	const struct fsl_ddr_devtype_data *devtype_data;
> +	bool axi_id_read, axi_id_write;
>  	int irq;
>  	int id;
>  };
> @@ -128,6 +143,8 @@ static struct attribute *ddr_perf_events_attrs[] = {
>  	IMX8_DDR_PMU_EVENT_ATTR(refresh, 0x37),
>  	IMX8_DDR_PMU_EVENT_ATTR(write, 0x38),
>  	IMX8_DDR_PMU_EVENT_ATTR(raw-hazard, 0x39),
> +	IMX8_DDR_PMU_EVENT_ATTR(axi-id-read, 0x41),
> +	IMX8_DDR_PMU_EVENT_ATTR(axi-id-write, 0x42),
>  	NULL,
>  };
> 
> @@ -137,9 +154,11 @@ static struct attribute_group
> ddr_perf_events_attr_group = {  };
> 
>  PMU_FORMAT_ATTR(event, "config:0-7");
> +PMU_FORMAT_ATTR(axi_id, "config1:0-31");
> 
>  static struct attribute *ddr_perf_format_attrs[] = {
>  	&format_attr_event.attr,
> +	&format_attr_axi_id.attr,
>  	NULL,
>  };
> 
> @@ -274,6 +293,22 @@ static void ddr_perf_event_start(struct perf_event
> *event, int flags)
>  	struct hw_perf_event *hwc = &event->hw;
>  	int counter = hwc->idx;
> 
> +	if (pmu->devtype_data->quirks & DDR_CAP_AXI_ID_FILTER) {
> +		if (event->attr.config == 0x41)
> +			pmu->axi_id_read = true;
> +
> +		if (event->attr.config == 0x42)
> +			pmu->axi_id_write = true;
> +
> +		if (pmu->axi_id_read && pmu->axi_id_write) {
> +			dev_err(pmu->dev, "axi-id-read/write event can't be
> specified at the same time\n");

 axi_id can be the same value for 0x41 and 0x42.
 It should be checked at event_add. 
 So it provide user early error information.  

Best regards
Frank Li

> +		} else {
> +			int val = event->attr.config1;
> +
> +			writel(val, pmu->base + COUNTER_DPCR1);
> +		}
> +	}
> +
>  	local64_set(&hwc->prev_count, 0);
> 
>  	ddr_perf_counter_enable(pmu, event->attr.config, counter, true); @@ -
> 316,6 +351,11 @@ static void ddr_perf_event_stop(struct perf_event *event,
> int flags)
>  	ddr_perf_event_update(event);
> 
>  	hwc->state |= PERF_HES_STOPPED;
> +
> +	if (pmu->devtype_data->quirks & DDR_CAP_AXI_ID_FILTER) {
> +		pmu->axi_id_read = false;
> +		pmu->axi_id_write = false;
> +	}
>  }
> 
>  static void ddr_perf_event_del(struct perf_event *event, int flags) @@ -445,6
> +485,7 @@ static int ddr_perf_offline_cpu(unsigned int cpu, struct hlist_node
> *node)
> 
>  static int ddr_perf_probe(struct platform_device *pdev)  {
> +	const struct fsl_ddr_devtype_data *data;
>  	struct ddr_pmu *pmu;
>  	struct device_node *np;
>  	void __iomem *base;
> @@ -472,6 +513,9 @@ static int ddr_perf_probe(struct platform_device *pdev)
>  	if (!name)
>  		return -ENOMEM;
> 
> +	data = of_device_get_match_data(&pdev->dev);
> +	pmu->devtype_data = data;
> +
>  	pmu->cpu = raw_smp_processor_id();
>  	ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN,
>  				      DDR_CPUHP_CB_NAME,
> --
> 2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2019-07-25 16:03 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-25  7:22 [PATCH V2] perf: imx8_ddr_perf: add AXI ID filter support Joakim Zhang
2019-07-25 16:03 ` Frank Li

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).