aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/kernel/perf_counter.c2
-rw-r--r--arch/x86/kernel/cpu/perf_counter.c3
-rw-r--r--include/linux/perf_counter.h4
-rw-r--r--kernel/perf_counter.c29
4 files changed, 28 insertions, 10 deletions
diff --git a/arch/powerpc/kernel/perf_counter.c b/arch/powerpc/kernel/perf_counter.c
index 0a4d14f279ae..f88c35d0710a 100644
--- a/arch/powerpc/kernel/perf_counter.c
+++ b/arch/powerpc/kernel/perf_counter.c
@@ -732,7 +732,7 @@ static void record_and_restart(struct perf_counter *counter, long val,
732 * Finally record data if requested. 732 * Finally record data if requested.
733 */ 733 */
734 if (record) 734 if (record)
735 perf_counter_output(counter, 1, regs); 735 perf_counter_overflow(counter, 1, regs);
736} 736}
737 737
738/* 738/*
diff --git a/arch/x86/kernel/cpu/perf_counter.c b/arch/x86/kernel/cpu/perf_counter.c
index 438415866fe4..1116a41bc7b5 100644
--- a/arch/x86/kernel/cpu/perf_counter.c
+++ b/arch/x86/kernel/cpu/perf_counter.c
@@ -800,7 +800,8 @@ again:
800 continue; 800 continue;
801 801
802 perf_save_and_restart(counter); 802 perf_save_and_restart(counter);
803 perf_counter_output(counter, nmi, regs); 803 if (perf_counter_overflow(counter, nmi, regs))
804 __pmc_generic_disable(counter, &counter->hw, bit);
804 } 805 }
805 806
806 hw_perf_ack_status(ack); 807 hw_perf_ack_status(ack);
diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h
index 977fb15a53f3..ca2d4df29e0c 100644
--- a/include/linux/perf_counter.h
+++ b/include/linux/perf_counter.h
@@ -491,8 +491,8 @@ extern int hw_perf_group_sched_in(struct perf_counter *group_leader,
491 struct perf_counter_context *ctx, int cpu); 491 struct perf_counter_context *ctx, int cpu);
492extern void perf_counter_update_userpage(struct perf_counter *counter); 492extern void perf_counter_update_userpage(struct perf_counter *counter);
493 493
494extern void perf_counter_output(struct perf_counter *counter, 494extern int perf_counter_overflow(struct perf_counter *counter,
495 int nmi, struct pt_regs *regs); 495 int nmi, struct pt_regs *regs);
496/* 496/*
497 * Return 1 for a software counter, 0 for a hardware counter 497 * Return 1 for a software counter, 0 for a hardware counter
498 */ 498 */
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c
index 0a2ade2e4f11..195e976eb07d 100644
--- a/kernel/perf_counter.c
+++ b/kernel/perf_counter.c
@@ -1800,8 +1800,8 @@ static void perf_output_end(struct perf_output_handle *handle)
1800 rcu_read_unlock(); 1800 rcu_read_unlock();
1801} 1801}
1802 1802
1803void perf_counter_output(struct perf_counter *counter, 1803static void perf_counter_output(struct perf_counter *counter,
1804 int nmi, struct pt_regs *regs) 1804 int nmi, struct pt_regs *regs)
1805{ 1805{
1806 int ret; 1806 int ret;
1807 u64 record_type = counter->hw_event.record_type; 1807 u64 record_type = counter->hw_event.record_type;
@@ -2034,6 +2034,17 @@ void perf_counter_munmap(unsigned long addr, unsigned long len,
2034} 2034}
2035 2035
2036/* 2036/*
2037 * Generic counter overflow handling.
2038 */
2039
2040int perf_counter_overflow(struct perf_counter *counter,
2041 int nmi, struct pt_regs *regs)
2042{
2043 perf_counter_output(counter, nmi, regs);
2044 return 0;
2045}
2046
2047/*
2037 * Generic software counter infrastructure 2048 * Generic software counter infrastructure
2038 */ 2049 */
2039 2050
@@ -2077,6 +2088,7 @@ static void perf_swcounter_set_period(struct perf_counter *counter)
2077 2088
2078static enum hrtimer_restart perf_swcounter_hrtimer(struct hrtimer *hrtimer) 2089static enum hrtimer_restart perf_swcounter_hrtimer(struct hrtimer *hrtimer)
2079{ 2090{
2091 enum hrtimer_restart ret = HRTIMER_RESTART;
2080 struct perf_counter *counter; 2092 struct perf_counter *counter;
2081 struct pt_regs *regs; 2093 struct pt_regs *regs;
2082 2094
@@ -2092,12 +2104,14 @@ static enum hrtimer_restart perf_swcounter_hrtimer(struct hrtimer *hrtimer)
2092 !counter->hw_event.exclude_user) 2104 !counter->hw_event.exclude_user)
2093 regs = task_pt_regs(current); 2105 regs = task_pt_regs(current);
2094 2106
2095 if (regs) 2107 if (regs) {
2096 perf_counter_output(counter, 0, regs); 2108 if (perf_counter_overflow(counter, 0, regs))
2109 ret = HRTIMER_NORESTART;
2110 }
2097 2111
2098 hrtimer_forward_now(hrtimer, ns_to_ktime(counter->hw.irq_period)); 2112 hrtimer_forward_now(hrtimer, ns_to_ktime(counter->hw.irq_period));
2099 2113
2100 return HRTIMER_RESTART; 2114 return ret;
2101} 2115}
2102 2116
2103static void perf_swcounter_overflow(struct perf_counter *counter, 2117static void perf_swcounter_overflow(struct perf_counter *counter,
@@ -2105,7 +2119,10 @@ static void perf_swcounter_overflow(struct perf_counter *counter,
2105{ 2119{
2106 perf_swcounter_update(counter); 2120 perf_swcounter_update(counter);
2107 perf_swcounter_set_period(counter); 2121 perf_swcounter_set_period(counter);
2108 perf_counter_output(counter, nmi, regs); 2122 if (perf_counter_overflow(counter, nmi, regs))
2123 /* soft-disable the counter */
2124 ;
2125
2109} 2126}
2110 2127
2111static int perf_swcounter_match(struct perf_counter *counter, 2128static int perf_swcounter_match(struct perf_counter *counter,