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 | #define to_ddr_pmu(p) container_of(p, struct ddr_pmu, pmu) | 53 | #define to_ddr_pmu(p) container_of(p, struct ddr_pmu, pmu) |
| 54 | 54 | ||
| 55 | #define DDR_PERF_DEV_NAME "imx8_ddr" | 55 | #define DDR_PERF_DEV_NAME "imx8_ddr" |
| 56 | #define DB_PERF_DEV_NAME "imx8_db" | ||
| 56 | #define DDR_CPUHP_CB_NAME DDR_PERF_DEV_NAME "_perf_pmu" | 57 | #define DDR_CPUHP_CB_NAME DDR_PERF_DEV_NAME "_perf_pmu" |
| 57 | 58 | ||
| 58 | static DEFINE_IDA(ddr_ida); | 59 | static DEFINE_IDA(ddr_ida); |
| 60 | static DEFINE_IDA(db_ida); | ||
| 59 | 61 | ||
| 60 | /* DDR Perf hardware feature */ | 62 | /* DDR Perf hardware feature */ |
| 61 | #define DDR_CAP_AXI_ID_FILTER 0x1 /* support AXI ID filter */ | 63 | #define DDR_CAP_AXI_ID_FILTER 0x1 /* support AXI ID filter */ |
| 62 | #define DDR_CAP_AXI_ID_FILTER_ENHANCED 0x3 /* support enhanced AXI ID filter */ | 64 | #define DDR_CAP_AXI_ID_FILTER_ENHANCED 0x3 /* support enhanced AXI ID filter */ |
| 63 | #define DDR_CAP_AXI_ID_PORT_CHANNEL_FILTER 0x4 /* support AXI ID PORT CHANNEL filter */ | 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 | struct fsl_ddr_devtype_data { | 73 | struct fsl_ddr_devtype_data { |
| 66 | unsigned int quirks; /* quirks needed for different DDR Perf core */ | 74 | unsigned int quirks; /* quirks needed for different DDR Perf core */ |
| 67 | const char *identifier; /* system PMU identifier for userspace */ | 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 | static const struct fsl_ddr_devtype_data imx8_devtype_data; | 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 | .identifier = "i.MX8DXL", | 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 | static const struct of_device_id imx_ddr_pmu_dt_ids[] = { | 116 | static const struct of_device_id imx_ddr_pmu_dt_ids[] = { |
| 102 | { .compatible = "fsl,imx8-ddr-pmu", .data = &imx8_devtype_data}, | 117 | { .compatible = "fsl,imx8-ddr-pmu", .data = &imx8_devtype_data}, |
| 103 | { .compatible = "fsl,imx8m-ddr-pmu", .data = &imx8m_devtype_data}, | 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 | { .compatible = "fsl,imx8mn-ddr-pmu", .data = &imx8mn_devtype_data}, | 121 | { .compatible = "fsl,imx8mn-ddr-pmu", .data = &imx8mn_devtype_data}, |
| 107 | { .compatible = "fsl,imx8mp-ddr-pmu", .data = &imx8mp_devtype_data}, | 122 | { .compatible = "fsl,imx8mp-ddr-pmu", .data = &imx8mp_devtype_data}, |
| 108 | { .compatible = "fsl,imx8dxl-ddr-pmu", .data = &imx8dxl_devtype_data}, | 123 | { .compatible = "fsl,imx8dxl-ddr-pmu", .data = &imx8dxl_devtype_data}, |
| 124 | { .compatible = "fsl,imx8dxl-db-pmu", .data = &imx8dxl_db_devtype_data}, | ||
| 109 | { /* sentinel */ } | 125 | { /* sentinel */ } |
| 110 | }; | 126 | }; |
| 111 | MODULE_DEVICE_TABLE(of, imx_ddr_pmu_dt_ids); | 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 | NULL, | 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 | static const struct attribute_group ddr_perf_events_attr_group = { | 331 | static const struct attribute_group ddr_perf_events_attr_group = { |
| 289 | .name = "events", | 332 | .name = "events", |
| 290 | .attrs = ddr_perf_events_attrs, | 333 | .attrs = ddr_perf_events_attrs, |
| 334 | .is_visible = ddr_perf_events_attrs_is_visible, | ||
| 291 | }; | 335 | }; |
| 292 | 336 | ||
| 293 | PMU_FORMAT_ATTR(event, "config:0-7"); | 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 | struct ddr_pmu *pmu; | 781 | struct ddr_pmu *pmu; |
| 738 | struct device_node *np; | 782 | struct device_node *np; |
| 739 | void __iomem *base; | 783 | void __iomem *base; |
| 784 | struct ida *ida; | ||
| 740 | char *name; | 785 | char *name; |
| 741 | int nclks; | 786 | int nclks; |
| 742 | int num; | 787 | int num; |
| @@ -761,21 +806,25 @@ static int ddr_perf_probe(struct platform_device *pdev) · 18 unmodified lines | |||
| 761 | if (nclks < 0) | 806 | if (nclks < 0) |
| 762 | return dev_err_probe(&pdev->dev, nclks, "Failure get clks\n"); | 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 | if (num < 0) | 813 | if (num < 0) |
| 766 | return num; | 814 | return num; |
| 767 | 815 | ||
| 768 | pmu->id = num; | 816 | pmu->id = num; |
| 769 | 817 | ||
| 770 | name = devm_kasprintf(&pdev->dev, GFP_KERNEL, DDR_PERF_DEV_NAME "%d", | 818 | if (pmu->devtype_data->type == DDR_PERF_TYPE) |
| 771 | num); | 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 | if (!name) { | 823 | if (!name) { |
| 773 | ret = -ENOMEM; | 824 | ret = -ENOMEM; |
| 774 | goto idr_free; | 825 | goto idr_free; |
| 775 | } | 826 | } |
| 776 | 827 | ||
| 777 | pmu->devtype_data = of_device_get_match_data(&pdev->dev); | ||
| 778 | |||
| 779 | pmu->cpu = raw_smp_processor_id(); | 828 | pmu->cpu = raw_smp_processor_id(); |
| 780 | ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, | 829 | ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, |
| 781 | DDR_CPUHP_CB_NAME, | 830 | DDR_CPUHP_CB_NAME, |
| @@ -832,7 +881,7 @@ ddr_perf_err: · 50 unmodified lines | |||
| 832 | cpuhp_instance_err: | 881 | cpuhp_instance_err: |
| 833 | cpuhp_remove_multi_state(pmu->cpuhp_state); | 882 | cpuhp_remove_multi_state(pmu->cpuhp_state); |
| 834 | idr_free: | 883 | idr_free: |
| 835 | ida_free(&ddr_ida, pmu->id); | 884 | ida_free(ida, pmu->id); |
| 836 | dev_warn(&pdev->dev, "i.MX8 DDR Perf PMU failed (%d), disabled\n", ret); | 885 | dev_warn(&pdev->dev, "i.MX8 DDR Perf PMU failed (%d), disabled\n", ret); |
| 837 | return ret; | 886 | return ret; |
| 838 | } | 887 | } |
| @@ -846,7 +895,11 @@ static void ddr_perf_remove(struct platform_device *pdev) · 7 unmodified lines | |||
| 846 | 895 | ||
| 847 | perf_pmu_unregister(&pmu->pmu); | 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 | static struct platform_driver imx_ddr_pmu_driver = { | 905 | static struct platform_driver imx_ddr_pmu_driver = { |