[go: nahoru, domu]

dmatest.c revision 872f05c6e9a37e9358fd58eb54deee7337863496
14a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen/*
24a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen * DMA Engine test module
34a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen *
44a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen * Copyright (C) 2007 Atmel Corporation
5851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenko * Copyright (C) 2013 Intel Corporation
64a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen *
74a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen * This program is free software; you can redistribute it and/or modify
84a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen * it under the terms of the GNU General Public License version 2 as
94a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen * published by the Free Software Foundation.
104a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen */
11872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams
134a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen#include <linux/delay.h>
14b7f080cfe223b3b7424872639d153695615a9255Alexey Dobriyan#include <linux/dma-mapping.h>
154a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen#include <linux/dmaengine.h>
16981ed70d8e4faf3689dbf3c48868a31d5b004d7aGuennadi Liakhovetski#include <linux/freezer.h>
174a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen#include <linux/init.h>
184a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen#include <linux/kthread.h>
194a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen#include <linux/module.h>
204a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen#include <linux/moduleparam.h>
214a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen#include <linux/random.h>
225a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
234a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen#include <linux/wait.h>
244a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen#include <linux/ctype.h>
254a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen#include <linux/debugfs.h>
26a6c268d033b1f363e0d76c0483a0f99266542820Andy Shevchenko#include <linux/uaccess.h>
274a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen#include <linux/seq_file.h>
284a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen
2906190d8415219d9eef7d8f04b52a109e34575a76Kay Sieversstatic unsigned int test_buf_size = 16384;
30a6c268d033b1f363e0d76c0483a0f99266542820Andy Shevchenkomodule_param(test_buf_size, uint, S_IRUGO | S_IWUSR);
31a6c268d033b1f363e0d76c0483a0f99266542820Andy ShevchenkoMODULE_PARM_DESC(test_buf_size, "Size of the memcpy test buffer");
324a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen
334a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoenstatic char test_channel[20];
3406190d8415219d9eef7d8f04b52a109e34575a76Kay Sieversmodule_param_string(channel, test_channel, sizeof(test_channel),
35a6c268d033b1f363e0d76c0483a0f99266542820Andy Shevchenko		S_IRUGO | S_IWUSR);
36a6c268d033b1f363e0d76c0483a0f99266542820Andy ShevchenkoMODULE_PARM_DESC(channel, "Bus ID of the channel to test (default: any)");
374a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen
384a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoenstatic char test_device[20];
394a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoenmodule_param_string(device, test_device, sizeof(test_device),
40a6c268d033b1f363e0d76c0483a0f99266542820Andy Shevchenko		S_IRUGO | S_IWUSR);
414a776f0aa922a552460192c07b56f4fe9cd82632Haavard SkinnemoenMODULE_PARM_DESC(device, "Bus ID of the DMA Engine to test (default: any)");
424a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen
434a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoenstatic unsigned int threads_per_chan = 1;
444a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoenmodule_param(threads_per_chan, uint, S_IRUGO | S_IWUSR);
45a6c268d033b1f363e0d76c0483a0f99266542820Andy ShevchenkoMODULE_PARM_DESC(threads_per_chan,
4633df8ca068123457db56c316946a3c0e4ef787d6Dan Williams		"Number of threads to start per channel (default: 1)");
474a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen
484a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoenstatic unsigned int max_channels;
490a2ff57d6fba92842272889b4bca447344cd9d36Nicolas Ferremodule_param(max_channels, uint, S_IRUGO | S_IWUSR);
50a6c268d033b1f363e0d76c0483a0f99266542820Andy ShevchenkoMODULE_PARM_DESC(max_channels,
510a2ff57d6fba92842272889b4bca447344cd9d36Nicolas Ferre		"Maximum number of channels to use (default: all)");
520a2ff57d6fba92842272889b4bca447344cd9d36Nicolas Ferre
530a2ff57d6fba92842272889b4bca447344cd9d36Nicolas Ferrestatic unsigned int iterations;
54b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williamsmodule_param(iterations, uint, S_IRUGO | S_IWUSR);
55a6c268d033b1f363e0d76c0483a0f99266542820Andy ShevchenkoMODULE_PARM_DESC(iterations,
56b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		"Iterations before stopping test (default: infinite)");
57b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams
58b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williamsstatic unsigned int xor_sources = 3;
5958691d64c44ae41ddf098ecb31e9a994026e3cffDan Williamsmodule_param(xor_sources, uint, S_IRUGO | S_IWUSR);
60a6c268d033b1f363e0d76c0483a0f99266542820Andy ShevchenkoMODULE_PARM_DESC(xor_sources,
6158691d64c44ae41ddf098ecb31e9a994026e3cffDan Williams		"Number of xor source buffers (default: 3)");
6258691d64c44ae41ddf098ecb31e9a994026e3cffDan Williams
6358691d64c44ae41ddf098ecb31e9a994026e3cffDan Williamsstatic unsigned int pq_sources = 3;
64d42efe6bfb4eed8314c8ce3547f21954a4140399Viresh Kumarmodule_param(pq_sources, uint, S_IRUGO | S_IWUSR);
65a6c268d033b1f363e0d76c0483a0f99266542820Andy ShevchenkoMODULE_PARM_DESC(pq_sources,
6685ee7a1d39d75d23d21f3871f6dc9b87d572747aJoe Perches		"Number of p+q source buffers (default: 3)");
6785ee7a1d39d75d23d21f3871f6dc9b87d572747aJoe Perches
68d42efe6bfb4eed8314c8ce3547f21954a4140399Viresh Kumarstatic int timeout = 3000;
69e3b9c347316fe243bea6abd08681050c43ca22eeDan Williamsmodule_param(timeout, uint, S_IRUGO | S_IWUSR);
70e3b9c347316fe243bea6abd08681050c43ca22eeDan WilliamsMODULE_PARM_DESC(timeout, "Transfer Timeout in msec (default: 3000), "
71e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams		 "Pass -1 for infinite timeout");
72e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams
73e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko/* Maximum amount of mismatched bytes in buffer to print */
7415b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko#define MAX_ERROR_COUNT		32
75e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko
76e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko/*
77e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko * Initialization patterns. All bytes in the source buffer has bit 7
78e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko * set, all bytes in the destination buffer has bit 7 cleared.
79e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko *
80e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko * Bit 6 is set for all bytes which are to be copied by the DMA
81e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko * engine. Bit 5 is set for all bytes which are to be overwritten by
82e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko * the DMA engine.
83e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko *
84e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko * The remaining bits are the inverse of a counter which increments by
8515b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko * one for each byte address.
86e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko */
87e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko#define PATTERN_SRC		0x80
88e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko#define PATTERN_DST		0x00
89e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko#define PATTERN_COPY		0x40
90e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko#define PATTERN_OVERWRITE	0x20
91e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko#define PATTERN_COUNT_MASK	0x1f
92e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko
93e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenkostruct dmatest_info;
94e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko
95e3b9c347316fe243bea6abd08681050c43ca22eeDan Williamsstruct dmatest_thread {
9615b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko	struct list_head	node;
9715b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko	struct dmatest_info	*info;
9815b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko	struct task_struct	*task;
9915b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko	struct dma_chan		*chan;
10015b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko	u8			**srcs;
101851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenko	u8			**dsts;
10215b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko	enum dma_transaction_type type;
103a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	bool			done;
10415b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko};
10515b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko
106838cc704ce5c8ab2a6d64d1324e37e040fcae3d8Andy Shevchenkostruct dmatest_chan {
107838cc704ce5c8ab2a6d64d1324e37e040fcae3d8Andy Shevchenko	struct list_head	node;
108838cc704ce5c8ab2a6d64d1324e37e040fcae3d8Andy Shevchenko	struct dma_chan		*chan;
109838cc704ce5c8ab2a6d64d1324e37e040fcae3d8Andy Shevchenko	struct list_head	threads;
110851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenko};
111a310d037b8d06755c62bb4878c00d19490af5550Dan Williams
112a310d037b8d06755c62bb4878c00d19490af5550Dan Williams/**
113a310d037b8d06755c62bb4878c00d19490af5550Dan Williams * struct dmatest_params - test parameters.
114a310d037b8d06755c62bb4878c00d19490af5550Dan Williams * @buf_size:		size of the memcpy test buffer
115a310d037b8d06755c62bb4878c00d19490af5550Dan Williams * @channel:		bus ID of the channel to test
116851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenko * @device:		bus ID of the DMA Engine to test
117a310d037b8d06755c62bb4878c00d19490af5550Dan Williams * @threads_per_chan:	number of threads to start per channel
118a310d037b8d06755c62bb4878c00d19490af5550Dan Williams * @max_channels:	maximum number of channels to use
119a310d037b8d06755c62bb4878c00d19490af5550Dan Williams * @iterations:		iterations before stopping test
120a310d037b8d06755c62bb4878c00d19490af5550Dan Williams * @xor_sources:	number of xor source buffers
121a310d037b8d06755c62bb4878c00d19490af5550Dan Williams * @pq_sources:		number of p+q source buffers
122e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko * @timeout:		transfer timeout in msec, -1 for infinite timeout
123a310d037b8d06755c62bb4878c00d19490af5550Dan Williams */
124a310d037b8d06755c62bb4878c00d19490af5550Dan Williamsstruct dmatest_params {
125a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	unsigned int	buf_size;
126e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko	char		channel[20];
127a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	char		device[20];
128a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	unsigned int	threads_per_chan;
129a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	unsigned int	max_channels;
130a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	unsigned int	iterations;
131a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	unsigned int	xor_sources;
132a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	unsigned int	pq_sources;
133a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	int		timeout;
134a310d037b8d06755c62bb4878c00d19490af5550Dan Williams};
135a310d037b8d06755c62bb4878c00d19490af5550Dan Williams
136a310d037b8d06755c62bb4878c00d19490af5550Dan Williams/**
137a310d037b8d06755c62bb4878c00d19490af5550Dan Williams * struct dmatest_info - test information.
138a310d037b8d06755c62bb4878c00d19490af5550Dan Williams * @params:		test parameters
139a310d037b8d06755c62bb4878c00d19490af5550Dan Williams * @lock:		access protection to the fields of this structure
140a310d037b8d06755c62bb4878c00d19490af5550Dan Williams */
141a310d037b8d06755c62bb4878c00d19490af5550Dan Williamsstruct dmatest_info {
142a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	/* Test parameters */
143a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	struct dmatest_params	params;
144a310d037b8d06755c62bb4878c00d19490af5550Dan Williams
145a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	/* Internal state */
146a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	struct list_head	channels;
147a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	unsigned int		nr_channels;
148a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	struct mutex		lock;
149a310d037b8d06755c62bb4878c00d19490af5550Dan Williams
150a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	/* debugfs related stuff */
151a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	struct dentry		*root;
152a310d037b8d06755c62bb4878c00d19490af5550Dan Williams};
153a310d037b8d06755c62bb4878c00d19490af5550Dan Williams
154a310d037b8d06755c62bb4878c00d19490af5550Dan Williamsstatic struct dmatest_info test_info;
155a310d037b8d06755c62bb4878c00d19490af5550Dan Williams
156a310d037b8d06755c62bb4878c00d19490af5550Dan Williamsstatic bool dmatest_match_channel(struct dmatest_params *params,
157a310d037b8d06755c62bb4878c00d19490af5550Dan Williams		struct dma_chan *chan)
158a310d037b8d06755c62bb4878c00d19490af5550Dan Williams{
159a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	if (params->channel[0] == '\0')
160a310d037b8d06755c62bb4878c00d19490af5550Dan Williams		return true;
161a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	return strcmp(dma_chan_name(chan), params->channel) == 0;
162a310d037b8d06755c62bb4878c00d19490af5550Dan Williams}
163e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko
16415b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenkostatic bool dmatest_match_device(struct dmatest_params *params,
165e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko		struct dma_device *device)
1664a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen{
16715b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko	if (params->device[0] == '\0')
1684a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		return true;
16915b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko	return strcmp(dev_name(device->dev), params->device) == 0;
1704a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen}
1714a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen
17215b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenkostatic unsigned long dmatest_random(void)
173e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko{
1744a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	unsigned long buf;
17515b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko
1764a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	get_random_bytes(&buf, sizeof(buf));
17715b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko	return buf;
1784a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen}
1794a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen
1804a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoenstatic void dmatest_init_srcs(u8 **bufs, unsigned int start, unsigned int len,
1814a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		unsigned int buf_size)
1824a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen{
1834a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	unsigned int i;
184be9fa5a43641103bf13cd1bb8101a1453da03616Dan Williams	u8 *buf;
1854a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen
1864a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	for (; (buf = *bufs); bufs++) {
1874a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		for (i = 0; i < start; i++)
188e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko			buf[i] = PATTERN_SRC | (~i & PATTERN_COUNT_MASK);
189e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko		for ( ; i < start + len; i++)
1904a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen			buf[i] = PATTERN_SRC | PATTERN_COPY
1914a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen				| (~i & PATTERN_COUNT_MASK);
192b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		for ( ; i < buf_size; i++)
193b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams			buf[i] = PATTERN_SRC | (~i & PATTERN_COUNT_MASK);
194b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		buf++;
195b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	}
196b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams}
197b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams
198b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williamsstatic void dmatest_init_dsts(u8 **bufs, unsigned int start, unsigned int len,
199c019894efc9c9ba5939948caa78c133b1ec8ae63Joe Perches		unsigned int buf_size)
200e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko{
201b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	unsigned int i;
202b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	u8 *buf;
203b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams
2044a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	for (; (buf = *bufs); bufs++) {
2054a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		for (i = 0; i < start; i++)
206e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko			buf[i] = PATTERN_DST | (~i & PATTERN_COUNT_MASK);
207e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko		for ( ; i < start + len; i++)
2084a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen			buf[i] = PATTERN_DST | PATTERN_OVERWRITE
2094a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen				| (~i & PATTERN_COUNT_MASK);
210b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		for ( ; i < buf_size; i++)
211b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams			buf[i] = PATTERN_DST | (~i & PATTERN_COUNT_MASK);
212b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	}
213b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams}
214b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams
215b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williamsstatic void dmatest_mismatch(u8 actual, u8 pattern, unsigned int index,
216b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		unsigned int counter, bool is_srcbuf)
217b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams{
218e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko	u8		diff = actual ^ pattern;
219b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	u8		expected = pattern | (~counter & PATTERN_COUNT_MASK);
220b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	const char	*thread_name = current->comm;
2214a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen
2224a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	if (is_srcbuf)
2237b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams		pr_warn("%s: srcbuf[0x%x] overwritten! Expected %02x, got %02x\n",
2247b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams			thread_name, index, expected, actual);
2257b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams	else if ((pattern & PATTERN_COPY)
2267b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams			&& (diff & (PATTERN_COPY | PATTERN_OVERWRITE)))
2277b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams		pr_warn("%s: dstbuf[0x%x] not copied! Expected %02x, got %02x\n",
2287b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams			thread_name, index, expected, actual);
2297b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams	else if (diff & PATTERN_SRC)
2307b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams		pr_warn("%s: dstbuf[0x%x] was copied! Expected %02x, got %02x\n",
2317b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams			thread_name, index, expected, actual);
2327b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams	else
2337b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams		pr_warn("%s: dstbuf[0x%x] mismatch! Expected %02x, got %02x\n",
2347b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams			thread_name, index, expected, actual);
2357b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams}
2367b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams
2377b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williamsstatic unsigned int dmatest_verify(u8 **bufs, unsigned int start,
2387b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams		unsigned int end, unsigned int counter, u8 pattern,
2397b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams		bool is_srcbuf)
2407b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams{
2417b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams	unsigned int i;
2427b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams	unsigned int error_count = 0;
2437b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams	u8 actual;
2447b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams	u8 expected;
2457b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams	u8 *buf;
2467b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams	unsigned int counter_orig = counter;
2477b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams
2484a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	for (; (buf = *bufs); bufs++) {
2494a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		counter = counter_orig;
2504a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		for (i = start; i < end; i++) {
2514a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen			actual = buf[i];
252b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams			expected = pattern | (~counter & PATTERN_COUNT_MASK);
253b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams			if (actual != expected) {
254b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams				if (error_count < MAX_ERROR_COUNT)
255b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams					dmatest_mismatch(actual, pattern, i,
256b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams							 counter, is_srcbuf);
257b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams				error_count++;
258b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams			}
259b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams			counter++;
260b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		}
261b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	}
2627b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams
2637b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams	if (error_count > MAX_ERROR_COUNT)
2647b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams		pr_warn("%s: %u errors suppressed\n",
265b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams			current->comm, error_count - MAX_ERROR_COUNT);
266b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams
267b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	return error_count;
2684a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen}
2694a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen
2704a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen/* poor man's completion - we want to use wait_event_freezable() on it */
27174b5c07a515b2986c9bdfe649213b8e358d32ad2Andy Shevchenkostruct dmatest_done {
2727b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams	bool			done;
27374b5c07a515b2986c9bdfe649213b8e358d32ad2Andy Shevchenko	wait_queue_head_t	*wait;
2744a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen};
2754a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen
2764a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoenstatic void dmatest_callback(void *arg)
2774a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen{
278adfa543e7314b36ac55a40019977de6e47946dd7Tejun Heo	struct dmatest_done *done = arg;
279adfa543e7314b36ac55a40019977de6e47946dd7Tejun Heo
280adfa543e7314b36ac55a40019977de6e47946dd7Tejun Heo	done->done = true;
281adfa543e7314b36ac55a40019977de6e47946dd7Tejun Heo	wake_up_all(done->wait);
282adfa543e7314b36ac55a40019977de6e47946dd7Tejun Heo}
283adfa543e7314b36ac55a40019977de6e47946dd7Tejun Heo
284adfa543e7314b36ac55a40019977de6e47946dd7Tejun Heostatic inline void unmap_src(struct device *dev, dma_addr_t *addr, size_t len,
285e44e0aa3cfa97cddff01704751a4b25151830c72Dan Williams			     unsigned int count)
286adfa543e7314b36ac55a40019977de6e47946dd7Tejun Heo{
287adfa543e7314b36ac55a40019977de6e47946dd7Tejun Heo	while (count--)
288adfa543e7314b36ac55a40019977de6e47946dd7Tejun Heo		dma_unmap_single(dev, addr[count], len, DMA_TO_DEVICE);
289adfa543e7314b36ac55a40019977de6e47946dd7Tejun Heo}
290e44e0aa3cfa97cddff01704751a4b25151830c72Dan Williams
291e44e0aa3cfa97cddff01704751a4b25151830c72Dan Williamsstatic inline void unmap_dst(struct device *dev, dma_addr_t *addr, size_t len,
292632fd28326c0cc7be9c51ea0d76d8bec39a695e9Andy Shevchenko			     unsigned int count)
293632fd28326c0cc7be9c51ea0d76d8bec39a695e9Andy Shevchenko{
294632fd28326c0cc7be9c51ea0d76d8bec39a695e9Andy Shevchenko	while (count--)
295632fd28326c0cc7be9c51ea0d76d8bec39a695e9Andy Shevchenko		dma_unmap_single(dev, addr[count], len, DMA_BIDIRECTIONAL);
296632fd28326c0cc7be9c51ea0d76d8bec39a695e9Andy Shevchenko}
297632fd28326c0cc7be9c51ea0d76d8bec39a695e9Andy Shevchenko
298632fd28326c0cc7be9c51ea0d76d8bec39a695e9Andy Shevchenkostatic unsigned int min_odd(unsigned int x, unsigned int y)
299632fd28326c0cc7be9c51ea0d76d8bec39a695e9Andy Shevchenko{
300632fd28326c0cc7be9c51ea0d76d8bec39a695e9Andy Shevchenko	unsigned int val = min(x, y);
301632fd28326c0cc7be9c51ea0d76d8bec39a695e9Andy Shevchenko
302632fd28326c0cc7be9c51ea0d76d8bec39a695e9Andy Shevchenko	return val % 2 ? val : val - 1;
303632fd28326c0cc7be9c51ea0d76d8bec39a695e9Andy Shevchenko}
304632fd28326c0cc7be9c51ea0d76d8bec39a695e9Andy Shevchenko
305632fd28326c0cc7be9c51ea0d76d8bec39a695e9Andy Shevchenkostatic void result(const char *err, unsigned int n, unsigned int src_off,
3068be9e32b310cd8c4302991c8ff6692689c7d9d76Akinobu Mita		   unsigned int dst_off, unsigned int len, unsigned long data)
3078be9e32b310cd8c4302991c8ff6692689c7d9d76Akinobu Mita{
3088be9e32b310cd8c4302991c8ff6692689c7d9d76Akinobu Mita	pr_info("%s: result #%u: '%s' with src_off=0x%x ""dst_off=0x%x len=0x%x (%lu)",
3098be9e32b310cd8c4302991c8ff6692689c7d9d76Akinobu Mita		current->comm, n, err, src_off, dst_off, len, data);
3108be9e32b310cd8c4302991c8ff6692689c7d9d76Akinobu Mita}
3118be9e32b310cd8c4302991c8ff6692689c7d9d76Akinobu Mita
3128be9e32b310cd8c4302991c8ff6692689c7d9d76Akinobu Mitastatic void dbg_result(const char *err, unsigned int n, unsigned int src_off,
313872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams		       unsigned int dst_off, unsigned int len,
314872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams		       unsigned long data)
31595019c8c5af947f64e4a62e08a4a275bc36148eeAndy Shevchenko{
316872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams	pr_debug("%s: result #%u: '%s' with src_off=0x%x ""dst_off=0x%x len=0x%x (%lu)",
317872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams		 current->comm, n, err, src_off, dst_off, len, data);
31895019c8c5af947f64e4a62e08a4a275bc36148eeAndy Shevchenko}
31995019c8c5af947f64e4a62e08a4a275bc36148eeAndy Shevchenko
320872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams/*
321872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams * This function repeatedly tests DMA transfers of various lengths and
322872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams * offsets for a given operation type until it is told to exit by
32395019c8c5af947f64e4a62e08a4a275bc36148eeAndy Shevchenko * kthread_stop(). There may be multiple threads running this function
324872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams * in parallel for a single channel, and there may be multiple channels
325872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams * being tested in parallel.
32695019c8c5af947f64e4a62e08a4a275bc36148eeAndy Shevchenko *
32795019c8c5af947f64e4a62e08a4a275bc36148eeAndy Shevchenko * Before each test, the source and destination buffer is initialized
3284a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen * with a known pattern. This pattern is different depending on
3294a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen * whether it's in an area which is supposed to be copied or
330b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams * overwritten, and different in the source and destination buffers.
331b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams * So if the DMA engine doesn't copy exactly what we tell it to copy,
332b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams * we'll notice.
333b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams */
3344a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoenstatic int dmatest_func(void *data)
3354a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen{
3364a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_wait);
3374a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	struct dmatest_thread	*thread = data;
3384a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	struct dmatest_done	done = { .wait = &done_wait };
3394a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	struct dmatest_info	*info;
3404a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	struct dmatest_params	*params;
3414a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	struct dma_chan		*chan;
3424a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	struct dma_device	*dev;
3434a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	unsigned int		src_off, dst_off, len;
344adfa543e7314b36ac55a40019977de6e47946dd7Tejun Heo	unsigned int		error_count;
3454a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	unsigned int		failed_tests = 0;
346adfa543e7314b36ac55a40019977de6e47946dd7Tejun Heo	unsigned int		total_tests = 0;
347e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko	dma_cookie_t		cookie;
34815b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko	enum dma_status		status;
3494a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	enum dma_ctrl_flags 	flags;
3508be9e32b310cd8c4302991c8ff6692689c7d9d76Akinobu Mita	u8			*pq_coefs = NULL;
3514a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	int			ret;
3524a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	int			src_cnt;
3534a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	int			dst_cnt;
3544a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	int			i;
3554a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen
3564a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	set_freezable();
357b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams
358945b5af3cedcdfed6d2d940e53cd19933bb57386Andy Shevchenko	ret = -ENOMEM;
3594a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen
360b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	smp_rmb();
361b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	info = thread->info;
362b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	params = &info->params;
3634a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	chan = thread->chan;
364adfa543e7314b36ac55a40019977de6e47946dd7Tejun Heo	dev = chan->device;
3654a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	if (thread->type == DMA_MEMCPY)
3664a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		src_cnt = dst_cnt = 1;
3674a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	else if (thread->type == DMA_XOR) {
3684a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		/* force odd to ensure dst = src */
369e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko		src_cnt = min_odd(params->xor_sources | 1, dev->max_xor);
37015b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko		dst_cnt = 1;
3714a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	} else if (thread->type == DMA_PQ) {
3728be9e32b310cd8c4302991c8ff6692689c7d9d76Akinobu Mita		/* force odd to ensure dst = src */
373b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		src_cnt = min_odd(params->pq_sources | 1, dma_maxpq(dev, 0));
374b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		dst_cnt = 2;
375b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams
3768be9e32b310cd8c4302991c8ff6692689c7d9d76Akinobu Mita		pq_coefs = kmalloc(params->pq_sources+1, GFP_KERNEL);
37715b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko		if (!pq_coefs)
378b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams			goto err_thread_type;
37958691d64c44ae41ddf098ecb31e9a994026e3cffDan Williams
3808be9e32b310cd8c4302991c8ff6692689c7d9d76Akinobu Mita		for (i = 0; i < src_cnt; i++)
38115b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko			pq_coefs[i] = 1;
38258691d64c44ae41ddf098ecb31e9a994026e3cffDan Williams	} else
383945b5af3cedcdfed6d2d940e53cd19933bb57386Andy Shevchenko		goto err_thread_type;
38415b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko
385945b5af3cedcdfed6d2d940e53cd19933bb57386Andy Shevchenko	thread->srcs = kcalloc(src_cnt+1, sizeof(u8 *), GFP_KERNEL);
386945b5af3cedcdfed6d2d940e53cd19933bb57386Andy Shevchenko	if (!thread->srcs)
387945b5af3cedcdfed6d2d940e53cd19933bb57386Andy Shevchenko		goto err_srcs;
38894de648d72c8bc833590523f22386d4babbea988Anatolij Gustschin	for (i = 0; i < src_cnt; i++) {
38958691d64c44ae41ddf098ecb31e9a994026e3cffDan Williams		thread->srcs[i] = kmalloc(params->buf_size, GFP_KERNEL);
390b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		if (!thread->srcs[i])
391945b5af3cedcdfed6d2d940e53cd19933bb57386Andy Shevchenko			goto err_srcbuf;
392b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	}
393b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	thread->srcs[i] = NULL;
394b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams
395b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	thread->dsts = kcalloc(dst_cnt+1, sizeof(u8 *), GFP_KERNEL);
396b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	if (!thread->dsts)
39715b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko		goto err_dsts;
398b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	for (i = 0; i < dst_cnt; i++) {
399b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		thread->dsts[i] = kmalloc(params->buf_size, GFP_KERNEL);
400b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		if (!thread->dsts[i])
401b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams			goto err_dstbuf;
402b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	}
403b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	thread->dsts[i] = NULL;
404b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams
405b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	set_user_nice(current, 10);
406b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams
40715b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko	/*
408b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	 * src and dst buffers are freed by ourselves below
409b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	 */
410b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
411b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams
412b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	while (!kthread_should_stop()
413e44e0aa3cfa97cddff01704751a4b25151830c72Dan Williams	       && !(params->iterations && total_tests >= params->iterations)) {
414e44e0aa3cfa97cddff01704751a4b25151830c72Dan Williams		struct dma_async_tx_descriptor *tx = NULL;
415b203bd3f6b9c3db3b1979c2ff79bb2b9be8f03a3Ira Snyder		dma_addr_t dma_srcs[src_cnt];
416d1cab34c039584ebe76b04d2f2109e0d87d344e1Bartlomiej Zolnierkiewicz		dma_addr_t dma_dsts[dst_cnt];
417b203bd3f6b9c3db3b1979c2ff79bb2b9be8f03a3Ira Snyder		u8 align = 0;
4180776ae7b89782124ddd72eafe0b1e0fdcdabe32eBartlomiej Zolnierkiewicz
4194a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		total_tests++;
4200a2ff57d6fba92842272889b4bca447344cd9d36Nicolas Ferre
42115b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko		/* honor alignment restrictions */
422b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		if (thread->type == DMA_MEMCPY)
423b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams			align = dev->copy_align;
424b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		else if (thread->type == DMA_XOR)
42583544ae9f3991bfc7d5e0fe9a3008cd05a8d57b7Dan Williams			align = dev->xor_align;
426d86be86e9aab221089d72399072511f13fe2a771Atsushi Nemoto		else if (thread->type == DMA_PQ)
4274a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen			align = dev->pq_align;
4284a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen
42983544ae9f3991bfc7d5e0fe9a3008cd05a8d57b7Dan Williams		if (1 << align > params->buf_size) {
43083544ae9f3991bfc7d5e0fe9a3008cd05a8d57b7Dan Williams			pr_err("%u-byte buffer too small for %d-byte alignment\n",
43183544ae9f3991bfc7d5e0fe9a3008cd05a8d57b7Dan Williams			       params->buf_size, 1 << align);
43283544ae9f3991bfc7d5e0fe9a3008cd05a8d57b7Dan Williams			break;
43383544ae9f3991bfc7d5e0fe9a3008cd05a8d57b7Dan Williams		}
43483544ae9f3991bfc7d5e0fe9a3008cd05a8d57b7Dan Williams
43583544ae9f3991bfc7d5e0fe9a3008cd05a8d57b7Dan Williams		len = dmatest_random() % params->buf_size + 1;
43683544ae9f3991bfc7d5e0fe9a3008cd05a8d57b7Dan Williams		len = (len >> align) << align;
43715b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko		if (!len)
438cfe4f2751ef1a5390b56c5d263f90b6ff138ba31Guennadi Liakhovetski			len = 1 << align;
43915b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko		src_off = dmatest_random() % (params->buf_size - len + 1);
440cfe4f2751ef1a5390b56c5d263f90b6ff138ba31Guennadi Liakhovetski		dst_off = dmatest_random() % (params->buf_size - len + 1);
441cfe4f2751ef1a5390b56c5d263f90b6ff138ba31Guennadi Liakhovetski
442cfe4f2751ef1a5390b56c5d263f90b6ff138ba31Guennadi Liakhovetski		src_off = (src_off >> align) << align;
443e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams		dst_off = (dst_off >> align) << align;
444e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams
445e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams		dmatest_init_srcs(thread->srcs, src_off, len, params->buf_size);
446e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams		dmatest_init_dsts(thread->dsts, dst_off, len, params->buf_size);
447e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams
448e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams		for (i = 0; i < src_cnt; i++) {
449e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams			u8 *buf = thread->srcs[i] + src_off;
450e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams
451e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams			dma_srcs[i] = dma_map_single(dev->dev, buf, len,
452e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams						     DMA_TO_DEVICE);
453e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams			ret = dma_mapping_error(dev->dev, dma_srcs[i]);
454e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams			if (ret) {
455e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams				unmap_src(dev->dev, dma_srcs, len, i);
456e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams				result("src mapping error", total_tests,
457e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams				       src_off, dst_off, len, ret);
458e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams				failed_tests++;
459e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams				continue;
460e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams			}
461e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams		}
462e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams		/* map with DMA_BIDIRECTIONAL to force writeback/invalidate */
463e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams		for (i = 0; i < dst_cnt; i++) {
46483544ae9f3991bfc7d5e0fe9a3008cd05a8d57b7Dan Williams			dma_dsts[i] = dma_map_single(dev->dev, thread->dsts[i],
465cfe4f2751ef1a5390b56c5d263f90b6ff138ba31Guennadi Liakhovetski						     params->buf_size,
466cfe4f2751ef1a5390b56c5d263f90b6ff138ba31Guennadi Liakhovetski						     DMA_BIDIRECTIONAL);
4674a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen			ret = dma_mapping_error(dev->dev, dma_dsts[i]);
468b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams			if (ret) {
469b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams				unmap_src(dev->dev, dma_srcs, len, src_cnt);
470b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams				unmap_dst(dev->dev, dma_dsts, params->buf_size,
471b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams					  i);
472b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams				result("dst mapping error", total_tests,
473afde3be121efcc658e26f8cc71ead04af96d38f9Andy Shevchenko				       src_off, dst_off, len, ret);
474afde3be121efcc658e26f8cc71ead04af96d38f9Andy Shevchenko				failed_tests++;
475afde3be121efcc658e26f8cc71ead04af96d38f9Andy Shevchenko				continue;
476872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams			}
477872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams		}
478afde3be121efcc658e26f8cc71ead04af96d38f9Andy Shevchenko
479afde3be121efcc658e26f8cc71ead04af96d38f9Andy Shevchenko		if (thread->type == DMA_MEMCPY)
480afde3be121efcc658e26f8cc71ead04af96d38f9Andy Shevchenko			tx = dev->device_prep_dma_memcpy(chan,
481b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams							 dma_dsts[0] + dst_off,
482d86be86e9aab221089d72399072511f13fe2a771Atsushi Nemoto							 dma_srcs[0], len,
483b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams							 flags);
484b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		else if (thread->type == DMA_XOR)
48515b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko			tx = dev->device_prep_dma_xor(chan,
486b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams						      dma_dsts[0] + dst_off,
487afde3be121efcc658e26f8cc71ead04af96d38f9Andy Shevchenko						      dma_srcs, src_cnt,
488afde3be121efcc658e26f8cc71ead04af96d38f9Andy Shevchenko						      len, flags);
489afde3be121efcc658e26f8cc71ead04af96d38f9Andy Shevchenko		else if (thread->type == DMA_PQ) {
49015b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko			dma_addr_t dma_pq[dst_cnt];
49115b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko
492872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams			for (i = 0; i < dst_cnt; i++)
493872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams				dma_pq[i] = dma_dsts[i] + dst_off;
494afde3be121efcc658e26f8cc71ead04af96d38f9Andy Shevchenko			tx = dev->device_prep_dma_pq(chan, dma_pq, dma_srcs,
495afde3be121efcc658e26f8cc71ead04af96d38f9Andy Shevchenko						     src_cnt, pq_coefs,
496afde3be121efcc658e26f8cc71ead04af96d38f9Andy Shevchenko						     len, flags);
497b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		}
498b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams
499b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		if (!tx) {
500b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams			unmap_src(dev->dev, dma_srcs, len, src_cnt);
501b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams			unmap_dst(dev->dev, dma_dsts, params->buf_size,
502b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams				  dst_cnt);
503b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams			result("prep error", total_tests, src_off,
504b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams			       dst_off, len, ret);
505b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams			msleep(100);
506b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams			failed_tests++;
50767b9124f734b22b30d9adf18c39fe795e2901070Dan Williams			continue;
508b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		}
50958691d64c44ae41ddf098ecb31e9a994026e3cffDan Williams
51058691d64c44ae41ddf098ecb31e9a994026e3cffDan Williams		done.done = false;
51158691d64c44ae41ddf098ecb31e9a994026e3cffDan Williams		tx->callback = dmatest_callback;
51258691d64c44ae41ddf098ecb31e9a994026e3cffDan Williams		tx->callback_param = &done;
51358691d64c44ae41ddf098ecb31e9a994026e3cffDan Williams		cookie = tx->tx_submit(tx);
51458691d64c44ae41ddf098ecb31e9a994026e3cffDan Williams
51594de648d72c8bc833590523f22386d4babbea988Anatolij Gustschin		if (dma_submit_error(cookie)) {
51658691d64c44ae41ddf098ecb31e9a994026e3cffDan Williams			result("submit error", total_tests, src_off,
51758691d64c44ae41ddf098ecb31e9a994026e3cffDan Williams			       dst_off, len, ret);
518d86be86e9aab221089d72399072511f13fe2a771Atsushi Nemoto			msleep(100);
519d86be86e9aab221089d72399072511f13fe2a771Atsushi Nemoto			failed_tests++;
520632fd28326c0cc7be9c51ea0d76d8bec39a695e9Andy Shevchenko			continue;
52115b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko		}
52215b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko		dma_async_issue_pending(chan);
523872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams
524872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams		wait_event_freezable_timeout(done_wait, done.done,
525d86be86e9aab221089d72399072511f13fe2a771Atsushi Nemoto					     msecs_to_jiffies(params->timeout));
526d86be86e9aab221089d72399072511f13fe2a771Atsushi Nemoto
527d86be86e9aab221089d72399072511f13fe2a771Atsushi Nemoto		status = dma_async_is_tx_complete(chan, cookie, NULL, NULL);
528d86be86e9aab221089d72399072511f13fe2a771Atsushi Nemoto
529e44e0aa3cfa97cddff01704751a4b25151830c72Dan Williams		if (!done.done) {
530adfa543e7314b36ac55a40019977de6e47946dd7Tejun Heo			/*
531e44e0aa3cfa97cddff01704751a4b25151830c72Dan Williams			 * We're leaving the timed out dma operation with
532adfa543e7314b36ac55a40019977de6e47946dd7Tejun Heo			 * dangling pointer to done_wait.  To make this
533d86be86e9aab221089d72399072511f13fe2a771Atsushi Nemoto			 * correct, we'll need to allocate wait_done for
534d86be86e9aab221089d72399072511f13fe2a771Atsushi Nemoto			 * each test iteration and perform "who's gonna
5354a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen			 * free it this time?" dancing.  For now, just
536872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams			 * leave it dangling.
537872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams			 */
5384a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen			result("test timed out", total_tests, src_off, dst_off,
5394a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen			       len, 0);
5404a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen			failed_tests++;
5414a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen			continue;
542b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		} else if (status != DMA_SUCCESS) {
5434a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen			result(status == DMA_ERROR ?
544bcc567e3115055a9cc256183d72864f01286be22Andy Shevchenko			       "completion error status" :
54515b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko			       "completion busy status", total_tests, src_off,
546981ed70d8e4faf3689dbf3c48868a31d5b004d7aGuennadi Liakhovetski			       dst_off, len, ret);
547e44e0aa3cfa97cddff01704751a4b25151830c72Dan Williams			failed_tests++;
5484a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen			continue;
549adfa543e7314b36ac55a40019977de6e47946dd7Tejun Heo		}
550adfa543e7314b36ac55a40019977de6e47946dd7Tejun Heo
551adfa543e7314b36ac55a40019977de6e47946dd7Tejun Heo		/* Unmap by myself */
552adfa543e7314b36ac55a40019977de6e47946dd7Tejun Heo		unmap_src(dev->dev, dma_srcs, len, src_cnt);
553adfa543e7314b36ac55a40019977de6e47946dd7Tejun Heo		unmap_dst(dev->dev, dma_dsts, params->buf_size, dst_cnt);
554adfa543e7314b36ac55a40019977de6e47946dd7Tejun Heo
555adfa543e7314b36ac55a40019977de6e47946dd7Tejun Heo		error_count = 0;
556adfa543e7314b36ac55a40019977de6e47946dd7Tejun Heo
557adfa543e7314b36ac55a40019977de6e47946dd7Tejun Heo		pr_debug("%s: verifying source buffer...\n", current->comm);
558872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams		error_count += dmatest_verify(thread->srcs, 0, src_off,
559872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams				0, PATTERN_SRC, true);
560e44e0aa3cfa97cddff01704751a4b25151830c72Dan Williams		error_count += dmatest_verify(thread->srcs, src_off,
561e44e0aa3cfa97cddff01704751a4b25151830c72Dan Williams				src_off + len, src_off,
562e44e0aa3cfa97cddff01704751a4b25151830c72Dan Williams				PATTERN_SRC | PATTERN_COPY, true);
563872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams		error_count += dmatest_verify(thread->srcs, src_off + len,
564872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams				params->buf_size, src_off + len,
565872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams				PATTERN_SRC, true);
566872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams
5674a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		pr_debug("%s: verifying dest buffer...\n", current->comm);
5684a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		error_count += dmatest_verify(thread->dsts, 0, dst_off,
5694a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen				0, PATTERN_DST, false);
570e44e0aa3cfa97cddff01704751a4b25151830c72Dan Williams		error_count += dmatest_verify(thread->dsts, dst_off,
571d1cab34c039584ebe76b04d2f2109e0d87d344e1Bartlomiej Zolnierkiewicz				dst_off + len, src_off,
572d1cab34c039584ebe76b04d2f2109e0d87d344e1Bartlomiej Zolnierkiewicz				PATTERN_SRC | PATTERN_COPY, false);
57315b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko		error_count += dmatest_verify(thread->dsts, dst_off + len,
5744a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen				params->buf_size, dst_off + len,
575e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams				PATTERN_DST, false);
576e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams
577e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams		if (error_count) {
578e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams			result("data error", total_tests, src_off, dst_off,
579e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams			       len, error_count);
5804a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen			failed_tests++;
581872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams		} else {
582e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams			dbg_result("test passed", total_tests, src_off, dst_off,
5834a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen				   len, 0);
5847b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams		}
5857b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams	}
5867b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams
5877b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams	ret = 0;
5887b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams	for (i = 0; thread->dsts[i]; i++)
5897b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams		kfree(thread->dsts[i]);
5907b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williamserr_dstbuf:
591872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams	kfree(thread->dsts);
5927b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williamserr_dsts:
5934a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	for (i = 0; thread->srcs[i]; i++)
5947b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams		kfree(thread->srcs[i]);
5957b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williamserr_srcbuf:
5967b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams	kfree(thread->srcs);
5977b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williamserr_srcs:
5987b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williams	kfree(pq_coefs);
5997b61017822cdff9c18ae70005cf52d84e8dafe5dDan Williamserr_thread_type:
6004a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	pr_info("%s: terminating after %u tests, %u failures (status %d)\n",
6014a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		current->comm, total_tests, failed_tests, ret);
602872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams
603872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams	/* terminate all transfers on specified channels */
6044a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	if (ret)
6054a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		dmaengine_terminate_all(chan);
606872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams
607872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams	thread->done = true;
6084a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen
6094a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	if (params->iterations > 0)
6104a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		while (!kthread_should_stop()) {
6114a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen			DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wait_dmatest_exit);
612b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams			interruptible_sleep_on(&wait_dmatest_exit);
613b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		}
6144a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen
615b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	return ret;
616b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams}
617b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams
618b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williamsstatic void dmatest_cleanup_channel(struct dmatest_chan *dtc)
6194a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen{
620b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	struct dmatest_thread	*thread;
621b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	struct dmatest_thread	*_thread;
622945b5af3cedcdfed6d2d940e53cd19933bb57386Andy Shevchenko	int			ret;
623945b5af3cedcdfed6d2d940e53cd19933bb57386Andy Shevchenko
624872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams	list_for_each_entry_safe(thread, _thread, &dtc->threads, node) {
625872f05c6e9a37e9358fd58eb54deee7337863496Dan Williams		ret = kthread_stop(thread->task);
6260a2ff57d6fba92842272889b4bca447344cd9d36Nicolas Ferre		pr_debug("dmatest: thread %s exited with status %d\n",
6279704efaa52ab18eb3504c4e0bc421c1d01b7981aViresh Kumar				thread->task->comm, ret);
6285e034f7b659be9d94e64aaaa985ab530dd847fdbShiraz Hashim		list_del(&thread->node);
6295e034f7b659be9d94e64aaaa985ab530dd847fdbShiraz Hashim		kfree(thread);
6305e034f7b659be9d94e64aaaa985ab530dd847fdbShiraz Hashim	}
6313e5ccd866fdf3a1e1d4d2c08c81f861ad6798d32Andy Shevchenko
6323e5ccd866fdf3a1e1d4d2c08c81f861ad6798d32Andy Shevchenko	/* terminate all transfers on specified channels */
63315b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko	dmaengine_terminate_all(dtc->chan);
6340a2ff57d6fba92842272889b4bca447344cd9d36Nicolas Ferre
635b953df7c70740cd7593072ebec77a8f658505630Yong Zhang	kfree(dtc);
6360a2ff57d6fba92842272889b4bca447344cd9d36Nicolas Ferre}
6370a2ff57d6fba92842272889b4bca447344cd9d36Nicolas Ferre
6380a2ff57d6fba92842272889b4bca447344cd9d36Nicolas Ferrestatic int dmatest_add_threads(struct dmatest_info *info,
6394a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		struct dmatest_chan *dtc, enum dma_transaction_type type)
6404a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen{
6414a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	struct dmatest_params *params = &info->params;
6424a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	struct dmatest_thread *thread;
6434a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	struct dma_chan *chan = dtc->chan;
6444a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	char *op;
6454a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	unsigned int i;
6464a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen
6474a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	if (type == DMA_MEMCPY)
6484a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		op = "copy";
6494a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	else if (type == DMA_XOR)
6500adff800662f52d0ffc3e420db231769cb3fff13Dan Williams		op = "xor";
6510adff800662f52d0ffc3e420db231769cb3fff13Dan Williams	else if (type == DMA_PQ)
6524a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		op = "pq";
6534a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	else
6544a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		return -EINVAL;
6559704efaa52ab18eb3504c4e0bc421c1d01b7981aViresh Kumar
6569704efaa52ab18eb3504c4e0bc421c1d01b7981aViresh Kumar	for (i = 0; i < params->threads_per_chan; i++) {
657944ea4dd38b8575e30a5699633c81945bff1864dJon Mason		thread = kzalloc(sizeof(struct dmatest_thread), GFP_KERNEL);
6589704efaa52ab18eb3504c4e0bc421c1d01b7981aViresh Kumar		if (!thread) {
6594a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen			pr_warning("dmatest: No memory for %s-%s%u\n",
6604a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen				   dma_chan_name(chan), op, i);
6614a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen
662e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko			break;
663e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko		}
6644a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		thread->info = info;
66515b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko		thread->chan = dtc->chan;
666b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		thread->type = type;
667b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		smp_wmb();
668b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		thread->task = kthread_run(dmatest_func, thread, "%s-%s%u",
669b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams				dma_chan_name(chan), op, i);
6704a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		if (IS_ERR(thread->task)) {
671b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams			pr_warning("dmatest: Failed to run thread %s-%s%u\n",
672b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams					dma_chan_name(chan), op, i);
673b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams			kfree(thread);
674b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams			break;
67558691d64c44ae41ddf098ecb31e9a994026e3cffDan Williams		}
67658691d64c44ae41ddf098ecb31e9a994026e3cffDan Williams
677b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		/* srcbuf and dstbuf are allocated by the thread itself */
678b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams
6794a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		list_add_tail(&thread->node, &dtc->threads);
68015b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko	}
6814a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen
6824a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	return i;
6830adff800662f52d0ffc3e420db231769cb3fff13Dan Williams}
6840adff800662f52d0ffc3e420db231769cb3fff13Dan Williams
6854a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoenstatic int dmatest_add_channel(struct dmatest_info *info,
6864a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		struct dma_chan *chan)
687e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko{
6884a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	struct dmatest_chan	*dtc;
689b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	struct dma_device	*dma_dev = chan->device;
6904a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	unsigned int		thread_count = 0;
691b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	int cnt;
692b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams
6934a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	dtc = kmalloc(sizeof(struct dmatest_chan), GFP_KERNEL);
6940adff800662f52d0ffc3e420db231769cb3fff13Dan Williams	if (!dtc) {
6950adff800662f52d0ffc3e420db231769cb3fff13Dan Williams		pr_warning("dmatest: No memory for %s\n", dma_chan_name(chan));
6964a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		return -ENOMEM;
6974a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	}
6984a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen
6994a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	dtc->chan = chan;
7004a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	INIT_LIST_HEAD(&dtc->threads);
7014a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen
7024a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask)) {
7034a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		cnt = dmatest_add_threads(info, dtc, DMA_MEMCPY);
7044a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		thread_count += cnt > 0 ? cnt : 0;
705b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	}
706b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) {
707b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		cnt = dmatest_add_threads(info, dtc, DMA_XOR);
708e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko		thread_count += cnt > 0 ? cnt : 0;
709e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko	}
710b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	if (dma_has_cap(DMA_PQ, dma_dev->cap_mask)) {
711b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		cnt = dmatest_add_threads(info, dtc, DMA_PQ);
712b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		thread_count += cnt > 0 ? cnt : 0;
713b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	}
714b9033e682e86f3c6a66763f9b6a3935c5c64e145Kulikov Vasiliy
715b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	pr_info("dmatest: Started %u threads using %s\n",
716b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		thread_count, dma_chan_name(chan));
717b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams
7180adff800662f52d0ffc3e420db231769cb3fff13Dan Williams	list_add_tail(&dtc->node, &info->channels);
719b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	info->nr_channels++;
720b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams
721b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	return 0;
722b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams}
723b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams
724b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williamsstatic bool filter(struct dma_chan *chan, void *param)
725b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams{
726e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko	struct dmatest_params *params = param;
727f1aef8b6e6abf32a3a269542f95a19e2cb319f6cNicolas Ferre
728b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	if (!dmatest_match_channel(params, chan) ||
729b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	    !dmatest_match_device(params, chan->device))
730e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko		return false;
731f1aef8b6e6abf32a3a269542f95a19e2cb319f6cNicolas Ferre	else
732b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams		return true;
73358691d64c44ae41ddf098ecb31e9a994026e3cffDan Williams}
734e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko
735d07a74a546981a09ba490936645fbf0d1340b96cDr. David Alan Gilbertstatic int __run_threaded_test(struct dmatest_info *info)
73658691d64c44ae41ddf098ecb31e9a994026e3cffDan Williams{
737b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	dma_cap_mask_t mask;
7380adff800662f52d0ffc3e420db231769cb3fff13Dan Williams	struct dma_chan *chan;
739b54d5cb9156868fb4f27ccd46a3afb0bf3ef8e0cDan Williams	struct dmatest_params *params = &info->params;
7404a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	int err = 0;
741838cc704ce5c8ab2a6d64d1324e37e040fcae3d8Andy Shevchenko
742838cc704ce5c8ab2a6d64d1324e37e040fcae3d8Andy Shevchenko	dma_cap_zero(mask);
7434a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	dma_cap_set(DMA_MEMCPY, mask);
74433df8ca068123457db56c316946a3c0e4ef787d6Dan Williams	for (;;) {
7454a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		chan = dma_request_channel(mask, filter, params);
7464a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		if (chan) {
7477dd602510128d7a64b11ff3b7d4f30ac8e3946ceDan Williams			err = dmatest_add_channel(info, chan);
7484a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen			if (err) {
74915b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko				dma_release_channel(chan);
750e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko				break; /* add_channel failed, punt */
75115b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko			}
75215b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko		} else
7537dd602510128d7a64b11ff3b7d4f30ac8e3946ceDan Williams			break; /* no more channels available */
75433df8ca068123457db56c316946a3c0e4ef787d6Dan Williams		if (params->max_channels &&
7557dd602510128d7a64b11ff3b7d4f30ac8e3946ceDan Williams		    info->nr_channels >= params->max_channels)
7564a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen			break; /* we have all we need */
7574a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	}
758a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams	return err;
759a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams}
7604a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen
76133df8ca068123457db56c316946a3c0e4ef787d6Dan Williams#ifndef MODULE
762a310d037b8d06755c62bb4878c00d19490af5550Dan Williamsstatic int run_threaded_test(struct dmatest_info *info)
76333df8ca068123457db56c316946a3c0e4ef787d6Dan Williams{
764a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams	int ret;
76533df8ca068123457db56c316946a3c0e4ef787d6Dan Williams
766a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams	mutex_lock(&info->lock);
767a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams	ret = __run_threaded_test(info);
768a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams	mutex_unlock(&info->lock);
76915b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko	return ret;
77033df8ca068123457db56c316946a3c0e4ef787d6Dan Williams}
771a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams#endif
77233df8ca068123457db56c316946a3c0e4ef787d6Dan Williams
77333df8ca068123457db56c316946a3c0e4ef787d6Dan Williamsstatic void __stop_threaded_test(struct dmatest_info *info)
77433df8ca068123457db56c316946a3c0e4ef787d6Dan Williams{
77533df8ca068123457db56c316946a3c0e4ef787d6Dan Williams	struct dmatest_chan *dtc, *_dtc;
77633df8ca068123457db56c316946a3c0e4ef787d6Dan Williams	struct dma_chan *chan;
77715b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko
77815b8a8ea1a87313f1b46ea878c65942fd52147edAndy Shevchenko	list_for_each_entry_safe(dtc, _dtc, &info->channels, node) {
77933df8ca068123457db56c316946a3c0e4ef787d6Dan Williams		list_del(&dtc->node);
78033df8ca068123457db56c316946a3c0e4ef787d6Dan Williams		chan = dtc->chan;
7814a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		dmatest_cleanup_channel(dtc);
7824a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen		pr_debug("dmatest: dropped channel %s\n", dma_chan_name(chan));
783a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams		dma_release_channel(chan);
784a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams	}
785a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams
786a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams	info->nr_channels = 0;
787a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams}
788a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams
789a9e554957de406d6adc581731f571b8a1503f6b0Dan Williamsstatic void stop_threaded_test(struct dmatest_info *info)
790a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams{
791a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams	mutex_lock(&info->lock);
792a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams	__stop_threaded_test(info);
793a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams	mutex_unlock(&info->lock);
794a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams}
795a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams
796a9e554957de406d6adc581731f571b8a1503f6b0Dan Williamsstatic int __restart_threaded_test(struct dmatest_info *info, bool run)
797e3b9c347316fe243bea6abd08681050c43ca22eeDan Williams{
798a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams	struct dmatest_params *params = &info->params;
799a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams
800a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams	/* Stop any running test first */
801a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams	__stop_threaded_test(info);
802a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams
803851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenko	if (run == false)
804a310d037b8d06755c62bb4878c00d19490af5550Dan Williams		return 0;
8054a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen
80633df8ca068123457db56c316946a3c0e4ef787d6Dan Williams	/* Copy test parameters */
8077cbd4877e5b167b56a3d6033b926a9f925186e12Dan Williams	params->buf_size = test_buf_size;
80833df8ca068123457db56c316946a3c0e4ef787d6Dan Williams	strlcpy(params->channel, strim(test_channel), sizeof(params->channel));
809838cc704ce5c8ab2a6d64d1324e37e040fcae3d8Andy Shevchenko	strlcpy(params->device, strim(test_device), sizeof(params->device));
81033df8ca068123457db56c316946a3c0e4ef787d6Dan Williams	params->threads_per_chan = threads_per_chan;
8117cbd4877e5b167b56a3d6033b926a9f925186e12Dan Williams	params->max_channels = max_channels;
81233df8ca068123457db56c316946a3c0e4ef787d6Dan Williams	params->iterations = iterations;
8130adff800662f52d0ffc3e420db231769cb3fff13Dan Williams	params->xor_sources = xor_sources;
8147cbd4877e5b167b56a3d6033b926a9f925186e12Dan Williams	params->pq_sources = pq_sources;
81533df8ca068123457db56c316946a3c0e4ef787d6Dan Williams	params->timeout = timeout;
816838cc704ce5c8ab2a6d64d1324e37e040fcae3d8Andy Shevchenko
817838cc704ce5c8ab2a6d64d1324e37e040fcae3d8Andy Shevchenko	/* Run test with new parameters */
8184a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	return __run_threaded_test(info);
819e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko}
820a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams
821851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenkostatic bool __is_threaded_test_run(struct dmatest_info *info)
822a310d037b8d06755c62bb4878c00d19490af5550Dan Williams{
823a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	struct dmatest_chan *dtc;
824a310d037b8d06755c62bb4878c00d19490af5550Dan Williams
825a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	list_for_each_entry(dtc, &info->channels, node) {
826a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams		struct dmatest_thread *thread;
827851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenko
828a310d037b8d06755c62bb4878c00d19490af5550Dan Williams		list_for_each_entry(thread, &dtc->threads, node) {
829a310d037b8d06755c62bb4878c00d19490af5550Dan Williams			if (!thread->done)
830851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenko				return true;
831851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenko		}
832a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams	}
833bcc567e3115055a9cc256183d72864f01286be22Andy Shevchenko
834bcc567e3115055a9cc256183d72864f01286be22Andy Shevchenko	return false;
835a310d037b8d06755c62bb4878c00d19490af5550Dan Williams}
836bcc567e3115055a9cc256183d72864f01286be22Andy Shevchenko
837bcc567e3115055a9cc256183d72864f01286be22Andy Shevchenkostatic ssize_t dtf_read_run(struct file *file, char __user *user_buf,
838bcc567e3115055a9cc256183d72864f01286be22Andy Shevchenko		size_t count, loff_t *ppos)
839bcc567e3115055a9cc256183d72864f01286be22Andy Shevchenko{
840bcc567e3115055a9cc256183d72864f01286be22Andy Shevchenko	struct dmatest_info *info = file->private_data;
841bcc567e3115055a9cc256183d72864f01286be22Andy Shevchenko	char buf[3];
842bcc567e3115055a9cc256183d72864f01286be22Andy Shevchenko
843bcc567e3115055a9cc256183d72864f01286be22Andy Shevchenko	mutex_lock(&info->lock);
844bcc567e3115055a9cc256183d72864f01286be22Andy Shevchenko
845bcc567e3115055a9cc256183d72864f01286be22Andy Shevchenko	if (__is_threaded_test_run(info)) {
846851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenko		buf[0] = 'Y';
847851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenko	} else {
848bcc567e3115055a9cc256183d72864f01286be22Andy Shevchenko		__stop_threaded_test(info);
849851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenko		buf[0] = 'N';
850851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenko	}
851a310d037b8d06755c62bb4878c00d19490af5550Dan Williams
852851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenko	mutex_unlock(&info->lock);
853a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	buf[1] = '\n';
854851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenko	buf[2] = 0x00;
855851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenko	return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
856a310d037b8d06755c62bb4878c00d19490af5550Dan Williams}
857a310d037b8d06755c62bb4878c00d19490af5550Dan Williams
8583e5ccd866fdf3a1e1d4d2c08c81f861ad6798d32Andy Shevchenkostatic ssize_t dtf_write_run(struct file *file, const char __user *user_buf,
859a310d037b8d06755c62bb4878c00d19490af5550Dan Williams		size_t count, loff_t *ppos)
860a310d037b8d06755c62bb4878c00d19490af5550Dan Williams{
8613e5ccd866fdf3a1e1d4d2c08c81f861ad6798d32Andy Shevchenko	struct dmatest_info *info = file->private_data;
862851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenko	char buf[16];
863a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	bool bv;
864a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	int ret = 0;
865851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenko
866851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenko	if (copy_from_user(buf, user_buf, min(count, (sizeof(buf) - 1))))
867a310d037b8d06755c62bb4878c00d19490af5550Dan Williams		return -EFAULT;
868851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenko
869a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	if (strtobool(buf, &bv) == 0) {
870a310d037b8d06755c62bb4878c00d19490af5550Dan Williams		mutex_lock(&info->lock);
871bcc567e3115055a9cc256183d72864f01286be22Andy Shevchenko
872a310d037b8d06755c62bb4878c00d19490af5550Dan Williams		if (__is_threaded_test_run(info))
873a310d037b8d06755c62bb4878c00d19490af5550Dan Williams			ret = -EBUSY;
874a310d037b8d06755c62bb4878c00d19490af5550Dan Williams		else
875851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenko			ret = __restart_threaded_test(info, bv);
876a310d037b8d06755c62bb4878c00d19490af5550Dan Williams
877851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenko		mutex_unlock(&info->lock);
878851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenko	}
879a310d037b8d06755c62bb4878c00d19490af5550Dan Williams
880a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	return ret ? ret : count;
881a310d037b8d06755c62bb4878c00d19490af5550Dan Williams}
882a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams
883851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenkostatic const struct file_operations dtf_run_fops = {
884a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	.read	= dtf_read_run,
885851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenko	.write	= dtf_write_run,
886a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	.open	= simple_open,
887851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenko	.llseek	= default_llseek,
888851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenko};
889e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko
890e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenkostatic int dmatest_register_dbgfs(struct dmatest_info *info)
891e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko{
892e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko	struct dentry *d;
893a310d037b8d06755c62bb4878c00d19490af5550Dan Williams
894a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	d = debugfs_create_dir("dmatest", NULL);
895a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams	if (IS_ERR(d))
896a310d037b8d06755c62bb4878c00d19490af5550Dan Williams		return PTR_ERR(d);
897a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	if (!d)
898838cc704ce5c8ab2a6d64d1324e37e040fcae3d8Andy Shevchenko		goto err_root;
899a310d037b8d06755c62bb4878c00d19490af5550Dan Williams
900a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	info->root = d;
901a310d037b8d06755c62bb4878c00d19490af5550Dan Williams
902a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	/* Run or stop threaded test */
903851b7e16a07dfda6178d4e35fea9a9e3eb8954aeAndy Shevchenko	debugfs_create_file("run", S_IWUSR | S_IRUGO, info->root, info,
904a9e554957de406d6adc581731f571b8a1503f6b0Dan Williams			    &dtf_run_fops);
905e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko
906e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko	return 0;
907e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko
908e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenkoerr_root:
909e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko	pr_err("dmatest: Failed to initialize debugfs\n");
910e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko	return -ENOMEM;
911e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko}
912e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko
913a310d037b8d06755c62bb4878c00d19490af5550Dan Williamsstatic int __init dmatest_init(void)
914e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko{
915a310d037b8d06755c62bb4878c00d19490af5550Dan Williams	struct dmatest_info *info = &test_info;
916e03e93a976d0f0da63f02fd3384c4b99cac8d715Andy Shevchenko	int ret;
9174a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen
9184a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	memset(info, 0, sizeof(*info));
919e05503ef1186ad33dfe56794407891eb1dd93ef6Jean Delvare
9204a776f0aa922a552460192c07b56f4fe9cd82632Haavard Skinnemoen	mutex_init(&info->lock);
921	INIT_LIST_HEAD(&info->channels);
922
923	ret = dmatest_register_dbgfs(info);
924	if (ret)
925		return ret;
926
927#ifdef MODULE
928	return 0;
929#else
930	return run_threaded_test(info);
931#endif
932}
933/* when compiled-in wait for drivers to load first */
934late_initcall(dmatest_init);
935
936static void __exit dmatest_exit(void)
937{
938	struct dmatest_info *info = &test_info;
939
940	debugfs_remove_recursive(info->root);
941	stop_threaded_test(info);
942}
943module_exit(dmatest_exit);
944
945MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
946MODULE_LICENSE("GPL v2");
947