aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel/perf_event.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-09-30 00:27:06 -0400
committerDavid S. Miller <davem@davemloft.net>2009-09-30 00:27:06 -0400
commitd17513889a8b754c5872b6b46e6f7822338a0b79 (patch)
treeddf3d70d4bb3c0a565b4d229cb7cd204c13edb6b /arch/sparc/kernel/perf_event.c
parent6e804251d119bbd5522d76bdb0f48f5c9a7abf51 (diff)
sparc64: Cache per-cpu %pcr register value in perf code.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc/kernel/perf_event.c')
-rw-r--r--arch/sparc/kernel/perf_event.c59
1 files changed, 42 insertions, 17 deletions
diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c
index 32fc974bf8b5..04db92743896 100644
--- a/arch/sparc/kernel/perf_event.c
+++ b/arch/sparc/kernel/perf_event.c
@@ -56,7 +56,8 @@ struct cpu_hw_events {
56 struct perf_event *events[MAX_HWEVENTS]; 56 struct perf_event *events[MAX_HWEVENTS];
57 unsigned long used_mask[BITS_TO_LONGS(MAX_HWEVENTS)]; 57 unsigned long used_mask[BITS_TO_LONGS(MAX_HWEVENTS)];
58 unsigned long active_mask[BITS_TO_LONGS(MAX_HWEVENTS)]; 58 unsigned long active_mask[BITS_TO_LONGS(MAX_HWEVENTS)];
59 int enabled; 59 u64 pcr;
60 int enabled;
60}; 61};
61DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = { .enabled = 1, }; 62DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = { .enabled = 1, };
62 63
@@ -464,21 +465,30 @@ static u64 nop_for_index(int idx)
464 sparc_pmu->lower_nop, idx); 465 sparc_pmu->lower_nop, idx);
465} 466}
466 467
467static inline void sparc_pmu_enable_event(struct hw_perf_event *hwc, int idx) 468static inline void sparc_pmu_enable_event(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc, int idx)
468{ 469{
469 u64 val, mask = mask_for_index(idx); 470 u64 val, mask = mask_for_index(idx);
470 471
471 val = pcr_ops->read(); 472 val = cpuc->pcr;
472 pcr_ops->write((val & ~mask) | hwc->config); 473 val &= ~mask;
474 val |= hwc->config;
475 cpuc->pcr = val;
476
477 pcr_ops->write(cpuc->pcr);
473} 478}
474 479
475static inline void sparc_pmu_disable_event(struct hw_perf_event *hwc, int idx) 480static inline void sparc_pmu_disable_event(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc, int idx)
476{ 481{
477 u64 mask = mask_for_index(idx); 482 u64 mask = mask_for_index(idx);
478 u64 nop = nop_for_index(idx); 483 u64 nop = nop_for_index(idx);
479 u64 val = pcr_ops->read(); 484 u64 val;
480 485
481 pcr_ops->write((val & ~mask) | nop); 486 val = cpuc->pcr;
487 val &= ~mask;
488 val |= nop;
489 cpuc->pcr = val;
490
491 pcr_ops->write(cpuc->pcr);
482} 492}
483 493
484void hw_perf_enable(void) 494void hw_perf_enable(void)
@@ -493,7 +503,7 @@ void hw_perf_enable(void)
493 cpuc->enabled = 1; 503 cpuc->enabled = 1;
494 barrier(); 504 barrier();
495 505
496 val = pcr_ops->read(); 506 val = cpuc->pcr;
497 507
498 for (i = 0; i < MAX_HWEVENTS; i++) { 508 for (i = 0; i < MAX_HWEVENTS; i++) {
499 struct perf_event *cp = cpuc->events[i]; 509 struct perf_event *cp = cpuc->events[i];
@@ -505,7 +515,9 @@ void hw_perf_enable(void)
505 val |= hwc->config_base; 515 val |= hwc->config_base;
506 } 516 }
507 517
508 pcr_ops->write(val); 518 cpuc->pcr = val;
519
520 pcr_ops->write(cpuc->pcr);
509} 521}
510 522
511void hw_perf_disable(void) 523void hw_perf_disable(void)
@@ -518,10 +530,12 @@ void hw_perf_disable(void)
518 530
519 cpuc->enabled = 0; 531 cpuc->enabled = 0;
520 532
521 val = pcr_ops->read(); 533 val = cpuc->pcr;
522 val &= ~(PCR_UTRACE | PCR_STRACE | 534 val &= ~(PCR_UTRACE | PCR_STRACE |
523 sparc_pmu->hv_bit | sparc_pmu->irq_bit); 535 sparc_pmu->hv_bit | sparc_pmu->irq_bit);
524 pcr_ops->write(val); 536 cpuc->pcr = val;
537
538 pcr_ops->write(cpuc->pcr);
525} 539}
526 540
527static u32 read_pmc(int idx) 541static u32 read_pmc(int idx)
@@ -593,13 +607,13 @@ static int sparc_pmu_enable(struct perf_event *event)
593 if (test_and_set_bit(idx, cpuc->used_mask)) 607 if (test_and_set_bit(idx, cpuc->used_mask))
594 return -EAGAIN; 608 return -EAGAIN;
595 609
596 sparc_pmu_disable_event(hwc, idx); 610 sparc_pmu_disable_event(cpuc, hwc, idx);
597 611
598 cpuc->events[idx] = event; 612 cpuc->events[idx] = event;
599 set_bit(idx, cpuc->active_mask); 613 set_bit(idx, cpuc->active_mask);
600 614
601 sparc_perf_event_set_period(event, hwc, idx); 615 sparc_perf_event_set_period(event, hwc, idx);
602 sparc_pmu_enable_event(hwc, idx); 616 sparc_pmu_enable_event(cpuc, hwc, idx);
603 perf_event_update_userpage(event); 617 perf_event_update_userpage(event);
604 return 0; 618 return 0;
605} 619}
@@ -635,7 +649,7 @@ static void sparc_pmu_disable(struct perf_event *event)
635 int idx = hwc->idx; 649 int idx = hwc->idx;
636 650
637 clear_bit(idx, cpuc->active_mask); 651 clear_bit(idx, cpuc->active_mask);
638 sparc_pmu_disable_event(hwc, idx); 652 sparc_pmu_disable_event(cpuc, hwc, idx);
639 653
640 barrier(); 654 barrier();
641 655
@@ -649,18 +663,29 @@ static void sparc_pmu_disable(struct perf_event *event)
649static void sparc_pmu_read(struct perf_event *event) 663static void sparc_pmu_read(struct perf_event *event)
650{ 664{
651 struct hw_perf_event *hwc = &event->hw; 665 struct hw_perf_event *hwc = &event->hw;
666
652 sparc_perf_event_update(event, hwc, hwc->idx); 667 sparc_perf_event_update(event, hwc, hwc->idx);
653} 668}
654 669
655static void sparc_pmu_unthrottle(struct perf_event *event) 670static void sparc_pmu_unthrottle(struct perf_event *event)
656{ 671{
672 struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
657 struct hw_perf_event *hwc = &event->hw; 673 struct hw_perf_event *hwc = &event->hw;
658 sparc_pmu_enable_event(hwc, hwc->idx); 674
675 sparc_pmu_enable_event(cpuc, hwc, hwc->idx);
659} 676}
660 677
661static atomic_t active_events = ATOMIC_INIT(0); 678static atomic_t active_events = ATOMIC_INIT(0);
662static DEFINE_MUTEX(pmc_grab_mutex); 679static DEFINE_MUTEX(pmc_grab_mutex);
663 680
681static void perf_stop_nmi_watchdog(void *unused)
682{
683 struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
684
685 stop_nmi_watchdog(NULL);
686 cpuc->pcr = pcr_ops->read();
687}
688
664void perf_event_grab_pmc(void) 689void perf_event_grab_pmc(void)
665{ 690{
666 if (atomic_inc_not_zero(&active_events)) 691 if (atomic_inc_not_zero(&active_events))
@@ -669,7 +694,7 @@ void perf_event_grab_pmc(void)
669 mutex_lock(&pmc_grab_mutex); 694 mutex_lock(&pmc_grab_mutex);
670 if (atomic_read(&active_events) == 0) { 695 if (atomic_read(&active_events) == 0) {
671 if (atomic_read(&nmi_active) > 0) { 696 if (atomic_read(&nmi_active) > 0) {
672 on_each_cpu(stop_nmi_watchdog, NULL, 1); 697 on_each_cpu(perf_stop_nmi_watchdog, NULL, 1);
673 BUG_ON(atomic_read(&nmi_active) != 0); 698 BUG_ON(atomic_read(&nmi_active) != 0);
674 } 699 }
675 atomic_inc(&active_events); 700 atomic_inc(&active_events);
@@ -978,7 +1003,7 @@ static int __kprobes perf_event_nmi_handler(struct notifier_block *self,
978 continue; 1003 continue;
979 1004
980 if (perf_event_overflow(event, 1, &data, regs)) 1005 if (perf_event_overflow(event, 1, &data, regs))
981 sparc_pmu_disable_event(hwc, idx); 1006 sparc_pmu_disable_event(cpuc, hwc, idx);
982 } 1007 }
983 1008
984 return NOTIFY_STOP; 1009 return NOTIFY_STOP;