[PATCH v2 1/5] perf: fsl_imx8_ddr: Add AXI ID PORT CHANNEL filter support
Frank Li
frank.li at nxp.com
Thu Oct 12 09:09:23 PDT 2023
> -----Original Message-----
> From: Xu Yang <xu.yang_2 at nxp.com>
> Sent: Wednesday, October 11, 2023 1:09 AM
> To: Frank Li <frank.li at nxp.com>; corbet at lwn.net; shawnguo at kernel.org;
> s.hauer at pengutronix.de; kernel at pengutronix.de; will at kernel.org;
> mark.rutland at arm.com; robh+dt at kernel.org;
> krzysztof.kozlowski+dt at linaro.org
> Cc: festevam at gmail.com; conor+dt at kernel.org; dl-linux-imx <linux-
> imx at nxp.com>; linux-arm-kernel at lists.infradead.org; linux-
> doc at vger.kernel.org; devicetree at vger.kernel.org; Xu Yang
> <xu.yang_2 at nxp.com>
> Subject: [PATCH v2 1/5] perf: fsl_imx8_ddr: Add AXI ID PORT CHANNEL filter
> support
>
> This is the extension of AXI ID filter.
>
> Filter is defined with 2 configuration registers per counter 1-3 (counter
> 0 is not used for filtering and lacks these registers).
> * Counter N MASK COMP register - AXI_ID and AXI_MASKING.
> * Counter N MUX CNTL register - AXI CHANNEL and AXI PORT.
> -- 0: address channel
> -- 1: data channel
>
> This filter is exposed to userspace as an additional (channel, port) pair.
> The definition of axi_channel is inverted in userspace, and it will be
> reverted in driver automatically.
>
> AXI filter of Perf Monitor in DDR Subsystem, only a single port0 exist, so
> axi_port is reserved which should be 0.
>
> e.g.
> perf stat -a -e imx8_ddr0/axid-
> read,axi_mask=0xMMMM,axi_id=0xDDDD,axi_channel=0xH/ cmd
> perf stat -a -e imx8_ddr0/axid-
> write,axi_mask=0xMMMM,axi_id=0xDDDD,axi_channel=0xH/ cmd
>
> Signed-off-by: Xu Yang <xu.yang_2 at nxp.com>
Reviewed-by: Frank Li <Frank.Li at nxp.com>
>
> ---
> Changes since v2:
> - no changes
> ---
> drivers/perf/fsl_imx8_ddr_perf.c | 39
> ++++++++++++++++++++++++++++++++
> 1 file changed, 39 insertions(+)
>
> diff --git a/drivers/perf/fsl_imx8_ddr_perf.c
> b/drivers/perf/fsl_imx8_ddr_perf.c
> index 92611c98120f..d0eae2d7e64b 100644
> --- a/drivers/perf/fsl_imx8_ddr_perf.c
> +++ b/drivers/perf/fsl_imx8_ddr_perf.c
> @@ -19,6 +19,8 @@
> #define COUNTER_READ 0x20
>
> #define COUNTER_DPCR1 0x30
> +#define COUNTER_MUX_CNTL 0x50
> +#define COUNTER_MASK_COMP 0x54
>
> #define CNTL_OVER 0x1
> #define CNTL_CLEAR 0x2
> @@ -32,6 +34,13 @@
> #define CNTL_CSV_SHIFT 24
> #define CNTL_CSV_MASK (0xFFU << CNTL_CSV_SHIFT)
>
> +#define READ_PORT_SHIFT 0
> +#define READ_PORT_MASK (0x7 << READ_PORT_SHIFT)
> +#define READ_CHANNEL_REVERT 0x00000008 /* bit 3 for read
> channel select */
> +#define WRITE_PORT_SHIFT 8
> +#define WRITE_PORT_MASK (0x7 << WRITE_PORT_SHIFT)
> +#define WRITE_CHANNEL_REVERT 0x00000800 /* bit 11 for write
> channel select */
> +
> #define EVENT_CYCLES_ID 0
> #define EVENT_CYCLES_COUNTER 0
> #define NUM_COUNTERS 4
> @@ -50,6 +59,7 @@ static DEFINE_IDA(ddr_ida);
> /* DDR Perf hardware feature */
> #define DDR_CAP_AXI_ID_FILTER 0x1 /* support AXI
> ID filter */
> #define DDR_CAP_AXI_ID_FILTER_ENHANCED 0x3 /* support
> enhanced AXI ID filter */
> +#define DDR_CAP_AXI_ID_PORT_CHANNEL_FILTER 0x4 /* support
> AXI ID PORT CHANNEL filter */
>
> struct fsl_ddr_devtype_data {
> unsigned int quirks; /* quirks needed for different DDR Perf core */
> @@ -144,6 +154,7 @@ static const struct attribute_group
> ddr_perf_identifier_attr_group = {
> enum ddr_perf_filter_capabilities {
> PERF_CAP_AXI_ID_FILTER = 0,
> PERF_CAP_AXI_ID_FILTER_ENHANCED,
> + PERF_CAP_AXI_ID_PORT_CHANNEL_FILTER,
> PERF_CAP_AXI_ID_FEAT_MAX,
> };
>
> @@ -157,6 +168,8 @@ static u32 ddr_perf_filter_cap_get(struct ddr_pmu
> *pmu, int cap)
> case PERF_CAP_AXI_ID_FILTER_ENHANCED:
> quirks &= DDR_CAP_AXI_ID_FILTER_ENHANCED;
> return quirks == DDR_CAP_AXI_ID_FILTER_ENHANCED;
> + case PERF_CAP_AXI_ID_PORT_CHANNEL_FILTER:
> + return !!(quirks & DDR_CAP_AXI_ID_PORT_CHANNEL_FILTER);
> default:
> WARN(1, "unknown filter cap %d\n", cap);
> }
> @@ -187,6 +200,7 @@ static ssize_t ddr_perf_filter_cap_show(struct device
> *dev,
> static struct attribute *ddr_perf_filter_cap_attr[] = {
> PERF_FILTER_EXT_ATTR_ENTRY(filter, PERF_CAP_AXI_ID_FILTER),
> PERF_FILTER_EXT_ATTR_ENTRY(enhanced_filter,
> PERF_CAP_AXI_ID_FILTER_ENHANCED),
> + PERF_FILTER_EXT_ATTR_ENTRY(super_filter,
> PERF_CAP_AXI_ID_PORT_CHANNEL_FILTER),
> NULL,
> };
>
> @@ -272,11 +286,15 @@ static const struct attribute_group
> ddr_perf_events_attr_group = {
> PMU_FORMAT_ATTR(event, "config:0-7");
> PMU_FORMAT_ATTR(axi_id, "config1:0-15");
> PMU_FORMAT_ATTR(axi_mask, "config1:16-31");
> +PMU_FORMAT_ATTR(axi_port, "config2:0-2");
> +PMU_FORMAT_ATTR(axi_channel, "config2:3-3");
>
> static struct attribute *ddr_perf_format_attrs[] = {
> &format_attr_event.attr,
> &format_attr_axi_id.attr,
> &format_attr_axi_mask.attr,
> + &format_attr_axi_port.attr,
> + &format_attr_axi_channel.attr,
> NULL,
> };
>
> @@ -530,6 +548,7 @@ static int ddr_perf_event_add(struct perf_event
> *event, int flags)
> int counter;
> int cfg = event->attr.config;
> int cfg1 = event->attr.config1;
> + int cfg2 = event->attr.config2;
>
> if (pmu->devtype_data->quirks & DDR_CAP_AXI_ID_FILTER) {
> int i;
> @@ -553,6 +572,26 @@ static int ddr_perf_event_add(struct perf_event
> *event, int flags)
> return -EOPNOTSUPP;
> }
>
> + if (pmu->devtype_data->quirks &
> DDR_CAP_AXI_ID_PORT_CHANNEL_FILTER) {
> + if (ddr_perf_is_filtered(event)) {
> + /* revert axi id masking(axi_mask) value */
> + cfg1 ^= AXI_MASKING_REVERT;
> + writel(cfg1, pmu->base + COUNTER_MASK_COMP +
> ((counter - 1) << 4));
> +
> + if (cfg == 0x41) {
> + /* revert axi read channel(axi_channel) value
> */
> + cfg2 ^= READ_CHANNEL_REVERT;
> + cfg2 |= FIELD_PREP(READ_PORT_MASK, cfg2);
> + } else {
> + /* revert axi write channel(axi_channel) value
> */
> + cfg2 ^= WRITE_CHANNEL_REVERT;
> + cfg2 |= FIELD_PREP(WRITE_PORT_MASK,
> cfg2);
> + }
> +
> + writel(cfg2, pmu->base + COUNTER_MUX_CNTL +
> ((counter - 1) << 4));
> + }
> + }
> +
> pmu->events[counter] = event;
> hwc->idx = counter;
>
> --
> 2.34.1
More information about the linux-arm-kernel
mailing list