aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/ds_selftest.c
diff options
context:
space:
mode:
authorMarkus Metzger <markus.t.metzger@intel.com>2009-04-03 10:43:44 -0400
committerIngo Molnar <mingo@elte.hu>2009-04-07 07:36:25 -0400
commit01f6569ece6915616f6cae1d7d8b46ab8da9c1bd (patch)
tree7737a8d64ddaaebf5a2d3a801932e1732d3aca68 /arch/x86/kernel/ds_selftest.c
parent84f201139245c30777ff858e71b8d7e134b8c3ed (diff)
x86, ds: selftest each cpu
Perform debug store selftests on each cpu. Cover both the normal and the _noirq variant of the debug store interface. Signed-off-by: Markus Metzger <markus.t.metzger@intel.com> Cc: roland@redhat.com Cc: eranian@googlemail.com Cc: oleg@redhat.com Cc: juan.villacis@intel.com Cc: ak@linux.jf.intel.com LKML-Reference: <20090403144559.394583000@intel.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/ds_selftest.c')
-rw-r--r--arch/x86/kernel/ds_selftest.c182
1 files changed, 135 insertions, 47 deletions
diff --git a/arch/x86/kernel/ds_selftest.c b/arch/x86/kernel/ds_selftest.c
index cccc19a38f6d..599a96300628 100644
--- a/arch/x86/kernel/ds_selftest.c
+++ b/arch/x86/kernel/ds_selftest.c
@@ -11,13 +11,21 @@
11#include <linux/kernel.h> 11#include <linux/kernel.h>
12#include <linux/string.h> 12#include <linux/string.h>
13#include <linux/smp.h> 13#include <linux/smp.h>
14#include <linux/cpu.h>
14 15
15#include <asm/ds.h> 16#include <asm/ds.h>
16 17
17 18
18#define BUFFER_SIZE 1021 /* Intentionally chose an odd size. */ 19#define BUFFER_SIZE 521 /* Intentionally chose an odd size. */
19 20
20 21
22struct ds_selftest_bts_conf {
23 struct bts_tracer *tracer;
24 int error;
25 int (*suspend)(struct bts_tracer *);
26 int (*resume)(struct bts_tracer *);
27};
28
21static int ds_selftest_bts_consistency(const struct bts_trace *trace) 29static int ds_selftest_bts_consistency(const struct bts_trace *trace)
22{ 30{
23 int error = 0; 31 int error = 0;
@@ -125,36 +133,32 @@ static int ds_selftest_bts_read(struct bts_tracer *tracer,
125 return 0; 133 return 0;
126} 134}
127 135
128int ds_selftest_bts(void) 136static void ds_selftest_bts_cpu(void *arg)
129{ 137{
138 struct ds_selftest_bts_conf *conf = arg;
130 const struct bts_trace *trace; 139 const struct bts_trace *trace;
131 struct bts_tracer *tracer;
132 int error = 0;
133 void *top; 140 void *top;
134 unsigned char buffer[BUFFER_SIZE];
135 141
136 printk(KERN_INFO "[ds] bts selftest..."); 142 if (IS_ERR(conf->tracer)) {
137 143 conf->error = PTR_ERR(conf->tracer);
138 tracer = ds_request_bts_cpu(smp_processor_id(), buffer, BUFFER_SIZE, 144 conf->tracer = NULL;
139 NULL, (size_t)-1, BTS_KERNEL);
140 if (IS_ERR(tracer)) {
141 error = PTR_ERR(tracer);
142 tracer = NULL;
143 145
144 printk(KERN_CONT 146 printk(KERN_CONT
145 "initialization failed (err: %d)...", error); 147 "initialization failed (err: %d)...", conf->error);
146 goto out; 148 return;
147 } 149 }
148 150
149 /* The return should already give us enough trace. */ 151 /* We should meanwhile have enough trace. */
150 ds_suspend_bts(tracer); 152 conf->error = conf->suspend(conf->tracer);
153 if (conf->error < 0)
154 return;
151 155
152 /* Let's see if we can access the trace. */ 156 /* Let's see if we can access the trace. */
153 trace = ds_read_bts(tracer); 157 trace = ds_read_bts(conf->tracer);
154 158
155 error = ds_selftest_bts_consistency(trace); 159 conf->error = ds_selftest_bts_consistency(trace);
156 if (error < 0) 160 if (conf->error < 0)
157 goto out; 161 return;
158 162
159 /* If everything went well, we should have a few trace entries. */ 163 /* If everything went well, we should have a few trace entries. */
160 if (trace->ds.top == trace->ds.begin) { 164 if (trace->ds.top == trace->ds.begin) {
@@ -168,10 +172,11 @@ int ds_selftest_bts(void)
168 } 172 }
169 173
170 /* Let's try to read the trace we collected. */ 174 /* Let's try to read the trace we collected. */
171 error = ds_selftest_bts_read(tracer, trace, 175 conf->error =
176 ds_selftest_bts_read(conf->tracer, trace,
172 trace->ds.begin, trace->ds.top); 177 trace->ds.begin, trace->ds.top);
173 if (error < 0) 178 if (conf->error < 0)
174 goto out; 179 return;
175 180
176 /* 181 /*
177 * Let's read the trace again. 182 * Let's read the trace again.
@@ -179,26 +184,31 @@ int ds_selftest_bts(void)
179 */ 184 */
180 top = trace->ds.top; 185 top = trace->ds.top;
181 186
182 trace = ds_read_bts(tracer); 187 trace = ds_read_bts(conf->tracer);
183 error = ds_selftest_bts_consistency(trace); 188 conf->error = ds_selftest_bts_consistency(trace);
184 if (error < 0) 189 if (conf->error < 0)
185 goto out; 190 return;
186 191
187 if (top != trace->ds.top) { 192 if (top != trace->ds.top) {
188 printk(KERN_CONT "suspend not working..."); 193 printk(KERN_CONT "suspend not working...");
189 error = -1; 194 conf->error = -1;
190 goto out; 195 return;
191 } 196 }
192 197
193 /* Let's collect some more trace - see if resume is working. */ 198 /* Let's collect some more trace - see if resume is working. */
194 ds_resume_bts(tracer); 199 conf->error = conf->resume(conf->tracer);
195 ds_suspend_bts(tracer); 200 if (conf->error < 0)
201 return;
202
203 conf->error = conf->suspend(conf->tracer);
204 if (conf->error < 0)
205 return;
196 206
197 trace = ds_read_bts(tracer); 207 trace = ds_read_bts(conf->tracer);
198 208
199 error = ds_selftest_bts_consistency(trace); 209 conf->error = ds_selftest_bts_consistency(trace);
200 if (error < 0) 210 if (conf->error < 0)
201 goto out; 211 return;
202 212
203 if (trace->ds.top == top) { 213 if (trace->ds.top == top) {
204 /* 214 /*
@@ -210,35 +220,113 @@ int ds_selftest_bts(void)
210 printk(KERN_CONT 220 printk(KERN_CONT
211 "no resume progress/overflow..."); 221 "no resume progress/overflow...");
212 222
213 error = ds_selftest_bts_read(tracer, trace, 223 conf->error =
224 ds_selftest_bts_read(conf->tracer, trace,
214 trace->ds.begin, trace->ds.end); 225 trace->ds.begin, trace->ds.end);
215 } else if (trace->ds.top < top) { 226 } else if (trace->ds.top < top) {
216 /* 227 /*
217 * We had a buffer overflow - the entire buffer should 228 * We had a buffer overflow - the entire buffer should
218 * contain trace records. 229 * contain trace records.
219 */ 230 */
220 error = ds_selftest_bts_read(tracer, trace, 231 conf->error =
232 ds_selftest_bts_read(conf->tracer, trace,
221 trace->ds.begin, trace->ds.end); 233 trace->ds.begin, trace->ds.end);
222 } else { 234 } else {
223 /* 235 /*
224 * It is quite likely that the buffer did not overflow. 236 * It is quite likely that the buffer did not overflow.
225 * Let's just check the delta trace. 237 * Let's just check the delta trace.
226 */ 238 */
227 error = ds_selftest_bts_read(tracer, trace, 239 conf->error =
228 top, trace->ds.top); 240 ds_selftest_bts_read(conf->tracer, trace, top,
241 trace->ds.top);
229 } 242 }
230 if (error < 0) 243 if (conf->error < 0)
231 goto out; 244 return;
232 245
233 error = 0; 246 conf->error = 0;
247}
234 248
235 /* The final test: release the tracer while tracing is suspended. */ 249static int ds_suspend_bts_wrap(struct bts_tracer *tracer)
236 out: 250{
237 ds_release_bts(tracer); 251 ds_suspend_bts(tracer);
252 return 0;
253}
254
255static int ds_resume_bts_wrap(struct bts_tracer *tracer)
256{
257 ds_resume_bts(tracer);
258 return 0;
259}
238 260
239 printk(KERN_CONT "%s.\n", (error ? "failed" : "passed")); 261static void ds_release_bts_noirq_wrap(void *tracer)
262{
263 (void)ds_release_bts_noirq(tracer);
264}
240 265
241 return error; 266static int ds_selftest_bts_bad_release_noirq(int cpu,
267 struct bts_tracer *tracer)
268{
269 int error = -EPERM;
270
271 /* Try to release the tracer on the wrong cpu. */
272 get_cpu();
273 if (cpu != smp_processor_id()) {
274 error = ds_release_bts_noirq(tracer);
275 if (error != -EPERM)
276 printk(KERN_CONT "release on wrong cpu...");
277 }
278 put_cpu();
279
280 return error ? 0 : -1;
281}
282
283int ds_selftest_bts(void)
284{
285 struct ds_selftest_bts_conf conf;
286 unsigned char buffer[BUFFER_SIZE];
287 int cpu;
288
289 printk(KERN_INFO "[ds] bts selftest...");
290 conf.error = 0;
291
292 get_online_cpus();
293 for_each_online_cpu(cpu) {
294 conf.suspend = ds_suspend_bts_wrap;
295 conf.resume = ds_resume_bts_wrap;
296 conf.tracer =
297 ds_request_bts_cpu(cpu, buffer, BUFFER_SIZE,
298 NULL, (size_t)-1, BTS_KERNEL);
299 ds_selftest_bts_cpu(&conf);
300 ds_release_bts(conf.tracer);
301 if (conf.error < 0)
302 goto out;
303
304 conf.suspend = ds_suspend_bts_noirq;
305 conf.resume = ds_resume_bts_noirq;
306 conf.tracer =
307 ds_request_bts_cpu(cpu, buffer, BUFFER_SIZE,
308 NULL, (size_t)-1, BTS_KERNEL);
309 smp_call_function_single(cpu, ds_selftest_bts_cpu, &conf, 1);
310 if (conf.error >= 0) {
311 conf.error =
312 ds_selftest_bts_bad_release_noirq(cpu,
313 conf.tracer);
314 /* We must not release the tracer twice. */
315 if (conf.error < 0)
316 conf.tracer = NULL;
317 }
318 smp_call_function_single(cpu, ds_release_bts_noirq_wrap,
319 conf.tracer, 1);
320 if (conf.error < 0)
321 goto out;
322 }
323
324 conf.error = 0;
325 out:
326 put_online_cpus();
327 printk(KERN_CONT "%s.\n", (conf.error ? "failed" : "passed"));
328
329 return conf.error;
242} 330}
243 331
244int ds_selftest_pebs(void) 332int ds_selftest_pebs(void)