There is a PMU in DB, which has the same function with PMU in DDR subsystem, the difference is PMU in DB only supports cycles, axid-read, axid-write events. 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
Unified · Split
| @@ -53,18 +53,27 @@ · 52 unmodified lines | ||
| 53 | 53 | #define to_ddr_pmu(p) container_of(p, struct ddr_pmu, pmu) |
| 54 | 54 | |
| 55 | 55 | #define DDR_PERF_DEV_NAME "imx8_ddr" |
| 56 | +#define DB_PERF_DEV_NAME "imx8_db" | |
| 56 | 57 | #define DDR_CPUHP_CB_NAME DDR_PERF_DEV_NAME "_perf_pmu" |
| 57 | 58 | |
| 58 | 59 | static DEFINE_IDA(ddr_ida); |
| 60 | +static DEFINE_IDA(db_ida); | |
| 59 | 61 | |
| 60 | 62 | /* DDR Perf hardware feature */ |
| 61 | 63 | #define DDR_CAP_AXI_ID_FILTER 0x1 /* support AXI ID filter */ |
| 62 | 64 | #define DDR_CAP_AXI_ID_FILTER_ENHANCED 0x3 /* support enhanced AXI ID filter */ |
| 63 | 65 | #define DDR_CAP_AXI_ID_PORT_CHANNEL_FILTER 0x4 /* support AXI ID PORT CHANNEL filter */ |
| 64 | 66 | |
| 67 | +/* Perf type */ | |
| 68 | +enum fsl_ddr_type { | |
| 69 | + DDR_PERF_TYPE = 0, /* ddr Perf (default) */ | |
| 70 | + DB_PERF_TYPE, /* db Perf */ | |
| 71 | +}; | |
| 72 | + | |
| 65 | 73 | struct fsl_ddr_devtype_data { |
| 66 | 74 | unsigned int quirks; /* quirks needed for different DDR Perf core */ |
| 67 | 75 | const char *identifier; /* system PMU identifier for userspace */ |
| 76 | + enum fsl_ddr_type type; /* types of Perf, ddr or db */ | |
| 68 | 77 | }; |
| 69 | 78 | |
| 70 | 79 | static const struct fsl_ddr_devtype_data imx8_devtype_data; |
| @@ -98,6 +107,12 @@ static const struct fsl_ddr_devtype_data imx8dxl_devtype_data = { · 27 unmodified lines | ||
| 98 | 107 | .identifier = "i.MX8DXL", |
| 99 | 108 | }; |
| 100 | 109 | |
| 110 | +static const struct fsl_ddr_devtype_data imx8dxl_db_devtype_data = { | |
| 111 | + .quirks = DDR_CAP_AXI_ID_PORT_CHANNEL_FILTER, | |
| 112 | + .identifier = "i.MX8DXL", | |
| 113 | + .type = DB_PERF_TYPE, | |
| 114 | +}; | |
| 115 | + | |
| 101 | 116 | static const struct of_device_id imx_ddr_pmu_dt_ids[] = { |
| 102 | 117 | { .compatible = "fsl,imx8-ddr-pmu", .data = &imx8_devtype_data}, |
| 103 | 118 | { .compatible = "fsl,imx8m-ddr-pmu", .data = &imx8m_devtype_data}, |
| @@ -106,6 +121,7 @@ static const struct of_device_id imx_ddr_pmu_dt_ids[] = { · 2 unmodified lines | ||
| 106 | 121 | { .compatible = "fsl,imx8mn-ddr-pmu", .data = &imx8mn_devtype_data}, |
| 107 | 122 | { .compatible = "fsl,imx8mp-ddr-pmu", .data = &imx8mp_devtype_data}, |
| 108 | 123 | { .compatible = "fsl,imx8dxl-ddr-pmu", .data = &imx8dxl_devtype_data}, |
| 124 | + { .compatible = "fsl,imx8dxl-db-pmu", .data = &imx8dxl_db_devtype_data}, | |
| 109 | 125 | { /* sentinel */ } |
| 110 | 126 | }; |
| 111 | 127 | MODULE_DEVICE_TABLE(of, imx_ddr_pmu_dt_ids); |
| @@ -285,9 +301,37 @@ static struct attribute *ddr_perf_events_attrs[] = { · 173 unmodified lines | ||
| 285 | 301 | NULL, |
| 286 | 302 | }; |
| 287 | 303 | |
| 304 | +static const int ddr_perf_db_visible_event_list[] = { | |
| 305 | + EVENT_CYCLES_ID, | |
| 306 | + 0x41, | |
| 307 | + 0x42, | |
| 308 | +}; | |
| 309 | + | |
| 310 | +static umode_t ddr_perf_events_attrs_is_visible(struct kobject *kobj, | |
| 311 | + struct attribute *attr, int n) | |
| 312 | +{ | |
| 313 | + struct device *dev = kobj_to_dev(kobj); | |
| 314 | + struct ddr_pmu *pmu = dev_get_drvdata(dev); | |
| 315 | + struct perf_pmu_events_attr *pmu_attr; | |
| 316 | + unsigned int i; | |
| 317 | + | |
| 318 | + pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr.attr); | |
| 319 | + | |
| 320 | + if (pmu->devtype_data->type == DDR_PERF_TYPE) | |
| 321 | + return attr->mode; | |
| 322 | + | |
| 323 | + /* DB Type */ | |
| 324 | + for (i = 0; i < ARRAY_SIZE(ddr_perf_db_visible_event_list); i++) | |
| 325 | + if (pmu_attr->id == ddr_perf_db_visible_event_list[i]) | |
| 326 | + return attr->mode; | |
| 327 | + | |
| 328 | + return 0; | |
| 329 | +} | |
| 330 | + | |
| 288 | 331 | static const struct attribute_group ddr_perf_events_attr_group = { |
| 289 | 332 | .name = "events", |
| 290 | 333 | .attrs = ddr_perf_events_attrs, |
| 334 | + .is_visible = ddr_perf_events_attrs_is_visible, | |
| 291 | 335 | }; |
| 292 | 336 | |
| 293 | 337 | PMU_FORMAT_ATTR(event, "config:0-7"); |
| @@ -737,6 +781,7 @@ static int ddr_perf_probe(struct platform_device *pdev) · 443 unmodified lines | ||
| 737 | 781 | struct ddr_pmu *pmu; |
| 738 | 782 | struct device_node *np; |
| 739 | 783 | void __iomem *base; |
| 784 | + struct ida *ida; | |
| 740 | 785 | char *name; |
| 741 | 786 | int nclks; |
| 742 | 787 | int num; |
| @@ -761,21 +806,25 @@ static int ddr_perf_probe(struct platform_device *pdev) · 18 unmodified lines | ||
| 761 | 806 | if (nclks < 0) |
| 762 | 807 | return dev_err_probe(&pdev->dev, nclks, "Failure get clks\n"); |
| 763 | 808 | |
| 764 | − num = ida_alloc(&ddr_ida, GFP_KERNEL); | |
| 809 | + pmu->devtype_data = of_device_get_match_data(&pdev->dev); | |
| 810 | + | |
| 811 | + ida = pmu->devtype_data->type == DDR_PERF_TYPE ? &ddr_ida : &db_ida; | |
| 812 | + num = ida_alloc(ida, GFP_KERNEL); | |
| 765 | 813 | if (num < 0) |
| 766 | 814 | return num; |
| 767 | 815 | |
| 768 | 816 | pmu->id = num; |
| 769 | 817 | |
| 770 | − name = devm_kasprintf(&pdev->dev, GFP_KERNEL, DDR_PERF_DEV_NAME "%d", | |
| 771 | − num); | |
| 818 | + if (pmu->devtype_data->type == DDR_PERF_TYPE) | |
| 819 | + name = devm_kasprintf(&pdev->dev, GFP_KERNEL, DDR_PERF_DEV_NAME "%d", num); | |
| 820 | + else | |
| 821 | + name = devm_kasprintf(&pdev->dev, GFP_KERNEL, DB_PERF_DEV_NAME "%d", num); | |
| 822 | + | |
| 772 | 823 | if (!name) { |
| 773 | 824 | ret = -ENOMEM; |
| 774 | 825 | goto idr_free; |
| 775 | 826 | } |
| 776 | 827 | |
| 777 | − pmu->devtype_data = of_device_get_match_data(&pdev->dev); | |
| 778 | − | |
| 779 | 828 | pmu->cpu = raw_smp_processor_id(); |
| 780 | 829 | ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, |
| 781 | 830 | DDR_CPUHP_CB_NAME, |
| @@ -832,7 +881,7 @@ ddr_perf_err: · 50 unmodified lines | ||
| 832 | 881 | cpuhp_instance_err: |
| 833 | 882 | cpuhp_remove_multi_state(pmu->cpuhp_state); |
| 834 | 883 | idr_free: |
| 835 | − ida_free(&ddr_ida, pmu->id); | |
| 884 | + ida_free(ida, pmu->id); | |
| 836 | 885 | dev_warn(&pdev->dev, "i.MX8 DDR Perf PMU failed (%d), disabled\n", ret); |
| 837 | 886 | return ret; |
| 838 | 887 | } |
| @@ -846,7 +895,11 @@ static void ddr_perf_remove(struct platform_device *pdev) · 7 unmodified lines | ||
| 846 | 895 | |
| 847 | 896 | perf_pmu_unregister(&pmu->pmu); |
| 848 | 897 | |
| 849 | − ida_free(&ddr_ida, pmu->id); | |
| 898 | + if (pmu->devtype_data->type == DDR_PERF_TYPE) | |
| 899 | + ida_free(&ddr_ida, pmu->id); | |
| 900 | + else | |
| 901 | + ida_free(&db_ida, pmu->id); | |
| 902 | + | |
| 850 | 903 | } |
| 851 | 904 | |
| 852 | 905 | static struct platform_driver imx_ddr_pmu_driver = { |