FILE
hisi_uncore_sllc_pmu.c
File preview with syntax highlighting.
linux-6.19.14/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * HiSilicon SLLC uncore Hardware event counters support 4 * 5 * Copyright (C) 2020 HiSilicon Limited 6 * Author: Shaokun Zhang <zhangshaokun@hisilicon.com> 7 * 8 * This code is based on the uncore PMUs like arm-cci and arm-ccn. 9 */ 10#include <linux/acpi.h> 11#include <linux/cpuhotplug.h> 12#include <linux/interrupt.h> 13#include <linux/irq.h> 14#include <linux/list.h> 15#include <linux/smp.h> 16 17#include "hisi_uncore_pmu.h" 18 19/* SLLC register definition */ 20#define SLLC_INT_MASK 0x0814 21#define SLLC_INT_STATUS 0x0818 22#define SLLC_INT_CLEAR 0x081c 23#define SLLC_PERF_CTRL 0x1c00 24#define SLLC_SRCID_CTRL 0x1c04 25#define SLLC_TGTID_CTRL 0x1c08 26#define SLLC_EVENT_CTRL 0x1c14 27#define SLLC_EVENT_TYPE0 0x1c18 28#define SLLC_VERSION 0x1cf0 29#define SLLC_EVENT_CNT0_L 0x1d00 30 31/* SLLC registers definition in v3 */ 32#define SLLC_V3_INT_MASK 0x6834 33#define SLLC_V3_INT_STATUS 0x6838 34#define SLLC_V3_INT_CLEAR 0x683c 35#define SLLC_V3_VERSION 0x6c00 36#define SLLC_V3_PERF_CTRL 0x6d00 37#define SLLC_V3_SRCID_CTRL 0x6d04 38#define SLLC_V3_TGTID_CTRL 0x6d08 39#define SLLC_V3_EVENT_CTRL 0x6d14 40#define SLLC_V3_EVENT_TYPE0 0x6d18 41#define SLLC_V3_EVENT_CNT0_L 0x6e00 42 43#define SLLC_EVTYPE_MASK 0xff 44#define SLLC_PERF_CTRL_EN BIT(0) 45#define SLLC_FILT_EN BIT(1) 46#define SLLC_TRACETAG_EN BIT(2) 47#define SLLC_SRCID_EN BIT(4) 48#define SLLC_SRCID_NONE 0x0 49#define SLLC_TGTID_EN BIT(5) 50#define SLLC_TGTID_NONE 0x0 51#define SLLC_TGTID_MIN_SHIFT 1 52#define SLLC_TGTID_MAX_SHIFT 12 53#define SLLC_SRCID_CMD_SHIFT 1 54#define SLLC_SRCID_MSK_SHIFT 12 55 56#define SLLC_V3_TGTID_MIN_SHIFT 1 57#define SLLC_V3_TGTID_MAX_SHIFT 10 58#define SLLC_V3_SRCID_CMD_SHIFT 1 59#define SLLC_V3_SRCID_MSK_SHIFT 10 60 61#define SLLC_NR_EVENTS 0xff 62#define SLLC_EVENT_CNTn(cnt0, n) ((cnt0) + (n) * 8) 63 64HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_min, config1, 10, 0); 65HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_max, config1, 21, 11); 66HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_cmd, config1, 32, 22); 67HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_msk, config1, 43, 33); 68HISI_PMU_EVENT_ATTR_EXTRACTOR(tracetag_en, config1, 44, 44); 69 70struct hisi_sllc_pmu_regs { 71 u32 int_mask; 72 u32 int_clear; 73 u32 int_status; 74 u32 perf_ctrl; 75 u32 srcid_ctrl; 76 u32 srcid_cmd_shift; 77 u32 srcid_mask_shift; 78 u32 tgtid_ctrl; 79 u32 tgtid_min_shift; 80 u32 tgtid_max_shift; 81 u32 event_ctrl; 82 u32 event_type0; 83 u32 version; 84 u32 event_cnt0; 85}; 86 87static bool tgtid_is_valid(u32 max, u32 min) 88{ 89 return max > 0 && max >= min; 90} 91 92static void hisi_sllc_pmu_enable_tracetag(struct perf_event *event) 93{ 94 struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu); 95 struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private; 96 u32 tt_en = hisi_get_tracetag_en(event); 97 98 if (tt_en) { 99 u32 val; 100 101 val = readl(sllc_pmu->base + regs->perf_ctrl); 102 val |= SLLC_TRACETAG_EN | SLLC_FILT_EN; 103 writel(val, sllc_pmu->base + regs->perf_ctrl); 104 } 105} 106 107static void hisi_sllc_pmu_disable_tracetag(struct perf_event *event) 108{ 109 struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu); 110 struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private; 111 u32 tt_en = hisi_get_tracetag_en(event); 112 113 if (tt_en) { 114 u32 val; 115 116 val = readl(sllc_pmu->base + regs->perf_ctrl); 117 val &= ~(SLLC_TRACETAG_EN | SLLC_FILT_EN); 118 writel(val, sllc_pmu->base + regs->perf_ctrl); 119 } 120} 121 122static void hisi_sllc_pmu_config_tgtid(struct perf_event *event) 123{ 124 struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu); 125 struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private; 126 u32 min = hisi_get_tgtid_min(event); 127 u32 max = hisi_get_tgtid_max(event); 128 129 if (tgtid_is_valid(max, min)) { 130 u32 val = (max << regs->tgtid_max_shift) | 131 (min << regs->tgtid_min_shift); 132 133 writel(val, sllc_pmu->base + regs->tgtid_ctrl); 134 /* Enable the tgtid */ 135 val = readl(sllc_pmu->base + regs->perf_ctrl); 136 val |= SLLC_TGTID_EN | SLLC_FILT_EN; 137 writel(val, sllc_pmu->base + regs->perf_ctrl); 138 } 139} 140 141static void hisi_sllc_pmu_clear_tgtid(struct perf_event *event) 142{ 143 struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu); 144 struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private; 145 u32 min = hisi_get_tgtid_min(event); 146 u32 max = hisi_get_tgtid_max(event); 147 148 if (tgtid_is_valid(max, min)) { 149 u32 val; 150 151 writel(SLLC_TGTID_NONE, sllc_pmu->base + regs->tgtid_ctrl); 152 /* Disable the tgtid */ 153 val = readl(sllc_pmu->base + regs->perf_ctrl); 154 val &= ~(SLLC_TGTID_EN | SLLC_FILT_EN); 155 writel(val, sllc_pmu->base + regs->perf_ctrl); 156 } 157} 158 159static void hisi_sllc_pmu_config_srcid(struct perf_event *event) 160{ 161 struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu); 162 struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private; 163 u32 cmd = hisi_get_srcid_cmd(event); 164 165 if (cmd) { 166 u32 val, msk; 167 168 msk = hisi_get_srcid_msk(event); 169 val = (cmd << regs->srcid_cmd_shift) | 170 (msk << regs->srcid_mask_shift); 171 writel(val, sllc_pmu->base + regs->srcid_ctrl); 172 /* Enable the srcid */ 173 val = readl(sllc_pmu->base + regs->perf_ctrl); 174 val |= SLLC_SRCID_EN | SLLC_FILT_EN; 175 writel(val, sllc_pmu->base + regs->perf_ctrl); 176 } 177} 178 179static void hisi_sllc_pmu_clear_srcid(struct perf_event *event) 180{ 181 struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu); 182 struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private; 183 u32 cmd = hisi_get_srcid_cmd(event); 184 185 if (cmd) { 186 u32 val; 187 188 writel(SLLC_SRCID_NONE, sllc_pmu->base + regs->srcid_ctrl); 189 /* Disable the srcid */ 190 val = readl(sllc_pmu->base + regs->perf_ctrl); 191 val &= ~(SLLC_SRCID_EN | SLLC_FILT_EN); 192 writel(val, sllc_pmu->base + regs->perf_ctrl); 193 } 194} 195 196static void hisi_sllc_pmu_enable_filter(struct perf_event *event) 197{ 198 if (event->attr.config1 != 0x0) { 199 hisi_sllc_pmu_enable_tracetag(event); 200 hisi_sllc_pmu_config_srcid(event); 201 hisi_sllc_pmu_config_tgtid(event); 202 } 203} 204 205static void hisi_sllc_pmu_clear_filter(struct perf_event *event) 206{ 207 if (event->attr.config1 != 0x0) { 208 hisi_sllc_pmu_disable_tracetag(event); 209 hisi_sllc_pmu_clear_srcid(event); 210 hisi_sllc_pmu_clear_tgtid(event); 211 } 212} 213 214static u64 hisi_sllc_pmu_read_counter(struct hisi_pmu *sllc_pmu, 215 struct hw_perf_event *hwc) 216{ 217 struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private; 218 219 return readq(sllc_pmu->base + SLLC_EVENT_CNTn(regs->event_cnt0, hwc->idx)); 220} 221 222static void hisi_sllc_pmu_write_counter(struct hisi_pmu *sllc_pmu, 223 struct hw_perf_event *hwc, u64 val) 224{ 225 struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private; 226 227 writeq(val, sllc_pmu->base + SLLC_EVENT_CNTn(regs->event_cnt0, hwc->idx)); 228} 229 230static void hisi_sllc_pmu_write_evtype(struct hisi_pmu *sllc_pmu, int idx, 231 u32 type) 232{ 233 struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private; 234 u32 reg, val; 235 236 /* 237 * Select the appropriate event select register(SLLC_EVENT_TYPE0/1). 238 * There are 2 event select registers for the 8 hardware counters. 239 * Event code is 8-bits and for the former 4 hardware counters, 240 * SLLC_EVENT_TYPE0 is chosen. For the latter 4 hardware counters, 241 * SLLC_EVENT_TYPE1 is chosen. 242 */ 243 reg = regs->event_type0 + (idx / 4) * 4; 244 245 /* Write event code to SLLC_EVENT_TYPEx Register */ 246 val = readl(sllc_pmu->base + reg); 247 val &= ~(SLLC_EVTYPE_MASK << HISI_PMU_EVTYPE_SHIFT(idx)); 248 val |= (type << HISI_PMU_EVTYPE_SHIFT(idx)); 249 writel(val, sllc_pmu->base + reg); 250} 251 252static void hisi_sllc_pmu_start_counters(struct hisi_pmu *sllc_pmu) 253{ 254 struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private; 255 u32 val; 256 257 val = readl(sllc_pmu->base + regs->perf_ctrl); 258 val |= SLLC_PERF_CTRL_EN; 259 writel(val, sllc_pmu->base + regs->perf_ctrl); 260} 261 262static void hisi_sllc_pmu_stop_counters(struct hisi_pmu *sllc_pmu) 263{ 264 struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private; 265 u32 val; 266 267 val = readl(sllc_pmu->base + regs->perf_ctrl); 268 val &= ~(SLLC_PERF_CTRL_EN); 269 writel(val, sllc_pmu->base + regs->perf_ctrl); 270} 271 272static void hisi_sllc_pmu_enable_counter(struct hisi_pmu *sllc_pmu, 273 struct hw_perf_event *hwc) 274{ 275 struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private; 276 u32 val; 277 278 val = readl(sllc_pmu->base + regs->event_ctrl); 279 val |= BIT_ULL(hwc->idx); 280 writel(val, sllc_pmu->base + regs->event_ctrl); 281} 282 283static void hisi_sllc_pmu_disable_counter(struct hisi_pmu *sllc_pmu, 284 struct hw_perf_event *hwc) 285{ 286 struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private; 287 u32 val; 288 289 val = readl(sllc_pmu->base + regs->event_ctrl); 290 val &= ~BIT_ULL(hwc->idx); 291 writel(val, sllc_pmu->base + regs->event_ctrl); 292} 293 294static void hisi_sllc_pmu_enable_counter_int(struct hisi_pmu *sllc_pmu, 295 struct hw_perf_event *hwc) 296{ 297 struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private; 298 u32 val; 299 300 val = readl(sllc_pmu->base + regs->int_mask); 301 val &= ~BIT_ULL(hwc->idx); 302 writel(val, sllc_pmu->base + regs->int_mask); 303} 304 305static void hisi_sllc_pmu_disable_counter_int(struct hisi_pmu *sllc_pmu, 306 struct hw_perf_event *hwc) 307{ 308 struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private; 309 u32 val; 310 311 val = readl(sllc_pmu->base + regs->int_mask); 312 val |= BIT_ULL(hwc->idx); 313 writel(val, sllc_pmu->base + regs->int_mask); 314} 315 316static u32 hisi_sllc_pmu_get_int_status(struct hisi_pmu *sllc_pmu) 317{ 318 struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private; 319 320 return readl(sllc_pmu->base + regs->int_status); 321} 322 323static void hisi_sllc_pmu_clear_int_status(struct hisi_pmu *sllc_pmu, int idx) 324{ 325 struct hisi_sllc_pmu_regs *regs = sllc_pmu->dev_info->private; 326 327 writel(BIT_ULL(idx), sllc_pmu->base + regs->int_clear); 328} 329 330static int hisi_sllc_pmu_init_data(struct platform_device *pdev, 331 struct hisi_pmu *sllc_pmu) 332{ 333 struct hisi_sllc_pmu_regs *regs; 334 335 hisi_uncore_pmu_init_topology(sllc_pmu, &pdev->dev); 336 337 /* 338 * Use the SCCL_ID and the index ID to identify the SLLC PMU, 339 * while SCCL_ID is from MPIDR_EL1 by CPU. 340 */ 341 if (sllc_pmu->topo.sccl_id < 0) { 342 dev_err(&pdev->dev, "Cannot read sccl-id!\n"); 343 return -EINVAL; 344 } 345 346 if (sllc_pmu->topo.index_id < 0) { 347 dev_err(&pdev->dev, "Cannot read idx-id!\n"); 348 return -EINVAL; 349 } 350 351 sllc_pmu->dev_info = device_get_match_data(&pdev->dev); 352 if (!sllc_pmu->dev_info) 353 return -ENODEV; 354 355 sllc_pmu->base = devm_platform_ioremap_resource(pdev, 0); 356 if (IS_ERR(sllc_pmu->base)) { 357 dev_err(&pdev->dev, "ioremap failed for sllc_pmu resource.\n"); 358 return PTR_ERR(sllc_pmu->base); 359 } 360 361 regs = sllc_pmu->dev_info->private; 362 sllc_pmu->identifier = readl(sllc_pmu->base + regs->version); 363 364 return 0; 365} 366 367static struct attribute *hisi_sllc_pmu_v2_format_attr[] = { 368 HISI_PMU_FORMAT_ATTR(event, "config:0-7"), 369 HISI_PMU_FORMAT_ATTR(tgtid_min, "config1:0-10"), 370 HISI_PMU_FORMAT_ATTR(tgtid_max, "config1:11-21"), 371 HISI_PMU_FORMAT_ATTR(srcid_cmd, "config1:22-32"), 372 HISI_PMU_FORMAT_ATTR(srcid_msk, "config1:33-43"), 373 HISI_PMU_FORMAT_ATTR(tracetag_en, "config1:44"), 374 NULL 375}; 376 377static const struct attribute_group hisi_sllc_pmu_v2_format_group = { 378 .name = "format", 379 .attrs = hisi_sllc_pmu_v2_format_attr, 380}; 381 382static struct attribute *hisi_sllc_pmu_v2_events_attr[] = { 383 HISI_PMU_EVENT_ATTR(rx_req, 0x30), 384 HISI_PMU_EVENT_ATTR(rx_data, 0x31), 385 HISI_PMU_EVENT_ATTR(tx_req, 0x34), 386 HISI_PMU_EVENT_ATTR(tx_data, 0x35), 387 HISI_PMU_EVENT_ATTR(cycles, 0x09), 388 NULL 389}; 390 391static const struct attribute_group hisi_sllc_pmu_v2_events_group = { 392 .name = "events", 393 .attrs = hisi_sllc_pmu_v2_events_attr, 394}; 395 396static const struct attribute_group *hisi_sllc_pmu_v2_attr_groups[] = { 397 &hisi_sllc_pmu_v2_format_group, 398 &hisi_sllc_pmu_v2_events_group, 399 &hisi_pmu_cpumask_attr_group, 400 &hisi_pmu_identifier_group, 401 NULL 402}; 403 404static struct hisi_sllc_pmu_regs hisi_sllc_v2_pmu_regs = { 405 .int_mask = SLLC_INT_MASK, 406 .int_clear = SLLC_INT_CLEAR, 407 .int_status = SLLC_INT_STATUS, 408 .perf_ctrl = SLLC_PERF_CTRL, 409 .srcid_ctrl = SLLC_SRCID_CTRL, 410 .srcid_cmd_shift = SLLC_SRCID_CMD_SHIFT, 411 .srcid_mask_shift = SLLC_SRCID_MSK_SHIFT, 412 .tgtid_ctrl = SLLC_TGTID_CTRL, 413 .tgtid_min_shift = SLLC_TGTID_MIN_SHIFT, 414 .tgtid_max_shift = SLLC_TGTID_MAX_SHIFT, 415 .event_ctrl = SLLC_EVENT_CTRL, 416 .event_type0 = SLLC_EVENT_TYPE0, 417 .version = SLLC_VERSION, 418 .event_cnt0 = SLLC_EVENT_CNT0_L, 419}; 420 421static const struct hisi_pmu_dev_info hisi_sllc_v2 = { 422 .private = &hisi_sllc_v2_pmu_regs, 423}; 424 425static struct hisi_sllc_pmu_regs hisi_sllc_v3_pmu_regs = { 426 .int_mask = SLLC_V3_INT_MASK, 427 .int_clear = SLLC_V3_INT_CLEAR, 428 .int_status = SLLC_V3_INT_STATUS, 429 .perf_ctrl = SLLC_V3_PERF_CTRL, 430 .srcid_ctrl = SLLC_V3_SRCID_CTRL, 431 .srcid_cmd_shift = SLLC_V3_SRCID_CMD_SHIFT, 432 .srcid_mask_shift = SLLC_V3_SRCID_MSK_SHIFT, 433 .tgtid_ctrl = SLLC_V3_TGTID_CTRL, 434 .tgtid_min_shift = SLLC_V3_TGTID_MIN_SHIFT, 435 .tgtid_max_shift = SLLC_V3_TGTID_MAX_SHIFT, 436 .event_ctrl = SLLC_V3_EVENT_CTRL, 437 .event_type0 = SLLC_V3_EVENT_TYPE0, 438 .version = SLLC_V3_VERSION, 439 .event_cnt0 = SLLC_V3_EVENT_CNT0_L, 440}; 441 442static const struct hisi_pmu_dev_info hisi_sllc_v3 = { 443 .private = &hisi_sllc_v3_pmu_regs, 444}; 445 446static const struct hisi_uncore_ops hisi_uncore_sllc_ops = { 447 .write_evtype = hisi_sllc_pmu_write_evtype, 448 .get_event_idx = hisi_uncore_pmu_get_event_idx, 449 .start_counters = hisi_sllc_pmu_start_counters, 450 .stop_counters = hisi_sllc_pmu_stop_counters, 451 .enable_counter = hisi_sllc_pmu_enable_counter, 452 .disable_counter = hisi_sllc_pmu_disable_counter, 453 .enable_counter_int = hisi_sllc_pmu_enable_counter_int, 454 .disable_counter_int = hisi_sllc_pmu_disable_counter_int, 455 .write_counter = hisi_sllc_pmu_write_counter, 456 .read_counter = hisi_sllc_pmu_read_counter, 457 .get_int_status = hisi_sllc_pmu_get_int_status, 458 .clear_int_status = hisi_sllc_pmu_clear_int_status, 459 .enable_filter = hisi_sllc_pmu_enable_filter, 460 .disable_filter = hisi_sllc_pmu_clear_filter, 461}; 462 463static int hisi_sllc_pmu_dev_probe(struct platform_device *pdev, 464 struct hisi_pmu *sllc_pmu) 465{ 466 int ret; 467 468 ret = hisi_sllc_pmu_init_data(pdev, sllc_pmu); 469 if (ret) 470 return ret; 471 472 ret = hisi_uncore_pmu_init_irq(sllc_pmu, pdev); 473 if (ret) 474 return ret; 475 476 sllc_pmu->pmu_events.attr_groups = hisi_sllc_pmu_v2_attr_groups; 477 sllc_pmu->ops = &hisi_uncore_sllc_ops; 478 sllc_pmu->check_event = SLLC_NR_EVENTS; 479 sllc_pmu->counter_bits = 64; 480 sllc_pmu->num_counters = 8; 481 sllc_pmu->dev = &pdev->dev; 482 sllc_pmu->on_cpu = -1; 483 484 return 0; 485} 486 487static int hisi_sllc_pmu_probe(struct platform_device *pdev) 488{ 489 struct hisi_pmu *sllc_pmu; 490 char *name; 491 int ret; 492 493 sllc_pmu = devm_kzalloc(&pdev->dev, sizeof(*sllc_pmu), GFP_KERNEL); 494 if (!sllc_pmu) 495 return -ENOMEM; 496 497 ret = hisi_sllc_pmu_dev_probe(pdev, sllc_pmu); 498 if (ret) 499 return ret; 500 501 name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%d_sllc%d", 502 sllc_pmu->topo.sccl_id, sllc_pmu->topo.index_id); 503 if (!name) 504 return -ENOMEM; 505 506 ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE, 507 &sllc_pmu->node); 508 if (ret) { 509 dev_err(&pdev->dev, "Error %d registering hotplug\n", ret); 510 return ret; 511 } 512 513 hisi_pmu_init(sllc_pmu, THIS_MODULE); 514 515 ret = perf_pmu_register(&sllc_pmu->pmu, name, -1); 516 if (ret) { 517 dev_err(sllc_pmu->dev, "PMU register failed, ret = %d\n", ret); 518 cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE, 519 &sllc_pmu->node); 520 return ret; 521 } 522 523 platform_set_drvdata(pdev, sllc_pmu); 524 525 return ret; 526} 527 528static void hisi_sllc_pmu_remove(struct platform_device *pdev) 529{ 530 struct hisi_pmu *sllc_pmu = platform_get_drvdata(pdev); 531 532 perf_pmu_unregister(&sllc_pmu->pmu); 533 cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE, 534 &sllc_pmu->node); 535} 536 537static const struct acpi_device_id hisi_sllc_pmu_acpi_match[] = { 538 { "HISI0263", (kernel_ulong_t)&hisi_sllc_v2 }, 539 { "HISI0264", (kernel_ulong_t)&hisi_sllc_v3 }, 540 {} 541}; 542MODULE_DEVICE_TABLE(acpi, hisi_sllc_pmu_acpi_match); 543 544static struct platform_driver hisi_sllc_pmu_driver = { 545 .driver = { 546 .name = "hisi_sllc_pmu", 547 .acpi_match_table = hisi_sllc_pmu_acpi_match, 548 .suppress_bind_attrs = true, 549 }, 550 .probe = hisi_sllc_pmu_probe, 551 .remove = hisi_sllc_pmu_remove, 552}; 553 554static int __init hisi_sllc_pmu_module_init(void) 555{ 556 int ret; 557 558 ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE, 559 "AP_PERF_ARM_HISI_SLLC_ONLINE", 560 hisi_uncore_pmu_online_cpu, 561 hisi_uncore_pmu_offline_cpu); 562 if (ret) { 563 pr_err("SLLC PMU: cpuhp state setup failed, ret = %d\n", ret); 564 return ret; 565 } 566 567 ret = platform_driver_register(&hisi_sllc_pmu_driver); 568 if (ret) 569 cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE); 570 571 return ret; 572} 573module_init(hisi_sllc_pmu_module_init); 574 575static void __exit hisi_sllc_pmu_module_exit(void) 576{ 577 platform_driver_unregister(&hisi_sllc_pmu_driver); 578 cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE); 579} 580module_exit(hisi_sllc_pmu_module_exit); 581 582MODULE_IMPORT_NS("HISI_PMU"); 583MODULE_DESCRIPTION("HiSilicon SLLC uncore PMU driver"); 584MODULE_LICENSE("GPL v2"); 585MODULE_AUTHOR("Shaokun Zhang <zhangshaokun@hisilicon.com>"); 586MODULE_AUTHOR("Qi Liu <liuqi115@huawei.com>");
~/
Read-only file preview.