diff options
-rw-r--r-- | arch/powerpc/kernel/perf_counter.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/perf_counter.c | 3 | ||||
-rw-r--r-- | include/linux/perf_counter.h | 4 | ||||
-rw-r--r-- | kernel/perf_counter.c | 29 |
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); |
492 | extern void perf_counter_update_userpage(struct perf_counter *counter); | 492 | extern void perf_counter_update_userpage(struct perf_counter *counter); |
493 | 493 | ||
494 | extern void perf_counter_output(struct perf_counter *counter, | 494 | extern 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 | ||
1803 | void perf_counter_output(struct perf_counter *counter, | 1803 | static 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 | |||
2040 | int 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 | ||
2078 | static enum hrtimer_restart perf_swcounter_hrtimer(struct hrtimer *hrtimer) | 2089 | static 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 | ||
2103 | static void perf_swcounter_overflow(struct perf_counter *counter, | 2117 | static 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 | ||
2111 | static int perf_swcounter_match(struct perf_counter *counter, | 2128 | static int perf_swcounter_match(struct perf_counter *counter, |