blob: e7f8027165e697b3f2a1ef3926f2ce0b3e2153f1 [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
Pierre Ossman26610812008-07-04 18:17:13 +020024#define BUFFER_ORDER 2
25#define BUFFER_SIZE (PAGE_SIZE << BUFFER_ORDER)
Pierre Ossman88ae6002007-08-12 14:23:50 +020026
27struct mmc_test_card {
28 struct mmc_card *card;
29
Pierre Ossman6b174932008-06-30 09:09:27 +020030 u8 scratch[BUFFER_SIZE];
Pierre Ossman88ae6002007-08-12 14:23:50 +020031 u8 *buffer;
Pierre Ossman26610812008-07-04 18:17:13 +020032#ifdef CONFIG_HIGHMEM
33 struct page *highmem;
34#endif
Pierre Ossman88ae6002007-08-12 14:23:50 +020035};
36
37/*******************************************************************/
Pierre Ossman6b174932008-06-30 09:09:27 +020038/* General helper functions */
Pierre Ossman88ae6002007-08-12 14:23:50 +020039/*******************************************************************/
40
Pierre Ossman6b174932008-06-30 09:09:27 +020041/*
42 * Configure correct block size in card
43 */
Pierre Ossman88ae6002007-08-12 14:23:50 +020044static int mmc_test_set_blksize(struct mmc_test_card *test, unsigned size)
45{
46 struct mmc_command cmd;
47 int ret;
48
49 cmd.opcode = MMC_SET_BLOCKLEN;
50 cmd.arg = size;
51 cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
52 ret = mmc_wait_for_cmd(test->card->host, &cmd, 0);
53 if (ret)
54 return ret;
55
56 return 0;
57}
58
Pierre Ossman6b174932008-06-30 09:09:27 +020059/*
60 * Fill in the mmc_request structure given a set of transfer parameters.
61 */
62static void mmc_test_prepare_mrq(struct mmc_test_card *test,
63 struct mmc_request *mrq, struct scatterlist *sg, unsigned sg_len,
64 unsigned dev_addr, unsigned blocks, unsigned blksz, int write)
65{
66 BUG_ON(!mrq || !mrq->cmd || !mrq->data || !mrq->stop);
67
68 if (blocks > 1) {
69 mrq->cmd->opcode = write ?
70 MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK;
71 } else {
72 mrq->cmd->opcode = write ?
73 MMC_WRITE_BLOCK : MMC_READ_SINGLE_BLOCK;
74 }
75
76 mrq->cmd->arg = dev_addr;
Johan Kristellc286d032010-02-10 13:56:34 -080077 if (!mmc_card_blockaddr(test->card))
78 mrq->cmd->arg <<= 9;
79
Pierre Ossman6b174932008-06-30 09:09:27 +020080 mrq->cmd->flags = MMC_RSP_R1 | MMC_CMD_ADTC;
81
82 if (blocks == 1)
83 mrq->stop = NULL;
84 else {
85 mrq->stop->opcode = MMC_STOP_TRANSMISSION;
86 mrq->stop->arg = 0;
87 mrq->stop->flags = MMC_RSP_R1B | MMC_CMD_AC;
88 }
89
90 mrq->data->blksz = blksz;
91 mrq->data->blocks = blocks;
92 mrq->data->flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
93 mrq->data->sg = sg;
94 mrq->data->sg_len = sg_len;
95
96 mmc_set_data_timeout(mrq->data, test->card);
97}
98
99/*
100 * Wait for the card to finish the busy state
101 */
102static int mmc_test_wait_busy(struct mmc_test_card *test)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200103{
104 int ret, busy;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200105 struct mmc_command cmd;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200106
107 busy = 0;
108 do {
Pierre Ossman88ae6002007-08-12 14:23:50 +0200109 memset(&cmd, 0, sizeof(struct mmc_command));
110
111 cmd.opcode = MMC_SEND_STATUS;
112 cmd.arg = test->card->rca << 16;
113 cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
114
Pierre Ossman6b174932008-06-30 09:09:27 +0200115 ret = mmc_wait_for_cmd(test->card->host, &cmd, 0);
116 if (ret)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200117 break;
118
119 if (!busy && !(cmd.resp[0] & R1_READY_FOR_DATA)) {
120 busy = 1;
121 printk(KERN_INFO "%s: Warning: Host did not "
122 "wait for busy state to end.\n",
123 mmc_hostname(test->card->host));
124 }
125 } while (!(cmd.resp[0] & R1_READY_FOR_DATA));
126
127 return ret;
128}
129
Pierre Ossman6b174932008-06-30 09:09:27 +0200130/*
131 * Transfer a single sector of kernel addressable data
132 */
133static int mmc_test_buffer_transfer(struct mmc_test_card *test,
134 u8 *buffer, unsigned addr, unsigned blksz, int write)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200135{
Pierre Ossman6b174932008-06-30 09:09:27 +0200136 int ret;
137
138 struct mmc_request mrq;
139 struct mmc_command cmd;
140 struct mmc_command stop;
141 struct mmc_data data;
142
143 struct scatterlist sg;
144
145 memset(&mrq, 0, sizeof(struct mmc_request));
146 memset(&cmd, 0, sizeof(struct mmc_command));
147 memset(&data, 0, sizeof(struct mmc_data));
148 memset(&stop, 0, sizeof(struct mmc_command));
149
150 mrq.cmd = &cmd;
151 mrq.data = &data;
152 mrq.stop = &stop;
153
154 sg_init_one(&sg, buffer, blksz);
155
156 mmc_test_prepare_mrq(test, &mrq, &sg, 1, addr, 1, blksz, write);
157
158 mmc_wait_for_req(test->card->host, &mrq);
159
160 if (cmd.error)
161 return cmd.error;
162 if (data.error)
163 return data.error;
164
165 ret = mmc_test_wait_busy(test);
166 if (ret)
167 return ret;
168
169 return 0;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200170}
171
Pierre Ossman6b174932008-06-30 09:09:27 +0200172/*******************************************************************/
173/* Test preparation and cleanup */
174/*******************************************************************/
175
176/*
177 * Fill the first couple of sectors of the card with known data
178 * so that bad reads/writes can be detected
179 */
180static int __mmc_test_prepare(struct mmc_test_card *test, int write)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200181{
182 int ret, i;
183
184 ret = mmc_test_set_blksize(test, 512);
185 if (ret)
186 return ret;
187
188 if (write)
Pierre Ossman6b174932008-06-30 09:09:27 +0200189 memset(test->buffer, 0xDF, 512);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200190 else {
Pierre Ossman6b174932008-06-30 09:09:27 +0200191 for (i = 0;i < 512;i++)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200192 test->buffer[i] = i;
193 }
194
195 for (i = 0;i < BUFFER_SIZE / 512;i++) {
Johan Kristellc286d032010-02-10 13:56:34 -0800196 ret = mmc_test_buffer_transfer(test, test->buffer, i, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200197 if (ret)
198 return ret;
199 }
200
201 return 0;
202}
203
Pierre Ossman6b174932008-06-30 09:09:27 +0200204static int mmc_test_prepare_write(struct mmc_test_card *test)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200205{
Pierre Ossman6b174932008-06-30 09:09:27 +0200206 return __mmc_test_prepare(test, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200207}
208
Pierre Ossman6b174932008-06-30 09:09:27 +0200209static int mmc_test_prepare_read(struct mmc_test_card *test)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200210{
Pierre Ossman6b174932008-06-30 09:09:27 +0200211 return __mmc_test_prepare(test, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200212}
213
Pierre Ossman6b174932008-06-30 09:09:27 +0200214static int mmc_test_cleanup(struct mmc_test_card *test)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200215{
Pierre Ossman6b174932008-06-30 09:09:27 +0200216 int ret, i;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200217
Pierre Ossman6b174932008-06-30 09:09:27 +0200218 ret = mmc_test_set_blksize(test, 512);
219 if (ret)
220 return ret;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200221
Pierre Ossman6b174932008-06-30 09:09:27 +0200222 memset(test->buffer, 0, 512);
223
224 for (i = 0;i < BUFFER_SIZE / 512;i++) {
Johan Kristellc286d032010-02-10 13:56:34 -0800225 ret = mmc_test_buffer_transfer(test, test->buffer, i, 512, 1);
Pierre Ossman6b174932008-06-30 09:09:27 +0200226 if (ret)
227 return ret;
228 }
229
230 return 0;
231}
232
233/*******************************************************************/
234/* Test execution helpers */
235/*******************************************************************/
236
237/*
238 * Modifies the mmc_request to perform the "short transfer" tests
239 */
240static void mmc_test_prepare_broken_mrq(struct mmc_test_card *test,
241 struct mmc_request *mrq, int write)
242{
243 BUG_ON(!mrq || !mrq->cmd || !mrq->data);
244
245 if (mrq->data->blocks > 1) {
246 mrq->cmd->opcode = write ?
247 MMC_WRITE_BLOCK : MMC_READ_SINGLE_BLOCK;
248 mrq->stop = NULL;
249 } else {
250 mrq->cmd->opcode = MMC_SEND_STATUS;
251 mrq->cmd->arg = test->card->rca << 16;
252 }
253}
254
255/*
256 * Checks that a normal transfer didn't have any errors
257 */
258static int mmc_test_check_result(struct mmc_test_card *test,
259 struct mmc_request *mrq)
260{
261 int ret;
262
263 BUG_ON(!mrq || !mrq->cmd || !mrq->data);
264
265 ret = 0;
266
267 if (!ret && mrq->cmd->error)
268 ret = mrq->cmd->error;
269 if (!ret && mrq->data->error)
270 ret = mrq->data->error;
271 if (!ret && mrq->stop && mrq->stop->error)
272 ret = mrq->stop->error;
273 if (!ret && mrq->data->bytes_xfered !=
274 mrq->data->blocks * mrq->data->blksz)
275 ret = RESULT_FAIL;
276
277 if (ret == -EINVAL)
278 ret = RESULT_UNSUP_HOST;
279
280 return ret;
281}
282
283/*
284 * Checks that a "short transfer" behaved as expected
285 */
286static int mmc_test_check_broken_result(struct mmc_test_card *test,
287 struct mmc_request *mrq)
288{
289 int ret;
290
291 BUG_ON(!mrq || !mrq->cmd || !mrq->data);
292
293 ret = 0;
294
295 if (!ret && mrq->cmd->error)
296 ret = mrq->cmd->error;
297 if (!ret && mrq->data->error == 0)
298 ret = RESULT_FAIL;
299 if (!ret && mrq->data->error != -ETIMEDOUT)
300 ret = mrq->data->error;
301 if (!ret && mrq->stop && mrq->stop->error)
302 ret = mrq->stop->error;
303 if (mrq->data->blocks > 1) {
304 if (!ret && mrq->data->bytes_xfered > mrq->data->blksz)
305 ret = RESULT_FAIL;
306 } else {
307 if (!ret && mrq->data->bytes_xfered > 0)
308 ret = RESULT_FAIL;
309 }
310
311 if (ret == -EINVAL)
312 ret = RESULT_UNSUP_HOST;
313
314 return ret;
315}
316
317/*
318 * Tests a basic transfer with certain parameters
319 */
320static int mmc_test_simple_transfer(struct mmc_test_card *test,
321 struct scatterlist *sg, unsigned sg_len, unsigned dev_addr,
322 unsigned blocks, unsigned blksz, int write)
323{
324 struct mmc_request mrq;
325 struct mmc_command cmd;
326 struct mmc_command stop;
327 struct mmc_data data;
328
329 memset(&mrq, 0, sizeof(struct mmc_request));
330 memset(&cmd, 0, sizeof(struct mmc_command));
331 memset(&data, 0, sizeof(struct mmc_data));
332 memset(&stop, 0, sizeof(struct mmc_command));
333
334 mrq.cmd = &cmd;
335 mrq.data = &data;
336 mrq.stop = &stop;
337
338 mmc_test_prepare_mrq(test, &mrq, sg, sg_len, dev_addr,
339 blocks, blksz, write);
340
341 mmc_wait_for_req(test->card->host, &mrq);
342
343 mmc_test_wait_busy(test);
344
345 return mmc_test_check_result(test, &mrq);
346}
347
348/*
349 * Tests a transfer where the card will fail completely or partly
350 */
351static int mmc_test_broken_transfer(struct mmc_test_card *test,
352 unsigned blocks, unsigned blksz, int write)
353{
354 struct mmc_request mrq;
355 struct mmc_command cmd;
356 struct mmc_command stop;
357 struct mmc_data data;
358
359 struct scatterlist sg;
360
361 memset(&mrq, 0, sizeof(struct mmc_request));
362 memset(&cmd, 0, sizeof(struct mmc_command));
363 memset(&data, 0, sizeof(struct mmc_data));
364 memset(&stop, 0, sizeof(struct mmc_command));
365
366 mrq.cmd = &cmd;
367 mrq.data = &data;
368 mrq.stop = &stop;
369
370 sg_init_one(&sg, test->buffer, blocks * blksz);
371
372 mmc_test_prepare_mrq(test, &mrq, &sg, 1, 0, blocks, blksz, write);
373 mmc_test_prepare_broken_mrq(test, &mrq, write);
374
375 mmc_wait_for_req(test->card->host, &mrq);
376
377 mmc_test_wait_busy(test);
378
379 return mmc_test_check_broken_result(test, &mrq);
380}
381
382/*
383 * Does a complete transfer test where data is also validated
384 *
385 * Note: mmc_test_prepare() must have been done before this call
386 */
387static int mmc_test_transfer(struct mmc_test_card *test,
388 struct scatterlist *sg, unsigned sg_len, unsigned dev_addr,
389 unsigned blocks, unsigned blksz, int write)
390{
391 int ret, i;
392 unsigned long flags;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200393
394 if (write) {
395 for (i = 0;i < blocks * blksz;i++)
Pierre Ossman6b174932008-06-30 09:09:27 +0200396 test->scratch[i] = i;
397 } else {
Pierre Ossmanb7ac2cf2008-07-29 01:05:22 +0200398 memset(test->scratch, 0, BUFFER_SIZE);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200399 }
Pierre Ossman6b174932008-06-30 09:09:27 +0200400 local_irq_save(flags);
Pierre Ossmanb7ac2cf2008-07-29 01:05:22 +0200401 sg_copy_from_buffer(sg, sg_len, test->scratch, BUFFER_SIZE);
Pierre Ossman6b174932008-06-30 09:09:27 +0200402 local_irq_restore(flags);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200403
404 ret = mmc_test_set_blksize(test, blksz);
405 if (ret)
406 return ret;
407
Pierre Ossman6b174932008-06-30 09:09:27 +0200408 ret = mmc_test_simple_transfer(test, sg, sg_len, dev_addr,
409 blocks, blksz, write);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200410 if (ret)
411 return ret;
412
413 if (write) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200414 int sectors;
415
Pierre Ossman88ae6002007-08-12 14:23:50 +0200416 ret = mmc_test_set_blksize(test, 512);
417 if (ret)
418 return ret;
419
420 sectors = (blocks * blksz + 511) / 512;
421 if ((sectors * 512) == (blocks * blksz))
422 sectors++;
423
424 if ((sectors * 512) > BUFFER_SIZE)
425 return -EINVAL;
426
427 memset(test->buffer, 0, sectors * 512);
428
429 for (i = 0;i < sectors;i++) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200430 ret = mmc_test_buffer_transfer(test,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200431 test->buffer + i * 512,
Johan Kristellc286d032010-02-10 13:56:34 -0800432 dev_addr + i, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200433 if (ret)
434 return ret;
435 }
436
437 for (i = 0;i < blocks * blksz;i++) {
438 if (test->buffer[i] != (u8)i)
439 return RESULT_FAIL;
440 }
441
442 for (;i < sectors * 512;i++) {
443 if (test->buffer[i] != 0xDF)
444 return RESULT_FAIL;
445 }
446 } else {
Pierre Ossman6b174932008-06-30 09:09:27 +0200447 local_irq_save(flags);
Pierre Ossmanb7ac2cf2008-07-29 01:05:22 +0200448 sg_copy_to_buffer(sg, sg_len, test->scratch, BUFFER_SIZE);
Pierre Ossman6b174932008-06-30 09:09:27 +0200449 local_irq_restore(flags);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200450 for (i = 0;i < blocks * blksz;i++) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200451 if (test->scratch[i] != (u8)i)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200452 return RESULT_FAIL;
453 }
454 }
455
456 return 0;
457}
458
Pierre Ossman88ae6002007-08-12 14:23:50 +0200459/*******************************************************************/
460/* Tests */
461/*******************************************************************/
462
463struct mmc_test_case {
464 const char *name;
465
466 int (*prepare)(struct mmc_test_card *);
467 int (*run)(struct mmc_test_card *);
468 int (*cleanup)(struct mmc_test_card *);
469};
470
471static int mmc_test_basic_write(struct mmc_test_card *test)
472{
473 int ret;
Pierre Ossman6b174932008-06-30 09:09:27 +0200474 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200475
476 ret = mmc_test_set_blksize(test, 512);
477 if (ret)
478 return ret;
479
Pierre Ossman6b174932008-06-30 09:09:27 +0200480 sg_init_one(&sg, test->buffer, 512);
481
482 ret = mmc_test_simple_transfer(test, &sg, 1, 0, 1, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200483 if (ret)
484 return ret;
485
486 return 0;
487}
488
489static int mmc_test_basic_read(struct mmc_test_card *test)
490{
491 int ret;
Pierre Ossman6b174932008-06-30 09:09:27 +0200492 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200493
494 ret = mmc_test_set_blksize(test, 512);
495 if (ret)
496 return ret;
497
Pierre Ossman6b174932008-06-30 09:09:27 +0200498 sg_init_one(&sg, test->buffer, 512);
499
Rabin Vincent58a5dd32009-02-13 22:55:26 +0530500 ret = mmc_test_simple_transfer(test, &sg, 1, 0, 1, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200501 if (ret)
502 return ret;
503
504 return 0;
505}
506
507static int mmc_test_verify_write(struct mmc_test_card *test)
508{
509 int ret;
Pierre Ossman6b174932008-06-30 09:09:27 +0200510 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200511
Pierre Ossman6b174932008-06-30 09:09:27 +0200512 sg_init_one(&sg, test->buffer, 512);
513
514 ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200515 if (ret)
516 return ret;
517
518 return 0;
519}
520
521static int mmc_test_verify_read(struct mmc_test_card *test)
522{
523 int ret;
Pierre Ossman6b174932008-06-30 09:09:27 +0200524 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200525
Pierre Ossman6b174932008-06-30 09:09:27 +0200526 sg_init_one(&sg, test->buffer, 512);
527
528 ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200529 if (ret)
530 return ret;
531
532 return 0;
533}
534
535static int mmc_test_multi_write(struct mmc_test_card *test)
536{
537 int ret;
538 unsigned int size;
Pierre Ossman6b174932008-06-30 09:09:27 +0200539 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200540
541 if (test->card->host->max_blk_count == 1)
542 return RESULT_UNSUP_HOST;
543
544 size = PAGE_SIZE * 2;
545 size = min(size, test->card->host->max_req_size);
546 size = min(size, test->card->host->max_seg_size);
547 size = min(size, test->card->host->max_blk_count * 512);
548
549 if (size < 1024)
550 return RESULT_UNSUP_HOST;
551
Pierre Ossman6b174932008-06-30 09:09:27 +0200552 sg_init_one(&sg, test->buffer, size);
553
554 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200555 if (ret)
556 return ret;
557
558 return 0;
559}
560
561static int mmc_test_multi_read(struct mmc_test_card *test)
562{
563 int ret;
564 unsigned int size;
Pierre Ossman6b174932008-06-30 09:09:27 +0200565 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200566
567 if (test->card->host->max_blk_count == 1)
568 return RESULT_UNSUP_HOST;
569
570 size = PAGE_SIZE * 2;
571 size = min(size, test->card->host->max_req_size);
572 size = min(size, test->card->host->max_seg_size);
573 size = min(size, test->card->host->max_blk_count * 512);
574
575 if (size < 1024)
576 return RESULT_UNSUP_HOST;
577
Pierre Ossman6b174932008-06-30 09:09:27 +0200578 sg_init_one(&sg, test->buffer, size);
579
580 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200581 if (ret)
582 return ret;
583
584 return 0;
585}
586
587static int mmc_test_pow2_write(struct mmc_test_card *test)
588{
589 int ret, i;
Pierre Ossman6b174932008-06-30 09:09:27 +0200590 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200591
592 if (!test->card->csd.write_partial)
593 return RESULT_UNSUP_CARD;
594
595 for (i = 1; i < 512;i <<= 1) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200596 sg_init_one(&sg, test->buffer, i);
597 ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200598 if (ret)
599 return ret;
600 }
601
602 return 0;
603}
604
605static int mmc_test_pow2_read(struct mmc_test_card *test)
606{
607 int ret, i;
Pierre Ossman6b174932008-06-30 09:09:27 +0200608 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200609
610 if (!test->card->csd.read_partial)
611 return RESULT_UNSUP_CARD;
612
613 for (i = 1; i < 512;i <<= 1) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200614 sg_init_one(&sg, test->buffer, i);
615 ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200616 if (ret)
617 return ret;
618 }
619
620 return 0;
621}
622
623static int mmc_test_weird_write(struct mmc_test_card *test)
624{
625 int ret, i;
Pierre Ossman6b174932008-06-30 09:09:27 +0200626 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200627
628 if (!test->card->csd.write_partial)
629 return RESULT_UNSUP_CARD;
630
631 for (i = 3; i < 512;i += 7) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200632 sg_init_one(&sg, test->buffer, i);
633 ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200634 if (ret)
635 return ret;
636 }
637
638 return 0;
639}
640
641static int mmc_test_weird_read(struct mmc_test_card *test)
642{
643 int ret, i;
Pierre Ossman6b174932008-06-30 09:09:27 +0200644 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200645
646 if (!test->card->csd.read_partial)
647 return RESULT_UNSUP_CARD;
648
649 for (i = 3; i < 512;i += 7) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200650 sg_init_one(&sg, test->buffer, i);
651 ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200652 if (ret)
653 return ret;
654 }
655
656 return 0;
657}
658
659static int mmc_test_align_write(struct mmc_test_card *test)
660{
661 int ret, i;
Pierre Ossman6b174932008-06-30 09:09:27 +0200662 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200663
664 for (i = 1;i < 4;i++) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200665 sg_init_one(&sg, test->buffer + i, 512);
666 ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200667 if (ret)
668 return ret;
669 }
670
671 return 0;
672}
673
674static int mmc_test_align_read(struct mmc_test_card *test)
675{
676 int ret, i;
Pierre Ossman6b174932008-06-30 09:09:27 +0200677 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200678
679 for (i = 1;i < 4;i++) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200680 sg_init_one(&sg, test->buffer + i, 512);
681 ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200682 if (ret)
683 return ret;
684 }
685
686 return 0;
687}
688
689static int mmc_test_align_multi_write(struct mmc_test_card *test)
690{
691 int ret, i;
692 unsigned int size;
Pierre Ossman6b174932008-06-30 09:09:27 +0200693 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200694
695 if (test->card->host->max_blk_count == 1)
696 return RESULT_UNSUP_HOST;
697
698 size = PAGE_SIZE * 2;
699 size = min(size, test->card->host->max_req_size);
700 size = min(size, test->card->host->max_seg_size);
701 size = min(size, test->card->host->max_blk_count * 512);
702
703 if (size < 1024)
704 return RESULT_UNSUP_HOST;
705
706 for (i = 1;i < 4;i++) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200707 sg_init_one(&sg, test->buffer + i, size);
708 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200709 if (ret)
710 return ret;
711 }
712
713 return 0;
714}
715
716static int mmc_test_align_multi_read(struct mmc_test_card *test)
717{
718 int ret, i;
719 unsigned int size;
Pierre Ossman6b174932008-06-30 09:09:27 +0200720 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200721
722 if (test->card->host->max_blk_count == 1)
723 return RESULT_UNSUP_HOST;
724
725 size = PAGE_SIZE * 2;
726 size = min(size, test->card->host->max_req_size);
727 size = min(size, test->card->host->max_seg_size);
728 size = min(size, test->card->host->max_blk_count * 512);
729
730 if (size < 1024)
731 return RESULT_UNSUP_HOST;
732
733 for (i = 1;i < 4;i++) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200734 sg_init_one(&sg, test->buffer + i, size);
735 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200736 if (ret)
737 return ret;
738 }
739
740 return 0;
741}
742
743static int mmc_test_xfersize_write(struct mmc_test_card *test)
744{
745 int ret;
746
747 ret = mmc_test_set_blksize(test, 512);
748 if (ret)
749 return ret;
750
Pierre Ossman6b174932008-06-30 09:09:27 +0200751 ret = mmc_test_broken_transfer(test, 1, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200752 if (ret)
753 return ret;
754
755 return 0;
756}
757
758static int mmc_test_xfersize_read(struct mmc_test_card *test)
759{
760 int ret;
761
762 ret = mmc_test_set_blksize(test, 512);
763 if (ret)
764 return ret;
765
Pierre Ossman6b174932008-06-30 09:09:27 +0200766 ret = mmc_test_broken_transfer(test, 1, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200767 if (ret)
768 return ret;
769
770 return 0;
771}
772
773static int mmc_test_multi_xfersize_write(struct mmc_test_card *test)
774{
775 int ret;
776
777 if (test->card->host->max_blk_count == 1)
778 return RESULT_UNSUP_HOST;
779
780 ret = mmc_test_set_blksize(test, 512);
781 if (ret)
782 return ret;
783
Pierre Ossman6b174932008-06-30 09:09:27 +0200784 ret = mmc_test_broken_transfer(test, 2, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200785 if (ret)
786 return ret;
787
788 return 0;
789}
790
791static int mmc_test_multi_xfersize_read(struct mmc_test_card *test)
792{
793 int ret;
794
795 if (test->card->host->max_blk_count == 1)
796 return RESULT_UNSUP_HOST;
797
798 ret = mmc_test_set_blksize(test, 512);
799 if (ret)
800 return ret;
801
Pierre Ossman6b174932008-06-30 09:09:27 +0200802 ret = mmc_test_broken_transfer(test, 2, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200803 if (ret)
804 return ret;
805
806 return 0;
807}
808
Pierre Ossman26610812008-07-04 18:17:13 +0200809#ifdef CONFIG_HIGHMEM
810
811static int mmc_test_write_high(struct mmc_test_card *test)
812{
813 int ret;
814 struct scatterlist sg;
815
816 sg_init_table(&sg, 1);
817 sg_set_page(&sg, test->highmem, 512, 0);
818
819 ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1);
820 if (ret)
821 return ret;
822
823 return 0;
824}
825
826static int mmc_test_read_high(struct mmc_test_card *test)
827{
828 int ret;
829 struct scatterlist sg;
830
831 sg_init_table(&sg, 1);
832 sg_set_page(&sg, test->highmem, 512, 0);
833
834 ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0);
835 if (ret)
836 return ret;
837
838 return 0;
839}
840
841static int mmc_test_multi_write_high(struct mmc_test_card *test)
842{
843 int ret;
844 unsigned int size;
845 struct scatterlist sg;
846
847 if (test->card->host->max_blk_count == 1)
848 return RESULT_UNSUP_HOST;
849
850 size = PAGE_SIZE * 2;
851 size = min(size, test->card->host->max_req_size);
852 size = min(size, test->card->host->max_seg_size);
853 size = min(size, test->card->host->max_blk_count * 512);
854
855 if (size < 1024)
856 return RESULT_UNSUP_HOST;
857
858 sg_init_table(&sg, 1);
859 sg_set_page(&sg, test->highmem, size, 0);
860
861 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
862 if (ret)
863 return ret;
864
865 return 0;
866}
867
868static int mmc_test_multi_read_high(struct mmc_test_card *test)
869{
870 int ret;
871 unsigned int size;
872 struct scatterlist sg;
873
874 if (test->card->host->max_blk_count == 1)
875 return RESULT_UNSUP_HOST;
876
877 size = PAGE_SIZE * 2;
878 size = min(size, test->card->host->max_req_size);
879 size = min(size, test->card->host->max_seg_size);
880 size = min(size, test->card->host->max_blk_count * 512);
881
882 if (size < 1024)
883 return RESULT_UNSUP_HOST;
884
885 sg_init_table(&sg, 1);
886 sg_set_page(&sg, test->highmem, size, 0);
887
888 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
889 if (ret)
890 return ret;
891
892 return 0;
893}
894
895#endif /* CONFIG_HIGHMEM */
896
Pierre Ossman88ae6002007-08-12 14:23:50 +0200897static const struct mmc_test_case mmc_test_cases[] = {
898 {
899 .name = "Basic write (no data verification)",
900 .run = mmc_test_basic_write,
901 },
902
903 {
904 .name = "Basic read (no data verification)",
905 .run = mmc_test_basic_read,
906 },
907
908 {
909 .name = "Basic write (with data verification)",
Pierre Ossman6b174932008-06-30 09:09:27 +0200910 .prepare = mmc_test_prepare_write,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200911 .run = mmc_test_verify_write,
Pierre Ossman6b174932008-06-30 09:09:27 +0200912 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200913 },
914
915 {
916 .name = "Basic read (with data verification)",
Pierre Ossman6b174932008-06-30 09:09:27 +0200917 .prepare = mmc_test_prepare_read,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200918 .run = mmc_test_verify_read,
Pierre Ossman6b174932008-06-30 09:09:27 +0200919 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200920 },
921
922 {
923 .name = "Multi-block write",
Pierre Ossman6b174932008-06-30 09:09:27 +0200924 .prepare = mmc_test_prepare_write,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200925 .run = mmc_test_multi_write,
Pierre Ossman6b174932008-06-30 09:09:27 +0200926 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200927 },
928
929 {
930 .name = "Multi-block read",
Pierre Ossman6b174932008-06-30 09:09:27 +0200931 .prepare = mmc_test_prepare_read,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200932 .run = mmc_test_multi_read,
Pierre Ossman6b174932008-06-30 09:09:27 +0200933 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200934 },
935
936 {
937 .name = "Power of two block writes",
Pierre Ossman6b174932008-06-30 09:09:27 +0200938 .prepare = mmc_test_prepare_write,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200939 .run = mmc_test_pow2_write,
Pierre Ossman6b174932008-06-30 09:09:27 +0200940 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200941 },
942
943 {
944 .name = "Power of two block reads",
Pierre Ossman6b174932008-06-30 09:09:27 +0200945 .prepare = mmc_test_prepare_read,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200946 .run = mmc_test_pow2_read,
Pierre Ossman6b174932008-06-30 09:09:27 +0200947 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200948 },
949
950 {
951 .name = "Weird sized block writes",
Pierre Ossman6b174932008-06-30 09:09:27 +0200952 .prepare = mmc_test_prepare_write,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200953 .run = mmc_test_weird_write,
Pierre Ossman6b174932008-06-30 09:09:27 +0200954 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200955 },
956
957 {
958 .name = "Weird sized block reads",
Pierre Ossman6b174932008-06-30 09:09:27 +0200959 .prepare = mmc_test_prepare_read,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200960 .run = mmc_test_weird_read,
Pierre Ossman6b174932008-06-30 09:09:27 +0200961 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200962 },
963
964 {
965 .name = "Badly aligned write",
Pierre Ossman6b174932008-06-30 09:09:27 +0200966 .prepare = mmc_test_prepare_write,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200967 .run = mmc_test_align_write,
Pierre Ossman6b174932008-06-30 09:09:27 +0200968 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200969 },
970
971 {
972 .name = "Badly aligned read",
Pierre Ossman6b174932008-06-30 09:09:27 +0200973 .prepare = mmc_test_prepare_read,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200974 .run = mmc_test_align_read,
Pierre Ossman6b174932008-06-30 09:09:27 +0200975 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200976 },
977
978 {
979 .name = "Badly aligned multi-block write",
Pierre Ossman6b174932008-06-30 09:09:27 +0200980 .prepare = mmc_test_prepare_write,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200981 .run = mmc_test_align_multi_write,
Pierre Ossman6b174932008-06-30 09:09:27 +0200982 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200983 },
984
985 {
986 .name = "Badly aligned multi-block read",
Pierre Ossman6b174932008-06-30 09:09:27 +0200987 .prepare = mmc_test_prepare_read,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200988 .run = mmc_test_align_multi_read,
Pierre Ossman6b174932008-06-30 09:09:27 +0200989 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200990 },
991
992 {
993 .name = "Correct xfer_size at write (start failure)",
994 .run = mmc_test_xfersize_write,
995 },
996
997 {
998 .name = "Correct xfer_size at read (start failure)",
999 .run = mmc_test_xfersize_read,
1000 },
1001
1002 {
1003 .name = "Correct xfer_size at write (midway failure)",
1004 .run = mmc_test_multi_xfersize_write,
1005 },
1006
1007 {
1008 .name = "Correct xfer_size at read (midway failure)",
1009 .run = mmc_test_multi_xfersize_read,
1010 },
Pierre Ossman26610812008-07-04 18:17:13 +02001011
1012#ifdef CONFIG_HIGHMEM
1013
1014 {
1015 .name = "Highmem write",
1016 .prepare = mmc_test_prepare_write,
1017 .run = mmc_test_write_high,
1018 .cleanup = mmc_test_cleanup,
1019 },
1020
1021 {
1022 .name = "Highmem read",
1023 .prepare = mmc_test_prepare_read,
1024 .run = mmc_test_read_high,
1025 .cleanup = mmc_test_cleanup,
1026 },
1027
1028 {
1029 .name = "Multi-block highmem write",
1030 .prepare = mmc_test_prepare_write,
1031 .run = mmc_test_multi_write_high,
1032 .cleanup = mmc_test_cleanup,
1033 },
1034
1035 {
1036 .name = "Multi-block highmem read",
1037 .prepare = mmc_test_prepare_read,
1038 .run = mmc_test_multi_read_high,
1039 .cleanup = mmc_test_cleanup,
1040 },
1041
1042#endif /* CONFIG_HIGHMEM */
1043
Pierre Ossman88ae6002007-08-12 14:23:50 +02001044};
1045
Akinobu Mitaa6500312008-09-13 19:03:32 +09001046static DEFINE_MUTEX(mmc_test_lock);
Pierre Ossman88ae6002007-08-12 14:23:50 +02001047
Pierre Ossmanfd8c3262008-05-24 22:36:31 +02001048static void mmc_test_run(struct mmc_test_card *test, int testcase)
Pierre Ossman88ae6002007-08-12 14:23:50 +02001049{
1050 int i, ret;
1051
1052 printk(KERN_INFO "%s: Starting tests of card %s...\n",
1053 mmc_hostname(test->card->host), mmc_card_id(test->card));
1054
1055 mmc_claim_host(test->card->host);
1056
1057 for (i = 0;i < ARRAY_SIZE(mmc_test_cases);i++) {
Pierre Ossmanfd8c3262008-05-24 22:36:31 +02001058 if (testcase && ((i + 1) != testcase))
1059 continue;
1060
Pierre Ossman88ae6002007-08-12 14:23:50 +02001061 printk(KERN_INFO "%s: Test case %d. %s...\n",
1062 mmc_hostname(test->card->host), i + 1,
1063 mmc_test_cases[i].name);
1064
1065 if (mmc_test_cases[i].prepare) {
1066 ret = mmc_test_cases[i].prepare(test);
1067 if (ret) {
1068 printk(KERN_INFO "%s: Result: Prepare "
1069 "stage failed! (%d)\n",
1070 mmc_hostname(test->card->host),
1071 ret);
1072 continue;
1073 }
1074 }
1075
1076 ret = mmc_test_cases[i].run(test);
1077 switch (ret) {
1078 case RESULT_OK:
1079 printk(KERN_INFO "%s: Result: OK\n",
1080 mmc_hostname(test->card->host));
1081 break;
1082 case RESULT_FAIL:
1083 printk(KERN_INFO "%s: Result: FAILED\n",
1084 mmc_hostname(test->card->host));
1085 break;
1086 case RESULT_UNSUP_HOST:
1087 printk(KERN_INFO "%s: Result: UNSUPPORTED "
1088 "(by host)\n",
1089 mmc_hostname(test->card->host));
1090 break;
1091 case RESULT_UNSUP_CARD:
1092 printk(KERN_INFO "%s: Result: UNSUPPORTED "
1093 "(by card)\n",
1094 mmc_hostname(test->card->host));
1095 break;
1096 default:
1097 printk(KERN_INFO "%s: Result: ERROR (%d)\n",
1098 mmc_hostname(test->card->host), ret);
1099 }
1100
1101 if (mmc_test_cases[i].cleanup) {
1102 ret = mmc_test_cases[i].cleanup(test);
1103 if (ret) {
1104 printk(KERN_INFO "%s: Warning: Cleanup "
1105 "stage failed! (%d)\n",
1106 mmc_hostname(test->card->host),
1107 ret);
1108 }
1109 }
1110 }
1111
1112 mmc_release_host(test->card->host);
1113
1114 printk(KERN_INFO "%s: Tests completed.\n",
1115 mmc_hostname(test->card->host));
1116}
1117
1118static ssize_t mmc_test_show(struct device *dev,
1119 struct device_attribute *attr, char *buf)
1120{
1121 mutex_lock(&mmc_test_lock);
1122 mutex_unlock(&mmc_test_lock);
1123
1124 return 0;
1125}
1126
1127static ssize_t mmc_test_store(struct device *dev,
1128 struct device_attribute *attr, const char *buf, size_t count)
1129{
1130 struct mmc_card *card;
1131 struct mmc_test_card *test;
Pierre Ossmanfd8c3262008-05-24 22:36:31 +02001132 int testcase;
Pierre Ossman88ae6002007-08-12 14:23:50 +02001133
1134 card = container_of(dev, struct mmc_card, dev);
1135
Pierre Ossmanfd8c3262008-05-24 22:36:31 +02001136 testcase = simple_strtol(buf, NULL, 10);
1137
Pierre Ossman88ae6002007-08-12 14:23:50 +02001138 test = kzalloc(sizeof(struct mmc_test_card), GFP_KERNEL);
1139 if (!test)
1140 return -ENOMEM;
1141
1142 test->card = card;
1143
1144 test->buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL);
Pierre Ossman26610812008-07-04 18:17:13 +02001145#ifdef CONFIG_HIGHMEM
1146 test->highmem = alloc_pages(GFP_KERNEL | __GFP_HIGHMEM, BUFFER_ORDER);
1147#endif
1148
1149#ifdef CONFIG_HIGHMEM
1150 if (test->buffer && test->highmem) {
1151#else
Pierre Ossman88ae6002007-08-12 14:23:50 +02001152 if (test->buffer) {
Pierre Ossman26610812008-07-04 18:17:13 +02001153#endif
Pierre Ossman88ae6002007-08-12 14:23:50 +02001154 mutex_lock(&mmc_test_lock);
Pierre Ossmanfd8c3262008-05-24 22:36:31 +02001155 mmc_test_run(test, testcase);
Pierre Ossman88ae6002007-08-12 14:23:50 +02001156 mutex_unlock(&mmc_test_lock);
1157 }
1158
Pierre Ossman26610812008-07-04 18:17:13 +02001159#ifdef CONFIG_HIGHMEM
1160 __free_pages(test->highmem, BUFFER_ORDER);
1161#endif
Pierre Ossman88ae6002007-08-12 14:23:50 +02001162 kfree(test->buffer);
1163 kfree(test);
1164
1165 return count;
1166}
1167
1168static DEVICE_ATTR(test, S_IWUSR | S_IRUGO, mmc_test_show, mmc_test_store);
1169
1170static int mmc_test_probe(struct mmc_card *card)
1171{
1172 int ret;
1173
Pierre Ossman0121a982008-06-28 17:51:27 +02001174 if ((card->type != MMC_TYPE_MMC) && (card->type != MMC_TYPE_SD))
1175 return -ENODEV;
1176
Pierre Ossman88ae6002007-08-12 14:23:50 +02001177 ret = device_create_file(&card->dev, &dev_attr_test);
1178 if (ret)
1179 return ret;
1180
Pierre Ossman60c9c7b2008-07-22 14:38:35 +02001181 dev_info(&card->dev, "Card claimed for testing.\n");
1182
Pierre Ossman88ae6002007-08-12 14:23:50 +02001183 return 0;
1184}
1185
1186static void mmc_test_remove(struct mmc_card *card)
1187{
1188 device_remove_file(&card->dev, &dev_attr_test);
1189}
1190
1191static struct mmc_driver mmc_driver = {
1192 .drv = {
1193 .name = "mmc_test",
1194 },
1195 .probe = mmc_test_probe,
1196 .remove = mmc_test_remove,
1197};
1198
1199static int __init mmc_test_init(void)
1200{
1201 return mmc_register_driver(&mmc_driver);
1202}
1203
1204static void __exit mmc_test_exit(void)
1205{
1206 mmc_unregister_driver(&mmc_driver);
1207}
1208
1209module_init(mmc_test_init);
1210module_exit(mmc_test_exit);
1211
1212MODULE_LICENSE("GPL");
1213MODULE_DESCRIPTION("Multimedia Card (MMC) host test driver");
1214MODULE_AUTHOR("Pierre Ossman");