xref: /openbmc/linux/drivers/mmc/core/mmc_test.c (revision 5762451d)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2f397c8d8SUlf Hansson /*
3f397c8d8SUlf Hansson  *  Copyright 2007-2008 Pierre Ossman
4f397c8d8SUlf Hansson  */
5f397c8d8SUlf Hansson 
6f397c8d8SUlf Hansson #include <linux/mmc/core.h>
7f397c8d8SUlf Hansson #include <linux/mmc/card.h>
8f397c8d8SUlf Hansson #include <linux/mmc/host.h>
9f397c8d8SUlf Hansson #include <linux/mmc/mmc.h>
10f397c8d8SUlf Hansson #include <linux/slab.h>
11f397c8d8SUlf Hansson 
12f397c8d8SUlf Hansson #include <linux/scatterlist.h>
13f397c8d8SUlf Hansson #include <linux/list.h>
14f397c8d8SUlf Hansson 
15f397c8d8SUlf Hansson #include <linux/debugfs.h>
16f397c8d8SUlf Hansson #include <linux/uaccess.h>
17f397c8d8SUlf Hansson #include <linux/seq_file.h>
18f397c8d8SUlf Hansson #include <linux/module.h>
19f397c8d8SUlf Hansson 
2055244c56SUlf Hansson #include "core.h"
214facdde1SUlf Hansson #include "card.h"
225857b29bSUlf Hansson #include "host.h"
234facdde1SUlf Hansson #include "bus.h"
249d4579a8SAdrian Hunter #include "mmc_ops.h"
2555244c56SUlf Hansson 
26f397c8d8SUlf Hansson #define RESULT_OK		0
27f397c8d8SUlf Hansson #define RESULT_FAIL		1
28f397c8d8SUlf Hansson #define RESULT_UNSUP_HOST	2
29f397c8d8SUlf Hansson #define RESULT_UNSUP_CARD	3
30f397c8d8SUlf Hansson 
31f397c8d8SUlf Hansson #define BUFFER_ORDER		2
32f397c8d8SUlf Hansson #define BUFFER_SIZE		(PAGE_SIZE << BUFFER_ORDER)
33f397c8d8SUlf Hansson 
34f397c8d8SUlf Hansson #define TEST_ALIGN_END		8
35f397c8d8SUlf Hansson 
36f397c8d8SUlf Hansson /*
37f397c8d8SUlf Hansson  * Limit the test area size to the maximum MMC HC erase group size.  Note that
38f397c8d8SUlf Hansson  * the maximum SD allocation unit size is just 4MiB.
39f397c8d8SUlf Hansson  */
40f397c8d8SUlf Hansson #define TEST_AREA_MAX_SIZE (128 * 1024 * 1024)
41f397c8d8SUlf Hansson 
42f397c8d8SUlf Hansson /**
43f397c8d8SUlf Hansson  * struct mmc_test_pages - pages allocated by 'alloc_pages()'.
44f397c8d8SUlf Hansson  * @page: first page in the allocation
45f397c8d8SUlf Hansson  * @order: order of the number of pages allocated
46f397c8d8SUlf Hansson  */
47f397c8d8SUlf Hansson struct mmc_test_pages {
48f397c8d8SUlf Hansson 	struct page *page;
49f397c8d8SUlf Hansson 	unsigned int order;
50f397c8d8SUlf Hansson };
51f397c8d8SUlf Hansson 
52f397c8d8SUlf Hansson /**
53f397c8d8SUlf Hansson  * struct mmc_test_mem - allocated memory.
54f397c8d8SUlf Hansson  * @arr: array of allocations
55f397c8d8SUlf Hansson  * @cnt: number of allocations
56f397c8d8SUlf Hansson  */
57f397c8d8SUlf Hansson struct mmc_test_mem {
58f397c8d8SUlf Hansson 	struct mmc_test_pages *arr;
59f397c8d8SUlf Hansson 	unsigned int cnt;
60f397c8d8SUlf Hansson };
61f397c8d8SUlf Hansson 
62f397c8d8SUlf Hansson /**
63f397c8d8SUlf Hansson  * struct mmc_test_area - information for performance tests.
64f397c8d8SUlf Hansson  * @max_sz: test area size (in bytes)
65f397c8d8SUlf Hansson  * @dev_addr: address on card at which to do performance tests
66f397c8d8SUlf Hansson  * @max_tfr: maximum transfer size allowed by driver (in bytes)
67f397c8d8SUlf Hansson  * @max_segs: maximum segments allowed by driver in scatterlist @sg
68f397c8d8SUlf Hansson  * @max_seg_sz: maximum segment size allowed by driver
69f397c8d8SUlf Hansson  * @blocks: number of (512 byte) blocks currently mapped by @sg
70f397c8d8SUlf Hansson  * @sg_len: length of currently mapped scatterlist @sg
71f397c8d8SUlf Hansson  * @mem: allocated memory
72f397c8d8SUlf Hansson  * @sg: scatterlist
73ea21e9b2SVeerabhadrarao Badiganti  * @sg_areq: scatterlist for non-blocking request
74f397c8d8SUlf Hansson  */
75f397c8d8SUlf Hansson struct mmc_test_area {
76f397c8d8SUlf Hansson 	unsigned long max_sz;
77f397c8d8SUlf Hansson 	unsigned int dev_addr;
78f397c8d8SUlf Hansson 	unsigned int max_tfr;
79f397c8d8SUlf Hansson 	unsigned int max_segs;
80f397c8d8SUlf Hansson 	unsigned int max_seg_sz;
81f397c8d8SUlf Hansson 	unsigned int blocks;
82f397c8d8SUlf Hansson 	unsigned int sg_len;
83f397c8d8SUlf Hansson 	struct mmc_test_mem *mem;
84f397c8d8SUlf Hansson 	struct scatterlist *sg;
85ea21e9b2SVeerabhadrarao Badiganti 	struct scatterlist *sg_areq;
86f397c8d8SUlf Hansson };
87f397c8d8SUlf Hansson 
88f397c8d8SUlf Hansson /**
89f397c8d8SUlf Hansson  * struct mmc_test_transfer_result - transfer results for performance tests.
90f397c8d8SUlf Hansson  * @link: double-linked list
91f397c8d8SUlf Hansson  * @count: amount of group of sectors to check
92f397c8d8SUlf Hansson  * @sectors: amount of sectors to check in one group
93f397c8d8SUlf Hansson  * @ts: time values of transfer
94f397c8d8SUlf Hansson  * @rate: calculated transfer rate
95f397c8d8SUlf Hansson  * @iops: I/O operations per second (times 100)
96f397c8d8SUlf Hansson  */
97f397c8d8SUlf Hansson struct mmc_test_transfer_result {
98f397c8d8SUlf Hansson 	struct list_head link;
99f397c8d8SUlf Hansson 	unsigned int count;
100f397c8d8SUlf Hansson 	unsigned int sectors;
101a5b97be2SArnd Bergmann 	struct timespec64 ts;
102f397c8d8SUlf Hansson 	unsigned int rate;
103f397c8d8SUlf Hansson 	unsigned int iops;
104f397c8d8SUlf Hansson };
105f397c8d8SUlf Hansson 
106f397c8d8SUlf Hansson /**
107f397c8d8SUlf Hansson  * struct mmc_test_general_result - results for tests.
108f397c8d8SUlf Hansson  * @link: double-linked list
109f397c8d8SUlf Hansson  * @card: card under test
110f397c8d8SUlf Hansson  * @testcase: number of test case
111f397c8d8SUlf Hansson  * @result: result of test run
112f397c8d8SUlf Hansson  * @tr_lst: transfer measurements if any as mmc_test_transfer_result
113f397c8d8SUlf Hansson  */
114f397c8d8SUlf Hansson struct mmc_test_general_result {
115f397c8d8SUlf Hansson 	struct list_head link;
116f397c8d8SUlf Hansson 	struct mmc_card *card;
117f397c8d8SUlf Hansson 	int testcase;
118f397c8d8SUlf Hansson 	int result;
119f397c8d8SUlf Hansson 	struct list_head tr_lst;
120f397c8d8SUlf Hansson };
121f397c8d8SUlf Hansson 
122f397c8d8SUlf Hansson /**
123f397c8d8SUlf Hansson  * struct mmc_test_dbgfs_file - debugfs related file.
124f397c8d8SUlf Hansson  * @link: double-linked list
125f397c8d8SUlf Hansson  * @card: card under test
126f397c8d8SUlf Hansson  * @file: file created under debugfs
127f397c8d8SUlf Hansson  */
128f397c8d8SUlf Hansson struct mmc_test_dbgfs_file {
129f397c8d8SUlf Hansson 	struct list_head link;
130f397c8d8SUlf Hansson 	struct mmc_card *card;
131f397c8d8SUlf Hansson 	struct dentry *file;
132f397c8d8SUlf Hansson };
133f397c8d8SUlf Hansson 
134f397c8d8SUlf Hansson /**
135f397c8d8SUlf Hansson  * struct mmc_test_card - test information.
136f397c8d8SUlf Hansson  * @card: card under test
137f397c8d8SUlf Hansson  * @scratch: transfer buffer
138f397c8d8SUlf Hansson  * @buffer: transfer buffer
139f397c8d8SUlf Hansson  * @highmem: buffer for highmem tests
140f397c8d8SUlf Hansson  * @area: information for performance tests
141f397c8d8SUlf Hansson  * @gr: pointer to results of current testcase
142f397c8d8SUlf Hansson  */
143f397c8d8SUlf Hansson struct mmc_test_card {
144f397c8d8SUlf Hansson 	struct mmc_card	*card;
145f397c8d8SUlf Hansson 
146f397c8d8SUlf Hansson 	u8		scratch[BUFFER_SIZE];
147f397c8d8SUlf Hansson 	u8		*buffer;
148f397c8d8SUlf Hansson #ifdef CONFIG_HIGHMEM
149f397c8d8SUlf Hansson 	struct page	*highmem;
150f397c8d8SUlf Hansson #endif
151f397c8d8SUlf Hansson 	struct mmc_test_area		area;
152f397c8d8SUlf Hansson 	struct mmc_test_general_result	*gr;
153f397c8d8SUlf Hansson };
154f397c8d8SUlf Hansson 
155f397c8d8SUlf Hansson enum mmc_test_prep_media {
156f397c8d8SUlf Hansson 	MMC_TEST_PREP_NONE = 0,
157f397c8d8SUlf Hansson 	MMC_TEST_PREP_WRITE_FULL = 1 << 0,
158f397c8d8SUlf Hansson 	MMC_TEST_PREP_ERASE = 1 << 1,
159f397c8d8SUlf Hansson };
160f397c8d8SUlf Hansson 
161f397c8d8SUlf Hansson struct mmc_test_multiple_rw {
162f397c8d8SUlf Hansson 	unsigned int *sg_len;
163f397c8d8SUlf Hansson 	unsigned int *bs;
164f397c8d8SUlf Hansson 	unsigned int len;
165f397c8d8SUlf Hansson 	unsigned int size;
166f397c8d8SUlf Hansson 	bool do_write;
167f397c8d8SUlf Hansson 	bool do_nonblock_req;
168f397c8d8SUlf Hansson 	enum mmc_test_prep_media prepare;
169f397c8d8SUlf Hansson };
170f397c8d8SUlf Hansson 
171f397c8d8SUlf Hansson /*******************************************************************/
172f397c8d8SUlf Hansson /*  General helper functions                                       */
173f397c8d8SUlf Hansson /*******************************************************************/
174f397c8d8SUlf Hansson 
175f397c8d8SUlf Hansson /*
176f397c8d8SUlf Hansson  * Configure correct block size in card
177f397c8d8SUlf Hansson  */
mmc_test_set_blksize(struct mmc_test_card * test,unsigned size)178f397c8d8SUlf Hansson static int mmc_test_set_blksize(struct mmc_test_card *test, unsigned size)
179f397c8d8SUlf Hansson {
180f397c8d8SUlf Hansson 	return mmc_set_blocklen(test->card, size);
181f397c8d8SUlf Hansson }
182f397c8d8SUlf Hansson 
mmc_test_card_cmd23(struct mmc_card * card)183f397c8d8SUlf Hansson static bool mmc_test_card_cmd23(struct mmc_card *card)
184f397c8d8SUlf Hansson {
185f397c8d8SUlf Hansson 	return mmc_card_mmc(card) ||
186f397c8d8SUlf Hansson 	       (mmc_card_sd(card) && card->scr.cmds & SD_SCR_CMD23_SUPPORT);
187f397c8d8SUlf Hansson }
188f397c8d8SUlf Hansson 
mmc_test_prepare_sbc(struct mmc_test_card * test,struct mmc_request * mrq,unsigned int blocks)189f397c8d8SUlf Hansson static void mmc_test_prepare_sbc(struct mmc_test_card *test,
190f397c8d8SUlf Hansson 				 struct mmc_request *mrq, unsigned int blocks)
191f397c8d8SUlf Hansson {
192f397c8d8SUlf Hansson 	struct mmc_card *card = test->card;
193f397c8d8SUlf Hansson 
194f397c8d8SUlf Hansson 	if (!mrq->sbc || !mmc_host_cmd23(card->host) ||
195f397c8d8SUlf Hansson 	    !mmc_test_card_cmd23(card) || !mmc_op_multi(mrq->cmd->opcode) ||
196f397c8d8SUlf Hansson 	    (card->quirks & MMC_QUIRK_BLK_NO_CMD23)) {
197f397c8d8SUlf Hansson 		mrq->sbc = NULL;
198f397c8d8SUlf Hansson 		return;
199f397c8d8SUlf Hansson 	}
200f397c8d8SUlf Hansson 
201f397c8d8SUlf Hansson 	mrq->sbc->opcode = MMC_SET_BLOCK_COUNT;
202f397c8d8SUlf Hansson 	mrq->sbc->arg = blocks;
203f397c8d8SUlf Hansson 	mrq->sbc->flags = MMC_RSP_R1 | MMC_CMD_AC;
204f397c8d8SUlf Hansson }
205f397c8d8SUlf Hansson 
206f397c8d8SUlf Hansson /*
207f397c8d8SUlf Hansson  * Fill in the mmc_request structure given a set of transfer parameters.
208f397c8d8SUlf Hansson  */
mmc_test_prepare_mrq(struct mmc_test_card * test,struct mmc_request * mrq,struct scatterlist * sg,unsigned sg_len,unsigned dev_addr,unsigned blocks,unsigned blksz,int write)209f397c8d8SUlf Hansson static void mmc_test_prepare_mrq(struct mmc_test_card *test,
210f397c8d8SUlf Hansson 	struct mmc_request *mrq, struct scatterlist *sg, unsigned sg_len,
211f397c8d8SUlf Hansson 	unsigned dev_addr, unsigned blocks, unsigned blksz, int write)
212f397c8d8SUlf Hansson {
213f397c8d8SUlf Hansson 	if (WARN_ON(!mrq || !mrq->cmd || !mrq->data || !mrq->stop))
214f397c8d8SUlf Hansson 		return;
215f397c8d8SUlf Hansson 
216f397c8d8SUlf Hansson 	if (blocks > 1) {
217f397c8d8SUlf Hansson 		mrq->cmd->opcode = write ?
218f397c8d8SUlf Hansson 			MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK;
219f397c8d8SUlf Hansson 	} else {
220f397c8d8SUlf Hansson 		mrq->cmd->opcode = write ?
221f397c8d8SUlf Hansson 			MMC_WRITE_BLOCK : MMC_READ_SINGLE_BLOCK;
222f397c8d8SUlf Hansson 	}
223f397c8d8SUlf Hansson 
224f397c8d8SUlf Hansson 	mrq->cmd->arg = dev_addr;
225f397c8d8SUlf Hansson 	if (!mmc_card_blockaddr(test->card))
226f397c8d8SUlf Hansson 		mrq->cmd->arg <<= 9;
227f397c8d8SUlf Hansson 
228f397c8d8SUlf Hansson 	mrq->cmd->flags = MMC_RSP_R1 | MMC_CMD_ADTC;
229f397c8d8SUlf Hansson 
230f397c8d8SUlf Hansson 	if (blocks == 1)
231f397c8d8SUlf Hansson 		mrq->stop = NULL;
232f397c8d8SUlf Hansson 	else {
233f397c8d8SUlf Hansson 		mrq->stop->opcode = MMC_STOP_TRANSMISSION;
234f397c8d8SUlf Hansson 		mrq->stop->arg = 0;
235f397c8d8SUlf Hansson 		mrq->stop->flags = MMC_RSP_R1B | MMC_CMD_AC;
236f397c8d8SUlf Hansson 	}
237f397c8d8SUlf Hansson 
238f397c8d8SUlf Hansson 	mrq->data->blksz = blksz;
239f397c8d8SUlf Hansson 	mrq->data->blocks = blocks;
240f397c8d8SUlf Hansson 	mrq->data->flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
241f397c8d8SUlf Hansson 	mrq->data->sg = sg;
242f397c8d8SUlf Hansson 	mrq->data->sg_len = sg_len;
243f397c8d8SUlf Hansson 
244f397c8d8SUlf Hansson 	mmc_test_prepare_sbc(test, mrq, blocks);
245f397c8d8SUlf Hansson 
246f397c8d8SUlf Hansson 	mmc_set_data_timeout(mrq->data, test->card);
247f397c8d8SUlf Hansson }
248f397c8d8SUlf Hansson 
mmc_test_busy(struct mmc_command * cmd)249f397c8d8SUlf Hansson static int mmc_test_busy(struct mmc_command *cmd)
250f397c8d8SUlf Hansson {
251f397c8d8SUlf Hansson 	return !(cmd->resp[0] & R1_READY_FOR_DATA) ||
252f397c8d8SUlf Hansson 		(R1_CURRENT_STATE(cmd->resp[0]) == R1_STATE_PRG);
253f397c8d8SUlf Hansson }
254f397c8d8SUlf Hansson 
255f397c8d8SUlf Hansson /*
256f397c8d8SUlf Hansson  * Wait for the card to finish the busy state
257f397c8d8SUlf Hansson  */
mmc_test_wait_busy(struct mmc_test_card * test)258f397c8d8SUlf Hansson static int mmc_test_wait_busy(struct mmc_test_card *test)
259f397c8d8SUlf Hansson {
260f397c8d8SUlf Hansson 	int ret, busy;
261c7836d15SMasahiro Yamada 	struct mmc_command cmd = {};
262f397c8d8SUlf Hansson 
263f397c8d8SUlf Hansson 	busy = 0;
264f397c8d8SUlf Hansson 	do {
265f397c8d8SUlf Hansson 		memset(&cmd, 0, sizeof(struct mmc_command));
266f397c8d8SUlf Hansson 
267f397c8d8SUlf Hansson 		cmd.opcode = MMC_SEND_STATUS;
268f397c8d8SUlf Hansson 		cmd.arg = test->card->rca << 16;
269f397c8d8SUlf Hansson 		cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
270f397c8d8SUlf Hansson 
271f397c8d8SUlf Hansson 		ret = mmc_wait_for_cmd(test->card->host, &cmd, 0);
272f397c8d8SUlf Hansson 		if (ret)
273f397c8d8SUlf Hansson 			break;
274f397c8d8SUlf Hansson 
275f397c8d8SUlf Hansson 		if (!busy && mmc_test_busy(&cmd)) {
276f397c8d8SUlf Hansson 			busy = 1;
277f397c8d8SUlf Hansson 			if (test->card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)
2787200449dSMarkus Elfring 				pr_info("%s: Warning: Host did not wait for busy state to end.\n",
279f397c8d8SUlf Hansson 					mmc_hostname(test->card->host));
280f397c8d8SUlf Hansson 		}
281f397c8d8SUlf Hansson 	} while (mmc_test_busy(&cmd));
282f397c8d8SUlf Hansson 
283f397c8d8SUlf Hansson 	return ret;
284f397c8d8SUlf Hansson }
285f397c8d8SUlf Hansson 
286f397c8d8SUlf Hansson /*
287f397c8d8SUlf Hansson  * Transfer a single sector of kernel addressable data
288f397c8d8SUlf Hansson  */
mmc_test_buffer_transfer(struct mmc_test_card * test,u8 * buffer,unsigned addr,unsigned blksz,int write)289f397c8d8SUlf Hansson static int mmc_test_buffer_transfer(struct mmc_test_card *test,
290f397c8d8SUlf Hansson 	u8 *buffer, unsigned addr, unsigned blksz, int write)
291f397c8d8SUlf Hansson {
292c7836d15SMasahiro Yamada 	struct mmc_request mrq = {};
293c7836d15SMasahiro Yamada 	struct mmc_command cmd = {};
294c7836d15SMasahiro Yamada 	struct mmc_command stop = {};
295c7836d15SMasahiro Yamada 	struct mmc_data data = {};
296f397c8d8SUlf Hansson 
297f397c8d8SUlf Hansson 	struct scatterlist sg;
298f397c8d8SUlf Hansson 
299f397c8d8SUlf Hansson 	mrq.cmd = &cmd;
300f397c8d8SUlf Hansson 	mrq.data = &data;
301f397c8d8SUlf Hansson 	mrq.stop = &stop;
302f397c8d8SUlf Hansson 
303f397c8d8SUlf Hansson 	sg_init_one(&sg, buffer, blksz);
304f397c8d8SUlf Hansson 
305f397c8d8SUlf Hansson 	mmc_test_prepare_mrq(test, &mrq, &sg, 1, addr, 1, blksz, write);
306f397c8d8SUlf Hansson 
307f397c8d8SUlf Hansson 	mmc_wait_for_req(test->card->host, &mrq);
308f397c8d8SUlf Hansson 
309f397c8d8SUlf Hansson 	if (cmd.error)
310f397c8d8SUlf Hansson 		return cmd.error;
311f397c8d8SUlf Hansson 	if (data.error)
312f397c8d8SUlf Hansson 		return data.error;
313f397c8d8SUlf Hansson 
314f397c8d8SUlf Hansson 	return mmc_test_wait_busy(test);
315f397c8d8SUlf Hansson }
316f397c8d8SUlf Hansson 
mmc_test_free_mem(struct mmc_test_mem * mem)317f397c8d8SUlf Hansson static void mmc_test_free_mem(struct mmc_test_mem *mem)
318f397c8d8SUlf Hansson {
319f397c8d8SUlf Hansson 	if (!mem)
320f397c8d8SUlf Hansson 		return;
321f397c8d8SUlf Hansson 	while (mem->cnt--)
322f397c8d8SUlf Hansson 		__free_pages(mem->arr[mem->cnt].page,
323f397c8d8SUlf Hansson 			     mem->arr[mem->cnt].order);
324f397c8d8SUlf Hansson 	kfree(mem->arr);
325f397c8d8SUlf Hansson 	kfree(mem);
326f397c8d8SUlf Hansson }
327f397c8d8SUlf Hansson 
328f397c8d8SUlf Hansson /*
329f397c8d8SUlf Hansson  * Allocate a lot of memory, preferably max_sz but at least min_sz.  In case
330f397c8d8SUlf Hansson  * there isn't much memory do not exceed 1/16th total lowmem pages.  Also do
331f397c8d8SUlf Hansson  * not exceed a maximum number of segments and try not to make segments much
332f397c8d8SUlf Hansson  * bigger than maximum segment size.
333f397c8d8SUlf Hansson  */
mmc_test_alloc_mem(unsigned long min_sz,unsigned long max_sz,unsigned int max_segs,unsigned int max_seg_sz)334f397c8d8SUlf Hansson static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz,
335f397c8d8SUlf Hansson 					       unsigned long max_sz,
336f397c8d8SUlf Hansson 					       unsigned int max_segs,
337f397c8d8SUlf Hansson 					       unsigned int max_seg_sz)
338f397c8d8SUlf Hansson {
339f397c8d8SUlf Hansson 	unsigned long max_page_cnt = DIV_ROUND_UP(max_sz, PAGE_SIZE);
340f397c8d8SUlf Hansson 	unsigned long min_page_cnt = DIV_ROUND_UP(min_sz, PAGE_SIZE);
341f397c8d8SUlf Hansson 	unsigned long max_seg_page_cnt = DIV_ROUND_UP(max_seg_sz, PAGE_SIZE);
342f397c8d8SUlf Hansson 	unsigned long page_cnt = 0;
343f397c8d8SUlf Hansson 	unsigned long limit = nr_free_buffer_pages() >> 4;
344f397c8d8SUlf Hansson 	struct mmc_test_mem *mem;
345f397c8d8SUlf Hansson 
346f397c8d8SUlf Hansson 	if (max_page_cnt > limit)
347f397c8d8SUlf Hansson 		max_page_cnt = limit;
348f397c8d8SUlf Hansson 	if (min_page_cnt > max_page_cnt)
349f397c8d8SUlf Hansson 		min_page_cnt = max_page_cnt;
350f397c8d8SUlf Hansson 
351f397c8d8SUlf Hansson 	if (max_seg_page_cnt > max_page_cnt)
352f397c8d8SUlf Hansson 		max_seg_page_cnt = max_page_cnt;
353f397c8d8SUlf Hansson 
354f397c8d8SUlf Hansson 	if (max_segs > max_page_cnt)
355f397c8d8SUlf Hansson 		max_segs = max_page_cnt;
356f397c8d8SUlf Hansson 
357554d7c54SMarkus Elfring 	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
358f397c8d8SUlf Hansson 	if (!mem)
359f397c8d8SUlf Hansson 		return NULL;
360f397c8d8SUlf Hansson 
3613972a20bSMarkus Elfring 	mem->arr = kcalloc(max_segs, sizeof(*mem->arr), GFP_KERNEL);
362f397c8d8SUlf Hansson 	if (!mem->arr)
363f397c8d8SUlf Hansson 		goto out_free;
364f397c8d8SUlf Hansson 
365f397c8d8SUlf Hansson 	while (max_page_cnt) {
366f397c8d8SUlf Hansson 		struct page *page;
367f397c8d8SUlf Hansson 		unsigned int order;
368f397c8d8SUlf Hansson 		gfp_t flags = GFP_KERNEL | GFP_DMA | __GFP_NOWARN |
369f397c8d8SUlf Hansson 				__GFP_NORETRY;
370f397c8d8SUlf Hansson 
371f397c8d8SUlf Hansson 		order = get_order(max_seg_page_cnt << PAGE_SHIFT);
372f397c8d8SUlf Hansson 		while (1) {
373f397c8d8SUlf Hansson 			page = alloc_pages(flags, order);
374f397c8d8SUlf Hansson 			if (page || !order)
375f397c8d8SUlf Hansson 				break;
376f397c8d8SUlf Hansson 			order -= 1;
377f397c8d8SUlf Hansson 		}
378f397c8d8SUlf Hansson 		if (!page) {
379f397c8d8SUlf Hansson 			if (page_cnt < min_page_cnt)
380f397c8d8SUlf Hansson 				goto out_free;
381f397c8d8SUlf Hansson 			break;
382f397c8d8SUlf Hansson 		}
383f397c8d8SUlf Hansson 		mem->arr[mem->cnt].page = page;
384f397c8d8SUlf Hansson 		mem->arr[mem->cnt].order = order;
385f397c8d8SUlf Hansson 		mem->cnt += 1;
386f397c8d8SUlf Hansson 		if (max_page_cnt <= (1UL << order))
387f397c8d8SUlf Hansson 			break;
388f397c8d8SUlf Hansson 		max_page_cnt -= 1UL << order;
389f397c8d8SUlf Hansson 		page_cnt += 1UL << order;
390f397c8d8SUlf Hansson 		if (mem->cnt >= max_segs) {
391f397c8d8SUlf Hansson 			if (page_cnt < min_page_cnt)
392f397c8d8SUlf Hansson 				goto out_free;
393f397c8d8SUlf Hansson 			break;
394f397c8d8SUlf Hansson 		}
395f397c8d8SUlf Hansson 	}
396f397c8d8SUlf Hansson 
397f397c8d8SUlf Hansson 	return mem;
398f397c8d8SUlf Hansson 
399f397c8d8SUlf Hansson out_free:
400f397c8d8SUlf Hansson 	mmc_test_free_mem(mem);
401f397c8d8SUlf Hansson 	return NULL;
402f397c8d8SUlf Hansson }
403f397c8d8SUlf Hansson 
404f397c8d8SUlf Hansson /*
405f397c8d8SUlf Hansson  * Map memory into a scatterlist.  Optionally allow the same memory to be
406f397c8d8SUlf Hansson  * mapped more than once.
407f397c8d8SUlf Hansson  */
mmc_test_map_sg(struct mmc_test_mem * mem,unsigned long size,struct scatterlist * sglist,int repeat,unsigned int max_segs,unsigned int max_seg_sz,unsigned int * sg_len,int min_sg_len)408f397c8d8SUlf Hansson static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long size,
409f397c8d8SUlf Hansson 			   struct scatterlist *sglist, int repeat,
410f397c8d8SUlf Hansson 			   unsigned int max_segs, unsigned int max_seg_sz,
411f397c8d8SUlf Hansson 			   unsigned int *sg_len, int min_sg_len)
412f397c8d8SUlf Hansson {
413f397c8d8SUlf Hansson 	struct scatterlist *sg = NULL;
414f397c8d8SUlf Hansson 	unsigned int i;
415f397c8d8SUlf Hansson 	unsigned long sz = size;
416f397c8d8SUlf Hansson 
417f397c8d8SUlf Hansson 	sg_init_table(sglist, max_segs);
418f397c8d8SUlf Hansson 	if (min_sg_len > max_segs)
419f397c8d8SUlf Hansson 		min_sg_len = max_segs;
420f397c8d8SUlf Hansson 
421f397c8d8SUlf Hansson 	*sg_len = 0;
422f397c8d8SUlf Hansson 	do {
423f397c8d8SUlf Hansson 		for (i = 0; i < mem->cnt; i++) {
424f397c8d8SUlf Hansson 			unsigned long len = PAGE_SIZE << mem->arr[i].order;
425f397c8d8SUlf Hansson 
426f397c8d8SUlf Hansson 			if (min_sg_len && (size / min_sg_len < len))
427f397c8d8SUlf Hansson 				len = ALIGN(size / min_sg_len, 512);
428f397c8d8SUlf Hansson 			if (len > sz)
429f397c8d8SUlf Hansson 				len = sz;
430f397c8d8SUlf Hansson 			if (len > max_seg_sz)
431f397c8d8SUlf Hansson 				len = max_seg_sz;
432f397c8d8SUlf Hansson 			if (sg)
433f397c8d8SUlf Hansson 				sg = sg_next(sg);
434f397c8d8SUlf Hansson 			else
435f397c8d8SUlf Hansson 				sg = sglist;
436f397c8d8SUlf Hansson 			if (!sg)
437f397c8d8SUlf Hansson 				return -EINVAL;
438f397c8d8SUlf Hansson 			sg_set_page(sg, mem->arr[i].page, len, 0);
439f397c8d8SUlf Hansson 			sz -= len;
440f397c8d8SUlf Hansson 			*sg_len += 1;
441f397c8d8SUlf Hansson 			if (!sz)
442f397c8d8SUlf Hansson 				break;
443f397c8d8SUlf Hansson 		}
444f397c8d8SUlf Hansson 	} while (sz && repeat);
445f397c8d8SUlf Hansson 
446f397c8d8SUlf Hansson 	if (sz)
447f397c8d8SUlf Hansson 		return -EINVAL;
448f397c8d8SUlf Hansson 
449f397c8d8SUlf Hansson 	if (sg)
450f397c8d8SUlf Hansson 		sg_mark_end(sg);
451f397c8d8SUlf Hansson 
452f397c8d8SUlf Hansson 	return 0;
453f397c8d8SUlf Hansson }
454f397c8d8SUlf Hansson 
455f397c8d8SUlf Hansson /*
456f397c8d8SUlf Hansson  * Map memory into a scatterlist so that no pages are contiguous.  Allow the
457f397c8d8SUlf Hansson  * same memory to be mapped more than once.
458f397c8d8SUlf Hansson  */
mmc_test_map_sg_max_scatter(struct mmc_test_mem * mem,unsigned long sz,struct scatterlist * sglist,unsigned int max_segs,unsigned int max_seg_sz,unsigned int * sg_len)459f397c8d8SUlf Hansson static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem,
460f397c8d8SUlf Hansson 				       unsigned long sz,
461f397c8d8SUlf Hansson 				       struct scatterlist *sglist,
462f397c8d8SUlf Hansson 				       unsigned int max_segs,
463f397c8d8SUlf Hansson 				       unsigned int max_seg_sz,
464f397c8d8SUlf Hansson 				       unsigned int *sg_len)
465f397c8d8SUlf Hansson {
466f397c8d8SUlf Hansson 	struct scatterlist *sg = NULL;
467f397c8d8SUlf Hansson 	unsigned int i = mem->cnt, cnt;
468f397c8d8SUlf Hansson 	unsigned long len;
469f397c8d8SUlf Hansson 	void *base, *addr, *last_addr = NULL;
470f397c8d8SUlf Hansson 
471f397c8d8SUlf Hansson 	sg_init_table(sglist, max_segs);
472f397c8d8SUlf Hansson 
473f397c8d8SUlf Hansson 	*sg_len = 0;
474f397c8d8SUlf Hansson 	while (sz) {
475f397c8d8SUlf Hansson 		base = page_address(mem->arr[--i].page);
476f397c8d8SUlf Hansson 		cnt = 1 << mem->arr[i].order;
477f397c8d8SUlf Hansson 		while (sz && cnt) {
478f397c8d8SUlf Hansson 			addr = base + PAGE_SIZE * --cnt;
479f397c8d8SUlf Hansson 			if (last_addr && last_addr + PAGE_SIZE == addr)
480f397c8d8SUlf Hansson 				continue;
481f397c8d8SUlf Hansson 			last_addr = addr;
482f397c8d8SUlf Hansson 			len = PAGE_SIZE;
483f397c8d8SUlf Hansson 			if (len > max_seg_sz)
484f397c8d8SUlf Hansson 				len = max_seg_sz;
485f397c8d8SUlf Hansson 			if (len > sz)
486f397c8d8SUlf Hansson 				len = sz;
487f397c8d8SUlf Hansson 			if (sg)
488f397c8d8SUlf Hansson 				sg = sg_next(sg);
489f397c8d8SUlf Hansson 			else
490f397c8d8SUlf Hansson 				sg = sglist;
491f397c8d8SUlf Hansson 			if (!sg)
492f397c8d8SUlf Hansson 				return -EINVAL;
493f397c8d8SUlf Hansson 			sg_set_page(sg, virt_to_page(addr), len, 0);
494f397c8d8SUlf Hansson 			sz -= len;
495f397c8d8SUlf Hansson 			*sg_len += 1;
496f397c8d8SUlf Hansson 		}
497f397c8d8SUlf Hansson 		if (i == 0)
498f397c8d8SUlf Hansson 			i = mem->cnt;
499f397c8d8SUlf Hansson 	}
500f397c8d8SUlf Hansson 
501f397c8d8SUlf Hansson 	if (sg)
502f397c8d8SUlf Hansson 		sg_mark_end(sg);
503f397c8d8SUlf Hansson 
504f397c8d8SUlf Hansson 	return 0;
505f397c8d8SUlf Hansson }
506f397c8d8SUlf Hansson 
507f397c8d8SUlf Hansson /*
508f397c8d8SUlf Hansson  * Calculate transfer rate in bytes per second.
509f397c8d8SUlf Hansson  */
mmc_test_rate(uint64_t bytes,struct timespec64 * ts)510a5b97be2SArnd Bergmann static unsigned int mmc_test_rate(uint64_t bytes, struct timespec64 *ts)
511f397c8d8SUlf Hansson {
512f397c8d8SUlf Hansson 	uint64_t ns;
513f397c8d8SUlf Hansson 
514a5b97be2SArnd Bergmann 	ns = timespec64_to_ns(ts);
515f397c8d8SUlf Hansson 	bytes *= 1000000000;
516f397c8d8SUlf Hansson 
517f397c8d8SUlf Hansson 	while (ns > UINT_MAX) {
518f397c8d8SUlf Hansson 		bytes >>= 1;
519f397c8d8SUlf Hansson 		ns >>= 1;
520f397c8d8SUlf Hansson 	}
521f397c8d8SUlf Hansson 
522f397c8d8SUlf Hansson 	if (!ns)
523f397c8d8SUlf Hansson 		return 0;
524f397c8d8SUlf Hansson 
525f397c8d8SUlf Hansson 	do_div(bytes, (uint32_t)ns);
526f397c8d8SUlf Hansson 
527f397c8d8SUlf Hansson 	return bytes;
528f397c8d8SUlf Hansson }
529f397c8d8SUlf Hansson 
530f397c8d8SUlf Hansson /*
531f397c8d8SUlf Hansson  * Save transfer results for future usage
532f397c8d8SUlf Hansson  */
mmc_test_save_transfer_result(struct mmc_test_card * test,unsigned int count,unsigned int sectors,struct timespec64 ts,unsigned int rate,unsigned int iops)533f397c8d8SUlf Hansson static void mmc_test_save_transfer_result(struct mmc_test_card *test,
534a5b97be2SArnd Bergmann 	unsigned int count, unsigned int sectors, struct timespec64 ts,
535f397c8d8SUlf Hansson 	unsigned int rate, unsigned int iops)
536f397c8d8SUlf Hansson {
537f397c8d8SUlf Hansson 	struct mmc_test_transfer_result *tr;
538f397c8d8SUlf Hansson 
539f397c8d8SUlf Hansson 	if (!test->gr)
540f397c8d8SUlf Hansson 		return;
541f397c8d8SUlf Hansson 
542554d7c54SMarkus Elfring 	tr = kmalloc(sizeof(*tr), GFP_KERNEL);
543f397c8d8SUlf Hansson 	if (!tr)
544f397c8d8SUlf Hansson 		return;
545f397c8d8SUlf Hansson 
546f397c8d8SUlf Hansson 	tr->count = count;
547f397c8d8SUlf Hansson 	tr->sectors = sectors;
548f397c8d8SUlf Hansson 	tr->ts = ts;
549f397c8d8SUlf Hansson 	tr->rate = rate;
550f397c8d8SUlf Hansson 	tr->iops = iops;
551f397c8d8SUlf Hansson 
552f397c8d8SUlf Hansson 	list_add_tail(&tr->link, &test->gr->tr_lst);
553f397c8d8SUlf Hansson }
554f397c8d8SUlf Hansson 
555f397c8d8SUlf Hansson /*
556f397c8d8SUlf Hansson  * Print the transfer rate.
557f397c8d8SUlf Hansson  */
mmc_test_print_rate(struct mmc_test_card * test,uint64_t bytes,struct timespec64 * ts1,struct timespec64 * ts2)558f397c8d8SUlf Hansson static void mmc_test_print_rate(struct mmc_test_card *test, uint64_t bytes,
559a5b97be2SArnd Bergmann 				struct timespec64 *ts1, struct timespec64 *ts2)
560f397c8d8SUlf Hansson {
561f397c8d8SUlf Hansson 	unsigned int rate, iops, sectors = bytes >> 9;
562a5b97be2SArnd Bergmann 	struct timespec64 ts;
563f397c8d8SUlf Hansson 
564a5b97be2SArnd Bergmann 	ts = timespec64_sub(*ts2, *ts1);
565f397c8d8SUlf Hansson 
566f397c8d8SUlf Hansson 	rate = mmc_test_rate(bytes, &ts);
567f397c8d8SUlf Hansson 	iops = mmc_test_rate(100, &ts); /* I/O ops per sec x 100 */
568f397c8d8SUlf Hansson 
569a5b97be2SArnd Bergmann 	pr_info("%s: Transfer of %u sectors (%u%s KiB) took %llu.%09u "
570f397c8d8SUlf Hansson 			 "seconds (%u kB/s, %u KiB/s, %u.%02u IOPS)\n",
571f397c8d8SUlf Hansson 			 mmc_hostname(test->card->host), sectors, sectors >> 1,
572a5b97be2SArnd Bergmann 			 (sectors & 1 ? ".5" : ""), (u64)ts.tv_sec,
573a5b97be2SArnd Bergmann 			 (u32)ts.tv_nsec, rate / 1000, rate / 1024,
574f397c8d8SUlf Hansson 			 iops / 100, iops % 100);
575f397c8d8SUlf Hansson 
576f397c8d8SUlf Hansson 	mmc_test_save_transfer_result(test, 1, sectors, ts, rate, iops);
577f397c8d8SUlf Hansson }
578f397c8d8SUlf Hansson 
579f397c8d8SUlf Hansson /*
580f397c8d8SUlf Hansson  * Print the average transfer rate.
581f397c8d8SUlf Hansson  */
mmc_test_print_avg_rate(struct mmc_test_card * test,uint64_t bytes,unsigned int count,struct timespec64 * ts1,struct timespec64 * ts2)582f397c8d8SUlf Hansson static void mmc_test_print_avg_rate(struct mmc_test_card *test, uint64_t bytes,
583a5b97be2SArnd Bergmann 				    unsigned int count, struct timespec64 *ts1,
584a5b97be2SArnd Bergmann 				    struct timespec64 *ts2)
585f397c8d8SUlf Hansson {
586f397c8d8SUlf Hansson 	unsigned int rate, iops, sectors = bytes >> 9;
587f397c8d8SUlf Hansson 	uint64_t tot = bytes * count;
588a5b97be2SArnd Bergmann 	struct timespec64 ts;
589f397c8d8SUlf Hansson 
590a5b97be2SArnd Bergmann 	ts = timespec64_sub(*ts2, *ts1);
591f397c8d8SUlf Hansson 
592f397c8d8SUlf Hansson 	rate = mmc_test_rate(tot, &ts);
593f397c8d8SUlf Hansson 	iops = mmc_test_rate(count * 100, &ts); /* I/O ops per sec x 100 */
594f397c8d8SUlf Hansson 
595f397c8d8SUlf Hansson 	pr_info("%s: Transfer of %u x %u sectors (%u x %u%s KiB) took "
596a5b97be2SArnd Bergmann 			 "%llu.%09u seconds (%u kB/s, %u KiB/s, "
597f397c8d8SUlf Hansson 			 "%u.%02u IOPS, sg_len %d)\n",
598f397c8d8SUlf Hansson 			 mmc_hostname(test->card->host), count, sectors, count,
599f397c8d8SUlf Hansson 			 sectors >> 1, (sectors & 1 ? ".5" : ""),
600a5b97be2SArnd Bergmann 			 (u64)ts.tv_sec, (u32)ts.tv_nsec,
601f397c8d8SUlf Hansson 			 rate / 1000, rate / 1024, iops / 100, iops % 100,
602f397c8d8SUlf Hansson 			 test->area.sg_len);
603f397c8d8SUlf Hansson 
604f397c8d8SUlf Hansson 	mmc_test_save_transfer_result(test, count, sectors, ts, rate, iops);
605f397c8d8SUlf Hansson }
606f397c8d8SUlf Hansson 
607f397c8d8SUlf Hansson /*
608f397c8d8SUlf Hansson  * Return the card size in sectors.
609f397c8d8SUlf Hansson  */
mmc_test_capacity(struct mmc_card * card)610f397c8d8SUlf Hansson static unsigned int mmc_test_capacity(struct mmc_card *card)
611f397c8d8SUlf Hansson {
612f397c8d8SUlf Hansson 	if (!mmc_card_sd(card) && mmc_card_blockaddr(card))
613f397c8d8SUlf Hansson 		return card->ext_csd.sectors;
614f397c8d8SUlf Hansson 	else
615f397c8d8SUlf Hansson 		return card->csd.capacity << (card->csd.read_blkbits - 9);
616f397c8d8SUlf Hansson }
617f397c8d8SUlf Hansson 
618f397c8d8SUlf Hansson /*******************************************************************/
619f397c8d8SUlf Hansson /*  Test preparation and cleanup                                   */
620f397c8d8SUlf Hansson /*******************************************************************/
621f397c8d8SUlf Hansson 
622f397c8d8SUlf Hansson /*
623f397c8d8SUlf Hansson  * Fill the first couple of sectors of the card with known data
624f397c8d8SUlf Hansson  * so that bad reads/writes can be detected
625f397c8d8SUlf Hansson  */
__mmc_test_prepare(struct mmc_test_card * test,int write,int val)626707662d5SYue Hu static int __mmc_test_prepare(struct mmc_test_card *test, int write, int val)
627f397c8d8SUlf Hansson {
628f397c8d8SUlf Hansson 	int ret, i;
629f397c8d8SUlf Hansson 
630f397c8d8SUlf Hansson 	ret = mmc_test_set_blksize(test, 512);
631f397c8d8SUlf Hansson 	if (ret)
632f397c8d8SUlf Hansson 		return ret;
633f397c8d8SUlf Hansson 
634f397c8d8SUlf Hansson 	if (write)
635707662d5SYue Hu 		memset(test->buffer, val, 512);
636f397c8d8SUlf Hansson 	else {
637f397c8d8SUlf Hansson 		for (i = 0; i < 512; i++)
638f397c8d8SUlf Hansson 			test->buffer[i] = i;
639f397c8d8SUlf Hansson 	}
640f397c8d8SUlf Hansson 
641f397c8d8SUlf Hansson 	for (i = 0; i < BUFFER_SIZE / 512; i++) {
642f397c8d8SUlf Hansson 		ret = mmc_test_buffer_transfer(test, test->buffer, i, 512, 1);
643f397c8d8SUlf Hansson 		if (ret)
644f397c8d8SUlf Hansson 			return ret;
645f397c8d8SUlf Hansson 	}
646f397c8d8SUlf Hansson 
647f397c8d8SUlf Hansson 	return 0;
648f397c8d8SUlf Hansson }
649f397c8d8SUlf Hansson 
mmc_test_prepare_write(struct mmc_test_card * test)650f397c8d8SUlf Hansson static int mmc_test_prepare_write(struct mmc_test_card *test)
651f397c8d8SUlf Hansson {
652707662d5SYue Hu 	return __mmc_test_prepare(test, 1, 0xDF);
653f397c8d8SUlf Hansson }
654f397c8d8SUlf Hansson 
mmc_test_prepare_read(struct mmc_test_card * test)655f397c8d8SUlf Hansson static int mmc_test_prepare_read(struct mmc_test_card *test)
656f397c8d8SUlf Hansson {
657707662d5SYue Hu 	return __mmc_test_prepare(test, 0, 0);
658f397c8d8SUlf Hansson }
659f397c8d8SUlf Hansson 
mmc_test_cleanup(struct mmc_test_card * test)660f397c8d8SUlf Hansson static int mmc_test_cleanup(struct mmc_test_card *test)
661f397c8d8SUlf Hansson {
662707662d5SYue Hu 	return __mmc_test_prepare(test, 1, 0);
663f397c8d8SUlf Hansson }
664f397c8d8SUlf Hansson 
665f397c8d8SUlf Hansson /*******************************************************************/
666f397c8d8SUlf Hansson /*  Test execution helpers                                         */
667f397c8d8SUlf Hansson /*******************************************************************/
668f397c8d8SUlf Hansson 
669f397c8d8SUlf Hansson /*
670f397c8d8SUlf Hansson  * Modifies the mmc_request to perform the "short transfer" tests
671f397c8d8SUlf Hansson  */
mmc_test_prepare_broken_mrq(struct mmc_test_card * test,struct mmc_request * mrq,int write)672f397c8d8SUlf Hansson static void mmc_test_prepare_broken_mrq(struct mmc_test_card *test,
673f397c8d8SUlf Hansson 	struct mmc_request *mrq, int write)
674f397c8d8SUlf Hansson {
675f397c8d8SUlf Hansson 	if (WARN_ON(!mrq || !mrq->cmd || !mrq->data))
676f397c8d8SUlf Hansson 		return;
677f397c8d8SUlf Hansson 
678f397c8d8SUlf Hansson 	if (mrq->data->blocks > 1) {
679f397c8d8SUlf Hansson 		mrq->cmd->opcode = write ?
680f397c8d8SUlf Hansson 			MMC_WRITE_BLOCK : MMC_READ_SINGLE_BLOCK;
681f397c8d8SUlf Hansson 		mrq->stop = NULL;
682f397c8d8SUlf Hansson 	} else {
683f397c8d8SUlf Hansson 		mrq->cmd->opcode = MMC_SEND_STATUS;
684f397c8d8SUlf Hansson 		mrq->cmd->arg = test->card->rca << 16;
685f397c8d8SUlf Hansson 	}
686f397c8d8SUlf Hansson }
687f397c8d8SUlf Hansson 
688f397c8d8SUlf Hansson /*
689f397c8d8SUlf Hansson  * Checks that a normal transfer didn't have any errors
690f397c8d8SUlf Hansson  */
mmc_test_check_result(struct mmc_test_card * test,struct mmc_request * mrq)691f397c8d8SUlf Hansson static int mmc_test_check_result(struct mmc_test_card *test,
692f397c8d8SUlf Hansson 				 struct mmc_request *mrq)
693f397c8d8SUlf Hansson {
694f397c8d8SUlf Hansson 	int ret;
695f397c8d8SUlf Hansson 
696f397c8d8SUlf Hansson 	if (WARN_ON(!mrq || !mrq->cmd || !mrq->data))
697f397c8d8SUlf Hansson 		return -EINVAL;
698f397c8d8SUlf Hansson 
699f397c8d8SUlf Hansson 	ret = 0;
700f397c8d8SUlf Hansson 
701f397c8d8SUlf Hansson 	if (mrq->sbc && mrq->sbc->error)
702f397c8d8SUlf Hansson 		ret = mrq->sbc->error;
703f397c8d8SUlf Hansson 	if (!ret && mrq->cmd->error)
704f397c8d8SUlf Hansson 		ret = mrq->cmd->error;
705f397c8d8SUlf Hansson 	if (!ret && mrq->data->error)
706f397c8d8SUlf Hansson 		ret = mrq->data->error;
707f397c8d8SUlf Hansson 	if (!ret && mrq->stop && mrq->stop->error)
708f397c8d8SUlf Hansson 		ret = mrq->stop->error;
709f397c8d8SUlf Hansson 	if (!ret && mrq->data->bytes_xfered !=
710f397c8d8SUlf Hansson 		mrq->data->blocks * mrq->data->blksz)
711f397c8d8SUlf Hansson 		ret = RESULT_FAIL;
712f397c8d8SUlf Hansson 
713f397c8d8SUlf Hansson 	if (ret == -EINVAL)
714f397c8d8SUlf Hansson 		ret = RESULT_UNSUP_HOST;
715f397c8d8SUlf Hansson 
716f397c8d8SUlf Hansson 	return ret;
717f397c8d8SUlf Hansson }
718f397c8d8SUlf Hansson 
719f397c8d8SUlf Hansson /*
720f397c8d8SUlf Hansson  * Checks that a "short transfer" behaved as expected
721f397c8d8SUlf Hansson  */
mmc_test_check_broken_result(struct mmc_test_card * test,struct mmc_request * mrq)722f397c8d8SUlf Hansson static int mmc_test_check_broken_result(struct mmc_test_card *test,
723f397c8d8SUlf Hansson 	struct mmc_request *mrq)
724f397c8d8SUlf Hansson {
725f397c8d8SUlf Hansson 	int ret;
726f397c8d8SUlf Hansson 
727f397c8d8SUlf Hansson 	if (WARN_ON(!mrq || !mrq->cmd || !mrq->data))
728f397c8d8SUlf Hansson 		return -EINVAL;
729f397c8d8SUlf Hansson 
730f397c8d8SUlf Hansson 	ret = 0;
731f397c8d8SUlf Hansson 
732f397c8d8SUlf Hansson 	if (!ret && mrq->cmd->error)
733f397c8d8SUlf Hansson 		ret = mrq->cmd->error;
734f397c8d8SUlf Hansson 	if (!ret && mrq->data->error == 0)
735f397c8d8SUlf Hansson 		ret = RESULT_FAIL;
736f397c8d8SUlf Hansson 	if (!ret && mrq->data->error != -ETIMEDOUT)
737f397c8d8SUlf Hansson 		ret = mrq->data->error;
738f397c8d8SUlf Hansson 	if (!ret && mrq->stop && mrq->stop->error)
739f397c8d8SUlf Hansson 		ret = mrq->stop->error;
740f397c8d8SUlf Hansson 	if (mrq->data->blocks > 1) {
741f397c8d8SUlf Hansson 		if (!ret && mrq->data->bytes_xfered > mrq->data->blksz)
742f397c8d8SUlf Hansson 			ret = RESULT_FAIL;
743f397c8d8SUlf Hansson 	} else {
744f397c8d8SUlf Hansson 		if (!ret && mrq->data->bytes_xfered > 0)
745f397c8d8SUlf Hansson 			ret = RESULT_FAIL;
746f397c8d8SUlf Hansson 	}
747f397c8d8SUlf Hansson 
748f397c8d8SUlf Hansson 	if (ret == -EINVAL)
749f397c8d8SUlf Hansson 		ret = RESULT_UNSUP_HOST;
750f397c8d8SUlf Hansson 
751f397c8d8SUlf Hansson 	return ret;
752f397c8d8SUlf Hansson }
753f397c8d8SUlf Hansson 
754098dc66aSArnd Bergmann struct mmc_test_req {
755098dc66aSArnd Bergmann 	struct mmc_request mrq;
756098dc66aSArnd Bergmann 	struct mmc_command sbc;
757098dc66aSArnd Bergmann 	struct mmc_command cmd;
758098dc66aSArnd Bergmann 	struct mmc_command stop;
759098dc66aSArnd Bergmann 	struct mmc_command status;
760098dc66aSArnd Bergmann 	struct mmc_data data;
761098dc66aSArnd Bergmann };
762098dc66aSArnd Bergmann 
763f397c8d8SUlf Hansson /*
764f397c8d8SUlf Hansson  * Tests nonblock transfer with certain parameters
765f397c8d8SUlf Hansson  */
mmc_test_req_reset(struct mmc_test_req * rq)766098dc66aSArnd Bergmann static void mmc_test_req_reset(struct mmc_test_req *rq)
767f397c8d8SUlf Hansson {
768098dc66aSArnd Bergmann 	memset(rq, 0, sizeof(struct mmc_test_req));
769f397c8d8SUlf Hansson 
770098dc66aSArnd Bergmann 	rq->mrq.cmd = &rq->cmd;
771098dc66aSArnd Bergmann 	rq->mrq.data = &rq->data;
772098dc66aSArnd Bergmann 	rq->mrq.stop = &rq->stop;
773f397c8d8SUlf Hansson }
774098dc66aSArnd Bergmann 
mmc_test_req_alloc(void)775098dc66aSArnd Bergmann static struct mmc_test_req *mmc_test_req_alloc(void)
776098dc66aSArnd Bergmann {
777098dc66aSArnd Bergmann 	struct mmc_test_req *rq = kmalloc(sizeof(*rq), GFP_KERNEL);
778098dc66aSArnd Bergmann 
779098dc66aSArnd Bergmann 	if (rq)
780098dc66aSArnd Bergmann 		mmc_test_req_reset(rq);
781098dc66aSArnd Bergmann 
782098dc66aSArnd Bergmann 	return rq;
783098dc66aSArnd Bergmann }
784098dc66aSArnd Bergmann 
mmc_test_wait_done(struct mmc_request * mrq)78542f532daSAdrian Hunter static void mmc_test_wait_done(struct mmc_request *mrq)
78642f532daSAdrian Hunter {
78742f532daSAdrian Hunter 	complete(&mrq->completion);
78842f532daSAdrian Hunter }
78942f532daSAdrian Hunter 
mmc_test_start_areq(struct mmc_test_card * test,struct mmc_request * mrq,struct mmc_request * prev_mrq)79042f532daSAdrian Hunter static int mmc_test_start_areq(struct mmc_test_card *test,
79142f532daSAdrian Hunter 			       struct mmc_request *mrq,
79242f532daSAdrian Hunter 			       struct mmc_request *prev_mrq)
79342f532daSAdrian Hunter {
79442f532daSAdrian Hunter 	struct mmc_host *host = test->card->host;
79542f532daSAdrian Hunter 	int err = 0;
79642f532daSAdrian Hunter 
79742f532daSAdrian Hunter 	if (mrq) {
79842f532daSAdrian Hunter 		init_completion(&mrq->completion);
79942f532daSAdrian Hunter 		mrq->done = mmc_test_wait_done;
80042f532daSAdrian Hunter 		mmc_pre_req(host, mrq);
80142f532daSAdrian Hunter 	}
80242f532daSAdrian Hunter 
80342f532daSAdrian Hunter 	if (prev_mrq) {
80442f532daSAdrian Hunter 		wait_for_completion(&prev_mrq->completion);
80542f532daSAdrian Hunter 		err = mmc_test_wait_busy(test);
80642f532daSAdrian Hunter 		if (!err)
80742f532daSAdrian Hunter 			err = mmc_test_check_result(test, prev_mrq);
80842f532daSAdrian Hunter 	}
80942f532daSAdrian Hunter 
81042f532daSAdrian Hunter 	if (!err && mrq) {
81142f532daSAdrian Hunter 		err = mmc_start_request(host, mrq);
81242f532daSAdrian Hunter 		if (err)
81342f532daSAdrian Hunter 			mmc_retune_release(host);
81442f532daSAdrian Hunter 	}
81542f532daSAdrian Hunter 
81642f532daSAdrian Hunter 	if (prev_mrq)
81742f532daSAdrian Hunter 		mmc_post_req(host, prev_mrq, 0);
81842f532daSAdrian Hunter 
81942f532daSAdrian Hunter 	if (err && mrq)
82042f532daSAdrian Hunter 		mmc_post_req(host, mrq, err);
82142f532daSAdrian Hunter 
82242f532daSAdrian Hunter 	return err;
82342f532daSAdrian Hunter }
824098dc66aSArnd Bergmann 
mmc_test_nonblock_transfer(struct mmc_test_card * test,unsigned int dev_addr,int write,int count)825f397c8d8SUlf Hansson static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
826ea21e9b2SVeerabhadrarao Badiganti 				      unsigned int dev_addr, int write,
827ea21e9b2SVeerabhadrarao Badiganti 				      int count)
828f397c8d8SUlf Hansson {
829098dc66aSArnd Bergmann 	struct mmc_test_req *rq1, *rq2;
83042f532daSAdrian Hunter 	struct mmc_request *mrq, *prev_mrq;
831f397c8d8SUlf Hansson 	int i;
832f397c8d8SUlf Hansson 	int ret = RESULT_OK;
833ea21e9b2SVeerabhadrarao Badiganti 	struct mmc_test_area *t = &test->area;
834ea21e9b2SVeerabhadrarao Badiganti 	struct scatterlist *sg = t->sg;
835ea21e9b2SVeerabhadrarao Badiganti 	struct scatterlist *sg_areq = t->sg_areq;
836f397c8d8SUlf Hansson 
837098dc66aSArnd Bergmann 	rq1 = mmc_test_req_alloc();
838098dc66aSArnd Bergmann 	rq2 = mmc_test_req_alloc();
839098dc66aSArnd Bergmann 	if (!rq1 || !rq2) {
840098dc66aSArnd Bergmann 		ret = RESULT_FAIL;
841098dc66aSArnd Bergmann 		goto err;
842098dc66aSArnd Bergmann 	}
843f397c8d8SUlf Hansson 
84442f532daSAdrian Hunter 	mrq = &rq1->mrq;
84542f532daSAdrian Hunter 	prev_mrq = NULL;
846f397c8d8SUlf Hansson 
847f397c8d8SUlf Hansson 	for (i = 0; i < count; i++) {
84842f532daSAdrian Hunter 		mmc_test_req_reset(container_of(mrq, struct mmc_test_req, mrq));
849ea21e9b2SVeerabhadrarao Badiganti 		mmc_test_prepare_mrq(test, mrq, sg, t->sg_len, dev_addr,
850ea21e9b2SVeerabhadrarao Badiganti 				     t->blocks, 512, write);
85142f532daSAdrian Hunter 		ret = mmc_test_start_areq(test, mrq, prev_mrq);
85242f532daSAdrian Hunter 		if (ret)
853f397c8d8SUlf Hansson 			goto err;
854f397c8d8SUlf Hansson 
85542f532daSAdrian Hunter 		if (!prev_mrq)
85642f532daSAdrian Hunter 			prev_mrq = &rq2->mrq;
857098dc66aSArnd Bergmann 
85842f532daSAdrian Hunter 		swap(mrq, prev_mrq);
859ea21e9b2SVeerabhadrarao Badiganti 		swap(sg, sg_areq);
860ea21e9b2SVeerabhadrarao Badiganti 		dev_addr += t->blocks;
861f397c8d8SUlf Hansson 	}
862f397c8d8SUlf Hansson 
86342f532daSAdrian Hunter 	ret = mmc_test_start_areq(test, NULL, prev_mrq);
864f397c8d8SUlf Hansson err:
865098dc66aSArnd Bergmann 	kfree(rq1);
866098dc66aSArnd Bergmann 	kfree(rq2);
867f397c8d8SUlf Hansson 	return ret;
868f397c8d8SUlf Hansson }
869f397c8d8SUlf Hansson 
870f397c8d8SUlf Hansson /*
871f397c8d8SUlf Hansson  * Tests a basic transfer with certain parameters
872f397c8d8SUlf Hansson  */
mmc_test_simple_transfer(struct mmc_test_card * test,struct scatterlist * sg,unsigned sg_len,unsigned dev_addr,unsigned blocks,unsigned blksz,int write)873f397c8d8SUlf Hansson static int mmc_test_simple_transfer(struct mmc_test_card *test,
874f397c8d8SUlf Hansson 	struct scatterlist *sg, unsigned sg_len, unsigned dev_addr,
875f397c8d8SUlf Hansson 	unsigned blocks, unsigned blksz, int write)
876f397c8d8SUlf Hansson {
877c7836d15SMasahiro Yamada 	struct mmc_request mrq = {};
878c7836d15SMasahiro Yamada 	struct mmc_command cmd = {};
879c7836d15SMasahiro Yamada 	struct mmc_command stop = {};
880c7836d15SMasahiro Yamada 	struct mmc_data data = {};
881f397c8d8SUlf Hansson 
882f397c8d8SUlf Hansson 	mrq.cmd = &cmd;
883f397c8d8SUlf Hansson 	mrq.data = &data;
884f397c8d8SUlf Hansson 	mrq.stop = &stop;
885f397c8d8SUlf Hansson 
886f397c8d8SUlf Hansson 	mmc_test_prepare_mrq(test, &mrq, sg, sg_len, dev_addr,
887f397c8d8SUlf Hansson 		blocks, blksz, write);
888f397c8d8SUlf Hansson 
889f397c8d8SUlf Hansson 	mmc_wait_for_req(test->card->host, &mrq);
890f397c8d8SUlf Hansson 
891f397c8d8SUlf Hansson 	mmc_test_wait_busy(test);
892f397c8d8SUlf Hansson 
893f397c8d8SUlf Hansson 	return mmc_test_check_result(test, &mrq);
894f397c8d8SUlf Hansson }
895f397c8d8SUlf Hansson 
896f397c8d8SUlf Hansson /*
897f397c8d8SUlf Hansson  * Tests a transfer where the card will fail completely or partly
898f397c8d8SUlf Hansson  */
mmc_test_broken_transfer(struct mmc_test_card * test,unsigned blocks,unsigned blksz,int write)899f397c8d8SUlf Hansson static int mmc_test_broken_transfer(struct mmc_test_card *test,
900f397c8d8SUlf Hansson 	unsigned blocks, unsigned blksz, int write)
901f397c8d8SUlf Hansson {
902c7836d15SMasahiro Yamada 	struct mmc_request mrq = {};
903c7836d15SMasahiro Yamada 	struct mmc_command cmd = {};
904c7836d15SMasahiro Yamada 	struct mmc_command stop = {};
905c7836d15SMasahiro Yamada 	struct mmc_data data = {};
906f397c8d8SUlf Hansson 
907f397c8d8SUlf Hansson 	struct scatterlist sg;
908f397c8d8SUlf Hansson 
909f397c8d8SUlf Hansson 	mrq.cmd = &cmd;
910f397c8d8SUlf Hansson 	mrq.data = &data;
911f397c8d8SUlf Hansson 	mrq.stop = &stop;
912f397c8d8SUlf Hansson 
913f397c8d8SUlf Hansson 	sg_init_one(&sg, test->buffer, blocks * blksz);
914f397c8d8SUlf Hansson 
915f397c8d8SUlf Hansson 	mmc_test_prepare_mrq(test, &mrq, &sg, 1, 0, blocks, blksz, write);
916f397c8d8SUlf Hansson 	mmc_test_prepare_broken_mrq(test, &mrq, write);
917f397c8d8SUlf Hansson 
918f397c8d8SUlf Hansson 	mmc_wait_for_req(test->card->host, &mrq);
919f397c8d8SUlf Hansson 
920f397c8d8SUlf Hansson 	mmc_test_wait_busy(test);
921f397c8d8SUlf Hansson 
922f397c8d8SUlf Hansson 	return mmc_test_check_broken_result(test, &mrq);
923f397c8d8SUlf Hansson }
924f397c8d8SUlf Hansson 
925f397c8d8SUlf Hansson /*
926f397c8d8SUlf Hansson  * Does a complete transfer test where data is also validated
927f397c8d8SUlf Hansson  *
928f397c8d8SUlf Hansson  * Note: mmc_test_prepare() must have been done before this call
929f397c8d8SUlf Hansson  */
mmc_test_transfer(struct mmc_test_card * test,struct scatterlist * sg,unsigned sg_len,unsigned dev_addr,unsigned blocks,unsigned blksz,int write)930f397c8d8SUlf Hansson static int mmc_test_transfer(struct mmc_test_card *test,
931f397c8d8SUlf Hansson 	struct scatterlist *sg, unsigned sg_len, unsigned dev_addr,
932f397c8d8SUlf Hansson 	unsigned blocks, unsigned blksz, int write)
933f397c8d8SUlf Hansson {
934f397c8d8SUlf Hansson 	int ret, i;
935f397c8d8SUlf Hansson 
936f397c8d8SUlf Hansson 	if (write) {
937f397c8d8SUlf Hansson 		for (i = 0; i < blocks * blksz; i++)
938f397c8d8SUlf Hansson 			test->scratch[i] = i;
939f397c8d8SUlf Hansson 	} else {
940f397c8d8SUlf Hansson 		memset(test->scratch, 0, BUFFER_SIZE);
941f397c8d8SUlf Hansson 	}
942f397c8d8SUlf Hansson 	sg_copy_from_buffer(sg, sg_len, test->scratch, BUFFER_SIZE);
943f397c8d8SUlf Hansson 
944f397c8d8SUlf Hansson 	ret = mmc_test_set_blksize(test, blksz);
945f397c8d8SUlf Hansson 	if (ret)
946f397c8d8SUlf Hansson 		return ret;
947f397c8d8SUlf Hansson 
948f397c8d8SUlf Hansson 	ret = mmc_test_simple_transfer(test, sg, sg_len, dev_addr,
949f397c8d8SUlf Hansson 		blocks, blksz, write);
950f397c8d8SUlf Hansson 	if (ret)
951f397c8d8SUlf Hansson 		return ret;
952f397c8d8SUlf Hansson 
953f397c8d8SUlf Hansson 	if (write) {
954f397c8d8SUlf Hansson 		int sectors;
955f397c8d8SUlf Hansson 
956f397c8d8SUlf Hansson 		ret = mmc_test_set_blksize(test, 512);
957f397c8d8SUlf Hansson 		if (ret)
958f397c8d8SUlf Hansson 			return ret;
959f397c8d8SUlf Hansson 
960f397c8d8SUlf Hansson 		sectors = (blocks * blksz + 511) / 512;
961f397c8d8SUlf Hansson 		if ((sectors * 512) == (blocks * blksz))
962f397c8d8SUlf Hansson 			sectors++;
963f397c8d8SUlf Hansson 
964f397c8d8SUlf Hansson 		if ((sectors * 512) > BUFFER_SIZE)
965f397c8d8SUlf Hansson 			return -EINVAL;
966f397c8d8SUlf Hansson 
967f397c8d8SUlf Hansson 		memset(test->buffer, 0, sectors * 512);
968f397c8d8SUlf Hansson 
969f397c8d8SUlf Hansson 		for (i = 0; i < sectors; i++) {
970f397c8d8SUlf Hansson 			ret = mmc_test_buffer_transfer(test,
971f397c8d8SUlf Hansson 				test->buffer + i * 512,
972f397c8d8SUlf Hansson 				dev_addr + i, 512, 0);
973f397c8d8SUlf Hansson 			if (ret)
974f397c8d8SUlf Hansson 				return ret;
975f397c8d8SUlf Hansson 		}
976f397c8d8SUlf Hansson 
977f397c8d8SUlf Hansson 		for (i = 0; i < blocks * blksz; i++) {
978f397c8d8SUlf Hansson 			if (test->buffer[i] != (u8)i)
979f397c8d8SUlf Hansson 				return RESULT_FAIL;
980f397c8d8SUlf Hansson 		}
981f397c8d8SUlf Hansson 
982f397c8d8SUlf Hansson 		for (; i < sectors * 512; i++) {
983f397c8d8SUlf Hansson 			if (test->buffer[i] != 0xDF)
984f397c8d8SUlf Hansson 				return RESULT_FAIL;
985f397c8d8SUlf Hansson 		}
986f397c8d8SUlf Hansson 	} else {
987f397c8d8SUlf Hansson 		sg_copy_to_buffer(sg, sg_len, test->scratch, BUFFER_SIZE);
988f397c8d8SUlf Hansson 		for (i = 0; i < blocks * blksz; i++) {
989f397c8d8SUlf Hansson 			if (test->scratch[i] != (u8)i)
990f397c8d8SUlf Hansson 				return RESULT_FAIL;
991f397c8d8SUlf Hansson 		}
992f397c8d8SUlf Hansson 	}
993f397c8d8SUlf Hansson 
994f397c8d8SUlf Hansson 	return 0;
995f397c8d8SUlf Hansson }
996f397c8d8SUlf Hansson 
997f397c8d8SUlf Hansson /*******************************************************************/
998f397c8d8SUlf Hansson /*  Tests                                                          */
999f397c8d8SUlf Hansson /*******************************************************************/
1000f397c8d8SUlf Hansson 
1001f397c8d8SUlf Hansson struct mmc_test_case {
1002f397c8d8SUlf Hansson 	const char *name;
1003f397c8d8SUlf Hansson 
1004f397c8d8SUlf Hansson 	int (*prepare)(struct mmc_test_card *);
1005f397c8d8SUlf Hansson 	int (*run)(struct mmc_test_card *);
1006f397c8d8SUlf Hansson 	int (*cleanup)(struct mmc_test_card *);
1007f397c8d8SUlf Hansson };
1008f397c8d8SUlf Hansson 
mmc_test_basic_write(struct mmc_test_card * test)1009f397c8d8SUlf Hansson static int mmc_test_basic_write(struct mmc_test_card *test)
1010f397c8d8SUlf Hansson {
1011f397c8d8SUlf Hansson 	int ret;
1012f397c8d8SUlf Hansson 	struct scatterlist sg;
1013f397c8d8SUlf Hansson 
1014f397c8d8SUlf Hansson 	ret = mmc_test_set_blksize(test, 512);
1015f397c8d8SUlf Hansson 	if (ret)
1016f397c8d8SUlf Hansson 		return ret;
1017f397c8d8SUlf Hansson 
1018f397c8d8SUlf Hansson 	sg_init_one(&sg, test->buffer, 512);
1019f397c8d8SUlf Hansson 
1020f397c8d8SUlf Hansson 	return mmc_test_simple_transfer(test, &sg, 1, 0, 1, 512, 1);
1021f397c8d8SUlf Hansson }
1022f397c8d8SUlf Hansson 
mmc_test_basic_read(struct mmc_test_card * test)1023f397c8d8SUlf Hansson static int mmc_test_basic_read(struct mmc_test_card *test)
1024f397c8d8SUlf Hansson {
1025f397c8d8SUlf Hansson 	int ret;
1026f397c8d8SUlf Hansson 	struct scatterlist sg;
1027f397c8d8SUlf Hansson 
1028f397c8d8SUlf Hansson 	ret = mmc_test_set_blksize(test, 512);
1029f397c8d8SUlf Hansson 	if (ret)
1030f397c8d8SUlf Hansson 		return ret;
1031f397c8d8SUlf Hansson 
1032f397c8d8SUlf Hansson 	sg_init_one(&sg, test->buffer, 512);
1033f397c8d8SUlf Hansson 
1034f397c8d8SUlf Hansson 	return mmc_test_simple_transfer(test, &sg, 1, 0, 1, 512, 0);
1035f397c8d8SUlf Hansson }
1036f397c8d8SUlf Hansson 
mmc_test_verify_write(struct mmc_test_card * test)1037f397c8d8SUlf Hansson static int mmc_test_verify_write(struct mmc_test_card *test)
1038f397c8d8SUlf Hansson {
1039f397c8d8SUlf Hansson 	struct scatterlist sg;
1040f397c8d8SUlf Hansson 
1041f397c8d8SUlf Hansson 	sg_init_one(&sg, test->buffer, 512);
1042f397c8d8SUlf Hansson 
1043f397c8d8SUlf Hansson 	return mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1);
1044f397c8d8SUlf Hansson }
1045f397c8d8SUlf Hansson 
mmc_test_verify_read(struct mmc_test_card * test)1046f397c8d8SUlf Hansson static int mmc_test_verify_read(struct mmc_test_card *test)
1047f397c8d8SUlf Hansson {
1048f397c8d8SUlf Hansson 	struct scatterlist sg;
1049f397c8d8SUlf Hansson 
1050f397c8d8SUlf Hansson 	sg_init_one(&sg, test->buffer, 512);
1051f397c8d8SUlf Hansson 
1052f397c8d8SUlf Hansson 	return mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0);
1053f397c8d8SUlf Hansson }
1054f397c8d8SUlf Hansson 
mmc_test_multi_write(struct mmc_test_card * test)1055f397c8d8SUlf Hansson static int mmc_test_multi_write(struct mmc_test_card *test)
1056f397c8d8SUlf Hansson {
1057f397c8d8SUlf Hansson 	unsigned int size;
1058f397c8d8SUlf Hansson 	struct scatterlist sg;
1059f397c8d8SUlf Hansson 
1060f397c8d8SUlf Hansson 	if (test->card->host->max_blk_count == 1)
1061f397c8d8SUlf Hansson 		return RESULT_UNSUP_HOST;
1062f397c8d8SUlf Hansson 
1063f397c8d8SUlf Hansson 	size = PAGE_SIZE * 2;
1064f397c8d8SUlf Hansson 	size = min(size, test->card->host->max_req_size);
1065f397c8d8SUlf Hansson 	size = min(size, test->card->host->max_seg_size);
1066f397c8d8SUlf Hansson 	size = min(size, test->card->host->max_blk_count * 512);
1067f397c8d8SUlf Hansson 
1068f397c8d8SUlf Hansson 	if (size < 1024)
1069f397c8d8SUlf Hansson 		return RESULT_UNSUP_HOST;
1070f397c8d8SUlf Hansson 
1071f397c8d8SUlf Hansson 	sg_init_one(&sg, test->buffer, size);
1072f397c8d8SUlf Hansson 
1073f397c8d8SUlf Hansson 	return mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 1);
1074f397c8d8SUlf Hansson }
1075f397c8d8SUlf Hansson 
mmc_test_multi_read(struct mmc_test_card * test)1076f397c8d8SUlf Hansson static int mmc_test_multi_read(struct mmc_test_card *test)
1077f397c8d8SUlf Hansson {
1078f397c8d8SUlf Hansson 	unsigned int size;
1079f397c8d8SUlf Hansson 	struct scatterlist sg;
1080f397c8d8SUlf Hansson 
1081f397c8d8SUlf Hansson 	if (test->card->host->max_blk_count == 1)
1082f397c8d8SUlf Hansson 		return RESULT_UNSUP_HOST;
1083f397c8d8SUlf Hansson 
1084f397c8d8SUlf Hansson 	size = PAGE_SIZE * 2;
1085f397c8d8SUlf Hansson 	size = min(size, test->card->host->max_req_size);
1086f397c8d8SUlf Hansson 	size = min(size, test->card->host->max_seg_size);
1087f397c8d8SUlf Hansson 	size = min(size, test->card->host->max_blk_count * 512);
1088f397c8d8SUlf Hansson 
1089f397c8d8SUlf Hansson 	if (size < 1024)
1090f397c8d8SUlf Hansson 		return RESULT_UNSUP_HOST;
1091f397c8d8SUlf Hansson 
1092f397c8d8SUlf Hansson 	sg_init_one(&sg, test->buffer, size);
1093f397c8d8SUlf Hansson 
1094f397c8d8SUlf Hansson 	return mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 0);
1095f397c8d8SUlf Hansson }
1096f397c8d8SUlf Hansson 
mmc_test_pow2_write(struct mmc_test_card * test)1097f397c8d8SUlf Hansson static int mmc_test_pow2_write(struct mmc_test_card *test)
1098f397c8d8SUlf Hansson {
1099f397c8d8SUlf Hansson 	int ret, i;
1100f397c8d8SUlf Hansson 	struct scatterlist sg;
1101f397c8d8SUlf Hansson 
1102f397c8d8SUlf Hansson 	if (!test->card->csd.write_partial)
1103f397c8d8SUlf Hansson 		return RESULT_UNSUP_CARD;
1104f397c8d8SUlf Hansson 
1105f397c8d8SUlf Hansson 	for (i = 1; i < 512; i <<= 1) {
1106f397c8d8SUlf Hansson 		sg_init_one(&sg, test->buffer, i);
1107f397c8d8SUlf Hansson 		ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 1);
1108f397c8d8SUlf Hansson 		if (ret)
1109f397c8d8SUlf Hansson 			return ret;
1110f397c8d8SUlf Hansson 	}
1111f397c8d8SUlf Hansson 
1112f397c8d8SUlf Hansson 	return 0;
1113f397c8d8SUlf Hansson }
1114f397c8d8SUlf Hansson 
mmc_test_pow2_read(struct mmc_test_card * test)1115f397c8d8SUlf Hansson static int mmc_test_pow2_read(struct mmc_test_card *test)
1116f397c8d8SUlf Hansson {
1117f397c8d8SUlf Hansson 	int ret, i;
1118f397c8d8SUlf Hansson 	struct scatterlist sg;
1119f397c8d8SUlf Hansson 
1120f397c8d8SUlf Hansson 	if (!test->card->csd.read_partial)
1121f397c8d8SUlf Hansson 		return RESULT_UNSUP_CARD;
1122f397c8d8SUlf Hansson 
1123f397c8d8SUlf Hansson 	for (i = 1; i < 512; i <<= 1) {
1124f397c8d8SUlf Hansson 		sg_init_one(&sg, test->buffer, i);
1125f397c8d8SUlf Hansson 		ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 0);
1126f397c8d8SUlf Hansson 		if (ret)
1127f397c8d8SUlf Hansson 			return ret;
1128f397c8d8SUlf Hansson 	}
1129f397c8d8SUlf Hansson 
1130f397c8d8SUlf Hansson 	return 0;
1131f397c8d8SUlf Hansson }
1132f397c8d8SUlf Hansson 
mmc_test_weird_write(struct mmc_test_card * test)1133f397c8d8SUlf Hansson static int mmc_test_weird_write(struct mmc_test_card *test)
1134f397c8d8SUlf Hansson {
1135f397c8d8SUlf Hansson 	int ret, i;
1136f397c8d8SUlf Hansson 	struct scatterlist sg;
1137f397c8d8SUlf Hansson 
1138f397c8d8SUlf Hansson 	if (!test->card->csd.write_partial)
1139f397c8d8SUlf Hansson 		return RESULT_UNSUP_CARD;
1140f397c8d8SUlf Hansson 
1141f397c8d8SUlf Hansson 	for (i = 3; i < 512; i += 7) {
1142f397c8d8SUlf Hansson 		sg_init_one(&sg, test->buffer, i);
1143f397c8d8SUlf Hansson 		ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 1);
1144f397c8d8SUlf Hansson 		if (ret)
1145f397c8d8SUlf Hansson 			return ret;
1146f397c8d8SUlf Hansson 	}
1147f397c8d8SUlf Hansson 
1148f397c8d8SUlf Hansson 	return 0;
1149f397c8d8SUlf Hansson }
1150f397c8d8SUlf Hansson 
mmc_test_weird_read(struct mmc_test_card * test)1151f397c8d8SUlf Hansson static int mmc_test_weird_read(struct mmc_test_card *test)
1152f397c8d8SUlf Hansson {
1153f397c8d8SUlf Hansson 	int ret, i;
1154f397c8d8SUlf Hansson 	struct scatterlist sg;
1155f397c8d8SUlf Hansson 
1156f397c8d8SUlf Hansson 	if (!test->card->csd.read_partial)
1157f397c8d8SUlf Hansson 		return RESULT_UNSUP_CARD;
1158f397c8d8SUlf Hansson 
1159f397c8d8SUlf Hansson 	for (i = 3; i < 512; i += 7) {
1160f397c8d8SUlf Hansson 		sg_init_one(&sg, test->buffer, i);
1161f397c8d8SUlf Hansson 		ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 0);
1162f397c8d8SUlf Hansson 		if (ret)
1163f397c8d8SUlf Hansson 			return ret;
1164f397c8d8SUlf Hansson 	}
1165f397c8d8SUlf Hansson 
1166f397c8d8SUlf Hansson 	return 0;
1167f397c8d8SUlf Hansson }
1168f397c8d8SUlf Hansson 
mmc_test_align_write(struct mmc_test_card * test)1169f397c8d8SUlf Hansson static int mmc_test_align_write(struct mmc_test_card *test)
1170f397c8d8SUlf Hansson {
1171f397c8d8SUlf Hansson 	int ret, i;
1172f397c8d8SUlf Hansson 	struct scatterlist sg;
1173f397c8d8SUlf Hansson 
1174f397c8d8SUlf Hansson 	for (i = 1; i < TEST_ALIGN_END; i++) {
1175f397c8d8SUlf Hansson 		sg_init_one(&sg, test->buffer + i, 512);
1176f397c8d8SUlf Hansson 		ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1);
1177f397c8d8SUlf Hansson 		if (ret)
1178f397c8d8SUlf Hansson 			return ret;
1179f397c8d8SUlf Hansson 	}
1180f397c8d8SUlf Hansson 
1181f397c8d8SUlf Hansson 	return 0;
1182f397c8d8SUlf Hansson }
1183f397c8d8SUlf Hansson 
mmc_test_align_read(struct mmc_test_card * test)1184f397c8d8SUlf Hansson static int mmc_test_align_read(struct mmc_test_card *test)
1185f397c8d8SUlf Hansson {
1186f397c8d8SUlf Hansson 	int ret, i;
1187f397c8d8SUlf Hansson 	struct scatterlist sg;
1188f397c8d8SUlf Hansson 
1189f397c8d8SUlf Hansson 	for (i = 1; i < TEST_ALIGN_END; i++) {
1190f397c8d8SUlf Hansson 		sg_init_one(&sg, test->buffer + i, 512);
1191f397c8d8SUlf Hansson 		ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0);
1192f397c8d8SUlf Hansson 		if (ret)
1193f397c8d8SUlf Hansson 			return ret;
1194f397c8d8SUlf Hansson 	}
1195f397c8d8SUlf Hansson 
1196f397c8d8SUlf Hansson 	return 0;
1197f397c8d8SUlf Hansson }
1198f397c8d8SUlf Hansson 
mmc_test_align_multi_write(struct mmc_test_card * test)1199f397c8d8SUlf Hansson static int mmc_test_align_multi_write(struct mmc_test_card *test)
1200f397c8d8SUlf Hansson {
1201f397c8d8SUlf Hansson 	int ret, i;
1202f397c8d8SUlf Hansson 	unsigned int size;
1203f397c8d8SUlf Hansson 	struct scatterlist sg;
1204f397c8d8SUlf Hansson 
1205f397c8d8SUlf Hansson 	if (test->card->host->max_blk_count == 1)
1206f397c8d8SUlf Hansson 		return RESULT_UNSUP_HOST;
1207f397c8d8SUlf Hansson 
1208f397c8d8SUlf Hansson 	size = PAGE_SIZE * 2;
1209f397c8d8SUlf Hansson 	size = min(size, test->card->host->max_req_size);
1210f397c8d8SUlf Hansson 	size = min(size, test->card->host->max_seg_size);
1211f397c8d8SUlf Hansson 	size = min(size, test->card->host->max_blk_count * 512);
1212f397c8d8SUlf Hansson 
1213f397c8d8SUlf Hansson 	if (size < 1024)
1214f397c8d8SUlf Hansson 		return RESULT_UNSUP_HOST;
1215f397c8d8SUlf Hansson 
1216f397c8d8SUlf Hansson 	for (i = 1; i < TEST_ALIGN_END; i++) {
1217f397c8d8SUlf Hansson 		sg_init_one(&sg, test->buffer + i, size);
1218f397c8d8SUlf Hansson 		ret = mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 1);
1219f397c8d8SUlf Hansson 		if (ret)
1220f397c8d8SUlf Hansson 			return ret;
1221f397c8d8SUlf Hansson 	}
1222f397c8d8SUlf Hansson 
1223f397c8d8SUlf Hansson 	return 0;
1224f397c8d8SUlf Hansson }
1225f397c8d8SUlf Hansson 
mmc_test_align_multi_read(struct mmc_test_card * test)1226f397c8d8SUlf Hansson static int mmc_test_align_multi_read(struct mmc_test_card *test)
1227f397c8d8SUlf Hansson {
1228f397c8d8SUlf Hansson 	int ret, i;
1229f397c8d8SUlf Hansson 	unsigned int size;
1230f397c8d8SUlf Hansson 	struct scatterlist sg;
1231f397c8d8SUlf Hansson 
1232f397c8d8SUlf Hansson 	if (test->card->host->max_blk_count == 1)
1233f397c8d8SUlf Hansson 		return RESULT_UNSUP_HOST;
1234f397c8d8SUlf Hansson 
1235f397c8d8SUlf Hansson 	size = PAGE_SIZE * 2;
1236f397c8d8SUlf Hansson 	size = min(size, test->card->host->max_req_size);
1237f397c8d8SUlf Hansson 	size = min(size, test->card->host->max_seg_size);
1238f397c8d8SUlf Hansson 	size = min(size, test->card->host->max_blk_count * 512);
1239f397c8d8SUlf Hansson 
1240f397c8d8SUlf Hansson 	if (size < 1024)
1241f397c8d8SUlf Hansson 		return RESULT_UNSUP_HOST;
1242f397c8d8SUlf Hansson 
1243f397c8d8SUlf Hansson 	for (i = 1; i < TEST_ALIGN_END; i++) {
1244f397c8d8SUlf Hansson 		sg_init_one(&sg, test->buffer + i, size);
1245f397c8d8SUlf Hansson 		ret = mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 0);
1246f397c8d8SUlf Hansson 		if (ret)
1247f397c8d8SUlf Hansson 			return ret;
1248f397c8d8SUlf Hansson 	}
1249f397c8d8SUlf Hansson 
1250f397c8d8SUlf Hansson 	return 0;
1251f397c8d8SUlf Hansson }
1252f397c8d8SUlf Hansson 
mmc_test_xfersize_write(struct mmc_test_card * test)1253f397c8d8SUlf Hansson static int mmc_test_xfersize_write(struct mmc_test_card *test)
1254f397c8d8SUlf Hansson {
1255f397c8d8SUlf Hansson 	int ret;
1256f397c8d8SUlf Hansson 
1257f397c8d8SUlf Hansson 	ret = mmc_test_set_blksize(test, 512);
1258f397c8d8SUlf Hansson 	if (ret)
1259f397c8d8SUlf Hansson 		return ret;
1260f397c8d8SUlf Hansson 
1261f397c8d8SUlf Hansson 	return mmc_test_broken_transfer(test, 1, 512, 1);
1262f397c8d8SUlf Hansson }
1263f397c8d8SUlf Hansson 
mmc_test_xfersize_read(struct mmc_test_card * test)1264f397c8d8SUlf Hansson static int mmc_test_xfersize_read(struct mmc_test_card *test)
1265f397c8d8SUlf Hansson {
1266f397c8d8SUlf Hansson 	int ret;
1267f397c8d8SUlf Hansson 
1268f397c8d8SUlf Hansson 	ret = mmc_test_set_blksize(test, 512);
1269f397c8d8SUlf Hansson 	if (ret)
1270f397c8d8SUlf Hansson 		return ret;
1271f397c8d8SUlf Hansson 
1272f397c8d8SUlf Hansson 	return mmc_test_broken_transfer(test, 1, 512, 0);
1273f397c8d8SUlf Hansson }
1274f397c8d8SUlf Hansson 
mmc_test_multi_xfersize_write(struct mmc_test_card * test)1275f397c8d8SUlf Hansson static int mmc_test_multi_xfersize_write(struct mmc_test_card *test)
1276f397c8d8SUlf Hansson {
1277f397c8d8SUlf Hansson 	int ret;
1278f397c8d8SUlf Hansson 
1279f397c8d8SUlf Hansson 	if (test->card->host->max_blk_count == 1)
1280f397c8d8SUlf Hansson 		return RESULT_UNSUP_HOST;
1281f397c8d8SUlf Hansson 
1282f397c8d8SUlf Hansson 	ret = mmc_test_set_blksize(test, 512);
1283f397c8d8SUlf Hansson 	if (ret)
1284f397c8d8SUlf Hansson 		return ret;
1285f397c8d8SUlf Hansson 
1286f397c8d8SUlf Hansson 	return mmc_test_broken_transfer(test, 2, 512, 1);
1287f397c8d8SUlf Hansson }
1288f397c8d8SUlf Hansson 
mmc_test_multi_xfersize_read(struct mmc_test_card * test)1289f397c8d8SUlf Hansson static int mmc_test_multi_xfersize_read(struct mmc_test_card *test)
1290f397c8d8SUlf Hansson {
1291f397c8d8SUlf Hansson 	int ret;
1292f397c8d8SUlf Hansson 
1293f397c8d8SUlf Hansson 	if (test->card->host->max_blk_count == 1)
1294f397c8d8SUlf Hansson 		return RESULT_UNSUP_HOST;
1295f397c8d8SUlf Hansson 
1296f397c8d8SUlf Hansson 	ret = mmc_test_set_blksize(test, 512);
1297f397c8d8SUlf Hansson 	if (ret)
1298f397c8d8SUlf Hansson 		return ret;
1299f397c8d8SUlf Hansson 
1300f397c8d8SUlf Hansson 	return mmc_test_broken_transfer(test, 2, 512, 0);
1301f397c8d8SUlf Hansson }
1302f397c8d8SUlf Hansson 
1303f397c8d8SUlf Hansson #ifdef CONFIG_HIGHMEM
1304f397c8d8SUlf Hansson 
mmc_test_write_high(struct mmc_test_card * test)1305f397c8d8SUlf Hansson static int mmc_test_write_high(struct mmc_test_card *test)
1306f397c8d8SUlf Hansson {
1307f397c8d8SUlf Hansson 	struct scatterlist sg;
1308f397c8d8SUlf Hansson 
1309f397c8d8SUlf Hansson 	sg_init_table(&sg, 1);
1310f397c8d8SUlf Hansson 	sg_set_page(&sg, test->highmem, 512, 0);
1311f397c8d8SUlf Hansson 
1312f397c8d8SUlf Hansson 	return mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1);
1313f397c8d8SUlf Hansson }
1314f397c8d8SUlf Hansson 
mmc_test_read_high(struct mmc_test_card * test)1315f397c8d8SUlf Hansson static int mmc_test_read_high(struct mmc_test_card *test)
1316f397c8d8SUlf Hansson {
1317f397c8d8SUlf Hansson 	struct scatterlist sg;
1318f397c8d8SUlf Hansson 
1319f397c8d8SUlf Hansson 	sg_init_table(&sg, 1);
1320f397c8d8SUlf Hansson 	sg_set_page(&sg, test->highmem, 512, 0);
1321f397c8d8SUlf Hansson 
1322f397c8d8SUlf Hansson 	return mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0);
1323f397c8d8SUlf Hansson }
1324f397c8d8SUlf Hansson 
mmc_test_multi_write_high(struct mmc_test_card * test)1325f397c8d8SUlf Hansson static int mmc_test_multi_write_high(struct mmc_test_card *test)
1326f397c8d8SUlf Hansson {
1327f397c8d8SUlf Hansson 	unsigned int size;
1328f397c8d8SUlf Hansson 	struct scatterlist sg;
1329f397c8d8SUlf Hansson 
1330f397c8d8SUlf Hansson 	if (test->card->host->max_blk_count == 1)
1331f397c8d8SUlf Hansson 		return RESULT_UNSUP_HOST;
1332f397c8d8SUlf Hansson 
1333f397c8d8SUlf Hansson 	size = PAGE_SIZE * 2;
1334f397c8d8SUlf Hansson 	size = min(size, test->card->host->max_req_size);
1335f397c8d8SUlf Hansson 	size = min(size, test->card->host->max_seg_size);
1336f397c8d8SUlf Hansson 	size = min(size, test->card->host->max_blk_count * 512);
1337f397c8d8SUlf Hansson 
1338f397c8d8SUlf Hansson 	if (size < 1024)
1339f397c8d8SUlf Hansson 		return RESULT_UNSUP_HOST;
1340f397c8d8SUlf Hansson 
1341f397c8d8SUlf Hansson 	sg_init_table(&sg, 1);
1342f397c8d8SUlf Hansson 	sg_set_page(&sg, test->highmem, size, 0);
1343f397c8d8SUlf Hansson 
1344f397c8d8SUlf Hansson 	return mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 1);
1345f397c8d8SUlf Hansson }
1346f397c8d8SUlf Hansson 
mmc_test_multi_read_high(struct mmc_test_card * test)1347f397c8d8SUlf Hansson static int mmc_test_multi_read_high(struct mmc_test_card *test)
1348f397c8d8SUlf Hansson {
1349f397c8d8SUlf Hansson 	unsigned int size;
1350f397c8d8SUlf Hansson 	struct scatterlist sg;
1351f397c8d8SUlf Hansson 
1352f397c8d8SUlf Hansson 	if (test->card->host->max_blk_count == 1)
1353f397c8d8SUlf Hansson 		return RESULT_UNSUP_HOST;
1354f397c8d8SUlf Hansson 
1355f397c8d8SUlf Hansson 	size = PAGE_SIZE * 2;
1356f397c8d8SUlf Hansson 	size = min(size, test->card->host->max_req_size);
1357f397c8d8SUlf Hansson 	size = min(size, test->card->host->max_seg_size);
1358f397c8d8SUlf Hansson 	size = min(size, test->card->host->max_blk_count * 512);
1359f397c8d8SUlf Hansson 
1360f397c8d8SUlf Hansson 	if (size < 1024)
1361f397c8d8SUlf Hansson 		return RESULT_UNSUP_HOST;
1362f397c8d8SUlf Hansson 
1363f397c8d8SUlf Hansson 	sg_init_table(&sg, 1);
1364f397c8d8SUlf Hansson 	sg_set_page(&sg, test->highmem, size, 0);
1365f397c8d8SUlf Hansson 
1366f397c8d8SUlf Hansson 	return mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 0);
1367f397c8d8SUlf Hansson }
1368f397c8d8SUlf Hansson 
1369f397c8d8SUlf Hansson #else
1370f397c8d8SUlf Hansson 
mmc_test_no_highmem(struct mmc_test_card * test)1371f397c8d8SUlf Hansson static int mmc_test_no_highmem(struct mmc_test_card *test)
1372f397c8d8SUlf Hansson {
1373f397c8d8SUlf Hansson 	pr_info("%s: Highmem not configured - test skipped\n",
1374f397c8d8SUlf Hansson 	       mmc_hostname(test->card->host));
1375f397c8d8SUlf Hansson 	return 0;
1376f397c8d8SUlf Hansson }
1377f397c8d8SUlf Hansson 
1378f397c8d8SUlf Hansson #endif /* CONFIG_HIGHMEM */
1379f397c8d8SUlf Hansson 
1380f397c8d8SUlf Hansson /*
1381f397c8d8SUlf Hansson  * Map sz bytes so that it can be transferred.
1382f397c8d8SUlf Hansson  */
mmc_test_area_map(struct mmc_test_card * test,unsigned long sz,int max_scatter,int min_sg_len,bool nonblock)1383f397c8d8SUlf Hansson static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz,
1384ea21e9b2SVeerabhadrarao Badiganti 			     int max_scatter, int min_sg_len, bool nonblock)
1385f397c8d8SUlf Hansson {
1386f397c8d8SUlf Hansson 	struct mmc_test_area *t = &test->area;
1387f397c8d8SUlf Hansson 	int err;
1388ea21e9b2SVeerabhadrarao Badiganti 	unsigned int sg_len = 0;
1389f397c8d8SUlf Hansson 
1390f397c8d8SUlf Hansson 	t->blocks = sz >> 9;
1391f397c8d8SUlf Hansson 
1392f397c8d8SUlf Hansson 	if (max_scatter) {
1393f397c8d8SUlf Hansson 		err = mmc_test_map_sg_max_scatter(t->mem, sz, t->sg,
1394f397c8d8SUlf Hansson 						  t->max_segs, t->max_seg_sz,
1395f397c8d8SUlf Hansson 				       &t->sg_len);
1396f397c8d8SUlf Hansson 	} else {
1397f397c8d8SUlf Hansson 		err = mmc_test_map_sg(t->mem, sz, t->sg, 1, t->max_segs,
1398f397c8d8SUlf Hansson 				      t->max_seg_sz, &t->sg_len, min_sg_len);
1399f397c8d8SUlf Hansson 	}
1400ea21e9b2SVeerabhadrarao Badiganti 
1401ea21e9b2SVeerabhadrarao Badiganti 	if (err || !nonblock)
1402ea21e9b2SVeerabhadrarao Badiganti 		goto err;
1403ea21e9b2SVeerabhadrarao Badiganti 
1404ea21e9b2SVeerabhadrarao Badiganti 	if (max_scatter) {
1405ea21e9b2SVeerabhadrarao Badiganti 		err = mmc_test_map_sg_max_scatter(t->mem, sz, t->sg_areq,
1406ea21e9b2SVeerabhadrarao Badiganti 						  t->max_segs, t->max_seg_sz,
1407ea21e9b2SVeerabhadrarao Badiganti 						  &sg_len);
1408ea21e9b2SVeerabhadrarao Badiganti 	} else {
1409ea21e9b2SVeerabhadrarao Badiganti 		err = mmc_test_map_sg(t->mem, sz, t->sg_areq, 1, t->max_segs,
1410ea21e9b2SVeerabhadrarao Badiganti 				      t->max_seg_sz, &sg_len, min_sg_len);
1411ea21e9b2SVeerabhadrarao Badiganti 	}
1412ea21e9b2SVeerabhadrarao Badiganti 	if (!err && sg_len != t->sg_len)
1413ea21e9b2SVeerabhadrarao Badiganti 		err = -EINVAL;
1414ea21e9b2SVeerabhadrarao Badiganti 
1415ea21e9b2SVeerabhadrarao Badiganti err:
1416f397c8d8SUlf Hansson 	if (err)
1417f397c8d8SUlf Hansson 		pr_info("%s: Failed to map sg list\n",
1418f397c8d8SUlf Hansson 		       mmc_hostname(test->card->host));
1419f397c8d8SUlf Hansson 	return err;
1420f397c8d8SUlf Hansson }
1421f397c8d8SUlf Hansson 
1422f397c8d8SUlf Hansson /*
1423f397c8d8SUlf Hansson  * Transfer bytes mapped by mmc_test_area_map().
1424f397c8d8SUlf Hansson  */
mmc_test_area_transfer(struct mmc_test_card * test,unsigned int dev_addr,int write)1425f397c8d8SUlf Hansson static int mmc_test_area_transfer(struct mmc_test_card *test,
1426f397c8d8SUlf Hansson 				  unsigned int dev_addr, int write)
1427f397c8d8SUlf Hansson {
1428f397c8d8SUlf Hansson 	struct mmc_test_area *t = &test->area;
1429f397c8d8SUlf Hansson 
1430f397c8d8SUlf Hansson 	return mmc_test_simple_transfer(test, t->sg, t->sg_len, dev_addr,
1431f397c8d8SUlf Hansson 					t->blocks, 512, write);
1432f397c8d8SUlf Hansson }
1433f397c8d8SUlf Hansson 
1434f397c8d8SUlf Hansson /*
1435f397c8d8SUlf Hansson  * Map and transfer bytes for multiple transfers.
1436f397c8d8SUlf Hansson  */
mmc_test_area_io_seq(struct mmc_test_card * test,unsigned long sz,unsigned int dev_addr,int write,int max_scatter,int timed,int count,bool nonblock,int min_sg_len)1437f397c8d8SUlf Hansson static int mmc_test_area_io_seq(struct mmc_test_card *test, unsigned long sz,
1438f397c8d8SUlf Hansson 				unsigned int dev_addr, int write,
1439f397c8d8SUlf Hansson 				int max_scatter, int timed, int count,
1440f397c8d8SUlf Hansson 				bool nonblock, int min_sg_len)
1441f397c8d8SUlf Hansson {
1442a5b97be2SArnd Bergmann 	struct timespec64 ts1, ts2;
1443f397c8d8SUlf Hansson 	int ret = 0;
1444f397c8d8SUlf Hansson 	int i;
1445f397c8d8SUlf Hansson 
1446f397c8d8SUlf Hansson 	/*
1447f397c8d8SUlf Hansson 	 * In the case of a maximally scattered transfer, the maximum transfer
1448f397c8d8SUlf Hansson 	 * size is further limited by using PAGE_SIZE segments.
1449f397c8d8SUlf Hansson 	 */
1450f397c8d8SUlf Hansson 	if (max_scatter) {
1451f397c8d8SUlf Hansson 		struct mmc_test_area *t = &test->area;
1452f397c8d8SUlf Hansson 		unsigned long max_tfr;
1453f397c8d8SUlf Hansson 
1454f397c8d8SUlf Hansson 		if (t->max_seg_sz >= PAGE_SIZE)
1455f397c8d8SUlf Hansson 			max_tfr = t->max_segs * PAGE_SIZE;
1456f397c8d8SUlf Hansson 		else
1457f397c8d8SUlf Hansson 			max_tfr = t->max_segs * t->max_seg_sz;
1458f397c8d8SUlf Hansson 		if (sz > max_tfr)
1459f397c8d8SUlf Hansson 			sz = max_tfr;
1460f397c8d8SUlf Hansson 	}
1461f397c8d8SUlf Hansson 
1462ea21e9b2SVeerabhadrarao Badiganti 	ret = mmc_test_area_map(test, sz, max_scatter, min_sg_len, nonblock);
1463f397c8d8SUlf Hansson 	if (ret)
1464f397c8d8SUlf Hansson 		return ret;
1465f397c8d8SUlf Hansson 
1466f397c8d8SUlf Hansson 	if (timed)
1467a5b97be2SArnd Bergmann 		ktime_get_ts64(&ts1);
1468f397c8d8SUlf Hansson 	if (nonblock)
1469ea21e9b2SVeerabhadrarao Badiganti 		ret = mmc_test_nonblock_transfer(test, dev_addr, write, count);
1470f397c8d8SUlf Hansson 	else
1471f397c8d8SUlf Hansson 		for (i = 0; i < count && ret == 0; i++) {
1472f397c8d8SUlf Hansson 			ret = mmc_test_area_transfer(test, dev_addr, write);
1473f397c8d8SUlf Hansson 			dev_addr += sz >> 9;
1474f397c8d8SUlf Hansson 		}
1475f397c8d8SUlf Hansson 
1476f397c8d8SUlf Hansson 	if (ret)
1477f397c8d8SUlf Hansson 		return ret;
1478f397c8d8SUlf Hansson 
1479f397c8d8SUlf Hansson 	if (timed)
1480a5b97be2SArnd Bergmann 		ktime_get_ts64(&ts2);
1481f397c8d8SUlf Hansson 
1482f397c8d8SUlf Hansson 	if (timed)
1483f397c8d8SUlf Hansson 		mmc_test_print_avg_rate(test, sz, count, &ts1, &ts2);
1484f397c8d8SUlf Hansson 
1485f397c8d8SUlf Hansson 	return 0;
1486f397c8d8SUlf Hansson }
1487f397c8d8SUlf Hansson 
mmc_test_area_io(struct mmc_test_card * test,unsigned long sz,unsigned int dev_addr,int write,int max_scatter,int timed)1488f397c8d8SUlf Hansson static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
1489f397c8d8SUlf Hansson 			    unsigned int dev_addr, int write, int max_scatter,
1490f397c8d8SUlf Hansson 			    int timed)
1491f397c8d8SUlf Hansson {
1492f397c8d8SUlf Hansson 	return mmc_test_area_io_seq(test, sz, dev_addr, write, max_scatter,
1493f397c8d8SUlf Hansson 				    timed, 1, false, 0);
1494f397c8d8SUlf Hansson }
1495f397c8d8SUlf Hansson 
1496f397c8d8SUlf Hansson /*
1497f397c8d8SUlf Hansson  * Write the test area entirely.
1498f397c8d8SUlf Hansson  */
mmc_test_area_fill(struct mmc_test_card * test)1499f397c8d8SUlf Hansson static int mmc_test_area_fill(struct mmc_test_card *test)
1500f397c8d8SUlf Hansson {
1501f397c8d8SUlf Hansson 	struct mmc_test_area *t = &test->area;
1502f397c8d8SUlf Hansson 
1503f397c8d8SUlf Hansson 	return mmc_test_area_io(test, t->max_tfr, t->dev_addr, 1, 0, 0);
1504f397c8d8SUlf Hansson }
1505f397c8d8SUlf Hansson 
1506f397c8d8SUlf Hansson /*
1507f397c8d8SUlf Hansson  * Erase the test area entirely.
1508f397c8d8SUlf Hansson  */
mmc_test_area_erase(struct mmc_test_card * test)1509f397c8d8SUlf Hansson static int mmc_test_area_erase(struct mmc_test_card *test)
1510f397c8d8SUlf Hansson {
1511f397c8d8SUlf Hansson 	struct mmc_test_area *t = &test->area;
1512f397c8d8SUlf Hansson 
1513f397c8d8SUlf Hansson 	if (!mmc_can_erase(test->card))
1514f397c8d8SUlf Hansson 		return 0;
1515f397c8d8SUlf Hansson 
1516f397c8d8SUlf Hansson 	return mmc_erase(test->card, t->dev_addr, t->max_sz >> 9,
1517f397c8d8SUlf Hansson 			 MMC_ERASE_ARG);
1518f397c8d8SUlf Hansson }
1519f397c8d8SUlf Hansson 
1520f397c8d8SUlf Hansson /*
1521f397c8d8SUlf Hansson  * Cleanup struct mmc_test_area.
1522f397c8d8SUlf Hansson  */
mmc_test_area_cleanup(struct mmc_test_card * test)1523f397c8d8SUlf Hansson static int mmc_test_area_cleanup(struct mmc_test_card *test)
1524f397c8d8SUlf Hansson {
1525f397c8d8SUlf Hansson 	struct mmc_test_area *t = &test->area;
1526f397c8d8SUlf Hansson 
1527f397c8d8SUlf Hansson 	kfree(t->sg);
1528ea21e9b2SVeerabhadrarao Badiganti 	kfree(t->sg_areq);
1529f397c8d8SUlf Hansson 	mmc_test_free_mem(t->mem);
1530f397c8d8SUlf Hansson 
1531f397c8d8SUlf Hansson 	return 0;
1532f397c8d8SUlf Hansson }
1533f397c8d8SUlf Hansson 
1534f397c8d8SUlf Hansson /*
1535f397c8d8SUlf Hansson  * Initialize an area for testing large transfers.  The test area is set to the
153674536bc0SMarkus Elfring  * middle of the card because cards may have different characteristics at the
1537f397c8d8SUlf Hansson  * front (for FAT file system optimization).  Optionally, the area is erased
1538f397c8d8SUlf Hansson  * (if the card supports it) which may improve write performance.  Optionally,
1539f397c8d8SUlf Hansson  * the area is filled with data for subsequent read tests.
1540f397c8d8SUlf Hansson  */
mmc_test_area_init(struct mmc_test_card * test,int erase,int fill)1541f397c8d8SUlf Hansson static int mmc_test_area_init(struct mmc_test_card *test, int erase, int fill)
1542f397c8d8SUlf Hansson {
1543f397c8d8SUlf Hansson 	struct mmc_test_area *t = &test->area;
1544f397c8d8SUlf Hansson 	unsigned long min_sz = 64 * 1024, sz;
1545f397c8d8SUlf Hansson 	int ret;
1546f397c8d8SUlf Hansson 
1547f397c8d8SUlf Hansson 	ret = mmc_test_set_blksize(test, 512);
1548f397c8d8SUlf Hansson 	if (ret)
1549f397c8d8SUlf Hansson 		return ret;
1550f397c8d8SUlf Hansson 
1551f397c8d8SUlf Hansson 	/* Make the test area size about 4MiB */
1552f397c8d8SUlf Hansson 	sz = (unsigned long)test->card->pref_erase << 9;
1553f397c8d8SUlf Hansson 	t->max_sz = sz;
1554f397c8d8SUlf Hansson 	while (t->max_sz < 4 * 1024 * 1024)
1555f397c8d8SUlf Hansson 		t->max_sz += sz;
1556f397c8d8SUlf Hansson 	while (t->max_sz > TEST_AREA_MAX_SIZE && t->max_sz > sz)
1557f397c8d8SUlf Hansson 		t->max_sz -= sz;
1558f397c8d8SUlf Hansson 
1559f397c8d8SUlf Hansson 	t->max_segs = test->card->host->max_segs;
1560f397c8d8SUlf Hansson 	t->max_seg_sz = test->card->host->max_seg_size;
1561f397c8d8SUlf Hansson 	t->max_seg_sz -= t->max_seg_sz % 512;
1562f397c8d8SUlf Hansson 
1563f397c8d8SUlf Hansson 	t->max_tfr = t->max_sz;
1564f397c8d8SUlf Hansson 	if (t->max_tfr >> 9 > test->card->host->max_blk_count)
1565f397c8d8SUlf Hansson 		t->max_tfr = test->card->host->max_blk_count << 9;
1566f397c8d8SUlf Hansson 	if (t->max_tfr > test->card->host->max_req_size)
1567f397c8d8SUlf Hansson 		t->max_tfr = test->card->host->max_req_size;
1568f397c8d8SUlf Hansson 	if (t->max_tfr / t->max_seg_sz > t->max_segs)
1569f397c8d8SUlf Hansson 		t->max_tfr = t->max_segs * t->max_seg_sz;
1570f397c8d8SUlf Hansson 
1571f397c8d8SUlf Hansson 	/*
1572f397c8d8SUlf Hansson 	 * Try to allocate enough memory for a max. sized transfer.  Less is OK
1573f397c8d8SUlf Hansson 	 * because the same memory can be mapped into the scatterlist more than
1574f397c8d8SUlf Hansson 	 * once.  Also, take into account the limits imposed on scatterlist
1575f397c8d8SUlf Hansson 	 * segments by the host driver.
1576f397c8d8SUlf Hansson 	 */
1577f397c8d8SUlf Hansson 	t->mem = mmc_test_alloc_mem(min_sz, t->max_tfr, t->max_segs,
1578f397c8d8SUlf Hansson 				    t->max_seg_sz);
1579f397c8d8SUlf Hansson 	if (!t->mem)
1580f397c8d8SUlf Hansson 		return -ENOMEM;
1581f397c8d8SUlf Hansson 
1582457e4f7fSMarkus Elfring 	t->sg = kmalloc_array(t->max_segs, sizeof(*t->sg), GFP_KERNEL);
1583f397c8d8SUlf Hansson 	if (!t->sg) {
1584f397c8d8SUlf Hansson 		ret = -ENOMEM;
1585f397c8d8SUlf Hansson 		goto out_free;
1586f397c8d8SUlf Hansson 	}
1587f397c8d8SUlf Hansson 
1588ea21e9b2SVeerabhadrarao Badiganti 	t->sg_areq = kmalloc_array(t->max_segs, sizeof(*t->sg_areq),
1589ea21e9b2SVeerabhadrarao Badiganti 				   GFP_KERNEL);
1590ea21e9b2SVeerabhadrarao Badiganti 	if (!t->sg_areq) {
1591ea21e9b2SVeerabhadrarao Badiganti 		ret = -ENOMEM;
1592ea21e9b2SVeerabhadrarao Badiganti 		goto out_free;
1593ea21e9b2SVeerabhadrarao Badiganti 	}
1594ea21e9b2SVeerabhadrarao Badiganti 
1595f397c8d8SUlf Hansson 	t->dev_addr = mmc_test_capacity(test->card) / 2;
1596f397c8d8SUlf Hansson 	t->dev_addr -= t->dev_addr % (t->max_sz >> 9);
1597f397c8d8SUlf Hansson 
1598f397c8d8SUlf Hansson 	if (erase) {
1599f397c8d8SUlf Hansson 		ret = mmc_test_area_erase(test);
1600f397c8d8SUlf Hansson 		if (ret)
1601f397c8d8SUlf Hansson 			goto out_free;
1602f397c8d8SUlf Hansson 	}
1603f397c8d8SUlf Hansson 
1604f397c8d8SUlf Hansson 	if (fill) {
1605f397c8d8SUlf Hansson 		ret = mmc_test_area_fill(test);
1606f397c8d8SUlf Hansson 		if (ret)
1607f397c8d8SUlf Hansson 			goto out_free;
1608f397c8d8SUlf Hansson 	}
1609f397c8d8SUlf Hansson 
1610f397c8d8SUlf Hansson 	return 0;
1611f397c8d8SUlf Hansson 
1612f397c8d8SUlf Hansson out_free:
1613f397c8d8SUlf Hansson 	mmc_test_area_cleanup(test);
1614f397c8d8SUlf Hansson 	return ret;
1615f397c8d8SUlf Hansson }
1616f397c8d8SUlf Hansson 
1617f397c8d8SUlf Hansson /*
1618f397c8d8SUlf Hansson  * Prepare for large transfers.  Do not erase the test area.
1619f397c8d8SUlf Hansson  */
mmc_test_area_prepare(struct mmc_test_card * test)1620f397c8d8SUlf Hansson static int mmc_test_area_prepare(struct mmc_test_card *test)
1621f397c8d8SUlf Hansson {
1622f397c8d8SUlf Hansson 	return mmc_test_area_init(test, 0, 0);
1623f397c8d8SUlf Hansson }
1624f397c8d8SUlf Hansson 
1625f397c8d8SUlf Hansson /*
1626f397c8d8SUlf Hansson  * Prepare for large transfers.  Do erase the test area.
1627f397c8d8SUlf Hansson  */
mmc_test_area_prepare_erase(struct mmc_test_card * test)1628f397c8d8SUlf Hansson static int mmc_test_area_prepare_erase(struct mmc_test_card *test)
1629f397c8d8SUlf Hansson {
1630f397c8d8SUlf Hansson 	return mmc_test_area_init(test, 1, 0);
1631f397c8d8SUlf Hansson }
1632f397c8d8SUlf Hansson 
1633f397c8d8SUlf Hansson /*
1634f397c8d8SUlf Hansson  * Prepare for large transfers.  Erase and fill the test area.
1635f397c8d8SUlf Hansson  */
mmc_test_area_prepare_fill(struct mmc_test_card * test)1636f397c8d8SUlf Hansson static int mmc_test_area_prepare_fill(struct mmc_test_card *test)
1637f397c8d8SUlf Hansson {
1638f397c8d8SUlf Hansson 	return mmc_test_area_init(test, 1, 1);
1639f397c8d8SUlf Hansson }
1640f397c8d8SUlf Hansson 
1641f397c8d8SUlf Hansson /*
1642f397c8d8SUlf Hansson  * Test best-case performance.  Best-case performance is expected from
1643f397c8d8SUlf Hansson  * a single large transfer.
1644f397c8d8SUlf Hansson  *
1645f397c8d8SUlf Hansson  * An additional option (max_scatter) allows the measurement of the same
1646f397c8d8SUlf Hansson  * transfer but with no contiguous pages in the scatter list.  This tests
1647f397c8d8SUlf Hansson  * the efficiency of DMA to handle scattered pages.
1648f397c8d8SUlf Hansson  */
mmc_test_best_performance(struct mmc_test_card * test,int write,int max_scatter)1649f397c8d8SUlf Hansson static int mmc_test_best_performance(struct mmc_test_card *test, int write,
1650f397c8d8SUlf Hansson 				     int max_scatter)
1651f397c8d8SUlf Hansson {
1652f397c8d8SUlf Hansson 	struct mmc_test_area *t = &test->area;
1653f397c8d8SUlf Hansson 
1654f397c8d8SUlf Hansson 	return mmc_test_area_io(test, t->max_tfr, t->dev_addr, write,
1655f397c8d8SUlf Hansson 				max_scatter, 1);
1656f397c8d8SUlf Hansson }
1657f397c8d8SUlf Hansson 
1658f397c8d8SUlf Hansson /*
1659f397c8d8SUlf Hansson  * Best-case read performance.
1660f397c8d8SUlf Hansson  */
mmc_test_best_read_performance(struct mmc_test_card * test)1661f397c8d8SUlf Hansson static int mmc_test_best_read_performance(struct mmc_test_card *test)
1662f397c8d8SUlf Hansson {
1663f397c8d8SUlf Hansson 	return mmc_test_best_performance(test, 0, 0);
1664f397c8d8SUlf Hansson }
1665f397c8d8SUlf Hansson 
1666f397c8d8SUlf Hansson /*
1667f397c8d8SUlf Hansson  * Best-case write performance.
1668f397c8d8SUlf Hansson  */
mmc_test_best_write_performance(struct mmc_test_card * test)1669f397c8d8SUlf Hansson static int mmc_test_best_write_performance(struct mmc_test_card *test)
1670f397c8d8SUlf Hansson {
1671f397c8d8SUlf Hansson 	return mmc_test_best_performance(test, 1, 0);
1672f397c8d8SUlf Hansson }
1673f397c8d8SUlf Hansson 
1674f397c8d8SUlf Hansson /*
1675f397c8d8SUlf Hansson  * Best-case read performance into scattered pages.
1676f397c8d8SUlf Hansson  */
mmc_test_best_read_perf_max_scatter(struct mmc_test_card * test)1677f397c8d8SUlf Hansson static int mmc_test_best_read_perf_max_scatter(struct mmc_test_card *test)
1678f397c8d8SUlf Hansson {
1679f397c8d8SUlf Hansson 	return mmc_test_best_performance(test, 0, 1);
1680f397c8d8SUlf Hansson }
1681f397c8d8SUlf Hansson 
1682f397c8d8SUlf Hansson /*
1683f397c8d8SUlf Hansson  * Best-case write performance from scattered pages.
1684f397c8d8SUlf Hansson  */
mmc_test_best_write_perf_max_scatter(struct mmc_test_card * test)1685f397c8d8SUlf Hansson static int mmc_test_best_write_perf_max_scatter(struct mmc_test_card *test)
1686f397c8d8SUlf Hansson {
1687f397c8d8SUlf Hansson 	return mmc_test_best_performance(test, 1, 1);
1688f397c8d8SUlf Hansson }
1689f397c8d8SUlf Hansson 
1690f397c8d8SUlf Hansson /*
1691f397c8d8SUlf Hansson  * Single read performance by transfer size.
1692f397c8d8SUlf Hansson  */
mmc_test_profile_read_perf(struct mmc_test_card * test)1693f397c8d8SUlf Hansson static int mmc_test_profile_read_perf(struct mmc_test_card *test)
1694f397c8d8SUlf Hansson {
1695f397c8d8SUlf Hansson 	struct mmc_test_area *t = &test->area;
1696f397c8d8SUlf Hansson 	unsigned long sz;
1697f397c8d8SUlf Hansson 	unsigned int dev_addr;
1698f397c8d8SUlf Hansson 	int ret;
1699f397c8d8SUlf Hansson 
1700f397c8d8SUlf Hansson 	for (sz = 512; sz < t->max_tfr; sz <<= 1) {
1701f397c8d8SUlf Hansson 		dev_addr = t->dev_addr + (sz >> 9);
1702f397c8d8SUlf Hansson 		ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 1);
1703f397c8d8SUlf Hansson 		if (ret)
1704f397c8d8SUlf Hansson 			return ret;
1705f397c8d8SUlf Hansson 	}
1706f397c8d8SUlf Hansson 	sz = t->max_tfr;
1707f397c8d8SUlf Hansson 	dev_addr = t->dev_addr;
1708f397c8d8SUlf Hansson 	return mmc_test_area_io(test, sz, dev_addr, 0, 0, 1);
1709f397c8d8SUlf Hansson }
1710f397c8d8SUlf Hansson 
1711f397c8d8SUlf Hansson /*
1712f397c8d8SUlf Hansson  * Single write performance by transfer size.
1713f397c8d8SUlf Hansson  */
mmc_test_profile_write_perf(struct mmc_test_card * test)1714f397c8d8SUlf Hansson static int mmc_test_profile_write_perf(struct mmc_test_card *test)
1715f397c8d8SUlf Hansson {
1716f397c8d8SUlf Hansson 	struct mmc_test_area *t = &test->area;
1717f397c8d8SUlf Hansson 	unsigned long sz;
1718f397c8d8SUlf Hansson 	unsigned int dev_addr;
1719f397c8d8SUlf Hansson 	int ret;
1720f397c8d8SUlf Hansson 
1721f397c8d8SUlf Hansson 	ret = mmc_test_area_erase(test);
1722f397c8d8SUlf Hansson 	if (ret)
1723f397c8d8SUlf Hansson 		return ret;
1724f397c8d8SUlf Hansson 	for (sz = 512; sz < t->max_tfr; sz <<= 1) {
1725f397c8d8SUlf Hansson 		dev_addr = t->dev_addr + (sz >> 9);
1726f397c8d8SUlf Hansson 		ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 1);
1727f397c8d8SUlf Hansson 		if (ret)
1728f397c8d8SUlf Hansson 			return ret;
1729f397c8d8SUlf Hansson 	}
1730f397c8d8SUlf Hansson 	ret = mmc_test_area_erase(test);
1731f397c8d8SUlf Hansson 	if (ret)
1732f397c8d8SUlf Hansson 		return ret;
1733f397c8d8SUlf Hansson 	sz = t->max_tfr;
1734f397c8d8SUlf Hansson 	dev_addr = t->dev_addr;
1735f397c8d8SUlf Hansson 	return mmc_test_area_io(test, sz, dev_addr, 1, 0, 1);
1736f397c8d8SUlf Hansson }
1737f397c8d8SUlf Hansson 
1738f397c8d8SUlf Hansson /*
1739f397c8d8SUlf Hansson  * Single trim performance by transfer size.
1740f397c8d8SUlf Hansson  */
mmc_test_profile_trim_perf(struct mmc_test_card * test)1741f397c8d8SUlf Hansson static int mmc_test_profile_trim_perf(struct mmc_test_card *test)
1742f397c8d8SUlf Hansson {
1743f397c8d8SUlf Hansson 	struct mmc_test_area *t = &test->area;
1744f397c8d8SUlf Hansson 	unsigned long sz;
1745f397c8d8SUlf Hansson 	unsigned int dev_addr;
1746a5b97be2SArnd Bergmann 	struct timespec64 ts1, ts2;
1747f397c8d8SUlf Hansson 	int ret;
1748f397c8d8SUlf Hansson 
1749f397c8d8SUlf Hansson 	if (!mmc_can_trim(test->card))
1750f397c8d8SUlf Hansson 		return RESULT_UNSUP_CARD;
1751f397c8d8SUlf Hansson 
1752f397c8d8SUlf Hansson 	if (!mmc_can_erase(test->card))
1753f397c8d8SUlf Hansson 		return RESULT_UNSUP_HOST;
1754f397c8d8SUlf Hansson 
1755f397c8d8SUlf Hansson 	for (sz = 512; sz < t->max_sz; sz <<= 1) {
1756f397c8d8SUlf Hansson 		dev_addr = t->dev_addr + (sz >> 9);
1757a5b97be2SArnd Bergmann 		ktime_get_ts64(&ts1);
1758f397c8d8SUlf Hansson 		ret = mmc_erase(test->card, dev_addr, sz >> 9, MMC_TRIM_ARG);
1759f397c8d8SUlf Hansson 		if (ret)
1760f397c8d8SUlf Hansson 			return ret;
1761a5b97be2SArnd Bergmann 		ktime_get_ts64(&ts2);
1762f397c8d8SUlf Hansson 		mmc_test_print_rate(test, sz, &ts1, &ts2);
1763f397c8d8SUlf Hansson 	}
1764f397c8d8SUlf Hansson 	dev_addr = t->dev_addr;
1765a5b97be2SArnd Bergmann 	ktime_get_ts64(&ts1);
1766f397c8d8SUlf Hansson 	ret = mmc_erase(test->card, dev_addr, sz >> 9, MMC_TRIM_ARG);
1767f397c8d8SUlf Hansson 	if (ret)
1768f397c8d8SUlf Hansson 		return ret;
1769a5b97be2SArnd Bergmann 	ktime_get_ts64(&ts2);
1770f397c8d8SUlf Hansson 	mmc_test_print_rate(test, sz, &ts1, &ts2);
1771f397c8d8SUlf Hansson 	return 0;
1772f397c8d8SUlf Hansson }
1773f397c8d8SUlf Hansson 
mmc_test_seq_read_perf(struct mmc_test_card * test,unsigned long sz)1774f397c8d8SUlf Hansson static int mmc_test_seq_read_perf(struct mmc_test_card *test, unsigned long sz)
1775f397c8d8SUlf Hansson {
1776f397c8d8SUlf Hansson 	struct mmc_test_area *t = &test->area;
1777f397c8d8SUlf Hansson 	unsigned int dev_addr, i, cnt;
1778a5b97be2SArnd Bergmann 	struct timespec64 ts1, ts2;
1779f397c8d8SUlf Hansson 	int ret;
1780f397c8d8SUlf Hansson 
1781f397c8d8SUlf Hansson 	cnt = t->max_sz / sz;
1782f397c8d8SUlf Hansson 	dev_addr = t->dev_addr;
1783a5b97be2SArnd Bergmann 	ktime_get_ts64(&ts1);
1784f397c8d8SUlf Hansson 	for (i = 0; i < cnt; i++) {
1785f397c8d8SUlf Hansson 		ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 0);
1786f397c8d8SUlf Hansson 		if (ret)
1787f397c8d8SUlf Hansson 			return ret;
1788f397c8d8SUlf Hansson 		dev_addr += (sz >> 9);
1789f397c8d8SUlf Hansson 	}
1790a5b97be2SArnd Bergmann 	ktime_get_ts64(&ts2);
1791f397c8d8SUlf Hansson 	mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
1792f397c8d8SUlf Hansson 	return 0;
1793f397c8d8SUlf Hansson }
1794f397c8d8SUlf Hansson 
1795f397c8d8SUlf Hansson /*
1796f397c8d8SUlf Hansson  * Consecutive read performance by transfer size.
1797f397c8d8SUlf Hansson  */
mmc_test_profile_seq_read_perf(struct mmc_test_card * test)1798f397c8d8SUlf Hansson static int mmc_test_profile_seq_read_perf(struct mmc_test_card *test)
1799f397c8d8SUlf Hansson {
1800f397c8d8SUlf Hansson 	struct mmc_test_area *t = &test->area;
1801f397c8d8SUlf Hansson 	unsigned long sz;
1802f397c8d8SUlf Hansson 	int ret;
1803f397c8d8SUlf Hansson 
1804f397c8d8SUlf Hansson 	for (sz = 512; sz < t->max_tfr; sz <<= 1) {
1805f397c8d8SUlf Hansson 		ret = mmc_test_seq_read_perf(test, sz);
1806f397c8d8SUlf Hansson 		if (ret)
1807f397c8d8SUlf Hansson 			return ret;
1808f397c8d8SUlf Hansson 	}
1809f397c8d8SUlf Hansson 	sz = t->max_tfr;
1810f397c8d8SUlf Hansson 	return mmc_test_seq_read_perf(test, sz);
1811f397c8d8SUlf Hansson }
1812f397c8d8SUlf Hansson 
mmc_test_seq_write_perf(struct mmc_test_card * test,unsigned long sz)1813f397c8d8SUlf Hansson static int mmc_test_seq_write_perf(struct mmc_test_card *test, unsigned long sz)
1814f397c8d8SUlf Hansson {
1815f397c8d8SUlf Hansson 	struct mmc_test_area *t = &test->area;
1816f397c8d8SUlf Hansson 	unsigned int dev_addr, i, cnt;
1817a5b97be2SArnd Bergmann 	struct timespec64 ts1, ts2;
1818f397c8d8SUlf Hansson 	int ret;
1819f397c8d8SUlf Hansson 
1820f397c8d8SUlf Hansson 	ret = mmc_test_area_erase(test);
1821f397c8d8SUlf Hansson 	if (ret)
1822f397c8d8SUlf Hansson 		return ret;
1823f397c8d8SUlf Hansson 	cnt = t->max_sz / sz;
1824f397c8d8SUlf Hansson 	dev_addr = t->dev_addr;
1825a5b97be2SArnd Bergmann 	ktime_get_ts64(&ts1);
1826f397c8d8SUlf Hansson 	for (i = 0; i < cnt; i++) {
1827f397c8d8SUlf Hansson 		ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 0);
1828f397c8d8SUlf Hansson 		if (ret)
1829f397c8d8SUlf Hansson 			return ret;
1830f397c8d8SUlf Hansson 		dev_addr += (sz >> 9);
1831f397c8d8SUlf Hansson 	}
1832a5b97be2SArnd Bergmann 	ktime_get_ts64(&ts2);
1833f397c8d8SUlf Hansson 	mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
1834f397c8d8SUlf Hansson 	return 0;
1835f397c8d8SUlf Hansson }
1836f397c8d8SUlf Hansson 
1837f397c8d8SUlf Hansson /*
1838f397c8d8SUlf Hansson  * Consecutive write performance by transfer size.
1839f397c8d8SUlf Hansson  */
mmc_test_profile_seq_write_perf(struct mmc_test_card * test)1840f397c8d8SUlf Hansson static int mmc_test_profile_seq_write_perf(struct mmc_test_card *test)
1841f397c8d8SUlf Hansson {
1842f397c8d8SUlf Hansson 	struct mmc_test_area *t = &test->area;
1843f397c8d8SUlf Hansson 	unsigned long sz;
1844f397c8d8SUlf Hansson 	int ret;
1845f397c8d8SUlf Hansson 
1846f397c8d8SUlf Hansson 	for (sz = 512; sz < t->max_tfr; sz <<= 1) {
1847f397c8d8SUlf Hansson 		ret = mmc_test_seq_write_perf(test, sz);
1848f397c8d8SUlf Hansson 		if (ret)
1849f397c8d8SUlf Hansson 			return ret;
1850f397c8d8SUlf Hansson 	}
1851f397c8d8SUlf Hansson 	sz = t->max_tfr;
1852f397c8d8SUlf Hansson 	return mmc_test_seq_write_perf(test, sz);
1853f397c8d8SUlf Hansson }
1854f397c8d8SUlf Hansson 
1855f397c8d8SUlf Hansson /*
1856f397c8d8SUlf Hansson  * Consecutive trim performance by transfer size.
1857f397c8d8SUlf Hansson  */
mmc_test_profile_seq_trim_perf(struct mmc_test_card * test)1858f397c8d8SUlf Hansson static int mmc_test_profile_seq_trim_perf(struct mmc_test_card *test)
1859f397c8d8SUlf Hansson {
1860f397c8d8SUlf Hansson 	struct mmc_test_area *t = &test->area;
1861f397c8d8SUlf Hansson 	unsigned long sz;
1862f397c8d8SUlf Hansson 	unsigned int dev_addr, i, cnt;
1863a5b97be2SArnd Bergmann 	struct timespec64 ts1, ts2;
1864f397c8d8SUlf Hansson 	int ret;
1865f397c8d8SUlf Hansson 
1866f397c8d8SUlf Hansson 	if (!mmc_can_trim(test->card))
1867f397c8d8SUlf Hansson 		return RESULT_UNSUP_CARD;
1868f397c8d8SUlf Hansson 
1869f397c8d8SUlf Hansson 	if (!mmc_can_erase(test->card))
1870f397c8d8SUlf Hansson 		return RESULT_UNSUP_HOST;
1871f397c8d8SUlf Hansson 
1872f397c8d8SUlf Hansson 	for (sz = 512; sz <= t->max_sz; sz <<= 1) {
1873f397c8d8SUlf Hansson 		ret = mmc_test_area_erase(test);
1874f397c8d8SUlf Hansson 		if (ret)
1875f397c8d8SUlf Hansson 			return ret;
1876f397c8d8SUlf Hansson 		ret = mmc_test_area_fill(test);
1877f397c8d8SUlf Hansson 		if (ret)
1878f397c8d8SUlf Hansson 			return ret;
1879f397c8d8SUlf Hansson 		cnt = t->max_sz / sz;
1880f397c8d8SUlf Hansson 		dev_addr = t->dev_addr;
1881a5b97be2SArnd Bergmann 		ktime_get_ts64(&ts1);
1882f397c8d8SUlf Hansson 		for (i = 0; i < cnt; i++) {
1883f397c8d8SUlf Hansson 			ret = mmc_erase(test->card, dev_addr, sz >> 9,
1884f397c8d8SUlf Hansson 					MMC_TRIM_ARG);
1885f397c8d8SUlf Hansson 			if (ret)
1886f397c8d8SUlf Hansson 				return ret;
1887f397c8d8SUlf Hansson 			dev_addr += (sz >> 9);
1888f397c8d8SUlf Hansson 		}
1889a5b97be2SArnd Bergmann 		ktime_get_ts64(&ts2);
1890f397c8d8SUlf Hansson 		mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
1891f397c8d8SUlf Hansson 	}
1892f397c8d8SUlf Hansson 	return 0;
1893f397c8d8SUlf Hansson }
1894f397c8d8SUlf Hansson 
1895f397c8d8SUlf Hansson static unsigned int rnd_next = 1;
1896f397c8d8SUlf Hansson 
mmc_test_rnd_num(unsigned int rnd_cnt)1897f397c8d8SUlf Hansson static unsigned int mmc_test_rnd_num(unsigned int rnd_cnt)
1898f397c8d8SUlf Hansson {
1899f397c8d8SUlf Hansson 	uint64_t r;
1900f397c8d8SUlf Hansson 
1901f397c8d8SUlf Hansson 	rnd_next = rnd_next * 1103515245 + 12345;
1902f397c8d8SUlf Hansson 	r = (rnd_next >> 16) & 0x7fff;
1903f397c8d8SUlf Hansson 	return (r * rnd_cnt) >> 15;
1904f397c8d8SUlf Hansson }
1905f397c8d8SUlf Hansson 
mmc_test_rnd_perf(struct mmc_test_card * test,int write,int print,unsigned long sz)1906f397c8d8SUlf Hansson static int mmc_test_rnd_perf(struct mmc_test_card *test, int write, int print,
1907f397c8d8SUlf Hansson 			     unsigned long sz)
1908f397c8d8SUlf Hansson {
1909f397c8d8SUlf Hansson 	unsigned int dev_addr, cnt, rnd_addr, range1, range2, last_ea = 0, ea;
1910f397c8d8SUlf Hansson 	unsigned int ssz;
1911a5b97be2SArnd Bergmann 	struct timespec64 ts1, ts2, ts;
1912f397c8d8SUlf Hansson 	int ret;
1913f397c8d8SUlf Hansson 
1914f397c8d8SUlf Hansson 	ssz = sz >> 9;
1915f397c8d8SUlf Hansson 
1916f397c8d8SUlf Hansson 	rnd_addr = mmc_test_capacity(test->card) / 4;
1917f397c8d8SUlf Hansson 	range1 = rnd_addr / test->card->pref_erase;
1918f397c8d8SUlf Hansson 	range2 = range1 / ssz;
1919f397c8d8SUlf Hansson 
1920a5b97be2SArnd Bergmann 	ktime_get_ts64(&ts1);
1921f397c8d8SUlf Hansson 	for (cnt = 0; cnt < UINT_MAX; cnt++) {
1922a5b97be2SArnd Bergmann 		ktime_get_ts64(&ts2);
1923a5b97be2SArnd Bergmann 		ts = timespec64_sub(ts2, ts1);
1924f397c8d8SUlf Hansson 		if (ts.tv_sec >= 10)
1925f397c8d8SUlf Hansson 			break;
1926f397c8d8SUlf Hansson 		ea = mmc_test_rnd_num(range1);
1927f397c8d8SUlf Hansson 		if (ea == last_ea)
1928f397c8d8SUlf Hansson 			ea -= 1;
1929f397c8d8SUlf Hansson 		last_ea = ea;
1930f397c8d8SUlf Hansson 		dev_addr = rnd_addr + test->card->pref_erase * ea +
1931f397c8d8SUlf Hansson 			   ssz * mmc_test_rnd_num(range2);
1932f397c8d8SUlf Hansson 		ret = mmc_test_area_io(test, sz, dev_addr, write, 0, 0);
1933f397c8d8SUlf Hansson 		if (ret)
1934f397c8d8SUlf Hansson 			return ret;
1935f397c8d8SUlf Hansson 	}
1936f397c8d8SUlf Hansson 	if (print)
1937f397c8d8SUlf Hansson 		mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
1938f397c8d8SUlf Hansson 	return 0;
1939f397c8d8SUlf Hansson }
1940f397c8d8SUlf Hansson 
mmc_test_random_perf(struct mmc_test_card * test,int write)1941f397c8d8SUlf Hansson static int mmc_test_random_perf(struct mmc_test_card *test, int write)
1942f397c8d8SUlf Hansson {
1943f397c8d8SUlf Hansson 	struct mmc_test_area *t = &test->area;
1944f397c8d8SUlf Hansson 	unsigned int next;
1945f397c8d8SUlf Hansson 	unsigned long sz;
1946f397c8d8SUlf Hansson 	int ret;
1947f397c8d8SUlf Hansson 
1948f397c8d8SUlf Hansson 	for (sz = 512; sz < t->max_tfr; sz <<= 1) {
1949f397c8d8SUlf Hansson 		/*
1950f397c8d8SUlf Hansson 		 * When writing, try to get more consistent results by running
1951f397c8d8SUlf Hansson 		 * the test twice with exactly the same I/O but outputting the
1952f397c8d8SUlf Hansson 		 * results only for the 2nd run.
1953f397c8d8SUlf Hansson 		 */
1954f397c8d8SUlf Hansson 		if (write) {
1955f397c8d8SUlf Hansson 			next = rnd_next;
1956f397c8d8SUlf Hansson 			ret = mmc_test_rnd_perf(test, write, 0, sz);
1957f397c8d8SUlf Hansson 			if (ret)
1958f397c8d8SUlf Hansson 				return ret;
1959f397c8d8SUlf Hansson 			rnd_next = next;
1960f397c8d8SUlf Hansson 		}
1961f397c8d8SUlf Hansson 		ret = mmc_test_rnd_perf(test, write, 1, sz);
1962f397c8d8SUlf Hansson 		if (ret)
1963f397c8d8SUlf Hansson 			return ret;
1964f397c8d8SUlf Hansson 	}
1965f397c8d8SUlf Hansson 	sz = t->max_tfr;
1966f397c8d8SUlf Hansson 	if (write) {
1967f397c8d8SUlf Hansson 		next = rnd_next;
1968f397c8d8SUlf Hansson 		ret = mmc_test_rnd_perf(test, write, 0, sz);
1969f397c8d8SUlf Hansson 		if (ret)
1970f397c8d8SUlf Hansson 			return ret;
1971f397c8d8SUlf Hansson 		rnd_next = next;
1972f397c8d8SUlf Hansson 	}
1973f397c8d8SUlf Hansson 	return mmc_test_rnd_perf(test, write, 1, sz);
1974f397c8d8SUlf Hansson }
1975f397c8d8SUlf Hansson 
1976f397c8d8SUlf Hansson /*
1977f397c8d8SUlf Hansson  * Random read performance by transfer size.
1978f397c8d8SUlf Hansson  */
mmc_test_random_read_perf(struct mmc_test_card * test)1979f397c8d8SUlf Hansson static int mmc_test_random_read_perf(struct mmc_test_card *test)
1980f397c8d8SUlf Hansson {
1981f397c8d8SUlf Hansson 	return mmc_test_random_perf(test, 0);
1982f397c8d8SUlf Hansson }
1983f397c8d8SUlf Hansson 
1984f397c8d8SUlf Hansson /*
1985f397c8d8SUlf Hansson  * Random write performance by transfer size.
1986f397c8d8SUlf Hansson  */
mmc_test_random_write_perf(struct mmc_test_card * test)1987f397c8d8SUlf Hansson static int mmc_test_random_write_perf(struct mmc_test_card *test)
1988f397c8d8SUlf Hansson {
1989f397c8d8SUlf Hansson 	return mmc_test_random_perf(test, 1);
1990f397c8d8SUlf Hansson }
1991f397c8d8SUlf Hansson 
mmc_test_seq_perf(struct mmc_test_card * test,int write,unsigned int tot_sz,int max_scatter)1992f397c8d8SUlf Hansson static int mmc_test_seq_perf(struct mmc_test_card *test, int write,
1993f397c8d8SUlf Hansson 			     unsigned int tot_sz, int max_scatter)
1994f397c8d8SUlf Hansson {
1995f397c8d8SUlf Hansson 	struct mmc_test_area *t = &test->area;
1996f397c8d8SUlf Hansson 	unsigned int dev_addr, i, cnt, sz, ssz;
1997a5b97be2SArnd Bergmann 	struct timespec64 ts1, ts2;
1998f397c8d8SUlf Hansson 	int ret;
1999f397c8d8SUlf Hansson 
2000f397c8d8SUlf Hansson 	sz = t->max_tfr;
2001f397c8d8SUlf Hansson 
2002f397c8d8SUlf Hansson 	/*
2003f397c8d8SUlf Hansson 	 * In the case of a maximally scattered transfer, the maximum transfer
2004f397c8d8SUlf Hansson 	 * size is further limited by using PAGE_SIZE segments.
2005f397c8d8SUlf Hansson 	 */
2006f397c8d8SUlf Hansson 	if (max_scatter) {
2007f397c8d8SUlf Hansson 		unsigned long max_tfr;
2008f397c8d8SUlf Hansson 
2009f397c8d8SUlf Hansson 		if (t->max_seg_sz >= PAGE_SIZE)
2010f397c8d8SUlf Hansson 			max_tfr = t->max_segs * PAGE_SIZE;
2011f397c8d8SUlf Hansson 		else
2012f397c8d8SUlf Hansson 			max_tfr = t->max_segs * t->max_seg_sz;
2013f397c8d8SUlf Hansson 		if (sz > max_tfr)
2014f397c8d8SUlf Hansson 			sz = max_tfr;
2015f397c8d8SUlf Hansson 	}
2016f397c8d8SUlf Hansson 
2017f397c8d8SUlf Hansson 	ssz = sz >> 9;
2018f397c8d8SUlf Hansson 	dev_addr = mmc_test_capacity(test->card) / 4;
2019f397c8d8SUlf Hansson 	if (tot_sz > dev_addr << 9)
2020f397c8d8SUlf Hansson 		tot_sz = dev_addr << 9;
2021f397c8d8SUlf Hansson 	cnt = tot_sz / sz;
2022f397c8d8SUlf Hansson 	dev_addr &= 0xffff0000; /* Round to 64MiB boundary */
2023f397c8d8SUlf Hansson 
2024a5b97be2SArnd Bergmann 	ktime_get_ts64(&ts1);
2025f397c8d8SUlf Hansson 	for (i = 0; i < cnt; i++) {
2026f397c8d8SUlf Hansson 		ret = mmc_test_area_io(test, sz, dev_addr, write,
2027f397c8d8SUlf Hansson 				       max_scatter, 0);
2028f397c8d8SUlf Hansson 		if (ret)
2029f397c8d8SUlf Hansson 			return ret;
2030f397c8d8SUlf Hansson 		dev_addr += ssz;
2031f397c8d8SUlf Hansson 	}
2032a5b97be2SArnd Bergmann 	ktime_get_ts64(&ts2);
2033f397c8d8SUlf Hansson 
2034f397c8d8SUlf Hansson 	mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
2035f397c8d8SUlf Hansson 
2036f397c8d8SUlf Hansson 	return 0;
2037f397c8d8SUlf Hansson }
2038f397c8d8SUlf Hansson 
mmc_test_large_seq_perf(struct mmc_test_card * test,int write)2039f397c8d8SUlf Hansson static int mmc_test_large_seq_perf(struct mmc_test_card *test, int write)
2040f397c8d8SUlf Hansson {
2041f397c8d8SUlf Hansson 	int ret, i;
2042f397c8d8SUlf Hansson 
2043f397c8d8SUlf Hansson 	for (i = 0; i < 10; i++) {
2044f397c8d8SUlf Hansson 		ret = mmc_test_seq_perf(test, write, 10 * 1024 * 1024, 1);
2045f397c8d8SUlf Hansson 		if (ret)
2046f397c8d8SUlf Hansson 			return ret;
2047f397c8d8SUlf Hansson 	}
2048f397c8d8SUlf Hansson 	for (i = 0; i < 5; i++) {
2049f397c8d8SUlf Hansson 		ret = mmc_test_seq_perf(test, write, 100 * 1024 * 1024, 1);
2050f397c8d8SUlf Hansson 		if (ret)
2051f397c8d8SUlf Hansson 			return ret;
2052f397c8d8SUlf Hansson 	}
2053f397c8d8SUlf Hansson 	for (i = 0; i < 3; i++) {
2054f397c8d8SUlf Hansson 		ret = mmc_test_seq_perf(test, write, 1000 * 1024 * 1024, 1);
2055f397c8d8SUlf Hansson 		if (ret)
2056f397c8d8SUlf Hansson 			return ret;
2057f397c8d8SUlf Hansson 	}
2058f397c8d8SUlf Hansson 
2059f397c8d8SUlf Hansson 	return ret;
2060f397c8d8SUlf Hansson }
2061f397c8d8SUlf Hansson 
2062f397c8d8SUlf Hansson /*
2063f397c8d8SUlf Hansson  * Large sequential read performance.
2064f397c8d8SUlf Hansson  */
mmc_test_large_seq_read_perf(struct mmc_test_card * test)2065f397c8d8SUlf Hansson static int mmc_test_large_seq_read_perf(struct mmc_test_card *test)
2066f397c8d8SUlf Hansson {
2067f397c8d8SUlf Hansson 	return mmc_test_large_seq_perf(test, 0);
2068f397c8d8SUlf Hansson }
2069f397c8d8SUlf Hansson 
2070f397c8d8SUlf Hansson /*
2071f397c8d8SUlf Hansson  * Large sequential write performance.
2072f397c8d8SUlf Hansson  */
mmc_test_large_seq_write_perf(struct mmc_test_card * test)2073f397c8d8SUlf Hansson static int mmc_test_large_seq_write_perf(struct mmc_test_card *test)
2074f397c8d8SUlf Hansson {
2075f397c8d8SUlf Hansson 	return mmc_test_large_seq_perf(test, 1);
2076f397c8d8SUlf Hansson }
2077f397c8d8SUlf Hansson 
mmc_test_rw_multiple(struct mmc_test_card * test,struct mmc_test_multiple_rw * tdata,unsigned int reqsize,unsigned int size,int min_sg_len)2078f397c8d8SUlf Hansson static int mmc_test_rw_multiple(struct mmc_test_card *test,
2079f397c8d8SUlf Hansson 				struct mmc_test_multiple_rw *tdata,
2080f397c8d8SUlf Hansson 				unsigned int reqsize, unsigned int size,
2081f397c8d8SUlf Hansson 				int min_sg_len)
2082f397c8d8SUlf Hansson {
2083f397c8d8SUlf Hansson 	unsigned int dev_addr;
2084f397c8d8SUlf Hansson 	struct mmc_test_area *t = &test->area;
2085f397c8d8SUlf Hansson 	int ret = 0;
2086f397c8d8SUlf Hansson 
2087f397c8d8SUlf Hansson 	/* Set up test area */
2088f397c8d8SUlf Hansson 	if (size > mmc_test_capacity(test->card) / 2 * 512)
2089f397c8d8SUlf Hansson 		size = mmc_test_capacity(test->card) / 2 * 512;
2090f397c8d8SUlf Hansson 	if (reqsize > t->max_tfr)
2091f397c8d8SUlf Hansson 		reqsize = t->max_tfr;
2092f397c8d8SUlf Hansson 	dev_addr = mmc_test_capacity(test->card) / 4;
2093f397c8d8SUlf Hansson 	if ((dev_addr & 0xffff0000))
2094f397c8d8SUlf Hansson 		dev_addr &= 0xffff0000; /* Round to 64MiB boundary */
2095f397c8d8SUlf Hansson 	else
2096f397c8d8SUlf Hansson 		dev_addr &= 0xfffff800; /* Round to 1MiB boundary */
2097f397c8d8SUlf Hansson 	if (!dev_addr)
2098f397c8d8SUlf Hansson 		goto err;
2099f397c8d8SUlf Hansson 
2100f397c8d8SUlf Hansson 	if (reqsize > size)
2101f397c8d8SUlf Hansson 		return 0;
2102f397c8d8SUlf Hansson 
2103f397c8d8SUlf Hansson 	/* prepare test area */
2104f397c8d8SUlf Hansson 	if (mmc_can_erase(test->card) &&
2105f397c8d8SUlf Hansson 	    tdata->prepare & MMC_TEST_PREP_ERASE) {
2106f397c8d8SUlf Hansson 		ret = mmc_erase(test->card, dev_addr,
21073f957decSYann Gautier 				size / 512, test->card->erase_arg);
2108f397c8d8SUlf Hansson 		if (ret)
2109f397c8d8SUlf Hansson 			ret = mmc_erase(test->card, dev_addr,
2110f397c8d8SUlf Hansson 					size / 512, MMC_ERASE_ARG);
2111f397c8d8SUlf Hansson 		if (ret)
2112f397c8d8SUlf Hansson 			goto err;
2113f397c8d8SUlf Hansson 	}
2114f397c8d8SUlf Hansson 
2115f397c8d8SUlf Hansson 	/* Run test */
2116f397c8d8SUlf Hansson 	ret = mmc_test_area_io_seq(test, reqsize, dev_addr,
2117f397c8d8SUlf Hansson 				   tdata->do_write, 0, 1, size / reqsize,
2118f397c8d8SUlf Hansson 				   tdata->do_nonblock_req, min_sg_len);
2119f397c8d8SUlf Hansson 	if (ret)
2120f397c8d8SUlf Hansson 		goto err;
2121f397c8d8SUlf Hansson 
2122f397c8d8SUlf Hansson 	return ret;
2123f397c8d8SUlf Hansson  err:
2124f397c8d8SUlf Hansson 	pr_info("[%s] error\n", __func__);
2125f397c8d8SUlf Hansson 	return ret;
2126f397c8d8SUlf Hansson }
2127f397c8d8SUlf Hansson 
mmc_test_rw_multiple_size(struct mmc_test_card * test,struct mmc_test_multiple_rw * rw)2128f397c8d8SUlf Hansson static int mmc_test_rw_multiple_size(struct mmc_test_card *test,
2129f397c8d8SUlf Hansson 				     struct mmc_test_multiple_rw *rw)
2130f397c8d8SUlf Hansson {
2131f397c8d8SUlf Hansson 	int ret = 0;
2132f397c8d8SUlf Hansson 	int i;
2133f397c8d8SUlf Hansson 	void *pre_req = test->card->host->ops->pre_req;
2134f397c8d8SUlf Hansson 	void *post_req = test->card->host->ops->post_req;
2135f397c8d8SUlf Hansson 
2136f397c8d8SUlf Hansson 	if (rw->do_nonblock_req &&
2137f397c8d8SUlf Hansson 	    ((!pre_req && post_req) || (pre_req && !post_req))) {
2138f397c8d8SUlf Hansson 		pr_info("error: only one of pre/post is defined\n");
2139f397c8d8SUlf Hansson 		return -EINVAL;
2140f397c8d8SUlf Hansson 	}
2141f397c8d8SUlf Hansson 
2142f397c8d8SUlf Hansson 	for (i = 0 ; i < rw->len && ret == 0; i++) {
2143f397c8d8SUlf Hansson 		ret = mmc_test_rw_multiple(test, rw, rw->bs[i], rw->size, 0);
2144f397c8d8SUlf Hansson 		if (ret)
2145f397c8d8SUlf Hansson 			break;
2146f397c8d8SUlf Hansson 	}
2147f397c8d8SUlf Hansson 	return ret;
2148f397c8d8SUlf Hansson }
2149f397c8d8SUlf Hansson 
mmc_test_rw_multiple_sg_len(struct mmc_test_card * test,struct mmc_test_multiple_rw * rw)2150f397c8d8SUlf Hansson static int mmc_test_rw_multiple_sg_len(struct mmc_test_card *test,
2151f397c8d8SUlf Hansson 				       struct mmc_test_multiple_rw *rw)
2152f397c8d8SUlf Hansson {
2153f397c8d8SUlf Hansson 	int ret = 0;
2154f397c8d8SUlf Hansson 	int i;
2155f397c8d8SUlf Hansson 
2156f397c8d8SUlf Hansson 	for (i = 0 ; i < rw->len && ret == 0; i++) {
2157f397c8d8SUlf Hansson 		ret = mmc_test_rw_multiple(test, rw, 512 * 1024, rw->size,
2158f397c8d8SUlf Hansson 					   rw->sg_len[i]);
2159f397c8d8SUlf Hansson 		if (ret)
2160f397c8d8SUlf Hansson 			break;
2161f397c8d8SUlf Hansson 	}
2162f397c8d8SUlf Hansson 	return ret;
2163f397c8d8SUlf Hansson }
2164f397c8d8SUlf Hansson 
2165f397c8d8SUlf Hansson /*
2166f397c8d8SUlf Hansson  * Multiple blocking write 4k to 4 MB chunks
2167f397c8d8SUlf Hansson  */
mmc_test_profile_mult_write_blocking_perf(struct mmc_test_card * test)2168f397c8d8SUlf Hansson static int mmc_test_profile_mult_write_blocking_perf(struct mmc_test_card *test)
2169f397c8d8SUlf Hansson {
2170f397c8d8SUlf Hansson 	unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
2171f397c8d8SUlf Hansson 			     1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
2172f397c8d8SUlf Hansson 	struct mmc_test_multiple_rw test_data = {
2173f397c8d8SUlf Hansson 		.bs = bs,
2174f397c8d8SUlf Hansson 		.size = TEST_AREA_MAX_SIZE,
2175f397c8d8SUlf Hansson 		.len = ARRAY_SIZE(bs),
2176f397c8d8SUlf Hansson 		.do_write = true,
2177f397c8d8SUlf Hansson 		.do_nonblock_req = false,
2178f397c8d8SUlf Hansson 		.prepare = MMC_TEST_PREP_ERASE,
2179f397c8d8SUlf Hansson 	};
2180f397c8d8SUlf Hansson 
2181f397c8d8SUlf Hansson 	return mmc_test_rw_multiple_size(test, &test_data);
2182f397c8d8SUlf Hansson };
2183f397c8d8SUlf Hansson 
2184f397c8d8SUlf Hansson /*
2185f397c8d8SUlf Hansson  * Multiple non-blocking write 4k to 4 MB chunks
2186f397c8d8SUlf Hansson  */
mmc_test_profile_mult_write_nonblock_perf(struct mmc_test_card * test)2187f397c8d8SUlf Hansson static int mmc_test_profile_mult_write_nonblock_perf(struct mmc_test_card *test)
2188f397c8d8SUlf Hansson {
2189f397c8d8SUlf Hansson 	unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
2190f397c8d8SUlf Hansson 			     1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
2191f397c8d8SUlf Hansson 	struct mmc_test_multiple_rw test_data = {
2192f397c8d8SUlf Hansson 		.bs = bs,
2193f397c8d8SUlf Hansson 		.size = TEST_AREA_MAX_SIZE,
2194f397c8d8SUlf Hansson 		.len = ARRAY_SIZE(bs),
2195f397c8d8SUlf Hansson 		.do_write = true,
2196f397c8d8SUlf Hansson 		.do_nonblock_req = true,
2197f397c8d8SUlf Hansson 		.prepare = MMC_TEST_PREP_ERASE,
2198f397c8d8SUlf Hansson 	};
2199f397c8d8SUlf Hansson 
2200f397c8d8SUlf Hansson 	return mmc_test_rw_multiple_size(test, &test_data);
2201f397c8d8SUlf Hansson }
2202f397c8d8SUlf Hansson 
2203f397c8d8SUlf Hansson /*
2204f397c8d8SUlf Hansson  * Multiple blocking read 4k to 4 MB chunks
2205f397c8d8SUlf Hansson  */
mmc_test_profile_mult_read_blocking_perf(struct mmc_test_card * test)2206f397c8d8SUlf Hansson static int mmc_test_profile_mult_read_blocking_perf(struct mmc_test_card *test)
2207f397c8d8SUlf Hansson {
2208f397c8d8SUlf Hansson 	unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
2209f397c8d8SUlf Hansson 			     1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
2210f397c8d8SUlf Hansson 	struct mmc_test_multiple_rw test_data = {
2211f397c8d8SUlf Hansson 		.bs = bs,
2212f397c8d8SUlf Hansson 		.size = TEST_AREA_MAX_SIZE,
2213f397c8d8SUlf Hansson 		.len = ARRAY_SIZE(bs),
2214f397c8d8SUlf Hansson 		.do_write = false,
2215f397c8d8SUlf Hansson 		.do_nonblock_req = false,
2216f397c8d8SUlf Hansson 		.prepare = MMC_TEST_PREP_NONE,
2217f397c8d8SUlf Hansson 	};
2218f397c8d8SUlf Hansson 
2219f397c8d8SUlf Hansson 	return mmc_test_rw_multiple_size(test, &test_data);
2220f397c8d8SUlf Hansson }
2221f397c8d8SUlf Hansson 
2222f397c8d8SUlf Hansson /*
2223f397c8d8SUlf Hansson  * Multiple non-blocking read 4k to 4 MB chunks
2224f397c8d8SUlf Hansson  */
mmc_test_profile_mult_read_nonblock_perf(struct mmc_test_card * test)2225f397c8d8SUlf Hansson static int mmc_test_profile_mult_read_nonblock_perf(struct mmc_test_card *test)
2226f397c8d8SUlf Hansson {
2227f397c8d8SUlf Hansson 	unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
2228f397c8d8SUlf Hansson 			     1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
2229f397c8d8SUlf Hansson 	struct mmc_test_multiple_rw test_data = {
2230f397c8d8SUlf Hansson 		.bs = bs,
2231f397c8d8SUlf Hansson 		.size = TEST_AREA_MAX_SIZE,
2232f397c8d8SUlf Hansson 		.len = ARRAY_SIZE(bs),
2233f397c8d8SUlf Hansson 		.do_write = false,
2234f397c8d8SUlf Hansson 		.do_nonblock_req = true,
2235f397c8d8SUlf Hansson 		.prepare = MMC_TEST_PREP_NONE,
2236f397c8d8SUlf Hansson 	};
2237f397c8d8SUlf Hansson 
2238f397c8d8SUlf Hansson 	return mmc_test_rw_multiple_size(test, &test_data);
2239f397c8d8SUlf Hansson }
2240f397c8d8SUlf Hansson 
2241f397c8d8SUlf Hansson /*
2242f397c8d8SUlf Hansson  * Multiple blocking write 1 to 512 sg elements
2243f397c8d8SUlf Hansson  */
mmc_test_profile_sglen_wr_blocking_perf(struct mmc_test_card * test)2244f397c8d8SUlf Hansson static int mmc_test_profile_sglen_wr_blocking_perf(struct mmc_test_card *test)
2245f397c8d8SUlf Hansson {
2246f397c8d8SUlf Hansson 	unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
2247f397c8d8SUlf Hansson 				 1 << 7, 1 << 8, 1 << 9};
2248f397c8d8SUlf Hansson 	struct mmc_test_multiple_rw test_data = {
2249f397c8d8SUlf Hansson 		.sg_len = sg_len,
2250f397c8d8SUlf Hansson 		.size = TEST_AREA_MAX_SIZE,
2251f397c8d8SUlf Hansson 		.len = ARRAY_SIZE(sg_len),
2252f397c8d8SUlf Hansson 		.do_write = true,
2253f397c8d8SUlf Hansson 		.do_nonblock_req = false,
2254f397c8d8SUlf Hansson 		.prepare = MMC_TEST_PREP_ERASE,
2255f397c8d8SUlf Hansson 	};
2256f397c8d8SUlf Hansson 
2257f397c8d8SUlf Hansson 	return mmc_test_rw_multiple_sg_len(test, &test_data);
2258f397c8d8SUlf Hansson };
2259f397c8d8SUlf Hansson 
2260f397c8d8SUlf Hansson /*
2261f397c8d8SUlf Hansson  * Multiple non-blocking write 1 to 512 sg elements
2262f397c8d8SUlf Hansson  */
mmc_test_profile_sglen_wr_nonblock_perf(struct mmc_test_card * test)2263f397c8d8SUlf Hansson static int mmc_test_profile_sglen_wr_nonblock_perf(struct mmc_test_card *test)
2264f397c8d8SUlf Hansson {
2265f397c8d8SUlf Hansson 	unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
2266f397c8d8SUlf Hansson 				 1 << 7, 1 << 8, 1 << 9};
2267f397c8d8SUlf Hansson 	struct mmc_test_multiple_rw test_data = {
2268f397c8d8SUlf Hansson 		.sg_len = sg_len,
2269f397c8d8SUlf Hansson 		.size = TEST_AREA_MAX_SIZE,
2270f397c8d8SUlf Hansson 		.len = ARRAY_SIZE(sg_len),
2271f397c8d8SUlf Hansson 		.do_write = true,
2272f397c8d8SUlf Hansson 		.do_nonblock_req = true,
2273f397c8d8SUlf Hansson 		.prepare = MMC_TEST_PREP_ERASE,
2274f397c8d8SUlf Hansson 	};
2275f397c8d8SUlf Hansson 
2276f397c8d8SUlf Hansson 	return mmc_test_rw_multiple_sg_len(test, &test_data);
2277f397c8d8SUlf Hansson }
2278f397c8d8SUlf Hansson 
2279f397c8d8SUlf Hansson /*
2280f397c8d8SUlf Hansson  * Multiple blocking read 1 to 512 sg elements
2281f397c8d8SUlf Hansson  */
mmc_test_profile_sglen_r_blocking_perf(struct mmc_test_card * test)2282f397c8d8SUlf Hansson static int mmc_test_profile_sglen_r_blocking_perf(struct mmc_test_card *test)
2283f397c8d8SUlf Hansson {
2284f397c8d8SUlf Hansson 	unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
2285f397c8d8SUlf Hansson 				 1 << 7, 1 << 8, 1 << 9};
2286f397c8d8SUlf Hansson 	struct mmc_test_multiple_rw test_data = {
2287f397c8d8SUlf Hansson 		.sg_len = sg_len,
2288f397c8d8SUlf Hansson 		.size = TEST_AREA_MAX_SIZE,
2289f397c8d8SUlf Hansson 		.len = ARRAY_SIZE(sg_len),
2290f397c8d8SUlf Hansson 		.do_write = false,
2291f397c8d8SUlf Hansson 		.do_nonblock_req = false,
2292f397c8d8SUlf Hansson 		.prepare = MMC_TEST_PREP_NONE,
2293f397c8d8SUlf Hansson 	};
2294f397c8d8SUlf Hansson 
2295f397c8d8SUlf Hansson 	return mmc_test_rw_multiple_sg_len(test, &test_data);
2296f397c8d8SUlf Hansson }
2297f397c8d8SUlf Hansson 
2298f397c8d8SUlf Hansson /*
2299f397c8d8SUlf Hansson  * Multiple non-blocking read 1 to 512 sg elements
2300f397c8d8SUlf Hansson  */
mmc_test_profile_sglen_r_nonblock_perf(struct mmc_test_card * test)2301f397c8d8SUlf Hansson static int mmc_test_profile_sglen_r_nonblock_perf(struct mmc_test_card *test)
2302f397c8d8SUlf Hansson {
2303f397c8d8SUlf Hansson 	unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
2304f397c8d8SUlf Hansson 				 1 << 7, 1 << 8, 1 << 9};
2305f397c8d8SUlf Hansson 	struct mmc_test_multiple_rw test_data = {
2306f397c8d8SUlf Hansson 		.sg_len = sg_len,
2307f397c8d8SUlf Hansson 		.size = TEST_AREA_MAX_SIZE,
2308f397c8d8SUlf Hansson 		.len = ARRAY_SIZE(sg_len),
2309f397c8d8SUlf Hansson 		.do_write = false,
2310f397c8d8SUlf Hansson 		.do_nonblock_req = true,
2311f397c8d8SUlf Hansson 		.prepare = MMC_TEST_PREP_NONE,
2312f397c8d8SUlf Hansson 	};
2313f397c8d8SUlf Hansson 
2314f397c8d8SUlf Hansson 	return mmc_test_rw_multiple_sg_len(test, &test_data);
2315f397c8d8SUlf Hansson }
2316f397c8d8SUlf Hansson 
2317f397c8d8SUlf Hansson /*
2318f397c8d8SUlf Hansson  * eMMC hardware reset.
2319f397c8d8SUlf Hansson  */
mmc_test_reset(struct mmc_test_card * test)2320f397c8d8SUlf Hansson static int mmc_test_reset(struct mmc_test_card *test)
2321f397c8d8SUlf Hansson {
2322f397c8d8SUlf Hansson 	struct mmc_card *card = test->card;
2323f397c8d8SUlf Hansson 	int err;
2324f397c8d8SUlf Hansson 
2325b71597edSWolfram Sang 	err = mmc_hw_reset(card);
232623a18525SAdrian Hunter 	if (!err) {
232723a18525SAdrian Hunter 		/*
232823a18525SAdrian Hunter 		 * Reset will re-enable the card's command queue, but tests
232923a18525SAdrian Hunter 		 * expect it to be disabled.
233023a18525SAdrian Hunter 		 */
233123a18525SAdrian Hunter 		if (card->ext_csd.cmdq_en)
233223a18525SAdrian Hunter 			mmc_cmdq_disable(card);
2333f397c8d8SUlf Hansson 		return RESULT_OK;
233423a18525SAdrian Hunter 	} else if (err == -EOPNOTSUPP) {
2335f397c8d8SUlf Hansson 		return RESULT_UNSUP_HOST;
233623a18525SAdrian Hunter 	}
2337f397c8d8SUlf Hansson 
2338f397c8d8SUlf Hansson 	return RESULT_FAIL;
2339f397c8d8SUlf Hansson }
2340f397c8d8SUlf Hansson 
mmc_test_send_status(struct mmc_test_card * test,struct mmc_command * cmd)2341f397c8d8SUlf Hansson static int mmc_test_send_status(struct mmc_test_card *test,
2342f397c8d8SUlf Hansson 				struct mmc_command *cmd)
2343f397c8d8SUlf Hansson {
2344f397c8d8SUlf Hansson 	memset(cmd, 0, sizeof(*cmd));
2345f397c8d8SUlf Hansson 
2346f397c8d8SUlf Hansson 	cmd->opcode = MMC_SEND_STATUS;
2347f397c8d8SUlf Hansson 	if (!mmc_host_is_spi(test->card->host))
2348f397c8d8SUlf Hansson 		cmd->arg = test->card->rca << 16;
2349f397c8d8SUlf Hansson 	cmd->flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
2350f397c8d8SUlf Hansson 
2351f397c8d8SUlf Hansson 	return mmc_wait_for_cmd(test->card->host, cmd, 0);
2352f397c8d8SUlf Hansson }
2353f397c8d8SUlf Hansson 
mmc_test_ongoing_transfer(struct mmc_test_card * test,unsigned int dev_addr,int use_sbc,int repeat_cmd,int write,int use_areq)2354f397c8d8SUlf Hansson static int mmc_test_ongoing_transfer(struct mmc_test_card *test,
2355f397c8d8SUlf Hansson 				     unsigned int dev_addr, int use_sbc,
2356f397c8d8SUlf Hansson 				     int repeat_cmd, int write, int use_areq)
2357f397c8d8SUlf Hansson {
2358f397c8d8SUlf Hansson 	struct mmc_test_req *rq = mmc_test_req_alloc();
2359f397c8d8SUlf Hansson 	struct mmc_host *host = test->card->host;
2360f397c8d8SUlf Hansson 	struct mmc_test_area *t = &test->area;
2361f397c8d8SUlf Hansson 	struct mmc_request *mrq;
2362f397c8d8SUlf Hansson 	unsigned long timeout;
2363f397c8d8SUlf Hansson 	bool expired = false;
2364f397c8d8SUlf Hansson 	int ret = 0, cmd_ret;
2365f397c8d8SUlf Hansson 	u32 status = 0;
2366f397c8d8SUlf Hansson 	int count = 0;
2367f397c8d8SUlf Hansson 
2368f397c8d8SUlf Hansson 	if (!rq)
2369f397c8d8SUlf Hansson 		return -ENOMEM;
2370f397c8d8SUlf Hansson 
2371f397c8d8SUlf Hansson 	mrq = &rq->mrq;
2372f397c8d8SUlf Hansson 	if (use_sbc)
2373f397c8d8SUlf Hansson 		mrq->sbc = &rq->sbc;
2374f397c8d8SUlf Hansson 	mrq->cap_cmd_during_tfr = true;
2375f397c8d8SUlf Hansson 
2376f397c8d8SUlf Hansson 	mmc_test_prepare_mrq(test, mrq, t->sg, t->sg_len, dev_addr, t->blocks,
2377f397c8d8SUlf Hansson 			     512, write);
2378f397c8d8SUlf Hansson 
2379f397c8d8SUlf Hansson 	if (use_sbc && t->blocks > 1 && !mrq->sbc) {
2380f397c8d8SUlf Hansson 		ret =  mmc_host_cmd23(host) ?
2381f397c8d8SUlf Hansson 		       RESULT_UNSUP_CARD :
2382f397c8d8SUlf Hansson 		       RESULT_UNSUP_HOST;
2383f397c8d8SUlf Hansson 		goto out_free;
2384f397c8d8SUlf Hansson 	}
2385f397c8d8SUlf Hansson 
2386f397c8d8SUlf Hansson 	/* Start ongoing data request */
2387f397c8d8SUlf Hansson 	if (use_areq) {
238842f532daSAdrian Hunter 		ret = mmc_test_start_areq(test, mrq, NULL);
238942f532daSAdrian Hunter 		if (ret)
2390f397c8d8SUlf Hansson 			goto out_free;
2391f397c8d8SUlf Hansson 	} else {
2392f397c8d8SUlf Hansson 		mmc_wait_for_req(host, mrq);
2393f397c8d8SUlf Hansson 	}
2394f397c8d8SUlf Hansson 
2395f397c8d8SUlf Hansson 	timeout = jiffies + msecs_to_jiffies(3000);
2396f397c8d8SUlf Hansson 	do {
2397f397c8d8SUlf Hansson 		count += 1;
2398f397c8d8SUlf Hansson 
2399f397c8d8SUlf Hansson 		/* Send status command while data transfer in progress */
2400f397c8d8SUlf Hansson 		cmd_ret = mmc_test_send_status(test, &rq->status);
2401f397c8d8SUlf Hansson 		if (cmd_ret)
2402f397c8d8SUlf Hansson 			break;
2403f397c8d8SUlf Hansson 
2404f397c8d8SUlf Hansson 		status = rq->status.resp[0];
2405f397c8d8SUlf Hansson 		if (status & R1_ERROR) {
2406f397c8d8SUlf Hansson 			cmd_ret = -EIO;
2407f397c8d8SUlf Hansson 			break;
2408f397c8d8SUlf Hansson 		}
2409f397c8d8SUlf Hansson 
2410f397c8d8SUlf Hansson 		if (mmc_is_req_done(host, mrq))
2411f397c8d8SUlf Hansson 			break;
2412f397c8d8SUlf Hansson 
2413f397c8d8SUlf Hansson 		expired = time_after(jiffies, timeout);
2414f397c8d8SUlf Hansson 		if (expired) {
2415f397c8d8SUlf Hansson 			pr_info("%s: timeout waiting for Tran state status %#x\n",
2416f397c8d8SUlf Hansson 				mmc_hostname(host), status);
2417f397c8d8SUlf Hansson 			cmd_ret = -ETIMEDOUT;
2418f397c8d8SUlf Hansson 			break;
2419f397c8d8SUlf Hansson 		}
2420f397c8d8SUlf Hansson 	} while (repeat_cmd && R1_CURRENT_STATE(status) != R1_STATE_TRAN);
2421f397c8d8SUlf Hansson 
2422f397c8d8SUlf Hansson 	/* Wait for data request to complete */
2423f397c8d8SUlf Hansson 	if (use_areq) {
242442f532daSAdrian Hunter 		ret = mmc_test_start_areq(test, NULL, mrq);
2425f397c8d8SUlf Hansson 	} else {
2426f397c8d8SUlf Hansson 		mmc_wait_for_req_done(test->card->host, mrq);
2427f397c8d8SUlf Hansson 	}
2428f397c8d8SUlf Hansson 
2429f397c8d8SUlf Hansson 	/*
2430f397c8d8SUlf Hansson 	 * For cap_cmd_during_tfr request, upper layer must send stop if
2431f397c8d8SUlf Hansson 	 * required.
2432f397c8d8SUlf Hansson 	 */
2433f397c8d8SUlf Hansson 	if (mrq->data->stop && (mrq->data->error || !mrq->sbc)) {
2434f397c8d8SUlf Hansson 		if (ret)
2435f397c8d8SUlf Hansson 			mmc_wait_for_cmd(host, mrq->data->stop, 0);
2436f397c8d8SUlf Hansson 		else
2437f397c8d8SUlf Hansson 			ret = mmc_wait_for_cmd(host, mrq->data->stop, 0);
2438f397c8d8SUlf Hansson 	}
2439f397c8d8SUlf Hansson 
2440f397c8d8SUlf Hansson 	if (ret)
2441f397c8d8SUlf Hansson 		goto out_free;
2442f397c8d8SUlf Hansson 
2443f397c8d8SUlf Hansson 	if (cmd_ret) {
2444f397c8d8SUlf Hansson 		pr_info("%s: Send Status failed: status %#x, error %d\n",
2445f397c8d8SUlf Hansson 			mmc_hostname(test->card->host), status, cmd_ret);
2446f397c8d8SUlf Hansson 	}
2447f397c8d8SUlf Hansson 
2448f397c8d8SUlf Hansson 	ret = mmc_test_check_result(test, mrq);
2449f397c8d8SUlf Hansson 	if (ret)
2450f397c8d8SUlf Hansson 		goto out_free;
2451f397c8d8SUlf Hansson 
2452f397c8d8SUlf Hansson 	ret = mmc_test_wait_busy(test);
2453f397c8d8SUlf Hansson 	if (ret)
2454f397c8d8SUlf Hansson 		goto out_free;
2455f397c8d8SUlf Hansson 
2456f397c8d8SUlf Hansson 	if (repeat_cmd && (t->blocks + 1) << 9 > t->max_tfr)
2457f397c8d8SUlf Hansson 		pr_info("%s: %d commands completed during transfer of %u blocks\n",
2458f397c8d8SUlf Hansson 			mmc_hostname(test->card->host), count, t->blocks);
2459f397c8d8SUlf Hansson 
2460f397c8d8SUlf Hansson 	if (cmd_ret)
2461f397c8d8SUlf Hansson 		ret = cmd_ret;
2462f397c8d8SUlf Hansson out_free:
2463f397c8d8SUlf Hansson 	kfree(rq);
2464f397c8d8SUlf Hansson 
2465f397c8d8SUlf Hansson 	return ret;
2466f397c8d8SUlf Hansson }
2467f397c8d8SUlf Hansson 
__mmc_test_cmds_during_tfr(struct mmc_test_card * test,unsigned long sz,int use_sbc,int write,int use_areq)2468f397c8d8SUlf Hansson static int __mmc_test_cmds_during_tfr(struct mmc_test_card *test,
2469f397c8d8SUlf Hansson 				      unsigned long sz, int use_sbc, int write,
2470f397c8d8SUlf Hansson 				      int use_areq)
2471f397c8d8SUlf Hansson {
2472f397c8d8SUlf Hansson 	struct mmc_test_area *t = &test->area;
2473f397c8d8SUlf Hansson 	int ret;
2474f397c8d8SUlf Hansson 
2475f397c8d8SUlf Hansson 	if (!(test->card->host->caps & MMC_CAP_CMD_DURING_TFR))
2476f397c8d8SUlf Hansson 		return RESULT_UNSUP_HOST;
2477f397c8d8SUlf Hansson 
2478ea21e9b2SVeerabhadrarao Badiganti 	ret = mmc_test_area_map(test, sz, 0, 0, use_areq);
2479f397c8d8SUlf Hansson 	if (ret)
2480f397c8d8SUlf Hansson 		return ret;
2481f397c8d8SUlf Hansson 
2482f397c8d8SUlf Hansson 	ret = mmc_test_ongoing_transfer(test, t->dev_addr, use_sbc, 0, write,
2483f397c8d8SUlf Hansson 					use_areq);
2484f397c8d8SUlf Hansson 	if (ret)
2485f397c8d8SUlf Hansson 		return ret;
2486f397c8d8SUlf Hansson 
2487f397c8d8SUlf Hansson 	return mmc_test_ongoing_transfer(test, t->dev_addr, use_sbc, 1, write,
2488f397c8d8SUlf Hansson 					 use_areq);
2489f397c8d8SUlf Hansson }
2490f397c8d8SUlf Hansson 
mmc_test_cmds_during_tfr(struct mmc_test_card * test,int use_sbc,int write,int use_areq)2491f397c8d8SUlf Hansson static int mmc_test_cmds_during_tfr(struct mmc_test_card *test, int use_sbc,
2492f397c8d8SUlf Hansson 				    int write, int use_areq)
2493f397c8d8SUlf Hansson {
2494f397c8d8SUlf Hansson 	struct mmc_test_area *t = &test->area;
2495f397c8d8SUlf Hansson 	unsigned long sz;
2496f397c8d8SUlf Hansson 	int ret;
2497f397c8d8SUlf Hansson 
2498f397c8d8SUlf Hansson 	for (sz = 512; sz <= t->max_tfr; sz += 512) {
2499f397c8d8SUlf Hansson 		ret = __mmc_test_cmds_during_tfr(test, sz, use_sbc, write,
2500f397c8d8SUlf Hansson 						 use_areq);
2501f397c8d8SUlf Hansson 		if (ret)
2502f397c8d8SUlf Hansson 			return ret;
2503f397c8d8SUlf Hansson 	}
2504f397c8d8SUlf Hansson 	return 0;
2505f397c8d8SUlf Hansson }
2506f397c8d8SUlf Hansson 
2507f397c8d8SUlf Hansson /*
2508f397c8d8SUlf Hansson  * Commands during read - no Set Block Count (CMD23).
2509f397c8d8SUlf Hansson  */
mmc_test_cmds_during_read(struct mmc_test_card * test)2510f397c8d8SUlf Hansson static int mmc_test_cmds_during_read(struct mmc_test_card *test)
2511f397c8d8SUlf Hansson {
2512f397c8d8SUlf Hansson 	return mmc_test_cmds_during_tfr(test, 0, 0, 0);
2513f397c8d8SUlf Hansson }
2514f397c8d8SUlf Hansson 
2515f397c8d8SUlf Hansson /*
2516f397c8d8SUlf Hansson  * Commands during write - no Set Block Count (CMD23).
2517f397c8d8SUlf Hansson  */
mmc_test_cmds_during_write(struct mmc_test_card * test)2518f397c8d8SUlf Hansson static int mmc_test_cmds_during_write(struct mmc_test_card *test)
2519f397c8d8SUlf Hansson {
2520f397c8d8SUlf Hansson 	return mmc_test_cmds_during_tfr(test, 0, 1, 0);
2521f397c8d8SUlf Hansson }
2522f397c8d8SUlf Hansson 
2523f397c8d8SUlf Hansson /*
2524f397c8d8SUlf Hansson  * Commands during read - use Set Block Count (CMD23).
2525f397c8d8SUlf Hansson  */
mmc_test_cmds_during_read_cmd23(struct mmc_test_card * test)2526f397c8d8SUlf Hansson static int mmc_test_cmds_during_read_cmd23(struct mmc_test_card *test)
2527f397c8d8SUlf Hansson {
2528f397c8d8SUlf Hansson 	return mmc_test_cmds_during_tfr(test, 1, 0, 0);
2529f397c8d8SUlf Hansson }
2530f397c8d8SUlf Hansson 
2531f397c8d8SUlf Hansson /*
2532f397c8d8SUlf Hansson  * Commands during write - use Set Block Count (CMD23).
2533f397c8d8SUlf Hansson  */
mmc_test_cmds_during_write_cmd23(struct mmc_test_card * test)2534f397c8d8SUlf Hansson static int mmc_test_cmds_during_write_cmd23(struct mmc_test_card *test)
2535f397c8d8SUlf Hansson {
2536f397c8d8SUlf Hansson 	return mmc_test_cmds_during_tfr(test, 1, 1, 0);
2537f397c8d8SUlf Hansson }
2538f397c8d8SUlf Hansson 
2539f397c8d8SUlf Hansson /*
2540f397c8d8SUlf Hansson  * Commands during non-blocking read - use Set Block Count (CMD23).
2541f397c8d8SUlf Hansson  */
mmc_test_cmds_during_read_cmd23_nonblock(struct mmc_test_card * test)2542f397c8d8SUlf Hansson static int mmc_test_cmds_during_read_cmd23_nonblock(struct mmc_test_card *test)
2543f397c8d8SUlf Hansson {
2544f397c8d8SUlf Hansson 	return mmc_test_cmds_during_tfr(test, 1, 0, 1);
2545f397c8d8SUlf Hansson }
2546f397c8d8SUlf Hansson 
2547f397c8d8SUlf Hansson /*
2548f397c8d8SUlf Hansson  * Commands during non-blocking write - use Set Block Count (CMD23).
2549f397c8d8SUlf Hansson  */
mmc_test_cmds_during_write_cmd23_nonblock(struct mmc_test_card * test)2550f397c8d8SUlf Hansson static int mmc_test_cmds_during_write_cmd23_nonblock(struct mmc_test_card *test)
2551f397c8d8SUlf Hansson {
2552f397c8d8SUlf Hansson 	return mmc_test_cmds_during_tfr(test, 1, 1, 1);
2553f397c8d8SUlf Hansson }
2554f397c8d8SUlf Hansson 
2555f397c8d8SUlf Hansson static const struct mmc_test_case mmc_test_cases[] = {
2556f397c8d8SUlf Hansson 	{
2557f397c8d8SUlf Hansson 		.name = "Basic write (no data verification)",
2558f397c8d8SUlf Hansson 		.run = mmc_test_basic_write,
2559f397c8d8SUlf Hansson 	},
2560f397c8d8SUlf Hansson 
2561f397c8d8SUlf Hansson 	{
2562f397c8d8SUlf Hansson 		.name = "Basic read (no data verification)",
2563f397c8d8SUlf Hansson 		.run = mmc_test_basic_read,
2564f397c8d8SUlf Hansson 	},
2565f397c8d8SUlf Hansson 
2566f397c8d8SUlf Hansson 	{
2567f397c8d8SUlf Hansson 		.name = "Basic write (with data verification)",
2568f397c8d8SUlf Hansson 		.prepare = mmc_test_prepare_write,
2569f397c8d8SUlf Hansson 		.run = mmc_test_verify_write,
2570f397c8d8SUlf Hansson 		.cleanup = mmc_test_cleanup,
2571f397c8d8SUlf Hansson 	},
2572f397c8d8SUlf Hansson 
2573f397c8d8SUlf Hansson 	{
2574f397c8d8SUlf Hansson 		.name = "Basic read (with data verification)",
2575f397c8d8SUlf Hansson 		.prepare = mmc_test_prepare_read,
2576f397c8d8SUlf Hansson 		.run = mmc_test_verify_read,
2577f397c8d8SUlf Hansson 		.cleanup = mmc_test_cleanup,
2578f397c8d8SUlf Hansson 	},
2579f397c8d8SUlf Hansson 
2580f397c8d8SUlf Hansson 	{
2581f397c8d8SUlf Hansson 		.name = "Multi-block write",
2582f397c8d8SUlf Hansson 		.prepare = mmc_test_prepare_write,
2583f397c8d8SUlf Hansson 		.run = mmc_test_multi_write,
2584f397c8d8SUlf Hansson 		.cleanup = mmc_test_cleanup,
2585f397c8d8SUlf Hansson 	},
2586f397c8d8SUlf Hansson 
2587f397c8d8SUlf Hansson 	{
2588f397c8d8SUlf Hansson 		.name = "Multi-block read",
2589f397c8d8SUlf Hansson 		.prepare = mmc_test_prepare_read,
2590f397c8d8SUlf Hansson 		.run = mmc_test_multi_read,
2591f397c8d8SUlf Hansson 		.cleanup = mmc_test_cleanup,
2592f397c8d8SUlf Hansson 	},
2593f397c8d8SUlf Hansson 
2594f397c8d8SUlf Hansson 	{
2595f397c8d8SUlf Hansson 		.name = "Power of two block writes",
2596f397c8d8SUlf Hansson 		.prepare = mmc_test_prepare_write,
2597f397c8d8SUlf Hansson 		.run = mmc_test_pow2_write,
2598f397c8d8SUlf Hansson 		.cleanup = mmc_test_cleanup,
2599f397c8d8SUlf Hansson 	},
2600f397c8d8SUlf Hansson 
2601f397c8d8SUlf Hansson 	{
2602f397c8d8SUlf Hansson 		.name = "Power of two block reads",
2603f397c8d8SUlf Hansson 		.prepare = mmc_test_prepare_read,
2604f397c8d8SUlf Hansson 		.run = mmc_test_pow2_read,
2605f397c8d8SUlf Hansson 		.cleanup = mmc_test_cleanup,
2606f397c8d8SUlf Hansson 	},
2607f397c8d8SUlf Hansson 
2608f397c8d8SUlf Hansson 	{
2609f397c8d8SUlf Hansson 		.name = "Weird sized block writes",
2610f397c8d8SUlf Hansson 		.prepare = mmc_test_prepare_write,
2611f397c8d8SUlf Hansson 		.run = mmc_test_weird_write,
2612f397c8d8SUlf Hansson 		.cleanup = mmc_test_cleanup,
2613f397c8d8SUlf Hansson 	},
2614f397c8d8SUlf Hansson 
2615f397c8d8SUlf Hansson 	{
2616f397c8d8SUlf Hansson 		.name = "Weird sized block reads",
2617f397c8d8SUlf Hansson 		.prepare = mmc_test_prepare_read,
2618f397c8d8SUlf Hansson 		.run = mmc_test_weird_read,
2619f397c8d8SUlf Hansson 		.cleanup = mmc_test_cleanup,
2620f397c8d8SUlf Hansson 	},
2621f397c8d8SUlf Hansson 
2622f397c8d8SUlf Hansson 	{
2623f397c8d8SUlf Hansson 		.name = "Badly aligned write",
2624f397c8d8SUlf Hansson 		.prepare = mmc_test_prepare_write,
2625f397c8d8SUlf Hansson 		.run = mmc_test_align_write,
2626f397c8d8SUlf Hansson 		.cleanup = mmc_test_cleanup,
2627f397c8d8SUlf Hansson 	},
2628f397c8d8SUlf Hansson 
2629f397c8d8SUlf Hansson 	{
2630f397c8d8SUlf Hansson 		.name = "Badly aligned read",
2631f397c8d8SUlf Hansson 		.prepare = mmc_test_prepare_read,
2632f397c8d8SUlf Hansson 		.run = mmc_test_align_read,
2633f397c8d8SUlf Hansson 		.cleanup = mmc_test_cleanup,
2634f397c8d8SUlf Hansson 	},
2635f397c8d8SUlf Hansson 
2636f397c8d8SUlf Hansson 	{
2637f397c8d8SUlf Hansson 		.name = "Badly aligned multi-block write",
2638f397c8d8SUlf Hansson 		.prepare = mmc_test_prepare_write,
2639f397c8d8SUlf Hansson 		.run = mmc_test_align_multi_write,
2640f397c8d8SUlf Hansson 		.cleanup = mmc_test_cleanup,
2641f397c8d8SUlf Hansson 	},
2642f397c8d8SUlf Hansson 
2643f397c8d8SUlf Hansson 	{
2644f397c8d8SUlf Hansson 		.name = "Badly aligned multi-block read",
2645f397c8d8SUlf Hansson 		.prepare = mmc_test_prepare_read,
2646f397c8d8SUlf Hansson 		.run = mmc_test_align_multi_read,
2647f397c8d8SUlf Hansson 		.cleanup = mmc_test_cleanup,
2648f397c8d8SUlf Hansson 	},
2649f397c8d8SUlf Hansson 
2650f397c8d8SUlf Hansson 	{
2651c92a6af6SWolfram Sang 		.name = "Proper xfer_size at write (start failure)",
2652f397c8d8SUlf Hansson 		.run = mmc_test_xfersize_write,
2653f397c8d8SUlf Hansson 	},
2654f397c8d8SUlf Hansson 
2655f397c8d8SUlf Hansson 	{
2656c92a6af6SWolfram Sang 		.name = "Proper xfer_size at read (start failure)",
2657f397c8d8SUlf Hansson 		.run = mmc_test_xfersize_read,
2658f397c8d8SUlf Hansson 	},
2659f397c8d8SUlf Hansson 
2660f397c8d8SUlf Hansson 	{
2661c92a6af6SWolfram Sang 		.name = "Proper xfer_size at write (midway failure)",
2662f397c8d8SUlf Hansson 		.run = mmc_test_multi_xfersize_write,
2663f397c8d8SUlf Hansson 	},
2664f397c8d8SUlf Hansson 
2665f397c8d8SUlf Hansson 	{
2666c92a6af6SWolfram Sang 		.name = "Proper xfer_size at read (midway failure)",
2667f397c8d8SUlf Hansson 		.run = mmc_test_multi_xfersize_read,
2668f397c8d8SUlf Hansson 	},
2669f397c8d8SUlf Hansson 
2670f397c8d8SUlf Hansson #ifdef CONFIG_HIGHMEM
2671f397c8d8SUlf Hansson 
2672f397c8d8SUlf Hansson 	{
2673f397c8d8SUlf Hansson 		.name = "Highmem write",
2674f397c8d8SUlf Hansson 		.prepare = mmc_test_prepare_write,
2675f397c8d8SUlf Hansson 		.run = mmc_test_write_high,
2676f397c8d8SUlf Hansson 		.cleanup = mmc_test_cleanup,
2677f397c8d8SUlf Hansson 	},
2678f397c8d8SUlf Hansson 
2679f397c8d8SUlf Hansson 	{
2680f397c8d8SUlf Hansson 		.name = "Highmem read",
2681f397c8d8SUlf Hansson 		.prepare = mmc_test_prepare_read,
2682f397c8d8SUlf Hansson 		.run = mmc_test_read_high,
2683f397c8d8SUlf Hansson 		.cleanup = mmc_test_cleanup,
2684f397c8d8SUlf Hansson 	},
2685f397c8d8SUlf Hansson 
2686f397c8d8SUlf Hansson 	{
2687f397c8d8SUlf Hansson 		.name = "Multi-block highmem write",
2688f397c8d8SUlf Hansson 		.prepare = mmc_test_prepare_write,
2689f397c8d8SUlf Hansson 		.run = mmc_test_multi_write_high,
2690f397c8d8SUlf Hansson 		.cleanup = mmc_test_cleanup,
2691f397c8d8SUlf Hansson 	},
2692f397c8d8SUlf Hansson 
2693f397c8d8SUlf Hansson 	{
2694f397c8d8SUlf Hansson 		.name = "Multi-block highmem read",
2695f397c8d8SUlf Hansson 		.prepare = mmc_test_prepare_read,
2696f397c8d8SUlf Hansson 		.run = mmc_test_multi_read_high,
2697f397c8d8SUlf Hansson 		.cleanup = mmc_test_cleanup,
2698f397c8d8SUlf Hansson 	},
2699f397c8d8SUlf Hansson 
2700f397c8d8SUlf Hansson #else
2701f397c8d8SUlf Hansson 
2702f397c8d8SUlf Hansson 	{
2703f397c8d8SUlf Hansson 		.name = "Highmem write",
2704f397c8d8SUlf Hansson 		.run = mmc_test_no_highmem,
2705f397c8d8SUlf Hansson 	},
2706f397c8d8SUlf Hansson 
2707f397c8d8SUlf Hansson 	{
2708f397c8d8SUlf Hansson 		.name = "Highmem read",
2709f397c8d8SUlf Hansson 		.run = mmc_test_no_highmem,
2710f397c8d8SUlf Hansson 	},
2711f397c8d8SUlf Hansson 
2712f397c8d8SUlf Hansson 	{
2713f397c8d8SUlf Hansson 		.name = "Multi-block highmem write",
2714f397c8d8SUlf Hansson 		.run = mmc_test_no_highmem,
2715f397c8d8SUlf Hansson 	},
2716f397c8d8SUlf Hansson 
2717f397c8d8SUlf Hansson 	{
2718f397c8d8SUlf Hansson 		.name = "Multi-block highmem read",
2719f397c8d8SUlf Hansson 		.run = mmc_test_no_highmem,
2720f397c8d8SUlf Hansson 	},
2721f397c8d8SUlf Hansson 
2722f397c8d8SUlf Hansson #endif /* CONFIG_HIGHMEM */
2723f397c8d8SUlf Hansson 
2724f397c8d8SUlf Hansson 	{
2725f397c8d8SUlf Hansson 		.name = "Best-case read performance",
2726f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare_fill,
2727f397c8d8SUlf Hansson 		.run = mmc_test_best_read_performance,
2728f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2729f397c8d8SUlf Hansson 	},
2730f397c8d8SUlf Hansson 
2731f397c8d8SUlf Hansson 	{
2732f397c8d8SUlf Hansson 		.name = "Best-case write performance",
2733f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare_erase,
2734f397c8d8SUlf Hansson 		.run = mmc_test_best_write_performance,
2735f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2736f397c8d8SUlf Hansson 	},
2737f397c8d8SUlf Hansson 
2738f397c8d8SUlf Hansson 	{
2739f397c8d8SUlf Hansson 		.name = "Best-case read performance into scattered pages",
2740f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare_fill,
2741f397c8d8SUlf Hansson 		.run = mmc_test_best_read_perf_max_scatter,
2742f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2743f397c8d8SUlf Hansson 	},
2744f397c8d8SUlf Hansson 
2745f397c8d8SUlf Hansson 	{
2746f397c8d8SUlf Hansson 		.name = "Best-case write performance from scattered pages",
2747f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare_erase,
2748f397c8d8SUlf Hansson 		.run = mmc_test_best_write_perf_max_scatter,
2749f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2750f397c8d8SUlf Hansson 	},
2751f397c8d8SUlf Hansson 
2752f397c8d8SUlf Hansson 	{
2753f397c8d8SUlf Hansson 		.name = "Single read performance by transfer size",
2754f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare_fill,
2755f397c8d8SUlf Hansson 		.run = mmc_test_profile_read_perf,
2756f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2757f397c8d8SUlf Hansson 	},
2758f397c8d8SUlf Hansson 
2759f397c8d8SUlf Hansson 	{
2760f397c8d8SUlf Hansson 		.name = "Single write performance by transfer size",
2761f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare,
2762f397c8d8SUlf Hansson 		.run = mmc_test_profile_write_perf,
2763f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2764f397c8d8SUlf Hansson 	},
2765f397c8d8SUlf Hansson 
2766f397c8d8SUlf Hansson 	{
2767f397c8d8SUlf Hansson 		.name = "Single trim performance by transfer size",
2768f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare_fill,
2769f397c8d8SUlf Hansson 		.run = mmc_test_profile_trim_perf,
2770f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2771f397c8d8SUlf Hansson 	},
2772f397c8d8SUlf Hansson 
2773f397c8d8SUlf Hansson 	{
2774f397c8d8SUlf Hansson 		.name = "Consecutive read performance by transfer size",
2775f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare_fill,
2776f397c8d8SUlf Hansson 		.run = mmc_test_profile_seq_read_perf,
2777f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2778f397c8d8SUlf Hansson 	},
2779f397c8d8SUlf Hansson 
2780f397c8d8SUlf Hansson 	{
2781f397c8d8SUlf Hansson 		.name = "Consecutive write performance by transfer size",
2782f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare,
2783f397c8d8SUlf Hansson 		.run = mmc_test_profile_seq_write_perf,
2784f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2785f397c8d8SUlf Hansson 	},
2786f397c8d8SUlf Hansson 
2787f397c8d8SUlf Hansson 	{
2788f397c8d8SUlf Hansson 		.name = "Consecutive trim performance by transfer size",
2789f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare,
2790f397c8d8SUlf Hansson 		.run = mmc_test_profile_seq_trim_perf,
2791f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2792f397c8d8SUlf Hansson 	},
2793f397c8d8SUlf Hansson 
2794f397c8d8SUlf Hansson 	{
2795f397c8d8SUlf Hansson 		.name = "Random read performance by transfer size",
2796f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare,
2797f397c8d8SUlf Hansson 		.run = mmc_test_random_read_perf,
2798f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2799f397c8d8SUlf Hansson 	},
2800f397c8d8SUlf Hansson 
2801f397c8d8SUlf Hansson 	{
2802f397c8d8SUlf Hansson 		.name = "Random write performance by transfer size",
2803f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare,
2804f397c8d8SUlf Hansson 		.run = mmc_test_random_write_perf,
2805f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2806f397c8d8SUlf Hansson 	},
2807f397c8d8SUlf Hansson 
2808f397c8d8SUlf Hansson 	{
2809f397c8d8SUlf Hansson 		.name = "Large sequential read into scattered pages",
2810f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare,
2811f397c8d8SUlf Hansson 		.run = mmc_test_large_seq_read_perf,
2812f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2813f397c8d8SUlf Hansson 	},
2814f397c8d8SUlf Hansson 
2815f397c8d8SUlf Hansson 	{
2816f397c8d8SUlf Hansson 		.name = "Large sequential write from scattered pages",
2817f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare,
2818f397c8d8SUlf Hansson 		.run = mmc_test_large_seq_write_perf,
2819f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2820f397c8d8SUlf Hansson 	},
2821f397c8d8SUlf Hansson 
2822f397c8d8SUlf Hansson 	{
2823f397c8d8SUlf Hansson 		.name = "Write performance with blocking req 4k to 4MB",
2824f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare,
2825f397c8d8SUlf Hansson 		.run = mmc_test_profile_mult_write_blocking_perf,
2826f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2827f397c8d8SUlf Hansson 	},
2828f397c8d8SUlf Hansson 
2829f397c8d8SUlf Hansson 	{
2830f397c8d8SUlf Hansson 		.name = "Write performance with non-blocking req 4k to 4MB",
2831f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare,
2832f397c8d8SUlf Hansson 		.run = mmc_test_profile_mult_write_nonblock_perf,
2833f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2834f397c8d8SUlf Hansson 	},
2835f397c8d8SUlf Hansson 
2836f397c8d8SUlf Hansson 	{
2837f397c8d8SUlf Hansson 		.name = "Read performance with blocking req 4k to 4MB",
2838f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare,
2839f397c8d8SUlf Hansson 		.run = mmc_test_profile_mult_read_blocking_perf,
2840f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2841f397c8d8SUlf Hansson 	},
2842f397c8d8SUlf Hansson 
2843f397c8d8SUlf Hansson 	{
2844f397c8d8SUlf Hansson 		.name = "Read performance with non-blocking req 4k to 4MB",
2845f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare,
2846f397c8d8SUlf Hansson 		.run = mmc_test_profile_mult_read_nonblock_perf,
2847f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2848f397c8d8SUlf Hansson 	},
2849f397c8d8SUlf Hansson 
2850f397c8d8SUlf Hansson 	{
2851f397c8d8SUlf Hansson 		.name = "Write performance blocking req 1 to 512 sg elems",
2852f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare,
2853f397c8d8SUlf Hansson 		.run = mmc_test_profile_sglen_wr_blocking_perf,
2854f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2855f397c8d8SUlf Hansson 	},
2856f397c8d8SUlf Hansson 
2857f397c8d8SUlf Hansson 	{
2858f397c8d8SUlf Hansson 		.name = "Write performance non-blocking req 1 to 512 sg elems",
2859f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare,
2860f397c8d8SUlf Hansson 		.run = mmc_test_profile_sglen_wr_nonblock_perf,
2861f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2862f397c8d8SUlf Hansson 	},
2863f397c8d8SUlf Hansson 
2864f397c8d8SUlf Hansson 	{
2865f397c8d8SUlf Hansson 		.name = "Read performance blocking req 1 to 512 sg elems",
2866f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare,
2867f397c8d8SUlf Hansson 		.run = mmc_test_profile_sglen_r_blocking_perf,
2868f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2869f397c8d8SUlf Hansson 	},
2870f397c8d8SUlf Hansson 
2871f397c8d8SUlf Hansson 	{
2872f397c8d8SUlf Hansson 		.name = "Read performance non-blocking req 1 to 512 sg elems",
2873f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare,
2874f397c8d8SUlf Hansson 		.run = mmc_test_profile_sglen_r_nonblock_perf,
2875f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2876f397c8d8SUlf Hansson 	},
2877f397c8d8SUlf Hansson 
2878f397c8d8SUlf Hansson 	{
2879f397c8d8SUlf Hansson 		.name = "Reset test",
2880f397c8d8SUlf Hansson 		.run = mmc_test_reset,
2881f397c8d8SUlf Hansson 	},
2882f397c8d8SUlf Hansson 
2883f397c8d8SUlf Hansson 	{
2884f397c8d8SUlf Hansson 		.name = "Commands during read - no Set Block Count (CMD23)",
2885f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare,
2886f397c8d8SUlf Hansson 		.run = mmc_test_cmds_during_read,
2887f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2888f397c8d8SUlf Hansson 	},
2889f397c8d8SUlf Hansson 
2890f397c8d8SUlf Hansson 	{
2891f397c8d8SUlf Hansson 		.name = "Commands during write - no Set Block Count (CMD23)",
2892f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare,
2893f397c8d8SUlf Hansson 		.run = mmc_test_cmds_during_write,
2894f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2895f397c8d8SUlf Hansson 	},
2896f397c8d8SUlf Hansson 
2897f397c8d8SUlf Hansson 	{
2898f397c8d8SUlf Hansson 		.name = "Commands during read - use Set Block Count (CMD23)",
2899f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare,
2900f397c8d8SUlf Hansson 		.run = mmc_test_cmds_during_read_cmd23,
2901f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2902f397c8d8SUlf Hansson 	},
2903f397c8d8SUlf Hansson 
2904f397c8d8SUlf Hansson 	{
2905f397c8d8SUlf Hansson 		.name = "Commands during write - use Set Block Count (CMD23)",
2906f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare,
2907f397c8d8SUlf Hansson 		.run = mmc_test_cmds_during_write_cmd23,
2908f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2909f397c8d8SUlf Hansson 	},
2910f397c8d8SUlf Hansson 
2911f397c8d8SUlf Hansson 	{
2912f397c8d8SUlf Hansson 		.name = "Commands during non-blocking read - use Set Block Count (CMD23)",
2913f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare,
2914f397c8d8SUlf Hansson 		.run = mmc_test_cmds_during_read_cmd23_nonblock,
2915f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2916f397c8d8SUlf Hansson 	},
2917f397c8d8SUlf Hansson 
2918f397c8d8SUlf Hansson 	{
2919f397c8d8SUlf Hansson 		.name = "Commands during non-blocking write - use Set Block Count (CMD23)",
2920f397c8d8SUlf Hansson 		.prepare = mmc_test_area_prepare,
2921f397c8d8SUlf Hansson 		.run = mmc_test_cmds_during_write_cmd23_nonblock,
2922f397c8d8SUlf Hansson 		.cleanup = mmc_test_area_cleanup,
2923f397c8d8SUlf Hansson 	},
2924f397c8d8SUlf Hansson };
2925f397c8d8SUlf Hansson 
2926f397c8d8SUlf Hansson static DEFINE_MUTEX(mmc_test_lock);
2927f397c8d8SUlf Hansson 
2928f397c8d8SUlf Hansson static LIST_HEAD(mmc_test_result);
2929f397c8d8SUlf Hansson 
mmc_test_run(struct mmc_test_card * test,int testcase)2930f397c8d8SUlf Hansson static void mmc_test_run(struct mmc_test_card *test, int testcase)
2931f397c8d8SUlf Hansson {
2932f397c8d8SUlf Hansson 	int i, ret;
2933f397c8d8SUlf Hansson 
2934f397c8d8SUlf Hansson 	pr_info("%s: Starting tests of card %s...\n",
2935f397c8d8SUlf Hansson 		mmc_hostname(test->card->host), mmc_card_id(test->card));
2936f397c8d8SUlf Hansson 
2937f397c8d8SUlf Hansson 	mmc_claim_host(test->card->host);
2938f397c8d8SUlf Hansson 
2939f397c8d8SUlf Hansson 	for (i = 0; i < ARRAY_SIZE(mmc_test_cases); i++) {
2940f397c8d8SUlf Hansson 		struct mmc_test_general_result *gr;
2941f397c8d8SUlf Hansson 
2942f397c8d8SUlf Hansson 		if (testcase && ((i + 1) != testcase))
2943f397c8d8SUlf Hansson 			continue;
2944f397c8d8SUlf Hansson 
2945f397c8d8SUlf Hansson 		pr_info("%s: Test case %d. %s...\n",
2946f397c8d8SUlf Hansson 			mmc_hostname(test->card->host), i + 1,
2947f397c8d8SUlf Hansson 			mmc_test_cases[i].name);
2948f397c8d8SUlf Hansson 
2949f397c8d8SUlf Hansson 		if (mmc_test_cases[i].prepare) {
2950f397c8d8SUlf Hansson 			ret = mmc_test_cases[i].prepare(test);
2951f397c8d8SUlf Hansson 			if (ret) {
29527200449dSMarkus Elfring 				pr_info("%s: Result: Prepare stage failed! (%d)\n",
2953f397c8d8SUlf Hansson 					mmc_hostname(test->card->host),
2954f397c8d8SUlf Hansson 					ret);
2955f397c8d8SUlf Hansson 				continue;
2956f397c8d8SUlf Hansson 			}
2957f397c8d8SUlf Hansson 		}
2958f397c8d8SUlf Hansson 
2959554d7c54SMarkus Elfring 		gr = kzalloc(sizeof(*gr), GFP_KERNEL);
2960f397c8d8SUlf Hansson 		if (gr) {
2961f397c8d8SUlf Hansson 			INIT_LIST_HEAD(&gr->tr_lst);
2962f397c8d8SUlf Hansson 
2963f397c8d8SUlf Hansson 			/* Assign data what we know already */
2964f397c8d8SUlf Hansson 			gr->card = test->card;
2965f397c8d8SUlf Hansson 			gr->testcase = i;
2966f397c8d8SUlf Hansson 
2967f397c8d8SUlf Hansson 			/* Append container to global one */
2968f397c8d8SUlf Hansson 			list_add_tail(&gr->link, &mmc_test_result);
2969f397c8d8SUlf Hansson 
2970f397c8d8SUlf Hansson 			/*
2971f397c8d8SUlf Hansson 			 * Save the pointer to created container in our private
2972f397c8d8SUlf Hansson 			 * structure.
2973f397c8d8SUlf Hansson 			 */
2974f397c8d8SUlf Hansson 			test->gr = gr;
2975f397c8d8SUlf Hansson 		}
2976f397c8d8SUlf Hansson 
2977f397c8d8SUlf Hansson 		ret = mmc_test_cases[i].run(test);
2978f397c8d8SUlf Hansson 		switch (ret) {
2979f397c8d8SUlf Hansson 		case RESULT_OK:
2980f397c8d8SUlf Hansson 			pr_info("%s: Result: OK\n",
2981f397c8d8SUlf Hansson 				mmc_hostname(test->card->host));
2982f397c8d8SUlf Hansson 			break;
2983f397c8d8SUlf Hansson 		case RESULT_FAIL:
2984f397c8d8SUlf Hansson 			pr_info("%s: Result: FAILED\n",
2985f397c8d8SUlf Hansson 				mmc_hostname(test->card->host));
2986f397c8d8SUlf Hansson 			break;
2987f397c8d8SUlf Hansson 		case RESULT_UNSUP_HOST:
29887200449dSMarkus Elfring 			pr_info("%s: Result: UNSUPPORTED (by host)\n",
2989f397c8d8SUlf Hansson 				mmc_hostname(test->card->host));
2990f397c8d8SUlf Hansson 			break;
2991f397c8d8SUlf Hansson 		case RESULT_UNSUP_CARD:
29927200449dSMarkus Elfring 			pr_info("%s: Result: UNSUPPORTED (by card)\n",
2993f397c8d8SUlf Hansson 				mmc_hostname(test->card->host));
2994f397c8d8SUlf Hansson 			break;
2995f397c8d8SUlf Hansson 		default:
2996f397c8d8SUlf Hansson 			pr_info("%s: Result: ERROR (%d)\n",
2997f397c8d8SUlf Hansson 				mmc_hostname(test->card->host), ret);
2998f397c8d8SUlf Hansson 		}
2999f397c8d8SUlf Hansson 
3000f397c8d8SUlf Hansson 		/* Save the result */
3001f397c8d8SUlf Hansson 		if (gr)
3002f397c8d8SUlf Hansson 			gr->result = ret;
3003f397c8d8SUlf Hansson 
3004f397c8d8SUlf Hansson 		if (mmc_test_cases[i].cleanup) {
3005f397c8d8SUlf Hansson 			ret = mmc_test_cases[i].cleanup(test);
3006f397c8d8SUlf Hansson 			if (ret) {
30077200449dSMarkus Elfring 				pr_info("%s: Warning: Cleanup stage failed! (%d)\n",
3008f397c8d8SUlf Hansson 					mmc_hostname(test->card->host),
3009f397c8d8SUlf Hansson 					ret);
3010f397c8d8SUlf Hansson 			}
3011f397c8d8SUlf Hansson 		}
3012f397c8d8SUlf Hansson 	}
3013f397c8d8SUlf Hansson 
3014f397c8d8SUlf Hansson 	mmc_release_host(test->card->host);
3015f397c8d8SUlf Hansson 
3016f397c8d8SUlf Hansson 	pr_info("%s: Tests completed.\n",
3017f397c8d8SUlf Hansson 		mmc_hostname(test->card->host));
3018f397c8d8SUlf Hansson }
3019f397c8d8SUlf Hansson 
mmc_test_free_result(struct mmc_card * card)3020f397c8d8SUlf Hansson static void mmc_test_free_result(struct mmc_card *card)
3021f397c8d8SUlf Hansson {
3022f397c8d8SUlf Hansson 	struct mmc_test_general_result *gr, *grs;
3023f397c8d8SUlf Hansson 
3024f397c8d8SUlf Hansson 	mutex_lock(&mmc_test_lock);
3025f397c8d8SUlf Hansson 
3026f397c8d8SUlf Hansson 	list_for_each_entry_safe(gr, grs, &mmc_test_result, link) {
3027f397c8d8SUlf Hansson 		struct mmc_test_transfer_result *tr, *trs;
3028f397c8d8SUlf Hansson 
3029f397c8d8SUlf Hansson 		if (card && gr->card != card)
3030f397c8d8SUlf Hansson 			continue;
3031f397c8d8SUlf Hansson 
3032f397c8d8SUlf Hansson 		list_for_each_entry_safe(tr, trs, &gr->tr_lst, link) {
3033f397c8d8SUlf Hansson 			list_del(&tr->link);
3034f397c8d8SUlf Hansson 			kfree(tr);
3035f397c8d8SUlf Hansson 		}
3036f397c8d8SUlf Hansson 
3037f397c8d8SUlf Hansson 		list_del(&gr->link);
3038f397c8d8SUlf Hansson 		kfree(gr);
3039f397c8d8SUlf Hansson 	}
3040f397c8d8SUlf Hansson 
3041f397c8d8SUlf Hansson 	mutex_unlock(&mmc_test_lock);
3042f397c8d8SUlf Hansson }
3043f397c8d8SUlf Hansson 
3044f397c8d8SUlf Hansson static LIST_HEAD(mmc_test_file_test);
3045f397c8d8SUlf Hansson 
mtf_test_show(struct seq_file * sf,void * data)3046f397c8d8SUlf Hansson static int mtf_test_show(struct seq_file *sf, void *data)
3047f397c8d8SUlf Hansson {
3048*5762451dSYu Zhe 	struct mmc_card *card = sf->private;
3049f397c8d8SUlf Hansson 	struct mmc_test_general_result *gr;
3050f397c8d8SUlf Hansson 
3051f397c8d8SUlf Hansson 	mutex_lock(&mmc_test_lock);
3052f397c8d8SUlf Hansson 
3053f397c8d8SUlf Hansson 	list_for_each_entry(gr, &mmc_test_result, link) {
3054f397c8d8SUlf Hansson 		struct mmc_test_transfer_result *tr;
3055f397c8d8SUlf Hansson 
3056f397c8d8SUlf Hansson 		if (gr->card != card)
3057f397c8d8SUlf Hansson 			continue;
3058f397c8d8SUlf Hansson 
3059f397c8d8SUlf Hansson 		seq_printf(sf, "Test %d: %d\n", gr->testcase + 1, gr->result);
3060f397c8d8SUlf Hansson 
3061f397c8d8SUlf Hansson 		list_for_each_entry(tr, &gr->tr_lst, link) {
3062a5b97be2SArnd Bergmann 			seq_printf(sf, "%u %d %llu.%09u %u %u.%02u\n",
3063f397c8d8SUlf Hansson 				tr->count, tr->sectors,
3064a5b97be2SArnd Bergmann 				(u64)tr->ts.tv_sec, (u32)tr->ts.tv_nsec,
3065f397c8d8SUlf Hansson 				tr->rate, tr->iops / 100, tr->iops % 100);
3066f397c8d8SUlf Hansson 		}
3067f397c8d8SUlf Hansson 	}
3068f397c8d8SUlf Hansson 
3069f397c8d8SUlf Hansson 	mutex_unlock(&mmc_test_lock);
3070f397c8d8SUlf Hansson 
3071f397c8d8SUlf Hansson 	return 0;
3072f397c8d8SUlf Hansson }
3073f397c8d8SUlf Hansson 
mtf_test_open(struct inode * inode,struct file * file)3074f397c8d8SUlf Hansson static int mtf_test_open(struct inode *inode, struct file *file)
3075f397c8d8SUlf Hansson {
3076f397c8d8SUlf Hansson 	return single_open(file, mtf_test_show, inode->i_private);
3077f397c8d8SUlf Hansson }
3078f397c8d8SUlf Hansson 
mtf_test_write(struct file * file,const char __user * buf,size_t count,loff_t * pos)3079f397c8d8SUlf Hansson static ssize_t mtf_test_write(struct file *file, const char __user *buf,
3080f397c8d8SUlf Hansson 	size_t count, loff_t *pos)
3081f397c8d8SUlf Hansson {
3082*5762451dSYu Zhe 	struct seq_file *sf = file->private_data;
3083*5762451dSYu Zhe 	struct mmc_card *card = sf->private;
3084f397c8d8SUlf Hansson 	struct mmc_test_card *test;
3085f397c8d8SUlf Hansson 	long testcase;
3086f397c8d8SUlf Hansson 	int ret;
3087f397c8d8SUlf Hansson 
3088f397c8d8SUlf Hansson 	ret = kstrtol_from_user(buf, count, 10, &testcase);
3089f397c8d8SUlf Hansson 	if (ret)
3090f397c8d8SUlf Hansson 		return ret;
3091f397c8d8SUlf Hansson 
3092554d7c54SMarkus Elfring 	test = kzalloc(sizeof(*test), GFP_KERNEL);
3093f397c8d8SUlf Hansson 	if (!test)
3094f397c8d8SUlf Hansson 		return -ENOMEM;
3095f397c8d8SUlf Hansson 
3096f397c8d8SUlf Hansson 	/*
3097f397c8d8SUlf Hansson 	 * Remove all test cases associated with given card. Thus we have only
3098f397c8d8SUlf Hansson 	 * actual data of the last run.
3099f397c8d8SUlf Hansson 	 */
3100f397c8d8SUlf Hansson 	mmc_test_free_result(card);
3101f397c8d8SUlf Hansson 
3102f397c8d8SUlf Hansson 	test->card = card;
3103f397c8d8SUlf Hansson 
3104f397c8d8SUlf Hansson 	test->buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL);
3105f397c8d8SUlf Hansson #ifdef CONFIG_HIGHMEM
3106f397c8d8SUlf Hansson 	test->highmem = alloc_pages(GFP_KERNEL | __GFP_HIGHMEM, BUFFER_ORDER);
3107f397c8d8SUlf Hansson #endif
3108f397c8d8SUlf Hansson 
3109f397c8d8SUlf Hansson #ifdef CONFIG_HIGHMEM
3110f397c8d8SUlf Hansson 	if (test->buffer && test->highmem) {
3111f397c8d8SUlf Hansson #else
3112f397c8d8SUlf Hansson 	if (test->buffer) {
3113f397c8d8SUlf Hansson #endif
3114f397c8d8SUlf Hansson 		mutex_lock(&mmc_test_lock);
3115f397c8d8SUlf Hansson 		mmc_test_run(test, testcase);
3116f397c8d8SUlf Hansson 		mutex_unlock(&mmc_test_lock);
3117f397c8d8SUlf Hansson 	}
3118f397c8d8SUlf Hansson 
3119f397c8d8SUlf Hansson #ifdef CONFIG_HIGHMEM
3120f397c8d8SUlf Hansson 	__free_pages(test->highmem, BUFFER_ORDER);
3121f397c8d8SUlf Hansson #endif
3122f397c8d8SUlf Hansson 	kfree(test->buffer);
3123f397c8d8SUlf Hansson 	kfree(test);
3124f397c8d8SUlf Hansson 
3125f397c8d8SUlf Hansson 	return count;
3126f397c8d8SUlf Hansson }
3127f397c8d8SUlf Hansson 
3128f397c8d8SUlf Hansson static const struct file_operations mmc_test_fops_test = {
3129f397c8d8SUlf Hansson 	.open		= mtf_test_open,
3130f397c8d8SUlf Hansson 	.read		= seq_read,
3131f397c8d8SUlf Hansson 	.write		= mtf_test_write,
3132f397c8d8SUlf Hansson 	.llseek		= seq_lseek,
3133f397c8d8SUlf Hansson 	.release	= single_release,
3134f397c8d8SUlf Hansson };
3135f397c8d8SUlf Hansson 
3136f397c8d8SUlf Hansson static int mtf_testlist_show(struct seq_file *sf, void *data)
3137f397c8d8SUlf Hansson {
3138f397c8d8SUlf Hansson 	int i;
3139f397c8d8SUlf Hansson 
3140f397c8d8SUlf Hansson 	mutex_lock(&mmc_test_lock);
3141f397c8d8SUlf Hansson 
3142dc3a5fe6SMarkus Elfring 	seq_puts(sf, "0:\tRun all tests\n");
3143f397c8d8SUlf Hansson 	for (i = 0; i < ARRAY_SIZE(mmc_test_cases); i++)
3144f397c8d8SUlf Hansson 		seq_printf(sf, "%d:\t%s\n", i + 1, mmc_test_cases[i].name);
3145f397c8d8SUlf Hansson 
3146f397c8d8SUlf Hansson 	mutex_unlock(&mmc_test_lock);
3147f397c8d8SUlf Hansson 
3148f397c8d8SUlf Hansson 	return 0;
3149f397c8d8SUlf Hansson }
3150f397c8d8SUlf Hansson 
31518ceb2943SYangtao Li DEFINE_SHOW_ATTRIBUTE(mtf_testlist);
3152f397c8d8SUlf Hansson 
3153f397c8d8SUlf Hansson static void mmc_test_free_dbgfs_file(struct mmc_card *card)
3154f397c8d8SUlf Hansson {
3155f397c8d8SUlf Hansson 	struct mmc_test_dbgfs_file *df, *dfs;
3156f397c8d8SUlf Hansson 
3157f397c8d8SUlf Hansson 	mutex_lock(&mmc_test_lock);
3158f397c8d8SUlf Hansson 
3159f397c8d8SUlf Hansson 	list_for_each_entry_safe(df, dfs, &mmc_test_file_test, link) {
3160f397c8d8SUlf Hansson 		if (card && df->card != card)
3161f397c8d8SUlf Hansson 			continue;
3162f397c8d8SUlf Hansson 		debugfs_remove(df->file);
3163f397c8d8SUlf Hansson 		list_del(&df->link);
3164f397c8d8SUlf Hansson 		kfree(df);
3165f397c8d8SUlf Hansson 	}
3166f397c8d8SUlf Hansson 
3167f397c8d8SUlf Hansson 	mutex_unlock(&mmc_test_lock);
3168f397c8d8SUlf Hansson }
3169f397c8d8SUlf Hansson 
3170f397c8d8SUlf Hansson static int __mmc_test_register_dbgfs_file(struct mmc_card *card,
3171f397c8d8SUlf Hansson 	const char *name, umode_t mode, const struct file_operations *fops)
3172f397c8d8SUlf Hansson {
3173f397c8d8SUlf Hansson 	struct dentry *file = NULL;
3174f397c8d8SUlf Hansson 	struct mmc_test_dbgfs_file *df;
3175f397c8d8SUlf Hansson 
3176f397c8d8SUlf Hansson 	if (card->debugfs_root)
3177f4307b4dSYe Bin 		file = debugfs_create_file(name, mode, card->debugfs_root,
3178f4307b4dSYe Bin 					   card, fops);
3179f397c8d8SUlf Hansson 
3180554d7c54SMarkus Elfring 	df = kmalloc(sizeof(*df), GFP_KERNEL);
3181f397c8d8SUlf Hansson 	if (!df) {
3182f397c8d8SUlf Hansson 		debugfs_remove(file);
3183f397c8d8SUlf Hansson 		return -ENOMEM;
3184f397c8d8SUlf Hansson 	}
3185f397c8d8SUlf Hansson 
3186f397c8d8SUlf Hansson 	df->card = card;
3187f397c8d8SUlf Hansson 	df->file = file;
3188f397c8d8SUlf Hansson 
3189f397c8d8SUlf Hansson 	list_add(&df->link, &mmc_test_file_test);
3190f397c8d8SUlf Hansson 	return 0;
3191f397c8d8SUlf Hansson }
3192f397c8d8SUlf Hansson 
3193f397c8d8SUlf Hansson static int mmc_test_register_dbgfs_file(struct mmc_card *card)
3194f397c8d8SUlf Hansson {
3195f397c8d8SUlf Hansson 	int ret;
3196f397c8d8SUlf Hansson 
3197f397c8d8SUlf Hansson 	mutex_lock(&mmc_test_lock);
3198f397c8d8SUlf Hansson 
3199f397c8d8SUlf Hansson 	ret = __mmc_test_register_dbgfs_file(card, "test", S_IWUSR | S_IRUGO,
3200f397c8d8SUlf Hansson 		&mmc_test_fops_test);
3201f397c8d8SUlf Hansson 	if (ret)
3202f397c8d8SUlf Hansson 		goto err;
3203f397c8d8SUlf Hansson 
3204f397c8d8SUlf Hansson 	ret = __mmc_test_register_dbgfs_file(card, "testlist", S_IRUGO,
32058ceb2943SYangtao Li 		&mtf_testlist_fops);
3206f397c8d8SUlf Hansson 	if (ret)
3207f397c8d8SUlf Hansson 		goto err;
3208f397c8d8SUlf Hansson 
3209f397c8d8SUlf Hansson err:
3210f397c8d8SUlf Hansson 	mutex_unlock(&mmc_test_lock);
3211f397c8d8SUlf Hansson 
3212f397c8d8SUlf Hansson 	return ret;
3213f397c8d8SUlf Hansson }
3214f397c8d8SUlf Hansson 
3215f397c8d8SUlf Hansson static int mmc_test_probe(struct mmc_card *card)
3216f397c8d8SUlf Hansson {
3217f397c8d8SUlf Hansson 	int ret;
3218f397c8d8SUlf Hansson 
3219f397c8d8SUlf Hansson 	if (!mmc_card_mmc(card) && !mmc_card_sd(card))
3220f397c8d8SUlf Hansson 		return -ENODEV;
3221f397c8d8SUlf Hansson 
3222f397c8d8SUlf Hansson 	ret = mmc_test_register_dbgfs_file(card);
3223f397c8d8SUlf Hansson 	if (ret)
3224f397c8d8SUlf Hansson 		return ret;
3225f397c8d8SUlf Hansson 
32269d4579a8SAdrian Hunter 	if (card->ext_csd.cmdq_en) {
32279d4579a8SAdrian Hunter 		mmc_claim_host(card->host);
32289d4579a8SAdrian Hunter 		ret = mmc_cmdq_disable(card);
32299d4579a8SAdrian Hunter 		mmc_release_host(card->host);
32309d4579a8SAdrian Hunter 		if (ret)
32319d4579a8SAdrian Hunter 			return ret;
32329d4579a8SAdrian Hunter 	}
32339d4579a8SAdrian Hunter 
3234f397c8d8SUlf Hansson 	dev_info(&card->dev, "Card claimed for testing.\n");
3235f397c8d8SUlf Hansson 
3236f397c8d8SUlf Hansson 	return 0;
3237f397c8d8SUlf Hansson }
3238f397c8d8SUlf Hansson 
3239f397c8d8SUlf Hansson static void mmc_test_remove(struct mmc_card *card)
3240f397c8d8SUlf Hansson {
32419d4579a8SAdrian Hunter 	if (card->reenable_cmdq) {
32429d4579a8SAdrian Hunter 		mmc_claim_host(card->host);
32439d4579a8SAdrian Hunter 		mmc_cmdq_enable(card);
32449d4579a8SAdrian Hunter 		mmc_release_host(card->host);
32459d4579a8SAdrian Hunter 	}
3246f397c8d8SUlf Hansson 	mmc_test_free_result(card);
3247f397c8d8SUlf Hansson 	mmc_test_free_dbgfs_file(card);
3248f397c8d8SUlf Hansson }
3249f397c8d8SUlf Hansson 
3250f397c8d8SUlf Hansson static struct mmc_driver mmc_driver = {
3251f397c8d8SUlf Hansson 	.drv		= {
3252f397c8d8SUlf Hansson 		.name	= "mmc_test",
3253f397c8d8SUlf Hansson 	},
3254f397c8d8SUlf Hansson 	.probe		= mmc_test_probe,
3255f397c8d8SUlf Hansson 	.remove		= mmc_test_remove,
3256f397c8d8SUlf Hansson };
3257f397c8d8SUlf Hansson 
3258f397c8d8SUlf Hansson static int __init mmc_test_init(void)
3259f397c8d8SUlf Hansson {
3260f397c8d8SUlf Hansson 	return mmc_register_driver(&mmc_driver);
3261f397c8d8SUlf Hansson }
3262f397c8d8SUlf Hansson 
3263f397c8d8SUlf Hansson static void __exit mmc_test_exit(void)
3264f397c8d8SUlf Hansson {
3265f397c8d8SUlf Hansson 	/* Clear stalled data if card is still plugged */
3266f397c8d8SUlf Hansson 	mmc_test_free_result(NULL);
3267f397c8d8SUlf Hansson 	mmc_test_free_dbgfs_file(NULL);
3268f397c8d8SUlf Hansson 
3269f397c8d8SUlf Hansson 	mmc_unregister_driver(&mmc_driver);
3270f397c8d8SUlf Hansson }
3271f397c8d8SUlf Hansson 
3272f397c8d8SUlf Hansson module_init(mmc_test_init);
3273f397c8d8SUlf Hansson module_exit(mmc_test_exit);
3274f397c8d8SUlf Hansson 
3275f397c8d8SUlf Hansson MODULE_LICENSE("GPL");
3276f397c8d8SUlf Hansson MODULE_DESCRIPTION("Multimedia Card (MMC) host test driver");
3277f397c8d8SUlf Hansson MODULE_AUTHOR("Pierre Ossman");
3278