622 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * HiSilicon SoC L3C uncore Hardware event counters support4 *5 * Copyright (C) 2017 HiSilicon Limited6 * Author: Anurup M <anurup.m@huawei.com>7 * Shaokun Zhang <zhangshaokun@hisilicon.com>8 *9 * This code is based on the uncore PMUs like arm-cci and arm-ccn.10 */11#include <linux/acpi.h>12#include <linux/bug.h>13#include <linux/cpuhotplug.h>14#include <linux/interrupt.h>15#include <linux/irq.h>16#include <linux/list.h>17#include <linux/smp.h>18 19#include "hisi_uncore_pmu.h"20 21/* L3C register definition */22#define L3C_PERF_CTRL 0x040823#define L3C_INT_MASK 0x080024#define L3C_INT_STATUS 0x080825#define L3C_INT_CLEAR 0x080c26#define L3C_CORE_CTRL 0x1b0427#define L3C_TRACETAG_CTRL 0x1b2028#define L3C_DATSRC_TYPE 0x1b4829#define L3C_DATSRC_CTRL 0x1bf030#define L3C_EVENT_CTRL 0x1c0031#define L3C_VERSION 0x1cf032#define L3C_EVENT_TYPE0 0x1d0033/*34 * If the HW version only supports a 48-bit counter, then35 * bits [63:48] are reserved, which are Read-As-Zero and36 * Writes-Ignored.37 */38#define L3C_CNTR0_LOWER 0x1e0039 40/* L3C has 8-counters */41#define L3C_NR_COUNTERS 0x842 43#define L3C_PERF_CTRL_EN 0x1000044#define L3C_TRACETAG_EN BIT(31)45#define L3C_TRACETAG_REQ_SHIFT 746#define L3C_TRACETAG_MARK_EN BIT(0)47#define L3C_TRACETAG_REQ_EN (L3C_TRACETAG_MARK_EN | BIT(2))48#define L3C_TRACETAG_CORE_EN (L3C_TRACETAG_MARK_EN | BIT(3))49#define L3C_CORE_EN BIT(20)50#define L3C_COER_NONE 0x051#define L3C_DATSRC_MASK 0xFF52#define L3C_DATSRC_SKT_EN BIT(23)53#define L3C_DATSRC_NONE 0x054#define L3C_EVTYPE_NONE 0xff55#define L3C_V1_NR_EVENTS 0x5956#define L3C_V2_NR_EVENTS 0xFF57 58HISI_PMU_EVENT_ATTR_EXTRACTOR(tt_core, config1, 7, 0);59HISI_PMU_EVENT_ATTR_EXTRACTOR(tt_req, config1, 10, 8);60HISI_PMU_EVENT_ATTR_EXTRACTOR(datasrc_cfg, config1, 15, 11);61HISI_PMU_EVENT_ATTR_EXTRACTOR(datasrc_skt, config1, 16, 16);62 63static void hisi_l3c_pmu_config_req_tracetag(struct perf_event *event)64{65 struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu);66 u32 tt_req = hisi_get_tt_req(event);67 68 if (tt_req) {69 u32 val;70 71 /* Set request-type for tracetag */72 val = readl(l3c_pmu->base + L3C_TRACETAG_CTRL);73 val |= tt_req << L3C_TRACETAG_REQ_SHIFT;74 val |= L3C_TRACETAG_REQ_EN;75 writel(val, l3c_pmu->base + L3C_TRACETAG_CTRL);76 77 /* Enable request-tracetag statistics */78 val = readl(l3c_pmu->base + L3C_PERF_CTRL);79 val |= L3C_TRACETAG_EN;80 writel(val, l3c_pmu->base + L3C_PERF_CTRL);81 }82}83 84static void hisi_l3c_pmu_clear_req_tracetag(struct perf_event *event)85{86 struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu);87 u32 tt_req = hisi_get_tt_req(event);88 89 if (tt_req) {90 u32 val;91 92 /* Clear request-type */93 val = readl(l3c_pmu->base + L3C_TRACETAG_CTRL);94 val &= ~(tt_req << L3C_TRACETAG_REQ_SHIFT);95 val &= ~L3C_TRACETAG_REQ_EN;96 writel(val, l3c_pmu->base + L3C_TRACETAG_CTRL);97 98 /* Disable request-tracetag statistics */99 val = readl(l3c_pmu->base + L3C_PERF_CTRL);100 val &= ~L3C_TRACETAG_EN;101 writel(val, l3c_pmu->base + L3C_PERF_CTRL);102 }103}104 105static void hisi_l3c_pmu_write_ds(struct perf_event *event, u32 ds_cfg)106{107 struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu);108 struct hw_perf_event *hwc = &event->hw;109 u32 reg, reg_idx, shift, val;110 int idx = hwc->idx;111 112 /*113 * Select the appropriate datasource register(L3C_DATSRC_TYPE0/1).114 * There are 2 datasource ctrl register for the 8 hardware counters.115 * Datasrc is 8-bits and for the former 4 hardware counters,116 * L3C_DATSRC_TYPE0 is chosen. For the latter 4 hardware counters,117 * L3C_DATSRC_TYPE1 is chosen.118 */119 reg = L3C_DATSRC_TYPE + (idx / 4) * 4;120 reg_idx = idx % 4;121 shift = 8 * reg_idx;122 123 val = readl(l3c_pmu->base + reg);124 val &= ~(L3C_DATSRC_MASK << shift);125 val |= ds_cfg << shift;126 writel(val, l3c_pmu->base + reg);127}128 129static void hisi_l3c_pmu_config_ds(struct perf_event *event)130{131 struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu);132 u32 ds_cfg = hisi_get_datasrc_cfg(event);133 u32 ds_skt = hisi_get_datasrc_skt(event);134 135 if (ds_cfg)136 hisi_l3c_pmu_write_ds(event, ds_cfg);137 138 if (ds_skt) {139 u32 val;140 141 val = readl(l3c_pmu->base + L3C_DATSRC_CTRL);142 val |= L3C_DATSRC_SKT_EN;143 writel(val, l3c_pmu->base + L3C_DATSRC_CTRL);144 }145}146 147static void hisi_l3c_pmu_clear_ds(struct perf_event *event)148{149 struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu);150 u32 ds_cfg = hisi_get_datasrc_cfg(event);151 u32 ds_skt = hisi_get_datasrc_skt(event);152 153 if (ds_cfg)154 hisi_l3c_pmu_write_ds(event, L3C_DATSRC_NONE);155 156 if (ds_skt) {157 u32 val;158 159 val = readl(l3c_pmu->base + L3C_DATSRC_CTRL);160 val &= ~L3C_DATSRC_SKT_EN;161 writel(val, l3c_pmu->base + L3C_DATSRC_CTRL);162 }163}164 165static void hisi_l3c_pmu_config_core_tracetag(struct perf_event *event)166{167 struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu);168 u32 core = hisi_get_tt_core(event);169 170 if (core) {171 u32 val;172 173 /* Config and enable core information */174 writel(core, l3c_pmu->base + L3C_CORE_CTRL);175 val = readl(l3c_pmu->base + L3C_PERF_CTRL);176 val |= L3C_CORE_EN;177 writel(val, l3c_pmu->base + L3C_PERF_CTRL);178 179 /* Enable core-tracetag statistics */180 val = readl(l3c_pmu->base + L3C_TRACETAG_CTRL);181 val |= L3C_TRACETAG_CORE_EN;182 writel(val, l3c_pmu->base + L3C_TRACETAG_CTRL);183 }184}185 186static void hisi_l3c_pmu_clear_core_tracetag(struct perf_event *event)187{188 struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu);189 u32 core = hisi_get_tt_core(event);190 191 if (core) {192 u32 val;193 194 /* Clear core information */195 writel(L3C_COER_NONE, l3c_pmu->base + L3C_CORE_CTRL);196 val = readl(l3c_pmu->base + L3C_PERF_CTRL);197 val &= ~L3C_CORE_EN;198 writel(val, l3c_pmu->base + L3C_PERF_CTRL);199 200 /* Disable core-tracetag statistics */201 val = readl(l3c_pmu->base + L3C_TRACETAG_CTRL);202 val &= ~L3C_TRACETAG_CORE_EN;203 writel(val, l3c_pmu->base + L3C_TRACETAG_CTRL);204 }205}206 207static void hisi_l3c_pmu_enable_filter(struct perf_event *event)208{209 if (event->attr.config1 != 0x0) {210 hisi_l3c_pmu_config_req_tracetag(event);211 hisi_l3c_pmu_config_core_tracetag(event);212 hisi_l3c_pmu_config_ds(event);213 }214}215 216static void hisi_l3c_pmu_disable_filter(struct perf_event *event)217{218 if (event->attr.config1 != 0x0) {219 hisi_l3c_pmu_clear_ds(event);220 hisi_l3c_pmu_clear_core_tracetag(event);221 hisi_l3c_pmu_clear_req_tracetag(event);222 }223}224 225/*226 * Select the counter register offset using the counter index227 */228static u32 hisi_l3c_pmu_get_counter_offset(int cntr_idx)229{230 return (L3C_CNTR0_LOWER + (cntr_idx * 8));231}232 233static u64 hisi_l3c_pmu_read_counter(struct hisi_pmu *l3c_pmu,234 struct hw_perf_event *hwc)235{236 return readq(l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(hwc->idx));237}238 239static void hisi_l3c_pmu_write_counter(struct hisi_pmu *l3c_pmu,240 struct hw_perf_event *hwc, u64 val)241{242 writeq(val, l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(hwc->idx));243}244 245static void hisi_l3c_pmu_write_evtype(struct hisi_pmu *l3c_pmu, int idx,246 u32 type)247{248 u32 reg, reg_idx, shift, val;249 250 /*251 * Select the appropriate event select register(L3C_EVENT_TYPE0/1).252 * There are 2 event select registers for the 8 hardware counters.253 * Event code is 8-bits and for the former 4 hardware counters,254 * L3C_EVENT_TYPE0 is chosen. For the latter 4 hardware counters,255 * L3C_EVENT_TYPE1 is chosen.256 */257 reg = L3C_EVENT_TYPE0 + (idx / 4) * 4;258 reg_idx = idx % 4;259 shift = 8 * reg_idx;260 261 /* Write event code to L3C_EVENT_TYPEx Register */262 val = readl(l3c_pmu->base + reg);263 val &= ~(L3C_EVTYPE_NONE << shift);264 val |= (type << shift);265 writel(val, l3c_pmu->base + reg);266}267 268static void hisi_l3c_pmu_start_counters(struct hisi_pmu *l3c_pmu)269{270 u32 val;271 272 /*273 * Set perf_enable bit in L3C_PERF_CTRL register to start counting274 * for all enabled counters.275 */276 val = readl(l3c_pmu->base + L3C_PERF_CTRL);277 val |= L3C_PERF_CTRL_EN;278 writel(val, l3c_pmu->base + L3C_PERF_CTRL);279}280 281static void hisi_l3c_pmu_stop_counters(struct hisi_pmu *l3c_pmu)282{283 u32 val;284 285 /*286 * Clear perf_enable bit in L3C_PERF_CTRL register to stop counting287 * for all enabled counters.288 */289 val = readl(l3c_pmu->base + L3C_PERF_CTRL);290 val &= ~(L3C_PERF_CTRL_EN);291 writel(val, l3c_pmu->base + L3C_PERF_CTRL);292}293 294static void hisi_l3c_pmu_enable_counter(struct hisi_pmu *l3c_pmu,295 struct hw_perf_event *hwc)296{297 u32 val;298 299 /* Enable counter index in L3C_EVENT_CTRL register */300 val = readl(l3c_pmu->base + L3C_EVENT_CTRL);301 val |= (1 << hwc->idx);302 writel(val, l3c_pmu->base + L3C_EVENT_CTRL);303}304 305static void hisi_l3c_pmu_disable_counter(struct hisi_pmu *l3c_pmu,306 struct hw_perf_event *hwc)307{308 u32 val;309 310 /* Clear counter index in L3C_EVENT_CTRL register */311 val = readl(l3c_pmu->base + L3C_EVENT_CTRL);312 val &= ~(1 << hwc->idx);313 writel(val, l3c_pmu->base + L3C_EVENT_CTRL);314}315 316static void hisi_l3c_pmu_enable_counter_int(struct hisi_pmu *l3c_pmu,317 struct hw_perf_event *hwc)318{319 u32 val;320 321 val = readl(l3c_pmu->base + L3C_INT_MASK);322 /* Write 0 to enable interrupt */323 val &= ~(1 << hwc->idx);324 writel(val, l3c_pmu->base + L3C_INT_MASK);325}326 327static void hisi_l3c_pmu_disable_counter_int(struct hisi_pmu *l3c_pmu,328 struct hw_perf_event *hwc)329{330 u32 val;331 332 val = readl(l3c_pmu->base + L3C_INT_MASK);333 /* Write 1 to mask interrupt */334 val |= (1 << hwc->idx);335 writel(val, l3c_pmu->base + L3C_INT_MASK);336}337 338static u32 hisi_l3c_pmu_get_int_status(struct hisi_pmu *l3c_pmu)339{340 return readl(l3c_pmu->base + L3C_INT_STATUS);341}342 343static void hisi_l3c_pmu_clear_int_status(struct hisi_pmu *l3c_pmu, int idx)344{345 writel(1 << idx, l3c_pmu->base + L3C_INT_CLEAR);346}347 348static const struct acpi_device_id hisi_l3c_pmu_acpi_match[] = {349 { "HISI0213", },350 { "HISI0214", },351 {}352};353MODULE_DEVICE_TABLE(acpi, hisi_l3c_pmu_acpi_match);354 355static int hisi_l3c_pmu_init_data(struct platform_device *pdev,356 struct hisi_pmu *l3c_pmu)357{358 /*359 * Use the SCCL_ID and CCL_ID to identify the L3C PMU, while360 * SCCL_ID is in MPIDR[aff2] and CCL_ID is in MPIDR[aff1].361 */362 if (device_property_read_u32(&pdev->dev, "hisilicon,scl-id",363 &l3c_pmu->sccl_id)) {364 dev_err(&pdev->dev, "Can not read l3c sccl-id!\n");365 return -EINVAL;366 }367 368 if (device_property_read_u32(&pdev->dev, "hisilicon,ccl-id",369 &l3c_pmu->ccl_id)) {370 dev_err(&pdev->dev, "Can not read l3c ccl-id!\n");371 return -EINVAL;372 }373 374 l3c_pmu->base = devm_platform_ioremap_resource(pdev, 0);375 if (IS_ERR(l3c_pmu->base)) {376 dev_err(&pdev->dev, "ioremap failed for l3c_pmu resource\n");377 return PTR_ERR(l3c_pmu->base);378 }379 380 l3c_pmu->identifier = readl(l3c_pmu->base + L3C_VERSION);381 382 return 0;383}384 385static struct attribute *hisi_l3c_pmu_v1_format_attr[] = {386 HISI_PMU_FORMAT_ATTR(event, "config:0-7"),387 NULL,388};389 390static const struct attribute_group hisi_l3c_pmu_v1_format_group = {391 .name = "format",392 .attrs = hisi_l3c_pmu_v1_format_attr,393};394 395static struct attribute *hisi_l3c_pmu_v2_format_attr[] = {396 HISI_PMU_FORMAT_ATTR(event, "config:0-7"),397 HISI_PMU_FORMAT_ATTR(tt_core, "config1:0-7"),398 HISI_PMU_FORMAT_ATTR(tt_req, "config1:8-10"),399 HISI_PMU_FORMAT_ATTR(datasrc_cfg, "config1:11-15"),400 HISI_PMU_FORMAT_ATTR(datasrc_skt, "config1:16"),401 NULL402};403 404static const struct attribute_group hisi_l3c_pmu_v2_format_group = {405 .name = "format",406 .attrs = hisi_l3c_pmu_v2_format_attr,407};408 409static struct attribute *hisi_l3c_pmu_v1_events_attr[] = {410 HISI_PMU_EVENT_ATTR(rd_cpipe, 0x00),411 HISI_PMU_EVENT_ATTR(wr_cpipe, 0x01),412 HISI_PMU_EVENT_ATTR(rd_hit_cpipe, 0x02),413 HISI_PMU_EVENT_ATTR(wr_hit_cpipe, 0x03),414 HISI_PMU_EVENT_ATTR(victim_num, 0x04),415 HISI_PMU_EVENT_ATTR(rd_spipe, 0x20),416 HISI_PMU_EVENT_ATTR(wr_spipe, 0x21),417 HISI_PMU_EVENT_ATTR(rd_hit_spipe, 0x22),418 HISI_PMU_EVENT_ATTR(wr_hit_spipe, 0x23),419 HISI_PMU_EVENT_ATTR(back_invalid, 0x29),420 HISI_PMU_EVENT_ATTR(retry_cpu, 0x40),421 HISI_PMU_EVENT_ATTR(retry_ring, 0x41),422 HISI_PMU_EVENT_ATTR(prefetch_drop, 0x42),423 NULL,424};425 426static const struct attribute_group hisi_l3c_pmu_v1_events_group = {427 .name = "events",428 .attrs = hisi_l3c_pmu_v1_events_attr,429};430 431static struct attribute *hisi_l3c_pmu_v2_events_attr[] = {432 HISI_PMU_EVENT_ATTR(l3c_hit, 0x48),433 HISI_PMU_EVENT_ATTR(cycles, 0x7f),434 HISI_PMU_EVENT_ATTR(l3c_ref, 0xb8),435 HISI_PMU_EVENT_ATTR(dat_access, 0xb9),436 NULL437};438 439static const struct attribute_group hisi_l3c_pmu_v2_events_group = {440 .name = "events",441 .attrs = hisi_l3c_pmu_v2_events_attr,442};443 444static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);445 446static struct attribute *hisi_l3c_pmu_cpumask_attrs[] = {447 &dev_attr_cpumask.attr,448 NULL,449};450 451static const struct attribute_group hisi_l3c_pmu_cpumask_attr_group = {452 .attrs = hisi_l3c_pmu_cpumask_attrs,453};454 455static struct device_attribute hisi_l3c_pmu_identifier_attr =456 __ATTR(identifier, 0444, hisi_uncore_pmu_identifier_attr_show, NULL);457 458static struct attribute *hisi_l3c_pmu_identifier_attrs[] = {459 &hisi_l3c_pmu_identifier_attr.attr,460 NULL461};462 463static const struct attribute_group hisi_l3c_pmu_identifier_group = {464 .attrs = hisi_l3c_pmu_identifier_attrs,465};466 467static const struct attribute_group *hisi_l3c_pmu_v1_attr_groups[] = {468 &hisi_l3c_pmu_v1_format_group,469 &hisi_l3c_pmu_v1_events_group,470 &hisi_l3c_pmu_cpumask_attr_group,471 &hisi_l3c_pmu_identifier_group,472 NULL,473};474 475static const struct attribute_group *hisi_l3c_pmu_v2_attr_groups[] = {476 &hisi_l3c_pmu_v2_format_group,477 &hisi_l3c_pmu_v2_events_group,478 &hisi_l3c_pmu_cpumask_attr_group,479 &hisi_l3c_pmu_identifier_group,480 NULL481};482 483static const struct hisi_uncore_ops hisi_uncore_l3c_ops = {484 .write_evtype = hisi_l3c_pmu_write_evtype,485 .get_event_idx = hisi_uncore_pmu_get_event_idx,486 .start_counters = hisi_l3c_pmu_start_counters,487 .stop_counters = hisi_l3c_pmu_stop_counters,488 .enable_counter = hisi_l3c_pmu_enable_counter,489 .disable_counter = hisi_l3c_pmu_disable_counter,490 .enable_counter_int = hisi_l3c_pmu_enable_counter_int,491 .disable_counter_int = hisi_l3c_pmu_disable_counter_int,492 .write_counter = hisi_l3c_pmu_write_counter,493 .read_counter = hisi_l3c_pmu_read_counter,494 .get_int_status = hisi_l3c_pmu_get_int_status,495 .clear_int_status = hisi_l3c_pmu_clear_int_status,496 .enable_filter = hisi_l3c_pmu_enable_filter,497 .disable_filter = hisi_l3c_pmu_disable_filter,498};499 500static int hisi_l3c_pmu_dev_probe(struct platform_device *pdev,501 struct hisi_pmu *l3c_pmu)502{503 int ret;504 505 ret = hisi_l3c_pmu_init_data(pdev, l3c_pmu);506 if (ret)507 return ret;508 509 ret = hisi_uncore_pmu_init_irq(l3c_pmu, pdev);510 if (ret)511 return ret;512 513 if (l3c_pmu->identifier >= HISI_PMU_V2) {514 l3c_pmu->counter_bits = 64;515 l3c_pmu->check_event = L3C_V2_NR_EVENTS;516 l3c_pmu->pmu_events.attr_groups = hisi_l3c_pmu_v2_attr_groups;517 } else {518 l3c_pmu->counter_bits = 48;519 l3c_pmu->check_event = L3C_V1_NR_EVENTS;520 l3c_pmu->pmu_events.attr_groups = hisi_l3c_pmu_v1_attr_groups;521 }522 523 l3c_pmu->num_counters = L3C_NR_COUNTERS;524 l3c_pmu->ops = &hisi_uncore_l3c_ops;525 l3c_pmu->dev = &pdev->dev;526 l3c_pmu->on_cpu = -1;527 528 return 0;529}530 531static int hisi_l3c_pmu_probe(struct platform_device *pdev)532{533 struct hisi_pmu *l3c_pmu;534 char *name;535 int ret;536 537 l3c_pmu = devm_kzalloc(&pdev->dev, sizeof(*l3c_pmu), GFP_KERNEL);538 if (!l3c_pmu)539 return -ENOMEM;540 541 platform_set_drvdata(pdev, l3c_pmu);542 543 ret = hisi_l3c_pmu_dev_probe(pdev, l3c_pmu);544 if (ret)545 return ret;546 547 name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_l3c%u",548 l3c_pmu->sccl_id, l3c_pmu->ccl_id);549 if (!name)550 return -ENOMEM;551 552 ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE,553 &l3c_pmu->node);554 if (ret) {555 dev_err(&pdev->dev, "Error %d registering hotplug\n", ret);556 return ret;557 }558 559 hisi_pmu_init(l3c_pmu, THIS_MODULE);560 561 ret = perf_pmu_register(&l3c_pmu->pmu, name, -1);562 if (ret) {563 dev_err(l3c_pmu->dev, "L3C PMU register failed!\n");564 cpuhp_state_remove_instance_nocalls(565 CPUHP_AP_PERF_ARM_HISI_L3_ONLINE, &l3c_pmu->node);566 }567 568 return ret;569}570 571static void hisi_l3c_pmu_remove(struct platform_device *pdev)572{573 struct hisi_pmu *l3c_pmu = platform_get_drvdata(pdev);574 575 perf_pmu_unregister(&l3c_pmu->pmu);576 cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE,577 &l3c_pmu->node);578}579 580static struct platform_driver hisi_l3c_pmu_driver = {581 .driver = {582 .name = "hisi_l3c_pmu",583 .acpi_match_table = ACPI_PTR(hisi_l3c_pmu_acpi_match),584 .suppress_bind_attrs = true,585 },586 .probe = hisi_l3c_pmu_probe,587 .remove_new = hisi_l3c_pmu_remove,588};589 590static int __init hisi_l3c_pmu_module_init(void)591{592 int ret;593 594 ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE,595 "AP_PERF_ARM_HISI_L3_ONLINE",596 hisi_uncore_pmu_online_cpu,597 hisi_uncore_pmu_offline_cpu);598 if (ret) {599 pr_err("L3C PMU: Error setup hotplug, ret = %d\n", ret);600 return ret;601 }602 603 ret = platform_driver_register(&hisi_l3c_pmu_driver);604 if (ret)605 cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE);606 607 return ret;608}609module_init(hisi_l3c_pmu_module_init);610 611static void __exit hisi_l3c_pmu_module_exit(void)612{613 platform_driver_unregister(&hisi_l3c_pmu_driver);614 cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE);615}616module_exit(hisi_l3c_pmu_module_exit);617 618MODULE_DESCRIPTION("HiSilicon SoC L3C uncore PMU driver");619MODULE_LICENSE("GPL v2");620MODULE_AUTHOR("Anurup M <anurup.m@huawei.com>");621MODULE_AUTHOR("Shaokun Zhang <zhangshaokun@hisilicon.com>");622