Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * HiSilicon SoC DDRC uncore Hardware event counters support
0004  *
0005  * Copyright (C) 2017 HiSilicon Limited
0006  * Author: Shaokun Zhang <zhangshaokun@hisilicon.com>
0007  *         Anurup M <anurup.m@huawei.com>
0008  *
0009  * This code is based on the uncore PMUs like arm-cci and arm-ccn.
0010  */
0011 #include <linux/acpi.h>
0012 #include <linux/bug.h>
0013 #include <linux/cpuhotplug.h>
0014 #include <linux/interrupt.h>
0015 #include <linux/irq.h>
0016 #include <linux/list.h>
0017 #include <linux/smp.h>
0018 
0019 #include "hisi_uncore_pmu.h"
0020 
0021 /* DDRC register definition in v1 */
0022 #define DDRC_PERF_CTRL      0x010
0023 #define DDRC_FLUX_WR        0x380
0024 #define DDRC_FLUX_RD        0x384
0025 #define DDRC_FLUX_WCMD          0x388
0026 #define DDRC_FLUX_RCMD          0x38c
0027 #define DDRC_PRE_CMD            0x3c0
0028 #define DDRC_ACT_CMD            0x3c4
0029 #define DDRC_RNK_CHG            0x3cc
0030 #define DDRC_RW_CHG             0x3d0
0031 #define DDRC_EVENT_CTRL         0x6C0
0032 #define DDRC_INT_MASK       0x6c8
0033 #define DDRC_INT_STATUS     0x6cc
0034 #define DDRC_INT_CLEAR      0x6d0
0035 #define DDRC_VERSION        0x710
0036 
0037 /* DDRC register definition in v2 */
0038 #define DDRC_V2_INT_MASK    0x528
0039 #define DDRC_V2_INT_STATUS  0x52c
0040 #define DDRC_V2_INT_CLEAR   0x530
0041 #define DDRC_V2_EVENT_CNT   0xe00
0042 #define DDRC_V2_EVENT_CTRL  0xe70
0043 #define DDRC_V2_EVENT_TYPE  0xe74
0044 #define DDRC_V2_PERF_CTRL   0xeA0
0045 
0046 /* DDRC has 8-counters */
0047 #define DDRC_NR_COUNTERS    0x8
0048 #define DDRC_V1_PERF_CTRL_EN    0x2
0049 #define DDRC_V2_PERF_CTRL_EN    0x1
0050 #define DDRC_V1_NR_EVENTS   0x7
0051 #define DDRC_V2_NR_EVENTS   0x90
0052 
0053 /*
0054  * For PMU v1, there are eight-events and every event has been mapped
0055  * to fixed-purpose counters which register offset is not consistent.
0056  * Therefore there is no write event type and we assume that event
0057  * code (0 to 7) is equal to counter index in PMU driver.
0058  */
0059 #define GET_DDRC_EVENTID(hwc)   (hwc->config_base & 0x7)
0060 
0061 static const u32 ddrc_reg_off[] = {
0062     DDRC_FLUX_WR, DDRC_FLUX_RD, DDRC_FLUX_WCMD, DDRC_FLUX_RCMD,
0063     DDRC_PRE_CMD, DDRC_ACT_CMD, DDRC_RNK_CHG, DDRC_RW_CHG
0064 };
0065 
0066 /*
0067  * Select the counter register offset using the counter index.
0068  * In PMU v1, there are no programmable counter, the count
0069  * is read form the statistics counter register itself.
0070  */
0071 static u32 hisi_ddrc_pmu_v1_get_counter_offset(int cntr_idx)
0072 {
0073     return ddrc_reg_off[cntr_idx];
0074 }
0075 
0076 static u32 hisi_ddrc_pmu_v2_get_counter_offset(int cntr_idx)
0077 {
0078     return DDRC_V2_EVENT_CNT + cntr_idx * 8;
0079 }
0080 
0081 static u64 hisi_ddrc_pmu_v1_read_counter(struct hisi_pmu *ddrc_pmu,
0082                       struct hw_perf_event *hwc)
0083 {
0084     return readl(ddrc_pmu->base +
0085              hisi_ddrc_pmu_v1_get_counter_offset(hwc->idx));
0086 }
0087 
0088 static void hisi_ddrc_pmu_v1_write_counter(struct hisi_pmu *ddrc_pmu,
0089                     struct hw_perf_event *hwc, u64 val)
0090 {
0091     writel((u32)val,
0092            ddrc_pmu->base + hisi_ddrc_pmu_v1_get_counter_offset(hwc->idx));
0093 }
0094 
0095 static u64 hisi_ddrc_pmu_v2_read_counter(struct hisi_pmu *ddrc_pmu,
0096                      struct hw_perf_event *hwc)
0097 {
0098     return readq(ddrc_pmu->base +
0099              hisi_ddrc_pmu_v2_get_counter_offset(hwc->idx));
0100 }
0101 
0102 static void hisi_ddrc_pmu_v2_write_counter(struct hisi_pmu *ddrc_pmu,
0103                        struct hw_perf_event *hwc, u64 val)
0104 {
0105     writeq(val,
0106            ddrc_pmu->base + hisi_ddrc_pmu_v2_get_counter_offset(hwc->idx));
0107 }
0108 
0109 /*
0110  * For DDRC PMU v1, event has been mapped to fixed-purpose counter by hardware,
0111  * so there is no need to write event type, while it is programmable counter in
0112  * PMU v2.
0113  */
0114 static void hisi_ddrc_pmu_write_evtype(struct hisi_pmu *hha_pmu, int idx,
0115                        u32 type)
0116 {
0117     u32 offset;
0118 
0119     if (hha_pmu->identifier >= HISI_PMU_V2) {
0120         offset = DDRC_V2_EVENT_TYPE + 4 * idx;
0121         writel(type, hha_pmu->base + offset);
0122     }
0123 }
0124 
0125 static void hisi_ddrc_pmu_v1_start_counters(struct hisi_pmu *ddrc_pmu)
0126 {
0127     u32 val;
0128 
0129     /* Set perf_enable in DDRC_PERF_CTRL to start event counting */
0130     val = readl(ddrc_pmu->base + DDRC_PERF_CTRL);
0131     val |= DDRC_V1_PERF_CTRL_EN;
0132     writel(val, ddrc_pmu->base + DDRC_PERF_CTRL);
0133 }
0134 
0135 static void hisi_ddrc_pmu_v1_stop_counters(struct hisi_pmu *ddrc_pmu)
0136 {
0137     u32 val;
0138 
0139     /* Clear perf_enable in DDRC_PERF_CTRL to stop event counting */
0140     val = readl(ddrc_pmu->base + DDRC_PERF_CTRL);
0141     val &= ~DDRC_V1_PERF_CTRL_EN;
0142     writel(val, ddrc_pmu->base + DDRC_PERF_CTRL);
0143 }
0144 
0145 static void hisi_ddrc_pmu_v1_enable_counter(struct hisi_pmu *ddrc_pmu,
0146                         struct hw_perf_event *hwc)
0147 {
0148     u32 val;
0149 
0150     /* Set counter index(event code) in DDRC_EVENT_CTRL register */
0151     val = readl(ddrc_pmu->base + DDRC_EVENT_CTRL);
0152     val |= (1 << GET_DDRC_EVENTID(hwc));
0153     writel(val, ddrc_pmu->base + DDRC_EVENT_CTRL);
0154 }
0155 
0156 static void hisi_ddrc_pmu_v1_disable_counter(struct hisi_pmu *ddrc_pmu,
0157                          struct hw_perf_event *hwc)
0158 {
0159     u32 val;
0160 
0161     /* Clear counter index(event code) in DDRC_EVENT_CTRL register */
0162     val = readl(ddrc_pmu->base + DDRC_EVENT_CTRL);
0163     val &= ~(1 << GET_DDRC_EVENTID(hwc));
0164     writel(val, ddrc_pmu->base + DDRC_EVENT_CTRL);
0165 }
0166 
0167 static int hisi_ddrc_pmu_v1_get_event_idx(struct perf_event *event)
0168 {
0169     struct hisi_pmu *ddrc_pmu = to_hisi_pmu(event->pmu);
0170     unsigned long *used_mask = ddrc_pmu->pmu_events.used_mask;
0171     struct hw_perf_event *hwc = &event->hw;
0172     /* For DDRC PMU, we use event code as counter index */
0173     int idx = GET_DDRC_EVENTID(hwc);
0174 
0175     if (test_bit(idx, used_mask))
0176         return -EAGAIN;
0177 
0178     set_bit(idx, used_mask);
0179 
0180     return idx;
0181 }
0182 
0183 static int hisi_ddrc_pmu_v2_get_event_idx(struct perf_event *event)
0184 {
0185     return hisi_uncore_pmu_get_event_idx(event);
0186 }
0187 
0188 static void hisi_ddrc_pmu_v2_start_counters(struct hisi_pmu *ddrc_pmu)
0189 {
0190     u32 val;
0191 
0192     val = readl(ddrc_pmu->base + DDRC_V2_PERF_CTRL);
0193     val |= DDRC_V2_PERF_CTRL_EN;
0194     writel(val, ddrc_pmu->base + DDRC_V2_PERF_CTRL);
0195 }
0196 
0197 static void hisi_ddrc_pmu_v2_stop_counters(struct hisi_pmu *ddrc_pmu)
0198 {
0199     u32 val;
0200 
0201     val = readl(ddrc_pmu->base + DDRC_V2_PERF_CTRL);
0202     val &= ~DDRC_V2_PERF_CTRL_EN;
0203     writel(val, ddrc_pmu->base + DDRC_V2_PERF_CTRL);
0204 }
0205 
0206 static void hisi_ddrc_pmu_v2_enable_counter(struct hisi_pmu *ddrc_pmu,
0207                         struct hw_perf_event *hwc)
0208 {
0209     u32 val;
0210 
0211     val = readl(ddrc_pmu->base + DDRC_V2_EVENT_CTRL);
0212     val |= 1 << hwc->idx;
0213     writel(val, ddrc_pmu->base + DDRC_V2_EVENT_CTRL);
0214 }
0215 
0216 static void hisi_ddrc_pmu_v2_disable_counter(struct hisi_pmu *ddrc_pmu,
0217                          struct hw_perf_event *hwc)
0218 {
0219     u32 val;
0220 
0221     val = readl(ddrc_pmu->base + DDRC_V2_EVENT_CTRL);
0222     val &= ~(1 << hwc->idx);
0223     writel(val, ddrc_pmu->base + DDRC_V2_EVENT_CTRL);
0224 }
0225 
0226 static void hisi_ddrc_pmu_v1_enable_counter_int(struct hisi_pmu *ddrc_pmu,
0227                         struct hw_perf_event *hwc)
0228 {
0229     u32 val;
0230 
0231     /* Write 0 to enable interrupt */
0232     val = readl(ddrc_pmu->base + DDRC_INT_MASK);
0233     val &= ~(1 << hwc->idx);
0234     writel(val, ddrc_pmu->base + DDRC_INT_MASK);
0235 }
0236 
0237 static void hisi_ddrc_pmu_v1_disable_counter_int(struct hisi_pmu *ddrc_pmu,
0238                          struct hw_perf_event *hwc)
0239 {
0240     u32 val;
0241 
0242     /* Write 1 to mask interrupt */
0243     val = readl(ddrc_pmu->base + DDRC_INT_MASK);
0244     val |= 1 << hwc->idx;
0245     writel(val, ddrc_pmu->base + DDRC_INT_MASK);
0246 }
0247 
0248 static void hisi_ddrc_pmu_v2_enable_counter_int(struct hisi_pmu *ddrc_pmu,
0249                         struct hw_perf_event *hwc)
0250 {
0251     u32 val;
0252 
0253     val = readl(ddrc_pmu->base + DDRC_V2_INT_MASK);
0254     val &= ~(1 << hwc->idx);
0255     writel(val, ddrc_pmu->base + DDRC_V2_INT_MASK);
0256 }
0257 
0258 static void hisi_ddrc_pmu_v2_disable_counter_int(struct hisi_pmu *ddrc_pmu,
0259                         struct hw_perf_event *hwc)
0260 {
0261     u32 val;
0262 
0263     val = readl(ddrc_pmu->base + DDRC_V2_INT_MASK);
0264     val |= 1 << hwc->idx;
0265     writel(val, ddrc_pmu->base + DDRC_V2_INT_MASK);
0266 }
0267 
0268 static u32 hisi_ddrc_pmu_v1_get_int_status(struct hisi_pmu *ddrc_pmu)
0269 {
0270     return readl(ddrc_pmu->base + DDRC_INT_STATUS);
0271 }
0272 
0273 static void hisi_ddrc_pmu_v1_clear_int_status(struct hisi_pmu *ddrc_pmu,
0274                           int idx)
0275 {
0276     writel(1 << idx, ddrc_pmu->base + DDRC_INT_CLEAR);
0277 }
0278 
0279 static u32 hisi_ddrc_pmu_v2_get_int_status(struct hisi_pmu *ddrc_pmu)
0280 {
0281     return readl(ddrc_pmu->base + DDRC_V2_INT_STATUS);
0282 }
0283 
0284 static void hisi_ddrc_pmu_v2_clear_int_status(struct hisi_pmu *ddrc_pmu,
0285                           int idx)
0286 {
0287     writel(1 << idx, ddrc_pmu->base + DDRC_V2_INT_CLEAR);
0288 }
0289 
0290 static const struct acpi_device_id hisi_ddrc_pmu_acpi_match[] = {
0291     { "HISI0233", },
0292     { "HISI0234", },
0293     {}
0294 };
0295 MODULE_DEVICE_TABLE(acpi, hisi_ddrc_pmu_acpi_match);
0296 
0297 static int hisi_ddrc_pmu_init_data(struct platform_device *pdev,
0298                    struct hisi_pmu *ddrc_pmu)
0299 {
0300     /*
0301      * Use the SCCL_ID and DDRC channel ID to identify the
0302      * DDRC PMU, while SCCL_ID is in MPIDR[aff2].
0303      */
0304     if (device_property_read_u32(&pdev->dev, "hisilicon,ch-id",
0305                      &ddrc_pmu->index_id)) {
0306         dev_err(&pdev->dev, "Can not read ddrc channel-id!\n");
0307         return -EINVAL;
0308     }
0309 
0310     if (device_property_read_u32(&pdev->dev, "hisilicon,scl-id",
0311                      &ddrc_pmu->sccl_id)) {
0312         dev_err(&pdev->dev, "Can not read ddrc sccl-id!\n");
0313         return -EINVAL;
0314     }
0315     /* DDRC PMUs only share the same SCCL */
0316     ddrc_pmu->ccl_id = -1;
0317 
0318     ddrc_pmu->base = devm_platform_ioremap_resource(pdev, 0);
0319     if (IS_ERR(ddrc_pmu->base)) {
0320         dev_err(&pdev->dev, "ioremap failed for ddrc_pmu resource\n");
0321         return PTR_ERR(ddrc_pmu->base);
0322     }
0323 
0324     ddrc_pmu->identifier = readl(ddrc_pmu->base + DDRC_VERSION);
0325     if (ddrc_pmu->identifier >= HISI_PMU_V2) {
0326         if (device_property_read_u32(&pdev->dev, "hisilicon,sub-id",
0327                          &ddrc_pmu->sub_id)) {
0328             dev_err(&pdev->dev, "Can not read sub-id!\n");
0329             return -EINVAL;
0330         }
0331     }
0332 
0333     return 0;
0334 }
0335 
0336 static struct attribute *hisi_ddrc_pmu_v1_format_attr[] = {
0337     HISI_PMU_FORMAT_ATTR(event, "config:0-4"),
0338     NULL,
0339 };
0340 
0341 static const struct attribute_group hisi_ddrc_pmu_v1_format_group = {
0342     .name = "format",
0343     .attrs = hisi_ddrc_pmu_v1_format_attr,
0344 };
0345 
0346 static struct attribute *hisi_ddrc_pmu_v2_format_attr[] = {
0347     HISI_PMU_FORMAT_ATTR(event, "config:0-7"),
0348     NULL
0349 };
0350 
0351 static const struct attribute_group hisi_ddrc_pmu_v2_format_group = {
0352     .name = "format",
0353     .attrs = hisi_ddrc_pmu_v2_format_attr,
0354 };
0355 
0356 static struct attribute *hisi_ddrc_pmu_v1_events_attr[] = {
0357     HISI_PMU_EVENT_ATTR(flux_wr,        0x00),
0358     HISI_PMU_EVENT_ATTR(flux_rd,        0x01),
0359     HISI_PMU_EVENT_ATTR(flux_wcmd,      0x02),
0360     HISI_PMU_EVENT_ATTR(flux_rcmd,      0x03),
0361     HISI_PMU_EVENT_ATTR(pre_cmd,        0x04),
0362     HISI_PMU_EVENT_ATTR(act_cmd,        0x05),
0363     HISI_PMU_EVENT_ATTR(rnk_chg,        0x06),
0364     HISI_PMU_EVENT_ATTR(rw_chg,     0x07),
0365     NULL,
0366 };
0367 
0368 static const struct attribute_group hisi_ddrc_pmu_v1_events_group = {
0369     .name = "events",
0370     .attrs = hisi_ddrc_pmu_v1_events_attr,
0371 };
0372 
0373 static struct attribute *hisi_ddrc_pmu_v2_events_attr[] = {
0374     HISI_PMU_EVENT_ATTR(cycles,     0x00),
0375     HISI_PMU_EVENT_ATTR(flux_wr,        0x83),
0376     HISI_PMU_EVENT_ATTR(flux_rd,        0x84),
0377     NULL
0378 };
0379 
0380 static const struct attribute_group hisi_ddrc_pmu_v2_events_group = {
0381     .name = "events",
0382     .attrs = hisi_ddrc_pmu_v2_events_attr,
0383 };
0384 
0385 static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
0386 
0387 static struct attribute *hisi_ddrc_pmu_cpumask_attrs[] = {
0388     &dev_attr_cpumask.attr,
0389     NULL,
0390 };
0391 
0392 static const struct attribute_group hisi_ddrc_pmu_cpumask_attr_group = {
0393     .attrs = hisi_ddrc_pmu_cpumask_attrs,
0394 };
0395 
0396 static struct device_attribute hisi_ddrc_pmu_identifier_attr =
0397     __ATTR(identifier, 0444, hisi_uncore_pmu_identifier_attr_show, NULL);
0398 
0399 static struct attribute *hisi_ddrc_pmu_identifier_attrs[] = {
0400     &hisi_ddrc_pmu_identifier_attr.attr,
0401     NULL
0402 };
0403 
0404 static const struct attribute_group hisi_ddrc_pmu_identifier_group = {
0405     .attrs = hisi_ddrc_pmu_identifier_attrs,
0406 };
0407 
0408 static const struct attribute_group *hisi_ddrc_pmu_v1_attr_groups[] = {
0409     &hisi_ddrc_pmu_v1_format_group,
0410     &hisi_ddrc_pmu_v1_events_group,
0411     &hisi_ddrc_pmu_cpumask_attr_group,
0412     &hisi_ddrc_pmu_identifier_group,
0413     NULL,
0414 };
0415 
0416 static const struct attribute_group *hisi_ddrc_pmu_v2_attr_groups[] = {
0417     &hisi_ddrc_pmu_v2_format_group,
0418     &hisi_ddrc_pmu_v2_events_group,
0419     &hisi_ddrc_pmu_cpumask_attr_group,
0420     &hisi_ddrc_pmu_identifier_group,
0421     NULL
0422 };
0423 
0424 static const struct hisi_uncore_ops hisi_uncore_ddrc_v1_ops = {
0425     .write_evtype           = hisi_ddrc_pmu_write_evtype,
0426     .get_event_idx      = hisi_ddrc_pmu_v1_get_event_idx,
0427     .start_counters     = hisi_ddrc_pmu_v1_start_counters,
0428     .stop_counters      = hisi_ddrc_pmu_v1_stop_counters,
0429     .enable_counter     = hisi_ddrc_pmu_v1_enable_counter,
0430     .disable_counter    = hisi_ddrc_pmu_v1_disable_counter,
0431     .enable_counter_int = hisi_ddrc_pmu_v1_enable_counter_int,
0432     .disable_counter_int    = hisi_ddrc_pmu_v1_disable_counter_int,
0433     .write_counter      = hisi_ddrc_pmu_v1_write_counter,
0434     .read_counter       = hisi_ddrc_pmu_v1_read_counter,
0435     .get_int_status     = hisi_ddrc_pmu_v1_get_int_status,
0436     .clear_int_status   = hisi_ddrc_pmu_v1_clear_int_status,
0437 };
0438 
0439 static const struct hisi_uncore_ops hisi_uncore_ddrc_v2_ops = {
0440     .write_evtype           = hisi_ddrc_pmu_write_evtype,
0441     .get_event_idx      = hisi_ddrc_pmu_v2_get_event_idx,
0442     .start_counters     = hisi_ddrc_pmu_v2_start_counters,
0443     .stop_counters      = hisi_ddrc_pmu_v2_stop_counters,
0444     .enable_counter     = hisi_ddrc_pmu_v2_enable_counter,
0445     .disable_counter    = hisi_ddrc_pmu_v2_disable_counter,
0446     .enable_counter_int = hisi_ddrc_pmu_v2_enable_counter_int,
0447     .disable_counter_int    = hisi_ddrc_pmu_v2_disable_counter_int,
0448     .write_counter      = hisi_ddrc_pmu_v2_write_counter,
0449     .read_counter       = hisi_ddrc_pmu_v2_read_counter,
0450     .get_int_status     = hisi_ddrc_pmu_v2_get_int_status,
0451     .clear_int_status   = hisi_ddrc_pmu_v2_clear_int_status,
0452 };
0453 
0454 static int hisi_ddrc_pmu_dev_probe(struct platform_device *pdev,
0455                    struct hisi_pmu *ddrc_pmu)
0456 {
0457     int ret;
0458 
0459     ret = hisi_ddrc_pmu_init_data(pdev, ddrc_pmu);
0460     if (ret)
0461         return ret;
0462 
0463     ret = hisi_uncore_pmu_init_irq(ddrc_pmu, pdev);
0464     if (ret)
0465         return ret;
0466 
0467     if (ddrc_pmu->identifier >= HISI_PMU_V2) {
0468         ddrc_pmu->counter_bits = 48;
0469         ddrc_pmu->check_event = DDRC_V2_NR_EVENTS;
0470         ddrc_pmu->pmu_events.attr_groups = hisi_ddrc_pmu_v2_attr_groups;
0471         ddrc_pmu->ops = &hisi_uncore_ddrc_v2_ops;
0472     } else {
0473         ddrc_pmu->counter_bits = 32;
0474         ddrc_pmu->check_event = DDRC_V1_NR_EVENTS;
0475         ddrc_pmu->pmu_events.attr_groups = hisi_ddrc_pmu_v1_attr_groups;
0476         ddrc_pmu->ops = &hisi_uncore_ddrc_v1_ops;
0477     }
0478 
0479     ddrc_pmu->num_counters = DDRC_NR_COUNTERS;
0480     ddrc_pmu->dev = &pdev->dev;
0481     ddrc_pmu->on_cpu = -1;
0482 
0483     return 0;
0484 }
0485 
0486 static int hisi_ddrc_pmu_probe(struct platform_device *pdev)
0487 {
0488     struct hisi_pmu *ddrc_pmu;
0489     char *name;
0490     int ret;
0491 
0492     ddrc_pmu = devm_kzalloc(&pdev->dev, sizeof(*ddrc_pmu), GFP_KERNEL);
0493     if (!ddrc_pmu)
0494         return -ENOMEM;
0495 
0496     platform_set_drvdata(pdev, ddrc_pmu);
0497 
0498     ret = hisi_ddrc_pmu_dev_probe(pdev, ddrc_pmu);
0499     if (ret)
0500         return ret;
0501 
0502     ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE,
0503                        &ddrc_pmu->node);
0504     if (ret) {
0505         dev_err(&pdev->dev, "Error %d registering hotplug;\n", ret);
0506         return ret;
0507     }
0508 
0509     if (ddrc_pmu->identifier >= HISI_PMU_V2)
0510         name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
0511                       "hisi_sccl%u_ddrc%u_%u",
0512                       ddrc_pmu->sccl_id, ddrc_pmu->index_id,
0513                       ddrc_pmu->sub_id);
0514     else
0515         name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
0516                       "hisi_sccl%u_ddrc%u", ddrc_pmu->sccl_id,
0517                       ddrc_pmu->index_id);
0518 
0519     hisi_pmu_init(&ddrc_pmu->pmu, name, ddrc_pmu->pmu_events.attr_groups, THIS_MODULE);
0520 
0521     ret = perf_pmu_register(&ddrc_pmu->pmu, name, -1);
0522     if (ret) {
0523         dev_err(ddrc_pmu->dev, "DDRC PMU register failed!\n");
0524         cpuhp_state_remove_instance_nocalls(
0525             CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE, &ddrc_pmu->node);
0526     }
0527 
0528     return ret;
0529 }
0530 
0531 static int hisi_ddrc_pmu_remove(struct platform_device *pdev)
0532 {
0533     struct hisi_pmu *ddrc_pmu = platform_get_drvdata(pdev);
0534 
0535     perf_pmu_unregister(&ddrc_pmu->pmu);
0536     cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE,
0537                         &ddrc_pmu->node);
0538     return 0;
0539 }
0540 
0541 static struct platform_driver hisi_ddrc_pmu_driver = {
0542     .driver = {
0543         .name = "hisi_ddrc_pmu",
0544         .acpi_match_table = ACPI_PTR(hisi_ddrc_pmu_acpi_match),
0545         .suppress_bind_attrs = true,
0546     },
0547     .probe = hisi_ddrc_pmu_probe,
0548     .remove = hisi_ddrc_pmu_remove,
0549 };
0550 
0551 static int __init hisi_ddrc_pmu_module_init(void)
0552 {
0553     int ret;
0554 
0555     ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE,
0556                       "AP_PERF_ARM_HISI_DDRC_ONLINE",
0557                       hisi_uncore_pmu_online_cpu,
0558                       hisi_uncore_pmu_offline_cpu);
0559     if (ret) {
0560         pr_err("DDRC PMU: setup hotplug, ret = %d\n", ret);
0561         return ret;
0562     }
0563 
0564     ret = platform_driver_register(&hisi_ddrc_pmu_driver);
0565     if (ret)
0566         cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE);
0567 
0568     return ret;
0569 }
0570 module_init(hisi_ddrc_pmu_module_init);
0571 
0572 static void __exit hisi_ddrc_pmu_module_exit(void)
0573 {
0574     platform_driver_unregister(&hisi_ddrc_pmu_driver);
0575     cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE);
0576 
0577 }
0578 module_exit(hisi_ddrc_pmu_module_exit);
0579 
0580 MODULE_DESCRIPTION("HiSilicon SoC DDRC uncore PMU driver");
0581 MODULE_LICENSE("GPL v2");
0582 MODULE_AUTHOR("Shaokun Zhang <zhangshaokun@hisilicon.com>");
0583 MODULE_AUTHOR("Anurup M <anurup.m@huawei.com>");