aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma/dmatest.c
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2009-03-25 12:13:25 -0400
committerDan Williams <dan.j.williams@intel.com>2009-03-25 12:13:25 -0400
commitb54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0c (patch)
treee825eb374b73240180d33b34be8ab10d6dffbd1a /drivers/dma/dmatest.c
parent729b5d1b8ec72c28e99840b3f300ba67726e3ab9 (diff)
dmatest: add xor test
Extend dmatest to launch a thread per supported operation type and add an xor test. Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/dma/dmatest.c')
-rw-r--r--drivers/dma/dmatest.c274
1 files changed, 189 insertions, 85 deletions
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index e190d8b30700..224acf478fec 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -38,6 +38,11 @@ module_param(max_channels, uint, S_IRUGO);
38MODULE_PARM_DESC(max_channels, 38MODULE_PARM_DESC(max_channels,
39 "Maximum number of channels to use (default: all)"); 39 "Maximum number of channels to use (default: all)");
40 40
41static unsigned int xor_sources = 3;
42module_param(xor_sources, uint, S_IRUGO);
43MODULE_PARM_DESC(xor_sources,
44 "Number of xor source buffers (default: 3)");
45
41/* 46/*
42 * Initialization patterns. All bytes in the source buffer has bit 7 47 * Initialization patterns. All bytes in the source buffer has bit 7
43 * set, all bytes in the destination buffer has bit 7 cleared. 48 * set, all bytes in the destination buffer has bit 7 cleared.
@@ -59,8 +64,9 @@ struct dmatest_thread {
59 struct list_head node; 64 struct list_head node;
60 struct task_struct *task; 65 struct task_struct *task;
61 struct dma_chan *chan; 66 struct dma_chan *chan;
62 u8 *srcbuf; 67 u8 **srcs;
63 u8 *dstbuf; 68 u8 **dsts;
69 enum dma_transaction_type type;
64}; 70};
65 71
66struct dmatest_chan { 72struct dmatest_chan {
@@ -98,30 +104,37 @@ static unsigned long dmatest_random(void)
98 return buf; 104 return buf;
99} 105}
100 106
101static void dmatest_init_srcbuf(u8 *buf, unsigned int start, unsigned int len) 107static void dmatest_init_srcs(u8 **bufs, unsigned int start, unsigned int len)
102{ 108{
103 unsigned int i; 109 unsigned int i;
104 110 u8 *buf;
105 for (i = 0; i < start; i++) 111
106 buf[i] = PATTERN_SRC | (~i & PATTERN_COUNT_MASK); 112 for (; (buf = *bufs); bufs++) {
107 for ( ; i < start + len; i++) 113 for (i = 0; i < start; i++)
108 buf[i] = PATTERN_SRC | PATTERN_COPY 114 buf[i] = PATTERN_SRC | (~i & PATTERN_COUNT_MASK);
109 | (~i & PATTERN_COUNT_MASK);; 115 for ( ; i < start + len; i++)
110 for ( ; i < test_buf_size; i++) 116 buf[i] = PATTERN_SRC | PATTERN_COPY
111 buf[i] = PATTERN_SRC | (~i & PATTERN_COUNT_MASK); 117 | (~i & PATTERN_COUNT_MASK);;
118 for ( ; i < test_buf_size; i++)
119 buf[i] = PATTERN_SRC | (~i & PATTERN_COUNT_MASK);
120 buf++;
121 }
112} 122}
113 123
114static void dmatest_init_dstbuf(u8 *buf, unsigned int start, unsigned int len) 124static void dmatest_init_dsts(u8 **bufs, unsigned int start, unsigned int len)
115{ 125{
116 unsigned int i; 126 unsigned int i;
117 127 u8 *buf;
118 for (i = 0; i < start; i++) 128
119 buf[i] = PATTERN_DST | (~i & PATTERN_COUNT_MASK); 129 for (; (buf = *bufs); bufs++) {
120 for ( ; i < start + len; i++) 130 for (i = 0; i < start; i++)
121 buf[i] = PATTERN_DST | PATTERN_OVERWRITE 131 buf[i] = PATTERN_DST | (~i & PATTERN_COUNT_MASK);
122 | (~i & PATTERN_COUNT_MASK); 132 for ( ; i < start + len; i++)
123 for ( ; i < test_buf_size; i++) 133 buf[i] = PATTERN_DST | PATTERN_OVERWRITE
124 buf[i] = PATTERN_DST | (~i & PATTERN_COUNT_MASK); 134 | (~i & PATTERN_COUNT_MASK);
135 for ( ; i < test_buf_size; i++)
136 buf[i] = PATTERN_DST | (~i & PATTERN_COUNT_MASK);
137 }
125} 138}
126 139
127static void dmatest_mismatch(u8 actual, u8 pattern, unsigned int index, 140static void dmatest_mismatch(u8 actual, u8 pattern, unsigned int index,
@@ -150,23 +163,30 @@ static void dmatest_mismatch(u8 actual, u8 pattern, unsigned int index,
150 thread_name, index, expected, actual); 163 thread_name, index, expected, actual);
151} 164}
152 165
153static unsigned int dmatest_verify(u8 *buf, unsigned int start, 166static unsigned int dmatest_verify(u8 **bufs, unsigned int start,
154 unsigned int end, unsigned int counter, u8 pattern, 167 unsigned int end, unsigned int counter, u8 pattern,
155 bool is_srcbuf) 168 bool is_srcbuf)
156{ 169{
157 unsigned int i; 170 unsigned int i;
158 unsigned int error_count = 0; 171 unsigned int error_count = 0;
159 u8 actual; 172 u8 actual;
160 173 u8 expected;
161 for (i = start; i < end; i++) { 174 u8 *buf;
162 actual = buf[i]; 175 unsigned int counter_orig = counter;
163 if (actual != (pattern | (~counter & PATTERN_COUNT_MASK))) { 176
164 if (error_count < 32) 177 for (; (buf = *bufs); bufs++) {
165 dmatest_mismatch(actual, pattern, i, counter, 178 counter = counter_orig;
166 is_srcbuf); 179 for (i = start; i < end; i++) {
167 error_count++; 180 actual = buf[i];
181 expected = pattern | (~counter & PATTERN_COUNT_MASK);
182 if (actual != expected) {
183 if (error_count < 32)
184 dmatest_mismatch(actual, pattern, i,
185 counter, is_srcbuf);
186 error_count++;
187 }
188 counter++;
168 } 189 }
169 counter++;
170 } 190 }
171 191
172 if (error_count > 32) 192 if (error_count > 32)
@@ -178,10 +198,10 @@ static unsigned int dmatest_verify(u8 *buf, unsigned int start,
178 198
179/* 199/*
180 * This function repeatedly tests DMA transfers of various lengths and 200 * This function repeatedly tests DMA transfers of various lengths and
181 * offsets until it is told to exit by kthread_stop(). There may be 201 * offsets for a given operation type until it is told to exit by
182 * multiple threads running this function in parallel for a single 202 * kthread_stop(). There may be multiple threads running this function
183 * channel, and there may be multiple channels being tested in 203 * in parallel for a single channel, and there may be multiple channels
184 * parallel. 204 * being tested in parallel.
185 * 205 *
186 * Before each test, the source and destination buffer is initialized 206 * Before each test, the source and destination buffer is initialized
187 * with a known pattern. This pattern is different depending on 207 * with a known pattern. This pattern is different depending on
@@ -201,25 +221,53 @@ static int dmatest_func(void *data)
201 unsigned int total_tests = 0; 221 unsigned int total_tests = 0;
202 dma_cookie_t cookie; 222 dma_cookie_t cookie;
203 enum dma_status status; 223 enum dma_status status;
224 enum dma_ctrl_flags flags;
204 int ret; 225 int ret;
226 int src_cnt;
227 int dst_cnt;
228 int i;
205 229
206 thread_name = current->comm; 230 thread_name = current->comm;
207 231
208 ret = -ENOMEM; 232 ret = -ENOMEM;
209 thread->srcbuf = kmalloc(test_buf_size, GFP_KERNEL);
210 if (!thread->srcbuf)
211 goto err_srcbuf;
212 thread->dstbuf = kmalloc(test_buf_size, GFP_KERNEL);
213 if (!thread->dstbuf)
214 goto err_dstbuf;
215 233
216 smp_rmb(); 234 smp_rmb();
217 chan = thread->chan; 235 chan = thread->chan;
236 if (thread->type == DMA_MEMCPY)
237 src_cnt = dst_cnt = 1;
238 else if (thread->type == DMA_XOR) {
239 src_cnt = xor_sources | 1; /* force odd to ensure dst = src */
240 dst_cnt = 1;
241 } else
242 goto err_srcs;
243
244 thread->srcs = kcalloc(src_cnt+1, sizeof(u8 *), GFP_KERNEL);
245 if (!thread->srcs)
246 goto err_srcs;
247 for (i = 0; i < src_cnt; i++) {
248 thread->srcs[i] = kmalloc(test_buf_size, GFP_KERNEL);
249 if (!thread->srcs[i])
250 goto err_srcbuf;
251 }
252 thread->srcs[i] = NULL;
253
254 thread->dsts = kcalloc(dst_cnt+1, sizeof(u8 *), GFP_KERNEL);
255 if (!thread->dsts)
256 goto err_dsts;
257 for (i = 0; i < dst_cnt; i++) {
258 thread->dsts[i] = kmalloc(test_buf_size, GFP_KERNEL);
259 if (!thread->dsts[i])
260 goto err_dstbuf;
261 }
262 thread->dsts[i] = NULL;
263
264 flags = DMA_CTRL_ACK | DMA_COMPL_SKIP_DEST_UNMAP;
218 265
219 while (!kthread_should_stop()) { 266 while (!kthread_should_stop()) {
220 struct dma_device *dev = chan->device; 267 struct dma_device *dev = chan->device;
221 struct dma_async_tx_descriptor *tx; 268 struct dma_async_tx_descriptor *tx = NULL;
222 dma_addr_t dma_src, dma_dest; 269 dma_addr_t dma_srcs[src_cnt];
270 dma_addr_t dma_dsts[dst_cnt];
223 271
224 total_tests++; 272 total_tests++;
225 273
@@ -227,22 +275,41 @@ static int dmatest_func(void *data)
227 src_off = dmatest_random() % (test_buf_size - len + 1); 275 src_off = dmatest_random() % (test_buf_size - len + 1);
228 dst_off = dmatest_random() % (test_buf_size - len + 1); 276 dst_off = dmatest_random() % (test_buf_size - len + 1);
229 277
230 dmatest_init_srcbuf(thread->srcbuf, src_off, len); 278 dmatest_init_srcs(thread->srcs, src_off, len);
231 dmatest_init_dstbuf(thread->dstbuf, dst_off, len); 279 dmatest_init_dsts(thread->dsts, dst_off, len);
280
281 for (i = 0; i < src_cnt; i++) {
282 u8 *buf = thread->srcs[i] + src_off;
232 283
233 dma_src = dma_map_single(dev->dev, thread->srcbuf + src_off, 284 dma_srcs[i] = dma_map_single(dev->dev, buf, len,
234 len, DMA_TO_DEVICE); 285 DMA_TO_DEVICE);
286 }
235 /* map with DMA_BIDIRECTIONAL to force writeback/invalidate */ 287 /* map with DMA_BIDIRECTIONAL to force writeback/invalidate */
236 dma_dest = dma_map_single(dev->dev, thread->dstbuf, 288 for (i = 0; i < dst_cnt; i++) {
237 test_buf_size, DMA_BIDIRECTIONAL); 289 dma_dsts[i] = dma_map_single(dev->dev, thread->dsts[i],
290 test_buf_size,
291 DMA_BIDIRECTIONAL);
292 }
293
294 if (thread->type == DMA_MEMCPY)
295 tx = dev->device_prep_dma_memcpy(chan,
296 dma_dsts[0] + dst_off,
297 dma_srcs[0], len,
298 flags);
299 else if (thread->type == DMA_XOR)
300 tx = dev->device_prep_dma_xor(chan,
301 dma_dsts[0] + dst_off,
302 dma_srcs, xor_sources,
303 len, flags);
238 304
239 tx = dev->device_prep_dma_memcpy(chan, dma_dest + dst_off,
240 dma_src, len,
241 DMA_CTRL_ACK | DMA_COMPL_SKIP_DEST_UNMAP);
242 if (!tx) { 305 if (!tx) {
243 dma_unmap_single(dev->dev, dma_src, len, DMA_TO_DEVICE); 306 for (i = 0; i < src_cnt; i++)
244 dma_unmap_single(dev->dev, dma_dest, 307 dma_unmap_single(dev->dev, dma_srcs[i], len,
245 test_buf_size, DMA_BIDIRECTIONAL); 308 DMA_TO_DEVICE);
309 for (i = 0; i < dst_cnt; i++)
310 dma_unmap_single(dev->dev, dma_dsts[i],
311 test_buf_size,
312 DMA_BIDIRECTIONAL);
246 pr_warning("%s: #%u: prep error with src_off=0x%x " 313 pr_warning("%s: #%u: prep error with src_off=0x%x "
247 "dst_off=0x%x len=0x%x\n", 314 "dst_off=0x%x len=0x%x\n",
248 thread_name, total_tests - 1, 315 thread_name, total_tests - 1,
@@ -263,11 +330,11 @@ static int dmatest_func(void *data)
263 failed_tests++; 330 failed_tests++;
264 continue; 331 continue;
265 } 332 }
266 dma_async_memcpy_issue_pending(chan); 333 dma_async_issue_pending(chan);
267 334
268 do { 335 do {
269 msleep(1); 336 msleep(1);
270 status = dma_async_memcpy_complete( 337 status = dma_async_is_tx_complete(
271 chan, cookie, NULL, NULL); 338 chan, cookie, NULL, NULL);
272 } while (status == DMA_IN_PROGRESS); 339 } while (status == DMA_IN_PROGRESS);
273 340
@@ -278,29 +345,30 @@ static int dmatest_func(void *data)
278 continue; 345 continue;
279 } 346 }
280 /* Unmap by myself (see DMA_COMPL_SKIP_DEST_UNMAP above) */ 347 /* Unmap by myself (see DMA_COMPL_SKIP_DEST_UNMAP above) */
281 dma_unmap_single(dev->dev, dma_dest, 348 for (i = 0; i < dst_cnt; i++)
282 test_buf_size, DMA_BIDIRECTIONAL); 349 dma_unmap_single(dev->dev, dma_dsts[i], test_buf_size,
350 DMA_BIDIRECTIONAL);
283 351
284 error_count = 0; 352 error_count = 0;
285 353
286 pr_debug("%s: verifying source buffer...\n", thread_name); 354 pr_debug("%s: verifying source buffer...\n", thread_name);
287 error_count += dmatest_verify(thread->srcbuf, 0, src_off, 355 error_count += dmatest_verify(thread->srcs, 0, src_off,
288 0, PATTERN_SRC, true); 356 0, PATTERN_SRC, true);
289 error_count += dmatest_verify(thread->srcbuf, src_off, 357 error_count += dmatest_verify(thread->srcs, src_off,
290 src_off + len, src_off, 358 src_off + len, src_off,
291 PATTERN_SRC | PATTERN_COPY, true); 359 PATTERN_SRC | PATTERN_COPY, true);
292 error_count += dmatest_verify(thread->srcbuf, src_off + len, 360 error_count += dmatest_verify(thread->srcs, src_off + len,
293 test_buf_size, src_off + len, 361 test_buf_size, src_off + len,
294 PATTERN_SRC, true); 362 PATTERN_SRC, true);
295 363
296 pr_debug("%s: verifying dest buffer...\n", 364 pr_debug("%s: verifying dest buffer...\n",
297 thread->task->comm); 365 thread->task->comm);
298 error_count += dmatest_verify(thread->dstbuf, 0, dst_off, 366 error_count += dmatest_verify(thread->dsts, 0, dst_off,
299 0, PATTERN_DST, false); 367 0, PATTERN_DST, false);
300 error_count += dmatest_verify(thread->dstbuf, dst_off, 368 error_count += dmatest_verify(thread->dsts, dst_off,
301 dst_off + len, src_off, 369 dst_off + len, src_off,
302 PATTERN_SRC | PATTERN_COPY, false); 370 PATTERN_SRC | PATTERN_COPY, false);
303 error_count += dmatest_verify(thread->dstbuf, dst_off + len, 371 error_count += dmatest_verify(thread->dsts, dst_off + len,
304 test_buf_size, dst_off + len, 372 test_buf_size, dst_off + len,
305 PATTERN_DST, false); 373 PATTERN_DST, false);
306 374
@@ -319,10 +387,16 @@ static int dmatest_func(void *data)
319 } 387 }
320 388
321 ret = 0; 389 ret = 0;
322 kfree(thread->dstbuf); 390 for (i = 0; thread->dsts[i]; i++)
391 kfree(thread->dsts[i]);
323err_dstbuf: 392err_dstbuf:
324 kfree(thread->srcbuf); 393 kfree(thread->dsts);
394err_dsts:
395 for (i = 0; thread->srcs[i]; i++)
396 kfree(thread->srcs[i]);
325err_srcbuf: 397err_srcbuf:
398 kfree(thread->srcs);
399err_srcs:
326 pr_notice("%s: terminating after %u tests, %u failures (status %d)\n", 400 pr_notice("%s: terminating after %u tests, %u failures (status %d)\n",
327 thread_name, total_tests, failed_tests, ret); 401 thread_name, total_tests, failed_tests, ret);
328 return ret; 402 return ret;
@@ -344,35 +418,36 @@ static void dmatest_cleanup_channel(struct dmatest_chan *dtc)
344 kfree(dtc); 418 kfree(dtc);
345} 419}
346 420
347static int dmatest_add_channel(struct dma_chan *chan) 421static int dmatest_add_threads(struct dmatest_chan *dtc, enum dma_transaction_type type)
348{ 422{
349 struct dmatest_chan *dtc; 423 struct dmatest_thread *thread;
350 struct dmatest_thread *thread; 424 struct dma_chan *chan = dtc->chan;
351 unsigned int i; 425 char *op;
352 426 unsigned int i;
353 dtc = kmalloc(sizeof(struct dmatest_chan), GFP_KERNEL);
354 if (!dtc) {
355 pr_warning("dmatest: No memory for %s\n", dma_chan_name(chan));
356 return -ENOMEM;
357 }
358 427
359 dtc->chan = chan; 428 if (type == DMA_MEMCPY)
360 INIT_LIST_HEAD(&dtc->threads); 429 op = "copy";
430 else if (type == DMA_XOR)
431 op = "xor";
432 else
433 return -EINVAL;
361 434
362 for (i = 0; i < threads_per_chan; i++) { 435 for (i = 0; i < threads_per_chan; i++) {
363 thread = kzalloc(sizeof(struct dmatest_thread), GFP_KERNEL); 436 thread = kzalloc(sizeof(struct dmatest_thread), GFP_KERNEL);
364 if (!thread) { 437 if (!thread) {
365 pr_warning("dmatest: No memory for %s-test%u\n", 438 pr_warning("dmatest: No memory for %s-%s%u\n",
366 dma_chan_name(chan), i); 439 dma_chan_name(chan), op, i);
440
367 break; 441 break;
368 } 442 }
369 thread->chan = dtc->chan; 443 thread->chan = dtc->chan;
444 thread->type = type;
370 smp_wmb(); 445 smp_wmb();
371 thread->task = kthread_run(dmatest_func, thread, "%s-test%u", 446 thread->task = kthread_run(dmatest_func, thread, "%s-%s%u",
372 dma_chan_name(chan), i); 447 dma_chan_name(chan), op, i);
373 if (IS_ERR(thread->task)) { 448 if (IS_ERR(thread->task)) {
374 pr_warning("dmatest: Failed to run thread %s-test%u\n", 449 pr_warning("dmatest: Failed to run thread %s-%s%u\n",
375 dma_chan_name(chan), i); 450 dma_chan_name(chan), op, i);
376 kfree(thread); 451 kfree(thread);
377 break; 452 break;
378 } 453 }
@@ -382,7 +457,36 @@ static int dmatest_add_channel(struct dma_chan *chan)
382 list_add_tail(&thread->node, &dtc->threads); 457 list_add_tail(&thread->node, &dtc->threads);
383 } 458 }
384 459
385 pr_info("dmatest: Started %u threads using %s\n", i, dma_chan_name(chan)); 460 return i;
461}
462
463static int dmatest_add_channel(struct dma_chan *chan)
464{
465 struct dmatest_chan *dtc;
466 struct dma_device *dma_dev = chan->device;
467 unsigned int thread_count = 0;
468 unsigned int cnt;
469
470 dtc = kmalloc(sizeof(struct dmatest_chan), GFP_KERNEL);
471 if (!dtc) {
472 pr_warning("dmatest: No memory for %s\n", dma_chan_name(chan));
473 return -ENOMEM;
474 }
475
476 dtc->chan = chan;
477 INIT_LIST_HEAD(&dtc->threads);
478
479 if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask)) {
480 cnt = dmatest_add_threads(dtc, DMA_MEMCPY);
481 thread_count += cnt > 0 ?: 0;
482 }
483 if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) {
484 cnt = dmatest_add_threads(dtc, DMA_XOR);
485 thread_count += cnt > 0 ?: 0;
486 }
487
488 pr_info("dmatest: Started %u threads using %s\n",
489 thread_count, dma_chan_name(chan));
386 490
387 list_add_tail(&dtc->node, &dmatest_channels); 491 list_add_tail(&dtc->node, &dmatest_channels);
388 nr_channels++; 492 nr_channels++;