Blame view

drivers/dma/dmatest.c 34.1 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
2
3
4
5
  /*
   * DMA Engine test module
   *
   * Copyright (C) 2007 Atmel Corporation
851b7e16a   Andy Shevchenko   dmatest: run test...
6
   * Copyright (C) 2013 Intel Corporation
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
7
   */
872f05c6e   Dan Williams   dmatest: replace ...
8
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
9
  #include <linux/delay.h>
b7f080cfe   Alexey Dobriyan   net: remove mm.h ...
10
  #include <linux/dma-mapping.h>
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
11
  #include <linux/dmaengine.h>
981ed70d8   Guennadi Liakhovetski   dmatest: make dma...
12
  #include <linux/freezer.h>
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
13
14
  #include <linux/init.h>
  #include <linux/kthread.h>
0881e7bd3   Ingo Molnar   sched/headers: Pr...
15
  #include <linux/sched/task.h>
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
16
17
18
  #include <linux/module.h>
  #include <linux/moduleparam.h>
  #include <linux/random.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
19
  #include <linux/slab.h>
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
20
21
22
  #include <linux/wait.h>
  
  static unsigned int test_buf_size = 16384;
a6c268d03   Andy Shevchenko   dmatest: make mod...
23
  module_param(test_buf_size, uint, S_IRUGO | S_IWUSR);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
24
  MODULE_PARM_DESC(test_buf_size, "Size of the memcpy test buffer");
a85159fec   Guennadi Liakhovetski   DMA: dmatest: ext...
25
  static char test_device[32];
a6c268d03   Andy Shevchenko   dmatest: make mod...
26
27
  module_param_string(device, test_device, sizeof(test_device),
  		S_IRUGO | S_IWUSR);
4a776f0aa   Haavard Skinnemoen   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   Andy Shevchenko   dmatest: make mod...
31
  module_param(threads_per_chan, uint, S_IRUGO | S_IWUSR);
4a776f0aa   Haavard Skinnemoen   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   Andy Shevchenko   dmatest: make mod...
36
  module_param(max_channels, uint, S_IRUGO | S_IWUSR);
33df8ca06   Dan Williams   dmatest: convert ...
37
  MODULE_PARM_DESC(max_channels,
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
38
  		"Maximum number of channels to use (default: all)");
0a2ff57d6   Nicolas Ferre   dmaengine: dmates...
39
  static unsigned int iterations;
a6c268d03   Andy Shevchenko   dmatest: make mod...
40
  module_param(iterations, uint, S_IRUGO | S_IWUSR);
0a2ff57d6   Nicolas Ferre   dmaengine: dmates...
41
42
  MODULE_PARM_DESC(iterations,
  		"Iterations before stopping test (default: infinite)");
d86467249   Eugeniy Paltsev   dmaengine: dmates...
43
  static unsigned int dmatest;
a0d4cb44d   Kedareswara rao Appana   dmaengine: dmates...
44
45
  module_param(dmatest, uint, S_IRUGO | S_IWUSR);
  MODULE_PARM_DESC(dmatest,
c678fa663   Dave Jiang   dmaengine: remove...
46
  		"dmatest 0-memcpy 1-memset (default: 0)");
a0d4cb44d   Kedareswara rao Appana   dmaengine: dmates...
47

b54d5cb91   Dan Williams   dmatest: add xor ...
48
  static unsigned int xor_sources = 3;
a6c268d03   Andy Shevchenko   dmatest: make mod...
49
  module_param(xor_sources, uint, S_IRUGO | S_IWUSR);
b54d5cb91   Dan Williams   dmatest: add xor ...
50
51
  MODULE_PARM_DESC(xor_sources,
  		"Number of xor source buffers (default: 3)");
58691d64c   Dan Williams   dmatest: add pq s...
52
  static unsigned int pq_sources = 3;
a6c268d03   Andy Shevchenko   dmatest: make mod...
53
  module_param(pq_sources, uint, S_IRUGO | S_IWUSR);
58691d64c   Dan Williams   dmatest: add pq s...
54
55
  MODULE_PARM_DESC(pq_sources,
  		"Number of p+q source buffers (default: 3)");
d42efe6bf   Viresh Kumar   dmaengine/dmatest...
56
  static int timeout = 3000;
a6c268d03   Andy Shevchenko   dmatest: make mod...
57
  module_param(timeout, uint, S_IRUGO | S_IWUSR);
85ee7a1d3   Joe Perches   treewide: cleanup...
58
  MODULE_PARM_DESC(timeout, "Transfer Timeout in msec (default: 3000), "
ed04b7c57   Hook, Gary   dmaengine: dmates...
59
  		 "Pass 0xFFFFFFFF (4294967295) for maximum timeout");
d42efe6bf   Viresh Kumar   dmaengine/dmatest...
60

e3b9c3473   Dan Williams   dmatest: add supp...
61
62
  static bool noverify;
  module_param(noverify, bool, S_IRUGO | S_IWUSR);
2e67a0875   Yang Shunyong   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   Haavard Skinnemoen   dmatest: Simple D...
68

fb9816f9d   Peter Ujfalusi   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   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

a875abfad   Seraj Alijan   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   Seraj Alijan   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   Andy Shevchenko   dmatest: create d...
82
  /**
15b8a8ea1   Andy Shevchenko   dmatest: split te...
83
   * struct dmatest_params - test parameters.
e03e93a97   Andy Shevchenko   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   Hook, Gary   dmaengine: dmates...
92
   * @timeout:		transfer timeout in msec, 0 - 0xFFFFFFFF (4294967295)
e03e93a97   Andy Shevchenko   dmatest: create d...
93
   */
15b8a8ea1   Andy Shevchenko   dmatest: split te...
94
  struct dmatest_params {
e03e93a97   Andy Shevchenko   dmatest: create d...
95
96
  	unsigned int	buf_size;
  	char		channel[20];
a85159fec   Guennadi Liakhovetski   DMA: dmatest: ext...
97
  	char		device[32];
e03e93a97   Andy Shevchenko   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   Hook, Gary   dmaengine: dmates...
103
  	unsigned int	timeout;
e3b9c3473   Dan Williams   dmatest: add supp...
104
  	bool		noverify;
2e67a0875   Yang Shunyong   dmaengine: dmates...
105
  	bool		norandom;
a875abfad   Seraj Alijan   dmaengine: dmates...
106
  	int		alignment;
13396a130   Seraj Alijan   dmaengine: dmates...
107
  	unsigned int	transfer_size;
fb9816f9d   Peter Ujfalusi   dmaengine: dmates...
108
  	bool		polled;
15b8a8ea1   Andy Shevchenko   dmatest: split te...
109
110
111
112
113
  };
  
  /**
   * struct dmatest_info - test information.
   * @params:		test parameters
851b7e16a   Andy Shevchenko   dmatest: run test...
114
   * @lock:		access protection to the fields of this structure
15b8a8ea1   Andy Shevchenko   dmatest: split te...
115
   */
a310d037b   Dan Williams   dmatest: restore ...
116
  static struct dmatest_info {
15b8a8ea1   Andy Shevchenko   dmatest: split te...
117
118
  	/* Test parameters */
  	struct dmatest_params	params;
838cc704c   Andy Shevchenko   dmatest: move dma...
119
120
121
122
  
  	/* Internal state */
  	struct list_head	channels;
  	unsigned int		nr_channels;
851b7e16a   Andy Shevchenko   dmatest: run test...
123
  	struct mutex		lock;
a310d037b   Dan Williams   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   Andy Shevchenko   dmatest: run test...
129

a310d037b   Dan Williams   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   Luis R. Rodriguez   kernel/params: co...
132
  static const struct kernel_param_ops run_ops = {
a310d037b   Dan Williams   dmatest: restore ...
133
134
  	.set = dmatest_run_set,
  	.get = dmatest_run_get,
e03e93a97   Andy Shevchenko   dmatest: create d...
135
  };
a310d037b   Dan Williams   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   Andy Shevchenko   dmatest: create d...
139

d53513d5d   Seraj Alijan   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   Dan Williams   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   Sinan Kaya   dmaengine: dmates...
180
  #define PATTERN_MEMSET_IDX	0x01
851b7e16a   Andy Shevchenko   dmatest: run test...
181

6138f967b   Seraj Alijan   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   Adam Wallis   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   Alexandru Ardelean   dmaengine: dmates...
193
194
195
196
197
198
  struct dmatest_data {
  	u8		**raw;
  	u8		**aligned;
  	unsigned int	cnt;
  	unsigned int	off;
  };
a310d037b   Dan Williams   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   Alexandru Ardelean   dmaengine: dmates...
204
205
  	struct dmatest_data	src;
  	struct dmatest_data	dst;
a310d037b   Dan Williams   dmatest: restore ...
206
  	enum dma_transaction_type type;
6f6a23a21   Adam Wallis   dmaengine: dmates...
207
208
  	wait_queue_head_t done_wait;
  	struct dmatest_done test_done;
a310d037b   Dan Williams   dmatest: restore ...
209
  	bool			done;
d53513d5d   Seraj Alijan   dmaengine: dmates...
210
  	bool			pending;
a310d037b   Dan Williams   dmatest: restore ...
211
  };
95019c8c5   Andy Shevchenko   dmatest: gather t...
212

a310d037b   Dan Williams   dmatest: restore ...
213
214
215
216
  struct dmatest_chan {
  	struct list_head	node;
  	struct dma_chan		*chan;
  	struct list_head	threads;
e03e93a97   Andy Shevchenko   dmatest: create d...
217
  };
2d88ce76e   Dan Williams   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   Seraj Alijan   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   Dan Williams   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   Luis R. Rodriguez   kernel/params: co...
261
  static const struct kernel_param_ops wait_ops = {
2d88ce76e   Dan Williams   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   Andy Shevchenko   dmatest: create d...
267

15b8a8ea1   Andy Shevchenko   dmatest: split te...
268
  static bool dmatest_match_channel(struct dmatest_params *params,
e03e93a97   Andy Shevchenko   dmatest: create d...
269
  		struct dma_chan *chan)
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
270
  {
15b8a8ea1   Andy Shevchenko   dmatest: split te...
271
  	if (params->channel[0] == '\0')
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
272
  		return true;
15b8a8ea1   Andy Shevchenko   dmatest: split te...
273
  	return strcmp(dma_chan_name(chan), params->channel) == 0;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
274
  }
15b8a8ea1   Andy Shevchenko   dmatest: split te...
275
  static bool dmatest_match_device(struct dmatest_params *params,
e03e93a97   Andy Shevchenko   dmatest: create d...
276
  		struct dma_device *device)
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
277
  {
15b8a8ea1   Andy Shevchenko   dmatest: split te...
278
  	if (params->device[0] == '\0')
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
279
  		return true;
15b8a8ea1   Andy Shevchenko   dmatest: split te...
280
  	return strcmp(dev_name(device->dev), params->device) == 0;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
281
282
283
284
285
  }
  
  static unsigned long dmatest_random(void)
  {
  	unsigned long buf;
be9fa5a43   Dan Williams   dmatest: use pseu...
286
  	prandom_bytes(&buf, sizeof(buf));
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
287
288
  	return buf;
  }
61b5f54d8   Sinan Kaya   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   Andy Shevchenko   dmatest: create d...
305
  static void dmatest_init_srcs(u8 **bufs, unsigned int start, unsigned int len,
61b5f54d8   Sinan Kaya   dmaengine: dmates...
306
  		unsigned int buf_size, bool is_memset)
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
307
308
  {
  	unsigned int i;
b54d5cb91   Dan Williams   dmatest: add xor ...
309
310
311
312
  	u8 *buf;
  
  	for (; (buf = *bufs); bufs++) {
  		for (i = 0; i < start; i++)
61b5f54d8   Sinan Kaya   dmaengine: dmates...
313
  			buf[i] = gen_src_value(i, is_memset);
b54d5cb91   Dan Williams   dmatest: add xor ...
314
  		for ( ; i < start + len; i++)
61b5f54d8   Sinan Kaya   dmaengine: dmates...
315
  			buf[i] = gen_src_value(i, is_memset) | PATTERN_COPY;
e03e93a97   Andy Shevchenko   dmatest: create d...
316
  		for ( ; i < buf_size; i++)
61b5f54d8   Sinan Kaya   dmaengine: dmates...
317
  			buf[i] = gen_src_value(i, is_memset);
b54d5cb91   Dan Williams   dmatest: add xor ...
318
319
  		buf++;
  	}
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
320
  }
e03e93a97   Andy Shevchenko   dmatest: create d...
321
  static void dmatest_init_dsts(u8 **bufs, unsigned int start, unsigned int len,
61b5f54d8   Sinan Kaya   dmaengine: dmates...
322
  		unsigned int buf_size, bool is_memset)
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
323
324
  {
  	unsigned int i;
b54d5cb91   Dan Williams   dmatest: add xor ...
325
326
327
328
  	u8 *buf;
  
  	for (; (buf = *bufs); bufs++) {
  		for (i = 0; i < start; i++)
61b5f54d8   Sinan Kaya   dmaengine: dmates...
329
  			buf[i] = gen_dst_value(i, is_memset);
b54d5cb91   Dan Williams   dmatest: add xor ...
330
  		for ( ; i < start + len; i++)
61b5f54d8   Sinan Kaya   dmaengine: dmates...
331
332
  			buf[i] = gen_dst_value(i, is_memset) |
  						PATTERN_OVERWRITE;
e03e93a97   Andy Shevchenko   dmatest: create d...
333
  		for ( ; i < buf_size; i++)
61b5f54d8   Sinan Kaya   dmaengine: dmates...
334
  			buf[i] = gen_dst_value(i, is_memset);
b54d5cb91   Dan Williams   dmatest: add xor ...
335
  	}
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
336
  }
7b6101782   Dan Williams   Revert "dmatest: ...
337
  static void dmatest_mismatch(u8 actual, u8 pattern, unsigned int index,
61b5f54d8   Sinan Kaya   dmaengine: dmates...
338
  		unsigned int counter, bool is_srcbuf, bool is_memset)
7b6101782   Dan Williams   Revert "dmatest: ...
339
340
  {
  	u8		diff = actual ^ pattern;
61b5f54d8   Sinan Kaya   dmaengine: dmates...
341
  	u8		expected = pattern | gen_inv_idx(counter, is_memset);
7b6101782   Dan Williams   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   Sinan Kaya   dmaengine: dmates...
365
  		bool is_srcbuf, bool is_memset)
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
366
367
368
369
  {
  	unsigned int i;
  	unsigned int error_count = 0;
  	u8 actual;
b54d5cb91   Dan Williams   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   Sinan Kaya   dmaengine: dmates...
378
  			expected = pattern | gen_inv_idx(counter, is_memset);
b54d5cb91   Dan Williams   dmatest: add xor ...
379
  			if (actual != expected) {
7b6101782   Dan Williams   Revert "dmatest: ...
380
381
  				if (error_count < MAX_ERROR_COUNT)
  					dmatest_mismatch(actual, pattern, i,
61b5f54d8   Sinan Kaya   dmaengine: dmates...
382
383
  							 counter, is_srcbuf,
  							 is_memset);
b54d5cb91   Dan Williams   dmatest: add xor ...
384
385
386
  				error_count++;
  			}
  			counter++;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
387
  		}
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
388
  	}
74b5c07a5   Andy Shevchenko   dmatest: define M...
389
  	if (error_count > MAX_ERROR_COUNT)
7b6101782   Dan Williams   Revert "dmatest: ...
390
391
  		pr_warn("%s: %u errors suppressed
  ",
74b5c07a5   Andy Shevchenko   dmatest: define M...
392
  			current->comm, error_count - MAX_ERROR_COUNT);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
393
394
395
  
  	return error_count;
  }
adfa543e7   Tejun Heo   dmatest: don't us...
396
397
  
  static void dmatest_callback(void *arg)
e44e0aa3c   Dan Williams   dmatest: add dma ...
398
  {
adfa543e7   Tejun Heo   dmatest: don't us...
399
  	struct dmatest_done *done = arg;
6f6a23a21   Adam Wallis   dmaengine: dmates...
400
  	struct dmatest_thread *thread =
66b3bd235   Yang Shunyong   dmaengine: dmates...
401
  		container_of(done, struct dmatest_thread, test_done);
6f6a23a21   Adam Wallis   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   Dan Williams   dmatest: add dma ...
416
  }
8be9e32b3   Akinobu Mita   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   Dan Williams   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   Andy Shevchenko   dmatest: append v...
425
  {
2acec1503   Jerome Blin   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   Dan Williams   dmatest: replace ...
428
  		current->comm, n, err, src_off, dst_off, len, data);
d86b2f298   Andy Shevchenko   dmatest: append v...
429
  }
872f05c6e   Dan Williams   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   Andy Shevchenko   dmatest: gather t...
433
  {
2acec1503   Jerome Blin   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   Andy Shevchenko   dmatest: fix inde...
436
  		 current->comm, n, err, src_off, dst_off, len, data);
95019c8c5   Andy Shevchenko   dmatest: gather t...
437
  }
a835bb855   Andy Shevchenko   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   Dan Williams   dmatest: verbose ...
443
  })
95019c8c5   Andy Shevchenko   dmatest: gather t...
444

86727443a   Dan Williams   dmatest: add basi...
445
  static unsigned long long dmatest_persec(s64 runtime, unsigned int val)
d86b2f298   Andy Shevchenko   dmatest: append v...
446
  {
86727443a   Dan Williams   dmatest: add basi...
447
  	unsigned long long per_sec = 1000000;
d86b2f298   Andy Shevchenko   dmatest: append v...
448

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

86727443a   Dan Williams   dmatest: add basi...
452
453
454
455
  	/* drop precision until runtime is 32-bits */
  	while (runtime > UINT_MAX) {
  		runtime >>= 1;
  		per_sec <<= 1;
95019c8c5   Andy Shevchenko   dmatest: gather t...
456
  	}
86727443a   Dan Williams   dmatest: add basi...
457
  	per_sec *= val;
6138f967b   Seraj Alijan   dmaengine: dmates...
458
  	per_sec = INT_TO_FIXPT(per_sec);
86727443a   Dan Williams   dmatest: add basi...
459
  	do_div(per_sec, runtime);
6138f967b   Seraj Alijan   dmaengine: dmates...
460

86727443a   Dan Williams   dmatest: add basi...
461
  	return per_sec;
95019c8c5   Andy Shevchenko   dmatest: gather t...
462
  }
86727443a   Dan Williams   dmatest: add basi...
463
  static unsigned long long dmatest_KBs(s64 runtime, unsigned long long len)
95019c8c5   Andy Shevchenko   dmatest: gather t...
464
  {
6138f967b   Seraj Alijan   dmaengine: dmates...
465
  	return FIXPT_TO_INT(dmatest_persec(runtime, len >> 10));
95019c8c5   Andy Shevchenko   dmatest: gather t...
466
  }
3b6679f91   Alexandru Ardelean   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   Haavard Skinnemoen   dmatest: Simple D...
513
514
  /*
   * This function repeatedly tests DMA transfers of various lengths and
b54d5cb91   Dan Williams   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   Haavard Skinnemoen   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   Adam Wallis   dmaengine: dmates...
530
  	struct dmatest_done	*done = &thread->test_done;
e03e93a97   Andy Shevchenko   dmatest: create d...
531
  	struct dmatest_info	*info;
15b8a8ea1   Andy Shevchenko   dmatest: split te...
532
  	struct dmatest_params	*params;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
533
  	struct dma_chan		*chan;
8be9e32b3   Akinobu Mita   dmatest: adjust i...
534
  	struct dma_device	*dev;
4a776f0aa   Haavard Skinnemoen   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   Dan Williams   dmatest: add xor ...
540
  	enum dma_ctrl_flags 	flags;
945b5af3c   Andy Shevchenko   dmatest: allocate...
541
  	u8			*pq_coefs = NULL;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
542
  	int			ret;
41d00bb7a   Alexandru Ardelean   dmaengine: dmates...
543
  	unsigned int 		buf_size;
361deb724   Alexandru Ardelean   dmaengine: dmates...
544
545
  	struct dmatest_data	*src;
  	struct dmatest_data	*dst;
b54d5cb91   Dan Williams   dmatest: add xor ...
546
  	int			i;
e9405ef08   Sinan Kaya   dmaengine: dmates...
547
  	ktime_t			ktime, start, diff;
8b0e19531   Thomas Gleixner   ktime: Cleanup kt...
548
549
  	ktime_t			filltime = 0;
  	ktime_t			comparetime = 0;
86727443a   Dan Williams   dmatest: add basi...
550
551
  	s64			runtime = 0;
  	unsigned long long	total_len = 0;
6138f967b   Seraj Alijan   dmaengine: dmates...
552
  	unsigned long long	iops = 0;
d64816086   Dave Jiang   dmaengine: dmates...
553
  	u8			align = 0;
61b5f54d8   Sinan Kaya   dmaengine: dmates...
554
  	bool			is_memset = false;
72ef08bf6   Laura Abbott   dmaengine: dmates...
555
556
  	dma_addr_t		*srcs;
  	dma_addr_t		*dma_pq;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
557

adfa543e7   Tejun Heo   dmatest: don't us...
558
  	set_freezable();
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
559
560
  
  	ret = -ENOMEM;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
561
562
  
  	smp_rmb();
d53513d5d   Seraj Alijan   dmaengine: dmates...
563
  	thread->pending = false;
e03e93a97   Andy Shevchenko   dmatest: create d...
564
  	info = thread->info;
15b8a8ea1   Andy Shevchenko   dmatest: split te...
565
  	params = &info->params;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
566
  	chan = thread->chan;
8be9e32b3   Akinobu Mita   dmatest: adjust i...
567
  	dev = chan->device;
361deb724   Alexandru Ardelean   dmaengine: dmates...
568
569
  	src = &thread->src;
  	dst = &thread->dst;
d64816086   Dave Jiang   dmaengine: dmates...
570
  	if (thread->type == DMA_MEMCPY) {
a875abfad   Seraj Alijan   dmaengine: dmates...
571
572
  		align = params->alignment < 0 ? dev->copy_align :
  						params->alignment;
361deb724   Alexandru Ardelean   dmaengine: dmates...
573
  		src->cnt = dst->cnt = 1;
61b5f54d8   Sinan Kaya   dmaengine: dmates...
574
  	} else if (thread->type == DMA_MEMSET) {
a875abfad   Seraj Alijan   dmaengine: dmates...
575
576
  		align = params->alignment < 0 ? dev->fill_align :
  						params->alignment;
361deb724   Alexandru Ardelean   dmaengine: dmates...
577
  		src->cnt = dst->cnt = 1;
61b5f54d8   Sinan Kaya   dmaengine: dmates...
578
  		is_memset = true;
d64816086   Dave Jiang   dmaengine: dmates...
579
  	} else if (thread->type == DMA_XOR) {
8be9e32b3   Akinobu Mita   dmatest: adjust i...
580
  		/* force odd to ensure dst = src */
361deb724   Alexandru Ardelean   dmaengine: dmates...
581
582
  		src->cnt = min_odd(params->xor_sources | 1, dev->max_xor);
  		dst->cnt = 1;
a875abfad   Seraj Alijan   dmaengine: dmates...
583
584
  		align = params->alignment < 0 ? dev->xor_align :
  						params->alignment;
58691d64c   Dan Williams   dmatest: add pq s...
585
  	} else if (thread->type == DMA_PQ) {
8be9e32b3   Akinobu Mita   dmatest: adjust i...
586
  		/* force odd to ensure dst = src */
361deb724   Alexandru Ardelean   dmaengine: dmates...
587
588
  		src->cnt = min_odd(params->pq_sources | 1, dma_maxpq(dev, 0));
  		dst->cnt = 2;
a875abfad   Seraj Alijan   dmaengine: dmates...
589
590
  		align = params->alignment < 0 ? dev->pq_align :
  						params->alignment;
945b5af3c   Andy Shevchenko   dmatest: allocate...
591

31d182574   Dave Jiang   dmaengine: fix sp...
592
  		pq_coefs = kmalloc(params->pq_sources + 1, GFP_KERNEL);
945b5af3c   Andy Shevchenko   dmatest: allocate...
593
594
  		if (!pq_coefs)
  			goto err_thread_type;
361deb724   Alexandru Ardelean   dmaengine: dmates...
595
  		for (i = 0; i < src->cnt; i++)
58691d64c   Dan Williams   dmatest: add pq s...
596
  			pq_coefs[i] = 1;
b54d5cb91   Dan Williams   dmatest: add xor ...
597
  	} else
945b5af3c   Andy Shevchenko   dmatest: allocate...
598
  		goto err_thread_type;
b54d5cb91   Dan Williams   dmatest: add xor ...
599

787d3083c   Alexandru Ardelean   dmaengine: dmates...
600
  	/* Check if buffer count fits into map count variable (u8) */
361deb724   Alexandru Ardelean   dmaengine: dmates...
601
  	if ((src->cnt + dst->cnt) >= 255) {
787d3083c   Alexandru Ardelean   dmaengine: dmates...
602
603
  		pr_err("too many buffers (%d of 255 supported)
  ",
361deb724   Alexandru Ardelean   dmaengine: dmates...
604
  		       src->cnt + dst->cnt);
3f3c75541   Dan Carpenter   dmaengine: dmates...
605
  		goto err_free_coefs;
787d3083c   Alexandru Ardelean   dmaengine: dmates...
606
  	}
41d00bb7a   Alexandru Ardelean   dmaengine: dmates...
607
608
  	buf_size = params->buf_size;
  	if (1 << align > buf_size) {
787d3083c   Alexandru Ardelean   dmaengine: dmates...
609
610
  		pr_err("%u-byte buffer too small for %d-byte alignment
  ",
41d00bb7a   Alexandru Ardelean   dmaengine: dmates...
611
  		       buf_size, 1 << align);
3f3c75541   Dan Carpenter   dmaengine: dmates...
612
  		goto err_free_coefs;
787d3083c   Alexandru Ardelean   dmaengine: dmates...
613
  	}
3b6679f91   Alexandru Ardelean   dmaengine: dmates...
614
  	if (dmatest_alloc_test_data(src, buf_size, align) < 0)
3f3c75541   Dan Carpenter   dmaengine: dmates...
615
  		goto err_free_coefs;
d64816086   Dave Jiang   dmaengine: dmates...
616

3b6679f91   Alexandru Ardelean   dmaengine: dmates...
617
618
  	if (dmatest_alloc_test_data(dst, buf_size, align) < 0)
  		goto err_src;
b54d5cb91   Dan Williams   dmatest: add xor ...
619

e44e0aa3c   Dan Williams   dmatest: add dma ...
620
  	set_user_nice(current, 10);
361deb724   Alexandru Ardelean   dmaengine: dmates...
621
  	srcs = kcalloc(src->cnt, sizeof(dma_addr_t), GFP_KERNEL);
72ef08bf6   Laura Abbott   dmaengine: dmates...
622
  	if (!srcs)
3b6679f91   Alexandru Ardelean   dmaengine: dmates...
623
  		goto err_dst;
72ef08bf6   Laura Abbott   dmaengine: dmates...
624

361deb724   Alexandru Ardelean   dmaengine: dmates...
625
  	dma_pq = kcalloc(dst->cnt, sizeof(dma_addr_t), GFP_KERNEL);
72ef08bf6   Laura Abbott   dmaengine: dmates...
626
627
  	if (!dma_pq)
  		goto err_srcs_array;
b203bd3f6   Ira Snyder   dmatest: fix auto...
628
  	/*
d1cab34c0   Bartlomiej Zolnierkiewicz   dmatest: make dri...
629
  	 * src and dst buffers are freed by ourselves below
b203bd3f6   Ira Snyder   dmatest: fix auto...
630
  	 */
fb9816f9d   Peter Ujfalusi   dmaengine: dmates...
631
632
633
634
  	if (params->polled)
  		flags = DMA_CTRL_ACK;
  	else
  		flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
635

86727443a   Dan Williams   dmatest: add basi...
636
  	ktime = ktime_get();
0a2ff57d6   Nicolas Ferre   dmaengine: dmates...
637
  	while (!kthread_should_stop()
15b8a8ea1   Andy Shevchenko   dmatest: split te...
638
  	       && !(params->iterations && total_tests >= params->iterations)) {
b54d5cb91   Dan Williams   dmatest: add xor ...
639
  		struct dma_async_tx_descriptor *tx = NULL;
4076e755d   Dan Williams   dmatest: convert ...
640
  		struct dmaengine_unmap_data *um;
4076e755d   Dan Williams   dmatest: convert ...
641
  		dma_addr_t *dsts;
361deb724   Alexandru Ardelean   dmaengine: dmates...
642
  		unsigned int len;
d86be86e9   Atsushi Nemoto   dmatest: Use cust...
643

4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
644
  		total_tests++;
13396a130   Seraj Alijan   dmaengine: dmates...
645
  		if (params->transfer_size) {
41d00bb7a   Alexandru Ardelean   dmaengine: dmates...
646
  			if (params->transfer_size >= buf_size) {
13396a130   Seraj Alijan   dmaengine: dmates...
647
648
  				pr_err("%u-byte transfer size must be lower than %u-buffer size
  ",
41d00bb7a   Alexandru Ardelean   dmaengine: dmates...
649
  				       params->transfer_size, buf_size);
13396a130   Seraj Alijan   dmaengine: dmates...
650
651
652
653
  				break;
  			}
  			len = params->transfer_size;
  		} else if (params->norandom) {
41d00bb7a   Alexandru Ardelean   dmaengine: dmates...
654
  			len = buf_size;
13396a130   Seraj Alijan   dmaengine: dmates...
655
  		} else {
41d00bb7a   Alexandru Ardelean   dmaengine: dmates...
656
  			len = dmatest_random() % buf_size + 1;
13396a130   Seraj Alijan   dmaengine: dmates...
657
  		}
ede23a586   Andy Shevchenko   dmatest: move src...
658

13396a130   Seraj Alijan   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   Andy Shevchenko   dmatest: move src...
665
  		total_len += len;
2e67a0875   Yang Shunyong   dmaengine: dmates...
666
  		if (params->norandom) {
361deb724   Alexandru Ardelean   dmaengine: dmates...
667
668
  			src->off = 0;
  			dst->off = 0;
e3b9c3473   Dan Williams   dmatest: add supp...
669
  		} else {
41d00bb7a   Alexandru Ardelean   dmaengine: dmates...
670
671
  			src->off = dmatest_random() % (buf_size - len + 1);
  			dst->off = dmatest_random() % (buf_size - len + 1);
e3b9c3473   Dan Williams   dmatest: add supp...
672

361deb724   Alexandru Ardelean   dmaengine: dmates...
673
674
  			src->off = (src->off >> align) << align;
  			dst->off = (dst->off >> align) << align;
2e67a0875   Yang Shunyong   dmaengine: dmates...
675
  		}
e3b9c3473   Dan Williams   dmatest: add supp...
676

2e67a0875   Yang Shunyong   dmaengine: dmates...
677
678
  		if (!params->noverify) {
  			start = ktime_get();
361deb724   Alexandru Ardelean   dmaengine: dmates...
679
  			dmatest_init_srcs(src->aligned, src->off, len,
41d00bb7a   Alexandru Ardelean   dmaengine: dmates...
680
  					  buf_size, is_memset);
361deb724   Alexandru Ardelean   dmaengine: dmates...
681
  			dmatest_init_dsts(dst->aligned, dst->off, len,
41d00bb7a   Alexandru Ardelean   dmaengine: dmates...
682
  					  buf_size, is_memset);
e9405ef08   Sinan Kaya   dmaengine: dmates...
683
684
685
  
  			diff = ktime_sub(ktime_get(), start);
  			filltime = ktime_add(filltime, diff);
e3b9c3473   Dan Williams   dmatest: add supp...
686
  		}
361deb724   Alexandru Ardelean   dmaengine: dmates...
687
  		um = dmaengine_get_unmap_data(dev->dev, src->cnt + dst->cnt,
4076e755d   Dan Williams   dmatest: convert ...
688
689
690
691
  					      GFP_KERNEL);
  		if (!um) {
  			failed_tests++;
  			result("unmap data NULL", total_tests,
361deb724   Alexandru Ardelean   dmaengine: dmates...
692
  			       src->off, dst->off, len, ret);
4076e755d   Dan Williams   dmatest: convert ...
693
694
  			continue;
  		}
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
695

41d00bb7a   Alexandru Ardelean   dmaengine: dmates...
696
  		um->len = buf_size;
361deb724   Alexandru Ardelean   dmaengine: dmates...
697
698
  		for (i = 0; i < src->cnt; i++) {
  			void *buf = src->aligned[i];
4076e755d   Dan Williams   dmatest: convert ...
699
  			struct page *pg = virt_to_page(buf);
f62e5f613   Geliang Tang   dmaengine: dmates...
700
  			unsigned long pg_off = offset_in_page(buf);
4076e755d   Dan Williams   dmatest: convert ...
701
702
703
  
  			um->addr[i] = dma_map_page(dev->dev, pg, pg_off,
  						   um->len, DMA_TO_DEVICE);
361deb724   Alexandru Ardelean   dmaengine: dmates...
704
  			srcs[i] = um->addr[i] + src->off;
4076e755d   Dan Williams   dmatest: convert ...
705
  			ret = dma_mapping_error(dev->dev, um->addr[i]);
afde3be12   Andy Shevchenko   dmatest: check fo...
706
  			if (ret) {
872f05c6e   Dan Williams   dmatest: replace ...
707
  				result("src mapping error", total_tests,
361deb724   Alexandru Ardelean   dmaengine: dmates...
708
  				       src->off, dst->off, len, ret);
6454368a8   Andy Shevchenko   dmaengine: dmates...
709
  				goto error_unmap_continue;
afde3be12   Andy Shevchenko   dmatest: check fo...
710
  			}
4076e755d   Dan Williams   dmatest: convert ...
711
  			um->to_cnt++;
b54d5cb91   Dan Williams   dmatest: add xor ...
712
  		}
d86be86e9   Atsushi Nemoto   dmatest: Use cust...
713
  		/* map with DMA_BIDIRECTIONAL to force writeback/invalidate */
361deb724   Alexandru Ardelean   dmaengine: dmates...
714
715
716
  		dsts = &um->addr[src->cnt];
  		for (i = 0; i < dst->cnt; i++) {
  			void *buf = dst->aligned[i];
4076e755d   Dan Williams   dmatest: convert ...
717
  			struct page *pg = virt_to_page(buf);
f62e5f613   Geliang Tang   dmaengine: dmates...
718
  			unsigned long pg_off = offset_in_page(buf);
4076e755d   Dan Williams   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   Andy Shevchenko   dmatest: check fo...
723
  			if (ret) {
872f05c6e   Dan Williams   dmatest: replace ...
724
  				result("dst mapping error", total_tests,
361deb724   Alexandru Ardelean   dmaengine: dmates...
725
  				       src->off, dst->off, len, ret);
6454368a8   Andy Shevchenko   dmaengine: dmates...
726
  				goto error_unmap_continue;
afde3be12   Andy Shevchenko   dmatest: check fo...
727
  			}
4076e755d   Dan Williams   dmatest: convert ...
728
  			um->bidi_cnt++;
b54d5cb91   Dan Williams   dmatest: add xor ...
729
730
731
732
  		}
  
  		if (thread->type == DMA_MEMCPY)
  			tx = dev->device_prep_dma_memcpy(chan,
361deb724   Alexandru Ardelean   dmaengine: dmates...
733
  							 dsts[0] + dst->off,
4076e755d   Dan Williams   dmatest: convert ...
734
  							 srcs[0], len, flags);
61b5f54d8   Sinan Kaya   dmaengine: dmates...
735
736
  		else if (thread->type == DMA_MEMSET)
  			tx = dev->device_prep_dma_memset(chan,
361deb724   Alexandru Ardelean   dmaengine: dmates...
737
738
  						dsts[0] + dst->off,
  						*(src->aligned[0] + src->off),
61b5f54d8   Sinan Kaya   dmaengine: dmates...
739
  						len, flags);
b54d5cb91   Dan Williams   dmatest: add xor ...
740
741
  		else if (thread->type == DMA_XOR)
  			tx = dev->device_prep_dma_xor(chan,
361deb724   Alexandru Ardelean   dmaengine: dmates...
742
743
  						      dsts[0] + dst->off,
  						      srcs, src->cnt,
b54d5cb91   Dan Williams   dmatest: add xor ...
744
  						      len, flags);
58691d64c   Dan Williams   dmatest: add pq s...
745
  		else if (thread->type == DMA_PQ) {
361deb724   Alexandru Ardelean   dmaengine: dmates...
746
747
  			for (i = 0; i < dst->cnt; i++)
  				dma_pq[i] = dsts[i] + dst->off;
4076e755d   Dan Williams   dmatest: convert ...
748
  			tx = dev->device_prep_dma_pq(chan, dma_pq, srcs,
361deb724   Alexandru Ardelean   dmaengine: dmates...
749
  						     src->cnt, pq_coefs,
58691d64c   Dan Williams   dmatest: add pq s...
750
751
  						     len, flags);
  		}
d86be86e9   Atsushi Nemoto   dmatest: Use cust...
752

d86be86e9   Atsushi Nemoto   dmatest: Use cust...
753
  		if (!tx) {
361deb724   Alexandru Ardelean   dmaengine: dmates...
754
755
  			result("prep error", total_tests, src->off,
  			       dst->off, len, ret);
d86be86e9   Atsushi Nemoto   dmatest: Use cust...
756
  			msleep(100);
6454368a8   Andy Shevchenko   dmaengine: dmates...
757
  			goto error_unmap_continue;
d86be86e9   Atsushi Nemoto   dmatest: Use cust...
758
  		}
e44e0aa3c   Dan Williams   dmatest: add dma ...
759

6f6a23a21   Adam Wallis   dmaengine: dmates...
760
  		done->done = false;
fb9816f9d   Peter Ujfalusi   dmaengine: dmates...
761
762
763
764
  		if (!params->polled) {
  			tx->callback = dmatest_callback;
  			tx->callback_param = done;
  		}
d86be86e9   Atsushi Nemoto   dmatest: Use cust...
765
  		cookie = tx->tx_submit(tx);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
766
  		if (dma_submit_error(cookie)) {
361deb724   Alexandru Ardelean   dmaengine: dmates...
767
768
  			result("submit error", total_tests, src->off,
  			       dst->off, len, ret);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
769
  			msleep(100);
6454368a8   Andy Shevchenko   dmaengine: dmates...
770
  			goto error_unmap_continue;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
771
  		}
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
772

fb9816f9d   Peter Ujfalusi   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   Guennadi Liakhovetski   dmatest: make dma...
784

fb9816f9d   Peter Ujfalusi   dmaengine: dmates...
785
786
787
  			status = dma_async_is_tx_complete(chan, cookie, NULL,
  							  NULL);
  		}
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
788

6f6a23a21   Adam Wallis   dmaengine: dmates...
789
  		if (!done->done) {
361deb724   Alexandru Ardelean   dmaengine: dmates...
790
  			result("test timed out", total_tests, src->off, dst->off,
872f05c6e   Dan Williams   dmatest: replace ...
791
  			       len, 0);
6454368a8   Andy Shevchenko   dmaengine: dmates...
792
  			goto error_unmap_continue;
19e9f99f2   Vinod Koul   dmaengine: dmates...
793
  		} else if (status != DMA_COMPLETE) {
872f05c6e   Dan Williams   dmatest: replace ...
794
795
  			result(status == DMA_ERROR ?
  			       "completion error status" :
361deb724   Alexandru Ardelean   dmaengine: dmates...
796
797
  			       "completion busy status", total_tests, src->off,
  			       dst->off, len, ret);
6454368a8   Andy Shevchenko   dmaengine: dmates...
798
  			goto error_unmap_continue;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
799
  		}
e44e0aa3c   Dan Williams   dmatest: add dma ...
800

6454368a8   Andy Shevchenko   dmaengine: dmates...
801
  		dmaengine_unmap_put(um);
e3b9c3473   Dan Williams   dmatest: add supp...
802
  		if (params->noverify) {
361deb724   Alexandru Ardelean   dmaengine: dmates...
803
804
  			verbose_result("test passed", total_tests, src->off,
  				       dst->off, len, 0);
e3b9c3473   Dan Williams   dmatest: add supp...
805
806
  			continue;
  		}
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
807

e9405ef08   Sinan Kaya   dmaengine: dmates...
808
  		start = ktime_get();
872f05c6e   Dan Williams   dmatest: replace ...
809
810
  		pr_debug("%s: verifying source buffer...
  ", current->comm);
361deb724   Alexandru Ardelean   dmaengine: dmates...
811
  		error_count = dmatest_verify(src->aligned, 0, src->off,
61b5f54d8   Sinan Kaya   dmaengine: dmates...
812
  				0, PATTERN_SRC, true, is_memset);
361deb724   Alexandru Ardelean   dmaengine: dmates...
813
814
  		error_count += dmatest_verify(src->aligned, src->off,
  				src->off + len, src->off,
61b5f54d8   Sinan Kaya   dmaengine: dmates...
815
  				PATTERN_SRC | PATTERN_COPY, true, is_memset);
361deb724   Alexandru Ardelean   dmaengine: dmates...
816
  		error_count += dmatest_verify(src->aligned, src->off + len,
41d00bb7a   Alexandru Ardelean   dmaengine: dmates...
817
  				buf_size, src->off + len,
61b5f54d8   Sinan Kaya   dmaengine: dmates...
818
  				PATTERN_SRC, true, is_memset);
7b6101782   Dan Williams   Revert "dmatest: ...
819

872f05c6e   Dan Williams   dmatest: replace ...
820
821
  		pr_debug("%s: verifying dest buffer...
  ", current->comm);
361deb724   Alexandru Ardelean   dmaengine: dmates...
822
  		error_count += dmatest_verify(dst->aligned, 0, dst->off,
61b5f54d8   Sinan Kaya   dmaengine: dmates...
823
  				0, PATTERN_DST, false, is_memset);
361deb724   Alexandru Ardelean   dmaengine: dmates...
824
825
  		error_count += dmatest_verify(dst->aligned, dst->off,
  				dst->off + len, src->off,
61b5f54d8   Sinan Kaya   dmaengine: dmates...
826
  				PATTERN_SRC | PATTERN_COPY, false, is_memset);
361deb724   Alexandru Ardelean   dmaengine: dmates...
827
  		error_count += dmatest_verify(dst->aligned, dst->off + len,
41d00bb7a   Alexandru Ardelean   dmaengine: dmates...
828
  				buf_size, dst->off + len,
61b5f54d8   Sinan Kaya   dmaengine: dmates...
829
  				PATTERN_DST, false, is_memset);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
830

e9405ef08   Sinan Kaya   dmaengine: dmates...
831
832
  		diff = ktime_sub(ktime_get(), start);
  		comparetime = ktime_add(comparetime, diff);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
833
  		if (error_count) {
361deb724   Alexandru Ardelean   dmaengine: dmates...
834
  			result("data error", total_tests, src->off, dst->off,
872f05c6e   Dan Williams   dmatest: replace ...
835
  			       len, error_count);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
836
837
  			failed_tests++;
  		} else {
361deb724   Alexandru Ardelean   dmaengine: dmates...
838
839
  			verbose_result("test passed", total_tests, src->off,
  				       dst->off, len, 0);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
840
  		}
6454368a8   Andy Shevchenko   dmaengine: dmates...
841
842
843
844
845
846
  
  		continue;
  
  error_unmap_continue:
  		dmaengine_unmap_put(um);
  		failed_tests++;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
847
  	}
e9405ef08   Sinan Kaya   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   Haavard Skinnemoen   dmatest: Simple D...
852
853
  
  	ret = 0;
72ef08bf6   Laura Abbott   dmaengine: dmates...
854
855
856
  	kfree(dma_pq);
  err_srcs_array:
  	kfree(srcs);
3b6679f91   Alexandru Ardelean   dmaengine: dmates...
857
858
859
860
  err_dst:
  	dmatest_free_test_data(dst);
  err_src:
  	dmatest_free_test_data(src);
3f3c75541   Dan Carpenter   dmaengine: dmates...
861
  err_free_coefs:
945b5af3c   Andy Shevchenko   dmatest: allocate...
862
863
  	kfree(pq_coefs);
  err_thread_type:
6138f967b   Seraj Alijan   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   Dan Williams   dmatest: add basi...
867
  		current->comm, total_tests, failed_tests,
6138f967b   Seraj Alijan   dmaengine: dmates...
868
  		FIXPT_TO_INT(iops), FIXPT_GET_FRAC(iops),
86727443a   Dan Williams   dmatest: add basi...
869
  		dmatest_KBs(runtime, total_len), ret);
0a2ff57d6   Nicolas Ferre   dmaengine: dmates...
870

9704efaa5   Viresh Kumar   dmaengine/dmatest...
871
  	/* terminate all transfers on specified channels */
6f6a23a21   Adam Wallis   dmaengine: dmates...
872
  	if (ret || failed_tests)
fbffb6b4d   Alexandru Ardelean   dmaengine: dmates...
873
  		dmaengine_terminate_sync(chan);
5e034f7b6   Shiraz Hashim   dmaengine/dmatest...
874

3e5ccd866   Andy Shevchenko   dmatest: return a...
875
  	thread->done = true;
2d88ce76e   Dan Williams   dmatest: add a 'w...
876
  	wake_up(&thread_wait);
0a2ff57d6   Nicolas Ferre   dmaengine: dmates...
877

4a776f0aa   Haavard Skinnemoen   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   Dan Williams   dmatest: cleanup ...
889
890
891
  		pr_debug("thread %s exited with status %d
  ",
  			 thread->task->comm, ret);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
892
  		list_del(&thread->node);
2d88ce76e   Dan Williams   dmatest: add a 'w...
893
  		put_task_struct(thread->task);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
894
895
  		kfree(thread);
  	}
9704efaa5   Viresh Kumar   dmaengine/dmatest...
896
897
  
  	/* terminate all transfers on specified channels */
fbffb6b4d   Alexandru Ardelean   dmaengine: dmates...
898
  	dmaengine_terminate_sync(dtc->chan);
9704efaa5   Viresh Kumar   dmaengine/dmatest...
899

4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
900
901
  	kfree(dtc);
  }
e03e93a97   Andy Shevchenko   dmatest: create d...
902
903
  static int dmatest_add_threads(struct dmatest_info *info,
  		struct dmatest_chan *dtc, enum dma_transaction_type type)
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
904
  {
15b8a8ea1   Andy Shevchenko   dmatest: split te...
905
  	struct dmatest_params *params = &info->params;
b54d5cb91   Dan Williams   dmatest: add xor ...
906
907
908
909
  	struct dmatest_thread *thread;
  	struct dma_chan *chan = dtc->chan;
  	char *op;
  	unsigned int i;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
910

b54d5cb91   Dan Williams   dmatest: add xor ...
911
912
  	if (type == DMA_MEMCPY)
  		op = "copy";
61b5f54d8   Sinan Kaya   dmaengine: dmates...
913
914
  	else if (type == DMA_MEMSET)
  		op = "set";
b54d5cb91   Dan Williams   dmatest: add xor ...
915
916
  	else if (type == DMA_XOR)
  		op = "xor";
58691d64c   Dan Williams   dmatest: add pq s...
917
918
  	else if (type == DMA_PQ)
  		op = "pq";
b54d5cb91   Dan Williams   dmatest: add xor ...
919
920
  	else
  		return -EINVAL;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
921

15b8a8ea1   Andy Shevchenko   dmatest: split te...
922
  	for (i = 0; i < params->threads_per_chan; i++) {
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
923
924
  		thread = kzalloc(sizeof(struct dmatest_thread), GFP_KERNEL);
  		if (!thread) {
0adff8006   Dan Williams   dmatest: cleanup ...
925
926
927
  			pr_warn("No memory for %s-%s%u
  ",
  				dma_chan_name(chan), op, i);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
928
929
  			break;
  		}
e03e93a97   Andy Shevchenko   dmatest: create d...
930
  		thread->info = info;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
931
  		thread->chan = dtc->chan;
b54d5cb91   Dan Williams   dmatest: add xor ...
932
  		thread->type = type;
6f6a23a21   Adam Wallis   dmaengine: dmates...
933
934
  		thread->test_done.wait = &thread->done_wait;
  		init_waitqueue_head(&thread->done_wait);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
935
  		smp_wmb();
2d88ce76e   Dan Williams   dmatest: add a 'w...
936
  		thread->task = kthread_create(dmatest_func, thread, "%s-%s%u",
b54d5cb91   Dan Williams   dmatest: add xor ...
937
  				dma_chan_name(chan), op, i);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
938
  		if (IS_ERR(thread->task)) {
2d88ce76e   Dan Williams   dmatest: add a 'w...
939
940
  			pr_warn("Failed to create thread %s-%s%u
  ",
0adff8006   Dan Williams   dmatest: cleanup ...
941
  				dma_chan_name(chan), op, i);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
942
943
944
945
946
  			kfree(thread);
  			break;
  		}
  
  		/* srcbuf and dstbuf are allocated by the thread itself */
2d88ce76e   Dan Williams   dmatest: add a 'w...
947
  		get_task_struct(thread->task);
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
948
  		list_add_tail(&thread->node, &dtc->threads);
d53513d5d   Seraj Alijan   dmaengine: dmates...
949
  		thread->pending = true;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
950
  	}
b54d5cb91   Dan Williams   dmatest: add xor ...
951
952
  	return i;
  }
e03e93a97   Andy Shevchenko   dmatest: create d...
953
954
  static int dmatest_add_channel(struct dmatest_info *info,
  		struct dma_chan *chan)
b54d5cb91   Dan Williams   dmatest: add xor ...
955
956
957
958
  {
  	struct dmatest_chan	*dtc;
  	struct dma_device	*dma_dev = chan->device;
  	unsigned int		thread_count = 0;
b9033e682   Kulikov Vasiliy   dma: dmatest: fix...
959
  	int cnt;
b54d5cb91   Dan Williams   dmatest: add xor ...
960
961
962
  
  	dtc = kmalloc(sizeof(struct dmatest_chan), GFP_KERNEL);
  	if (!dtc) {
0adff8006   Dan Williams   dmatest: cleanup ...
963
964
  		pr_warn("No memory for %s
  ", dma_chan_name(chan));
b54d5cb91   Dan Williams   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   Kedareswara rao Appana   dmaengine: dmates...
972
973
974
975
  		if (dmatest == 0) {
  			cnt = dmatest_add_threads(info, dtc, DMA_MEMCPY);
  			thread_count += cnt > 0 ? cnt : 0;
  		}
b54d5cb91   Dan Williams   dmatest: add xor ...
976
  	}
a0d4cb44d   Kedareswara rao Appana   dmaengine: dmates...
977

61b5f54d8   Sinan Kaya   dmaengine: dmates...
978
  	if (dma_has_cap(DMA_MEMSET, dma_dev->cap_mask)) {
a0d4cb44d   Kedareswara rao Appana   dmaengine: dmates...
979
  		if (dmatest == 1) {
c678fa663   Dave Jiang   dmaengine: remove...
980
  			cnt = dmatest_add_threads(info, dtc, DMA_MEMSET);
a0d4cb44d   Kedareswara rao Appana   dmaengine: dmates...
981
982
983
  			thread_count += cnt > 0 ? cnt : 0;
  		}
  	}
b54d5cb91   Dan Williams   dmatest: add xor ...
984
  	if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) {
e03e93a97   Andy Shevchenko   dmatest: create d...
985
  		cnt = dmatest_add_threads(info, dtc, DMA_XOR);
f1aef8b6e   Nicolas Ferre   dmaengine: dmates...
986
  		thread_count += cnt > 0 ? cnt : 0;
b54d5cb91   Dan Williams   dmatest: add xor ...
987
  	}
58691d64c   Dan Williams   dmatest: add pq s...
988
  	if (dma_has_cap(DMA_PQ, dma_dev->cap_mask)) {
e03e93a97   Andy Shevchenko   dmatest: create d...
989
  		cnt = dmatest_add_threads(info, dtc, DMA_PQ);
d07a74a54   Dr. David Alan Gilbert   dmaengine: fix mi...
990
  		thread_count += cnt > 0 ? cnt : 0;
58691d64c   Dan Williams   dmatest: add pq s...
991
  	}
b54d5cb91   Dan Williams   dmatest: add xor ...
992

d53513d5d   Seraj Alijan   dmaengine: dmates...
993
994
  	pr_info("Added %u threads using %s
  ",
b54d5cb91   Dan Williams   dmatest: add xor ...
995
  		thread_count, dma_chan_name(chan));
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
996

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

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

15b8a8ea1   Andy Shevchenko   dmatest: split te...
1006
1007
  	if (!dmatest_match_channel(params, chan) ||
  	    !dmatest_match_device(params, chan->device))
7dd602510   Dan Williams   dmaengine: kill e...
1008
  		return false;
33df8ca06   Dan Williams   dmatest: convert ...
1009
  	else
7dd602510   Dan Williams   dmaengine: kill e...
1010
  		return true;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
1011
  }
a9e554957   Dan Williams   dmatest: support ...
1012
1013
  static void request_channels(struct dmatest_info *info,
  			     enum dma_transaction_type type)
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
1014
  {
33df8ca06   Dan Williams   dmatest: convert ...
1015
  	dma_cap_mask_t mask;
33df8ca06   Dan Williams   dmatest: convert ...
1016
1017
  
  	dma_cap_zero(mask);
a9e554957   Dan Williams   dmatest: support ...
1018
  	dma_cap_set(type, mask);
33df8ca06   Dan Williams   dmatest: convert ...
1019
  	for (;;) {
a9e554957   Dan Williams   dmatest: support ...
1020
1021
  		struct dmatest_params *params = &info->params;
  		struct dma_chan *chan;
15b8a8ea1   Andy Shevchenko   dmatest: split te...
1022
  		chan = dma_request_channel(mask, filter, params);
33df8ca06   Dan Williams   dmatest: convert ...
1023
  		if (chan) {
a9e554957   Dan Williams   dmatest: support ...
1024
  			if (dmatest_add_channel(info, chan)) {
33df8ca06   Dan Williams   dmatest: convert ...
1025
1026
1027
1028
1029
  				dma_release_channel(chan);
  				break; /* add_channel failed, punt */
  			}
  		} else
  			break; /* no more channels available */
15b8a8ea1   Andy Shevchenko   dmatest: split te...
1030
1031
  		if (params->max_channels &&
  		    info->nr_channels >= params->max_channels)
33df8ca06   Dan Williams   dmatest: convert ...
1032
1033
  			break; /* we have all we need */
  	}
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
1034
  }
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
1035

d53513d5d   Seraj Alijan   dmaengine: dmates...
1036
  static void add_threaded_test(struct dmatest_info *info)
851b7e16a   Andy Shevchenko   dmatest: run test...
1037
  {
a9e554957   Dan Williams   dmatest: support ...
1038
  	struct dmatest_params *params = &info->params;
851b7e16a   Andy Shevchenko   dmatest: run test...
1039

a9e554957   Dan Williams   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   Dan Williams   dmatest: add supp...
1050
  	params->noverify = noverify;
2e67a0875   Yang Shunyong   dmaengine: dmates...
1051
  	params->norandom = norandom;
a875abfad   Seraj Alijan   dmaengine: dmates...
1052
  	params->alignment = alignment;
13396a130   Seraj Alijan   dmaengine: dmates...
1053
  	params->transfer_size = transfer_size;
fb9816f9d   Peter Ujfalusi   dmaengine: dmates...
1054
  	params->polled = polled;
a9e554957   Dan Williams   dmatest: support ...
1055
1056
  
  	request_channels(info, DMA_MEMCPY);
61b5f54d8   Sinan Kaya   dmaengine: dmates...
1057
  	request_channels(info, DMA_MEMSET);
a9e554957   Dan Williams   dmatest: support ...
1058
1059
  	request_channels(info, DMA_XOR);
  	request_channels(info, DMA_PQ);
851b7e16a   Andy Shevchenko   dmatest: run test...
1060
  }
851b7e16a   Andy Shevchenko   dmatest: run test...
1061

d53513d5d   Seraj Alijan   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   Dan Williams   dmatest: restore ...
1080
  static void stop_threaded_test(struct dmatest_info *info)
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
1081
  {
33df8ca06   Dan Williams   dmatest: convert ...
1082
  	struct dmatest_chan *dtc, *_dtc;
7cbd4877e   Dan Williams   dmatest: fix use ...
1083
  	struct dma_chan *chan;
33df8ca06   Dan Williams   dmatest: convert ...
1084

838cc704c   Andy Shevchenko   dmatest: move dma...
1085
  	list_for_each_entry_safe(dtc, _dtc, &info->channels, node) {
33df8ca06   Dan Williams   dmatest: convert ...
1086
  		list_del(&dtc->node);
7cbd4877e   Dan Williams   dmatest: fix use ...
1087
  		chan = dtc->chan;
33df8ca06   Dan Williams   dmatest: convert ...
1088
  		dmatest_cleanup_channel(dtc);
0adff8006   Dan Williams   dmatest: cleanup ...
1089
1090
  		pr_debug("dropped channel %s
  ", dma_chan_name(chan));
7cbd4877e   Dan Williams   dmatest: fix use ...
1091
  		dma_release_channel(chan);
33df8ca06   Dan Williams   dmatest: convert ...
1092
  	}
838cc704c   Andy Shevchenko   dmatest: move dma...
1093
1094
  
  	info->nr_channels = 0;
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
1095
  }
e03e93a97   Andy Shevchenko   dmatest: create d...
1096

d53513d5d   Seraj Alijan   dmaengine: dmates...
1097
  static void start_threaded_tests(struct dmatest_info *info)
851b7e16a   Andy Shevchenko   dmatest: run test...
1098
  {
a310d037b   Dan Williams   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   Dan Williams   dmatest: support ...
1103
  		return;
851b7e16a   Andy Shevchenko   dmatest: run test...
1104

d53513d5d   Seraj Alijan   dmaengine: dmates...
1105
  	run_pending_tests(info);
851b7e16a   Andy Shevchenko   dmatest: run test...
1106
  }
a310d037b   Dan Williams   dmatest: restore ...
1107
  static int dmatest_run_get(char *val, const struct kernel_param *kp)
851b7e16a   Andy Shevchenko   dmatest: run test...
1108
  {
a310d037b   Dan Williams   dmatest: restore ...
1109
  	struct dmatest_info *info = &test_info;
851b7e16a   Andy Shevchenko   dmatest: run test...
1110
1111
  
  	mutex_lock(&info->lock);
a310d037b   Dan Williams   dmatest: restore ...
1112
1113
  	if (is_threaded_test_run(info)) {
  		dmatest_run = true;
3e5ccd866   Andy Shevchenko   dmatest: return a...
1114
  	} else {
d53513d5d   Seraj Alijan   dmaengine: dmates...
1115
1116
  		if (!is_threaded_test_pending(info))
  			stop_threaded_test(info);
a310d037b   Dan Williams   dmatest: restore ...
1117
  		dmatest_run = false;
3e5ccd866   Andy Shevchenko   dmatest: return a...
1118
  	}
851b7e16a   Andy Shevchenko   dmatest: run test...
1119
  	mutex_unlock(&info->lock);
851b7e16a   Andy Shevchenko   dmatest: run test...
1120

a310d037b   Dan Williams   dmatest: restore ...
1121
  	return param_get_bool(val, kp);
851b7e16a   Andy Shevchenko   dmatest: run test...
1122
  }
a310d037b   Dan Williams   dmatest: restore ...
1123
  static int dmatest_run_set(const char *val, const struct kernel_param *kp)
95019c8c5   Andy Shevchenko   dmatest: gather t...
1124
  {
a310d037b   Dan Williams   dmatest: restore ...
1125
1126
  	struct dmatest_info *info = &test_info;
  	int ret;
95019c8c5   Andy Shevchenko   dmatest: gather t...
1127

a310d037b   Dan Williams   dmatest: restore ...
1128
1129
1130
  	mutex_lock(&info->lock);
  	ret = param_set_bool(val, kp);
  	if (ret) {
851b7e16a   Andy Shevchenko   dmatest: run test...
1131
  		mutex_unlock(&info->lock);
a310d037b   Dan Williams   dmatest: restore ...
1132
  		return ret;
d53513d5d   Seraj Alijan   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   Andy Shevchenko   dmatest: gather t...
1179
  	}
d53513d5d   Seraj Alijan   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   Dan Williams   dmatest: restore ...
1203
  		ret = -EBUSY;
d53513d5d   Seraj Alijan   dmaengine: dmates...
1204
1205
1206
1207
1208
1209
  		goto add_chan_err;
  	}
  
  	mutex_unlock(&info->lock);
  
  	return ret;
851b7e16a   Andy Shevchenko   dmatest: run test...
1210

d53513d5d   Seraj Alijan   dmaengine: dmates...
1211
1212
  add_chan_err:
  	param_set_copystring(chan_reset_val, kp);
a310d037b   Dan Williams   dmatest: restore ...
1213
  	mutex_unlock(&info->lock);
851b7e16a   Andy Shevchenko   dmatest: run test...
1214

a310d037b   Dan Williams   dmatest: restore ...
1215
  	return ret;
851b7e16a   Andy Shevchenko   dmatest: run test...
1216
  }
d53513d5d   Seraj Alijan   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   Andy Shevchenko   dmatest: create d...
1251
1252
1253
  static int __init dmatest_init(void)
  {
  	struct dmatest_info *info = &test_info;
2d88ce76e   Dan Williams   dmatest: add a 'w...
1254
  	struct dmatest_params *params = &info->params;
e03e93a97   Andy Shevchenko   dmatest: create d...
1255

a310d037b   Dan Williams   dmatest: restore ...
1256
1257
  	if (dmatest_run) {
  		mutex_lock(&info->lock);
d53513d5d   Seraj Alijan   dmaengine: dmates...
1258
1259
  		add_threaded_test(info);
  		run_pending_tests(info);
a310d037b   Dan Williams   dmatest: restore ...
1260
1261
  		mutex_unlock(&info->lock);
  	}
838cc704c   Andy Shevchenko   dmatest: move dma...
1262

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

a310d037b   Dan Williams   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   Andy Shevchenko   dmatest: run test...
1270

851b7e16a   Andy Shevchenko   dmatest: run test...
1271
  	return 0;
e03e93a97   Andy Shevchenko   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   Dan Williams   dmatest: restore ...
1279
  	mutex_lock(&info->lock);
e03e93a97   Andy Shevchenko   dmatest: create d...
1280
  	stop_threaded_test(info);
a310d037b   Dan Williams   dmatest: restore ...
1281
  	mutex_unlock(&info->lock);
e03e93a97   Andy Shevchenko   dmatest: create d...
1282
  }
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
1283
  module_exit(dmatest_exit);
e05503ef1   Jean Delvare   Haavard Skinnemoe...
1284
  MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
4a776f0aa   Haavard Skinnemoen   dmatest: Simple D...
1285
  MODULE_LICENSE("GPL v2");