aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/perf/arm_pmu.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/perf/arm_pmu.c')
-rw-r--r--drivers/perf/arm_pmu.c138
1 files changed, 61 insertions, 77 deletions
diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
index 7bc5eee96b31..f63db346c219 100644
--- a/drivers/perf/arm_pmu.c
+++ b/drivers/perf/arm_pmu.c
@@ -17,7 +17,6 @@
17#include <linux/export.h> 17#include <linux/export.h>
18#include <linux/kernel.h> 18#include <linux/kernel.h>
19#include <linux/perf/arm_pmu.h> 19#include <linux/perf/arm_pmu.h>
20#include <linux/platform_device.h>
21#include <linux/slab.h> 20#include <linux/slab.h>
22#include <linux/sched/clock.h> 21#include <linux/sched/clock.h>
23#include <linux/spinlock.h> 22#include <linux/spinlock.h>
@@ -26,6 +25,9 @@
26 25
27#include <asm/irq_regs.h> 26#include <asm/irq_regs.h>
28 27
28static DEFINE_PER_CPU(struct arm_pmu *, cpu_armpmu);
29static DEFINE_PER_CPU(int, cpu_irq);
30
29static int 31static int
30armpmu_map_cache_event(const unsigned (*cache_map) 32armpmu_map_cache_event(const unsigned (*cache_map)
31 [PERF_COUNT_HW_CACHE_MAX] 33 [PERF_COUNT_HW_CACHE_MAX]
@@ -320,17 +322,9 @@ validate_group(struct perf_event *event)
320 return 0; 322 return 0;
321} 323}
322 324
323static struct arm_pmu_platdata *armpmu_get_platdata(struct arm_pmu *armpmu)
324{
325 struct platform_device *pdev = armpmu->plat_device;
326
327 return pdev ? dev_get_platdata(&pdev->dev) : NULL;
328}
329
330static irqreturn_t armpmu_dispatch_irq(int irq, void *dev) 325static irqreturn_t armpmu_dispatch_irq(int irq, void *dev)
331{ 326{
332 struct arm_pmu *armpmu; 327 struct arm_pmu *armpmu;
333 struct arm_pmu_platdata *plat;
334 int ret; 328 int ret;
335 u64 start_clock, finish_clock; 329 u64 start_clock, finish_clock;
336 330
@@ -341,14 +335,11 @@ static irqreturn_t armpmu_dispatch_irq(int irq, void *dev)
341 * dereference. 335 * dereference.
342 */ 336 */
343 armpmu = *(void **)dev; 337 armpmu = *(void **)dev;
344 338 if (WARN_ON_ONCE(!armpmu))
345 plat = armpmu_get_platdata(armpmu); 339 return IRQ_NONE;
346 340
347 start_clock = sched_clock(); 341 start_clock = sched_clock();
348 if (plat && plat->handle_irq) 342 ret = armpmu->handle_irq(irq, armpmu);
349 ret = plat->handle_irq(irq, armpmu, armpmu->handle_irq);
350 else
351 ret = armpmu->handle_irq(irq, armpmu);
352 finish_clock = sched_clock(); 343 finish_clock = sched_clock();
353 344
354 perf_sample_event_took(finish_clock - start_clock); 345 perf_sample_event_took(finish_clock - start_clock);
@@ -531,54 +522,41 @@ int perf_num_counters(void)
531} 522}
532EXPORT_SYMBOL_GPL(perf_num_counters); 523EXPORT_SYMBOL_GPL(perf_num_counters);
533 524
534void armpmu_free_irq(struct arm_pmu *armpmu, int cpu) 525static int armpmu_count_irq_users(const int irq)
535{ 526{
536 struct pmu_hw_events __percpu *hw_events = armpmu->hw_events; 527 int cpu, count = 0;
537 int irq = per_cpu(hw_events->irq, cpu);
538 528
539 if (!cpumask_test_and_clear_cpu(cpu, &armpmu->active_irqs)) 529 for_each_possible_cpu(cpu) {
540 return; 530 if (per_cpu(cpu_irq, cpu) == irq)
541 531 count++;
542 if (irq_is_percpu_devid(irq)) {
543 free_percpu_irq(irq, &hw_events->percpu_pmu);
544 cpumask_clear(&armpmu->active_irqs);
545 return;
546 } 532 }
547 533
548 free_irq(irq, per_cpu_ptr(&hw_events->percpu_pmu, cpu)); 534 return count;
549} 535}
550 536
551void armpmu_free_irqs(struct arm_pmu *armpmu) 537void armpmu_free_irq(int irq, int cpu)
552{ 538{
553 int cpu; 539 if (per_cpu(cpu_irq, cpu) == 0)
540 return;
541 if (WARN_ON(irq != per_cpu(cpu_irq, cpu)))
542 return;
543
544 if (!irq_is_percpu_devid(irq))
545 free_irq(irq, per_cpu_ptr(&cpu_armpmu, cpu));
546 else if (armpmu_count_irq_users(irq) == 1)
547 free_percpu_irq(irq, &cpu_armpmu);
554 548
555 for_each_cpu(cpu, &armpmu->supported_cpus) 549 per_cpu(cpu_irq, cpu) = 0;
556 armpmu_free_irq(armpmu, cpu);
557} 550}
558 551
559int armpmu_request_irq(struct arm_pmu *armpmu, int cpu) 552int armpmu_request_irq(int irq, int cpu)
560{ 553{
561 int err = 0; 554 int err = 0;
562 struct pmu_hw_events __percpu *hw_events = armpmu->hw_events;
563 const irq_handler_t handler = armpmu_dispatch_irq; 555 const irq_handler_t handler = armpmu_dispatch_irq;
564 int irq = per_cpu(hw_events->irq, cpu);
565 if (!irq) 556 if (!irq)
566 return 0; 557 return 0;
567 558
568 if (irq_is_percpu_devid(irq) && cpumask_empty(&armpmu->active_irqs)) { 559 if (!irq_is_percpu_devid(irq)) {
569 err = request_percpu_irq(irq, handler, "arm-pmu",
570 &hw_events->percpu_pmu);
571 } else if (irq_is_percpu_devid(irq)) {
572 int other_cpu = cpumask_first(&armpmu->active_irqs);
573 int other_irq = per_cpu(hw_events->irq, other_cpu);
574
575 if (irq != other_irq) {
576 pr_warn("mismatched PPIs detected.\n");
577 err = -EINVAL;
578 goto err_out;
579 }
580 } else {
581 struct arm_pmu_platdata *platdata = armpmu_get_platdata(armpmu);
582 unsigned long irq_flags; 560 unsigned long irq_flags;
583 561
584 err = irq_force_affinity(irq, cpumask_of(cpu)); 562 err = irq_force_affinity(irq, cpumask_of(cpu));
@@ -589,22 +567,22 @@ int armpmu_request_irq(struct arm_pmu *armpmu, int cpu)
589 goto err_out; 567 goto err_out;
590 } 568 }
591 569
592 if (platdata && platdata->irq_flags) { 570 irq_flags = IRQF_PERCPU |
593 irq_flags = platdata->irq_flags; 571 IRQF_NOBALANCING |
594 } else { 572 IRQF_NO_THREAD;
595 irq_flags = IRQF_PERCPU |
596 IRQF_NOBALANCING |
597 IRQF_NO_THREAD;
598 }
599 573
574 irq_set_status_flags(irq, IRQ_NOAUTOEN);
600 err = request_irq(irq, handler, irq_flags, "arm-pmu", 575 err = request_irq(irq, handler, irq_flags, "arm-pmu",
601 per_cpu_ptr(&hw_events->percpu_pmu, cpu)); 576 per_cpu_ptr(&cpu_armpmu, cpu));
577 } else if (armpmu_count_irq_users(irq) == 0) {
578 err = request_percpu_irq(irq, handler, "arm-pmu",
579 &cpu_armpmu);
602 } 580 }
603 581
604 if (err) 582 if (err)
605 goto err_out; 583 goto err_out;
606 584
607 cpumask_set_cpu(cpu, &armpmu->active_irqs); 585 per_cpu(cpu_irq, cpu) = irq;
608 return 0; 586 return 0;
609 587
610err_out: 588err_out:
@@ -612,19 +590,6 @@ err_out:
612 return err; 590 return err;
613} 591}
614 592
615int armpmu_request_irqs(struct arm_pmu *armpmu)
616{
617 int cpu, err;
618
619 for_each_cpu(cpu, &armpmu->supported_cpus) {
620 err = armpmu_request_irq(armpmu, cpu);
621 if (err)
622 break;
623 }
624
625 return err;
626}
627
628static int armpmu_get_cpu_irq(struct arm_pmu *pmu, int cpu) 593static int armpmu_get_cpu_irq(struct arm_pmu *pmu, int cpu)
629{ 594{
630 struct pmu_hw_events __percpu *hw_events = pmu->hw_events; 595 struct pmu_hw_events __percpu *hw_events = pmu->hw_events;
@@ -647,12 +612,14 @@ static int arm_perf_starting_cpu(unsigned int cpu, struct hlist_node *node)
647 if (pmu->reset) 612 if (pmu->reset)
648 pmu->reset(pmu); 613 pmu->reset(pmu);
649 614
615 per_cpu(cpu_armpmu, cpu) = pmu;
616
650 irq = armpmu_get_cpu_irq(pmu, cpu); 617 irq = armpmu_get_cpu_irq(pmu, cpu);
651 if (irq) { 618 if (irq) {
652 if (irq_is_percpu_devid(irq)) { 619 if (irq_is_percpu_devid(irq))
653 enable_percpu_irq(irq, IRQ_TYPE_NONE); 620 enable_percpu_irq(irq, IRQ_TYPE_NONE);
654 return 0; 621 else
655 } 622 enable_irq(irq);
656 } 623 }
657 624
658 return 0; 625 return 0;
@@ -667,8 +634,14 @@ static int arm_perf_teardown_cpu(unsigned int cpu, struct hlist_node *node)
667 return 0; 634 return 0;
668 635
669 irq = armpmu_get_cpu_irq(pmu, cpu); 636 irq = armpmu_get_cpu_irq(pmu, cpu);
670 if (irq && irq_is_percpu_devid(irq)) 637 if (irq) {
671 disable_percpu_irq(irq); 638 if (irq_is_percpu_devid(irq))
639 disable_percpu_irq(irq);
640 else
641 disable_irq_nosync(irq);
642 }
643
644 per_cpu(cpu_armpmu, cpu) = NULL;
672 645
673 return 0; 646 return 0;
674} 647}
@@ -800,18 +773,18 @@ static void cpu_pmu_destroy(struct arm_pmu *cpu_pmu)
800 &cpu_pmu->node); 773 &cpu_pmu->node);
801} 774}
802 775
803struct arm_pmu *armpmu_alloc(void) 776static struct arm_pmu *__armpmu_alloc(gfp_t flags)
804{ 777{
805 struct arm_pmu *pmu; 778 struct arm_pmu *pmu;
806 int cpu; 779 int cpu;
807 780
808 pmu = kzalloc(sizeof(*pmu), GFP_KERNEL); 781 pmu = kzalloc(sizeof(*pmu), flags);
809 if (!pmu) { 782 if (!pmu) {
810 pr_info("failed to allocate PMU device!\n"); 783 pr_info("failed to allocate PMU device!\n");
811 goto out; 784 goto out;
812 } 785 }
813 786
814 pmu->hw_events = alloc_percpu(struct pmu_hw_events); 787 pmu->hw_events = alloc_percpu_gfp(struct pmu_hw_events, flags);
815 if (!pmu->hw_events) { 788 if (!pmu->hw_events) {
816 pr_info("failed to allocate per-cpu PMU data.\n"); 789 pr_info("failed to allocate per-cpu PMU data.\n");
817 goto out_free_pmu; 790 goto out_free_pmu;
@@ -857,6 +830,17 @@ out:
857 return NULL; 830 return NULL;
858} 831}
859 832
833struct arm_pmu *armpmu_alloc(void)
834{
835 return __armpmu_alloc(GFP_KERNEL);
836}
837
838struct arm_pmu *armpmu_alloc_atomic(void)
839{
840 return __armpmu_alloc(GFP_ATOMIC);
841}
842
843
860void armpmu_free(struct arm_pmu *pmu) 844void armpmu_free(struct arm_pmu *pmu)
861{ 845{
862 free_percpu(pmu->hw_events); 846 free_percpu(pmu->hw_events);