blob: 599a96300628afff8fbebc294aeb489f66224cdf [file] [log] [blame]
Markus Metzger8a327f62009-03-13 10:45:07 +01001/*
2 * Debug Store support - selftest
3 *
4 *
5 * Copyright (C) 2009 Intel Corporation.
6 * Markus Metzger <markus.t.metzger@intel.com>, 2009
7 */
8
9#include "ds_selftest.h"
10
11#include <linux/kernel.h>
12#include <linux/string.h>
Markus Metzgerde79f542009-04-03 16:43:40 +020013#include <linux/smp.h>
Markus Metzger01f65692009-04-03 16:43:44 +020014#include <linux/cpu.h>
Markus Metzger8a327f62009-03-13 10:45:07 +010015
16#include <asm/ds.h>
17
18
Markus Metzger01f65692009-04-03 16:43:44 +020019#define BUFFER_SIZE 521 /* Intentionally chose an odd size. */
Markus Metzger8a327f62009-03-13 10:45:07 +010020
21
Markus Metzger01f65692009-04-03 16:43:44 +020022struct 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
Markus Metzger8a327f62009-03-13 10:45:07 +010029static int ds_selftest_bts_consistency(const struct bts_trace *trace)
30{
31 int error = 0;
32
33 if (!trace) {
34 printk(KERN_CONT "failed to access trace...");
35 /* Bail out. Other tests are pointless. */
36 return -1;
37 }
38
39 if (!trace->read) {
40 printk(KERN_CONT "bts read not available...");
41 error = -1;
42 }
43
44 /* Do some sanity checks on the trace configuration. */
45 if (!trace->ds.n) {
46 printk(KERN_CONT "empty bts buffer...");
47 error = -1;
48 }
49 if (!trace->ds.size) {
50 printk(KERN_CONT "bad bts trace setup...");
51 error = -1;
52 }
53 if (trace->ds.end !=
54 (char *)trace->ds.begin + (trace->ds.n * trace->ds.size)) {
55 printk(KERN_CONT "bad bts buffer setup...");
56 error = -1;
57 }
Markus Metzger84f20112009-04-03 16:43:43 +020058 /*
59 * We allow top in [begin; end], since its not clear when the
60 * overflow adjustment happens: after the increment or before the
61 * write.
62 */
Markus Metzger8a327f62009-03-13 10:45:07 +010063 if ((trace->ds.top < trace->ds.begin) ||
Markus Metzger84f20112009-04-03 16:43:43 +020064 (trace->ds.end < trace->ds.top)) {
Markus Metzger8a327f62009-03-13 10:45:07 +010065 printk(KERN_CONT "bts top out of bounds...");
66 error = -1;
67 }
68
69 return error;
70}
71
72static int ds_selftest_bts_read(struct bts_tracer *tracer,
73 const struct bts_trace *trace,
74 const void *from, const void *to)
75{
76 const unsigned char *at;
77
78 /*
79 * Check a few things which do not belong to this test.
80 * They should be covered by other tests.
81 */
82 if (!trace)
83 return -1;
84
85 if (!trace->read)
86 return -1;
87
88 if (to < from)
89 return -1;
90
91 if (from < trace->ds.begin)
92 return -1;
93
94 if (trace->ds.end < to)
95 return -1;
96
97 if (!trace->ds.size)
98 return -1;
99
100 /* Now to the test itself. */
101 for (at = from; (void *)at < to; at += trace->ds.size) {
102 struct bts_struct bts;
Markus Metzger353afee2009-04-03 16:43:42 +0200103 unsigned long index;
Markus Metzger8a327f62009-03-13 10:45:07 +0100104 int error;
105
106 if (((void *)at - trace->ds.begin) % trace->ds.size) {
107 printk(KERN_CONT
108 "read from non-integer index...");
109 return -1;
110 }
111 index = ((void *)at - trace->ds.begin) / trace->ds.size;
112
113 memset(&bts, 0, sizeof(bts));
114 error = trace->read(tracer, at, &bts);
115 if (error < 0) {
116 printk(KERN_CONT
117 "error reading bts trace at [%lu] (0x%p)...",
118 index, at);
119 return error;
120 }
121
122 switch (bts.qualifier) {
123 case BTS_BRANCH:
124 break;
125 default:
126 printk(KERN_CONT
127 "unexpected bts entry %llu at [%lu] (0x%p)...",
128 bts.qualifier, index, at);
129 return -1;
130 }
131 }
132
133 return 0;
134}
135
Markus Metzger01f65692009-04-03 16:43:44 +0200136static void ds_selftest_bts_cpu(void *arg)
Markus Metzger8a327f62009-03-13 10:45:07 +0100137{
Markus Metzger01f65692009-04-03 16:43:44 +0200138 struct ds_selftest_bts_conf *conf = arg;
Markus Metzger8a327f62009-03-13 10:45:07 +0100139 const struct bts_trace *trace;
Markus Metzger8a327f62009-03-13 10:45:07 +0100140 void *top;
Markus Metzger8a327f62009-03-13 10:45:07 +0100141
Markus Metzger01f65692009-04-03 16:43:44 +0200142 if (IS_ERR(conf->tracer)) {
143 conf->error = PTR_ERR(conf->tracer);
144 conf->tracer = NULL;
Markus Metzger8a327f62009-03-13 10:45:07 +0100145
146 printk(KERN_CONT
Markus Metzger01f65692009-04-03 16:43:44 +0200147 "initialization failed (err: %d)...", conf->error);
148 return;
Markus Metzger8a327f62009-03-13 10:45:07 +0100149 }
150
Markus Metzger01f65692009-04-03 16:43:44 +0200151 /* We should meanwhile have enough trace. */
152 conf->error = conf->suspend(conf->tracer);
153 if (conf->error < 0)
154 return;
Markus Metzger8a327f62009-03-13 10:45:07 +0100155
156 /* Let's see if we can access the trace. */
Markus Metzger01f65692009-04-03 16:43:44 +0200157 trace = ds_read_bts(conf->tracer);
Markus Metzger8a327f62009-03-13 10:45:07 +0100158
Markus Metzger01f65692009-04-03 16:43:44 +0200159 conf->error = ds_selftest_bts_consistency(trace);
160 if (conf->error < 0)
161 return;
Markus Metzger8a327f62009-03-13 10:45:07 +0100162
163 /* If everything went well, we should have a few trace entries. */
164 if (trace->ds.top == trace->ds.begin) {
165 /*
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.
170 */
171 printk(KERN_CONT "no trace/overflow...");
172 }
173
174 /* Let's try to read the trace we collected. */
Markus Metzger01f65692009-04-03 16:43:44 +0200175 conf->error =
176 ds_selftest_bts_read(conf->tracer, trace,
Markus Metzger8a327f62009-03-13 10:45:07 +0100177 trace->ds.begin, trace->ds.top);
Markus Metzger01f65692009-04-03 16:43:44 +0200178 if (conf->error < 0)
179 return;
Markus Metzger8a327f62009-03-13 10:45:07 +0100180
181 /*
182 * Let's read the trace again.
183 * Since we suspended tracing, we should get the same result.
184 */
185 top = trace->ds.top;
186
Markus Metzger01f65692009-04-03 16:43:44 +0200187 trace = ds_read_bts(conf->tracer);
188 conf->error = ds_selftest_bts_consistency(trace);
189 if (conf->error < 0)
190 return;
Markus Metzger8a327f62009-03-13 10:45:07 +0100191
192 if (top != trace->ds.top) {
193 printk(KERN_CONT "suspend not working...");
Markus Metzger01f65692009-04-03 16:43:44 +0200194 conf->error = -1;
195 return;
Markus Metzger8a327f62009-03-13 10:45:07 +0100196 }
197
198 /* Let's collect some more trace - see if resume is working. */
Markus Metzger01f65692009-04-03 16:43:44 +0200199 conf->error = conf->resume(conf->tracer);
200 if (conf->error < 0)
201 return;
Markus Metzger8a327f62009-03-13 10:45:07 +0100202
Markus Metzger01f65692009-04-03 16:43:44 +0200203 conf->error = conf->suspend(conf->tracer);
204 if (conf->error < 0)
205 return;
Markus Metzger8a327f62009-03-13 10:45:07 +0100206
Markus Metzger01f65692009-04-03 16:43:44 +0200207 trace = ds_read_bts(conf->tracer);
208
209 conf->error = ds_selftest_bts_consistency(trace);
210 if (conf->error < 0)
211 return;
Markus Metzger8a327f62009-03-13 10:45:07 +0100212
213 if (trace->ds.top == top) {
214 /*
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.
219 */
220 printk(KERN_CONT
221 "no resume progress/overflow...");
222
Markus Metzger01f65692009-04-03 16:43:44 +0200223 conf->error =
224 ds_selftest_bts_read(conf->tracer, trace,
Markus Metzger8a327f62009-03-13 10:45:07 +0100225 trace->ds.begin, trace->ds.end);
226 } else if (trace->ds.top < top) {
227 /*
228 * We had a buffer overflow - the entire buffer should
229 * contain trace records.
230 */
Markus Metzger01f65692009-04-03 16:43:44 +0200231 conf->error =
232 ds_selftest_bts_read(conf->tracer, trace,
Markus Metzger8a327f62009-03-13 10:45:07 +0100233 trace->ds.begin, trace->ds.end);
234 } else {
235 /*
236 * It is quite likely that the buffer did not overflow.
237 * Let's just check the delta trace.
238 */
Markus Metzger01f65692009-04-03 16:43:44 +0200239 conf->error =
240 ds_selftest_bts_read(conf->tracer, trace, top,
241 trace->ds.top);
Markus Metzger8a327f62009-03-13 10:45:07 +0100242 }
Markus Metzger01f65692009-04-03 16:43:44 +0200243 if (conf->error < 0)
244 return;
Markus Metzger8a327f62009-03-13 10:45:07 +0100245
Markus Metzger01f65692009-04-03 16:43:44 +0200246 conf->error = 0;
247}
Markus Metzger8a327f62009-03-13 10:45:07 +0100248
Markus Metzger01f65692009-04-03 16:43:44 +0200249static int ds_suspend_bts_wrap(struct bts_tracer *tracer)
250{
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}
260
261static void ds_release_bts_noirq_wrap(void *tracer)
262{
263 (void)ds_release_bts_noirq(tracer);
264}
265
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;
Markus Metzger8a327f62009-03-13 10:45:07 +0100325 out:
Markus Metzger01f65692009-04-03 16:43:44 +0200326 put_online_cpus();
327 printk(KERN_CONT "%s.\n", (conf.error ? "failed" : "passed"));
Markus Metzger8a327f62009-03-13 10:45:07 +0100328
Markus Metzger01f65692009-04-03 16:43:44 +0200329 return conf.error;
Markus Metzger8a327f62009-03-13 10:45:07 +0100330}
331
332int ds_selftest_pebs(void)
333{
334 return 0;
335}