diff options
Diffstat (limited to 'arch/powerpc/kernel/perf_counter.c')
-rw-r--r-- | arch/powerpc/kernel/perf_counter.c | 68 |
1 files changed, 35 insertions, 33 deletions
diff --git a/arch/powerpc/kernel/perf_counter.c b/arch/powerpc/kernel/perf_counter.c index 70e1f57f7dd8..7ceefaf3a7f5 100644 --- a/arch/powerpc/kernel/perf_counter.c +++ b/arch/powerpc/kernel/perf_counter.c | |||
@@ -32,6 +32,9 @@ struct cpu_hw_counters { | |||
32 | unsigned long mmcr[3]; | 32 | unsigned long mmcr[3]; |
33 | struct perf_counter *limited_counter[MAX_LIMITED_HWCOUNTERS]; | 33 | struct perf_counter *limited_counter[MAX_LIMITED_HWCOUNTERS]; |
34 | u8 limited_hwidx[MAX_LIMITED_HWCOUNTERS]; | 34 | u8 limited_hwidx[MAX_LIMITED_HWCOUNTERS]; |
35 | u64 alternatives[MAX_HWCOUNTERS][MAX_EVENT_ALTERNATIVES]; | ||
36 | unsigned long amasks[MAX_HWCOUNTERS][MAX_EVENT_ALTERNATIVES]; | ||
37 | unsigned long avalues[MAX_HWCOUNTERS][MAX_EVENT_ALTERNATIVES]; | ||
35 | }; | 38 | }; |
36 | DEFINE_PER_CPU(struct cpu_hw_counters, cpu_hw_counters); | 39 | DEFINE_PER_CPU(struct cpu_hw_counters, cpu_hw_counters); |
37 | 40 | ||
@@ -62,7 +65,6 @@ static inline unsigned long perf_ip_adjust(struct pt_regs *regs) | |||
62 | { | 65 | { |
63 | return 0; | 66 | return 0; |
64 | } | 67 | } |
65 | static inline void perf_set_pmu_inuse(int inuse) { } | ||
66 | static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp) { } | 68 | static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp) { } |
67 | static inline u32 perf_get_misc_flags(struct pt_regs *regs) | 69 | static inline u32 perf_get_misc_flags(struct pt_regs *regs) |
68 | { | 70 | { |
@@ -93,11 +95,6 @@ static inline unsigned long perf_ip_adjust(struct pt_regs *regs) | |||
93 | return 0; | 95 | return 0; |
94 | } | 96 | } |
95 | 97 | ||
96 | static inline void perf_set_pmu_inuse(int inuse) | ||
97 | { | ||
98 | get_lppaca()->pmcregs_in_use = inuse; | ||
99 | } | ||
100 | |||
101 | /* | 98 | /* |
102 | * The user wants a data address recorded. | 99 | * The user wants a data address recorded. |
103 | * If we're not doing instruction sampling, give them the SDAR | 100 | * If we're not doing instruction sampling, give them the SDAR |
@@ -245,13 +242,11 @@ static void write_pmc(int idx, unsigned long val) | |||
245 | * and see if any combination of alternative codes is feasible. | 242 | * and see if any combination of alternative codes is feasible. |
246 | * The feasible set is returned in event[]. | 243 | * The feasible set is returned in event[]. |
247 | */ | 244 | */ |
248 | static int power_check_constraints(u64 event[], unsigned int cflags[], | 245 | static int power_check_constraints(struct cpu_hw_counters *cpuhw, |
246 | u64 event[], unsigned int cflags[], | ||
249 | int n_ev) | 247 | int n_ev) |
250 | { | 248 | { |
251 | unsigned long mask, value, nv; | 249 | unsigned long mask, value, nv; |
252 | u64 alternatives[MAX_HWCOUNTERS][MAX_EVENT_ALTERNATIVES]; | ||
253 | unsigned long amasks[MAX_HWCOUNTERS][MAX_EVENT_ALTERNATIVES]; | ||
254 | unsigned long avalues[MAX_HWCOUNTERS][MAX_EVENT_ALTERNATIVES]; | ||
255 | unsigned long smasks[MAX_HWCOUNTERS], svalues[MAX_HWCOUNTERS]; | 250 | unsigned long smasks[MAX_HWCOUNTERS], svalues[MAX_HWCOUNTERS]; |
256 | int n_alt[MAX_HWCOUNTERS], choice[MAX_HWCOUNTERS]; | 251 | int n_alt[MAX_HWCOUNTERS], choice[MAX_HWCOUNTERS]; |
257 | int i, j; | 252 | int i, j; |
@@ -266,21 +261,23 @@ static int power_check_constraints(u64 event[], unsigned int cflags[], | |||
266 | if ((cflags[i] & PPMU_LIMITED_PMC_REQD) | 261 | if ((cflags[i] & PPMU_LIMITED_PMC_REQD) |
267 | && !ppmu->limited_pmc_event(event[i])) { | 262 | && !ppmu->limited_pmc_event(event[i])) { |
268 | ppmu->get_alternatives(event[i], cflags[i], | 263 | ppmu->get_alternatives(event[i], cflags[i], |
269 | alternatives[i]); | 264 | cpuhw->alternatives[i]); |
270 | event[i] = alternatives[i][0]; | 265 | event[i] = cpuhw->alternatives[i][0]; |
271 | } | 266 | } |
272 | if (ppmu->get_constraint(event[i], &amasks[i][0], | 267 | if (ppmu->get_constraint(event[i], &cpuhw->amasks[i][0], |
273 | &avalues[i][0])) | 268 | &cpuhw->avalues[i][0])) |
274 | return -1; | 269 | return -1; |
275 | } | 270 | } |
276 | value = mask = 0; | 271 | value = mask = 0; |
277 | for (i = 0; i < n_ev; ++i) { | 272 | for (i = 0; i < n_ev; ++i) { |
278 | nv = (value | avalues[i][0]) + (value & avalues[i][0] & addf); | 273 | nv = (value | cpuhw->avalues[i][0]) + |
274 | (value & cpuhw->avalues[i][0] & addf); | ||
279 | if ((((nv + tadd) ^ value) & mask) != 0 || | 275 | if ((((nv + tadd) ^ value) & mask) != 0 || |
280 | (((nv + tadd) ^ avalues[i][0]) & amasks[i][0]) != 0) | 276 | (((nv + tadd) ^ cpuhw->avalues[i][0]) & |
277 | cpuhw->amasks[i][0]) != 0) | ||
281 | break; | 278 | break; |
282 | value = nv; | 279 | value = nv; |
283 | mask |= amasks[i][0]; | 280 | mask |= cpuhw->amasks[i][0]; |
284 | } | 281 | } |
285 | if (i == n_ev) | 282 | if (i == n_ev) |
286 | return 0; /* all OK */ | 283 | return 0; /* all OK */ |
@@ -291,10 +288,11 @@ static int power_check_constraints(u64 event[], unsigned int cflags[], | |||
291 | for (i = 0; i < n_ev; ++i) { | 288 | for (i = 0; i < n_ev; ++i) { |
292 | choice[i] = 0; | 289 | choice[i] = 0; |
293 | n_alt[i] = ppmu->get_alternatives(event[i], cflags[i], | 290 | n_alt[i] = ppmu->get_alternatives(event[i], cflags[i], |
294 | alternatives[i]); | 291 | cpuhw->alternatives[i]); |
295 | for (j = 1; j < n_alt[i]; ++j) | 292 | for (j = 1; j < n_alt[i]; ++j) |
296 | ppmu->get_constraint(alternatives[i][j], | 293 | ppmu->get_constraint(cpuhw->alternatives[i][j], |
297 | &amasks[i][j], &avalues[i][j]); | 294 | &cpuhw->amasks[i][j], |
295 | &cpuhw->avalues[i][j]); | ||
298 | } | 296 | } |
299 | 297 | ||
300 | /* enumerate all possibilities and see if any will work */ | 298 | /* enumerate all possibilities and see if any will work */ |
@@ -313,11 +311,11 @@ static int power_check_constraints(u64 event[], unsigned int cflags[], | |||
313 | * where k > j, will satisfy the constraints. | 311 | * where k > j, will satisfy the constraints. |
314 | */ | 312 | */ |
315 | while (++j < n_alt[i]) { | 313 | while (++j < n_alt[i]) { |
316 | nv = (value | avalues[i][j]) + | 314 | nv = (value | cpuhw->avalues[i][j]) + |
317 | (value & avalues[i][j] & addf); | 315 | (value & cpuhw->avalues[i][j] & addf); |
318 | if ((((nv + tadd) ^ value) & mask) == 0 && | 316 | if ((((nv + tadd) ^ value) & mask) == 0 && |
319 | (((nv + tadd) ^ avalues[i][j]) | 317 | (((nv + tadd) ^ cpuhw->avalues[i][j]) |
320 | & amasks[i][j]) == 0) | 318 | & cpuhw->amasks[i][j]) == 0) |
321 | break; | 319 | break; |
322 | } | 320 | } |
323 | if (j >= n_alt[i]) { | 321 | if (j >= n_alt[i]) { |
@@ -339,7 +337,7 @@ static int power_check_constraints(u64 event[], unsigned int cflags[], | |||
339 | svalues[i] = value; | 337 | svalues[i] = value; |
340 | smasks[i] = mask; | 338 | smasks[i] = mask; |
341 | value = nv; | 339 | value = nv; |
342 | mask |= amasks[i][j]; | 340 | mask |= cpuhw->amasks[i][j]; |
343 | ++i; | 341 | ++i; |
344 | j = -1; | 342 | j = -1; |
345 | } | 343 | } |
@@ -347,7 +345,7 @@ static int power_check_constraints(u64 event[], unsigned int cflags[], | |||
347 | 345 | ||
348 | /* OK, we have a feasible combination, tell the caller the solution */ | 346 | /* OK, we have a feasible combination, tell the caller the solution */ |
349 | for (i = 0; i < n_ev; ++i) | 347 | for (i = 0; i < n_ev; ++i) |
350 | event[i] = alternatives[i][choice[i]]; | 348 | event[i] = cpuhw->alternatives[i][choice[i]]; |
351 | return 0; | 349 | return 0; |
352 | } | 350 | } |
353 | 351 | ||
@@ -531,8 +529,7 @@ void hw_perf_disable(void) | |||
531 | * Check if we ever enabled the PMU on this cpu. | 529 | * Check if we ever enabled the PMU on this cpu. |
532 | */ | 530 | */ |
533 | if (!cpuhw->pmcs_enabled) { | 531 | if (!cpuhw->pmcs_enabled) { |
534 | if (ppc_md.enable_pmcs) | 532 | ppc_enable_pmcs(); |
535 | ppc_md.enable_pmcs(); | ||
536 | cpuhw->pmcs_enabled = 1; | 533 | cpuhw->pmcs_enabled = 1; |
537 | } | 534 | } |
538 | 535 | ||
@@ -594,7 +591,7 @@ void hw_perf_enable(void) | |||
594 | mtspr(SPRN_MMCRA, cpuhw->mmcr[2] & ~MMCRA_SAMPLE_ENABLE); | 591 | mtspr(SPRN_MMCRA, cpuhw->mmcr[2] & ~MMCRA_SAMPLE_ENABLE); |
595 | mtspr(SPRN_MMCR1, cpuhw->mmcr[1]); | 592 | mtspr(SPRN_MMCR1, cpuhw->mmcr[1]); |
596 | if (cpuhw->n_counters == 0) | 593 | if (cpuhw->n_counters == 0) |
597 | perf_set_pmu_inuse(0); | 594 | ppc_set_pmu_inuse(0); |
598 | goto out_enable; | 595 | goto out_enable; |
599 | } | 596 | } |
600 | 597 | ||
@@ -627,7 +624,7 @@ void hw_perf_enable(void) | |||
627 | * bit set and set the hardware counters to their initial values. | 624 | * bit set and set the hardware counters to their initial values. |
628 | * Then unfreeze the counters. | 625 | * Then unfreeze the counters. |
629 | */ | 626 | */ |
630 | perf_set_pmu_inuse(1); | 627 | ppc_set_pmu_inuse(1); |
631 | mtspr(SPRN_MMCRA, cpuhw->mmcr[2] & ~MMCRA_SAMPLE_ENABLE); | 628 | mtspr(SPRN_MMCRA, cpuhw->mmcr[2] & ~MMCRA_SAMPLE_ENABLE); |
632 | mtspr(SPRN_MMCR1, cpuhw->mmcr[1]); | 629 | mtspr(SPRN_MMCR1, cpuhw->mmcr[1]); |
633 | mtspr(SPRN_MMCR0, (cpuhw->mmcr[0] & ~(MMCR0_PMC1CE | MMCR0_PMCjCE)) | 630 | mtspr(SPRN_MMCR0, (cpuhw->mmcr[0] & ~(MMCR0_PMC1CE | MMCR0_PMCjCE)) |
@@ -752,7 +749,7 @@ int hw_perf_group_sched_in(struct perf_counter *group_leader, | |||
752 | return -EAGAIN; | 749 | return -EAGAIN; |
753 | if (check_excludes(cpuhw->counter, cpuhw->flags, n0, n)) | 750 | if (check_excludes(cpuhw->counter, cpuhw->flags, n0, n)) |
754 | return -EAGAIN; | 751 | return -EAGAIN; |
755 | i = power_check_constraints(cpuhw->events, cpuhw->flags, n + n0); | 752 | i = power_check_constraints(cpuhw, cpuhw->events, cpuhw->flags, n + n0); |
756 | if (i < 0) | 753 | if (i < 0) |
757 | return -EAGAIN; | 754 | return -EAGAIN; |
758 | cpuhw->n_counters = n0 + n; | 755 | cpuhw->n_counters = n0 + n; |
@@ -807,7 +804,7 @@ static int power_pmu_enable(struct perf_counter *counter) | |||
807 | cpuhw->flags[n0] = counter->hw.counter_base; | 804 | cpuhw->flags[n0] = counter->hw.counter_base; |
808 | if (check_excludes(cpuhw->counter, cpuhw->flags, n0, 1)) | 805 | if (check_excludes(cpuhw->counter, cpuhw->flags, n0, 1)) |
809 | goto out; | 806 | goto out; |
810 | if (power_check_constraints(cpuhw->events, cpuhw->flags, n0 + 1)) | 807 | if (power_check_constraints(cpuhw, cpuhw->events, cpuhw->flags, n0 + 1)) |
811 | goto out; | 808 | goto out; |
812 | 809 | ||
813 | counter->hw.config = cpuhw->events[n0]; | 810 | counter->hw.config = cpuhw->events[n0]; |
@@ -1012,6 +1009,7 @@ const struct pmu *hw_perf_counter_init(struct perf_counter *counter) | |||
1012 | unsigned int cflags[MAX_HWCOUNTERS]; | 1009 | unsigned int cflags[MAX_HWCOUNTERS]; |
1013 | int n; | 1010 | int n; |
1014 | int err; | 1011 | int err; |
1012 | struct cpu_hw_counters *cpuhw; | ||
1015 | 1013 | ||
1016 | if (!ppmu) | 1014 | if (!ppmu) |
1017 | return ERR_PTR(-ENXIO); | 1015 | return ERR_PTR(-ENXIO); |
@@ -1090,7 +1088,11 @@ const struct pmu *hw_perf_counter_init(struct perf_counter *counter) | |||
1090 | cflags[n] = flags; | 1088 | cflags[n] = flags; |
1091 | if (check_excludes(ctrs, cflags, n, 1)) | 1089 | if (check_excludes(ctrs, cflags, n, 1)) |
1092 | return ERR_PTR(-EINVAL); | 1090 | return ERR_PTR(-EINVAL); |
1093 | if (power_check_constraints(events, cflags, n + 1)) | 1091 | |
1092 | cpuhw = &get_cpu_var(cpu_hw_counters); | ||
1093 | err = power_check_constraints(cpuhw, events, cflags, n + 1); | ||
1094 | put_cpu_var(cpu_hw_counters); | ||
1095 | if (err) | ||
1094 | return ERR_PTR(-EINVAL); | 1096 | return ERR_PTR(-EINVAL); |
1095 | 1097 | ||
1096 | counter->hw.config = events[n]; | 1098 | counter->hw.config = events[n]; |