diff options
Diffstat (limited to 'arch/x86/oprofile/op_model_ppro.c')
-rw-r--r-- | arch/x86/oprofile/op_model_ppro.c | 81 |
1 files changed, 40 insertions, 41 deletions
diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c index 2bf90fafa7b..d769cda5408 100644 --- a/arch/x86/oprofile/op_model_ppro.c +++ b/arch/x86/oprofile/op_model_ppro.c | |||
@@ -30,19 +30,46 @@ static int counter_width = 32; | |||
30 | 30 | ||
31 | static u64 *reset_value; | 31 | static u64 *reset_value; |
32 | 32 | ||
33 | static void ppro_fill_in_addresses(struct op_msrs * const msrs) | 33 | static void ppro_shutdown(struct op_msrs const * const msrs) |
34 | { | 34 | { |
35 | int i; | 35 | int i; |
36 | 36 | ||
37 | for (i = 0; i < num_counters; i++) { | 37 | for (i = 0; i < num_counters; ++i) { |
38 | if (reserve_perfctr_nmi(MSR_P6_PERFCTR0 + i)) | 38 | if (!msrs->counters[i].addr) |
39 | msrs->counters[i].addr = MSR_P6_PERFCTR0 + i; | 39 | continue; |
40 | release_perfctr_nmi(MSR_P6_PERFCTR0 + i); | ||
41 | release_evntsel_nmi(MSR_P6_EVNTSEL0 + i); | ||
42 | } | ||
43 | if (reset_value) { | ||
44 | kfree(reset_value); | ||
45 | reset_value = NULL; | ||
40 | } | 46 | } |
47 | } | ||
48 | |||
49 | static int ppro_fill_in_addresses(struct op_msrs * const msrs) | ||
50 | { | ||
51 | int i; | ||
41 | 52 | ||
42 | for (i = 0; i < num_counters; i++) { | 53 | for (i = 0; i < num_counters; i++) { |
43 | if (reserve_evntsel_nmi(MSR_P6_EVNTSEL0 + i)) | 54 | if (!reserve_perfctr_nmi(MSR_P6_PERFCTR0 + i)) |
44 | msrs->controls[i].addr = MSR_P6_EVNTSEL0 + i; | 55 | goto fail; |
56 | if (!reserve_evntsel_nmi(MSR_P6_EVNTSEL0 + i)) { | ||
57 | release_perfctr_nmi(MSR_P6_PERFCTR0 + i); | ||
58 | goto fail; | ||
59 | } | ||
60 | /* both registers must be reserved */ | ||
61 | msrs->counters[i].addr = MSR_P6_PERFCTR0 + i; | ||
62 | msrs->controls[i].addr = MSR_P6_EVNTSEL0 + i; | ||
63 | continue; | ||
64 | fail: | ||
65 | if (!counter_config[i].enabled) | ||
66 | continue; | ||
67 | op_x86_warn_reserved(i); | ||
68 | ppro_shutdown(msrs); | ||
69 | return -EBUSY; | ||
45 | } | 70 | } |
71 | |||
72 | return 0; | ||
46 | } | 73 | } |
47 | 74 | ||
48 | 75 | ||
@@ -78,26 +105,17 @@ static void ppro_setup_ctrs(struct op_x86_model_spec const *model, | |||
78 | 105 | ||
79 | /* clear all counters */ | 106 | /* clear all counters */ |
80 | for (i = 0; i < num_counters; ++i) { | 107 | for (i = 0; i < num_counters; ++i) { |
81 | if (unlikely(!msrs->controls[i].addr)) { | 108 | if (!msrs->controls[i].addr) |
82 | if (counter_config[i].enabled && !smp_processor_id()) | ||
83 | /* | ||
84 | * counter is reserved, this is on all | ||
85 | * cpus, so report only for cpu #0 | ||
86 | */ | ||
87 | op_x86_warn_reserved(i); | ||
88 | continue; | 109 | continue; |
89 | } | ||
90 | rdmsrl(msrs->controls[i].addr, val); | 110 | rdmsrl(msrs->controls[i].addr, val); |
91 | if (val & ARCH_PERFMON_EVENTSEL_ENABLE) | 111 | if (val & ARCH_PERFMON_EVENTSEL_ENABLE) |
92 | op_x86_warn_in_use(i); | 112 | op_x86_warn_in_use(i); |
93 | val &= model->reserved; | 113 | val &= model->reserved; |
94 | wrmsrl(msrs->controls[i].addr, val); | 114 | wrmsrl(msrs->controls[i].addr, val); |
95 | } | 115 | /* |
96 | 116 | * avoid a false detection of ctr overflows in NMI * | |
97 | /* avoid a false detection of ctr overflows in NMI handler */ | 117 | * handler |
98 | for (i = 0; i < num_counters; ++i) { | 118 | */ |
99 | if (unlikely(!msrs->counters[i].addr)) | ||
100 | continue; | ||
101 | wrmsrl(msrs->counters[i].addr, -1LL); | 119 | wrmsrl(msrs->counters[i].addr, -1LL); |
102 | } | 120 | } |
103 | 121 | ||
@@ -189,25 +207,6 @@ static void ppro_stop(struct op_msrs const * const msrs) | |||
189 | } | 207 | } |
190 | } | 208 | } |
191 | 209 | ||
192 | static void ppro_shutdown(struct op_msrs const * const msrs) | ||
193 | { | ||
194 | int i; | ||
195 | |||
196 | for (i = 0; i < num_counters; ++i) { | ||
197 | if (msrs->counters[i].addr) | ||
198 | release_perfctr_nmi(MSR_P6_PERFCTR0 + i); | ||
199 | } | ||
200 | for (i = 0; i < num_counters; ++i) { | ||
201 | if (msrs->controls[i].addr) | ||
202 | release_evntsel_nmi(MSR_P6_EVNTSEL0 + i); | ||
203 | } | ||
204 | if (reset_value) { | ||
205 | kfree(reset_value); | ||
206 | reset_value = NULL; | ||
207 | } | ||
208 | } | ||
209 | |||
210 | |||
211 | struct op_x86_model_spec op_ppro_spec = { | 210 | struct op_x86_model_spec op_ppro_spec = { |
212 | .num_counters = 2, | 211 | .num_counters = 2, |
213 | .num_controls = 2, | 212 | .num_controls = 2, |
@@ -239,11 +238,11 @@ static void arch_perfmon_setup_counters(void) | |||
239 | if (eax.split.version_id == 0 && current_cpu_data.x86 == 6 && | 238 | if (eax.split.version_id == 0 && current_cpu_data.x86 == 6 && |
240 | current_cpu_data.x86_model == 15) { | 239 | current_cpu_data.x86_model == 15) { |
241 | eax.split.version_id = 2; | 240 | eax.split.version_id = 2; |
242 | eax.split.num_events = 2; | 241 | eax.split.num_counters = 2; |
243 | eax.split.bit_width = 40; | 242 | eax.split.bit_width = 40; |
244 | } | 243 | } |
245 | 244 | ||
246 | num_counters = eax.split.num_events; | 245 | num_counters = eax.split.num_counters; |
247 | 246 | ||
248 | op_arch_perfmon_spec.num_counters = num_counters; | 247 | op_arch_perfmon_spec.num_counters = num_counters; |
249 | op_arch_perfmon_spec.num_controls = num_counters; | 248 | op_arch_perfmon_spec.num_controls = num_counters; |