blob: cccc19a38f6d03969cafd825ce969d642eb5f27a [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 Metzger8a327f62009-03-13 10:45:07 +010014
15#include <asm/ds.h>
16
17
Markus Metzgerde79f542009-04-03 16:43:40 +020018#define BUFFER_SIZE 1021 /* Intentionally chose an odd size. */
Markus Metzger8a327f62009-03-13 10:45:07 +010019
20
21static int ds_selftest_bts_consistency(const struct bts_trace *trace)
22{
23 int error = 0;
24
25 if (!trace) {
26 printk(KERN_CONT "failed to access trace...");
27 /* Bail out. Other tests are pointless. */
28 return -1;
29 }
30
31 if (!trace->read) {
32 printk(KERN_CONT "bts read not available...");
33 error = -1;
34 }
35
36 /* Do some sanity checks on the trace configuration. */
37 if (!trace->ds.n) {
38 printk(KERN_CONT "empty bts buffer...");
39 error = -1;
40 }
41 if (!trace->ds.size) {
42 printk(KERN_CONT "bad bts trace setup...");
43 error = -1;
44 }
45 if (trace->ds.end !=
46 (char *)trace->ds.begin + (trace->ds.n * trace->ds.size)) {
47 printk(KERN_CONT "bad bts buffer setup...");
48 error = -1;
49 }
Markus Metzger84f20112009-04-03 16:43:43 +020050 /*
51 * We allow top in [begin; end], since its not clear when the
52 * overflow adjustment happens: after the increment or before the
53 * write.
54 */
Markus Metzger8a327f62009-03-13 10:45:07 +010055 if ((trace->ds.top < trace->ds.begin) ||
Markus Metzger84f20112009-04-03 16:43:43 +020056 (trace->ds.end < trace->ds.top)) {
Markus Metzger8a327f62009-03-13 10:45:07 +010057 printk(KERN_CONT "bts top out of bounds...");
58 error = -1;
59 }
60
61 return error;
62}
63
64static int ds_selftest_bts_read(struct bts_tracer *tracer,
65 const struct bts_trace *trace,
66 const void *from, const void *to)
67{
68 const unsigned char *at;
69
70 /*
71 * Check a few things which do not belong to this test.
72 * They should be covered by other tests.
73 */
74 if (!trace)
75 return -1;
76
77 if (!trace->read)
78 return -1;
79
80 if (to < from)
81 return -1;
82
83 if (from < trace->ds.begin)
84 return -1;
85
86 if (trace->ds.end < to)
87 return -1;
88
89 if (!trace->ds.size)
90 return -1;
91
92 /* Now to the test itself. */
93 for (at = from; (void *)at < to; at += trace->ds.size) {
94 struct bts_struct bts;
Markus Metzger353afee2009-04-03 16:43:42 +020095 unsigned long index;
Markus Metzger8a327f62009-03-13 10:45:07 +010096 int error;
97
98 if (((void *)at - trace->ds.begin) % trace->ds.size) {
99 printk(KERN_CONT
100 "read from non-integer index...");
101 return -1;
102 }
103 index = ((void *)at - trace->ds.begin) / trace->ds.size;
104
105 memset(&bts, 0, sizeof(bts));
106 error = trace->read(tracer, at, &bts);
107 if (error < 0) {
108 printk(KERN_CONT
109 "error reading bts trace at [%lu] (0x%p)...",
110 index, at);
111 return error;
112 }
113
114 switch (bts.qualifier) {
115 case BTS_BRANCH:
116 break;
117 default:
118 printk(KERN_CONT
119 "unexpected bts entry %llu at [%lu] (0x%p)...",
120 bts.qualifier, index, at);
121 return -1;
122 }
123 }
124
125 return 0;
126}
127
128int ds_selftest_bts(void)
129{
130 const struct bts_trace *trace;
131 struct bts_tracer *tracer;
132 int error = 0;
133 void *top;
Markus Metzgerde79f542009-04-03 16:43:40 +0200134 unsigned char buffer[BUFFER_SIZE];
Markus Metzger8a327f62009-03-13 10:45:07 +0100135
136 printk(KERN_INFO "[ds] bts selftest...");
137
Markus Metzgerde79f542009-04-03 16:43:40 +0200138 tracer = ds_request_bts_cpu(smp_processor_id(), buffer, BUFFER_SIZE,
139 NULL, (size_t)-1, BTS_KERNEL);
Markus Metzger8a327f62009-03-13 10:45:07 +0100140 if (IS_ERR(tracer)) {
141 error = PTR_ERR(tracer);
142 tracer = NULL;
143
144 printk(KERN_CONT
145 "initialization failed (err: %d)...", error);
146 goto out;
147 }
148
149 /* The return should already give us enough trace. */
150 ds_suspend_bts(tracer);
151
152 /* Let's see if we can access the trace. */
153 trace = ds_read_bts(tracer);
154
155 error = ds_selftest_bts_consistency(trace);
156 if (error < 0)
157 goto out;
158
159 /* If everything went well, we should have a few trace entries. */
160 if (trace->ds.top == trace->ds.begin) {
161 /*
162 * It is possible but highly unlikely that we got a
163 * buffer overflow and end up at exactly the same
164 * position we started from.
165 * Let's issue a warning, but continue.
166 */
167 printk(KERN_CONT "no trace/overflow...");
168 }
169
170 /* Let's try to read the trace we collected. */
171 error = ds_selftest_bts_read(tracer, trace,
172 trace->ds.begin, trace->ds.top);
173 if (error < 0)
174 goto out;
175
176 /*
177 * Let's read the trace again.
178 * Since we suspended tracing, we should get the same result.
179 */
180 top = trace->ds.top;
181
182 trace = ds_read_bts(tracer);
183 error = ds_selftest_bts_consistency(trace);
184 if (error < 0)
185 goto out;
186
187 if (top != trace->ds.top) {
188 printk(KERN_CONT "suspend not working...");
189 error = -1;
190 goto out;
191 }
192
193 /* Let's collect some more trace - see if resume is working. */
194 ds_resume_bts(tracer);
195 ds_suspend_bts(tracer);
196
197 trace = ds_read_bts(tracer);
198
199 error = ds_selftest_bts_consistency(trace);
200 if (error < 0)
201 goto out;
202
203 if (trace->ds.top == top) {
204 /*
205 * It is possible but highly unlikely that we got a
206 * buffer overflow and end up at exactly the same
207 * position we started from.
208 * Let's issue a warning and check the full trace.
209 */
210 printk(KERN_CONT
211 "no resume progress/overflow...");
212
213 error = ds_selftest_bts_read(tracer, trace,
214 trace->ds.begin, trace->ds.end);
215 } else if (trace->ds.top < top) {
216 /*
217 * We had a buffer overflow - the entire buffer should
218 * contain trace records.
219 */
220 error = ds_selftest_bts_read(tracer, trace,
221 trace->ds.begin, trace->ds.end);
222 } else {
223 /*
224 * It is quite likely that the buffer did not overflow.
225 * Let's just check the delta trace.
226 */
227 error = ds_selftest_bts_read(tracer, trace,
228 top, trace->ds.top);
229 }
230 if (error < 0)
231 goto out;
232
233 error = 0;
234
235 /* The final test: release the tracer while tracing is suspended. */
236 out:
237 ds_release_bts(tracer);
238
239 printk(KERN_CONT "%s.\n", (error ? "failed" : "passed"));
240
241 return error;
242}
243
244int ds_selftest_pebs(void)
245{
246 return 0;
247}