diff options
Diffstat (limited to 'arch/i386/oprofile/op_model_ppro.c')
-rw-r--r-- | arch/i386/oprofile/op_model_ppro.c | 65 |
1 files changed, 53 insertions, 12 deletions
diff --git a/arch/i386/oprofile/op_model_ppro.c b/arch/i386/oprofile/op_model_ppro.c index 5c3ab4b027ad..f88e05ba8eb3 100644 --- a/arch/i386/oprofile/op_model_ppro.c +++ b/arch/i386/oprofile/op_model_ppro.c | |||
@@ -22,10 +22,12 @@ | |||
22 | #define NUM_COUNTERS 2 | 22 | #define NUM_COUNTERS 2 |
23 | #define NUM_CONTROLS 2 | 23 | #define NUM_CONTROLS 2 |
24 | 24 | ||
25 | #define CTR_IS_RESERVED(msrs,c) (msrs->counters[(c)].addr ? 1 : 0) | ||
25 | #define CTR_READ(l,h,msrs,c) do {rdmsr(msrs->counters[(c)].addr, (l), (h));} while (0) | 26 | #define CTR_READ(l,h,msrs,c) do {rdmsr(msrs->counters[(c)].addr, (l), (h));} while (0) |
26 | #define CTR_WRITE(l,msrs,c) do {wrmsr(msrs->counters[(c)].addr, -(u32)(l), -1);} while (0) | 27 | #define CTR_WRITE(l,msrs,c) do {wrmsr(msrs->counters[(c)].addr, -(u32)(l), -1);} while (0) |
27 | #define CTR_OVERFLOWED(n) (!((n) & (1U<<31))) | 28 | #define CTR_OVERFLOWED(n) (!((n) & (1U<<31))) |
28 | 29 | ||
30 | #define CTRL_IS_RESERVED(msrs,c) (msrs->controls[(c)].addr ? 1 : 0) | ||
29 | #define CTRL_READ(l,h,msrs,c) do {rdmsr((msrs->controls[(c)].addr), (l), (h));} while (0) | 31 | #define CTRL_READ(l,h,msrs,c) do {rdmsr((msrs->controls[(c)].addr), (l), (h));} while (0) |
30 | #define CTRL_WRITE(l,h,msrs,c) do {wrmsr((msrs->controls[(c)].addr), (l), (h));} while (0) | 32 | #define CTRL_WRITE(l,h,msrs,c) do {wrmsr((msrs->controls[(c)].addr), (l), (h));} while (0) |
31 | #define CTRL_SET_ACTIVE(n) (n |= (1<<22)) | 33 | #define CTRL_SET_ACTIVE(n) (n |= (1<<22)) |
@@ -41,11 +43,21 @@ static unsigned long reset_value[NUM_COUNTERS]; | |||
41 | 43 | ||
42 | static void ppro_fill_in_addresses(struct op_msrs * const msrs) | 44 | static void ppro_fill_in_addresses(struct op_msrs * const msrs) |
43 | { | 45 | { |
44 | msrs->counters[0].addr = MSR_P6_PERFCTR0; | 46 | int i; |
45 | msrs->counters[1].addr = MSR_P6_PERFCTR1; | 47 | |
48 | for (i=0; i < NUM_COUNTERS; i++) { | ||
49 | if (reserve_perfctr_nmi(MSR_P6_PERFCTR0 + i)) | ||
50 | msrs->counters[i].addr = MSR_P6_PERFCTR0 + i; | ||
51 | else | ||
52 | msrs->counters[i].addr = 0; | ||
53 | } | ||
46 | 54 | ||
47 | msrs->controls[0].addr = MSR_P6_EVNTSEL0; | 55 | for (i=0; i < NUM_CONTROLS; i++) { |
48 | msrs->controls[1].addr = MSR_P6_EVNTSEL1; | 56 | if (reserve_evntsel_nmi(MSR_P6_EVNTSEL0 + i)) |
57 | msrs->controls[i].addr = MSR_P6_EVNTSEL0 + i; | ||
58 | else | ||
59 | msrs->controls[i].addr = 0; | ||
60 | } | ||
49 | } | 61 | } |
50 | 62 | ||
51 | 63 | ||
@@ -56,6 +68,8 @@ static void ppro_setup_ctrs(struct op_msrs const * const msrs) | |||
56 | 68 | ||
57 | /* clear all counters */ | 69 | /* clear all counters */ |
58 | for (i = 0 ; i < NUM_CONTROLS; ++i) { | 70 | for (i = 0 ; i < NUM_CONTROLS; ++i) { |
71 | if (unlikely(!CTRL_IS_RESERVED(msrs,i))) | ||
72 | continue; | ||
59 | CTRL_READ(low, high, msrs, i); | 73 | CTRL_READ(low, high, msrs, i); |
60 | CTRL_CLEAR(low); | 74 | CTRL_CLEAR(low); |
61 | CTRL_WRITE(low, high, msrs, i); | 75 | CTRL_WRITE(low, high, msrs, i); |
@@ -63,12 +77,14 @@ static void ppro_setup_ctrs(struct op_msrs const * const msrs) | |||
63 | 77 | ||
64 | /* avoid a false detection of ctr overflows in NMI handler */ | 78 | /* avoid a false detection of ctr overflows in NMI handler */ |
65 | for (i = 0; i < NUM_COUNTERS; ++i) { | 79 | for (i = 0; i < NUM_COUNTERS; ++i) { |
80 | if (unlikely(!CTR_IS_RESERVED(msrs,i))) | ||
81 | continue; | ||
66 | CTR_WRITE(1, msrs, i); | 82 | CTR_WRITE(1, msrs, i); |
67 | } | 83 | } |
68 | 84 | ||
69 | /* enable active counters */ | 85 | /* enable active counters */ |
70 | for (i = 0; i < NUM_COUNTERS; ++i) { | 86 | for (i = 0; i < NUM_COUNTERS; ++i) { |
71 | if (counter_config[i].enabled) { | 87 | if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs,i))) { |
72 | reset_value[i] = counter_config[i].count; | 88 | reset_value[i] = counter_config[i].count; |
73 | 89 | ||
74 | CTR_WRITE(counter_config[i].count, msrs, i); | 90 | CTR_WRITE(counter_config[i].count, msrs, i); |
@@ -81,6 +97,8 @@ static void ppro_setup_ctrs(struct op_msrs const * const msrs) | |||
81 | CTRL_SET_UM(low, counter_config[i].unit_mask); | 97 | CTRL_SET_UM(low, counter_config[i].unit_mask); |
82 | CTRL_SET_EVENT(low, counter_config[i].event); | 98 | CTRL_SET_EVENT(low, counter_config[i].event); |
83 | CTRL_WRITE(low, high, msrs, i); | 99 | CTRL_WRITE(low, high, msrs, i); |
100 | } else { | ||
101 | reset_value[i] = 0; | ||
84 | } | 102 | } |
85 | } | 103 | } |
86 | } | 104 | } |
@@ -93,6 +111,8 @@ static int ppro_check_ctrs(struct pt_regs * const regs, | |||
93 | int i; | 111 | int i; |
94 | 112 | ||
95 | for (i = 0 ; i < NUM_COUNTERS; ++i) { | 113 | for (i = 0 ; i < NUM_COUNTERS; ++i) { |
114 | if (!reset_value[i]) | ||
115 | continue; | ||
96 | CTR_READ(low, high, msrs, i); | 116 | CTR_READ(low, high, msrs, i); |
97 | if (CTR_OVERFLOWED(low)) { | 117 | if (CTR_OVERFLOWED(low)) { |
98 | oprofile_add_sample(regs, i); | 118 | oprofile_add_sample(regs, i); |
@@ -118,18 +138,38 @@ static int ppro_check_ctrs(struct pt_regs * const regs, | |||
118 | static void ppro_start(struct op_msrs const * const msrs) | 138 | static void ppro_start(struct op_msrs const * const msrs) |
119 | { | 139 | { |
120 | unsigned int low,high; | 140 | unsigned int low,high; |
121 | CTRL_READ(low, high, msrs, 0); | 141 | |
122 | CTRL_SET_ACTIVE(low); | 142 | if (reset_value[0]) { |
123 | CTRL_WRITE(low, high, msrs, 0); | 143 | CTRL_READ(low, high, msrs, 0); |
144 | CTRL_SET_ACTIVE(low); | ||
145 | CTRL_WRITE(low, high, msrs, 0); | ||
146 | } | ||
124 | } | 147 | } |
125 | 148 | ||
126 | 149 | ||
127 | static void ppro_stop(struct op_msrs const * const msrs) | 150 | static void ppro_stop(struct op_msrs const * const msrs) |
128 | { | 151 | { |
129 | unsigned int low,high; | 152 | unsigned int low,high; |
130 | CTRL_READ(low, high, msrs, 0); | 153 | |
131 | CTRL_SET_INACTIVE(low); | 154 | if (reset_value[0]) { |
132 | CTRL_WRITE(low, high, msrs, 0); | 155 | CTRL_READ(low, high, msrs, 0); |
156 | CTRL_SET_INACTIVE(low); | ||
157 | CTRL_WRITE(low, high, msrs, 0); | ||
158 | } | ||
159 | } | ||
160 | |||
161 | static void ppro_shutdown(struct op_msrs const * const msrs) | ||
162 | { | ||
163 | int i; | ||
164 | |||
165 | for (i = 0 ; i < NUM_COUNTERS ; ++i) { | ||
166 | if (CTR_IS_RESERVED(msrs,i)) | ||
167 | release_perfctr_nmi(MSR_P6_PERFCTR0 + i); | ||
168 | } | ||
169 | for (i = 0 ; i < NUM_CONTROLS ; ++i) { | ||
170 | if (CTRL_IS_RESERVED(msrs,i)) | ||
171 | release_evntsel_nmi(MSR_P6_EVNTSEL0 + i); | ||
172 | } | ||
133 | } | 173 | } |
134 | 174 | ||
135 | 175 | ||
@@ -140,5 +180,6 @@ struct op_x86_model_spec const op_ppro_spec = { | |||
140 | .setup_ctrs = &ppro_setup_ctrs, | 180 | .setup_ctrs = &ppro_setup_ctrs, |
141 | .check_ctrs = &ppro_check_ctrs, | 181 | .check_ctrs = &ppro_check_ctrs, |
142 | .start = &ppro_start, | 182 | .start = &ppro_start, |
143 | .stop = &ppro_stop | 183 | .stop = &ppro_stop, |
184 | .shutdown = &ppro_shutdown | ||
144 | }; | 185 | }; |