diff options
| -rw-r--r-- | arch/powerpc/kernel/perf_counter.c | 55 |
1 files changed, 32 insertions, 23 deletions
diff --git a/arch/powerpc/kernel/perf_counter.c b/arch/powerpc/kernel/perf_counter.c index ccd6b2135642..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 | ||
| @@ -239,13 +242,11 @@ static void write_pmc(int idx, unsigned long val) | |||
| 239 | * and see if any combination of alternative codes is feasible. | 242 | * and see if any combination of alternative codes is feasible. |
| 240 | * The feasible set is returned in event[]. | 243 | * The feasible set is returned in event[]. |
| 241 | */ | 244 | */ |
| 242 | 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[], | ||
| 243 | int n_ev) | 247 | int n_ev) |
| 244 | { | 248 | { |
| 245 | unsigned long mask, value, nv; | 249 | unsigned long mask, value, nv; |
| 246 | u64 alternatives[MAX_HWCOUNTERS][MAX_EVENT_ALTERNATIVES]; | ||
| 247 | unsigned long amasks[MAX_HWCOUNTERS][MAX_EVENT_ALTERNATIVES]; | ||
| 248 | unsigned long avalues[MAX_HWCOUNTERS][MAX_EVENT_ALTERNATIVES]; | ||
| 249 | unsigned long smasks[MAX_HWCOUNTERS], svalues[MAX_HWCOUNTERS]; | 250 | unsigned long smasks[MAX_HWCOUNTERS], svalues[MAX_HWCOUNTERS]; |
| 250 | int n_alt[MAX_HWCOUNTERS], choice[MAX_HWCOUNTERS]; | 251 | int n_alt[MAX_HWCOUNTERS], choice[MAX_HWCOUNTERS]; |
| 251 | int i, j; | 252 | int i, j; |
| @@ -260,21 +261,23 @@ static int power_check_constraints(u64 event[], unsigned int cflags[], | |||
| 260 | if ((cflags[i] & PPMU_LIMITED_PMC_REQD) | 261 | if ((cflags[i] & PPMU_LIMITED_PMC_REQD) |
| 261 | && !ppmu->limited_pmc_event(event[i])) { | 262 | && !ppmu->limited_pmc_event(event[i])) { |
| 262 | ppmu->get_alternatives(event[i], cflags[i], | 263 | ppmu->get_alternatives(event[i], cflags[i], |
| 263 | alternatives[i]); | 264 | cpuhw->alternatives[i]); |
| 264 | event[i] = alternatives[i][0]; | 265 | event[i] = cpuhw->alternatives[i][0]; |
| 265 | } | 266 | } |
| 266 | if (ppmu->get_constraint(event[i], &amasks[i][0], | 267 | if (ppmu->get_constraint(event[i], &cpuhw->amasks[i][0], |
| 267 | &avalues[i][0])) | 268 | &cpuhw->avalues[i][0])) |
| 268 | return -1; | 269 | return -1; |
| 269 | } | 270 | } |
| 270 | value = mask = 0; | 271 | value = mask = 0; |
| 271 | for (i = 0; i < n_ev; ++i) { | 272 | for (i = 0; i < n_ev; ++i) { |
| 272 | nv = (value | avalues[i][0]) + (value & avalues[i][0] & addf); | 273 | nv = (value | cpuhw->avalues[i][0]) + |
| 274 | (value & cpuhw->avalues[i][0] & addf); | ||
| 273 | if ((((nv + tadd) ^ value) & mask) != 0 || | 275 | if ((((nv + tadd) ^ value) & mask) != 0 || |
| 274 | (((nv + tadd) ^ avalues[i][0]) & amasks[i][0]) != 0) | 276 | (((nv + tadd) ^ cpuhw->avalues[i][0]) & |
| 277 | cpuhw->amasks[i][0]) != 0) | ||
| 275 | break; | 278 | break; |
| 276 | value = nv; | 279 | value = nv; |
| 277 | mask |= amasks[i][0]; | 280 | mask |= cpuhw->amasks[i][0]; |
| 278 | } | 281 | } |
| 279 | if (i == n_ev) | 282 | if (i == n_ev) |
| 280 | return 0; /* all OK */ | 283 | return 0; /* all OK */ |
| @@ -285,10 +288,11 @@ static int power_check_constraints(u64 event[], unsigned int cflags[], | |||
| 285 | for (i = 0; i < n_ev; ++i) { | 288 | for (i = 0; i < n_ev; ++i) { |
| 286 | choice[i] = 0; | 289 | choice[i] = 0; |
| 287 | n_alt[i] = ppmu->get_alternatives(event[i], cflags[i], | 290 | n_alt[i] = ppmu->get_alternatives(event[i], cflags[i], |
| 288 | alternatives[i]); | 291 | cpuhw->alternatives[i]); |
| 289 | for (j = 1; j < n_alt[i]; ++j) | 292 | for (j = 1; j < n_alt[i]; ++j) |
| 290 | ppmu->get_constraint(alternatives[i][j], | 293 | ppmu->get_constraint(cpuhw->alternatives[i][j], |
| 291 | &amasks[i][j], &avalues[i][j]); | 294 | &cpuhw->amasks[i][j], |
| 295 | &cpuhw->avalues[i][j]); | ||
| 292 | } | 296 | } |
| 293 | 297 | ||
| 294 | /* enumerate all possibilities and see if any will work */ | 298 | /* enumerate all possibilities and see if any will work */ |
| @@ -307,11 +311,11 @@ static int power_check_constraints(u64 event[], unsigned int cflags[], | |||
| 307 | * where k > j, will satisfy the constraints. | 311 | * where k > j, will satisfy the constraints. |
| 308 | */ | 312 | */ |
| 309 | while (++j < n_alt[i]) { | 313 | while (++j < n_alt[i]) { |
| 310 | nv = (value | avalues[i][j]) + | 314 | nv = (value | cpuhw->avalues[i][j]) + |
| 311 | (value & avalues[i][j] & addf); | 315 | (value & cpuhw->avalues[i][j] & addf); |
| 312 | if ((((nv + tadd) ^ value) & mask) == 0 && | 316 | if ((((nv + tadd) ^ value) & mask) == 0 && |
| 313 | (((nv + tadd) ^ avalues[i][j]) | 317 | (((nv + tadd) ^ cpuhw->avalues[i][j]) |
| 314 | & amasks[i][j]) == 0) | 318 | & cpuhw->amasks[i][j]) == 0) |
| 315 | break; | 319 | break; |
| 316 | } | 320 | } |
| 317 | if (j >= n_alt[i]) { | 321 | if (j >= n_alt[i]) { |
| @@ -333,7 +337,7 @@ static int power_check_constraints(u64 event[], unsigned int cflags[], | |||
| 333 | svalues[i] = value; | 337 | svalues[i] = value; |
| 334 | smasks[i] = mask; | 338 | smasks[i] = mask; |
| 335 | value = nv; | 339 | value = nv; |
| 336 | mask |= amasks[i][j]; | 340 | mask |= cpuhw->amasks[i][j]; |
| 337 | ++i; | 341 | ++i; |
| 338 | j = -1; | 342 | j = -1; |
| 339 | } | 343 | } |
| @@ -341,7 +345,7 @@ static int power_check_constraints(u64 event[], unsigned int cflags[], | |||
| 341 | 345 | ||
| 342 | /* OK, we have a feasible combination, tell the caller the solution */ | 346 | /* OK, we have a feasible combination, tell the caller the solution */ |
| 343 | for (i = 0; i < n_ev; ++i) | 347 | for (i = 0; i < n_ev; ++i) |
| 344 | event[i] = alternatives[i][choice[i]]; | 348 | event[i] = cpuhw->alternatives[i][choice[i]]; |
| 345 | return 0; | 349 | return 0; |
| 346 | } | 350 | } |
| 347 | 351 | ||
| @@ -745,7 +749,7 @@ int hw_perf_group_sched_in(struct perf_counter *group_leader, | |||
| 745 | return -EAGAIN; | 749 | return -EAGAIN; |
| 746 | if (check_excludes(cpuhw->counter, cpuhw->flags, n0, n)) | 750 | if (check_excludes(cpuhw->counter, cpuhw->flags, n0, n)) |
| 747 | return -EAGAIN; | 751 | return -EAGAIN; |
| 748 | i = power_check_constraints(cpuhw->events, cpuhw->flags, n + n0); | 752 | i = power_check_constraints(cpuhw, cpuhw->events, cpuhw->flags, n + n0); |
| 749 | if (i < 0) | 753 | if (i < 0) |
| 750 | return -EAGAIN; | 754 | return -EAGAIN; |
| 751 | cpuhw->n_counters = n0 + n; | 755 | cpuhw->n_counters = n0 + n; |
| @@ -800,7 +804,7 @@ static int power_pmu_enable(struct perf_counter *counter) | |||
| 800 | cpuhw->flags[n0] = counter->hw.counter_base; | 804 | cpuhw->flags[n0] = counter->hw.counter_base; |
| 801 | if (check_excludes(cpuhw->counter, cpuhw->flags, n0, 1)) | 805 | if (check_excludes(cpuhw->counter, cpuhw->flags, n0, 1)) |
| 802 | goto out; | 806 | goto out; |
| 803 | if (power_check_constraints(cpuhw->events, cpuhw->flags, n0 + 1)) | 807 | if (power_check_constraints(cpuhw, cpuhw->events, cpuhw->flags, n0 + 1)) |
| 804 | goto out; | 808 | goto out; |
| 805 | 809 | ||
| 806 | counter->hw.config = cpuhw->events[n0]; | 810 | counter->hw.config = cpuhw->events[n0]; |
| @@ -1005,6 +1009,7 @@ const struct pmu *hw_perf_counter_init(struct perf_counter *counter) | |||
| 1005 | unsigned int cflags[MAX_HWCOUNTERS]; | 1009 | unsigned int cflags[MAX_HWCOUNTERS]; |
| 1006 | int n; | 1010 | int n; |
| 1007 | int err; | 1011 | int err; |
| 1012 | struct cpu_hw_counters *cpuhw; | ||
| 1008 | 1013 | ||
| 1009 | if (!ppmu) | 1014 | if (!ppmu) |
| 1010 | return ERR_PTR(-ENXIO); | 1015 | return ERR_PTR(-ENXIO); |
| @@ -1083,7 +1088,11 @@ const struct pmu *hw_perf_counter_init(struct perf_counter *counter) | |||
| 1083 | cflags[n] = flags; | 1088 | cflags[n] = flags; |
| 1084 | if (check_excludes(ctrs, cflags, n, 1)) | 1089 | if (check_excludes(ctrs, cflags, n, 1)) |
| 1085 | return ERR_PTR(-EINVAL); | 1090 | return ERR_PTR(-EINVAL); |
| 1086 | 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) | ||
| 1087 | return ERR_PTR(-EINVAL); | 1096 | return ERR_PTR(-EINVAL); |
| 1088 | 1097 | ||
| 1089 | counter->hw.config = events[n]; | 1098 | counter->hw.config = events[n]; |
