blob: d6b9b486417cc702acb18bba2fd413baedf592d9 [file] [log] [blame]
Pierre Ossman88ae6002007-08-12 14:23:50 +02001/*
2 * linux/drivers/mmc/card/mmc_test.c
3 *
Pierre Ossman0121a982008-06-28 17:51:27 +02004 * Copyright 2007-2008 Pierre Ossman
Pierre Ossman88ae6002007-08-12 14:23:50 +02005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or (at
9 * your option) any later version.
10 */
11
12#include <linux/mmc/core.h>
13#include <linux/mmc/card.h>
14#include <linux/mmc/host.h>
15#include <linux/mmc/mmc.h>
16
17#include <linux/scatterlist.h>
18
19#define RESULT_OK 0
20#define RESULT_FAIL 1
21#define RESULT_UNSUP_HOST 2
22#define RESULT_UNSUP_CARD 3
23
24#define BUFFER_SIZE (PAGE_SIZE * 4)
25
26struct mmc_test_card {
27 struct mmc_card *card;
28
Pierre Ossman6b174932008-06-30 09:09:27 +020029 u8 scratch[BUFFER_SIZE];
Pierre Ossman88ae6002007-08-12 14:23:50 +020030 u8 *buffer;
31};
32
33/*******************************************************************/
Pierre Ossman6b174932008-06-30 09:09:27 +020034/* General helper functions */
Pierre Ossman88ae6002007-08-12 14:23:50 +020035/*******************************************************************/
36
Pierre Ossman6b174932008-06-30 09:09:27 +020037/*
38 * Configure correct block size in card
39 */
Pierre Ossman88ae6002007-08-12 14:23:50 +020040static int mmc_test_set_blksize(struct mmc_test_card *test, unsigned size)
41{
42 struct mmc_command cmd;
43 int ret;
44
45 cmd.opcode = MMC_SET_BLOCKLEN;
46 cmd.arg = size;
47 cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
48 ret = mmc_wait_for_cmd(test->card->host, &cmd, 0);
49 if (ret)
50 return ret;
51
52 return 0;
53}
54
Pierre Ossman6b174932008-06-30 09:09:27 +020055/*
56 * Fill in the mmc_request structure given a set of transfer parameters.
57 */
58static void mmc_test_prepare_mrq(struct mmc_test_card *test,
59 struct mmc_request *mrq, struct scatterlist *sg, unsigned sg_len,
60 unsigned dev_addr, unsigned blocks, unsigned blksz, int write)
61{
62 BUG_ON(!mrq || !mrq->cmd || !mrq->data || !mrq->stop);
63
64 if (blocks > 1) {
65 mrq->cmd->opcode = write ?
66 MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK;
67 } else {
68 mrq->cmd->opcode = write ?
69 MMC_WRITE_BLOCK : MMC_READ_SINGLE_BLOCK;
70 }
71
72 mrq->cmd->arg = dev_addr;
73 mrq->cmd->flags = MMC_RSP_R1 | MMC_CMD_ADTC;
74
75 if (blocks == 1)
76 mrq->stop = NULL;
77 else {
78 mrq->stop->opcode = MMC_STOP_TRANSMISSION;
79 mrq->stop->arg = 0;
80 mrq->stop->flags = MMC_RSP_R1B | MMC_CMD_AC;
81 }
82
83 mrq->data->blksz = blksz;
84 mrq->data->blocks = blocks;
85 mrq->data->flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
86 mrq->data->sg = sg;
87 mrq->data->sg_len = sg_len;
88
89 mmc_set_data_timeout(mrq->data, test->card);
90}
91
92/*
93 * Wait for the card to finish the busy state
94 */
95static int mmc_test_wait_busy(struct mmc_test_card *test)
Pierre Ossman88ae6002007-08-12 14:23:50 +020096{
97 int ret, busy;
Pierre Ossman88ae6002007-08-12 14:23:50 +020098 struct mmc_command cmd;
Pierre Ossman88ae6002007-08-12 14:23:50 +020099
100 busy = 0;
101 do {
Pierre Ossman88ae6002007-08-12 14:23:50 +0200102 memset(&cmd, 0, sizeof(struct mmc_command));
103
104 cmd.opcode = MMC_SEND_STATUS;
105 cmd.arg = test->card->rca << 16;
106 cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
107
Pierre Ossman6b174932008-06-30 09:09:27 +0200108 ret = mmc_wait_for_cmd(test->card->host, &cmd, 0);
109 if (ret)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200110 break;
111
112 if (!busy && !(cmd.resp[0] & R1_READY_FOR_DATA)) {
113 busy = 1;
114 printk(KERN_INFO "%s: Warning: Host did not "
115 "wait for busy state to end.\n",
116 mmc_hostname(test->card->host));
117 }
118 } while (!(cmd.resp[0] & R1_READY_FOR_DATA));
119
120 return ret;
121}
122
Pierre Ossman6b174932008-06-30 09:09:27 +0200123/*
124 * Transfer a single sector of kernel addressable data
125 */
126static int mmc_test_buffer_transfer(struct mmc_test_card *test,
127 u8 *buffer, unsigned addr, unsigned blksz, int write)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200128{
Pierre Ossman6b174932008-06-30 09:09:27 +0200129 int ret;
130
131 struct mmc_request mrq;
132 struct mmc_command cmd;
133 struct mmc_command stop;
134 struct mmc_data data;
135
136 struct scatterlist sg;
137
138 memset(&mrq, 0, sizeof(struct mmc_request));
139 memset(&cmd, 0, sizeof(struct mmc_command));
140 memset(&data, 0, sizeof(struct mmc_data));
141 memset(&stop, 0, sizeof(struct mmc_command));
142
143 mrq.cmd = &cmd;
144 mrq.data = &data;
145 mrq.stop = &stop;
146
147 sg_init_one(&sg, buffer, blksz);
148
149 mmc_test_prepare_mrq(test, &mrq, &sg, 1, addr, 1, blksz, write);
150
151 mmc_wait_for_req(test->card->host, &mrq);
152
153 if (cmd.error)
154 return cmd.error;
155 if (data.error)
156 return data.error;
157
158 ret = mmc_test_wait_busy(test);
159 if (ret)
160 return ret;
161
162 return 0;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200163}
164
Pierre Ossman6b174932008-06-30 09:09:27 +0200165/*******************************************************************/
166/* Test preparation and cleanup */
167/*******************************************************************/
168
169/*
170 * Fill the first couple of sectors of the card with known data
171 * so that bad reads/writes can be detected
172 */
173static int __mmc_test_prepare(struct mmc_test_card *test, int write)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200174{
175 int ret, i;
176
177 ret = mmc_test_set_blksize(test, 512);
178 if (ret)
179 return ret;
180
181 if (write)
Pierre Ossman6b174932008-06-30 09:09:27 +0200182 memset(test->buffer, 0xDF, 512);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200183 else {
Pierre Ossman6b174932008-06-30 09:09:27 +0200184 for (i = 0;i < 512;i++)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200185 test->buffer[i] = i;
186 }
187
188 for (i = 0;i < BUFFER_SIZE / 512;i++) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200189 ret = mmc_test_buffer_transfer(test, test->buffer, i * 512, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200190 if (ret)
191 return ret;
192 }
193
194 return 0;
195}
196
Pierre Ossman6b174932008-06-30 09:09:27 +0200197static int mmc_test_prepare_write(struct mmc_test_card *test)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200198{
Pierre Ossman6b174932008-06-30 09:09:27 +0200199 return __mmc_test_prepare(test, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200200}
201
Pierre Ossman6b174932008-06-30 09:09:27 +0200202static int mmc_test_prepare_read(struct mmc_test_card *test)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200203{
Pierre Ossman6b174932008-06-30 09:09:27 +0200204 return __mmc_test_prepare(test, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200205}
206
Pierre Ossman6b174932008-06-30 09:09:27 +0200207static int mmc_test_cleanup(struct mmc_test_card *test)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200208{
Pierre Ossman6b174932008-06-30 09:09:27 +0200209 int ret, i;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200210
Pierre Ossman6b174932008-06-30 09:09:27 +0200211 ret = mmc_test_set_blksize(test, 512);
212 if (ret)
213 return ret;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200214
Pierre Ossman6b174932008-06-30 09:09:27 +0200215 memset(test->buffer, 0, 512);
216
217 for (i = 0;i < BUFFER_SIZE / 512;i++) {
218 ret = mmc_test_buffer_transfer(test, test->buffer, i * 512, 512, 1);
219 if (ret)
220 return ret;
221 }
222
223 return 0;
224}
225
226/*******************************************************************/
227/* Test execution helpers */
228/*******************************************************************/
229
230/*
231 * Modifies the mmc_request to perform the "short transfer" tests
232 */
233static void mmc_test_prepare_broken_mrq(struct mmc_test_card *test,
234 struct mmc_request *mrq, int write)
235{
236 BUG_ON(!mrq || !mrq->cmd || !mrq->data);
237
238 if (mrq->data->blocks > 1) {
239 mrq->cmd->opcode = write ?
240 MMC_WRITE_BLOCK : MMC_READ_SINGLE_BLOCK;
241 mrq->stop = NULL;
242 } else {
243 mrq->cmd->opcode = MMC_SEND_STATUS;
244 mrq->cmd->arg = test->card->rca << 16;
245 }
246}
247
248/*
249 * Checks that a normal transfer didn't have any errors
250 */
251static int mmc_test_check_result(struct mmc_test_card *test,
252 struct mmc_request *mrq)
253{
254 int ret;
255
256 BUG_ON(!mrq || !mrq->cmd || !mrq->data);
257
258 ret = 0;
259
260 if (!ret && mrq->cmd->error)
261 ret = mrq->cmd->error;
262 if (!ret && mrq->data->error)
263 ret = mrq->data->error;
264 if (!ret && mrq->stop && mrq->stop->error)
265 ret = mrq->stop->error;
266 if (!ret && mrq->data->bytes_xfered !=
267 mrq->data->blocks * mrq->data->blksz)
268 ret = RESULT_FAIL;
269
270 if (ret == -EINVAL)
271 ret = RESULT_UNSUP_HOST;
272
273 return ret;
274}
275
276/*
277 * Checks that a "short transfer" behaved as expected
278 */
279static int mmc_test_check_broken_result(struct mmc_test_card *test,
280 struct mmc_request *mrq)
281{
282 int ret;
283
284 BUG_ON(!mrq || !mrq->cmd || !mrq->data);
285
286 ret = 0;
287
288 if (!ret && mrq->cmd->error)
289 ret = mrq->cmd->error;
290 if (!ret && mrq->data->error == 0)
291 ret = RESULT_FAIL;
292 if (!ret && mrq->data->error != -ETIMEDOUT)
293 ret = mrq->data->error;
294 if (!ret && mrq->stop && mrq->stop->error)
295 ret = mrq->stop->error;
296 if (mrq->data->blocks > 1) {
297 if (!ret && mrq->data->bytes_xfered > mrq->data->blksz)
298 ret = RESULT_FAIL;
299 } else {
300 if (!ret && mrq->data->bytes_xfered > 0)
301 ret = RESULT_FAIL;
302 }
303
304 if (ret == -EINVAL)
305 ret = RESULT_UNSUP_HOST;
306
307 return ret;
308}
309
310/*
311 * Tests a basic transfer with certain parameters
312 */
313static int mmc_test_simple_transfer(struct mmc_test_card *test,
314 struct scatterlist *sg, unsigned sg_len, unsigned dev_addr,
315 unsigned blocks, unsigned blksz, int write)
316{
317 struct mmc_request mrq;
318 struct mmc_command cmd;
319 struct mmc_command stop;
320 struct mmc_data data;
321
322 memset(&mrq, 0, sizeof(struct mmc_request));
323 memset(&cmd, 0, sizeof(struct mmc_command));
324 memset(&data, 0, sizeof(struct mmc_data));
325 memset(&stop, 0, sizeof(struct mmc_command));
326
327 mrq.cmd = &cmd;
328 mrq.data = &data;
329 mrq.stop = &stop;
330
331 mmc_test_prepare_mrq(test, &mrq, sg, sg_len, dev_addr,
332 blocks, blksz, write);
333
334 mmc_wait_for_req(test->card->host, &mrq);
335
336 mmc_test_wait_busy(test);
337
338 return mmc_test_check_result(test, &mrq);
339}
340
341/*
342 * Tests a transfer where the card will fail completely or partly
343 */
344static int mmc_test_broken_transfer(struct mmc_test_card *test,
345 unsigned blocks, unsigned blksz, int write)
346{
347 struct mmc_request mrq;
348 struct mmc_command cmd;
349 struct mmc_command stop;
350 struct mmc_data data;
351
352 struct scatterlist sg;
353
354 memset(&mrq, 0, sizeof(struct mmc_request));
355 memset(&cmd, 0, sizeof(struct mmc_command));
356 memset(&data, 0, sizeof(struct mmc_data));
357 memset(&stop, 0, sizeof(struct mmc_command));
358
359 mrq.cmd = &cmd;
360 mrq.data = &data;
361 mrq.stop = &stop;
362
363 sg_init_one(&sg, test->buffer, blocks * blksz);
364
365 mmc_test_prepare_mrq(test, &mrq, &sg, 1, 0, blocks, blksz, write);
366 mmc_test_prepare_broken_mrq(test, &mrq, write);
367
368 mmc_wait_for_req(test->card->host, &mrq);
369
370 mmc_test_wait_busy(test);
371
372 return mmc_test_check_broken_result(test, &mrq);
373}
374
375/*
376 * Does a complete transfer test where data is also validated
377 *
378 * Note: mmc_test_prepare() must have been done before this call
379 */
380static int mmc_test_transfer(struct mmc_test_card *test,
381 struct scatterlist *sg, unsigned sg_len, unsigned dev_addr,
382 unsigned blocks, unsigned blksz, int write)
383{
384 int ret, i;
385 unsigned long flags;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200386
387 if (write) {
388 for (i = 0;i < blocks * blksz;i++)
Pierre Ossman6b174932008-06-30 09:09:27 +0200389 test->scratch[i] = i;
390 } else {
391 memset(test->scratch, 0, BUFFER_SIZE);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200392 }
Pierre Ossman6b174932008-06-30 09:09:27 +0200393 local_irq_save(flags);
394 sg_copy_from_buffer(sg, sg_len, test->scratch, BUFFER_SIZE);
395 local_irq_restore(flags);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200396
397 ret = mmc_test_set_blksize(test, blksz);
398 if (ret)
399 return ret;
400
Pierre Ossman6b174932008-06-30 09:09:27 +0200401 ret = mmc_test_simple_transfer(test, sg, sg_len, dev_addr,
402 blocks, blksz, write);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200403 if (ret)
404 return ret;
405
406 if (write) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200407 int sectors;
408
Pierre Ossman88ae6002007-08-12 14:23:50 +0200409 ret = mmc_test_set_blksize(test, 512);
410 if (ret)
411 return ret;
412
413 sectors = (blocks * blksz + 511) / 512;
414 if ((sectors * 512) == (blocks * blksz))
415 sectors++;
416
417 if ((sectors * 512) > BUFFER_SIZE)
418 return -EINVAL;
419
420 memset(test->buffer, 0, sectors * 512);
421
422 for (i = 0;i < sectors;i++) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200423 ret = mmc_test_buffer_transfer(test,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200424 test->buffer + i * 512,
Pierre Ossman6b174932008-06-30 09:09:27 +0200425 dev_addr + i * 512, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200426 if (ret)
427 return ret;
428 }
429
430 for (i = 0;i < blocks * blksz;i++) {
431 if (test->buffer[i] != (u8)i)
432 return RESULT_FAIL;
433 }
434
435 for (;i < sectors * 512;i++) {
436 if (test->buffer[i] != 0xDF)
437 return RESULT_FAIL;
438 }
439 } else {
Pierre Ossman6b174932008-06-30 09:09:27 +0200440 local_irq_save(flags);
441 sg_copy_to_buffer(sg, sg_len, test->scratch, BUFFER_SIZE);
442 local_irq_restore(flags);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200443 for (i = 0;i < blocks * blksz;i++) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200444 if (test->scratch[i] != (u8)i)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200445 return RESULT_FAIL;
446 }
447 }
448
449 return 0;
450}
451
Pierre Ossman88ae6002007-08-12 14:23:50 +0200452/*******************************************************************/
453/* Tests */
454/*******************************************************************/
455
456struct mmc_test_case {
457 const char *name;
458
459 int (*prepare)(struct mmc_test_card *);
460 int (*run)(struct mmc_test_card *);
461 int (*cleanup)(struct mmc_test_card *);
462};
463
464static int mmc_test_basic_write(struct mmc_test_card *test)
465{
466 int ret;
Pierre Ossman6b174932008-06-30 09:09:27 +0200467 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200468
469 ret = mmc_test_set_blksize(test, 512);
470 if (ret)
471 return ret;
472
Pierre Ossman6b174932008-06-30 09:09:27 +0200473 sg_init_one(&sg, test->buffer, 512);
474
475 ret = mmc_test_simple_transfer(test, &sg, 1, 0, 1, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200476 if (ret)
477 return ret;
478
479 return 0;
480}
481
482static int mmc_test_basic_read(struct mmc_test_card *test)
483{
484 int ret;
Pierre Ossman6b174932008-06-30 09:09:27 +0200485 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200486
487 ret = mmc_test_set_blksize(test, 512);
488 if (ret)
489 return ret;
490
Pierre Ossman6b174932008-06-30 09:09:27 +0200491 sg_init_one(&sg, test->buffer, 512);
492
493 ret = mmc_test_simple_transfer(test, &sg, 1, 0, 1, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200494 if (ret)
495 return ret;
496
497 return 0;
498}
499
500static int mmc_test_verify_write(struct mmc_test_card *test)
501{
502 int ret;
Pierre Ossman6b174932008-06-30 09:09:27 +0200503 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200504
Pierre Ossman6b174932008-06-30 09:09:27 +0200505 sg_init_one(&sg, test->buffer, 512);
506
507 ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200508 if (ret)
509 return ret;
510
511 return 0;
512}
513
514static int mmc_test_verify_read(struct mmc_test_card *test)
515{
516 int ret;
Pierre Ossman6b174932008-06-30 09:09:27 +0200517 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200518
Pierre Ossman6b174932008-06-30 09:09:27 +0200519 sg_init_one(&sg, test->buffer, 512);
520
521 ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200522 if (ret)
523 return ret;
524
525 return 0;
526}
527
528static int mmc_test_multi_write(struct mmc_test_card *test)
529{
530 int ret;
531 unsigned int size;
Pierre Ossman6b174932008-06-30 09:09:27 +0200532 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200533
534 if (test->card->host->max_blk_count == 1)
535 return RESULT_UNSUP_HOST;
536
537 size = PAGE_SIZE * 2;
538 size = min(size, test->card->host->max_req_size);
539 size = min(size, test->card->host->max_seg_size);
540 size = min(size, test->card->host->max_blk_count * 512);
541
542 if (size < 1024)
543 return RESULT_UNSUP_HOST;
544
Pierre Ossman6b174932008-06-30 09:09:27 +0200545 sg_init_one(&sg, test->buffer, size);
546
547 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200548 if (ret)
549 return ret;
550
551 return 0;
552}
553
554static int mmc_test_multi_read(struct mmc_test_card *test)
555{
556 int ret;
557 unsigned int size;
Pierre Ossman6b174932008-06-30 09:09:27 +0200558 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200559
560 if (test->card->host->max_blk_count == 1)
561 return RESULT_UNSUP_HOST;
562
563 size = PAGE_SIZE * 2;
564 size = min(size, test->card->host->max_req_size);
565 size = min(size, test->card->host->max_seg_size);
566 size = min(size, test->card->host->max_blk_count * 512);
567
568 if (size < 1024)
569 return RESULT_UNSUP_HOST;
570
Pierre Ossman6b174932008-06-30 09:09:27 +0200571 sg_init_one(&sg, test->buffer, size);
572
573 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200574 if (ret)
575 return ret;
576
577 return 0;
578}
579
580static int mmc_test_pow2_write(struct mmc_test_card *test)
581{
582 int ret, i;
Pierre Ossman6b174932008-06-30 09:09:27 +0200583 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200584
585 if (!test->card->csd.write_partial)
586 return RESULT_UNSUP_CARD;
587
588 for (i = 1; i < 512;i <<= 1) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200589 sg_init_one(&sg, test->buffer, i);
590 ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200591 if (ret)
592 return ret;
593 }
594
595 return 0;
596}
597
598static int mmc_test_pow2_read(struct mmc_test_card *test)
599{
600 int ret, i;
Pierre Ossman6b174932008-06-30 09:09:27 +0200601 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200602
603 if (!test->card->csd.read_partial)
604 return RESULT_UNSUP_CARD;
605
606 for (i = 1; i < 512;i <<= 1) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200607 sg_init_one(&sg, test->buffer, i);
608 ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200609 if (ret)
610 return ret;
611 }
612
613 return 0;
614}
615
616static int mmc_test_weird_write(struct mmc_test_card *test)
617{
618 int ret, i;
Pierre Ossman6b174932008-06-30 09:09:27 +0200619 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200620
621 if (!test->card->csd.write_partial)
622 return RESULT_UNSUP_CARD;
623
624 for (i = 3; i < 512;i += 7) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200625 sg_init_one(&sg, test->buffer, i);
626 ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200627 if (ret)
628 return ret;
629 }
630
631 return 0;
632}
633
634static int mmc_test_weird_read(struct mmc_test_card *test)
635{
636 int ret, i;
Pierre Ossman6b174932008-06-30 09:09:27 +0200637 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200638
639 if (!test->card->csd.read_partial)
640 return RESULT_UNSUP_CARD;
641
642 for (i = 3; i < 512;i += 7) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200643 sg_init_one(&sg, test->buffer, i);
644 ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200645 if (ret)
646 return ret;
647 }
648
649 return 0;
650}
651
652static int mmc_test_align_write(struct mmc_test_card *test)
653{
654 int ret, i;
Pierre Ossman6b174932008-06-30 09:09:27 +0200655 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200656
657 for (i = 1;i < 4;i++) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200658 sg_init_one(&sg, test->buffer + i, 512);
659 ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200660 if (ret)
661 return ret;
662 }
663
664 return 0;
665}
666
667static int mmc_test_align_read(struct mmc_test_card *test)
668{
669 int ret, i;
Pierre Ossman6b174932008-06-30 09:09:27 +0200670 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200671
672 for (i = 1;i < 4;i++) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200673 sg_init_one(&sg, test->buffer + i, 512);
674 ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200675 if (ret)
676 return ret;
677 }
678
679 return 0;
680}
681
682static int mmc_test_align_multi_write(struct mmc_test_card *test)
683{
684 int ret, i;
685 unsigned int size;
Pierre Ossman6b174932008-06-30 09:09:27 +0200686 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200687
688 if (test->card->host->max_blk_count == 1)
689 return RESULT_UNSUP_HOST;
690
691 size = PAGE_SIZE * 2;
692 size = min(size, test->card->host->max_req_size);
693 size = min(size, test->card->host->max_seg_size);
694 size = min(size, test->card->host->max_blk_count * 512);
695
696 if (size < 1024)
697 return RESULT_UNSUP_HOST;
698
699 for (i = 1;i < 4;i++) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200700 sg_init_one(&sg, test->buffer + i, size);
701 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200702 if (ret)
703 return ret;
704 }
705
706 return 0;
707}
708
709static int mmc_test_align_multi_read(struct mmc_test_card *test)
710{
711 int ret, i;
712 unsigned int size;
Pierre Ossman6b174932008-06-30 09:09:27 +0200713 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200714
715 if (test->card->host->max_blk_count == 1)
716 return RESULT_UNSUP_HOST;
717
718 size = PAGE_SIZE * 2;
719 size = min(size, test->card->host->max_req_size);
720 size = min(size, test->card->host->max_seg_size);
721 size = min(size, test->card->host->max_blk_count * 512);
722
723 if (size < 1024)
724 return RESULT_UNSUP_HOST;
725
726 for (i = 1;i < 4;i++) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200727 sg_init_one(&sg, test->buffer + i, size);
728 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200729 if (ret)
730 return ret;
731 }
732
733 return 0;
734}
735
736static int mmc_test_xfersize_write(struct mmc_test_card *test)
737{
738 int ret;
739
740 ret = mmc_test_set_blksize(test, 512);
741 if (ret)
742 return ret;
743
Pierre Ossman6b174932008-06-30 09:09:27 +0200744 ret = mmc_test_broken_transfer(test, 1, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200745 if (ret)
746 return ret;
747
748 return 0;
749}
750
751static int mmc_test_xfersize_read(struct mmc_test_card *test)
752{
753 int ret;
754
755 ret = mmc_test_set_blksize(test, 512);
756 if (ret)
757 return ret;
758
Pierre Ossman6b174932008-06-30 09:09:27 +0200759 ret = mmc_test_broken_transfer(test, 1, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200760 if (ret)
761 return ret;
762
763 return 0;
764}
765
766static int mmc_test_multi_xfersize_write(struct mmc_test_card *test)
767{
768 int ret;
769
770 if (test->card->host->max_blk_count == 1)
771 return RESULT_UNSUP_HOST;
772
773 ret = mmc_test_set_blksize(test, 512);
774 if (ret)
775 return ret;
776
Pierre Ossman6b174932008-06-30 09:09:27 +0200777 ret = mmc_test_broken_transfer(test, 2, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200778 if (ret)
779 return ret;
780
781 return 0;
782}
783
784static int mmc_test_multi_xfersize_read(struct mmc_test_card *test)
785{
786 int ret;
787
788 if (test->card->host->max_blk_count == 1)
789 return RESULT_UNSUP_HOST;
790
791 ret = mmc_test_set_blksize(test, 512);
792 if (ret)
793 return ret;
794
Pierre Ossman6b174932008-06-30 09:09:27 +0200795 ret = mmc_test_broken_transfer(test, 2, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200796 if (ret)
797 return ret;
798
799 return 0;
800}
801
802static const struct mmc_test_case mmc_test_cases[] = {
803 {
804 .name = "Basic write (no data verification)",
805 .run = mmc_test_basic_write,
806 },
807
808 {
809 .name = "Basic read (no data verification)",
810 .run = mmc_test_basic_read,
811 },
812
813 {
814 .name = "Basic write (with data verification)",
Pierre Ossman6b174932008-06-30 09:09:27 +0200815 .prepare = mmc_test_prepare_write,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200816 .run = mmc_test_verify_write,
Pierre Ossman6b174932008-06-30 09:09:27 +0200817 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200818 },
819
820 {
821 .name = "Basic read (with data verification)",
Pierre Ossman6b174932008-06-30 09:09:27 +0200822 .prepare = mmc_test_prepare_read,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200823 .run = mmc_test_verify_read,
Pierre Ossman6b174932008-06-30 09:09:27 +0200824 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200825 },
826
827 {
828 .name = "Multi-block write",
Pierre Ossman6b174932008-06-30 09:09:27 +0200829 .prepare = mmc_test_prepare_write,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200830 .run = mmc_test_multi_write,
Pierre Ossman6b174932008-06-30 09:09:27 +0200831 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200832 },
833
834 {
835 .name = "Multi-block read",
Pierre Ossman6b174932008-06-30 09:09:27 +0200836 .prepare = mmc_test_prepare_read,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200837 .run = mmc_test_multi_read,
Pierre Ossman6b174932008-06-30 09:09:27 +0200838 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200839 },
840
841 {
842 .name = "Power of two block writes",
Pierre Ossman6b174932008-06-30 09:09:27 +0200843 .prepare = mmc_test_prepare_write,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200844 .run = mmc_test_pow2_write,
Pierre Ossman6b174932008-06-30 09:09:27 +0200845 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200846 },
847
848 {
849 .name = "Power of two block reads",
Pierre Ossman6b174932008-06-30 09:09:27 +0200850 .prepare = mmc_test_prepare_read,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200851 .run = mmc_test_pow2_read,
Pierre Ossman6b174932008-06-30 09:09:27 +0200852 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200853 },
854
855 {
856 .name = "Weird sized block writes",
Pierre Ossman6b174932008-06-30 09:09:27 +0200857 .prepare = mmc_test_prepare_write,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200858 .run = mmc_test_weird_write,
Pierre Ossman6b174932008-06-30 09:09:27 +0200859 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200860 },
861
862 {
863 .name = "Weird sized block reads",
Pierre Ossman6b174932008-06-30 09:09:27 +0200864 .prepare = mmc_test_prepare_read,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200865 .run = mmc_test_weird_read,
Pierre Ossman6b174932008-06-30 09:09:27 +0200866 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200867 },
868
869 {
870 .name = "Badly aligned write",
Pierre Ossman6b174932008-06-30 09:09:27 +0200871 .prepare = mmc_test_prepare_write,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200872 .run = mmc_test_align_write,
Pierre Ossman6b174932008-06-30 09:09:27 +0200873 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200874 },
875
876 {
877 .name = "Badly aligned read",
Pierre Ossman6b174932008-06-30 09:09:27 +0200878 .prepare = mmc_test_prepare_read,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200879 .run = mmc_test_align_read,
Pierre Ossman6b174932008-06-30 09:09:27 +0200880 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200881 },
882
883 {
884 .name = "Badly aligned multi-block write",
Pierre Ossman6b174932008-06-30 09:09:27 +0200885 .prepare = mmc_test_prepare_write,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200886 .run = mmc_test_align_multi_write,
Pierre Ossman6b174932008-06-30 09:09:27 +0200887 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200888 },
889
890 {
891 .name = "Badly aligned multi-block read",
Pierre Ossman6b174932008-06-30 09:09:27 +0200892 .prepare = mmc_test_prepare_read,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200893 .run = mmc_test_align_multi_read,
Pierre Ossman6b174932008-06-30 09:09:27 +0200894 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200895 },
896
897 {
898 .name = "Correct xfer_size at write (start failure)",
899 .run = mmc_test_xfersize_write,
900 },
901
902 {
903 .name = "Correct xfer_size at read (start failure)",
904 .run = mmc_test_xfersize_read,
905 },
906
907 {
908 .name = "Correct xfer_size at write (midway failure)",
909 .run = mmc_test_multi_xfersize_write,
910 },
911
912 {
913 .name = "Correct xfer_size at read (midway failure)",
914 .run = mmc_test_multi_xfersize_read,
915 },
916};
917
918static struct mutex mmc_test_lock;
919
Pierre Ossmanfd8c3262008-05-24 22:36:31 +0200920static void mmc_test_run(struct mmc_test_card *test, int testcase)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200921{
922 int i, ret;
923
924 printk(KERN_INFO "%s: Starting tests of card %s...\n",
925 mmc_hostname(test->card->host), mmc_card_id(test->card));
926
927 mmc_claim_host(test->card->host);
928
929 for (i = 0;i < ARRAY_SIZE(mmc_test_cases);i++) {
Pierre Ossmanfd8c3262008-05-24 22:36:31 +0200930 if (testcase && ((i + 1) != testcase))
931 continue;
932
Pierre Ossman88ae6002007-08-12 14:23:50 +0200933 printk(KERN_INFO "%s: Test case %d. %s...\n",
934 mmc_hostname(test->card->host), i + 1,
935 mmc_test_cases[i].name);
936
937 if (mmc_test_cases[i].prepare) {
938 ret = mmc_test_cases[i].prepare(test);
939 if (ret) {
940 printk(KERN_INFO "%s: Result: Prepare "
941 "stage failed! (%d)\n",
942 mmc_hostname(test->card->host),
943 ret);
944 continue;
945 }
946 }
947
948 ret = mmc_test_cases[i].run(test);
949 switch (ret) {
950 case RESULT_OK:
951 printk(KERN_INFO "%s: Result: OK\n",
952 mmc_hostname(test->card->host));
953 break;
954 case RESULT_FAIL:
955 printk(KERN_INFO "%s: Result: FAILED\n",
956 mmc_hostname(test->card->host));
957 break;
958 case RESULT_UNSUP_HOST:
959 printk(KERN_INFO "%s: Result: UNSUPPORTED "
960 "(by host)\n",
961 mmc_hostname(test->card->host));
962 break;
963 case RESULT_UNSUP_CARD:
964 printk(KERN_INFO "%s: Result: UNSUPPORTED "
965 "(by card)\n",
966 mmc_hostname(test->card->host));
967 break;
968 default:
969 printk(KERN_INFO "%s: Result: ERROR (%d)\n",
970 mmc_hostname(test->card->host), ret);
971 }
972
973 if (mmc_test_cases[i].cleanup) {
974 ret = mmc_test_cases[i].cleanup(test);
975 if (ret) {
976 printk(KERN_INFO "%s: Warning: Cleanup "
977 "stage failed! (%d)\n",
978 mmc_hostname(test->card->host),
979 ret);
980 }
981 }
982 }
983
984 mmc_release_host(test->card->host);
985
986 printk(KERN_INFO "%s: Tests completed.\n",
987 mmc_hostname(test->card->host));
988}
989
990static ssize_t mmc_test_show(struct device *dev,
991 struct device_attribute *attr, char *buf)
992{
993 mutex_lock(&mmc_test_lock);
994 mutex_unlock(&mmc_test_lock);
995
996 return 0;
997}
998
999static ssize_t mmc_test_store(struct device *dev,
1000 struct device_attribute *attr, const char *buf, size_t count)
1001{
1002 struct mmc_card *card;
1003 struct mmc_test_card *test;
Pierre Ossmanfd8c3262008-05-24 22:36:31 +02001004 int testcase;
Pierre Ossman88ae6002007-08-12 14:23:50 +02001005
1006 card = container_of(dev, struct mmc_card, dev);
1007
Pierre Ossmanfd8c3262008-05-24 22:36:31 +02001008 testcase = simple_strtol(buf, NULL, 10);
1009
Pierre Ossman88ae6002007-08-12 14:23:50 +02001010 test = kzalloc(sizeof(struct mmc_test_card), GFP_KERNEL);
1011 if (!test)
1012 return -ENOMEM;
1013
1014 test->card = card;
1015
1016 test->buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL);
1017 if (test->buffer) {
1018 mutex_lock(&mmc_test_lock);
Pierre Ossmanfd8c3262008-05-24 22:36:31 +02001019 mmc_test_run(test, testcase);
Pierre Ossman88ae6002007-08-12 14:23:50 +02001020 mutex_unlock(&mmc_test_lock);
1021 }
1022
1023 kfree(test->buffer);
1024 kfree(test);
1025
1026 return count;
1027}
1028
1029static DEVICE_ATTR(test, S_IWUSR | S_IRUGO, mmc_test_show, mmc_test_store);
1030
1031static int mmc_test_probe(struct mmc_card *card)
1032{
1033 int ret;
1034
Pierre Ossman0121a982008-06-28 17:51:27 +02001035 if ((card->type != MMC_TYPE_MMC) && (card->type != MMC_TYPE_SD))
1036 return -ENODEV;
1037
Pierre Ossman88ae6002007-08-12 14:23:50 +02001038 mutex_init(&mmc_test_lock);
1039
1040 ret = device_create_file(&card->dev, &dev_attr_test);
1041 if (ret)
1042 return ret;
1043
1044 return 0;
1045}
1046
1047static void mmc_test_remove(struct mmc_card *card)
1048{
1049 device_remove_file(&card->dev, &dev_attr_test);
1050}
1051
1052static struct mmc_driver mmc_driver = {
1053 .drv = {
1054 .name = "mmc_test",
1055 },
1056 .probe = mmc_test_probe,
1057 .remove = mmc_test_remove,
1058};
1059
1060static int __init mmc_test_init(void)
1061{
1062 return mmc_register_driver(&mmc_driver);
1063}
1064
1065static void __exit mmc_test_exit(void)
1066{
1067 mmc_unregister_driver(&mmc_driver);
1068}
1069
1070module_init(mmc_test_init);
1071module_exit(mmc_test_exit);
1072
1073MODULE_LICENSE("GPL");
1074MODULE_DESCRIPTION("Multimedia Card (MMC) host test driver");
1075MODULE_AUTHOR("Pierre Ossman");