Blame view
drivers/dma/dmatest.c
34.1 KB
d2912cb15 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
4a776f0aa dmatest: Simple D... |
2 3 4 5 |
/* * DMA Engine test module * * Copyright (C) 2007 Atmel Corporation |
851b7e16a dmatest: run test... |
6 |
* Copyright (C) 2013 Intel Corporation |
4a776f0aa dmatest: Simple D... |
7 |
*/ |
872f05c6e dmatest: replace ... |
8 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
4a776f0aa dmatest: Simple D... |
9 |
#include <linux/delay.h> |
b7f080cfe net: remove mm.h ... |
10 |
#include <linux/dma-mapping.h> |
4a776f0aa dmatest: Simple D... |
11 |
#include <linux/dmaengine.h> |
981ed70d8 dmatest: make dma... |
12 |
#include <linux/freezer.h> |
4a776f0aa dmatest: Simple D... |
13 14 |
#include <linux/init.h> #include <linux/kthread.h> |
0881e7bd3 sched/headers: Pr... |
15 |
#include <linux/sched/task.h> |
4a776f0aa dmatest: Simple D... |
16 17 18 |
#include <linux/module.h> #include <linux/moduleparam.h> #include <linux/random.h> |
5a0e3ad6a include cleanup: ... |
19 |
#include <linux/slab.h> |
4a776f0aa dmatest: Simple D... |
20 21 22 |
#include <linux/wait.h> static unsigned int test_buf_size = 16384; |
a6c268d03 dmatest: make mod... |
23 |
module_param(test_buf_size, uint, S_IRUGO | S_IWUSR); |
4a776f0aa dmatest: Simple D... |
24 |
MODULE_PARM_DESC(test_buf_size, "Size of the memcpy test buffer"); |
a85159fec DMA: dmatest: ext... |
25 |
static char test_device[32]; |
a6c268d03 dmatest: make mod... |
26 27 |
module_param_string(device, test_device, sizeof(test_device), S_IRUGO | S_IWUSR); |
4a776f0aa dmatest: Simple D... |
28 29 30 |
MODULE_PARM_DESC(device, "Bus ID of the DMA Engine to test (default: any)"); static unsigned int threads_per_chan = 1; |
a6c268d03 dmatest: make mod... |
31 |
module_param(threads_per_chan, uint, S_IRUGO | S_IWUSR); |
4a776f0aa dmatest: Simple D... |
32 33 34 35 |
MODULE_PARM_DESC(threads_per_chan, "Number of threads to start per channel (default: 1)"); static unsigned int max_channels; |
a6c268d03 dmatest: make mod... |
36 |
module_param(max_channels, uint, S_IRUGO | S_IWUSR); |
33df8ca06 dmatest: convert ... |
37 |
MODULE_PARM_DESC(max_channels, |
4a776f0aa dmatest: Simple D... |
38 |
"Maximum number of channels to use (default: all)"); |
0a2ff57d6 dmaengine: dmates... |
39 |
static unsigned int iterations; |
a6c268d03 dmatest: make mod... |
40 |
module_param(iterations, uint, S_IRUGO | S_IWUSR); |
0a2ff57d6 dmaengine: dmates... |
41 42 |
MODULE_PARM_DESC(iterations, "Iterations before stopping test (default: infinite)"); |
d86467249 dmaengine: dmates... |
43 |
static unsigned int dmatest; |
a0d4cb44d dmaengine: dmates... |
44 45 |
module_param(dmatest, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(dmatest, |
c678fa663 dmaengine: remove... |
46 |
"dmatest 0-memcpy 1-memset (default: 0)"); |
a0d4cb44d dmaengine: dmates... |
47 |
|
b54d5cb91 dmatest: add xor ... |
48 |
static unsigned int xor_sources = 3; |
a6c268d03 dmatest: make mod... |
49 |
module_param(xor_sources, uint, S_IRUGO | S_IWUSR); |
b54d5cb91 dmatest: add xor ... |
50 51 |
MODULE_PARM_DESC(xor_sources, "Number of xor source buffers (default: 3)"); |
58691d64c dmatest: add pq s... |
52 |
static unsigned int pq_sources = 3; |
a6c268d03 dmatest: make mod... |
53 |
module_param(pq_sources, uint, S_IRUGO | S_IWUSR); |
58691d64c dmatest: add pq s... |
54 55 |
MODULE_PARM_DESC(pq_sources, "Number of p+q source buffers (default: 3)"); |
d42efe6bf dmaengine/dmatest... |
56 |
static int timeout = 3000; |
a6c268d03 dmatest: make mod... |
57 |
module_param(timeout, uint, S_IRUGO | S_IWUSR); |
85ee7a1d3 treewide: cleanup... |
58 |
MODULE_PARM_DESC(timeout, "Transfer Timeout in msec (default: 3000), " |
ed04b7c57 dmaengine: dmates... |
59 |
"Pass 0xFFFFFFFF (4294967295) for maximum timeout"); |
d42efe6bf dmaengine/dmatest... |
60 |
|
e3b9c3473 dmatest: add supp... |
61 62 |
static bool noverify; module_param(noverify, bool, S_IRUGO | S_IWUSR); |
2e67a0875 dmaengine: dmates... |
63 64 65 66 67 |
MODULE_PARM_DESC(noverify, "Disable data verification (default: verify)"); static bool norandom; module_param(norandom, bool, 0644); MODULE_PARM_DESC(norandom, "Disable random offset setup (default: random)"); |
4a776f0aa dmatest: Simple D... |
68 |
|
fb9816f9d dmaengine: dmates... |
69 70 71 |
static bool polled; module_param(polled, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(polled, "Use polling for completion instead of interrupts"); |
50137a7df dmatest: verbose ... |
72 73 74 |
static bool verbose; module_param(verbose, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(verbose, "Enable \"success\" result messages (default: off)"); |
4a776f0aa dmatest: Simple D... |
75 |
|
a875abfad dmaengine: dmates... |
76 77 78 |
static int alignment = -1; module_param(alignment, int, 0644); MODULE_PARM_DESC(alignment, "Custom data address alignment taken as 2^(alignment) (default: not used (-1))"); |
13396a130 dmaengine: dmates... |
79 80 81 |
static unsigned int transfer_size; module_param(transfer_size, uint, 0644); MODULE_PARM_DESC(transfer_size, "Optional custom transfer size in bytes (default: not used (0))"); |
e03e93a97 dmatest: create d... |
82 |
/** |
15b8a8ea1 dmatest: split te... |
83 |
* struct dmatest_params - test parameters. |
e03e93a97 dmatest: create d... |
84 85 86 87 88 89 90 91 |
* @buf_size: size of the memcpy test buffer * @channel: bus ID of the channel to test * @device: bus ID of the DMA Engine to test * @threads_per_chan: number of threads to start per channel * @max_channels: maximum number of channels to use * @iterations: iterations before stopping test * @xor_sources: number of xor source buffers * @pq_sources: number of p+q source buffers |
ed04b7c57 dmaengine: dmates... |
92 |
* @timeout: transfer timeout in msec, 0 - 0xFFFFFFFF (4294967295) |
e03e93a97 dmatest: create d... |
93 |
*/ |
15b8a8ea1 dmatest: split te... |
94 |
struct dmatest_params { |
e03e93a97 dmatest: create d... |
95 96 |
unsigned int buf_size; char channel[20]; |
a85159fec DMA: dmatest: ext... |
97 |
char device[32]; |
e03e93a97 dmatest: create d... |
98 99 100 101 102 |
unsigned int threads_per_chan; unsigned int max_channels; unsigned int iterations; unsigned int xor_sources; unsigned int pq_sources; |
ed04b7c57 dmaengine: dmates... |
103 |
unsigned int timeout; |
e3b9c3473 dmatest: add supp... |
104 |
bool noverify; |
2e67a0875 dmaengine: dmates... |
105 |
bool norandom; |
a875abfad dmaengine: dmates... |
106 |
int alignment; |
13396a130 dmaengine: dmates... |
107 |
unsigned int transfer_size; |
fb9816f9d dmaengine: dmates... |
108 |
bool polled; |
15b8a8ea1 dmatest: split te... |
109 110 111 112 113 |
}; /** * struct dmatest_info - test information. * @params: test parameters |
851b7e16a dmatest: run test... |
114 |
* @lock: access protection to the fields of this structure |
15b8a8ea1 dmatest: split te... |
115 |
*/ |
a310d037b dmatest: restore ... |
116 |
static struct dmatest_info { |
15b8a8ea1 dmatest: split te... |
117 118 |
/* Test parameters */ struct dmatest_params params; |
838cc704c dmatest: move dma... |
119 120 121 122 |
/* Internal state */ struct list_head channels; unsigned int nr_channels; |
851b7e16a dmatest: run test... |
123 |
struct mutex lock; |
a310d037b dmatest: restore ... |
124 125 126 127 128 |
bool did_init; } test_info = { .channels = LIST_HEAD_INIT(test_info.channels), .lock = __MUTEX_INITIALIZER(test_info.lock), }; |
851b7e16a dmatest: run test... |
129 |
|
a310d037b dmatest: restore ... |
130 131 |
static int dmatest_run_set(const char *val, const struct kernel_param *kp); static int dmatest_run_get(char *val, const struct kernel_param *kp); |
9c27847dd kernel/params: co... |
132 |
static const struct kernel_param_ops run_ops = { |
a310d037b dmatest: restore ... |
133 134 |
.set = dmatest_run_set, .get = dmatest_run_get, |
e03e93a97 dmatest: create d... |
135 |
}; |
a310d037b dmatest: restore ... |
136 137 138 |
static bool dmatest_run; module_param_cb(run, &run_ops, &dmatest_run, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(run, "Run the test (default: false)"); |
e03e93a97 dmatest: create d... |
139 |
|
d53513d5d dmaengine: dmates... |
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
static int dmatest_chan_set(const char *val, const struct kernel_param *kp); static int dmatest_chan_get(char *val, const struct kernel_param *kp); static const struct kernel_param_ops multi_chan_ops = { .set = dmatest_chan_set, .get = dmatest_chan_get, }; static char test_channel[20]; static struct kparam_string newchan_kps = { .string = test_channel, .maxlen = 20, }; module_param_cb(channel, &multi_chan_ops, &newchan_kps, 0644); MODULE_PARM_DESC(channel, "Bus ID of the channel to test (default: any)"); static int dmatest_test_list_get(char *val, const struct kernel_param *kp); static const struct kernel_param_ops test_list_ops = { .get = dmatest_test_list_get, }; module_param_cb(test_list, &test_list_ops, NULL, 0444); MODULE_PARM_DESC(test_list, "Print current test list"); |
a310d037b dmatest: restore ... |
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
/* Maximum amount of mismatched bytes in buffer to print */ #define MAX_ERROR_COUNT 32 /* * Initialization patterns. All bytes in the source buffer has bit 7 * set, all bytes in the destination buffer has bit 7 cleared. * * Bit 6 is set for all bytes which are to be copied by the DMA * engine. Bit 5 is set for all bytes which are to be overwritten by * the DMA engine. * * The remaining bits are the inverse of a counter which increments by * one for each byte address. */ #define PATTERN_SRC 0x80 #define PATTERN_DST 0x00 #define PATTERN_COPY 0x40 #define PATTERN_OVERWRITE 0x20 #define PATTERN_COUNT_MASK 0x1f |
61b5f54d8 dmaengine: dmates... |
180 |
#define PATTERN_MEMSET_IDX 0x01 |
851b7e16a dmatest: run test... |
181 |
|
6138f967b dmaengine: dmates... |
182 183 184 185 186 187 |
/* Fixed point arithmetic ops */ #define FIXPT_SHIFT 8 #define FIXPNT_MASK 0xFF #define FIXPT_TO_INT(a) ((a) >> FIXPT_SHIFT) #define INT_TO_FIXPT(a) ((a) << FIXPT_SHIFT) #define FIXPT_GET_FRAC(a) ((((a) & FIXPNT_MASK) * 100) >> FIXPT_SHIFT) |
6f6a23a21 dmaengine: dmates... |
188 189 190 191 192 |
/* poor man's completion - we want to use wait_event_freezable() on it */ struct dmatest_done { bool done; wait_queue_head_t *wait; }; |
361deb724 dmaengine: dmates... |
193 194 195 196 197 198 |
struct dmatest_data { u8 **raw; u8 **aligned; unsigned int cnt; unsigned int off; }; |
a310d037b dmatest: restore ... |
199 200 201 202 203 |
struct dmatest_thread { struct list_head node; struct dmatest_info *info; struct task_struct *task; struct dma_chan *chan; |
361deb724 dmaengine: dmates... |
204 205 |
struct dmatest_data src; struct dmatest_data dst; |
a310d037b dmatest: restore ... |
206 |
enum dma_transaction_type type; |
6f6a23a21 dmaengine: dmates... |
207 208 |
wait_queue_head_t done_wait; struct dmatest_done test_done; |
a310d037b dmatest: restore ... |
209 |
bool done; |
d53513d5d dmaengine: dmates... |
210 |
bool pending; |
a310d037b dmatest: restore ... |
211 |
}; |
95019c8c5 dmatest: gather t... |
212 |
|
a310d037b dmatest: restore ... |
213 214 215 216 |
struct dmatest_chan { struct list_head node; struct dma_chan *chan; struct list_head threads; |
e03e93a97 dmatest: create d... |
217 |
}; |
2d88ce76e dmatest: add a 'w... |
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
static DECLARE_WAIT_QUEUE_HEAD(thread_wait); static bool wait; static bool is_threaded_test_run(struct dmatest_info *info) { struct dmatest_chan *dtc; list_for_each_entry(dtc, &info->channels, node) { struct dmatest_thread *thread; list_for_each_entry(thread, &dtc->threads, node) { if (!thread->done) return true; } } return false; } |
d53513d5d dmaengine: dmates... |
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 |
static bool is_threaded_test_pending(struct dmatest_info *info) { struct dmatest_chan *dtc; list_for_each_entry(dtc, &info->channels, node) { struct dmatest_thread *thread; list_for_each_entry(thread, &dtc->threads, node) { if (thread->pending) return true; } } return false; } |
2d88ce76e dmatest: add a 'w... |
251 252 253 254 255 256 257 258 259 260 |
static int dmatest_wait_get(char *val, const struct kernel_param *kp) { struct dmatest_info *info = &test_info; struct dmatest_params *params = &info->params; if (params->iterations) wait_event(thread_wait, !is_threaded_test_run(info)); wait = true; return param_get_bool(val, kp); } |
9c27847dd kernel/params: co... |
261 |
static const struct kernel_param_ops wait_ops = { |
2d88ce76e dmatest: add a 'w... |
262 263 264 265 266 |
.get = dmatest_wait_get, .set = param_set_bool, }; module_param_cb(wait, &wait_ops, &wait, S_IRUGO); MODULE_PARM_DESC(wait, "Wait for tests to complete (default: false)"); |
e03e93a97 dmatest: create d... |
267 |
|
15b8a8ea1 dmatest: split te... |
268 |
static bool dmatest_match_channel(struct dmatest_params *params, |
e03e93a97 dmatest: create d... |
269 |
struct dma_chan *chan) |
4a776f0aa dmatest: Simple D... |
270 |
{ |
15b8a8ea1 dmatest: split te... |
271 |
if (params->channel[0] == '\0') |
4a776f0aa dmatest: Simple D... |
272 |
return true; |
15b8a8ea1 dmatest: split te... |
273 |
return strcmp(dma_chan_name(chan), params->channel) == 0; |
4a776f0aa dmatest: Simple D... |
274 |
} |
15b8a8ea1 dmatest: split te... |
275 |
static bool dmatest_match_device(struct dmatest_params *params, |
e03e93a97 dmatest: create d... |
276 |
struct dma_device *device) |
4a776f0aa dmatest: Simple D... |
277 |
{ |
15b8a8ea1 dmatest: split te... |
278 |
if (params->device[0] == '\0') |
4a776f0aa dmatest: Simple D... |
279 |
return true; |
15b8a8ea1 dmatest: split te... |
280 |
return strcmp(dev_name(device->dev), params->device) == 0; |
4a776f0aa dmatest: Simple D... |
281 282 283 284 285 |
} static unsigned long dmatest_random(void) { unsigned long buf; |
be9fa5a43 dmatest: use pseu... |
286 |
prandom_bytes(&buf, sizeof(buf)); |
4a776f0aa dmatest: Simple D... |
287 288 |
return buf; } |
61b5f54d8 dmaengine: dmates... |
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 |
static inline u8 gen_inv_idx(u8 index, bool is_memset) { u8 val = is_memset ? PATTERN_MEMSET_IDX : index; return ~val & PATTERN_COUNT_MASK; } static inline u8 gen_src_value(u8 index, bool is_memset) { return PATTERN_SRC | gen_inv_idx(index, is_memset); } static inline u8 gen_dst_value(u8 index, bool is_memset) { return PATTERN_DST | gen_inv_idx(index, is_memset); } |
e03e93a97 dmatest: create d... |
305 |
static void dmatest_init_srcs(u8 **bufs, unsigned int start, unsigned int len, |
61b5f54d8 dmaengine: dmates... |
306 |
unsigned int buf_size, bool is_memset) |
4a776f0aa dmatest: Simple D... |
307 308 |
{ unsigned int i; |
b54d5cb91 dmatest: add xor ... |
309 310 311 312 |
u8 *buf; for (; (buf = *bufs); bufs++) { for (i = 0; i < start; i++) |
61b5f54d8 dmaengine: dmates... |
313 |
buf[i] = gen_src_value(i, is_memset); |
b54d5cb91 dmatest: add xor ... |
314 |
for ( ; i < start + len; i++) |
61b5f54d8 dmaengine: dmates... |
315 |
buf[i] = gen_src_value(i, is_memset) | PATTERN_COPY; |
e03e93a97 dmatest: create d... |
316 |
for ( ; i < buf_size; i++) |
61b5f54d8 dmaengine: dmates... |
317 |
buf[i] = gen_src_value(i, is_memset); |
b54d5cb91 dmatest: add xor ... |
318 319 |
buf++; } |
4a776f0aa dmatest: Simple D... |
320 |
} |
e03e93a97 dmatest: create d... |
321 |
static void dmatest_init_dsts(u8 **bufs, unsigned int start, unsigned int len, |
61b5f54d8 dmaengine: dmates... |
322 |
unsigned int buf_size, bool is_memset) |
4a776f0aa dmatest: Simple D... |
323 324 |
{ unsigned int i; |
b54d5cb91 dmatest: add xor ... |
325 326 327 328 |
u8 *buf; for (; (buf = *bufs); bufs++) { for (i = 0; i < start; i++) |
61b5f54d8 dmaengine: dmates... |
329 |
buf[i] = gen_dst_value(i, is_memset); |
b54d5cb91 dmatest: add xor ... |
330 |
for ( ; i < start + len; i++) |
61b5f54d8 dmaengine: dmates... |
331 332 |
buf[i] = gen_dst_value(i, is_memset) | PATTERN_OVERWRITE; |
e03e93a97 dmatest: create d... |
333 |
for ( ; i < buf_size; i++) |
61b5f54d8 dmaengine: dmates... |
334 |
buf[i] = gen_dst_value(i, is_memset); |
b54d5cb91 dmatest: add xor ... |
335 |
} |
4a776f0aa dmatest: Simple D... |
336 |
} |
7b6101782 Revert "dmatest: ... |
337 |
static void dmatest_mismatch(u8 actual, u8 pattern, unsigned int index, |
61b5f54d8 dmaengine: dmates... |
338 |
unsigned int counter, bool is_srcbuf, bool is_memset) |
7b6101782 Revert "dmatest: ... |
339 340 |
{ u8 diff = actual ^ pattern; |
61b5f54d8 dmaengine: dmates... |
341 |
u8 expected = pattern | gen_inv_idx(counter, is_memset); |
7b6101782 Revert "dmatest: ... |
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 |
const char *thread_name = current->comm; if (is_srcbuf) pr_warn("%s: srcbuf[0x%x] overwritten! Expected %02x, got %02x ", thread_name, index, expected, actual); else if ((pattern & PATTERN_COPY) && (diff & (PATTERN_COPY | PATTERN_OVERWRITE))) pr_warn("%s: dstbuf[0x%x] not copied! Expected %02x, got %02x ", thread_name, index, expected, actual); else if (diff & PATTERN_SRC) pr_warn("%s: dstbuf[0x%x] was copied! Expected %02x, got %02x ", thread_name, index, expected, actual); else pr_warn("%s: dstbuf[0x%x] mismatch! Expected %02x, got %02x ", thread_name, index, expected, actual); } static unsigned int dmatest_verify(u8 **bufs, unsigned int start, unsigned int end, unsigned int counter, u8 pattern, |
61b5f54d8 dmaengine: dmates... |
365 |
bool is_srcbuf, bool is_memset) |
4a776f0aa dmatest: Simple D... |
366 367 368 369 |
{ unsigned int i; unsigned int error_count = 0; u8 actual; |
b54d5cb91 dmatest: add xor ... |
370 371 372 373 374 375 376 377 |
u8 expected; u8 *buf; unsigned int counter_orig = counter; for (; (buf = *bufs); bufs++) { counter = counter_orig; for (i = start; i < end; i++) { actual = buf[i]; |
61b5f54d8 dmaengine: dmates... |
378 |
expected = pattern | gen_inv_idx(counter, is_memset); |
b54d5cb91 dmatest: add xor ... |
379 |
if (actual != expected) { |
7b6101782 Revert "dmatest: ... |
380 381 |
if (error_count < MAX_ERROR_COUNT) dmatest_mismatch(actual, pattern, i, |
61b5f54d8 dmaengine: dmates... |
382 383 |
counter, is_srcbuf, is_memset); |
b54d5cb91 dmatest: add xor ... |
384 385 386 |
error_count++; } counter++; |
4a776f0aa dmatest: Simple D... |
387 |
} |
4a776f0aa dmatest: Simple D... |
388 |
} |
74b5c07a5 dmatest: define M... |
389 |
if (error_count > MAX_ERROR_COUNT) |
7b6101782 Revert "dmatest: ... |
390 391 |
pr_warn("%s: %u errors suppressed ", |
74b5c07a5 dmatest: define M... |
392 |
current->comm, error_count - MAX_ERROR_COUNT); |
4a776f0aa dmatest: Simple D... |
393 394 395 |
return error_count; } |
adfa543e7 dmatest: don't us... |
396 397 |
static void dmatest_callback(void *arg) |
e44e0aa3c dmatest: add dma ... |
398 |
{ |
adfa543e7 dmatest: don't us... |
399 |
struct dmatest_done *done = arg; |
6f6a23a21 dmaengine: dmates... |
400 |
struct dmatest_thread *thread = |
66b3bd235 dmaengine: dmates... |
401 |
container_of(done, struct dmatest_thread, test_done); |
6f6a23a21 dmaengine: dmates... |
402 403 404 405 406 407 408 409 410 411 412 413 414 415 |
if (!thread->done) { done->done = true; wake_up_all(done->wait); } else { /* * If thread->done, it means that this callback occurred * after the parent thread has cleaned up. This can * happen in the case that driver doesn't implement * the terminate_all() functionality and a dma operation * did not occur within the timeout period */ WARN(1, "dmatest: Kernel memory may be corrupted!! "); } |
e44e0aa3c dmatest: add dma ... |
416 |
} |
8be9e32b3 dmatest: adjust i... |
417 418 419 420 421 422 |
static unsigned int min_odd(unsigned int x, unsigned int y) { unsigned int val = min(x, y); return val % 2 ? val : val - 1; } |
872f05c6e dmatest: replace ... |
423 424 |
static void result(const char *err, unsigned int n, unsigned int src_off, unsigned int dst_off, unsigned int len, unsigned long data) |
d86b2f298 dmatest: append v... |
425 |
{ |
2acec1503 Add new line to t... |
426 427 |
pr_info("%s: result #%u: '%s' with src_off=0x%x dst_off=0x%x len=0x%x (%lu) ", |
872f05c6e dmatest: replace ... |
428 |
current->comm, n, err, src_off, dst_off, len, data); |
d86b2f298 dmatest: append v... |
429 |
} |
872f05c6e dmatest: replace ... |
430 431 432 |
static void dbg_result(const char *err, unsigned int n, unsigned int src_off, unsigned int dst_off, unsigned int len, unsigned long data) |
95019c8c5 dmatest: gather t... |
433 |
{ |
2acec1503 Add new line to t... |
434 435 |
pr_debug("%s: result #%u: '%s' with src_off=0x%x dst_off=0x%x len=0x%x (%lu) ", |
a835bb855 dmatest: fix inde... |
436 |
current->comm, n, err, src_off, dst_off, len, data); |
95019c8c5 dmatest: gather t... |
437 |
} |
a835bb855 dmatest: fix inde... |
438 439 440 441 442 |
#define verbose_result(err, n, src_off, dst_off, len, data) ({ \ if (verbose) \ result(err, n, src_off, dst_off, len, data); \ else \ dbg_result(err, n, src_off, dst_off, len, data);\ |
50137a7df dmatest: verbose ... |
443 |
}) |
95019c8c5 dmatest: gather t... |
444 |
|
86727443a dmatest: add basi... |
445 |
static unsigned long long dmatest_persec(s64 runtime, unsigned int val) |
d86b2f298 dmatest: append v... |
446 |
{ |
86727443a dmatest: add basi... |
447 |
unsigned long long per_sec = 1000000; |
d86b2f298 dmatest: append v... |
448 |
|
86727443a dmatest: add basi... |
449 450 |
if (runtime <= 0) return 0; |
95019c8c5 dmatest: gather t... |
451 |
|
86727443a dmatest: add basi... |
452 453 454 455 |
/* drop precision until runtime is 32-bits */ while (runtime > UINT_MAX) { runtime >>= 1; per_sec <<= 1; |
95019c8c5 dmatest: gather t... |
456 |
} |
86727443a dmatest: add basi... |
457 |
per_sec *= val; |
6138f967b dmaengine: dmates... |
458 |
per_sec = INT_TO_FIXPT(per_sec); |
86727443a dmatest: add basi... |
459 |
do_div(per_sec, runtime); |
6138f967b dmaengine: dmates... |
460 |
|
86727443a dmatest: add basi... |
461 |
return per_sec; |
95019c8c5 dmatest: gather t... |
462 |
} |
86727443a dmatest: add basi... |
463 |
static unsigned long long dmatest_KBs(s64 runtime, unsigned long long len) |
95019c8c5 dmatest: gather t... |
464 |
{ |
6138f967b dmaengine: dmates... |
465 |
return FIXPT_TO_INT(dmatest_persec(runtime, len >> 10)); |
95019c8c5 dmatest: gather t... |
466 |
} |
3b6679f91 dmaengine: dmates... |
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 |
static void __dmatest_free_test_data(struct dmatest_data *d, unsigned int cnt) { unsigned int i; for (i = 0; i < cnt; i++) kfree(d->raw[i]); kfree(d->aligned); kfree(d->raw); } static void dmatest_free_test_data(struct dmatest_data *d) { __dmatest_free_test_data(d, d->cnt); } static int dmatest_alloc_test_data(struct dmatest_data *d, unsigned int buf_size, u8 align) { unsigned int i = 0; d->raw = kcalloc(d->cnt + 1, sizeof(u8 *), GFP_KERNEL); if (!d->raw) return -ENOMEM; d->aligned = kcalloc(d->cnt + 1, sizeof(u8 *), GFP_KERNEL); if (!d->aligned) goto err; for (i = 0; i < d->cnt; i++) { d->raw[i] = kmalloc(buf_size + align, GFP_KERNEL); if (!d->raw[i]) goto err; /* align to alignment restriction */ if (align) d->aligned[i] = PTR_ALIGN(d->raw[i], align); else d->aligned[i] = d->raw[i]; } return 0; err: __dmatest_free_test_data(d, i); return -ENOMEM; } |
4a776f0aa dmatest: Simple D... |
513 514 |
/* * This function repeatedly tests DMA transfers of various lengths and |
b54d5cb91 dmatest: add xor ... |
515 516 517 518 |
* offsets for a given operation type until it is told to exit by * kthread_stop(). There may be multiple threads running this function * in parallel for a single channel, and there may be multiple channels * being tested in parallel. |
4a776f0aa dmatest: Simple D... |
519 520 521 522 523 524 525 526 527 528 529 |
* * Before each test, the source and destination buffer is initialized * with a known pattern. This pattern is different depending on * whether it's in an area which is supposed to be copied or * overwritten, and different in the source and destination buffers. * So if the DMA engine doesn't copy exactly what we tell it to copy, * we'll notice. */ static int dmatest_func(void *data) { struct dmatest_thread *thread = data; |
6f6a23a21 dmaengine: dmates... |
530 |
struct dmatest_done *done = &thread->test_done; |
e03e93a97 dmatest: create d... |
531 |
struct dmatest_info *info; |
15b8a8ea1 dmatest: split te... |
532 |
struct dmatest_params *params; |
4a776f0aa dmatest: Simple D... |
533 |
struct dma_chan *chan; |
8be9e32b3 dmatest: adjust i... |
534 |
struct dma_device *dev; |
4a776f0aa dmatest: Simple D... |
535 536 537 538 539 |
unsigned int error_count; unsigned int failed_tests = 0; unsigned int total_tests = 0; dma_cookie_t cookie; enum dma_status status; |
b54d5cb91 dmatest: add xor ... |
540 |
enum dma_ctrl_flags flags; |
945b5af3c dmatest: allocate... |
541 |
u8 *pq_coefs = NULL; |
4a776f0aa dmatest: Simple D... |
542 |
int ret; |
41d00bb7a dmaengine: dmates... |
543 |
unsigned int buf_size; |
361deb724 dmaengine: dmates... |
544 545 |
struct dmatest_data *src; struct dmatest_data *dst; |
b54d5cb91 dmatest: add xor ... |
546 |
int i; |
e9405ef08 dmaengine: dmates... |
547 |
ktime_t ktime, start, diff; |
8b0e19531 ktime: Cleanup kt... |
548 549 |
ktime_t filltime = 0; ktime_t comparetime = 0; |
86727443a dmatest: add basi... |
550 551 |
s64 runtime = 0; unsigned long long total_len = 0; |
6138f967b dmaengine: dmates... |
552 |
unsigned long long iops = 0; |
d64816086 dmaengine: dmates... |
553 |
u8 align = 0; |
61b5f54d8 dmaengine: dmates... |
554 |
bool is_memset = false; |
72ef08bf6 dmaengine: dmates... |
555 556 |
dma_addr_t *srcs; dma_addr_t *dma_pq; |
4a776f0aa dmatest: Simple D... |
557 |
|
adfa543e7 dmatest: don't us... |
558 |
set_freezable(); |
4a776f0aa dmatest: Simple D... |
559 560 |
ret = -ENOMEM; |
4a776f0aa dmatest: Simple D... |
561 562 |
smp_rmb(); |
d53513d5d dmaengine: dmates... |
563 |
thread->pending = false; |
e03e93a97 dmatest: create d... |
564 |
info = thread->info; |
15b8a8ea1 dmatest: split te... |
565 |
params = &info->params; |
4a776f0aa dmatest: Simple D... |
566 |
chan = thread->chan; |
8be9e32b3 dmatest: adjust i... |
567 |
dev = chan->device; |
361deb724 dmaengine: dmates... |
568 569 |
src = &thread->src; dst = &thread->dst; |
d64816086 dmaengine: dmates... |
570 |
if (thread->type == DMA_MEMCPY) { |
a875abfad dmaengine: dmates... |
571 572 |
align = params->alignment < 0 ? dev->copy_align : params->alignment; |
361deb724 dmaengine: dmates... |
573 |
src->cnt = dst->cnt = 1; |
61b5f54d8 dmaengine: dmates... |
574 |
} else if (thread->type == DMA_MEMSET) { |
a875abfad dmaengine: dmates... |
575 576 |
align = params->alignment < 0 ? dev->fill_align : params->alignment; |
361deb724 dmaengine: dmates... |
577 |
src->cnt = dst->cnt = 1; |
61b5f54d8 dmaengine: dmates... |
578 |
is_memset = true; |
d64816086 dmaengine: dmates... |
579 |
} else if (thread->type == DMA_XOR) { |
8be9e32b3 dmatest: adjust i... |
580 |
/* force odd to ensure dst = src */ |
361deb724 dmaengine: dmates... |
581 582 |
src->cnt = min_odd(params->xor_sources | 1, dev->max_xor); dst->cnt = 1; |
a875abfad dmaengine: dmates... |
583 584 |
align = params->alignment < 0 ? dev->xor_align : params->alignment; |
58691d64c dmatest: add pq s... |
585 |
} else if (thread->type == DMA_PQ) { |
8be9e32b3 dmatest: adjust i... |
586 |
/* force odd to ensure dst = src */ |
361deb724 dmaengine: dmates... |
587 588 |
src->cnt = min_odd(params->pq_sources | 1, dma_maxpq(dev, 0)); dst->cnt = 2; |
a875abfad dmaengine: dmates... |
589 590 |
align = params->alignment < 0 ? dev->pq_align : params->alignment; |
945b5af3c dmatest: allocate... |
591 |
|
31d182574 dmaengine: fix sp... |
592 |
pq_coefs = kmalloc(params->pq_sources + 1, GFP_KERNEL); |
945b5af3c dmatest: allocate... |
593 594 |
if (!pq_coefs) goto err_thread_type; |
361deb724 dmaengine: dmates... |
595 |
for (i = 0; i < src->cnt; i++) |
58691d64c dmatest: add pq s... |
596 |
pq_coefs[i] = 1; |
b54d5cb91 dmatest: add xor ... |
597 |
} else |
945b5af3c dmatest: allocate... |
598 |
goto err_thread_type; |
b54d5cb91 dmatest: add xor ... |
599 |
|
787d3083c dmaengine: dmates... |
600 |
/* Check if buffer count fits into map count variable (u8) */ |
361deb724 dmaengine: dmates... |
601 |
if ((src->cnt + dst->cnt) >= 255) { |
787d3083c dmaengine: dmates... |
602 603 |
pr_err("too many buffers (%d of 255 supported) ", |
361deb724 dmaengine: dmates... |
604 |
src->cnt + dst->cnt); |
3f3c75541 dmaengine: dmates... |
605 |
goto err_free_coefs; |
787d3083c dmaengine: dmates... |
606 |
} |
41d00bb7a dmaengine: dmates... |
607 608 |
buf_size = params->buf_size; if (1 << align > buf_size) { |
787d3083c dmaengine: dmates... |
609 610 |
pr_err("%u-byte buffer too small for %d-byte alignment ", |
41d00bb7a dmaengine: dmates... |
611 |
buf_size, 1 << align); |
3f3c75541 dmaengine: dmates... |
612 |
goto err_free_coefs; |
787d3083c dmaengine: dmates... |
613 |
} |
3b6679f91 dmaengine: dmates... |
614 |
if (dmatest_alloc_test_data(src, buf_size, align) < 0) |
3f3c75541 dmaengine: dmates... |
615 |
goto err_free_coefs; |
d64816086 dmaengine: dmates... |
616 |
|
3b6679f91 dmaengine: dmates... |
617 618 |
if (dmatest_alloc_test_data(dst, buf_size, align) < 0) goto err_src; |
b54d5cb91 dmatest: add xor ... |
619 |
|
e44e0aa3c dmatest: add dma ... |
620 |
set_user_nice(current, 10); |
361deb724 dmaengine: dmates... |
621 |
srcs = kcalloc(src->cnt, sizeof(dma_addr_t), GFP_KERNEL); |
72ef08bf6 dmaengine: dmates... |
622 |
if (!srcs) |
3b6679f91 dmaengine: dmates... |
623 |
goto err_dst; |
72ef08bf6 dmaengine: dmates... |
624 |
|
361deb724 dmaengine: dmates... |
625 |
dma_pq = kcalloc(dst->cnt, sizeof(dma_addr_t), GFP_KERNEL); |
72ef08bf6 dmaengine: dmates... |
626 627 |
if (!dma_pq) goto err_srcs_array; |
b203bd3f6 dmatest: fix auto... |
628 |
/* |
d1cab34c0 dmatest: make dri... |
629 |
* src and dst buffers are freed by ourselves below |
b203bd3f6 dmatest: fix auto... |
630 |
*/ |
fb9816f9d dmaengine: dmates... |
631 632 633 634 |
if (params->polled) flags = DMA_CTRL_ACK; else flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; |
4a776f0aa dmatest: Simple D... |
635 |
|
86727443a dmatest: add basi... |
636 |
ktime = ktime_get(); |
0a2ff57d6 dmaengine: dmates... |
637 |
while (!kthread_should_stop() |
15b8a8ea1 dmatest: split te... |
638 |
&& !(params->iterations && total_tests >= params->iterations)) { |
b54d5cb91 dmatest: add xor ... |
639 |
struct dma_async_tx_descriptor *tx = NULL; |
4076e755d dmatest: convert ... |
640 |
struct dmaengine_unmap_data *um; |
4076e755d dmatest: convert ... |
641 |
dma_addr_t *dsts; |
361deb724 dmaengine: dmates... |
642 |
unsigned int len; |
d86be86e9 dmatest: Use cust... |
643 |
|
4a776f0aa dmatest: Simple D... |
644 |
total_tests++; |
13396a130 dmaengine: dmates... |
645 |
if (params->transfer_size) { |
41d00bb7a dmaengine: dmates... |
646 |
if (params->transfer_size >= buf_size) { |
13396a130 dmaengine: dmates... |
647 648 |
pr_err("%u-byte transfer size must be lower than %u-buffer size ", |
41d00bb7a dmaengine: dmates... |
649 |
params->transfer_size, buf_size); |
13396a130 dmaengine: dmates... |
650 651 652 653 |
break; } len = params->transfer_size; } else if (params->norandom) { |
41d00bb7a dmaengine: dmates... |
654 |
len = buf_size; |
13396a130 dmaengine: dmates... |
655 |
} else { |
41d00bb7a dmaengine: dmates... |
656 |
len = dmatest_random() % buf_size + 1; |
13396a130 dmaengine: dmates... |
657 |
} |
ede23a586 dmatest: move src... |
658 |
|
13396a130 dmaengine: dmates... |
659 660 661 662 663 664 |
/* Do not alter transfer size explicitly defined by user */ if (!params->transfer_size) { len = (len >> align) << align; if (!len) len = 1 << align; } |
ede23a586 dmatest: move src... |
665 |
total_len += len; |
2e67a0875 dmaengine: dmates... |
666 |
if (params->norandom) { |
361deb724 dmaengine: dmates... |
667 668 |
src->off = 0; dst->off = 0; |
e3b9c3473 dmatest: add supp... |
669 |
} else { |
41d00bb7a dmaengine: dmates... |
670 671 |
src->off = dmatest_random() % (buf_size - len + 1); dst->off = dmatest_random() % (buf_size - len + 1); |
e3b9c3473 dmatest: add supp... |
672 |
|
361deb724 dmaengine: dmates... |
673 674 |
src->off = (src->off >> align) << align; dst->off = (dst->off >> align) << align; |
2e67a0875 dmaengine: dmates... |
675 |
} |
e3b9c3473 dmatest: add supp... |
676 |
|
2e67a0875 dmaengine: dmates... |
677 678 |
if (!params->noverify) { start = ktime_get(); |
361deb724 dmaengine: dmates... |
679 |
dmatest_init_srcs(src->aligned, src->off, len, |
41d00bb7a dmaengine: dmates... |
680 |
buf_size, is_memset); |
361deb724 dmaengine: dmates... |
681 |
dmatest_init_dsts(dst->aligned, dst->off, len, |
41d00bb7a dmaengine: dmates... |
682 |
buf_size, is_memset); |
e9405ef08 dmaengine: dmates... |
683 684 685 |
diff = ktime_sub(ktime_get(), start); filltime = ktime_add(filltime, diff); |
e3b9c3473 dmatest: add supp... |
686 |
} |
361deb724 dmaengine: dmates... |
687 |
um = dmaengine_get_unmap_data(dev->dev, src->cnt + dst->cnt, |
4076e755d dmatest: convert ... |
688 689 690 691 |
GFP_KERNEL); if (!um) { failed_tests++; result("unmap data NULL", total_tests, |
361deb724 dmaengine: dmates... |
692 |
src->off, dst->off, len, ret); |
4076e755d dmatest: convert ... |
693 694 |
continue; } |
4a776f0aa dmatest: Simple D... |
695 |
|
41d00bb7a dmaengine: dmates... |
696 |
um->len = buf_size; |
361deb724 dmaengine: dmates... |
697 698 |
for (i = 0; i < src->cnt; i++) { void *buf = src->aligned[i]; |
4076e755d dmatest: convert ... |
699 |
struct page *pg = virt_to_page(buf); |
f62e5f613 dmaengine: dmates... |
700 |
unsigned long pg_off = offset_in_page(buf); |
4076e755d dmatest: convert ... |
701 702 703 |
um->addr[i] = dma_map_page(dev->dev, pg, pg_off, um->len, DMA_TO_DEVICE); |
361deb724 dmaengine: dmates... |
704 |
srcs[i] = um->addr[i] + src->off; |
4076e755d dmatest: convert ... |
705 |
ret = dma_mapping_error(dev->dev, um->addr[i]); |
afde3be12 dmatest: check fo... |
706 |
if (ret) { |
872f05c6e dmatest: replace ... |
707 |
result("src mapping error", total_tests, |
361deb724 dmaengine: dmates... |
708 |
src->off, dst->off, len, ret); |
6454368a8 dmaengine: dmates... |
709 |
goto error_unmap_continue; |
afde3be12 dmatest: check fo... |
710 |
} |
4076e755d dmatest: convert ... |
711 |
um->to_cnt++; |
b54d5cb91 dmatest: add xor ... |
712 |
} |
d86be86e9 dmatest: Use cust... |
713 |
/* map with DMA_BIDIRECTIONAL to force writeback/invalidate */ |
361deb724 dmaengine: dmates... |
714 715 716 |
dsts = &um->addr[src->cnt]; for (i = 0; i < dst->cnt; i++) { void *buf = dst->aligned[i]; |
4076e755d dmatest: convert ... |
717 |
struct page *pg = virt_to_page(buf); |
f62e5f613 dmaengine: dmates... |
718 |
unsigned long pg_off = offset_in_page(buf); |
4076e755d dmatest: convert ... |
719 720 721 722 |
dsts[i] = dma_map_page(dev->dev, pg, pg_off, um->len, DMA_BIDIRECTIONAL); ret = dma_mapping_error(dev->dev, dsts[i]); |
afde3be12 dmatest: check fo... |
723 |
if (ret) { |
872f05c6e dmatest: replace ... |
724 |
result("dst mapping error", total_tests, |
361deb724 dmaengine: dmates... |
725 |
src->off, dst->off, len, ret); |
6454368a8 dmaengine: dmates... |
726 |
goto error_unmap_continue; |
afde3be12 dmatest: check fo... |
727 |
} |
4076e755d dmatest: convert ... |
728 |
um->bidi_cnt++; |
b54d5cb91 dmatest: add xor ... |
729 730 731 732 |
} if (thread->type == DMA_MEMCPY) tx = dev->device_prep_dma_memcpy(chan, |
361deb724 dmaengine: dmates... |
733 |
dsts[0] + dst->off, |
4076e755d dmatest: convert ... |
734 |
srcs[0], len, flags); |
61b5f54d8 dmaengine: dmates... |
735 736 |
else if (thread->type == DMA_MEMSET) tx = dev->device_prep_dma_memset(chan, |
361deb724 dmaengine: dmates... |
737 738 |
dsts[0] + dst->off, *(src->aligned[0] + src->off), |
61b5f54d8 dmaengine: dmates... |
739 |
len, flags); |
b54d5cb91 dmatest: add xor ... |
740 741 |
else if (thread->type == DMA_XOR) tx = dev->device_prep_dma_xor(chan, |
361deb724 dmaengine: dmates... |
742 743 |
dsts[0] + dst->off, srcs, src->cnt, |
b54d5cb91 dmatest: add xor ... |
744 |
len, flags); |
58691d64c dmatest: add pq s... |
745 |
else if (thread->type == DMA_PQ) { |
361deb724 dmaengine: dmates... |
746 747 |
for (i = 0; i < dst->cnt; i++) dma_pq[i] = dsts[i] + dst->off; |
4076e755d dmatest: convert ... |
748 |
tx = dev->device_prep_dma_pq(chan, dma_pq, srcs, |
361deb724 dmaengine: dmates... |
749 |
src->cnt, pq_coefs, |
58691d64c dmatest: add pq s... |
750 751 |
len, flags); } |
d86be86e9 dmatest: Use cust... |
752 |
|
d86be86e9 dmatest: Use cust... |
753 |
if (!tx) { |
361deb724 dmaengine: dmates... |
754 755 |
result("prep error", total_tests, src->off, dst->off, len, ret); |
d86be86e9 dmatest: Use cust... |
756 |
msleep(100); |
6454368a8 dmaengine: dmates... |
757 |
goto error_unmap_continue; |
d86be86e9 dmatest: Use cust... |
758 |
} |
e44e0aa3c dmatest: add dma ... |
759 |
|
6f6a23a21 dmaengine: dmates... |
760 |
done->done = false; |
fb9816f9d dmaengine: dmates... |
761 762 763 764 |
if (!params->polled) { tx->callback = dmatest_callback; tx->callback_param = done; } |
d86be86e9 dmatest: Use cust... |
765 |
cookie = tx->tx_submit(tx); |
4a776f0aa dmatest: Simple D... |
766 |
if (dma_submit_error(cookie)) { |
361deb724 dmaengine: dmates... |
767 768 |
result("submit error", total_tests, src->off, dst->off, len, ret); |
4a776f0aa dmatest: Simple D... |
769 |
msleep(100); |
6454368a8 dmaengine: dmates... |
770 |
goto error_unmap_continue; |
4a776f0aa dmatest: Simple D... |
771 |
} |
4a776f0aa dmatest: Simple D... |
772 |
|
fb9816f9d dmaengine: dmates... |
773 774 775 776 777 778 779 780 781 782 783 |
if (params->polled) { status = dma_sync_wait(chan, cookie); dmaengine_terminate_sync(chan); if (status == DMA_COMPLETE) done->done = true; } else { dma_async_issue_pending(chan); wait_event_freezable_timeout(thread->done_wait, done->done, msecs_to_jiffies(params->timeout)); |
981ed70d8 dmatest: make dma... |
784 |
|
fb9816f9d dmaengine: dmates... |
785 786 787 |
status = dma_async_is_tx_complete(chan, cookie, NULL, NULL); } |
4a776f0aa dmatest: Simple D... |
788 |
|
6f6a23a21 dmaengine: dmates... |
789 |
if (!done->done) { |
361deb724 dmaengine: dmates... |
790 |
result("test timed out", total_tests, src->off, dst->off, |
872f05c6e dmatest: replace ... |
791 |
len, 0); |
6454368a8 dmaengine: dmates... |
792 |
goto error_unmap_continue; |
19e9f99f2 dmaengine: dmates... |
793 |
} else if (status != DMA_COMPLETE) { |
872f05c6e dmatest: replace ... |
794 795 |
result(status == DMA_ERROR ? "completion error status" : |
361deb724 dmaengine: dmates... |
796 797 |
"completion busy status", total_tests, src->off, dst->off, len, ret); |
6454368a8 dmaengine: dmates... |
798 |
goto error_unmap_continue; |
4a776f0aa dmatest: Simple D... |
799 |
} |
e44e0aa3c dmatest: add dma ... |
800 |
|
6454368a8 dmaengine: dmates... |
801 |
dmaengine_unmap_put(um); |
e3b9c3473 dmatest: add supp... |
802 |
if (params->noverify) { |
361deb724 dmaengine: dmates... |
803 804 |
verbose_result("test passed", total_tests, src->off, dst->off, len, 0); |
e3b9c3473 dmatest: add supp... |
805 806 |
continue; } |
4a776f0aa dmatest: Simple D... |
807 |
|
e9405ef08 dmaengine: dmates... |
808 |
start = ktime_get(); |
872f05c6e dmatest: replace ... |
809 810 |
pr_debug("%s: verifying source buffer... ", current->comm); |
361deb724 dmaengine: dmates... |
811 |
error_count = dmatest_verify(src->aligned, 0, src->off, |
61b5f54d8 dmaengine: dmates... |
812 |
0, PATTERN_SRC, true, is_memset); |
361deb724 dmaengine: dmates... |
813 814 |
error_count += dmatest_verify(src->aligned, src->off, src->off + len, src->off, |
61b5f54d8 dmaengine: dmates... |
815 |
PATTERN_SRC | PATTERN_COPY, true, is_memset); |
361deb724 dmaengine: dmates... |
816 |
error_count += dmatest_verify(src->aligned, src->off + len, |
41d00bb7a dmaengine: dmates... |
817 |
buf_size, src->off + len, |
61b5f54d8 dmaengine: dmates... |
818 |
PATTERN_SRC, true, is_memset); |
7b6101782 Revert "dmatest: ... |
819 |
|
872f05c6e dmatest: replace ... |
820 821 |
pr_debug("%s: verifying dest buffer... ", current->comm); |
361deb724 dmaengine: dmates... |
822 |
error_count += dmatest_verify(dst->aligned, 0, dst->off, |
61b5f54d8 dmaengine: dmates... |
823 |
0, PATTERN_DST, false, is_memset); |
361deb724 dmaengine: dmates... |
824 825 |
error_count += dmatest_verify(dst->aligned, dst->off, dst->off + len, src->off, |
61b5f54d8 dmaengine: dmates... |
826 |
PATTERN_SRC | PATTERN_COPY, false, is_memset); |
361deb724 dmaengine: dmates... |
827 |
error_count += dmatest_verify(dst->aligned, dst->off + len, |
41d00bb7a dmaengine: dmates... |
828 |
buf_size, dst->off + len, |
61b5f54d8 dmaengine: dmates... |
829 |
PATTERN_DST, false, is_memset); |
4a776f0aa dmatest: Simple D... |
830 |
|
e9405ef08 dmaengine: dmates... |
831 832 |
diff = ktime_sub(ktime_get(), start); comparetime = ktime_add(comparetime, diff); |
4a776f0aa dmatest: Simple D... |
833 |
if (error_count) { |
361deb724 dmaengine: dmates... |
834 |
result("data error", total_tests, src->off, dst->off, |
872f05c6e dmatest: replace ... |
835 |
len, error_count); |
4a776f0aa dmatest: Simple D... |
836 837 |
failed_tests++; } else { |
361deb724 dmaengine: dmates... |
838 839 |
verbose_result("test passed", total_tests, src->off, dst->off, len, 0); |
4a776f0aa dmatest: Simple D... |
840 |
} |
6454368a8 dmaengine: dmates... |
841 842 843 844 845 846 |
continue; error_unmap_continue: dmaengine_unmap_put(um); failed_tests++; |
4a776f0aa dmatest: Simple D... |
847 |
} |
e9405ef08 dmaengine: dmates... |
848 849 850 851 |
ktime = ktime_sub(ktime_get(), ktime); ktime = ktime_sub(ktime, comparetime); ktime = ktime_sub(ktime, filltime); runtime = ktime_to_us(ktime); |
4a776f0aa dmatest: Simple D... |
852 853 |
ret = 0; |
72ef08bf6 dmaengine: dmates... |
854 855 856 |
kfree(dma_pq); err_srcs_array: kfree(srcs); |
3b6679f91 dmaengine: dmates... |
857 858 859 860 |
err_dst: dmatest_free_test_data(dst); err_src: dmatest_free_test_data(src); |
3f3c75541 dmaengine: dmates... |
861 |
err_free_coefs: |
945b5af3c dmatest: allocate... |
862 863 |
kfree(pq_coefs); err_thread_type: |
6138f967b dmaengine: dmates... |
864 865 866 |
iops = dmatest_persec(runtime, total_tests); pr_info("%s: summary %u tests, %u failures %llu.%02llu iops %llu KB/s (%d) ", |
86727443a dmatest: add basi... |
867 |
current->comm, total_tests, failed_tests, |
6138f967b dmaengine: dmates... |
868 |
FIXPT_TO_INT(iops), FIXPT_GET_FRAC(iops), |
86727443a dmatest: add basi... |
869 |
dmatest_KBs(runtime, total_len), ret); |
0a2ff57d6 dmaengine: dmates... |
870 |
|
9704efaa5 dmaengine/dmatest... |
871 |
/* terminate all transfers on specified channels */ |
6f6a23a21 dmaengine: dmates... |
872 |
if (ret || failed_tests) |
fbffb6b4d dmaengine: dmates... |
873 |
dmaengine_terminate_sync(chan); |
5e034f7b6 dmaengine/dmatest... |
874 |
|
3e5ccd866 dmatest: return a... |
875 |
thread->done = true; |
2d88ce76e dmatest: add a 'w... |
876 |
wake_up(&thread_wait); |
0a2ff57d6 dmaengine: dmates... |
877 |
|
4a776f0aa dmatest: Simple D... |
878 879 880 881 882 883 884 885 886 887 888 |
return ret; } static void dmatest_cleanup_channel(struct dmatest_chan *dtc) { struct dmatest_thread *thread; struct dmatest_thread *_thread; int ret; list_for_each_entry_safe(thread, _thread, &dtc->threads, node) { ret = kthread_stop(thread->task); |
0adff8006 dmatest: cleanup ... |
889 890 891 |
pr_debug("thread %s exited with status %d ", thread->task->comm, ret); |
4a776f0aa dmatest: Simple D... |
892 |
list_del(&thread->node); |
2d88ce76e dmatest: add a 'w... |
893 |
put_task_struct(thread->task); |
4a776f0aa dmatest: Simple D... |
894 895 |
kfree(thread); } |
9704efaa5 dmaengine/dmatest... |
896 897 |
/* terminate all transfers on specified channels */ |
fbffb6b4d dmaengine: dmates... |
898 |
dmaengine_terminate_sync(dtc->chan); |
9704efaa5 dmaengine/dmatest... |
899 |
|
4a776f0aa dmatest: Simple D... |
900 901 |
kfree(dtc); } |
e03e93a97 dmatest: create d... |
902 903 |
static int dmatest_add_threads(struct dmatest_info *info, struct dmatest_chan *dtc, enum dma_transaction_type type) |
4a776f0aa dmatest: Simple D... |
904 |
{ |
15b8a8ea1 dmatest: split te... |
905 |
struct dmatest_params *params = &info->params; |
b54d5cb91 dmatest: add xor ... |
906 907 908 909 |
struct dmatest_thread *thread; struct dma_chan *chan = dtc->chan; char *op; unsigned int i; |
4a776f0aa dmatest: Simple D... |
910 |
|
b54d5cb91 dmatest: add xor ... |
911 912 |
if (type == DMA_MEMCPY) op = "copy"; |
61b5f54d8 dmaengine: dmates... |
913 914 |
else if (type == DMA_MEMSET) op = "set"; |
b54d5cb91 dmatest: add xor ... |
915 916 |
else if (type == DMA_XOR) op = "xor"; |
58691d64c dmatest: add pq s... |
917 918 |
else if (type == DMA_PQ) op = "pq"; |
b54d5cb91 dmatest: add xor ... |
919 920 |
else return -EINVAL; |
4a776f0aa dmatest: Simple D... |
921 |
|
15b8a8ea1 dmatest: split te... |
922 |
for (i = 0; i < params->threads_per_chan; i++) { |
4a776f0aa dmatest: Simple D... |
923 924 |
thread = kzalloc(sizeof(struct dmatest_thread), GFP_KERNEL); if (!thread) { |
0adff8006 dmatest: cleanup ... |
925 926 927 |
pr_warn("No memory for %s-%s%u ", dma_chan_name(chan), op, i); |
4a776f0aa dmatest: Simple D... |
928 929 |
break; } |
e03e93a97 dmatest: create d... |
930 |
thread->info = info; |
4a776f0aa dmatest: Simple D... |
931 |
thread->chan = dtc->chan; |
b54d5cb91 dmatest: add xor ... |
932 |
thread->type = type; |
6f6a23a21 dmaengine: dmates... |
933 934 |
thread->test_done.wait = &thread->done_wait; init_waitqueue_head(&thread->done_wait); |
4a776f0aa dmatest: Simple D... |
935 |
smp_wmb(); |
2d88ce76e dmatest: add a 'w... |
936 |
thread->task = kthread_create(dmatest_func, thread, "%s-%s%u", |
b54d5cb91 dmatest: add xor ... |
937 |
dma_chan_name(chan), op, i); |
4a776f0aa dmatest: Simple D... |
938 |
if (IS_ERR(thread->task)) { |
2d88ce76e dmatest: add a 'w... |
939 940 |
pr_warn("Failed to create thread %s-%s%u ", |
0adff8006 dmatest: cleanup ... |
941 |
dma_chan_name(chan), op, i); |
4a776f0aa dmatest: Simple D... |
942 943 944 945 946 |
kfree(thread); break; } /* srcbuf and dstbuf are allocated by the thread itself */ |
2d88ce76e dmatest: add a 'w... |
947 |
get_task_struct(thread->task); |
4a776f0aa dmatest: Simple D... |
948 |
list_add_tail(&thread->node, &dtc->threads); |
d53513d5d dmaengine: dmates... |
949 |
thread->pending = true; |
4a776f0aa dmatest: Simple D... |
950 |
} |
b54d5cb91 dmatest: add xor ... |
951 952 |
return i; } |
e03e93a97 dmatest: create d... |
953 954 |
static int dmatest_add_channel(struct dmatest_info *info, struct dma_chan *chan) |
b54d5cb91 dmatest: add xor ... |
955 956 957 958 |
{ struct dmatest_chan *dtc; struct dma_device *dma_dev = chan->device; unsigned int thread_count = 0; |
b9033e682 dma: dmatest: fix... |
959 |
int cnt; |
b54d5cb91 dmatest: add xor ... |
960 961 962 |
dtc = kmalloc(sizeof(struct dmatest_chan), GFP_KERNEL); if (!dtc) { |
0adff8006 dmatest: cleanup ... |
963 964 |
pr_warn("No memory for %s ", dma_chan_name(chan)); |
b54d5cb91 dmatest: add xor ... |
965 966 967 968 969 970 971 |
return -ENOMEM; } dtc->chan = chan; INIT_LIST_HEAD(&dtc->threads); if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask)) { |
a0d4cb44d dmaengine: dmates... |
972 973 974 975 |
if (dmatest == 0) { cnt = dmatest_add_threads(info, dtc, DMA_MEMCPY); thread_count += cnt > 0 ? cnt : 0; } |
b54d5cb91 dmatest: add xor ... |
976 |
} |
a0d4cb44d dmaengine: dmates... |
977 |
|
61b5f54d8 dmaengine: dmates... |
978 |
if (dma_has_cap(DMA_MEMSET, dma_dev->cap_mask)) { |
a0d4cb44d dmaengine: dmates... |
979 |
if (dmatest == 1) { |
c678fa663 dmaengine: remove... |
980 |
cnt = dmatest_add_threads(info, dtc, DMA_MEMSET); |
a0d4cb44d dmaengine: dmates... |
981 982 983 |
thread_count += cnt > 0 ? cnt : 0; } } |
b54d5cb91 dmatest: add xor ... |
984 |
if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) { |
e03e93a97 dmatest: create d... |
985 |
cnt = dmatest_add_threads(info, dtc, DMA_XOR); |
f1aef8b6e dmaengine: dmates... |
986 |
thread_count += cnt > 0 ? cnt : 0; |
b54d5cb91 dmatest: add xor ... |
987 |
} |
58691d64c dmatest: add pq s... |
988 |
if (dma_has_cap(DMA_PQ, dma_dev->cap_mask)) { |
e03e93a97 dmatest: create d... |
989 |
cnt = dmatest_add_threads(info, dtc, DMA_PQ); |
d07a74a54 dmaengine: fix mi... |
990 |
thread_count += cnt > 0 ? cnt : 0; |
58691d64c dmatest: add pq s... |
991 |
} |
b54d5cb91 dmatest: add xor ... |
992 |
|
d53513d5d dmaengine: dmates... |
993 994 |
pr_info("Added %u threads using %s ", |
b54d5cb91 dmatest: add xor ... |
995 |
thread_count, dma_chan_name(chan)); |
4a776f0aa dmatest: Simple D... |
996 |
|
838cc704c dmatest: move dma... |
997 998 |
list_add_tail(&dtc->node, &info->channels); info->nr_channels++; |
4a776f0aa dmatest: Simple D... |
999 |
|
33df8ca06 dmatest: convert ... |
1000 |
return 0; |
4a776f0aa dmatest: Simple D... |
1001 |
} |
7dd602510 dmaengine: kill e... |
1002 |
static bool filter(struct dma_chan *chan, void *param) |
4a776f0aa dmatest: Simple D... |
1003 |
{ |
15b8a8ea1 dmatest: split te... |
1004 |
struct dmatest_params *params = param; |
e03e93a97 dmatest: create d... |
1005 |
|
15b8a8ea1 dmatest: split te... |
1006 1007 |
if (!dmatest_match_channel(params, chan) || !dmatest_match_device(params, chan->device)) |
7dd602510 dmaengine: kill e... |
1008 |
return false; |
33df8ca06 dmatest: convert ... |
1009 |
else |
7dd602510 dmaengine: kill e... |
1010 |
return true; |
4a776f0aa dmatest: Simple D... |
1011 |
} |
a9e554957 dmatest: support ... |
1012 1013 |
static void request_channels(struct dmatest_info *info, enum dma_transaction_type type) |
4a776f0aa dmatest: Simple D... |
1014 |
{ |
33df8ca06 dmatest: convert ... |
1015 |
dma_cap_mask_t mask; |
33df8ca06 dmatest: convert ... |
1016 1017 |
dma_cap_zero(mask); |
a9e554957 dmatest: support ... |
1018 |
dma_cap_set(type, mask); |
33df8ca06 dmatest: convert ... |
1019 |
for (;;) { |
a9e554957 dmatest: support ... |
1020 1021 |
struct dmatest_params *params = &info->params; struct dma_chan *chan; |
15b8a8ea1 dmatest: split te... |
1022 |
chan = dma_request_channel(mask, filter, params); |
33df8ca06 dmatest: convert ... |
1023 |
if (chan) { |
a9e554957 dmatest: support ... |
1024 |
if (dmatest_add_channel(info, chan)) { |
33df8ca06 dmatest: convert ... |
1025 1026 1027 1028 1029 |
dma_release_channel(chan); break; /* add_channel failed, punt */ } } else break; /* no more channels available */ |
15b8a8ea1 dmatest: split te... |
1030 1031 |
if (params->max_channels && info->nr_channels >= params->max_channels) |
33df8ca06 dmatest: convert ... |
1032 1033 |
break; /* we have all we need */ } |
4a776f0aa dmatest: Simple D... |
1034 |
} |
4a776f0aa dmatest: Simple D... |
1035 |
|
d53513d5d dmaengine: dmates... |
1036 |
static void add_threaded_test(struct dmatest_info *info) |
851b7e16a dmatest: run test... |
1037 |
{ |
a9e554957 dmatest: support ... |
1038 |
struct dmatest_params *params = &info->params; |
851b7e16a dmatest: run test... |
1039 |
|
a9e554957 dmatest: support ... |
1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 |
/* Copy test parameters */ params->buf_size = test_buf_size; strlcpy(params->channel, strim(test_channel), sizeof(params->channel)); strlcpy(params->device, strim(test_device), sizeof(params->device)); params->threads_per_chan = threads_per_chan; params->max_channels = max_channels; params->iterations = iterations; params->xor_sources = xor_sources; params->pq_sources = pq_sources; params->timeout = timeout; |
e3b9c3473 dmatest: add supp... |
1050 |
params->noverify = noverify; |
2e67a0875 dmaengine: dmates... |
1051 |
params->norandom = norandom; |
a875abfad dmaengine: dmates... |
1052 |
params->alignment = alignment; |
13396a130 dmaengine: dmates... |
1053 |
params->transfer_size = transfer_size; |
fb9816f9d dmaengine: dmates... |
1054 |
params->polled = polled; |
a9e554957 dmatest: support ... |
1055 1056 |
request_channels(info, DMA_MEMCPY); |
61b5f54d8 dmaengine: dmates... |
1057 |
request_channels(info, DMA_MEMSET); |
a9e554957 dmatest: support ... |
1058 1059 |
request_channels(info, DMA_XOR); request_channels(info, DMA_PQ); |
851b7e16a dmatest: run test... |
1060 |
} |
851b7e16a dmatest: run test... |
1061 |
|
d53513d5d dmaengine: dmates... |
1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 |
static void run_pending_tests(struct dmatest_info *info) { struct dmatest_chan *dtc; unsigned int thread_count = 0; list_for_each_entry(dtc, &info->channels, node) { struct dmatest_thread *thread; thread_count = 0; list_for_each_entry(thread, &dtc->threads, node) { wake_up_process(thread->task); thread_count++; } pr_info("Started %u threads using %s ", thread_count, dma_chan_name(dtc->chan)); } } |
a310d037b dmatest: restore ... |
1080 |
static void stop_threaded_test(struct dmatest_info *info) |
4a776f0aa dmatest: Simple D... |
1081 |
{ |
33df8ca06 dmatest: convert ... |
1082 |
struct dmatest_chan *dtc, *_dtc; |
7cbd4877e dmatest: fix use ... |
1083 |
struct dma_chan *chan; |
33df8ca06 dmatest: convert ... |
1084 |
|
838cc704c dmatest: move dma... |
1085 |
list_for_each_entry_safe(dtc, _dtc, &info->channels, node) { |
33df8ca06 dmatest: convert ... |
1086 |
list_del(&dtc->node); |
7cbd4877e dmatest: fix use ... |
1087 |
chan = dtc->chan; |
33df8ca06 dmatest: convert ... |
1088 |
dmatest_cleanup_channel(dtc); |
0adff8006 dmatest: cleanup ... |
1089 1090 |
pr_debug("dropped channel %s ", dma_chan_name(chan)); |
7cbd4877e dmatest: fix use ... |
1091 |
dma_release_channel(chan); |
33df8ca06 dmatest: convert ... |
1092 |
} |
838cc704c dmatest: move dma... |
1093 1094 |
info->nr_channels = 0; |
4a776f0aa dmatest: Simple D... |
1095 |
} |
e03e93a97 dmatest: create d... |
1096 |
|
d53513d5d dmaengine: dmates... |
1097 |
static void start_threaded_tests(struct dmatest_info *info) |
851b7e16a dmatest: run test... |
1098 |
{ |
a310d037b dmatest: restore ... |
1099 1100 1101 1102 |
/* we might be called early to set run=, defer running until all * parameters have been evaluated */ if (!info->did_init) |
a9e554957 dmatest: support ... |
1103 |
return; |
851b7e16a dmatest: run test... |
1104 |
|
d53513d5d dmaengine: dmates... |
1105 |
run_pending_tests(info); |
851b7e16a dmatest: run test... |
1106 |
} |
a310d037b dmatest: restore ... |
1107 |
static int dmatest_run_get(char *val, const struct kernel_param *kp) |
851b7e16a dmatest: run test... |
1108 |
{ |
a310d037b dmatest: restore ... |
1109 |
struct dmatest_info *info = &test_info; |
851b7e16a dmatest: run test... |
1110 1111 |
mutex_lock(&info->lock); |
a310d037b dmatest: restore ... |
1112 1113 |
if (is_threaded_test_run(info)) { dmatest_run = true; |
3e5ccd866 dmatest: return a... |
1114 |
} else { |
d53513d5d dmaengine: dmates... |
1115 1116 |
if (!is_threaded_test_pending(info)) stop_threaded_test(info); |
a310d037b dmatest: restore ... |
1117 |
dmatest_run = false; |
3e5ccd866 dmatest: return a... |
1118 |
} |
851b7e16a dmatest: run test... |
1119 |
mutex_unlock(&info->lock); |
851b7e16a dmatest: run test... |
1120 |
|
a310d037b dmatest: restore ... |
1121 |
return param_get_bool(val, kp); |
851b7e16a dmatest: run test... |
1122 |
} |
a310d037b dmatest: restore ... |
1123 |
static int dmatest_run_set(const char *val, const struct kernel_param *kp) |
95019c8c5 dmatest: gather t... |
1124 |
{ |
a310d037b dmatest: restore ... |
1125 1126 |
struct dmatest_info *info = &test_info; int ret; |
95019c8c5 dmatest: gather t... |
1127 |
|
a310d037b dmatest: restore ... |
1128 1129 1130 |
mutex_lock(&info->lock); ret = param_set_bool(val, kp); if (ret) { |
851b7e16a dmatest: run test... |
1131 |
mutex_unlock(&info->lock); |
a310d037b dmatest: restore ... |
1132 |
return ret; |
d53513d5d dmaengine: dmates... |
1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 |
} else if (dmatest_run) { if (is_threaded_test_pending(info)) start_threaded_tests(info); else pr_info("Could not start test, no channels configured "); } else { stop_threaded_test(info); } mutex_unlock(&info->lock); return ret; } static int dmatest_chan_set(const char *val, const struct kernel_param *kp) { struct dmatest_info *info = &test_info; struct dmatest_chan *dtc; char chan_reset_val[20]; int ret = 0; mutex_lock(&info->lock); ret = param_set_copystring(val, kp); if (ret) { mutex_unlock(&info->lock); return ret; } /*Clear any previously run threads */ if (!is_threaded_test_run(info) && !is_threaded_test_pending(info)) stop_threaded_test(info); /* Reject channels that are already registered */ if (is_threaded_test_pending(info)) { list_for_each_entry(dtc, &info->channels, node) { if (strcmp(dma_chan_name(dtc->chan), strim(test_channel)) == 0) { dtc = list_last_entry(&info->channels, struct dmatest_chan, node); strlcpy(chan_reset_val, dma_chan_name(dtc->chan), sizeof(chan_reset_val)); ret = -EBUSY; goto add_chan_err; } } |
95019c8c5 dmatest: gather t... |
1179 |
} |
d53513d5d dmaengine: dmates... |
1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 |
add_threaded_test(info); /* Check if channel was added successfully */ dtc = list_last_entry(&info->channels, struct dmatest_chan, node); if (dtc->chan) { /* * if new channel was not successfully added, revert the * "test_channel" string to the name of the last successfully * added channel. exception for when users issues empty string * to channel parameter. */ if ((strcmp(dma_chan_name(dtc->chan), strim(test_channel)) != 0) && (strcmp("", strim(test_channel)) != 0)) { ret = -EINVAL; strlcpy(chan_reset_val, dma_chan_name(dtc->chan), sizeof(chan_reset_val)); goto add_chan_err; } } else { /* Clear test_channel if no channels were added successfully */ strlcpy(chan_reset_val, "", sizeof(chan_reset_val)); |
a310d037b dmatest: restore ... |
1203 |
ret = -EBUSY; |
d53513d5d dmaengine: dmates... |
1204 1205 1206 1207 1208 1209 |
goto add_chan_err; } mutex_unlock(&info->lock); return ret; |
851b7e16a dmatest: run test... |
1210 |
|
d53513d5d dmaengine: dmates... |
1211 1212 |
add_chan_err: param_set_copystring(chan_reset_val, kp); |
a310d037b dmatest: restore ... |
1213 |
mutex_unlock(&info->lock); |
851b7e16a dmatest: run test... |
1214 |
|
a310d037b dmatest: restore ... |
1215 |
return ret; |
851b7e16a dmatest: run test... |
1216 |
} |
d53513d5d dmaengine: dmates... |
1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 |
static int dmatest_chan_get(char *val, const struct kernel_param *kp) { struct dmatest_info *info = &test_info; mutex_lock(&info->lock); if (!is_threaded_test_run(info) && !is_threaded_test_pending(info)) { stop_threaded_test(info); strlcpy(test_channel, "", sizeof(test_channel)); } mutex_unlock(&info->lock); return param_get_string(val, kp); } static int dmatest_test_list_get(char *val, const struct kernel_param *kp) { struct dmatest_info *info = &test_info; struct dmatest_chan *dtc; unsigned int thread_count = 0; list_for_each_entry(dtc, &info->channels, node) { struct dmatest_thread *thread; thread_count = 0; list_for_each_entry(thread, &dtc->threads, node) { thread_count++; } pr_info("%u threads using %s ", thread_count, dma_chan_name(dtc->chan)); } return 0; } |
e03e93a97 dmatest: create d... |
1251 1252 1253 |
static int __init dmatest_init(void) { struct dmatest_info *info = &test_info; |
2d88ce76e dmatest: add a 'w... |
1254 |
struct dmatest_params *params = &info->params; |
e03e93a97 dmatest: create d... |
1255 |
|
a310d037b dmatest: restore ... |
1256 1257 |
if (dmatest_run) { mutex_lock(&info->lock); |
d53513d5d dmaengine: dmates... |
1258 1259 |
add_threaded_test(info); run_pending_tests(info); |
a310d037b dmatest: restore ... |
1260 1261 |
mutex_unlock(&info->lock); } |
838cc704c dmatest: move dma... |
1262 |
|
2d88ce76e dmatest: add a 'w... |
1263 1264 |
if (params->iterations && wait) wait_event(thread_wait, !is_threaded_test_run(info)); |
95019c8c5 dmatest: gather t... |
1265 |
|
a310d037b dmatest: restore ... |
1266 1267 1268 1269 |
/* module parameters are stable, inittime tests are started, * let userspace take over 'run' control */ info->did_init = true; |
851b7e16a dmatest: run test... |
1270 |
|
851b7e16a dmatest: run test... |
1271 |
return 0; |
e03e93a97 dmatest: create d... |
1272 1273 1274 1275 1276 1277 1278 |
} /* when compiled-in wait for drivers to load first */ late_initcall(dmatest_init); static void __exit dmatest_exit(void) { struct dmatest_info *info = &test_info; |
a310d037b dmatest: restore ... |
1279 |
mutex_lock(&info->lock); |
e03e93a97 dmatest: create d... |
1280 |
stop_threaded_test(info); |
a310d037b dmatest: restore ... |
1281 |
mutex_unlock(&info->lock); |
e03e93a97 dmatest: create d... |
1282 |
} |
4a776f0aa dmatest: Simple D... |
1283 |
module_exit(dmatest_exit); |
e05503ef1 Haavard Skinnemoe... |
1284 |
MODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); |
4a776f0aa dmatest: Simple D... |
1285 |
MODULE_LICENSE("GPL v2"); |