diff options
Diffstat (limited to 'arch/arm/kernel/perf_event.c')
| -rw-r--r-- | arch/arm/kernel/perf_event.c | 33 |
1 files changed, 25 insertions, 8 deletions
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index 22e194eb8536..979da3947f42 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c | |||
| @@ -79,6 +79,7 @@ struct arm_pmu { | |||
| 79 | void (*write_counter)(int idx, u32 val); | 79 | void (*write_counter)(int idx, u32 val); |
| 80 | void (*start)(void); | 80 | void (*start)(void); |
| 81 | void (*stop)(void); | 81 | void (*stop)(void); |
| 82 | void (*reset)(void *); | ||
| 82 | const unsigned (*cache_map)[PERF_COUNT_HW_CACHE_MAX] | 83 | const unsigned (*cache_map)[PERF_COUNT_HW_CACHE_MAX] |
| 83 | [PERF_COUNT_HW_CACHE_OP_MAX] | 84 | [PERF_COUNT_HW_CACHE_OP_MAX] |
| 84 | [PERF_COUNT_HW_CACHE_RESULT_MAX]; | 85 | [PERF_COUNT_HW_CACHE_RESULT_MAX]; |
| @@ -204,11 +205,9 @@ armpmu_event_set_period(struct perf_event *event, | |||
| 204 | static u64 | 205 | static u64 |
| 205 | armpmu_event_update(struct perf_event *event, | 206 | armpmu_event_update(struct perf_event *event, |
| 206 | struct hw_perf_event *hwc, | 207 | struct hw_perf_event *hwc, |
| 207 | int idx) | 208 | int idx, int overflow) |
| 208 | { | 209 | { |
| 209 | int shift = 64 - 32; | 210 | u64 delta, prev_raw_count, new_raw_count; |
| 210 | s64 prev_raw_count, new_raw_count; | ||
| 211 | u64 delta; | ||
| 212 | 211 | ||
| 213 | again: | 212 | again: |
| 214 | prev_raw_count = local64_read(&hwc->prev_count); | 213 | prev_raw_count = local64_read(&hwc->prev_count); |
| @@ -218,8 +217,13 @@ again: | |||
| 218 | new_raw_count) != prev_raw_count) | 217 | new_raw_count) != prev_raw_count) |
| 219 | goto again; | 218 | goto again; |
| 220 | 219 | ||
| 221 | delta = (new_raw_count << shift) - (prev_raw_count << shift); | 220 | new_raw_count &= armpmu->max_period; |
| 222 | delta >>= shift; | 221 | prev_raw_count &= armpmu->max_period; |
| 222 | |||
| 223 | if (overflow) | ||
| 224 | delta = armpmu->max_period - prev_raw_count + new_raw_count + 1; | ||
| 225 | else | ||
| 226 | delta = new_raw_count - prev_raw_count; | ||
| 223 | 227 | ||
| 224 | local64_add(delta, &event->count); | 228 | local64_add(delta, &event->count); |
| 225 | local64_sub(delta, &hwc->period_left); | 229 | local64_sub(delta, &hwc->period_left); |
| @@ -236,7 +240,7 @@ armpmu_read(struct perf_event *event) | |||
| 236 | if (hwc->idx < 0) | 240 | if (hwc->idx < 0) |
| 237 | return; | 241 | return; |
| 238 | 242 | ||
| 239 | armpmu_event_update(event, hwc, hwc->idx); | 243 | armpmu_event_update(event, hwc, hwc->idx, 0); |
| 240 | } | 244 | } |
| 241 | 245 | ||
| 242 | static void | 246 | static void |
| @@ -254,7 +258,7 @@ armpmu_stop(struct perf_event *event, int flags) | |||
| 254 | if (!(hwc->state & PERF_HES_STOPPED)) { | 258 | if (!(hwc->state & PERF_HES_STOPPED)) { |
| 255 | armpmu->disable(hwc, hwc->idx); | 259 | armpmu->disable(hwc, hwc->idx); |
| 256 | barrier(); /* why? */ | 260 | barrier(); /* why? */ |
| 257 | armpmu_event_update(event, hwc, hwc->idx); | 261 | armpmu_event_update(event, hwc, hwc->idx, 0); |
| 258 | hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE; | 262 | hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE; |
| 259 | } | 263 | } |
| 260 | } | 264 | } |
| @@ -624,6 +628,19 @@ static struct pmu pmu = { | |||
| 624 | #include "perf_event_v6.c" | 628 | #include "perf_event_v6.c" |
| 625 | #include "perf_event_v7.c" | 629 | #include "perf_event_v7.c" |
| 626 | 630 | ||
| 631 | /* | ||
| 632 | * Ensure the PMU has sane values out of reset. | ||
| 633 | * This requires SMP to be available, so exists as a separate initcall. | ||
| 634 | */ | ||
| 635 | static int __init | ||
| 636 | armpmu_reset(void) | ||
| 637 | { | ||
| 638 | if (armpmu && armpmu->reset) | ||
| 639 | return on_each_cpu(armpmu->reset, NULL, 1); | ||
| 640 | return 0; | ||
| 641 | } | ||
| 642 | arch_initcall(armpmu_reset); | ||
| 643 | |||
| 627 | static int __init | 644 | static int __init |
| 628 | init_hw_perf_events(void) | 645 | init_hw_perf_events(void) |
| 629 | { | 646 | { |
