diff options
| author | David S. Miller <davem@davemloft.net> | 2009-09-30 00:27:06 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2009-09-30 00:27:06 -0400 |
| commit | d17513889a8b754c5872b6b46e6f7822338a0b79 (patch) | |
| tree | ddf3d70d4bb3c0a565b4d229cb7cd204c13edb6b | |
| parent | 6e804251d119bbd5522d76bdb0f48f5c9a7abf51 (diff) | |
sparc64: Cache per-cpu %pcr register value in perf code.
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | arch/sparc/kernel/perf_event.c | 59 |
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 | }; |
| 61 | DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = { .enabled = 1, }; | 62 | DEFINE_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 | ||
| 467 | static inline void sparc_pmu_enable_event(struct hw_perf_event *hwc, int idx) | 468 | static 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 | ||
| 475 | static inline void sparc_pmu_disable_event(struct hw_perf_event *hwc, int idx) | 480 | static 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 | ||
| 484 | void hw_perf_enable(void) | 494 | void 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 | ||
| 511 | void hw_perf_disable(void) | 523 | void 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 | ||
| 527 | static u32 read_pmc(int idx) | 541 | static 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) | |||
| 649 | static void sparc_pmu_read(struct perf_event *event) | 663 | static 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 | ||
| 655 | static void sparc_pmu_unthrottle(struct perf_event *event) | 670 | static 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 | ||
| 661 | static atomic_t active_events = ATOMIC_INIT(0); | 678 | static atomic_t active_events = ATOMIC_INIT(0); |
| 662 | static DEFINE_MUTEX(pmc_grab_mutex); | 679 | static DEFINE_MUTEX(pmc_grab_mutex); |
| 663 | 680 | ||
| 681 | static 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 | |||
| 664 | void perf_event_grab_pmc(void) | 689 | void 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; |
