2 * Debug Store support - selftest
5 * Copyright (C) 2009 Intel Corporation.
6 * Markus Metzger <markus.t.metzger@intel.com>, 2009
9 #include "ds_selftest.h"
11 #include <linux/kernel.h>
12 #include <linux/string.h>
13 #include <linux/smp.h>
14 #include <linux/cpu.h>
19 #define BUFFER_SIZE 521 /* Intentionally chose an odd size. */
20 #define SMALL_BUFFER_SIZE 24 /* A single bts entry. */
22 struct ds_selftest_bts_conf
{
23 struct bts_tracer
*tracer
;
25 int (*suspend
)(struct bts_tracer
*);
26 int (*resume
)(struct bts_tracer
*);
29 static int ds_selftest_bts_consistency(const struct bts_trace
*trace
)
34 printk(KERN_CONT
"failed to access trace...");
35 /* Bail out. Other tests are pointless. */
40 printk(KERN_CONT
"bts read not available...");
44 /* Do some sanity checks on the trace configuration. */
46 printk(KERN_CONT
"empty bts buffer...");
49 if (!trace
->ds
.size
) {
50 printk(KERN_CONT
"bad bts trace setup...");
54 (char *)trace
->ds
.begin
+ (trace
->ds
.n
* trace
->ds
.size
)) {
55 printk(KERN_CONT
"bad bts buffer setup...");
59 * We allow top in [begin; end], since its not clear when the
60 * overflow adjustment happens: after the increment or before the
63 if ((trace
->ds
.top
< trace
->ds
.begin
) ||
64 (trace
->ds
.end
< trace
->ds
.top
)) {
65 printk(KERN_CONT
"bts top out of bounds...");
72 static int ds_selftest_bts_read(struct bts_tracer
*tracer
,
73 const struct bts_trace
*trace
,
74 const void *from
, const void *to
)
76 const unsigned char *at
;
79 * Check a few things which do not belong to this test.
80 * They should be covered by other tests.
91 if (from
< trace
->ds
.begin
)
94 if (trace
->ds
.end
< to
)
100 /* Now to the test itself. */
101 for (at
= from
; (void *)at
< to
; at
+= trace
->ds
.size
) {
102 struct bts_struct bts
;
106 if (((void *)at
- trace
->ds
.begin
) % trace
->ds
.size
) {
108 "read from non-integer index...");
111 index
= ((void *)at
- trace
->ds
.begin
) / trace
->ds
.size
;
113 memset(&bts
, 0, sizeof(bts
));
114 error
= trace
->read(tracer
, at
, &bts
);
117 "error reading bts trace at [%lu] (0x%p)...",
122 switch (bts
.qualifier
) {
127 "unexpected bts entry %llu at [%lu] (0x%p)...",
128 bts
.qualifier
, index
, at
);
136 static void ds_selftest_bts_cpu(void *arg
)
138 struct ds_selftest_bts_conf
*conf
= arg
;
139 const struct bts_trace
*trace
;
142 if (IS_ERR(conf
->tracer
)) {
143 conf
->error
= PTR_ERR(conf
->tracer
);
147 "initialization failed (err: %d)...", conf
->error
);
151 /* We should meanwhile have enough trace. */
152 conf
->error
= conf
->suspend(conf
->tracer
);
156 /* Let's see if we can access the trace. */
157 trace
= ds_read_bts(conf
->tracer
);
159 conf
->error
= ds_selftest_bts_consistency(trace
);
163 /* If everything went well, we should have a few trace entries. */
164 if (trace
->ds
.top
== trace
->ds
.begin
) {
166 * It is possible but highly unlikely that we got a
167 * buffer overflow and end up at exactly the same
168 * position we started from.
169 * Let's issue a warning, but continue.
171 printk(KERN_CONT
"no trace/overflow...");
174 /* Let's try to read the trace we collected. */
176 ds_selftest_bts_read(conf
->tracer
, trace
,
177 trace
->ds
.begin
, trace
->ds
.top
);
182 * Let's read the trace again.
183 * Since we suspended tracing, we should get the same result.
187 trace
= ds_read_bts(conf
->tracer
);
188 conf
->error
= ds_selftest_bts_consistency(trace
);
192 if (top
!= trace
->ds
.top
) {
193 printk(KERN_CONT
"suspend not working...");
198 /* Let's collect some more trace - see if resume is working. */
199 conf
->error
= conf
->resume(conf
->tracer
);
203 conf
->error
= conf
->suspend(conf
->tracer
);
207 trace
= ds_read_bts(conf
->tracer
);
209 conf
->error
= ds_selftest_bts_consistency(trace
);
213 if (trace
->ds
.top
== top
) {
215 * It is possible but highly unlikely that we got a
216 * buffer overflow and end up at exactly the same
217 * position we started from.
218 * Let's issue a warning and check the full trace.
221 "no resume progress/overflow...");
224 ds_selftest_bts_read(conf
->tracer
, trace
,
225 trace
->ds
.begin
, trace
->ds
.end
);
226 } else if (trace
->ds
.top
< top
) {
228 * We had a buffer overflow - the entire buffer should
229 * contain trace records.
232 ds_selftest_bts_read(conf
->tracer
, trace
,
233 trace
->ds
.begin
, trace
->ds
.end
);
236 * It is quite likely that the buffer did not overflow.
237 * Let's just check the delta trace.
240 ds_selftest_bts_read(conf
->tracer
, trace
, top
,
249 static int ds_suspend_bts_wrap(struct bts_tracer
*tracer
)
251 ds_suspend_bts(tracer
);
255 static int ds_resume_bts_wrap(struct bts_tracer
*tracer
)
257 ds_resume_bts(tracer
);
261 static void ds_release_bts_noirq_wrap(void *tracer
)
263 (void)ds_release_bts_noirq(tracer
);
266 static int ds_selftest_bts_bad_release_noirq(int cpu
,
267 struct bts_tracer
*tracer
)
271 /* Try to release the tracer on the wrong cpu. */
273 if (cpu
!= smp_processor_id()) {
274 error
= ds_release_bts_noirq(tracer
);
276 printk(KERN_CONT
"release on wrong cpu...");
280 return error
? 0 : -1;
283 static int ds_selftest_bts_bad_request_cpu(int cpu
, void *buffer
)
285 struct bts_tracer
*tracer
;
288 /* Try to request cpu tracing while task tracing is active. */
289 tracer
= ds_request_bts_cpu(cpu
, buffer
, BUFFER_SIZE
, NULL
,
290 (size_t)-1, BTS_KERNEL
);
291 error
= PTR_ERR(tracer
);
292 if (!IS_ERR(tracer
)) {
293 ds_release_bts(tracer
);
298 printk(KERN_CONT
"cpu/task tracing overlap...");
300 return error
? 0 : -1;
303 static int ds_selftest_bts_bad_request_task(void *buffer
)
305 struct bts_tracer
*tracer
;
308 /* Try to request cpu tracing while task tracing is active. */
309 tracer
= ds_request_bts_task(current
, buffer
, BUFFER_SIZE
, NULL
,
310 (size_t)-1, BTS_KERNEL
);
311 error
= PTR_ERR(tracer
);
312 if (!IS_ERR(tracer
)) {
314 ds_release_bts(tracer
);
318 printk(KERN_CONT
"task/cpu tracing overlap...");
320 return error
? 0 : -1;
323 int ds_selftest_bts(void)
325 struct ds_selftest_bts_conf conf
;
326 unsigned char buffer
[BUFFER_SIZE
], *small_buffer
;
330 printk(KERN_INFO
"[ds] bts selftest...");
333 small_buffer
= (unsigned char *)ALIGN((unsigned long)buffer
, 8) + 8;
336 for_each_online_cpu(cpu
) {
337 conf
.suspend
= ds_suspend_bts_wrap
;
338 conf
.resume
= ds_resume_bts_wrap
;
340 ds_request_bts_cpu(cpu
, buffer
, BUFFER_SIZE
,
341 NULL
, (size_t)-1, BTS_KERNEL
);
342 ds_selftest_bts_cpu(&conf
);
344 conf
.error
= ds_selftest_bts_bad_request_task(buffer
);
345 ds_release_bts(conf
.tracer
);
349 conf
.suspend
= ds_suspend_bts_noirq
;
350 conf
.resume
= ds_resume_bts_noirq
;
352 ds_request_bts_cpu(cpu
, buffer
, BUFFER_SIZE
,
353 NULL
, (size_t)-1, BTS_KERNEL
);
354 smp_call_function_single(cpu
, ds_selftest_bts_cpu
, &conf
, 1);
355 if (conf
.error
>= 0) {
357 ds_selftest_bts_bad_release_noirq(cpu
,
359 /* We must not release the tracer twice. */
364 conf
.error
= ds_selftest_bts_bad_request_task(buffer
);
365 smp_call_function_single(cpu
, ds_release_bts_noirq_wrap
,
371 conf
.suspend
= ds_suspend_bts_wrap
;
372 conf
.resume
= ds_resume_bts_wrap
;
374 ds_request_bts_task(current
, buffer
, BUFFER_SIZE
,
375 NULL
, (size_t)-1, BTS_KERNEL
);
376 ds_selftest_bts_cpu(&conf
);
378 conf
.error
= ds_selftest_bts_bad_request_cpu(0, buffer
);
379 ds_release_bts(conf
.tracer
);
383 conf
.suspend
= ds_suspend_bts_noirq
;
384 conf
.resume
= ds_resume_bts_noirq
;
386 ds_request_bts_task(current
, small_buffer
, SMALL_BUFFER_SIZE
,
387 NULL
, (size_t)-1, BTS_KERNEL
);
389 ds_selftest_bts_cpu(&conf
);
391 conf
.error
= ds_selftest_bts_bad_request_cpu(0, buffer
);
392 ds_release_bts_noirq(conf
.tracer
);
393 local_irq_restore(irq
);
400 printk(KERN_CONT
"%s.\n", (conf
.error
? "failed" : "passed"));
405 int ds_selftest_pebs(void)