aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Rutland <mark.rutland@arm.com>2011-04-28 05:17:04 -0400
committerWill Deacon <will.deacon@arm.com>2011-08-31 05:50:07 -0400
commit0f78d2d5ccf72ec834da6901886a40fd8e3b7615 (patch)
treeda1262d040b2c10d95c6fc313b44e18801bcb4a3
parent1b69beb7684c79673995607939d8acab51056b63 (diff)
ARM: perf: lock PMU registers per-CPU
Currently, a single lock serialises access to CPU PMU registers. This global locking is unnecessary as PMU registers are local to the CPU they monitor. This patch replaces the global lock with a per-CPU lock. As the lock is in struct cpu_hw_events, PMUs providing a single cpu_hw_events instance can be locked globally. Signed-off-by: Mark Rutland <mark.rutland@arm.com> Reviewed-by: Will Deacon <will.deacon@arm.com> Reviewed-by: Jamie Iles <jamie@jamieiles.com> Reviewed-by: Ashwin Chaugule <ashwinc@codeaurora.org> Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r--arch/arm/kernel/perf_event.c17
-rw-r--r--arch/arm/kernel/perf_event_v6.c25
-rw-r--r--arch/arm/kernel/perf_event_v7.c20
-rw-r--r--arch/arm/kernel/perf_event_xscale.c40
4 files changed, 62 insertions, 40 deletions
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 5ce6c3332915..9331d5731445 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -27,12 +27,6 @@
27#include <asm/stacktrace.h> 27#include <asm/stacktrace.h>
28 28
29/* 29/*
30 * Hardware lock to serialize accesses to PMU registers. Needed for the
31 * read/modify/write sequences.
32 */
33static DEFINE_RAW_SPINLOCK(pmu_lock);
34
35/*
36 * ARMv6 supports a maximum of 3 events, starting from index 0. If we add 30 * ARMv6 supports a maximum of 3 events, starting from index 0. If we add
37 * another platform that supports more, we need to increase this to be the 31 * another platform that supports more, we need to increase this to be the
38 * largest of all platforms. 32 * largest of all platforms.
@@ -55,6 +49,12 @@ struct cpu_hw_events {
55 * an event. A 0 means that the counter can be used. 49 * an event. A 0 means that the counter can be used.
56 */ 50 */
57 unsigned long used_mask[BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)]; 51 unsigned long used_mask[BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)];
52
53 /*
54 * Hardware lock to serialize accesses to PMU registers. Needed for the
55 * read/modify/write sequences.
56 */
57 raw_spinlock_t pmu_lock;
58}; 58};
59static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events); 59static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
60 60
@@ -685,6 +685,11 @@ static struct cpu_hw_events *armpmu_get_cpu_events(void)
685 685
686static void __init cpu_pmu_init(struct arm_pmu *armpmu) 686static void __init cpu_pmu_init(struct arm_pmu *armpmu)
687{ 687{
688 int cpu;
689 for_each_possible_cpu(cpu) {
690 struct cpu_hw_events *events = &per_cpu(cpu_hw_events, cpu);
691 raw_spin_lock_init(&events->pmu_lock);
692 }
688 armpmu->get_hw_events = armpmu_get_cpu_events; 693 armpmu->get_hw_events = armpmu_get_cpu_events;
689} 694}
690 695
diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c
index 839012862264..68cf70425f2f 100644
--- a/arch/arm/kernel/perf_event_v6.c
+++ b/arch/arm/kernel/perf_event_v6.c
@@ -433,6 +433,7 @@ armv6pmu_enable_event(struct hw_perf_event *hwc,
433 int idx) 433 int idx)
434{ 434{
435 unsigned long val, mask, evt, flags; 435 unsigned long val, mask, evt, flags;
436 struct cpu_hw_events *events = armpmu->get_hw_events();
436 437
437 if (ARMV6_CYCLE_COUNTER == idx) { 438 if (ARMV6_CYCLE_COUNTER == idx) {
438 mask = 0; 439 mask = 0;
@@ -454,12 +455,12 @@ armv6pmu_enable_event(struct hw_perf_event *hwc,
454 * Mask out the current event and set the counter to count the event 455 * Mask out the current event and set the counter to count the event
455 * that we're interested in. 456 * that we're interested in.
456 */ 457 */
457 raw_spin_lock_irqsave(&pmu_lock, flags); 458 raw_spin_lock_irqsave(&events->pmu_lock, flags);
458 val = armv6_pmcr_read(); 459 val = armv6_pmcr_read();
459 val &= ~mask; 460 val &= ~mask;
460 val |= evt; 461 val |= evt;
461 armv6_pmcr_write(val); 462 armv6_pmcr_write(val);
462 raw_spin_unlock_irqrestore(&pmu_lock, flags); 463 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
463} 464}
464 465
465static int counter_is_active(unsigned long pmcr, int idx) 466static int counter_is_active(unsigned long pmcr, int idx)
@@ -544,24 +545,26 @@ static void
544armv6pmu_start(void) 545armv6pmu_start(void)
545{ 546{
546 unsigned long flags, val; 547 unsigned long flags, val;
548 struct cpu_hw_events *events = armpmu->get_hw_events();
547 549
548 raw_spin_lock_irqsave(&pmu_lock, flags); 550 raw_spin_lock_irqsave(&events->pmu_lock, flags);
549 val = armv6_pmcr_read(); 551 val = armv6_pmcr_read();
550 val |= ARMV6_PMCR_ENABLE; 552 val |= ARMV6_PMCR_ENABLE;
551 armv6_pmcr_write(val); 553 armv6_pmcr_write(val);
552 raw_spin_unlock_irqrestore(&pmu_lock, flags); 554 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
553} 555}
554 556
555static void 557static void
556armv6pmu_stop(void) 558armv6pmu_stop(void)
557{ 559{
558 unsigned long flags, val; 560 unsigned long flags, val;
561 struct cpu_hw_events *events = armpmu->get_hw_events();
559 562
560 raw_spin_lock_irqsave(&pmu_lock, flags); 563 raw_spin_lock_irqsave(&events->pmu_lock, flags);
561 val = armv6_pmcr_read(); 564 val = armv6_pmcr_read();
562 val &= ~ARMV6_PMCR_ENABLE; 565 val &= ~ARMV6_PMCR_ENABLE;
563 armv6_pmcr_write(val); 566 armv6_pmcr_write(val);
564 raw_spin_unlock_irqrestore(&pmu_lock, flags); 567 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
565} 568}
566 569
567static int 570static int
@@ -595,6 +598,7 @@ armv6pmu_disable_event(struct hw_perf_event *hwc,
595 int idx) 598 int idx)
596{ 599{
597 unsigned long val, mask, evt, flags; 600 unsigned long val, mask, evt, flags;
601 struct cpu_hw_events *events = armpmu->get_hw_events();
598 602
599 if (ARMV6_CYCLE_COUNTER == idx) { 603 if (ARMV6_CYCLE_COUNTER == idx) {
600 mask = ARMV6_PMCR_CCOUNT_IEN; 604 mask = ARMV6_PMCR_CCOUNT_IEN;
@@ -615,12 +619,12 @@ armv6pmu_disable_event(struct hw_perf_event *hwc,
615 * of ETM bus signal assertion cycles. The external reporting should 619 * of ETM bus signal assertion cycles. The external reporting should
616 * be disabled and so this should never increment. 620 * be disabled and so this should never increment.
617 */ 621 */
618 raw_spin_lock_irqsave(&pmu_lock, flags); 622 raw_spin_lock_irqsave(&events->pmu_lock, flags);
619 val = armv6_pmcr_read(); 623 val = armv6_pmcr_read();
620 val &= ~mask; 624 val &= ~mask;
621 val |= evt; 625 val |= evt;
622 armv6_pmcr_write(val); 626 armv6_pmcr_write(val);
623 raw_spin_unlock_irqrestore(&pmu_lock, flags); 627 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
624} 628}
625 629
626static void 630static void
@@ -628,6 +632,7 @@ armv6mpcore_pmu_disable_event(struct hw_perf_event *hwc,
628 int idx) 632 int idx)
629{ 633{
630 unsigned long val, mask, flags, evt = 0; 634 unsigned long val, mask, flags, evt = 0;
635 struct cpu_hw_events *events = armpmu->get_hw_events();
631 636
632 if (ARMV6_CYCLE_COUNTER == idx) { 637 if (ARMV6_CYCLE_COUNTER == idx) {
633 mask = ARMV6_PMCR_CCOUNT_IEN; 638 mask = ARMV6_PMCR_CCOUNT_IEN;
@@ -644,12 +649,12 @@ armv6mpcore_pmu_disable_event(struct hw_perf_event *hwc,
644 * Unlike UP ARMv6, we don't have a way of stopping the counters. We 649 * Unlike UP ARMv6, we don't have a way of stopping the counters. We
645 * simply disable the interrupt reporting. 650 * simply disable the interrupt reporting.
646 */ 651 */
647 raw_spin_lock_irqsave(&pmu_lock, flags); 652 raw_spin_lock_irqsave(&events->pmu_lock, flags);
648 val = armv6_pmcr_read(); 653 val = armv6_pmcr_read();
649 val &= ~mask; 654 val &= ~mask;
650 val |= evt; 655 val |= evt;
651 armv6_pmcr_write(val); 656 armv6_pmcr_write(val);
652 raw_spin_unlock_irqrestore(&pmu_lock, flags); 657 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
653} 658}
654 659
655static struct arm_pmu armv6pmu = { 660static struct arm_pmu armv6pmu = {
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index f4170fc228b6..68ac522fd940 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -936,12 +936,13 @@ static void armv7_pmnc_dump_regs(void)
936static void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx) 936static void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx)
937{ 937{
938 unsigned long flags; 938 unsigned long flags;
939 struct cpu_hw_events *events = armpmu->get_hw_events();
939 940
940 /* 941 /*
941 * Enable counter and interrupt, and set the counter to count 942 * Enable counter and interrupt, and set the counter to count
942 * the event that we're interested in. 943 * the event that we're interested in.
943 */ 944 */
944 raw_spin_lock_irqsave(&pmu_lock, flags); 945 raw_spin_lock_irqsave(&events->pmu_lock, flags);
945 946
946 /* 947 /*
947 * Disable counter 948 * Disable counter
@@ -966,17 +967,18 @@ static void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx)
966 */ 967 */
967 armv7_pmnc_enable_counter(idx); 968 armv7_pmnc_enable_counter(idx);
968 969
969 raw_spin_unlock_irqrestore(&pmu_lock, flags); 970 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
970} 971}
971 972
972static void armv7pmu_disable_event(struct hw_perf_event *hwc, int idx) 973static void armv7pmu_disable_event(struct hw_perf_event *hwc, int idx)
973{ 974{
974 unsigned long flags; 975 unsigned long flags;
976 struct cpu_hw_events *events = armpmu->get_hw_events();
975 977
976 /* 978 /*
977 * Disable counter and interrupt 979 * Disable counter and interrupt
978 */ 980 */
979 raw_spin_lock_irqsave(&pmu_lock, flags); 981 raw_spin_lock_irqsave(&events->pmu_lock, flags);
980 982
981 /* 983 /*
982 * Disable counter 984 * Disable counter
@@ -988,7 +990,7 @@ static void armv7pmu_disable_event(struct hw_perf_event *hwc, int idx)
988 */ 990 */
989 armv7_pmnc_disable_intens(idx); 991 armv7_pmnc_disable_intens(idx);
990 992
991 raw_spin_unlock_irqrestore(&pmu_lock, flags); 993 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
992} 994}
993 995
994static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev) 996static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)
@@ -1054,21 +1056,23 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)
1054static void armv7pmu_start(void) 1056static void armv7pmu_start(void)
1055{ 1057{
1056 unsigned long flags; 1058 unsigned long flags;
1059 struct cpu_hw_events *events = armpmu->get_hw_events();
1057 1060
1058 raw_spin_lock_irqsave(&pmu_lock, flags); 1061 raw_spin_lock_irqsave(&events->pmu_lock, flags);
1059 /* Enable all counters */ 1062 /* Enable all counters */
1060 armv7_pmnc_write(armv7_pmnc_read() | ARMV7_PMNC_E); 1063 armv7_pmnc_write(armv7_pmnc_read() | ARMV7_PMNC_E);
1061 raw_spin_unlock_irqrestore(&pmu_lock, flags); 1064 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
1062} 1065}
1063 1066
1064static void armv7pmu_stop(void) 1067static void armv7pmu_stop(void)
1065{ 1068{
1066 unsigned long flags; 1069 unsigned long flags;
1070 struct cpu_hw_events *events = armpmu->get_hw_events();
1067 1071
1068 raw_spin_lock_irqsave(&pmu_lock, flags); 1072 raw_spin_lock_irqsave(&events->pmu_lock, flags);
1069 /* Disable all counters */ 1073 /* Disable all counters */
1070 armv7_pmnc_write(armv7_pmnc_read() & ~ARMV7_PMNC_E); 1074 armv7_pmnc_write(armv7_pmnc_read() & ~ARMV7_PMNC_E);
1071 raw_spin_unlock_irqrestore(&pmu_lock, flags); 1075 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
1072} 1076}
1073 1077
1074static int armv7pmu_get_event_idx(struct cpu_hw_events *cpuc, 1078static int armv7pmu_get_event_idx(struct cpu_hw_events *cpuc,
diff --git a/arch/arm/kernel/perf_event_xscale.c b/arch/arm/kernel/perf_event_xscale.c
index ca89a06c8e92..18e4823a0a62 100644
--- a/arch/arm/kernel/perf_event_xscale.c
+++ b/arch/arm/kernel/perf_event_xscale.c
@@ -281,6 +281,7 @@ static void
281xscale1pmu_enable_event(struct hw_perf_event *hwc, int idx) 281xscale1pmu_enable_event(struct hw_perf_event *hwc, int idx)
282{ 282{
283 unsigned long val, mask, evt, flags; 283 unsigned long val, mask, evt, flags;
284 struct cpu_hw_events *events = armpmu->get_hw_events();
284 285
285 switch (idx) { 286 switch (idx) {
286 case XSCALE_CYCLE_COUNTER: 287 case XSCALE_CYCLE_COUNTER:
@@ -302,18 +303,19 @@ xscale1pmu_enable_event(struct hw_perf_event *hwc, int idx)
302 return; 303 return;
303 } 304 }
304 305
305 raw_spin_lock_irqsave(&pmu_lock, flags); 306 raw_spin_lock_irqsave(&events->pmu_lock, flags);
306 val = xscale1pmu_read_pmnc(); 307 val = xscale1pmu_read_pmnc();
307 val &= ~mask; 308 val &= ~mask;
308 val |= evt; 309 val |= evt;
309 xscale1pmu_write_pmnc(val); 310 xscale1pmu_write_pmnc(val);
310 raw_spin_unlock_irqrestore(&pmu_lock, flags); 311 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
311} 312}
312 313
313static void 314static void
314xscale1pmu_disable_event(struct hw_perf_event *hwc, int idx) 315xscale1pmu_disable_event(struct hw_perf_event *hwc, int idx)
315{ 316{
316 unsigned long val, mask, evt, flags; 317 unsigned long val, mask, evt, flags;
318 struct cpu_hw_events *events = armpmu->get_hw_events();
317 319
318 switch (idx) { 320 switch (idx) {
319 case XSCALE_CYCLE_COUNTER: 321 case XSCALE_CYCLE_COUNTER:
@@ -333,12 +335,12 @@ xscale1pmu_disable_event(struct hw_perf_event *hwc, int idx)
333 return; 335 return;
334 } 336 }
335 337
336 raw_spin_lock_irqsave(&pmu_lock, flags); 338 raw_spin_lock_irqsave(&events->pmu_lock, flags);
337 val = xscale1pmu_read_pmnc(); 339 val = xscale1pmu_read_pmnc();
338 val &= ~mask; 340 val &= ~mask;
339 val |= evt; 341 val |= evt;
340 xscale1pmu_write_pmnc(val); 342 xscale1pmu_write_pmnc(val);
341 raw_spin_unlock_irqrestore(&pmu_lock, flags); 343 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
342} 344}
343 345
344static int 346static int
@@ -365,24 +367,26 @@ static void
365xscale1pmu_start(void) 367xscale1pmu_start(void)
366{ 368{
367 unsigned long flags, val; 369 unsigned long flags, val;
370 struct cpu_hw_events *events = armpmu->get_hw_events();
368 371
369 raw_spin_lock_irqsave(&pmu_lock, flags); 372 raw_spin_lock_irqsave(&events->pmu_lock, flags);
370 val = xscale1pmu_read_pmnc(); 373 val = xscale1pmu_read_pmnc();
371 val |= XSCALE_PMU_ENABLE; 374 val |= XSCALE_PMU_ENABLE;
372 xscale1pmu_write_pmnc(val); 375 xscale1pmu_write_pmnc(val);
373 raw_spin_unlock_irqrestore(&pmu_lock, flags); 376 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
374} 377}
375 378
376static void 379static void
377xscale1pmu_stop(void) 380xscale1pmu_stop(void)
378{ 381{
379 unsigned long flags, val; 382 unsigned long flags, val;
383 struct cpu_hw_events *events = armpmu->get_hw_events();
380 384
381 raw_spin_lock_irqsave(&pmu_lock, flags); 385 raw_spin_lock_irqsave(&events->pmu_lock, flags);
382 val = xscale1pmu_read_pmnc(); 386 val = xscale1pmu_read_pmnc();
383 val &= ~XSCALE_PMU_ENABLE; 387 val &= ~XSCALE_PMU_ENABLE;
384 xscale1pmu_write_pmnc(val); 388 xscale1pmu_write_pmnc(val);
385 raw_spin_unlock_irqrestore(&pmu_lock, flags); 389 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
386} 390}
387 391
388static inline u32 392static inline u32
@@ -610,6 +614,7 @@ static void
610xscale2pmu_enable_event(struct hw_perf_event *hwc, int idx) 614xscale2pmu_enable_event(struct hw_perf_event *hwc, int idx)
611{ 615{
612 unsigned long flags, ien, evtsel; 616 unsigned long flags, ien, evtsel;
617 struct cpu_hw_events *events = armpmu->get_hw_events();
613 618
614 ien = xscale2pmu_read_int_enable(); 619 ien = xscale2pmu_read_int_enable();
615 evtsel = xscale2pmu_read_event_select(); 620 evtsel = xscale2pmu_read_event_select();
@@ -643,16 +648,17 @@ xscale2pmu_enable_event(struct hw_perf_event *hwc, int idx)
643 return; 648 return;
644 } 649 }
645 650
646 raw_spin_lock_irqsave(&pmu_lock, flags); 651 raw_spin_lock_irqsave(&events->pmu_lock, flags);
647 xscale2pmu_write_event_select(evtsel); 652 xscale2pmu_write_event_select(evtsel);
648 xscale2pmu_write_int_enable(ien); 653 xscale2pmu_write_int_enable(ien);
649 raw_spin_unlock_irqrestore(&pmu_lock, flags); 654 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
650} 655}
651 656
652static void 657static void
653xscale2pmu_disable_event(struct hw_perf_event *hwc, int idx) 658xscale2pmu_disable_event(struct hw_perf_event *hwc, int idx)
654{ 659{
655 unsigned long flags, ien, evtsel; 660 unsigned long flags, ien, evtsel;
661 struct cpu_hw_events *events = armpmu->get_hw_events();
656 662
657 ien = xscale2pmu_read_int_enable(); 663 ien = xscale2pmu_read_int_enable();
658 evtsel = xscale2pmu_read_event_select(); 664 evtsel = xscale2pmu_read_event_select();
@@ -686,10 +692,10 @@ xscale2pmu_disable_event(struct hw_perf_event *hwc, int idx)
686 return; 692 return;
687 } 693 }
688 694
689 raw_spin_lock_irqsave(&pmu_lock, flags); 695 raw_spin_lock_irqsave(&events->pmu_lock, flags);
690 xscale2pmu_write_event_select(evtsel); 696 xscale2pmu_write_event_select(evtsel);
691 xscale2pmu_write_int_enable(ien); 697 xscale2pmu_write_int_enable(ien);
692 raw_spin_unlock_irqrestore(&pmu_lock, flags); 698 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
693} 699}
694 700
695static int 701static int
@@ -712,24 +718,26 @@ static void
712xscale2pmu_start(void) 718xscale2pmu_start(void)
713{ 719{
714 unsigned long flags, val; 720 unsigned long flags, val;
721 struct cpu_hw_events *events = armpmu->get_hw_events();
715 722
716 raw_spin_lock_irqsave(&pmu_lock, flags); 723 raw_spin_lock_irqsave(&events->pmu_lock, flags);
717 val = xscale2pmu_read_pmnc() & ~XSCALE_PMU_CNT64; 724 val = xscale2pmu_read_pmnc() & ~XSCALE_PMU_CNT64;
718 val |= XSCALE_PMU_ENABLE; 725 val |= XSCALE_PMU_ENABLE;
719 xscale2pmu_write_pmnc(val); 726 xscale2pmu_write_pmnc(val);
720 raw_spin_unlock_irqrestore(&pmu_lock, flags); 727 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
721} 728}
722 729
723static void 730static void
724xscale2pmu_stop(void) 731xscale2pmu_stop(void)
725{ 732{
726 unsigned long flags, val; 733 unsigned long flags, val;
734 struct cpu_hw_events *events = armpmu->get_hw_events();
727 735
728 raw_spin_lock_irqsave(&pmu_lock, flags); 736 raw_spin_lock_irqsave(&events->pmu_lock, flags);
729 val = xscale2pmu_read_pmnc(); 737 val = xscale2pmu_read_pmnc();
730 val &= ~XSCALE_PMU_ENABLE; 738 val &= ~XSCALE_PMU_ENABLE;
731 xscale2pmu_write_pmnc(val); 739 xscale2pmu_write_pmnc(val);
732 raw_spin_unlock_irqrestore(&pmu_lock, flags); 740 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
733} 741}
734 742
735static inline u32 743static inline u32