| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright 2017 NXP |
|---|
| 3 | 4 | * Copyright 2011,2016 Freescale Semiconductor, Inc. |
|---|
| 4 | 5 | * Copyright 2011 Linaro Ltd. |
|---|
| 5 | | - * |
|---|
| 6 | | - * The code contained herein is licensed under the GNU General Public |
|---|
| 7 | | - * License. You may obtain a copy of the GNU General Public License |
|---|
| 8 | | - * Version 2 or later at the following locations: |
|---|
| 9 | | - * |
|---|
| 10 | | - * http://www.opensource.org/licenses/gpl-license.html |
|---|
| 11 | | - * http://www.gnu.org/copyleft/gpl.html |
|---|
| 12 | 6 | */ |
|---|
| 13 | 7 | |
|---|
| 14 | 8 | #include <linux/clk.h> |
|---|
| .. | .. |
|---|
| 105 | 99 | cpumask_t cpu; |
|---|
| 106 | 100 | struct hrtimer hrtimer; |
|---|
| 107 | 101 | unsigned int active_events; |
|---|
| 102 | + int id; |
|---|
| 108 | 103 | struct device *dev; |
|---|
| 109 | 104 | struct perf_event *mmdc_events[MMDC_NUM_COUNTERS]; |
|---|
| 110 | 105 | struct hlist_node node; |
|---|
| .. | .. |
|---|
| 295 | 290 | return -EOPNOTSUPP; |
|---|
| 296 | 291 | } |
|---|
| 297 | 292 | |
|---|
| 298 | | - if (event->attr.exclude_user || |
|---|
| 299 | | - event->attr.exclude_kernel || |
|---|
| 300 | | - event->attr.exclude_hv || |
|---|
| 301 | | - event->attr.exclude_idle || |
|---|
| 302 | | - event->attr.exclude_host || |
|---|
| 303 | | - event->attr.exclude_guest || |
|---|
| 304 | | - event->attr.sample_period) |
|---|
| 293 | + if (event->attr.sample_period) |
|---|
| 305 | 294 | return -EINVAL; |
|---|
| 306 | 295 | |
|---|
| 307 | 296 | if (cfg < 0 || cfg >= MMDC_NUM_COUNTERS) |
|---|
| .. | .. |
|---|
| 445 | 434 | static int mmdc_pmu_init(struct mmdc_pmu *pmu_mmdc, |
|---|
| 446 | 435 | void __iomem *mmdc_base, struct device *dev) |
|---|
| 447 | 436 | { |
|---|
| 448 | | - int mmdc_num; |
|---|
| 449 | | - |
|---|
| 450 | 437 | *pmu_mmdc = (struct mmdc_pmu) { |
|---|
| 451 | 438 | .pmu = (struct pmu) { |
|---|
| 452 | 439 | .task_ctx_nr = perf_invalid_context, |
|---|
| .. | .. |
|---|
| 457 | 444 | .start = mmdc_pmu_event_start, |
|---|
| 458 | 445 | .stop = mmdc_pmu_event_stop, |
|---|
| 459 | 446 | .read = mmdc_pmu_event_update, |
|---|
| 447 | + .capabilities = PERF_PMU_CAP_NO_EXCLUDE, |
|---|
| 460 | 448 | }, |
|---|
| 461 | 449 | .mmdc_base = mmdc_base, |
|---|
| 462 | 450 | .dev = dev, |
|---|
| 463 | 451 | .active_events = 0, |
|---|
| 464 | 452 | }; |
|---|
| 465 | 453 | |
|---|
| 466 | | - mmdc_num = ida_simple_get(&mmdc_ida, 0, 0, GFP_KERNEL); |
|---|
| 454 | + pmu_mmdc->id = ida_simple_get(&mmdc_ida, 0, 0, GFP_KERNEL); |
|---|
| 467 | 455 | |
|---|
| 468 | | - return mmdc_num; |
|---|
| 456 | + return pmu_mmdc->id; |
|---|
| 469 | 457 | } |
|---|
| 470 | 458 | |
|---|
| 471 | 459 | static int imx_mmdc_remove(struct platform_device *pdev) |
|---|
| 472 | 460 | { |
|---|
| 473 | 461 | struct mmdc_pmu *pmu_mmdc = platform_get_drvdata(pdev); |
|---|
| 474 | 462 | |
|---|
| 463 | + ida_simple_remove(&mmdc_ida, pmu_mmdc->id); |
|---|
| 475 | 464 | cpuhp_state_remove_instance_nocalls(cpuhp_mmdc_state, &pmu_mmdc->node); |
|---|
| 476 | 465 | perf_pmu_unregister(&pmu_mmdc->pmu); |
|---|
| 477 | 466 | iounmap(pmu_mmdc->mmdc_base); |
|---|
| .. | .. |
|---|
| 485 | 474 | { |
|---|
| 486 | 475 | struct mmdc_pmu *pmu_mmdc; |
|---|
| 487 | 476 | char *name; |
|---|
| 488 | | - int mmdc_num; |
|---|
| 489 | 477 | int ret; |
|---|
| 490 | 478 | const struct of_device_id *of_id = |
|---|
| 491 | 479 | of_match_device(imx_mmdc_dt_ids, &pdev->dev); |
|---|
| .. | .. |
|---|
| 508 | 496 | cpuhp_mmdc_state = ret; |
|---|
| 509 | 497 | } |
|---|
| 510 | 498 | |
|---|
| 511 | | - mmdc_num = mmdc_pmu_init(pmu_mmdc, mmdc_base, &pdev->dev); |
|---|
| 512 | | - pmu_mmdc->mmdc_ipg_clk = mmdc_ipg_clk; |
|---|
| 513 | | - if (mmdc_num == 0) |
|---|
| 514 | | - name = "mmdc"; |
|---|
| 515 | | - else |
|---|
| 516 | | - name = devm_kasprintf(&pdev->dev, |
|---|
| 517 | | - GFP_KERNEL, "mmdc%d", mmdc_num); |
|---|
| 499 | + ret = mmdc_pmu_init(pmu_mmdc, mmdc_base, &pdev->dev); |
|---|
| 500 | + if (ret < 0) |
|---|
| 501 | + goto pmu_free; |
|---|
| 518 | 502 | |
|---|
| 503 | + name = devm_kasprintf(&pdev->dev, |
|---|
| 504 | + GFP_KERNEL, "mmdc%d", ret); |
|---|
| 505 | + |
|---|
| 506 | + pmu_mmdc->mmdc_ipg_clk = mmdc_ipg_clk; |
|---|
| 519 | 507 | pmu_mmdc->devtype_data = (struct fsl_mmdc_devtype_data *)of_id->data; |
|---|
| 520 | 508 | |
|---|
| 521 | 509 | hrtimer_init(&pmu_mmdc->hrtimer, CLOCK_MONOTONIC, |
|---|
| .. | .. |
|---|
| 536 | 524 | |
|---|
| 537 | 525 | pmu_register_err: |
|---|
| 538 | 526 | pr_warn("MMDC Perf PMU failed (%d), disabled\n", ret); |
|---|
| 527 | + ida_simple_remove(&mmdc_ida, pmu_mmdc->id); |
|---|
| 539 | 528 | cpuhp_state_remove_instance_nocalls(cpuhp_mmdc_state, &pmu_mmdc->node); |
|---|
| 540 | 529 | hrtimer_cancel(&pmu_mmdc->hrtimer); |
|---|
| 541 | 530 | pmu_free: |
|---|