Blame view

drivers/dma/dmatest.c 28.1 KB
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
1
2
3
4
  /*
   * DMA Engine test module
   *
   * Copyright (C) 2007 Atmel Corporation
851b7e16a   Andy Shevchenko   dmatest: run test...
5
   * Copyright (C) 2013 Intel Corporation
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
6
7
8
9
10
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   */
872f05c6e   Dan Williams   dmatest: replace ...
11
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
12
  #include <linux/delay.h>
b7f080cfe   Alexey Dobriyan   net: remove mm.h ...
13
  #include <linux/dma-mapping.h>
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
14
  #include <linux/dmaengine.h>
981ed70d8   Guennadi Liakhovetski   dmatest: make dma...
15
  #include <linux/freezer.h>
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
16
17
  #include <linux/init.h>
  #include <linux/kthread.h>
0881e7bd3   Ingo Molnar   sched/headers: Pr...
18
  #include <linux/sched/task.h>
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
19
20
21
  #include <linux/module.h>
  #include <linux/moduleparam.h>
  #include <linux/random.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
22
  #include <linux/slab.h>
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
23
24
25
  #include <linux/wait.h>
  
  static unsigned int test_buf_size = 16384;
a6c268d03   Andy Shevchenko   dmatest: make mod...
26
  module_param(test_buf_size, uint, S_IRUGO | S_IWUSR);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
27
  MODULE_PARM_DESC(test_buf_size, "Size of the memcpy test buffer");
06190d841   Kay Sievers   dmaengine: struct...
28
  static char test_channel[20];
a6c268d03   Andy Shevchenko   dmatest: make mod...
29
30
  module_param_string(channel, test_channel, sizeof(test_channel),
  		S_IRUGO | S_IWUSR);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
31
  MODULE_PARM_DESC(channel, "Bus ID of the channel to test (default: any)");
a85159fec   Guennadi Liakhovetski   DMA: dmatest: ext...
32
  static char test_device[32];
a6c268d03   Andy Shevchenko   dmatest: make mod...
33
34
  module_param_string(device, test_device, sizeof(test_device),
  		S_IRUGO | S_IWUSR);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
35
36
37
  MODULE_PARM_DESC(device, "Bus ID of the DMA Engine to test (default: any)");
  
  static unsigned int threads_per_chan = 1;
a6c268d03   Andy Shevchenko   dmatest: make mod...
38
  module_param(threads_per_chan, uint, S_IRUGO | S_IWUSR);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
39
40
41
42
  MODULE_PARM_DESC(threads_per_chan,
  		"Number of threads to start per channel (default: 1)");
  
  static unsigned int max_channels;
a6c268d03   Andy Shevchenko   dmatest: make mod...
43
  module_param(max_channels, uint, S_IRUGO | S_IWUSR);
33df8ca06   Dan Williams   dmatest: convert ...
44
  MODULE_PARM_DESC(max_channels,
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
45
  		"Maximum number of channels to use (default: all)");
0a2ff57d6   Nicolas Ferre   dmaengine: dmates...
46
  static unsigned int iterations;
a6c268d03   Andy Shevchenko   dmatest: make mod...
47
  module_param(iterations, uint, S_IRUGO | S_IWUSR);
0a2ff57d6   Nicolas Ferre   dmaengine: dmates...
48
49
  MODULE_PARM_DESC(iterations,
  		"Iterations before stopping test (default: infinite)");
d86467249   Eugeniy Paltsev   dmaengine: dmates...
50
  static unsigned int dmatest;
a0d4cb44d   Kedareswara rao Appana   dmaengine: dmates...
51
52
  module_param(dmatest, uint, S_IRUGO | S_IWUSR);
  MODULE_PARM_DESC(dmatest,
c678fa663   Dave Jiang   dmaengine: remove...
53
  		"dmatest 0-memcpy 1-memset (default: 0)");
a0d4cb44d   Kedareswara rao Appana   dmaengine: dmates...
54

b54d5cb91   Dan Williams   dmatest: add xor ...
55
  static unsigned int xor_sources = 3;
a6c268d03   Andy Shevchenko   dmatest: make mod...
56
  module_param(xor_sources, uint, S_IRUGO | S_IWUSR);
b54d5cb91   Dan Williams   dmatest: add xor ...
57
58
  MODULE_PARM_DESC(xor_sources,
  		"Number of xor source buffers (default: 3)");
58691d64c   Dan Williams   dmatest: add pq s...
59
  static unsigned int pq_sources = 3;
a6c268d03   Andy Shevchenko   dmatest: make mod...
60
  module_param(pq_sources, uint, S_IRUGO | S_IWUSR);
58691d64c   Dan Williams   dmatest: add pq s...
61
62
  MODULE_PARM_DESC(pq_sources,
  		"Number of p+q source buffers (default: 3)");
d42efe6bf   Viresh Kumar   dmaengine/dmatest...
63
  static int timeout = 3000;
a6c268d03   Andy Shevchenko   dmatest: make mod...
64
  module_param(timeout, uint, S_IRUGO | S_IWUSR);
85ee7a1d3   Joe Perches   treewide: cleanup...
65
66
  MODULE_PARM_DESC(timeout, "Transfer Timeout in msec (default: 3000), "
  		 "Pass -1 for infinite timeout");
d42efe6bf   Viresh Kumar   dmaengine/dmatest...
67

e3b9c3473   Dan Williams   dmatest: add supp...
68
69
70
  static bool noverify;
  module_param(noverify, bool, S_IRUGO | S_IWUSR);
  MODULE_PARM_DESC(noverify, "Disable random data setup and verification");
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
71

50137a7df   Dan Williams   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   Haavard Skinnemoen   dmatest: Simple D...
75

e03e93a97   Andy Shevchenko   dmatest: create d...
76
  /**
15b8a8ea1   Andy Shevchenko   dmatest: split te...
77
   * struct dmatest_params - test parameters.
e03e93a97   Andy Shevchenko   dmatest: create d...
78
79
80
81
82
83
84
85
86
87
   * @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
   * @timeout:		transfer timeout in msec, -1 for infinite timeout
   */
15b8a8ea1   Andy Shevchenko   dmatest: split te...
88
  struct dmatest_params {
e03e93a97   Andy Shevchenko   dmatest: create d...
89
90
  	unsigned int	buf_size;
  	char		channel[20];
a85159fec   Guennadi Liakhovetski   DMA: dmatest: ext...
91
  	char		device[32];
e03e93a97   Andy Shevchenko   dmatest: create d...
92
93
94
95
96
97
  	unsigned int	threads_per_chan;
  	unsigned int	max_channels;
  	unsigned int	iterations;
  	unsigned int	xor_sources;
  	unsigned int	pq_sources;
  	int		timeout;
e3b9c3473   Dan Williams   dmatest: add supp...
98
  	bool		noverify;
15b8a8ea1   Andy Shevchenko   dmatest: split te...
99
100
101
102
103
  };
  
  /**
   * struct dmatest_info - test information.
   * @params:		test parameters
851b7e16a   Andy Shevchenko   dmatest: run test...
104
   * @lock:		access protection to the fields of this structure
15b8a8ea1   Andy Shevchenko   dmatest: split te...
105
   */
a310d037b   Dan Williams   dmatest: restore ...
106
  static struct dmatest_info {
15b8a8ea1   Andy Shevchenko   dmatest: split te...
107
108
  	/* Test parameters */
  	struct dmatest_params	params;
838cc704c   Andy Shevchenko   dmatest: move dma...
109
110
111
112
  
  	/* Internal state */
  	struct list_head	channels;
  	unsigned int		nr_channels;
851b7e16a   Andy Shevchenko   dmatest: run test...
113
  	struct mutex		lock;
a310d037b   Dan Williams   dmatest: restore ...
114
115
116
117
118
  	bool			did_init;
  } test_info = {
  	.channels = LIST_HEAD_INIT(test_info.channels),
  	.lock = __MUTEX_INITIALIZER(test_info.lock),
  };
851b7e16a   Andy Shevchenko   dmatest: run test...
119

a310d037b   Dan Williams   dmatest: restore ...
120
121
  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   Luis R. Rodriguez   kernel/params: co...
122
  static const struct kernel_param_ops run_ops = {
a310d037b   Dan Williams   dmatest: restore ...
123
124
  	.set = dmatest_run_set,
  	.get = dmatest_run_get,
e03e93a97   Andy Shevchenko   dmatest: create d...
125
  };
a310d037b   Dan Williams   dmatest: restore ...
126
127
128
  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   Andy Shevchenko   dmatest: create d...
129

a310d037b   Dan Williams   dmatest: restore ...
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
  /* 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   Sinan Kaya   dmaengine: dmates...
149
  #define PATTERN_MEMSET_IDX	0x01
851b7e16a   Andy Shevchenko   dmatest: run test...
150

0aa5d007b   Adam Wallis   dmaengine: dmates...
151
152
153
154
155
  /* poor man's completion - we want to use wait_event_freezable() on it */
  struct dmatest_done {
  	bool			done;
  	wait_queue_head_t	*wait;
  };
a310d037b   Dan Williams   dmatest: restore ...
156
157
158
159
160
161
  struct dmatest_thread {
  	struct list_head	node;
  	struct dmatest_info	*info;
  	struct task_struct	*task;
  	struct dma_chan		*chan;
  	u8			**srcs;
d64816086   Dave Jiang   dmaengine: dmates...
162
  	u8			**usrcs;
a310d037b   Dan Williams   dmatest: restore ...
163
  	u8			**dsts;
d64816086   Dave Jiang   dmaengine: dmates...
164
  	u8			**udsts;
a310d037b   Dan Williams   dmatest: restore ...
165
  	enum dma_transaction_type type;
0aa5d007b   Adam Wallis   dmaengine: dmates...
166
167
  	wait_queue_head_t done_wait;
  	struct dmatest_done test_done;
a310d037b   Dan Williams   dmatest: restore ...
168
169
  	bool			done;
  };
95019c8c5   Andy Shevchenko   dmatest: gather t...
170

a310d037b   Dan Williams   dmatest: restore ...
171
172
173
174
  struct dmatest_chan {
  	struct list_head	node;
  	struct dma_chan		*chan;
  	struct list_head	threads;
e03e93a97   Andy Shevchenko   dmatest: create d...
175
  };
2d88ce76e   Dan Williams   dmatest: add a 'w...
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
  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;
  }
  
  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   Luis R. Rodriguez   kernel/params: co...
205
  static const struct kernel_param_ops wait_ops = {
2d88ce76e   Dan Williams   dmatest: add a 'w...
206
207
208
209
210
  	.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   Andy Shevchenko   dmatest: create d...
211

15b8a8ea1   Andy Shevchenko   dmatest: split te...
212
  static bool dmatest_match_channel(struct dmatest_params *params,
e03e93a97   Andy Shevchenko   dmatest: create d...
213
  		struct dma_chan *chan)
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
214
  {
15b8a8ea1   Andy Shevchenko   dmatest: split te...
215
  	if (params->channel[0] == '\0')
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
216
  		return true;
15b8a8ea1   Andy Shevchenko   dmatest: split te...
217
  	return strcmp(dma_chan_name(chan), params->channel) == 0;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
218
  }
15b8a8ea1   Andy Shevchenko   dmatest: split te...
219
  static bool dmatest_match_device(struct dmatest_params *params,
e03e93a97   Andy Shevchenko   dmatest: create d...
220
  		struct dma_device *device)
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
221
  {
15b8a8ea1   Andy Shevchenko   dmatest: split te...
222
  	if (params->device[0] == '\0')
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
223
  		return true;
15b8a8ea1   Andy Shevchenko   dmatest: split te...
224
  	return strcmp(dev_name(device->dev), params->device) == 0;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
225
226
227
228
229
  }
  
  static unsigned long dmatest_random(void)
  {
  	unsigned long buf;
be9fa5a43   Dan Williams   dmatest: use pseu...
230
  	prandom_bytes(&buf, sizeof(buf));
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
231
232
  	return buf;
  }
61b5f54d8   Sinan Kaya   dmaengine: dmates...
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
  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   Andy Shevchenko   dmatest: create d...
249
  static void dmatest_init_srcs(u8 **bufs, unsigned int start, unsigned int len,
61b5f54d8   Sinan Kaya   dmaengine: dmates...
250
  		unsigned int buf_size, bool is_memset)
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
251
252
  {
  	unsigned int i;
b54d5cb91   Dan Williams   dmatest: add xor ...
253
254
255
256
  	u8 *buf;
  
  	for (; (buf = *bufs); bufs++) {
  		for (i = 0; i < start; i++)
61b5f54d8   Sinan Kaya   dmaengine: dmates...
257
  			buf[i] = gen_src_value(i, is_memset);
b54d5cb91   Dan Williams   dmatest: add xor ...
258
  		for ( ; i < start + len; i++)
61b5f54d8   Sinan Kaya   dmaengine: dmates...
259
  			buf[i] = gen_src_value(i, is_memset) | PATTERN_COPY;
e03e93a97   Andy Shevchenko   dmatest: create d...
260
  		for ( ; i < buf_size; i++)
61b5f54d8   Sinan Kaya   dmaengine: dmates...
261
  			buf[i] = gen_src_value(i, is_memset);
b54d5cb91   Dan Williams   dmatest: add xor ...
262
263
  		buf++;
  	}
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
264
  }
e03e93a97   Andy Shevchenko   dmatest: create d...
265
  static void dmatest_init_dsts(u8 **bufs, unsigned int start, unsigned int len,
61b5f54d8   Sinan Kaya   dmaengine: dmates...
266
  		unsigned int buf_size, bool is_memset)
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
267
268
  {
  	unsigned int i;
b54d5cb91   Dan Williams   dmatest: add xor ...
269
270
271
272
  	u8 *buf;
  
  	for (; (buf = *bufs); bufs++) {
  		for (i = 0; i < start; i++)
61b5f54d8   Sinan Kaya   dmaengine: dmates...
273
  			buf[i] = gen_dst_value(i, is_memset);
b54d5cb91   Dan Williams   dmatest: add xor ...
274
  		for ( ; i < start + len; i++)
61b5f54d8   Sinan Kaya   dmaengine: dmates...
275
276
  			buf[i] = gen_dst_value(i, is_memset) |
  						PATTERN_OVERWRITE;
e03e93a97   Andy Shevchenko   dmatest: create d...
277
  		for ( ; i < buf_size; i++)
61b5f54d8   Sinan Kaya   dmaengine: dmates...
278
  			buf[i] = gen_dst_value(i, is_memset);
b54d5cb91   Dan Williams   dmatest: add xor ...
279
  	}
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
280
  }
7b6101782   Dan Williams   Revert "dmatest: ...
281
  static void dmatest_mismatch(u8 actual, u8 pattern, unsigned int index,
61b5f54d8   Sinan Kaya   dmaengine: dmates...
282
  		unsigned int counter, bool is_srcbuf, bool is_memset)
7b6101782   Dan Williams   Revert "dmatest: ...
283
284
  {
  	u8		diff = actual ^ pattern;
61b5f54d8   Sinan Kaya   dmaengine: dmates...
285
  	u8		expected = pattern | gen_inv_idx(counter, is_memset);
7b6101782   Dan Williams   Revert "dmatest: ...
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
  	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   Sinan Kaya   dmaengine: dmates...
309
  		bool is_srcbuf, bool is_memset)
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
310
311
312
313
  {
  	unsigned int i;
  	unsigned int error_count = 0;
  	u8 actual;
b54d5cb91   Dan Williams   dmatest: add xor ...
314
315
316
317
318
319
320
321
  	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   Sinan Kaya   dmaengine: dmates...
322
  			expected = pattern | gen_inv_idx(counter, is_memset);
b54d5cb91   Dan Williams   dmatest: add xor ...
323
  			if (actual != expected) {
7b6101782   Dan Williams   Revert "dmatest: ...
324
325
  				if (error_count < MAX_ERROR_COUNT)
  					dmatest_mismatch(actual, pattern, i,
61b5f54d8   Sinan Kaya   dmaengine: dmates...
326
327
  							 counter, is_srcbuf,
  							 is_memset);
b54d5cb91   Dan Williams   dmatest: add xor ...
328
329
330
  				error_count++;
  			}
  			counter++;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
331
  		}
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
332
  	}
74b5c07a5   Andy Shevchenko   dmatest: define M...
333
  	if (error_count > MAX_ERROR_COUNT)
7b6101782   Dan Williams   Revert "dmatest: ...
334
335
  		pr_warn("%s: %u errors suppressed
  ",
74b5c07a5   Andy Shevchenko   dmatest: define M...
336
  			current->comm, error_count - MAX_ERROR_COUNT);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
337
338
339
  
  	return error_count;
  }
adfa543e7   Tejun Heo   dmatest: don't us...
340
341
  
  static void dmatest_callback(void *arg)
e44e0aa3c   Dan Williams   dmatest: add dma ...
342
  {
adfa543e7   Tejun Heo   dmatest: don't us...
343
  	struct dmatest_done *done = arg;
0aa5d007b   Adam Wallis   dmaengine: dmates...
344
  	struct dmatest_thread *thread =
69373cdc4   Yang Shunyong   dmaengine: dmates...
345
  		container_of(done, struct dmatest_thread, test_done);
0aa5d007b   Adam Wallis   dmaengine: dmates...
346
347
348
349
350
351
352
353
354
355
356
357
358
359
  	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   Dan Williams   dmatest: add dma ...
360
  }
8be9e32b3   Akinobu Mita   dmatest: adjust i...
361
362
363
364
365
366
  static unsigned int min_odd(unsigned int x, unsigned int y)
  {
  	unsigned int val = min(x, y);
  
  	return val % 2 ? val : val - 1;
  }
872f05c6e   Dan Williams   dmatest: replace ...
367
368
  static void result(const char *err, unsigned int n, unsigned int src_off,
  		   unsigned int dst_off, unsigned int len, unsigned long data)
d86b2f298   Andy Shevchenko   dmatest: append v...
369
  {
2acec1503   Jerome Blin   Add new line to t...
370
371
  	pr_info("%s: result #%u: '%s' with src_off=0x%x dst_off=0x%x len=0x%x (%lu)
  ",
872f05c6e   Dan Williams   dmatest: replace ...
372
  		current->comm, n, err, src_off, dst_off, len, data);
d86b2f298   Andy Shevchenko   dmatest: append v...
373
  }
872f05c6e   Dan Williams   dmatest: replace ...
374
375
376
  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   Andy Shevchenko   dmatest: gather t...
377
  {
2acec1503   Jerome Blin   Add new line to t...
378
379
  	pr_debug("%s: result #%u: '%s' with src_off=0x%x dst_off=0x%x len=0x%x (%lu)
  ",
a835bb855   Andy Shevchenko   dmatest: fix inde...
380
  		 current->comm, n, err, src_off, dst_off, len, data);
95019c8c5   Andy Shevchenko   dmatest: gather t...
381
  }
a835bb855   Andy Shevchenko   dmatest: fix inde...
382
383
384
385
386
  #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   Dan Williams   dmatest: verbose ...
387
  })
95019c8c5   Andy Shevchenko   dmatest: gather t...
388

86727443a   Dan Williams   dmatest: add basi...
389
  static unsigned long long dmatest_persec(s64 runtime, unsigned int val)
d86b2f298   Andy Shevchenko   dmatest: append v...
390
  {
86727443a   Dan Williams   dmatest: add basi...
391
  	unsigned long long per_sec = 1000000;
d86b2f298   Andy Shevchenko   dmatest: append v...
392

86727443a   Dan Williams   dmatest: add basi...
393
394
  	if (runtime <= 0)
  		return 0;
95019c8c5   Andy Shevchenko   dmatest: gather t...
395

86727443a   Dan Williams   dmatest: add basi...
396
397
398
399
  	/* drop precision until runtime is 32-bits */
  	while (runtime > UINT_MAX) {
  		runtime >>= 1;
  		per_sec <<= 1;
95019c8c5   Andy Shevchenko   dmatest: gather t...
400
  	}
86727443a   Dan Williams   dmatest: add basi...
401
402
403
  	per_sec *= val;
  	do_div(per_sec, runtime);
  	return per_sec;
95019c8c5   Andy Shevchenko   dmatest: gather t...
404
  }
86727443a   Dan Williams   dmatest: add basi...
405
  static unsigned long long dmatest_KBs(s64 runtime, unsigned long long len)
95019c8c5   Andy Shevchenko   dmatest: gather t...
406
  {
86727443a   Dan Williams   dmatest: add basi...
407
  	return dmatest_persec(runtime, len >> 10);
95019c8c5   Andy Shevchenko   dmatest: gather t...
408
  }
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
409
410
  /*
   * This function repeatedly tests DMA transfers of various lengths and
b54d5cb91   Dan Williams   dmatest: add xor ...
411
412
413
414
   * 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   Haavard Skinnemoen   dmatest: Simple D...
415
416
417
418
419
420
421
422
423
424
425
   *
   * 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;
0aa5d007b   Adam Wallis   dmaengine: dmates...
426
  	struct dmatest_done	*done = &thread->test_done;
e03e93a97   Andy Shevchenko   dmatest: create d...
427
  	struct dmatest_info	*info;
15b8a8ea1   Andy Shevchenko   dmatest: split te...
428
  	struct dmatest_params	*params;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
429
  	struct dma_chan		*chan;
8be9e32b3   Akinobu Mita   dmatest: adjust i...
430
  	struct dma_device	*dev;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
431
432
433
434
435
  	unsigned int		error_count;
  	unsigned int		failed_tests = 0;
  	unsigned int		total_tests = 0;
  	dma_cookie_t		cookie;
  	enum dma_status		status;
b54d5cb91   Dan Williams   dmatest: add xor ...
436
  	enum dma_ctrl_flags 	flags;
945b5af3c   Andy Shevchenko   dmatest: allocate...
437
  	u8			*pq_coefs = NULL;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
438
  	int			ret;
b54d5cb91   Dan Williams   dmatest: add xor ...
439
440
441
  	int			src_cnt;
  	int			dst_cnt;
  	int			i;
e9405ef08   Sinan Kaya   dmaengine: dmates...
442
  	ktime_t			ktime, start, diff;
8b0e19531   Thomas Gleixner   ktime: Cleanup kt...
443
444
  	ktime_t			filltime = 0;
  	ktime_t			comparetime = 0;
86727443a   Dan Williams   dmatest: add basi...
445
446
  	s64			runtime = 0;
  	unsigned long long	total_len = 0;
d64816086   Dave Jiang   dmaengine: dmates...
447
  	u8			align = 0;
61b5f54d8   Sinan Kaya   dmaengine: dmates...
448
  	bool			is_memset = false;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
449

adfa543e7   Tejun Heo   dmatest: don't us...
450
  	set_freezable();
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
451
452
  
  	ret = -ENOMEM;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
453
454
  
  	smp_rmb();
e03e93a97   Andy Shevchenko   dmatest: create d...
455
  	info = thread->info;
15b8a8ea1   Andy Shevchenko   dmatest: split te...
456
  	params = &info->params;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
457
  	chan = thread->chan;
8be9e32b3   Akinobu Mita   dmatest: adjust i...
458
  	dev = chan->device;
d64816086   Dave Jiang   dmaengine: dmates...
459
460
  	if (thread->type == DMA_MEMCPY) {
  		align = dev->copy_align;
b54d5cb91   Dan Williams   dmatest: add xor ...
461
  		src_cnt = dst_cnt = 1;
61b5f54d8   Sinan Kaya   dmaengine: dmates...
462
463
464
465
  	} else if (thread->type == DMA_MEMSET) {
  		align = dev->fill_align;
  		src_cnt = dst_cnt = 1;
  		is_memset = true;
d64816086   Dave Jiang   dmaengine: dmates...
466
  	} else if (thread->type == DMA_XOR) {
8be9e32b3   Akinobu Mita   dmatest: adjust i...
467
  		/* force odd to ensure dst = src */
15b8a8ea1   Andy Shevchenko   dmatest: split te...
468
  		src_cnt = min_odd(params->xor_sources | 1, dev->max_xor);
b54d5cb91   Dan Williams   dmatest: add xor ...
469
  		dst_cnt = 1;
d64816086   Dave Jiang   dmaengine: dmates...
470
  		align = dev->xor_align;
58691d64c   Dan Williams   dmatest: add pq s...
471
  	} else if (thread->type == DMA_PQ) {
8be9e32b3   Akinobu Mita   dmatest: adjust i...
472
  		/* force odd to ensure dst = src */
15b8a8ea1   Andy Shevchenko   dmatest: split te...
473
  		src_cnt = min_odd(params->pq_sources | 1, dma_maxpq(dev, 0));
58691d64c   Dan Williams   dmatest: add pq s...
474
  		dst_cnt = 2;
d64816086   Dave Jiang   dmaengine: dmates...
475
  		align = dev->pq_align;
945b5af3c   Andy Shevchenko   dmatest: allocate...
476

31d182574   Dave Jiang   dmaengine: fix sp...
477
  		pq_coefs = kmalloc(params->pq_sources + 1, GFP_KERNEL);
945b5af3c   Andy Shevchenko   dmatest: allocate...
478
479
  		if (!pq_coefs)
  			goto err_thread_type;
94de648d7   Anatolij Gustschin   dmatest: correct ...
480
  		for (i = 0; i < src_cnt; i++)
58691d64c   Dan Williams   dmatest: add pq s...
481
  			pq_coefs[i] = 1;
b54d5cb91   Dan Williams   dmatest: add xor ...
482
  	} else
945b5af3c   Andy Shevchenko   dmatest: allocate...
483
  		goto err_thread_type;
b54d5cb91   Dan Williams   dmatest: add xor ...
484

31d182574   Dave Jiang   dmaengine: fix sp...
485
  	thread->srcs = kcalloc(src_cnt + 1, sizeof(u8 *), GFP_KERNEL);
b54d5cb91   Dan Williams   dmatest: add xor ...
486
487
  	if (!thread->srcs)
  		goto err_srcs;
d64816086   Dave Jiang   dmaengine: dmates...
488
489
490
491
  
  	thread->usrcs = kcalloc(src_cnt + 1, sizeof(u8 *), GFP_KERNEL);
  	if (!thread->usrcs)
  		goto err_usrcs;
b54d5cb91   Dan Williams   dmatest: add xor ...
492
  	for (i = 0; i < src_cnt; i++) {
d64816086   Dave Jiang   dmaengine: dmates...
493
494
495
  		thread->usrcs[i] = kmalloc(params->buf_size + align,
  					   GFP_KERNEL);
  		if (!thread->usrcs[i])
b54d5cb91   Dan Williams   dmatest: add xor ...
496
  			goto err_srcbuf;
d64816086   Dave Jiang   dmaengine: dmates...
497
498
499
500
501
502
  
  		/* align srcs to alignment restriction */
  		if (align)
  			thread->srcs[i] = PTR_ALIGN(thread->usrcs[i], align);
  		else
  			thread->srcs[i] = thread->usrcs[i];
b54d5cb91   Dan Williams   dmatest: add xor ...
503
504
  	}
  	thread->srcs[i] = NULL;
31d182574   Dave Jiang   dmaengine: fix sp...
505
  	thread->dsts = kcalloc(dst_cnt + 1, sizeof(u8 *), GFP_KERNEL);
b54d5cb91   Dan Williams   dmatest: add xor ...
506
507
  	if (!thread->dsts)
  		goto err_dsts;
d64816086   Dave Jiang   dmaengine: dmates...
508
509
510
511
  
  	thread->udsts = kcalloc(dst_cnt + 1, sizeof(u8 *), GFP_KERNEL);
  	if (!thread->udsts)
  		goto err_udsts;
b54d5cb91   Dan Williams   dmatest: add xor ...
512
  	for (i = 0; i < dst_cnt; i++) {
d64816086   Dave Jiang   dmaengine: dmates...
513
514
515
  		thread->udsts[i] = kmalloc(params->buf_size + align,
  					   GFP_KERNEL);
  		if (!thread->udsts[i])
b54d5cb91   Dan Williams   dmatest: add xor ...
516
  			goto err_dstbuf;
d64816086   Dave Jiang   dmaengine: dmates...
517
518
519
520
521
522
  
  		/* align dsts to alignment restriction */
  		if (align)
  			thread->dsts[i] = PTR_ALIGN(thread->udsts[i], align);
  		else
  			thread->dsts[i] = thread->udsts[i];
b54d5cb91   Dan Williams   dmatest: add xor ...
523
524
  	}
  	thread->dsts[i] = NULL;
e44e0aa3c   Dan Williams   dmatest: add dma ...
525
  	set_user_nice(current, 10);
b203bd3f6   Ira Snyder   dmatest: fix auto...
526
  	/*
d1cab34c0   Bartlomiej Zolnierkiewicz   dmatest: make dri...
527
  	 * src and dst buffers are freed by ourselves below
b203bd3f6   Ira Snyder   dmatest: fix auto...
528
  	 */
0776ae7b8   Bartlomiej Zolnierkiewicz   dmaengine: remove...
529
  	flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
530

86727443a   Dan Williams   dmatest: add basi...
531
  	ktime = ktime_get();
0a2ff57d6   Nicolas Ferre   dmaengine: dmates...
532
  	while (!kthread_should_stop()
15b8a8ea1   Andy Shevchenko   dmatest: split te...
533
  	       && !(params->iterations && total_tests >= params->iterations)) {
b54d5cb91   Dan Williams   dmatest: add xor ...
534
  		struct dma_async_tx_descriptor *tx = NULL;
4076e755d   Dan Williams   dmatest: convert ...
535
536
537
  		struct dmaengine_unmap_data *um;
  		dma_addr_t srcs[src_cnt];
  		dma_addr_t *dsts;
ede23a586   Andy Shevchenko   dmatest: move src...
538
  		unsigned int src_off, dst_off, len;
d86be86e9   Atsushi Nemoto   dmatest: Use cust...
539

4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
540
  		total_tests++;
fbfb8e1dc   Stefan Roese   dmaengine: dmates...
541
542
543
544
545
546
547
  		/* Check if buffer count fits into map count variable (u8) */
  		if ((src_cnt + dst_cnt) >= 255) {
  			pr_err("too many buffers (%d of 255 supported)
  ",
  			       src_cnt + dst_cnt);
  			break;
  		}
15b8a8ea1   Andy Shevchenko   dmatest: split te...
548
  		if (1 << align > params->buf_size) {
cfe4f2751   Guennadi Liakhovetski   dmaengine: fix dm...
549
550
  			pr_err("%u-byte buffer too small for %d-byte alignment
  ",
15b8a8ea1   Andy Shevchenko   dmatest: split te...
551
  			       params->buf_size, 1 << align);
cfe4f2751   Guennadi Liakhovetski   dmaengine: fix dm...
552
553
  			break;
  		}
ede23a586   Andy Shevchenko   dmatest: move src...
554
  		if (params->noverify)
e3b9c3473   Dan Williams   dmatest: add supp...
555
  			len = params->buf_size;
ede23a586   Andy Shevchenko   dmatest: move src...
556
557
558
559
560
561
562
563
564
565
  		else
  			len = dmatest_random() % params->buf_size + 1;
  
  		len = (len >> align) << align;
  		if (!len)
  			len = 1 << align;
  
  		total_len += len;
  
  		if (params->noverify) {
e3b9c3473   Dan Williams   dmatest: add supp...
566
567
568
  			src_off = 0;
  			dst_off = 0;
  		} else {
e9405ef08   Sinan Kaya   dmaengine: dmates...
569
  			start = ktime_get();
e3b9c3473   Dan Williams   dmatest: add supp...
570
571
572
573
574
575
576
  			src_off = dmatest_random() % (params->buf_size - len + 1);
  			dst_off = dmatest_random() % (params->buf_size - len + 1);
  
  			src_off = (src_off >> align) << align;
  			dst_off = (dst_off >> align) << align;
  
  			dmatest_init_srcs(thread->srcs, src_off, len,
61b5f54d8   Sinan Kaya   dmaengine: dmates...
577
  					  params->buf_size, is_memset);
e3b9c3473   Dan Williams   dmatest: add supp...
578
  			dmatest_init_dsts(thread->dsts, dst_off, len,
61b5f54d8   Sinan Kaya   dmaengine: dmates...
579
  					  params->buf_size, is_memset);
e9405ef08   Sinan Kaya   dmaengine: dmates...
580
581
582
  
  			diff = ktime_sub(ktime_get(), start);
  			filltime = ktime_add(filltime, diff);
e3b9c3473   Dan Williams   dmatest: add supp...
583
  		}
31d182574   Dave Jiang   dmaengine: fix sp...
584
  		um = dmaengine_get_unmap_data(dev->dev, src_cnt + dst_cnt,
4076e755d   Dan Williams   dmatest: convert ...
585
586
587
588
589
590
591
  					      GFP_KERNEL);
  		if (!um) {
  			failed_tests++;
  			result("unmap data NULL", total_tests,
  			       src_off, dst_off, len, ret);
  			continue;
  		}
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
592

4076e755d   Dan Williams   dmatest: convert ...
593
  		um->len = params->buf_size;
b54d5cb91   Dan Williams   dmatest: add xor ...
594
  		for (i = 0; i < src_cnt; i++) {
745c00daf   Dan Williams   dmatest: fix buil...
595
  			void *buf = thread->srcs[i];
4076e755d   Dan Williams   dmatest: convert ...
596
  			struct page *pg = virt_to_page(buf);
f62e5f613   Geliang Tang   dmaengine: dmates...
597
  			unsigned long pg_off = offset_in_page(buf);
4076e755d   Dan Williams   dmatest: convert ...
598
599
600
601
602
  
  			um->addr[i] = dma_map_page(dev->dev, pg, pg_off,
  						   um->len, DMA_TO_DEVICE);
  			srcs[i] = um->addr[i] + src_off;
  			ret = dma_mapping_error(dev->dev, um->addr[i]);
afde3be12   Andy Shevchenko   dmatest: check fo...
603
  			if (ret) {
4076e755d   Dan Williams   dmatest: convert ...
604
  				dmaengine_unmap_put(um);
872f05c6e   Dan Williams   dmatest: replace ...
605
606
  				result("src mapping error", total_tests,
  				       src_off, dst_off, len, ret);
afde3be12   Andy Shevchenko   dmatest: check fo...
607
608
609
  				failed_tests++;
  				continue;
  			}
4076e755d   Dan Williams   dmatest: convert ...
610
  			um->to_cnt++;
b54d5cb91   Dan Williams   dmatest: add xor ...
611
  		}
d86be86e9   Atsushi Nemoto   dmatest: Use cust...
612
  		/* map with DMA_BIDIRECTIONAL to force writeback/invalidate */
4076e755d   Dan Williams   dmatest: convert ...
613
  		dsts = &um->addr[src_cnt];
b54d5cb91   Dan Williams   dmatest: add xor ...
614
  		for (i = 0; i < dst_cnt; i++) {
745c00daf   Dan Williams   dmatest: fix buil...
615
  			void *buf = thread->dsts[i];
4076e755d   Dan Williams   dmatest: convert ...
616
  			struct page *pg = virt_to_page(buf);
f62e5f613   Geliang Tang   dmaengine: dmates...
617
  			unsigned long pg_off = offset_in_page(buf);
4076e755d   Dan Williams   dmatest: convert ...
618
619
620
621
  
  			dsts[i] = dma_map_page(dev->dev, pg, pg_off, um->len,
  					       DMA_BIDIRECTIONAL);
  			ret = dma_mapping_error(dev->dev, dsts[i]);
afde3be12   Andy Shevchenko   dmatest: check fo...
622
  			if (ret) {
4076e755d   Dan Williams   dmatest: convert ...
623
  				dmaengine_unmap_put(um);
872f05c6e   Dan Williams   dmatest: replace ...
624
625
  				result("dst mapping error", total_tests,
  				       src_off, dst_off, len, ret);
afde3be12   Andy Shevchenko   dmatest: check fo...
626
627
628
  				failed_tests++;
  				continue;
  			}
4076e755d   Dan Williams   dmatest: convert ...
629
  			um->bidi_cnt++;
b54d5cb91   Dan Williams   dmatest: add xor ...
630
631
632
633
  		}
  
  		if (thread->type == DMA_MEMCPY)
  			tx = dev->device_prep_dma_memcpy(chan,
4076e755d   Dan Williams   dmatest: convert ...
634
635
  							 dsts[0] + dst_off,
  							 srcs[0], len, flags);
61b5f54d8   Sinan Kaya   dmaengine: dmates...
636
637
638
639
640
  		else if (thread->type == DMA_MEMSET)
  			tx = dev->device_prep_dma_memset(chan,
  						dsts[0] + dst_off,
  						*(thread->srcs[0] + src_off),
  						len, flags);
b54d5cb91   Dan Williams   dmatest: add xor ...
641
642
  		else if (thread->type == DMA_XOR)
  			tx = dev->device_prep_dma_xor(chan,
4076e755d   Dan Williams   dmatest: convert ...
643
644
  						      dsts[0] + dst_off,
  						      srcs, src_cnt,
b54d5cb91   Dan Williams   dmatest: add xor ...
645
  						      len, flags);
58691d64c   Dan Williams   dmatest: add pq s...
646
647
648
649
  		else if (thread->type == DMA_PQ) {
  			dma_addr_t dma_pq[dst_cnt];
  
  			for (i = 0; i < dst_cnt; i++)
4076e755d   Dan Williams   dmatest: convert ...
650
651
  				dma_pq[i] = dsts[i] + dst_off;
  			tx = dev->device_prep_dma_pq(chan, dma_pq, srcs,
94de648d7   Anatolij Gustschin   dmatest: correct ...
652
  						     src_cnt, pq_coefs,
58691d64c   Dan Williams   dmatest: add pq s...
653
654
  						     len, flags);
  		}
d86be86e9   Atsushi Nemoto   dmatest: Use cust...
655

d86be86e9   Atsushi Nemoto   dmatest: Use cust...
656
  		if (!tx) {
4076e755d   Dan Williams   dmatest: convert ...
657
  			dmaengine_unmap_put(um);
872f05c6e   Dan Williams   dmatest: replace ...
658
659
  			result("prep error", total_tests, src_off,
  			       dst_off, len, ret);
d86be86e9   Atsushi Nemoto   dmatest: Use cust...
660
661
662
663
  			msleep(100);
  			failed_tests++;
  			continue;
  		}
e44e0aa3c   Dan Williams   dmatest: add dma ...
664

0aa5d007b   Adam Wallis   dmaengine: dmates...
665
  		done->done = false;
e44e0aa3c   Dan Williams   dmatest: add dma ...
666
  		tx->callback = dmatest_callback;
0aa5d007b   Adam Wallis   dmaengine: dmates...
667
  		tx->callback_param = done;
d86be86e9   Atsushi Nemoto   dmatest: Use cust...
668
  		cookie = tx->tx_submit(tx);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
669
  		if (dma_submit_error(cookie)) {
4076e755d   Dan Williams   dmatest: convert ...
670
  			dmaengine_unmap_put(um);
872f05c6e   Dan Williams   dmatest: replace ...
671
672
  			result("submit error", total_tests, src_off,
  			       dst_off, len, ret);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
673
674
675
676
  			msleep(100);
  			failed_tests++;
  			continue;
  		}
b54d5cb91   Dan Williams   dmatest: add xor ...
677
  		dma_async_issue_pending(chan);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
678

0aa5d007b   Adam Wallis   dmaengine: dmates...
679
  		wait_event_freezable_timeout(thread->done_wait, done->done,
15b8a8ea1   Andy Shevchenko   dmatest: split te...
680
  					     msecs_to_jiffies(params->timeout));
981ed70d8   Guennadi Liakhovetski   dmatest: make dma...
681

e44e0aa3c   Dan Williams   dmatest: add dma ...
682
  		status = dma_async_is_tx_complete(chan, cookie, NULL, NULL);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
683

0aa5d007b   Adam Wallis   dmaengine: dmates...
684
  		if (!done->done) {
4076e755d   Dan Williams   dmatest: convert ...
685
  			dmaengine_unmap_put(um);
872f05c6e   Dan Williams   dmatest: replace ...
686
687
  			result("test timed out", total_tests, src_off, dst_off,
  			       len, 0);
e44e0aa3c   Dan Williams   dmatest: add dma ...
688
689
  			failed_tests++;
  			continue;
19e9f99f2   Vinod Koul   dmaengine: dmates...
690
  		} else if (status != DMA_COMPLETE) {
4076e755d   Dan Williams   dmatest: convert ...
691
  			dmaengine_unmap_put(um);
872f05c6e   Dan Williams   dmatest: replace ...
692
693
694
695
  			result(status == DMA_ERROR ?
  			       "completion error status" :
  			       "completion busy status", total_tests, src_off,
  			       dst_off, len, ret);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
696
697
698
  			failed_tests++;
  			continue;
  		}
e44e0aa3c   Dan Williams   dmatest: add dma ...
699

4076e755d   Dan Williams   dmatest: convert ...
700
  		dmaengine_unmap_put(um);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
701

e3b9c3473   Dan Williams   dmatest: add supp...
702
  		if (params->noverify) {
50137a7df   Dan Williams   dmatest: verbose ...
703
704
  			verbose_result("test passed", total_tests, src_off,
  				       dst_off, len, 0);
e3b9c3473   Dan Williams   dmatest: add supp...
705
706
  			continue;
  		}
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
707

e9405ef08   Sinan Kaya   dmaengine: dmates...
708
  		start = ktime_get();
872f05c6e   Dan Williams   dmatest: replace ...
709
710
  		pr_debug("%s: verifying source buffer...
  ", current->comm);
e3b9c3473   Dan Williams   dmatest: add supp...
711
  		error_count = dmatest_verify(thread->srcs, 0, src_off,
61b5f54d8   Sinan Kaya   dmaengine: dmates...
712
  				0, PATTERN_SRC, true, is_memset);
7b6101782   Dan Williams   Revert "dmatest: ...
713
714
  		error_count += dmatest_verify(thread->srcs, src_off,
  				src_off + len, src_off,
61b5f54d8   Sinan Kaya   dmaengine: dmates...
715
  				PATTERN_SRC | PATTERN_COPY, true, is_memset);
7b6101782   Dan Williams   Revert "dmatest: ...
716
717
  		error_count += dmatest_verify(thread->srcs, src_off + len,
  				params->buf_size, src_off + len,
61b5f54d8   Sinan Kaya   dmaengine: dmates...
718
  				PATTERN_SRC, true, is_memset);
7b6101782   Dan Williams   Revert "dmatest: ...
719

872f05c6e   Dan Williams   dmatest: replace ...
720
721
  		pr_debug("%s: verifying dest buffer...
  ", current->comm);
7b6101782   Dan Williams   Revert "dmatest: ...
722
  		error_count += dmatest_verify(thread->dsts, 0, dst_off,
61b5f54d8   Sinan Kaya   dmaengine: dmates...
723
  				0, PATTERN_DST, false, is_memset);
7b6101782   Dan Williams   Revert "dmatest: ...
724
725
  		error_count += dmatest_verify(thread->dsts, dst_off,
  				dst_off + len, src_off,
61b5f54d8   Sinan Kaya   dmaengine: dmates...
726
  				PATTERN_SRC | PATTERN_COPY, false, is_memset);
7b6101782   Dan Williams   Revert "dmatest: ...
727
728
  		error_count += dmatest_verify(thread->dsts, dst_off + len,
  				params->buf_size, dst_off + len,
61b5f54d8   Sinan Kaya   dmaengine: dmates...
729
  				PATTERN_DST, false, is_memset);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
730

e9405ef08   Sinan Kaya   dmaengine: dmates...
731
732
  		diff = ktime_sub(ktime_get(), start);
  		comparetime = ktime_add(comparetime, diff);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
733
  		if (error_count) {
872f05c6e   Dan Williams   dmatest: replace ...
734
735
  			result("data error", total_tests, src_off, dst_off,
  			       len, error_count);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
736
737
  			failed_tests++;
  		} else {
50137a7df   Dan Williams   dmatest: verbose ...
738
739
  			verbose_result("test passed", total_tests, src_off,
  				       dst_off, len, 0);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
740
741
  		}
  	}
e9405ef08   Sinan Kaya   dmaengine: dmates...
742
743
744
745
  	ktime = ktime_sub(ktime_get(), ktime);
  	ktime = ktime_sub(ktime, comparetime);
  	ktime = ktime_sub(ktime, filltime);
  	runtime = ktime_to_us(ktime);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
746
747
  
  	ret = 0;
8e1f50d74   Andy Shevchenko   dmatest: prevent ...
748
  err_dstbuf:
d64816086   Dave Jiang   dmaengine: dmates...
749
750
751
752
  	for (i = 0; thread->udsts[i]; i++)
  		kfree(thread->udsts[i]);
  	kfree(thread->udsts);
  err_udsts:
b54d5cb91   Dan Williams   dmatest: add xor ...
753
754
  	kfree(thread->dsts);
  err_dsts:
8e1f50d74   Andy Shevchenko   dmatest: prevent ...
755
  err_srcbuf:
d64816086   Dave Jiang   dmaengine: dmates...
756
757
758
759
  	for (i = 0; thread->usrcs[i]; i++)
  		kfree(thread->usrcs[i]);
  	kfree(thread->usrcs);
  err_usrcs:
b54d5cb91   Dan Williams   dmatest: add xor ...
760
761
  	kfree(thread->srcs);
  err_srcs:
945b5af3c   Andy Shevchenko   dmatest: allocate...
762
763
  	kfree(pq_coefs);
  err_thread_type:
86727443a   Dan Williams   dmatest: add basi...
764
765
766
767
768
  	pr_info("%s: summary %u tests, %u failures %llu iops %llu KB/s (%d)
  ",
  		current->comm, total_tests, failed_tests,
  		dmatest_persec(runtime, total_tests),
  		dmatest_KBs(runtime, total_len), ret);
0a2ff57d6   Nicolas Ferre   dmaengine: dmates...
769

9704efaa5   Viresh Kumar   dmaengine/dmatest...
770
  	/* terminate all transfers on specified channels */
0aa5d007b   Adam Wallis   dmaengine: dmates...
771
  	if (ret || failed_tests)
5e034f7b6   Shiraz Hashim   dmaengine/dmatest...
772
  		dmaengine_terminate_all(chan);
3e5ccd866   Andy Shevchenko   dmatest: return a...
773
  	thread->done = true;
2d88ce76e   Dan Williams   dmatest: add a 'w...
774
  	wake_up(&thread_wait);
0a2ff57d6   Nicolas Ferre   dmaengine: dmates...
775

4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
776
777
778
779
780
781
782
783
784
785
786
  	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   Dan Williams   dmatest: cleanup ...
787
788
789
  		pr_debug("thread %s exited with status %d
  ",
  			 thread->task->comm, ret);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
790
  		list_del(&thread->node);
2d88ce76e   Dan Williams   dmatest: add a 'w...
791
  		put_task_struct(thread->task);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
792
793
  		kfree(thread);
  	}
9704efaa5   Viresh Kumar   dmaengine/dmatest...
794
795
  
  	/* terminate all transfers on specified channels */
944ea4dd3   Jon Mason   dmatest: Fix NULL...
796
  	dmaengine_terminate_all(dtc->chan);
9704efaa5   Viresh Kumar   dmaengine/dmatest...
797

4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
798
799
  	kfree(dtc);
  }
e03e93a97   Andy Shevchenko   dmatest: create d...
800
801
  static int dmatest_add_threads(struct dmatest_info *info,
  		struct dmatest_chan *dtc, enum dma_transaction_type type)
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
802
  {
15b8a8ea1   Andy Shevchenko   dmatest: split te...
803
  	struct dmatest_params *params = &info->params;
b54d5cb91   Dan Williams   dmatest: add xor ...
804
805
806
807
  	struct dmatest_thread *thread;
  	struct dma_chan *chan = dtc->chan;
  	char *op;
  	unsigned int i;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
808

b54d5cb91   Dan Williams   dmatest: add xor ...
809
810
  	if (type == DMA_MEMCPY)
  		op = "copy";
61b5f54d8   Sinan Kaya   dmaengine: dmates...
811
812
  	else if (type == DMA_MEMSET)
  		op = "set";
b54d5cb91   Dan Williams   dmatest: add xor ...
813
814
  	else if (type == DMA_XOR)
  		op = "xor";
58691d64c   Dan Williams   dmatest: add pq s...
815
816
  	else if (type == DMA_PQ)
  		op = "pq";
b54d5cb91   Dan Williams   dmatest: add xor ...
817
818
  	else
  		return -EINVAL;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
819

15b8a8ea1   Andy Shevchenko   dmatest: split te...
820
  	for (i = 0; i < params->threads_per_chan; i++) {
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
821
822
  		thread = kzalloc(sizeof(struct dmatest_thread), GFP_KERNEL);
  		if (!thread) {
0adff8006   Dan Williams   dmatest: cleanup ...
823
824
825
  			pr_warn("No memory for %s-%s%u
  ",
  				dma_chan_name(chan), op, i);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
826
827
  			break;
  		}
e03e93a97   Andy Shevchenko   dmatest: create d...
828
  		thread->info = info;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
829
  		thread->chan = dtc->chan;
b54d5cb91   Dan Williams   dmatest: add xor ...
830
  		thread->type = type;
0aa5d007b   Adam Wallis   dmaengine: dmates...
831
832
  		thread->test_done.wait = &thread->done_wait;
  		init_waitqueue_head(&thread->done_wait);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
833
  		smp_wmb();
2d88ce76e   Dan Williams   dmatest: add a 'w...
834
  		thread->task = kthread_create(dmatest_func, thread, "%s-%s%u",
b54d5cb91   Dan Williams   dmatest: add xor ...
835
  				dma_chan_name(chan), op, i);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
836
  		if (IS_ERR(thread->task)) {
2d88ce76e   Dan Williams   dmatest: add a 'w...
837
838
  			pr_warn("Failed to create thread %s-%s%u
  ",
0adff8006   Dan Williams   dmatest: cleanup ...
839
  				dma_chan_name(chan), op, i);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
840
841
842
843
844
  			kfree(thread);
  			break;
  		}
  
  		/* srcbuf and dstbuf are allocated by the thread itself */
2d88ce76e   Dan Williams   dmatest: add a 'w...
845
  		get_task_struct(thread->task);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
846
  		list_add_tail(&thread->node, &dtc->threads);
2d88ce76e   Dan Williams   dmatest: add a 'w...
847
  		wake_up_process(thread->task);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
848
  	}
b54d5cb91   Dan Williams   dmatest: add xor ...
849
850
  	return i;
  }
e03e93a97   Andy Shevchenko   dmatest: create d...
851
852
  static int dmatest_add_channel(struct dmatest_info *info,
  		struct dma_chan *chan)
b54d5cb91   Dan Williams   dmatest: add xor ...
853
854
855
856
  {
  	struct dmatest_chan	*dtc;
  	struct dma_device	*dma_dev = chan->device;
  	unsigned int		thread_count = 0;
b9033e682   Kulikov Vasiliy   dma: dmatest: fix...
857
  	int cnt;
b54d5cb91   Dan Williams   dmatest: add xor ...
858
859
860
  
  	dtc = kmalloc(sizeof(struct dmatest_chan), GFP_KERNEL);
  	if (!dtc) {
0adff8006   Dan Williams   dmatest: cleanup ...
861
862
  		pr_warn("No memory for %s
  ", dma_chan_name(chan));
b54d5cb91   Dan Williams   dmatest: add xor ...
863
864
865
866
867
868
869
  		return -ENOMEM;
  	}
  
  	dtc->chan = chan;
  	INIT_LIST_HEAD(&dtc->threads);
  
  	if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask)) {
a0d4cb44d   Kedareswara rao Appana   dmaengine: dmates...
870
871
872
873
  		if (dmatest == 0) {
  			cnt = dmatest_add_threads(info, dtc, DMA_MEMCPY);
  			thread_count += cnt > 0 ? cnt : 0;
  		}
b54d5cb91   Dan Williams   dmatest: add xor ...
874
  	}
a0d4cb44d   Kedareswara rao Appana   dmaengine: dmates...
875

61b5f54d8   Sinan Kaya   dmaengine: dmates...
876
  	if (dma_has_cap(DMA_MEMSET, dma_dev->cap_mask)) {
a0d4cb44d   Kedareswara rao Appana   dmaengine: dmates...
877
  		if (dmatest == 1) {
c678fa663   Dave Jiang   dmaengine: remove...
878
  			cnt = dmatest_add_threads(info, dtc, DMA_MEMSET);
a0d4cb44d   Kedareswara rao Appana   dmaengine: dmates...
879
880
881
  			thread_count += cnt > 0 ? cnt : 0;
  		}
  	}
b54d5cb91   Dan Williams   dmatest: add xor ...
882
  	if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) {
e03e93a97   Andy Shevchenko   dmatest: create d...
883
  		cnt = dmatest_add_threads(info, dtc, DMA_XOR);
f1aef8b6e   Nicolas Ferre   dmaengine: dmates...
884
  		thread_count += cnt > 0 ? cnt : 0;
b54d5cb91   Dan Williams   dmatest: add xor ...
885
  	}
58691d64c   Dan Williams   dmatest: add pq s...
886
  	if (dma_has_cap(DMA_PQ, dma_dev->cap_mask)) {
e03e93a97   Andy Shevchenko   dmatest: create d...
887
  		cnt = dmatest_add_threads(info, dtc, DMA_PQ);
d07a74a54   Dr. David Alan Gilbert   dmaengine: fix mi...
888
  		thread_count += cnt > 0 ? cnt : 0;
58691d64c   Dan Williams   dmatest: add pq s...
889
  	}
b54d5cb91   Dan Williams   dmatest: add xor ...
890

0adff8006   Dan Williams   dmatest: cleanup ...
891
892
  	pr_info("Started %u threads using %s
  ",
b54d5cb91   Dan Williams   dmatest: add xor ...
893
  		thread_count, dma_chan_name(chan));
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
894

838cc704c   Andy Shevchenko   dmatest: move dma...
895
896
  	list_add_tail(&dtc->node, &info->channels);
  	info->nr_channels++;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
897

33df8ca06   Dan Williams   dmatest: convert ...
898
  	return 0;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
899
  }
7dd602510   Dan Williams   dmaengine: kill e...
900
  static bool filter(struct dma_chan *chan, void *param)
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
901
  {
15b8a8ea1   Andy Shevchenko   dmatest: split te...
902
  	struct dmatest_params *params = param;
e03e93a97   Andy Shevchenko   dmatest: create d...
903

15b8a8ea1   Andy Shevchenko   dmatest: split te...
904
905
  	if (!dmatest_match_channel(params, chan) ||
  	    !dmatest_match_device(params, chan->device))
7dd602510   Dan Williams   dmaengine: kill e...
906
  		return false;
33df8ca06   Dan Williams   dmatest: convert ...
907
  	else
7dd602510   Dan Williams   dmaengine: kill e...
908
  		return true;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
909
  }
a9e554957   Dan Williams   dmatest: support ...
910
911
  static void request_channels(struct dmatest_info *info,
  			     enum dma_transaction_type type)
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
912
  {
33df8ca06   Dan Williams   dmatest: convert ...
913
  	dma_cap_mask_t mask;
33df8ca06   Dan Williams   dmatest: convert ...
914
915
  
  	dma_cap_zero(mask);
a9e554957   Dan Williams   dmatest: support ...
916
  	dma_cap_set(type, mask);
33df8ca06   Dan Williams   dmatest: convert ...
917
  	for (;;) {
a9e554957   Dan Williams   dmatest: support ...
918
919
  		struct dmatest_params *params = &info->params;
  		struct dma_chan *chan;
15b8a8ea1   Andy Shevchenko   dmatest: split te...
920
  		chan = dma_request_channel(mask, filter, params);
33df8ca06   Dan Williams   dmatest: convert ...
921
  		if (chan) {
a9e554957   Dan Williams   dmatest: support ...
922
  			if (dmatest_add_channel(info, chan)) {
33df8ca06   Dan Williams   dmatest: convert ...
923
924
925
926
927
  				dma_release_channel(chan);
  				break; /* add_channel failed, punt */
  			}
  		} else
  			break; /* no more channels available */
15b8a8ea1   Andy Shevchenko   dmatest: split te...
928
929
  		if (params->max_channels &&
  		    info->nr_channels >= params->max_channels)
33df8ca06   Dan Williams   dmatest: convert ...
930
931
  			break; /* we have all we need */
  	}
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
932
  }
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
933

a9e554957   Dan Williams   dmatest: support ...
934
  static void run_threaded_test(struct dmatest_info *info)
851b7e16a   Andy Shevchenko   dmatest: run test...
935
  {
a9e554957   Dan Williams   dmatest: support ...
936
  	struct dmatest_params *params = &info->params;
851b7e16a   Andy Shevchenko   dmatest: run test...
937

a9e554957   Dan Williams   dmatest: support ...
938
939
940
941
942
943
944
945
946
947
  	/* 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   Dan Williams   dmatest: add supp...
948
  	params->noverify = noverify;
a9e554957   Dan Williams   dmatest: support ...
949
950
  
  	request_channels(info, DMA_MEMCPY);
61b5f54d8   Sinan Kaya   dmaengine: dmates...
951
  	request_channels(info, DMA_MEMSET);
a9e554957   Dan Williams   dmatest: support ...
952
953
  	request_channels(info, DMA_XOR);
  	request_channels(info, DMA_PQ);
851b7e16a   Andy Shevchenko   dmatest: run test...
954
  }
851b7e16a   Andy Shevchenko   dmatest: run test...
955

a310d037b   Dan Williams   dmatest: restore ...
956
  static void stop_threaded_test(struct dmatest_info *info)
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
957
  {
33df8ca06   Dan Williams   dmatest: convert ...
958
  	struct dmatest_chan *dtc, *_dtc;
7cbd4877e   Dan Williams   dmatest: fix use ...
959
  	struct dma_chan *chan;
33df8ca06   Dan Williams   dmatest: convert ...
960

838cc704c   Andy Shevchenko   dmatest: move dma...
961
  	list_for_each_entry_safe(dtc, _dtc, &info->channels, node) {
33df8ca06   Dan Williams   dmatest: convert ...
962
  		list_del(&dtc->node);
7cbd4877e   Dan Williams   dmatest: fix use ...
963
  		chan = dtc->chan;
33df8ca06   Dan Williams   dmatest: convert ...
964
  		dmatest_cleanup_channel(dtc);
0adff8006   Dan Williams   dmatest: cleanup ...
965
966
  		pr_debug("dropped channel %s
  ", dma_chan_name(chan));
7cbd4877e   Dan Williams   dmatest: fix use ...
967
  		dma_release_channel(chan);
33df8ca06   Dan Williams   dmatest: convert ...
968
  	}
838cc704c   Andy Shevchenko   dmatest: move dma...
969
970
  
  	info->nr_channels = 0;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
971
  }
e03e93a97   Andy Shevchenko   dmatest: create d...
972

a9e554957   Dan Williams   dmatest: support ...
973
  static void restart_threaded_test(struct dmatest_info *info, bool run)
851b7e16a   Andy Shevchenko   dmatest: run test...
974
  {
a310d037b   Dan Williams   dmatest: restore ...
975
976
977
978
  	/* we might be called early to set run=, defer running until all
  	 * parameters have been evaluated
  	 */
  	if (!info->did_init)
a9e554957   Dan Williams   dmatest: support ...
979
  		return;
851b7e16a   Andy Shevchenko   dmatest: run test...
980
981
  
  	/* Stop any running test first */
a310d037b   Dan Williams   dmatest: restore ...
982
  	stop_threaded_test(info);
851b7e16a   Andy Shevchenko   dmatest: run test...
983
984
  
  	/* Run test with new parameters */
a9e554957   Dan Williams   dmatest: support ...
985
  	run_threaded_test(info);
851b7e16a   Andy Shevchenko   dmatest: run test...
986
  }
a310d037b   Dan Williams   dmatest: restore ...
987
  static int dmatest_run_get(char *val, const struct kernel_param *kp)
851b7e16a   Andy Shevchenko   dmatest: run test...
988
  {
a310d037b   Dan Williams   dmatest: restore ...
989
  	struct dmatest_info *info = &test_info;
851b7e16a   Andy Shevchenko   dmatest: run test...
990
991
  
  	mutex_lock(&info->lock);
a310d037b   Dan Williams   dmatest: restore ...
992
993
  	if (is_threaded_test_run(info)) {
  		dmatest_run = true;
3e5ccd866   Andy Shevchenko   dmatest: return a...
994
  	} else {
a310d037b   Dan Williams   dmatest: restore ...
995
996
  		stop_threaded_test(info);
  		dmatest_run = false;
3e5ccd866   Andy Shevchenko   dmatest: return a...
997
  	}
851b7e16a   Andy Shevchenko   dmatest: run test...
998
  	mutex_unlock(&info->lock);
851b7e16a   Andy Shevchenko   dmatest: run test...
999

a310d037b   Dan Williams   dmatest: restore ...
1000
  	return param_get_bool(val, kp);
851b7e16a   Andy Shevchenko   dmatest: run test...
1001
  }
a310d037b   Dan Williams   dmatest: restore ...
1002
  static int dmatest_run_set(const char *val, const struct kernel_param *kp)
95019c8c5   Andy Shevchenko   dmatest: gather t...
1003
  {
a310d037b   Dan Williams   dmatest: restore ...
1004
1005
  	struct dmatest_info *info = &test_info;
  	int ret;
95019c8c5   Andy Shevchenko   dmatest: gather t...
1006

a310d037b   Dan Williams   dmatest: restore ...
1007
1008
1009
  	mutex_lock(&info->lock);
  	ret = param_set_bool(val, kp);
  	if (ret) {
851b7e16a   Andy Shevchenko   dmatest: run test...
1010
  		mutex_unlock(&info->lock);
a310d037b   Dan Williams   dmatest: restore ...
1011
  		return ret;
95019c8c5   Andy Shevchenko   dmatest: gather t...
1012
  	}
a310d037b   Dan Williams   dmatest: restore ...
1013
1014
1015
  	if (is_threaded_test_run(info))
  		ret = -EBUSY;
  	else if (dmatest_run)
a9e554957   Dan Williams   dmatest: support ...
1016
  		restart_threaded_test(info, dmatest_run);
851b7e16a   Andy Shevchenko   dmatest: run test...
1017

a310d037b   Dan Williams   dmatest: restore ...
1018
  	mutex_unlock(&info->lock);
851b7e16a   Andy Shevchenko   dmatest: run test...
1019

a310d037b   Dan Williams   dmatest: restore ...
1020
  	return ret;
851b7e16a   Andy Shevchenko   dmatest: run test...
1021
  }
e03e93a97   Andy Shevchenko   dmatest: create d...
1022
1023
1024
  static int __init dmatest_init(void)
  {
  	struct dmatest_info *info = &test_info;
2d88ce76e   Dan Williams   dmatest: add a 'w...
1025
  	struct dmatest_params *params = &info->params;
e03e93a97   Andy Shevchenko   dmatest: create d...
1026

a310d037b   Dan Williams   dmatest: restore ...
1027
1028
  	if (dmatest_run) {
  		mutex_lock(&info->lock);
a9e554957   Dan Williams   dmatest: support ...
1029
  		run_threaded_test(info);
a310d037b   Dan Williams   dmatest: restore ...
1030
1031
  		mutex_unlock(&info->lock);
  	}
838cc704c   Andy Shevchenko   dmatest: move dma...
1032

2d88ce76e   Dan Williams   dmatest: add a 'w...
1033
1034
  	if (params->iterations && wait)
  		wait_event(thread_wait, !is_threaded_test_run(info));
95019c8c5   Andy Shevchenko   dmatest: gather t...
1035

a310d037b   Dan Williams   dmatest: restore ...
1036
1037
1038
1039
  	/* module parameters are stable, inittime tests are started,
  	 * let userspace take over 'run' control
  	 */
  	info->did_init = true;
851b7e16a   Andy Shevchenko   dmatest: run test...
1040

851b7e16a   Andy Shevchenko   dmatest: run test...
1041
  	return 0;
e03e93a97   Andy Shevchenko   dmatest: create d...
1042
1043
1044
1045
1046
1047
1048
  }
  /* 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   Dan Williams   dmatest: restore ...
1049
  	mutex_lock(&info->lock);
e03e93a97   Andy Shevchenko   dmatest: create d...
1050
  	stop_threaded_test(info);
a310d037b   Dan Williams   dmatest: restore ...
1051
  	mutex_unlock(&info->lock);
e03e93a97   Andy Shevchenko   dmatest: create d...
1052
  }
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
1053
  module_exit(dmatest_exit);
e05503ef1   Jean Delvare   Haavard Skinnemoe...
1054
  MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
1055
  MODULE_LICENSE("GPL v2");