aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Zijlstra <a.p.zijlstra@chello.nl>2009-05-13 10:21:38 -0400
committerIngo Molnar <mingo@elte.hu>2009-05-15 03:47:02 -0400
commit9e35ad388bea89f7d6f375af4c0ae98803688666 (patch)
tree9abbce9f6c9a914b1ea8d8dae82e159366030e4a
parent962bf7a66edca4d36a730a38ff8410a67f560e40 (diff)
perf_counter: Rework the perf counter disable/enable
The current disable/enable mechanism is: token = hw_perf_save_disable(); ... /* do bits */ ... hw_perf_restore(token); This works well, provided that the use nests properly. Except we don't. x86 NMI/INT throttling has non-nested use of this, breaking things. Therefore provide a reference counter disable/enable interface, where the first disable disables the hardware, and the last enable enables the hardware again. [ Impact: refactor, simplify the PMU disable/enable logic ] Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Paul Mackerras <paulus@samba.org> Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com> LKML-Reference: <new-submission> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--arch/powerpc/kernel/perf_counter.c24
-rw-r--r--arch/x86/kernel/cpu/perf_counter.c113
-rw-r--r--drivers/acpi/processor_idle.c6
-rw-r--r--include/linux/perf_counter.h10
-rw-r--r--kernel/perf_counter.c76
5 files changed, 109 insertions, 120 deletions
diff --git a/arch/powerpc/kernel/perf_counter.c b/arch/powerpc/kernel/perf_counter.c
index 15cdc8e67229..bb1b463c1361 100644
--- a/arch/powerpc/kernel/perf_counter.c
+++ b/arch/powerpc/kernel/perf_counter.c
@@ -386,7 +386,7 @@ static void write_mmcr0(struct cpu_hw_counters *cpuhw, unsigned long mmcr0)
386 * Disable all counters to prevent PMU interrupts and to allow 386 * Disable all counters to prevent PMU interrupts and to allow
387 * counters to be added or removed. 387 * counters to be added or removed.
388 */ 388 */
389u64 hw_perf_save_disable(void) 389void hw_perf_disable(void)
390{ 390{
391 struct cpu_hw_counters *cpuhw; 391 struct cpu_hw_counters *cpuhw;
392 unsigned long ret; 392 unsigned long ret;
@@ -428,7 +428,6 @@ u64 hw_perf_save_disable(void)
428 mb(); 428 mb();
429 } 429 }
430 local_irq_restore(flags); 430 local_irq_restore(flags);
431 return ret;
432} 431}
433 432
434/* 433/*
@@ -436,7 +435,7 @@ u64 hw_perf_save_disable(void)
436 * If we were previously disabled and counters were added, then 435 * If we were previously disabled and counters were added, then
437 * put the new config on the PMU. 436 * put the new config on the PMU.
438 */ 437 */
439void hw_perf_restore(u64 disable) 438void hw_perf_enable(void)
440{ 439{
441 struct perf_counter *counter; 440 struct perf_counter *counter;
442 struct cpu_hw_counters *cpuhw; 441 struct cpu_hw_counters *cpuhw;
@@ -448,9 +447,12 @@ void hw_perf_restore(u64 disable)
448 int n_lim; 447 int n_lim;
449 int idx; 448 int idx;
450 449
451 if (disable)
452 return;
453 local_irq_save(flags); 450 local_irq_save(flags);
451 if (!cpuhw->disabled) {
452 local_irq_restore(flags);
453 return;
454 }
455
454 cpuhw = &__get_cpu_var(cpu_hw_counters); 456 cpuhw = &__get_cpu_var(cpu_hw_counters);
455 cpuhw->disabled = 0; 457 cpuhw->disabled = 0;
456 458
@@ -649,19 +651,18 @@ int hw_perf_group_sched_in(struct perf_counter *group_leader,
649/* 651/*
650 * Add a counter to the PMU. 652 * Add a counter to the PMU.
651 * If all counters are not already frozen, then we disable and 653 * If all counters are not already frozen, then we disable and
652 * re-enable the PMU in order to get hw_perf_restore to do the 654 * re-enable the PMU in order to get hw_perf_enable to do the
653 * actual work of reconfiguring the PMU. 655 * actual work of reconfiguring the PMU.
654 */ 656 */
655static int power_pmu_enable(struct perf_counter *counter) 657static int power_pmu_enable(struct perf_counter *counter)
656{ 658{
657 struct cpu_hw_counters *cpuhw; 659 struct cpu_hw_counters *cpuhw;
658 unsigned long flags; 660 unsigned long flags;
659 u64 pmudis;
660 int n0; 661 int n0;
661 int ret = -EAGAIN; 662 int ret = -EAGAIN;
662 663
663 local_irq_save(flags); 664 local_irq_save(flags);
664 pmudis = hw_perf_save_disable(); 665 perf_disable();
665 666
666 /* 667 /*
667 * Add the counter to the list (if there is room) 668 * Add the counter to the list (if there is room)
@@ -685,7 +686,7 @@ static int power_pmu_enable(struct perf_counter *counter)
685 686
686 ret = 0; 687 ret = 0;
687 out: 688 out:
688 hw_perf_restore(pmudis); 689 perf_enable();
689 local_irq_restore(flags); 690 local_irq_restore(flags);
690 return ret; 691 return ret;
691} 692}
@@ -697,11 +698,10 @@ static void power_pmu_disable(struct perf_counter *counter)
697{ 698{
698 struct cpu_hw_counters *cpuhw; 699 struct cpu_hw_counters *cpuhw;
699 long i; 700 long i;
700 u64 pmudis;
701 unsigned long flags; 701 unsigned long flags;
702 702
703 local_irq_save(flags); 703 local_irq_save(flags);
704 pmudis = hw_perf_save_disable(); 704 perf_disable();
705 705
706 power_pmu_read(counter); 706 power_pmu_read(counter);
707 707
@@ -735,7 +735,7 @@ static void power_pmu_disable(struct perf_counter *counter)
735 cpuhw->mmcr[0] &= ~(MMCR0_PMXE | MMCR0_FCECE); 735 cpuhw->mmcr[0] &= ~(MMCR0_PMXE | MMCR0_FCECE);
736 } 736 }
737 737
738 hw_perf_restore(pmudis); 738 perf_enable();
739 local_irq_restore(flags); 739 local_irq_restore(flags);
740} 740}
741 741
diff --git a/arch/x86/kernel/cpu/perf_counter.c b/arch/x86/kernel/cpu/perf_counter.c
index 7601c014f8f6..313638cecbb5 100644
--- a/arch/x86/kernel/cpu/perf_counter.c
+++ b/arch/x86/kernel/cpu/perf_counter.c
@@ -31,7 +31,6 @@ struct cpu_hw_counters {
31 unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)]; 31 unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
32 unsigned long active_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)]; 32 unsigned long active_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
33 unsigned long interrupts; 33 unsigned long interrupts;
34 u64 throttle_ctrl;
35 int enabled; 34 int enabled;
36}; 35};
37 36
@@ -42,8 +41,8 @@ struct x86_pmu {
42 const char *name; 41 const char *name;
43 int version; 42 int version;
44 int (*handle_irq)(struct pt_regs *, int); 43 int (*handle_irq)(struct pt_regs *, int);
45 u64 (*save_disable_all)(void); 44 void (*disable_all)(void);
46 void (*restore_all)(u64); 45 void (*enable_all)(void);
47 void (*enable)(struct hw_perf_counter *, int); 46 void (*enable)(struct hw_perf_counter *, int);
48 void (*disable)(struct hw_perf_counter *, int); 47 void (*disable)(struct hw_perf_counter *, int);
49 unsigned eventsel; 48 unsigned eventsel;
@@ -56,6 +55,7 @@ struct x86_pmu {
56 int counter_bits; 55 int counter_bits;
57 u64 counter_mask; 56 u64 counter_mask;
58 u64 max_period; 57 u64 max_period;
58 u64 intel_ctrl;
59}; 59};
60 60
61static struct x86_pmu x86_pmu __read_mostly; 61static struct x86_pmu x86_pmu __read_mostly;
@@ -311,22 +311,19 @@ static int __hw_perf_counter_init(struct perf_counter *counter)
311 return 0; 311 return 0;
312} 312}
313 313
314static u64 intel_pmu_save_disable_all(void) 314static void intel_pmu_disable_all(void)
315{ 315{
316 u64 ctrl;
317
318 rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, ctrl);
319 wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0); 316 wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0);
320
321 return ctrl;
322} 317}
323 318
324static u64 amd_pmu_save_disable_all(void) 319static void amd_pmu_disable_all(void)
325{ 320{
326 struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters); 321 struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
327 int enabled, idx; 322 int idx;
323
324 if (!cpuc->enabled)
325 return;
328 326
329 enabled = cpuc->enabled;
330 cpuc->enabled = 0; 327 cpuc->enabled = 0;
331 /* 328 /*
332 * ensure we write the disable before we start disabling the 329 * ensure we write the disable before we start disabling the
@@ -334,8 +331,6 @@ static u64 amd_pmu_save_disable_all(void)
334 * right thing. 331 * right thing.
335 */ 332 */
336 barrier(); 333 barrier();
337 if (!enabled)
338 goto out;
339 334
340 for (idx = 0; idx < x86_pmu.num_counters; idx++) { 335 for (idx = 0; idx < x86_pmu.num_counters; idx++) {
341 u64 val; 336 u64 val;
@@ -348,37 +343,31 @@ static u64 amd_pmu_save_disable_all(void)
348 val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE; 343 val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE;
349 wrmsrl(MSR_K7_EVNTSEL0 + idx, val); 344 wrmsrl(MSR_K7_EVNTSEL0 + idx, val);
350 } 345 }
351
352out:
353 return enabled;
354} 346}
355 347
356u64 hw_perf_save_disable(void) 348void hw_perf_disable(void)
357{ 349{
358 if (!x86_pmu_initialized()) 350 if (!x86_pmu_initialized())
359 return 0; 351 return;
360 return x86_pmu.save_disable_all(); 352 return x86_pmu.disable_all();
361} 353}
362/*
363 * Exported because of ACPI idle
364 */
365EXPORT_SYMBOL_GPL(hw_perf_save_disable);
366 354
367static void intel_pmu_restore_all(u64 ctrl) 355static void intel_pmu_enable_all(void)
368{ 356{
369 wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, ctrl); 357 wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, x86_pmu.intel_ctrl);
370} 358}
371 359
372static void amd_pmu_restore_all(u64 ctrl) 360static void amd_pmu_enable_all(void)
373{ 361{
374 struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters); 362 struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
375 int idx; 363 int idx;
376 364
377 cpuc->enabled = ctrl; 365 if (cpuc->enabled)
378 barrier();
379 if (!ctrl)
380 return; 366 return;
381 367
368 cpuc->enabled = 1;
369 barrier();
370
382 for (idx = 0; idx < x86_pmu.num_counters; idx++) { 371 for (idx = 0; idx < x86_pmu.num_counters; idx++) {
383 u64 val; 372 u64 val;
384 373
@@ -392,16 +381,12 @@ static void amd_pmu_restore_all(u64 ctrl)
392 } 381 }
393} 382}
394 383
395void hw_perf_restore(u64 ctrl) 384void hw_perf_enable(void)
396{ 385{
397 if (!x86_pmu_initialized()) 386 if (!x86_pmu_initialized())
398 return; 387 return;
399 x86_pmu.restore_all(ctrl); 388 x86_pmu.enable_all();
400} 389}
401/*
402 * Exported because of ACPI idle
403 */
404EXPORT_SYMBOL_GPL(hw_perf_restore);
405 390
406static inline u64 intel_pmu_get_status(void) 391static inline u64 intel_pmu_get_status(void)
407{ 392{
@@ -735,15 +720,14 @@ static int intel_pmu_handle_irq(struct pt_regs *regs, int nmi)
735 int bit, cpu = smp_processor_id(); 720 int bit, cpu = smp_processor_id();
736 u64 ack, status; 721 u64 ack, status;
737 struct cpu_hw_counters *cpuc = &per_cpu(cpu_hw_counters, cpu); 722 struct cpu_hw_counters *cpuc = &per_cpu(cpu_hw_counters, cpu);
738 int ret = 0;
739
740 cpuc->throttle_ctrl = intel_pmu_save_disable_all();
741 723
724 perf_disable();
742 status = intel_pmu_get_status(); 725 status = intel_pmu_get_status();
743 if (!status) 726 if (!status) {
744 goto out; 727 perf_enable();
728 return 0;
729 }
745 730
746 ret = 1;
747again: 731again:
748 inc_irq_stat(apic_perf_irqs); 732 inc_irq_stat(apic_perf_irqs);
749 ack = status; 733 ack = status;
@@ -767,19 +751,11 @@ again:
767 status = intel_pmu_get_status(); 751 status = intel_pmu_get_status();
768 if (status) 752 if (status)
769 goto again; 753 goto again;
770out:
771 /*
772 * Restore - do not reenable when global enable is off or throttled:
773 */
774 if (cpuc->throttle_ctrl) {
775 if (++cpuc->interrupts < PERFMON_MAX_INTERRUPTS) {
776 intel_pmu_restore_all(cpuc->throttle_ctrl);
777 } else {
778 pr_info("CPU#%d: perfcounters: max interrupt rate exceeded! Throttle on.\n", smp_processor_id());
779 }
780 }
781 754
782 return ret; 755 if (++cpuc->interrupts != PERFMON_MAX_INTERRUPTS)
756 perf_enable();
757
758 return 1;
783} 759}
784 760
785static int amd_pmu_handle_irq(struct pt_regs *regs, int nmi) 761static int amd_pmu_handle_irq(struct pt_regs *regs, int nmi)
@@ -792,13 +768,11 @@ static int amd_pmu_handle_irq(struct pt_regs *regs, int nmi)
792 struct hw_perf_counter *hwc; 768 struct hw_perf_counter *hwc;
793 int idx, throttle = 0; 769 int idx, throttle = 0;
794 770
795 cpuc->throttle_ctrl = cpuc->enabled; 771 if (++cpuc->interrupts == PERFMON_MAX_INTERRUPTS) {
796 cpuc->enabled = 0; 772 throttle = 1;
797 barrier(); 773 __perf_disable();
798 774 cpuc->enabled = 0;
799 if (cpuc->throttle_ctrl) { 775 barrier();
800 if (++cpuc->interrupts >= PERFMON_MAX_INTERRUPTS)
801 throttle = 1;
802 } 776 }
803 777
804 for (idx = 0; idx < x86_pmu.num_counters; idx++) { 778 for (idx = 0; idx < x86_pmu.num_counters; idx++) {
@@ -824,9 +798,6 @@ next:
824 amd_pmu_disable_counter(hwc, idx); 798 amd_pmu_disable_counter(hwc, idx);
825 } 799 }
826 800
827 if (cpuc->throttle_ctrl && !throttle)
828 cpuc->enabled = 1;
829
830 return handled; 801 return handled;
831} 802}
832 803
@@ -839,13 +810,11 @@ void perf_counter_unthrottle(void)
839 810
840 cpuc = &__get_cpu_var(cpu_hw_counters); 811 cpuc = &__get_cpu_var(cpu_hw_counters);
841 if (cpuc->interrupts >= PERFMON_MAX_INTERRUPTS) { 812 if (cpuc->interrupts >= PERFMON_MAX_INTERRUPTS) {
842 pr_info("CPU#%d: perfcounters: throttle off.\n", smp_processor_id());
843
844 /* 813 /*
845 * Clear them before re-enabling irqs/NMIs again: 814 * Clear them before re-enabling irqs/NMIs again:
846 */ 815 */
847 cpuc->interrupts = 0; 816 cpuc->interrupts = 0;
848 hw_perf_restore(cpuc->throttle_ctrl); 817 perf_enable();
849 } else { 818 } else {
850 cpuc->interrupts = 0; 819 cpuc->interrupts = 0;
851 } 820 }
@@ -931,8 +900,8 @@ static __read_mostly struct notifier_block perf_counter_nmi_notifier = {
931static struct x86_pmu intel_pmu = { 900static struct x86_pmu intel_pmu = {
932 .name = "Intel", 901 .name = "Intel",
933 .handle_irq = intel_pmu_handle_irq, 902 .handle_irq = intel_pmu_handle_irq,
934 .save_disable_all = intel_pmu_save_disable_all, 903 .disable_all = intel_pmu_disable_all,
935 .restore_all = intel_pmu_restore_all, 904 .enable_all = intel_pmu_enable_all,
936 .enable = intel_pmu_enable_counter, 905 .enable = intel_pmu_enable_counter,
937 .disable = intel_pmu_disable_counter, 906 .disable = intel_pmu_disable_counter,
938 .eventsel = MSR_ARCH_PERFMON_EVENTSEL0, 907 .eventsel = MSR_ARCH_PERFMON_EVENTSEL0,
@@ -951,8 +920,8 @@ static struct x86_pmu intel_pmu = {
951static struct x86_pmu amd_pmu = { 920static struct x86_pmu amd_pmu = {
952 .name = "AMD", 921 .name = "AMD",
953 .handle_irq = amd_pmu_handle_irq, 922 .handle_irq = amd_pmu_handle_irq,
954 .save_disable_all = amd_pmu_save_disable_all, 923 .disable_all = amd_pmu_disable_all,
955 .restore_all = amd_pmu_restore_all, 924 .enable_all = amd_pmu_enable_all,
956 .enable = amd_pmu_enable_counter, 925 .enable = amd_pmu_enable_counter,
957 .disable = amd_pmu_disable_counter, 926 .disable = amd_pmu_disable_counter,
958 .eventsel = MSR_K7_EVNTSEL0, 927 .eventsel = MSR_K7_EVNTSEL0,
@@ -1003,6 +972,8 @@ static int intel_pmu_init(void)
1003 x86_pmu.counter_bits = eax.split.bit_width; 972 x86_pmu.counter_bits = eax.split.bit_width;
1004 x86_pmu.counter_mask = (1ULL << eax.split.bit_width) - 1; 973 x86_pmu.counter_mask = (1ULL << eax.split.bit_width) - 1;
1005 974
975 rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, x86_pmu.intel_ctrl);
976
1006 return 0; 977 return 0;
1007} 978}
1008 979
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index d2830f39d46b..9645758c0472 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -763,11 +763,9 @@ static int acpi_idle_bm_check(void)
763 */ 763 */
764static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx) 764static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx)
765{ 765{
766 u64 perf_flags;
767
768 /* Don't trace irqs off for idle */ 766 /* Don't trace irqs off for idle */
769 stop_critical_timings(); 767 stop_critical_timings();
770 perf_flags = hw_perf_save_disable(); 768 perf_disable();
771 if (cx->entry_method == ACPI_CSTATE_FFH) { 769 if (cx->entry_method == ACPI_CSTATE_FFH) {
772 /* Call into architectural FFH based C-state */ 770 /* Call into architectural FFH based C-state */
773 acpi_processor_ffh_cstate_enter(cx); 771 acpi_processor_ffh_cstate_enter(cx);
@@ -782,7 +780,7 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx)
782 gets asserted in time to freeze execution properly. */ 780 gets asserted in time to freeze execution properly. */
783 unused = inl(acpi_gbl_FADT.xpm_timer_block.address); 781 unused = inl(acpi_gbl_FADT.xpm_timer_block.address);
784 } 782 }
785 hw_perf_restore(perf_flags); 783 perf_enable();
786 start_critical_timings(); 784 start_critical_timings();
787} 785}
788 786
diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h
index 614f921d616a..e543ecc129f1 100644
--- a/include/linux/perf_counter.h
+++ b/include/linux/perf_counter.h
@@ -544,8 +544,10 @@ extern void perf_counter_exit_task(struct task_struct *child);
544extern void perf_counter_do_pending(void); 544extern void perf_counter_do_pending(void);
545extern void perf_counter_print_debug(void); 545extern void perf_counter_print_debug(void);
546extern void perf_counter_unthrottle(void); 546extern void perf_counter_unthrottle(void);
547extern u64 hw_perf_save_disable(void); 547extern void __perf_disable(void);
548extern void hw_perf_restore(u64 ctrl); 548extern bool __perf_enable(void);
549extern void perf_disable(void);
550extern void perf_enable(void);
549extern int perf_counter_task_disable(void); 551extern int perf_counter_task_disable(void);
550extern int perf_counter_task_enable(void); 552extern int perf_counter_task_enable(void);
551extern int hw_perf_group_sched_in(struct perf_counter *group_leader, 553extern int hw_perf_group_sched_in(struct perf_counter *group_leader,
@@ -600,8 +602,8 @@ static inline void perf_counter_exit_task(struct task_struct *child) { }
600static inline void perf_counter_do_pending(void) { } 602static inline void perf_counter_do_pending(void) { }
601static inline void perf_counter_print_debug(void) { } 603static inline void perf_counter_print_debug(void) { }
602static inline void perf_counter_unthrottle(void) { } 604static inline void perf_counter_unthrottle(void) { }
603static inline void hw_perf_restore(u64 ctrl) { } 605static inline void perf_disable(void) { }
604static inline u64 hw_perf_save_disable(void) { return 0; } 606static inline void perf_enable(void) { }
605static inline int perf_counter_task_disable(void) { return -EINVAL; } 607static inline int perf_counter_task_disable(void) { return -EINVAL; }
606static inline int perf_counter_task_enable(void) { return -EINVAL; } 608static inline int perf_counter_task_enable(void) { return -EINVAL; }
607 609
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c
index 985be0b662af..e814ff04d7ca 100644
--- a/kernel/perf_counter.c
+++ b/kernel/perf_counter.c
@@ -60,8 +60,9 @@ extern __weak const struct pmu *hw_perf_counter_init(struct perf_counter *counte
60 return NULL; 60 return NULL;
61} 61}
62 62
63u64 __weak hw_perf_save_disable(void) { return 0; } 63void __weak hw_perf_disable(void) { barrier(); }
64void __weak hw_perf_restore(u64 ctrl) { barrier(); } 64void __weak hw_perf_enable(void) { barrier(); }
65
65void __weak hw_perf_counter_setup(int cpu) { barrier(); } 66void __weak hw_perf_counter_setup(int cpu) { barrier(); }
66int __weak hw_perf_group_sched_in(struct perf_counter *group_leader, 67int __weak hw_perf_group_sched_in(struct perf_counter *group_leader,
67 struct perf_cpu_context *cpuctx, 68 struct perf_cpu_context *cpuctx,
@@ -72,6 +73,32 @@ int __weak hw_perf_group_sched_in(struct perf_counter *group_leader,
72 73
73void __weak perf_counter_print_debug(void) { } 74void __weak perf_counter_print_debug(void) { }
74 75
76static DEFINE_PER_CPU(int, disable_count);
77
78void __perf_disable(void)
79{
80 __get_cpu_var(disable_count)++;
81}
82
83bool __perf_enable(void)
84{
85 return !--__get_cpu_var(disable_count);
86}
87
88void perf_disable(void)
89{
90 __perf_disable();
91 hw_perf_disable();
92}
93EXPORT_SYMBOL_GPL(perf_disable); /* ACPI idle */
94
95void perf_enable(void)
96{
97 if (__perf_enable())
98 hw_perf_enable();
99}
100EXPORT_SYMBOL_GPL(perf_enable); /* ACPI idle */
101
75static void 102static void
76list_add_counter(struct perf_counter *counter, struct perf_counter_context *ctx) 103list_add_counter(struct perf_counter *counter, struct perf_counter_context *ctx)
77{ 104{
@@ -170,7 +197,6 @@ static void __perf_counter_remove_from_context(void *info)
170 struct perf_counter *counter = info; 197 struct perf_counter *counter = info;
171 struct perf_counter_context *ctx = counter->ctx; 198 struct perf_counter_context *ctx = counter->ctx;
172 unsigned long flags; 199 unsigned long flags;
173 u64 perf_flags;
174 200
175 /* 201 /*
176 * If this is a task context, we need to check whether it is 202 * If this is a task context, we need to check whether it is
@@ -191,9 +217,9 @@ static void __perf_counter_remove_from_context(void *info)
191 * Protect the list operation against NMI by disabling the 217 * Protect the list operation against NMI by disabling the
192 * counters on a global level. NOP for non NMI based counters. 218 * counters on a global level. NOP for non NMI based counters.
193 */ 219 */
194 perf_flags = hw_perf_save_disable(); 220 perf_disable();
195 list_del_counter(counter, ctx); 221 list_del_counter(counter, ctx);
196 hw_perf_restore(perf_flags); 222 perf_enable();
197 223
198 if (!ctx->task) { 224 if (!ctx->task) {
199 /* 225 /*
@@ -538,7 +564,6 @@ static void __perf_install_in_context(void *info)
538 struct perf_counter *leader = counter->group_leader; 564 struct perf_counter *leader = counter->group_leader;
539 int cpu = smp_processor_id(); 565 int cpu = smp_processor_id();
540 unsigned long flags; 566 unsigned long flags;
541 u64 perf_flags;
542 int err; 567 int err;
543 568
544 /* 569 /*
@@ -556,7 +581,7 @@ static void __perf_install_in_context(void *info)
556 * Protect the list operation against NMI by disabling the 581 * Protect the list operation against NMI by disabling the
557 * counters on a global level. NOP for non NMI based counters. 582 * counters on a global level. NOP for non NMI based counters.
558 */ 583 */
559 perf_flags = hw_perf_save_disable(); 584 perf_disable();
560 585
561 add_counter_to_ctx(counter, ctx); 586 add_counter_to_ctx(counter, ctx);
562 587
@@ -596,7 +621,7 @@ static void __perf_install_in_context(void *info)
596 cpuctx->max_pertask--; 621 cpuctx->max_pertask--;
597 622
598 unlock: 623 unlock:
599 hw_perf_restore(perf_flags); 624 perf_enable();
600 625
601 spin_unlock_irqrestore(&ctx->lock, flags); 626 spin_unlock_irqrestore(&ctx->lock, flags);
602} 627}
@@ -663,7 +688,6 @@ static void __perf_counter_enable(void *info)
663 struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); 688 struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context);
664 struct perf_counter_context *ctx = counter->ctx; 689 struct perf_counter_context *ctx = counter->ctx;
665 struct perf_counter *leader = counter->group_leader; 690 struct perf_counter *leader = counter->group_leader;
666 unsigned long pmuflags;
667 unsigned long flags; 691 unsigned long flags;
668 int err; 692 int err;
669 693
@@ -693,14 +717,14 @@ static void __perf_counter_enable(void *info)
693 if (!group_can_go_on(counter, cpuctx, 1)) { 717 if (!group_can_go_on(counter, cpuctx, 1)) {
694 err = -EEXIST; 718 err = -EEXIST;
695 } else { 719 } else {
696 pmuflags = hw_perf_save_disable(); 720 perf_disable();
697 if (counter == leader) 721 if (counter == leader)
698 err = group_sched_in(counter, cpuctx, ctx, 722 err = group_sched_in(counter, cpuctx, ctx,
699 smp_processor_id()); 723 smp_processor_id());
700 else 724 else
701 err = counter_sched_in(counter, cpuctx, ctx, 725 err = counter_sched_in(counter, cpuctx, ctx,
702 smp_processor_id()); 726 smp_processor_id());
703 hw_perf_restore(pmuflags); 727 perf_enable();
704 } 728 }
705 729
706 if (err) { 730 if (err) {
@@ -795,7 +819,6 @@ void __perf_counter_sched_out(struct perf_counter_context *ctx,
795 struct perf_cpu_context *cpuctx) 819 struct perf_cpu_context *cpuctx)
796{ 820{
797 struct perf_counter *counter; 821 struct perf_counter *counter;
798 u64 flags;
799 822
800 spin_lock(&ctx->lock); 823 spin_lock(&ctx->lock);
801 ctx->is_active = 0; 824 ctx->is_active = 0;
@@ -803,12 +826,12 @@ void __perf_counter_sched_out(struct perf_counter_context *ctx,
803 goto out; 826 goto out;
804 update_context_time(ctx); 827 update_context_time(ctx);
805 828
806 flags = hw_perf_save_disable(); 829 perf_disable();
807 if (ctx->nr_active) { 830 if (ctx->nr_active) {
808 list_for_each_entry(counter, &ctx->counter_list, list_entry) 831 list_for_each_entry(counter, &ctx->counter_list, list_entry)
809 group_sched_out(counter, cpuctx, ctx); 832 group_sched_out(counter, cpuctx, ctx);
810 } 833 }
811 hw_perf_restore(flags); 834 perf_enable();
812 out: 835 out:
813 spin_unlock(&ctx->lock); 836 spin_unlock(&ctx->lock);
814} 837}
@@ -860,7 +883,6 @@ __perf_counter_sched_in(struct perf_counter_context *ctx,
860 struct perf_cpu_context *cpuctx, int cpu) 883 struct perf_cpu_context *cpuctx, int cpu)
861{ 884{
862 struct perf_counter *counter; 885 struct perf_counter *counter;
863 u64 flags;
864 int can_add_hw = 1; 886 int can_add_hw = 1;
865 887
866 spin_lock(&ctx->lock); 888 spin_lock(&ctx->lock);
@@ -870,7 +892,7 @@ __perf_counter_sched_in(struct perf_counter_context *ctx,
870 892
871 ctx->timestamp = perf_clock(); 893 ctx->timestamp = perf_clock();
872 894
873 flags = hw_perf_save_disable(); 895 perf_disable();
874 896
875 /* 897 /*
876 * First go through the list and put on any pinned groups 898 * First go through the list and put on any pinned groups
@@ -917,7 +939,7 @@ __perf_counter_sched_in(struct perf_counter_context *ctx,
917 can_add_hw = 0; 939 can_add_hw = 0;
918 } 940 }
919 } 941 }
920 hw_perf_restore(flags); 942 perf_enable();
921 out: 943 out:
922 spin_unlock(&ctx->lock); 944 spin_unlock(&ctx->lock);
923} 945}
@@ -955,7 +977,6 @@ int perf_counter_task_disable(void)
955 struct perf_counter_context *ctx = &curr->perf_counter_ctx; 977 struct perf_counter_context *ctx = &curr->perf_counter_ctx;
956 struct perf_counter *counter; 978 struct perf_counter *counter;
957 unsigned long flags; 979 unsigned long flags;
958 u64 perf_flags;
959 980
960 if (likely(!ctx->nr_counters)) 981 if (likely(!ctx->nr_counters))
961 return 0; 982 return 0;
@@ -969,7 +990,7 @@ int perf_counter_task_disable(void)
969 /* 990 /*
970 * Disable all the counters: 991 * Disable all the counters:
971 */ 992 */
972 perf_flags = hw_perf_save_disable(); 993 perf_disable();
973 994
974 list_for_each_entry(counter, &ctx->counter_list, list_entry) { 995 list_for_each_entry(counter, &ctx->counter_list, list_entry) {
975 if (counter->state != PERF_COUNTER_STATE_ERROR) { 996 if (counter->state != PERF_COUNTER_STATE_ERROR) {
@@ -978,7 +999,7 @@ int perf_counter_task_disable(void)
978 } 999 }
979 } 1000 }
980 1001
981 hw_perf_restore(perf_flags); 1002 perf_enable();
982 1003
983 spin_unlock_irqrestore(&ctx->lock, flags); 1004 spin_unlock_irqrestore(&ctx->lock, flags);
984 1005
@@ -991,7 +1012,6 @@ int perf_counter_task_enable(void)
991 struct perf_counter_context *ctx = &curr->perf_counter_ctx; 1012 struct perf_counter_context *ctx = &curr->perf_counter_ctx;
992 struct perf_counter *counter; 1013 struct perf_counter *counter;
993 unsigned long flags; 1014 unsigned long flags;
994 u64 perf_flags;
995 int cpu; 1015 int cpu;
996 1016
997 if (likely(!ctx->nr_counters)) 1017 if (likely(!ctx->nr_counters))
@@ -1007,7 +1027,7 @@ int perf_counter_task_enable(void)
1007 /* 1027 /*
1008 * Disable all the counters: 1028 * Disable all the counters:
1009 */ 1029 */
1010 perf_flags = hw_perf_save_disable(); 1030 perf_disable();
1011 1031
1012 list_for_each_entry(counter, &ctx->counter_list, list_entry) { 1032 list_for_each_entry(counter, &ctx->counter_list, list_entry) {
1013 if (counter->state > PERF_COUNTER_STATE_OFF) 1033 if (counter->state > PERF_COUNTER_STATE_OFF)
@@ -1017,7 +1037,7 @@ int perf_counter_task_enable(void)
1017 ctx->time - counter->total_time_enabled; 1037 ctx->time - counter->total_time_enabled;
1018 counter->hw_event.disabled = 0; 1038 counter->hw_event.disabled = 0;
1019 } 1039 }
1020 hw_perf_restore(perf_flags); 1040 perf_enable();
1021 1041
1022 spin_unlock(&ctx->lock); 1042 spin_unlock(&ctx->lock);
1023 1043
@@ -1034,7 +1054,6 @@ int perf_counter_task_enable(void)
1034static void rotate_ctx(struct perf_counter_context *ctx) 1054static void rotate_ctx(struct perf_counter_context *ctx)
1035{ 1055{
1036 struct perf_counter *counter; 1056 struct perf_counter *counter;
1037 u64 perf_flags;
1038 1057
1039 if (!ctx->nr_counters) 1058 if (!ctx->nr_counters)
1040 return; 1059 return;
@@ -1043,12 +1062,12 @@ static void rotate_ctx(struct perf_counter_context *ctx)
1043 /* 1062 /*
1044 * Rotate the first entry last (works just fine for group counters too): 1063 * Rotate the first entry last (works just fine for group counters too):
1045 */ 1064 */
1046 perf_flags = hw_perf_save_disable(); 1065 perf_disable();
1047 list_for_each_entry(counter, &ctx->counter_list, list_entry) { 1066 list_for_each_entry(counter, &ctx->counter_list, list_entry) {
1048 list_move_tail(&counter->list_entry, &ctx->counter_list); 1067 list_move_tail(&counter->list_entry, &ctx->counter_list);
1049 break; 1068 break;
1050 } 1069 }
1051 hw_perf_restore(perf_flags); 1070 perf_enable();
1052 1071
1053 spin_unlock(&ctx->lock); 1072 spin_unlock(&ctx->lock);
1054} 1073}
@@ -3194,7 +3213,6 @@ __perf_counter_exit_task(struct task_struct *child,
3194 } else { 3213 } else {
3195 struct perf_cpu_context *cpuctx; 3214 struct perf_cpu_context *cpuctx;
3196 unsigned long flags; 3215 unsigned long flags;
3197 u64 perf_flags;
3198 3216
3199 /* 3217 /*
3200 * Disable and unlink this counter. 3218 * Disable and unlink this counter.
@@ -3203,7 +3221,7 @@ __perf_counter_exit_task(struct task_struct *child,
3203 * could still be processing it: 3221 * could still be processing it:
3204 */ 3222 */
3205 local_irq_save(flags); 3223 local_irq_save(flags);
3206 perf_flags = hw_perf_save_disable(); 3224 perf_disable();
3207 3225
3208 cpuctx = &__get_cpu_var(perf_cpu_context); 3226 cpuctx = &__get_cpu_var(perf_cpu_context);
3209 3227
@@ -3214,7 +3232,7 @@ __perf_counter_exit_task(struct task_struct *child,
3214 3232
3215 child_ctx->nr_counters--; 3233 child_ctx->nr_counters--;
3216 3234
3217 hw_perf_restore(perf_flags); 3235 perf_enable();
3218 local_irq_restore(flags); 3236 local_irq_restore(flags);
3219 } 3237 }
3220 3238