diff options
author | Joakim Zhang <qiangqing.zhang@nxp.com> | 2019-09-24 14:03:49 +0800 |
---|---|---|
committer | Joakim Zhang <qiangqing.zhang@nxp.com> | 2020-03-04 09:06:04 +0800 |
commit | 18081034fd7a136f31e704812d36db0f4122acea (patch) | |
tree | 353bbe9fd54a7403b440badea7051223dd817246 /drivers/perf | |
parent | cb1a3f4a797561e1abdf3234b7d6a71f49ddac5d (diff) |
MLK-23418-1 perf/imx_ddr: Extend driver for PMU in DRAM Block(DB)
There is a PMU in DB(DRAM Block) which has the same function with PMU in DDR
subsystem, the difference is PMU in DB only supports cycles, axid-read,
axid-write events.
The role of the DB is to route the read/write transaction from connected
subsystems to either the DDR subsystem, or to any other subsystems. The AXI
IDs used is the one seen at the PORT.
e.g.
perf stat -a -e imx8_db0/axid-read,axi_mask=0xMMMM,axi_id=0xDDDD,axi_port=0xPP,axi_channel=0xH/ cmd
perf stat -a -e imx8_db0/axid-write,axi_mask=0xMMMM,axi_id=0xDDDD,axi_port=0xPP,axi_channel=0xH/ cmd
Reviewed-by: Fugang Duan <fugang.duan@nxp.com>
Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
Diffstat (limited to 'drivers/perf')
-rw-r--r-- | drivers/perf/fsl_imx8_ddr_perf.c | 73 |
1 files changed, 58 insertions, 15 deletions
diff --git a/drivers/perf/fsl_imx8_ddr_perf.c b/drivers/perf/fsl_imx8_ddr_perf.c index 4084470a2af3..4e816dfc5117 100644 --- a/drivers/perf/fsl_imx8_ddr_perf.c +++ b/drivers/perf/fsl_imx8_ddr_perf.c @@ -52,31 +52,43 @@ #define to_ddr_pmu(p) container_of(p, struct ddr_pmu, pmu) #define DDR_PERF_DEV_NAME "imx8_ddr" +#define DB_PERF_DEV_NAME "imx8_db" #define DDR_CPUHP_CB_NAME DDR_PERF_DEV_NAME "_perf_pmu" static DEFINE_IDA(ddr_ida); +static DEFINE_IDA(db_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 */ +/* Perf type */ +#define DDR_PERF_TYPE 0x1 /* ddr Perf */ +#define DB_PERF_TYPE 0x2 /* db Perf */ + struct fsl_ddr_devtype_data { unsigned int quirks; /* quirks needed for different DDR Perf core */ + unsigned int type; /* types of Perf, point the location of Perf */ }; -static const struct fsl_ddr_devtype_data imx8_devtype_data; +static const struct fsl_ddr_devtype_data imx8_devtype_data = { + .type = DDR_PERF_TYPE, +}; static const struct fsl_ddr_devtype_data imx8m_devtype_data = { .quirks = DDR_CAP_AXI_ID_FILTER, + .type = DDR_PERF_TYPE, }; static const struct fsl_ddr_devtype_data imx8mp_devtype_data = { .quirks = DDR_CAP_AXI_ID_FILTER_ENHANCED, + .type = DDR_PERF_TYPE, }; static const struct fsl_ddr_devtype_data imx8dxl_devtype_data = { .quirks = DDR_CAP_AXI_ID_PORT_CHANNEL_FILTER, + .type = DDR_PERF_TYPE, }; static const struct of_device_id imx_ddr_pmu_dt_ids[] = { @@ -239,6 +251,18 @@ static struct attribute_group ddr_perf_events_attr_group = { .attrs = ddr_perf_events_attrs, }; +static struct attribute *db_perf_events_attrs[] = { + IMX8_DDR_PMU_EVENT_ATTR(cycles, EVENT_CYCLES_ID), + IMX8_DDR_PMU_EVENT_ATTR(axid-read, 0x41), + IMX8_DDR_PMU_EVENT_ATTR(axid-write, 0x42), + NULL, +}; + +static struct attribute_group db_perf_events_attr_group = { + .name = "events", + .attrs = db_perf_events_attrs, +}; + PMU_FORMAT_ATTR(event, "config:0-7"); PMU_FORMAT_ATTR(axi_id, "config1:0-15"); PMU_FORMAT_ATTR(axi_mask, "config1:16-31"); @@ -259,7 +283,8 @@ static struct attribute_group ddr_perf_format_attr_group = { .attrs = ddr_perf_format_attrs, }; -static const struct attribute_group *attr_groups[] = { +static const struct attribute_group *ddr_attr_groups[] = { + &ddr_perf_events_attr_group, &ddr_perf_format_attr_group, &ddr_perf_cpumask_attr_group, @@ -267,6 +292,14 @@ static const struct attribute_group *attr_groups[] = { NULL, }; +static const struct attribute_group *db_attr_groups[] = { + &db_perf_events_attr_group, + &ddr_perf_format_attr_group, + &ddr_perf_cpumask_attr_group, + &ddr_perf_filter_cap_attr_group, + NULL, +}; + static bool ddr_perf_is_filtered(struct perf_event *event) { return event->attr.config == 0x41 || event->attr.config == 0x42; @@ -584,14 +617,13 @@ static void ddr_perf_pmu_disable(struct pmu *pmu) false); } -static int ddr_perf_init(struct ddr_pmu *pmu, void __iomem *base, +static void ddr_perf_init(struct ddr_pmu *pmu, void __iomem *base, struct device *dev) { *pmu = (struct ddr_pmu) { .pmu = (struct pmu) { .capabilities = PERF_PMU_CAP_NO_EXCLUDE, .task_ctx_nr = perf_invalid_context, - .attr_groups = attr_groups, .event_init = ddr_perf_event_init, .add = ddr_perf_event_add, .del = ddr_perf_event_del, @@ -604,9 +636,6 @@ static int ddr_perf_init(struct ddr_pmu *pmu, void __iomem *base, .base = base, .dev = dev, }; - - pmu->id = ida_simple_get(&ddr_ida, 0, 0, GFP_KERNEL); - return pmu->id; } static irqreturn_t ddr_perf_irq_handler(int irq, void *p) @@ -698,7 +727,6 @@ static int ddr_perf_probe(struct platform_device *pdev) struct device_node *np; void __iomem *base; char *name; - int num; int ret; int irq; @@ -712,18 +740,25 @@ static int ddr_perf_probe(struct platform_device *pdev) if (!pmu) return -ENOMEM; - num = ddr_perf_init(pmu, base, &pdev->dev); + ddr_perf_init(pmu, base, &pdev->dev); platform_set_drvdata(pdev, pmu); spin_lock_init(&pmu->lock); - name = devm_kasprintf(&pdev->dev, GFP_KERNEL, DDR_PERF_DEV_NAME "%d", - num); + pmu->devtype_data = of_device_get_match_data(&pdev->dev); + if (pmu->devtype_data->type & DDR_PERF_TYPE) { + pmu->pmu.attr_groups = ddr_attr_groups; + pmu->id = ida_simple_get(&ddr_ida, 0, 0, GFP_KERNEL); + name = devm_kasprintf(&pdev->dev, GFP_KERNEL, DDR_PERF_DEV_NAME "%d", pmu->id); + } else if (pmu->devtype_data->type & DB_PERF_TYPE) { + pmu->pmu.attr_groups = db_attr_groups; + pmu->id = ida_simple_get(&db_ida, 0, 0, GFP_KERNEL); + name = devm_kasprintf(&pdev->dev, GFP_KERNEL, DB_PERF_DEV_NAME "%d", pmu->id); + } else + return -EINVAL; if (!name) return -ENOMEM; - pmu->devtype_data = of_device_get_match_data(&pdev->dev); - pmu->cpu = raw_smp_processor_id(); ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, DDR_CPUHP_CB_NAME, @@ -775,7 +810,11 @@ ddr_perf_err: if (pmu->cpuhp_state) cpuhp_state_remove_instance_nocalls(pmu->cpuhp_state, &pmu->node); - ida_simple_remove(&ddr_ida, pmu->id); + if (pmu->devtype_data->type & DDR_PERF_TYPE) + ida_simple_remove(&ddr_ida, pmu->id); + else + ida_simple_remove(&db_ida, pmu->id); + dev_warn(&pdev->dev, "i.MX8 DDR Perf PMU failed (%d), disabled\n", ret); return ret; } @@ -789,7 +828,11 @@ static int ddr_perf_remove(struct platform_device *pdev) perf_pmu_unregister(&pmu->pmu); - ida_simple_remove(&ddr_ida, pmu->id); + if (pmu->devtype_data->type & DDR_PERF_TYPE) + ida_simple_remove(&ddr_ida, pmu->id); + else + ida_simple_remove(&db_ida, pmu->id); + return 0; } |