blob: 445d7db2277e4c91fbf9770cff6d1b04ddc76a5a [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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090016#include <linux/slab.h>
Pierre Ossman88ae6002007-08-12 14:23:50 +020017
18#include <linux/scatterlist.h>
19
20#define RESULT_OK 0
21#define RESULT_FAIL 1
22#define RESULT_UNSUP_HOST 2
23#define RESULT_UNSUP_CARD 3
24
Pierre Ossman26610812008-07-04 18:17:13 +020025#define BUFFER_ORDER 2
26#define BUFFER_SIZE (PAGE_SIZE << BUFFER_ORDER)
Pierre Ossman88ae6002007-08-12 14:23:50 +020027
28struct mmc_test_card {
29 struct mmc_card *card;
30
Pierre Ossman6b174932008-06-30 09:09:27 +020031 u8 scratch[BUFFER_SIZE];
Pierre Ossman88ae6002007-08-12 14:23:50 +020032 u8 *buffer;
Pierre Ossman26610812008-07-04 18:17:13 +020033#ifdef CONFIG_HIGHMEM
34 struct page *highmem;
35#endif
Pierre Ossman88ae6002007-08-12 14:23:50 +020036};
37
38/*******************************************************************/
Pierre Ossman6b174932008-06-30 09:09:27 +020039/* General helper functions */
Pierre Ossman88ae6002007-08-12 14:23:50 +020040/*******************************************************************/
41
Pierre Ossman6b174932008-06-30 09:09:27 +020042/*
43 * Configure correct block size in card
44 */
Pierre Ossman88ae6002007-08-12 14:23:50 +020045static int mmc_test_set_blksize(struct mmc_test_card *test, unsigned size)
46{
47 struct mmc_command cmd;
48 int ret;
49
50 cmd.opcode = MMC_SET_BLOCKLEN;
51 cmd.arg = size;
52 cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
53 ret = mmc_wait_for_cmd(test->card->host, &cmd, 0);
54 if (ret)
55 return ret;
56
57 return 0;
58}
59
Pierre Ossman6b174932008-06-30 09:09:27 +020060/*
61 * Fill in the mmc_request structure given a set of transfer parameters.
62 */
63static void mmc_test_prepare_mrq(struct mmc_test_card *test,
64 struct mmc_request *mrq, struct scatterlist *sg, unsigned sg_len,
65 unsigned dev_addr, unsigned blocks, unsigned blksz, int write)
66{
67 BUG_ON(!mrq || !mrq->cmd || !mrq->data || !mrq->stop);
68
69 if (blocks > 1) {
70 mrq->cmd->opcode = write ?
71 MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK;
72 } else {
73 mrq->cmd->opcode = write ?
74 MMC_WRITE_BLOCK : MMC_READ_SINGLE_BLOCK;
75 }
76
77 mrq->cmd->arg = dev_addr;
Johan Kristellc286d032010-02-10 13:56:34 -080078 if (!mmc_card_blockaddr(test->card))
79 mrq->cmd->arg <<= 9;
80
Pierre Ossman6b174932008-06-30 09:09:27 +020081 mrq->cmd->flags = MMC_RSP_R1 | MMC_CMD_ADTC;
82
83 if (blocks == 1)
84 mrq->stop = NULL;
85 else {
86 mrq->stop->opcode = MMC_STOP_TRANSMISSION;
87 mrq->stop->arg = 0;
88 mrq->stop->flags = MMC_RSP_R1B | MMC_CMD_AC;
89 }
90
91 mrq->data->blksz = blksz;
92 mrq->data->blocks = blocks;
93 mrq->data->flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
94 mrq->data->sg = sg;
95 mrq->data->sg_len = sg_len;
96
97 mmc_set_data_timeout(mrq->data, test->card);
98}
99
100/*
101 * Wait for the card to finish the busy state
102 */
103static int mmc_test_wait_busy(struct mmc_test_card *test)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200104{
105 int ret, busy;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200106 struct mmc_command cmd;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200107
108 busy = 0;
109 do {
Pierre Ossman88ae6002007-08-12 14:23:50 +0200110 memset(&cmd, 0, sizeof(struct mmc_command));
111
112 cmd.opcode = MMC_SEND_STATUS;
113 cmd.arg = test->card->rca << 16;
114 cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
115
Pierre Ossman6b174932008-06-30 09:09:27 +0200116 ret = mmc_wait_for_cmd(test->card->host, &cmd, 0);
117 if (ret)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200118 break;
119
120 if (!busy && !(cmd.resp[0] & R1_READY_FOR_DATA)) {
121 busy = 1;
122 printk(KERN_INFO "%s: Warning: Host did not "
123 "wait for busy state to end.\n",
124 mmc_hostname(test->card->host));
125 }
126 } while (!(cmd.resp[0] & R1_READY_FOR_DATA));
127
128 return ret;
129}
130
Pierre Ossman6b174932008-06-30 09:09:27 +0200131/*
132 * Transfer a single sector of kernel addressable data
133 */
134static int mmc_test_buffer_transfer(struct mmc_test_card *test,
135 u8 *buffer, unsigned addr, unsigned blksz, int write)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200136{
Pierre Ossman6b174932008-06-30 09:09:27 +0200137 int ret;
138
139 struct mmc_request mrq;
140 struct mmc_command cmd;
141 struct mmc_command stop;
142 struct mmc_data data;
143
144 struct scatterlist sg;
145
146 memset(&mrq, 0, sizeof(struct mmc_request));
147 memset(&cmd, 0, sizeof(struct mmc_command));
148 memset(&data, 0, sizeof(struct mmc_data));
149 memset(&stop, 0, sizeof(struct mmc_command));
150
151 mrq.cmd = &cmd;
152 mrq.data = &data;
153 mrq.stop = &stop;
154
155 sg_init_one(&sg, buffer, blksz);
156
157 mmc_test_prepare_mrq(test, &mrq, &sg, 1, addr, 1, blksz, write);
158
159 mmc_wait_for_req(test->card->host, &mrq);
160
161 if (cmd.error)
162 return cmd.error;
163 if (data.error)
164 return data.error;
165
166 ret = mmc_test_wait_busy(test);
167 if (ret)
168 return ret;
169
170 return 0;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200171}
172
Pierre Ossman6b174932008-06-30 09:09:27 +0200173/*******************************************************************/
174/* Test preparation and cleanup */
175/*******************************************************************/
176
177/*
178 * Fill the first couple of sectors of the card with known data
179 * so that bad reads/writes can be detected
180 */
181static int __mmc_test_prepare(struct mmc_test_card *test, int write)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200182{
183 int ret, i;
184
185 ret = mmc_test_set_blksize(test, 512);
186 if (ret)
187 return ret;
188
189 if (write)
Pierre Ossman6b174932008-06-30 09:09:27 +0200190 memset(test->buffer, 0xDF, 512);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200191 else {
Pierre Ossman6b174932008-06-30 09:09:27 +0200192 for (i = 0;i < 512;i++)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200193 test->buffer[i] = i;
194 }
195
196 for (i = 0;i < BUFFER_SIZE / 512;i++) {
Johan Kristellc286d032010-02-10 13:56:34 -0800197 ret = mmc_test_buffer_transfer(test, test->buffer, i, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200198 if (ret)
199 return ret;
200 }
201
202 return 0;
203}
204
Pierre Ossman6b174932008-06-30 09:09:27 +0200205static int mmc_test_prepare_write(struct mmc_test_card *test)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200206{
Pierre Ossman6b174932008-06-30 09:09:27 +0200207 return __mmc_test_prepare(test, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200208}
209
Pierre Ossman6b174932008-06-30 09:09:27 +0200210static int mmc_test_prepare_read(struct mmc_test_card *test)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200211{
Pierre Ossman6b174932008-06-30 09:09:27 +0200212 return __mmc_test_prepare(test, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200213}
214
Pierre Ossman6b174932008-06-30 09:09:27 +0200215static int mmc_test_cleanup(struct mmc_test_card *test)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200216{
Pierre Ossman6b174932008-06-30 09:09:27 +0200217 int ret, i;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200218
Pierre Ossman6b174932008-06-30 09:09:27 +0200219 ret = mmc_test_set_blksize(test, 512);
220 if (ret)
221 return ret;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200222
Pierre Ossman6b174932008-06-30 09:09:27 +0200223 memset(test->buffer, 0, 512);
224
225 for (i = 0;i < BUFFER_SIZE / 512;i++) {
Johan Kristellc286d032010-02-10 13:56:34 -0800226 ret = mmc_test_buffer_transfer(test, test->buffer, i, 512, 1);
Pierre Ossman6b174932008-06-30 09:09:27 +0200227 if (ret)
228 return ret;
229 }
230
231 return 0;
232}
233
234/*******************************************************************/
235/* Test execution helpers */
236/*******************************************************************/
237
238/*
239 * Modifies the mmc_request to perform the "short transfer" tests
240 */
241static void mmc_test_prepare_broken_mrq(struct mmc_test_card *test,
242 struct mmc_request *mrq, int write)
243{
244 BUG_ON(!mrq || !mrq->cmd || !mrq->data);
245
246 if (mrq->data->blocks > 1) {
247 mrq->cmd->opcode = write ?
248 MMC_WRITE_BLOCK : MMC_READ_SINGLE_BLOCK;
249 mrq->stop = NULL;
250 } else {
251 mrq->cmd->opcode = MMC_SEND_STATUS;
252 mrq->cmd->arg = test->card->rca << 16;
253 }
254}
255
256/*
257 * Checks that a normal transfer didn't have any errors
258 */
259static int mmc_test_check_result(struct mmc_test_card *test,
260 struct mmc_request *mrq)
261{
262 int ret;
263
264 BUG_ON(!mrq || !mrq->cmd || !mrq->data);
265
266 ret = 0;
267
268 if (!ret && mrq->cmd->error)
269 ret = mrq->cmd->error;
270 if (!ret && mrq->data->error)
271 ret = mrq->data->error;
272 if (!ret && mrq->stop && mrq->stop->error)
273 ret = mrq->stop->error;
274 if (!ret && mrq->data->bytes_xfered !=
275 mrq->data->blocks * mrq->data->blksz)
276 ret = RESULT_FAIL;
277
278 if (ret == -EINVAL)
279 ret = RESULT_UNSUP_HOST;
280
281 return ret;
282}
283
284/*
285 * Checks that a "short transfer" behaved as expected
286 */
287static int mmc_test_check_broken_result(struct mmc_test_card *test,
288 struct mmc_request *mrq)
289{
290 int ret;
291
292 BUG_ON(!mrq || !mrq->cmd || !mrq->data);
293
294 ret = 0;
295
296 if (!ret && mrq->cmd->error)
297 ret = mrq->cmd->error;
298 if (!ret && mrq->data->error == 0)
299 ret = RESULT_FAIL;
300 if (!ret && mrq->data->error != -ETIMEDOUT)
301 ret = mrq->data->error;
302 if (!ret && mrq->stop && mrq->stop->error)
303 ret = mrq->stop->error;
304 if (mrq->data->blocks > 1) {
305 if (!ret && mrq->data->bytes_xfered > mrq->data->blksz)
306 ret = RESULT_FAIL;
307 } else {
308 if (!ret && mrq->data->bytes_xfered > 0)
309 ret = RESULT_FAIL;
310 }
311
312 if (ret == -EINVAL)
313 ret = RESULT_UNSUP_HOST;
314
315 return ret;
316}
317
318/*
319 * Tests a basic transfer with certain parameters
320 */
321static int mmc_test_simple_transfer(struct mmc_test_card *test,
322 struct scatterlist *sg, unsigned sg_len, unsigned dev_addr,
323 unsigned blocks, unsigned blksz, int write)
324{
325 struct mmc_request mrq;
326 struct mmc_command cmd;
327 struct mmc_command stop;
328 struct mmc_data data;
329
330 memset(&mrq, 0, sizeof(struct mmc_request));
331 memset(&cmd, 0, sizeof(struct mmc_command));
332 memset(&data, 0, sizeof(struct mmc_data));
333 memset(&stop, 0, sizeof(struct mmc_command));
334
335 mrq.cmd = &cmd;
336 mrq.data = &data;
337 mrq.stop = &stop;
338
339 mmc_test_prepare_mrq(test, &mrq, sg, sg_len, dev_addr,
340 blocks, blksz, write);
341
342 mmc_wait_for_req(test->card->host, &mrq);
343
344 mmc_test_wait_busy(test);
345
346 return mmc_test_check_result(test, &mrq);
347}
348
349/*
350 * Tests a transfer where the card will fail completely or partly
351 */
352static int mmc_test_broken_transfer(struct mmc_test_card *test,
353 unsigned blocks, unsigned blksz, int write)
354{
355 struct mmc_request mrq;
356 struct mmc_command cmd;
357 struct mmc_command stop;
358 struct mmc_data data;
359
360 struct scatterlist sg;
361
362 memset(&mrq, 0, sizeof(struct mmc_request));
363 memset(&cmd, 0, sizeof(struct mmc_command));
364 memset(&data, 0, sizeof(struct mmc_data));
365 memset(&stop, 0, sizeof(struct mmc_command));
366
367 mrq.cmd = &cmd;
368 mrq.data = &data;
369 mrq.stop = &stop;
370
371 sg_init_one(&sg, test->buffer, blocks * blksz);
372
373 mmc_test_prepare_mrq(test, &mrq, &sg, 1, 0, blocks, blksz, write);
374 mmc_test_prepare_broken_mrq(test, &mrq, write);
375
376 mmc_wait_for_req(test->card->host, &mrq);
377
378 mmc_test_wait_busy(test);
379
380 return mmc_test_check_broken_result(test, &mrq);
381}
382
383/*
384 * Does a complete transfer test where data is also validated
385 *
386 * Note: mmc_test_prepare() must have been done before this call
387 */
388static int mmc_test_transfer(struct mmc_test_card *test,
389 struct scatterlist *sg, unsigned sg_len, unsigned dev_addr,
390 unsigned blocks, unsigned blksz, int write)
391{
392 int ret, i;
393 unsigned long flags;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200394
395 if (write) {
396 for (i = 0;i < blocks * blksz;i++)
Pierre Ossman6b174932008-06-30 09:09:27 +0200397 test->scratch[i] = i;
398 } else {
Pierre Ossmanb7ac2cf2008-07-29 01:05:22 +0200399 memset(test->scratch, 0, BUFFER_SIZE);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200400 }
Pierre Ossman6b174932008-06-30 09:09:27 +0200401 local_irq_save(flags);
Pierre Ossmanb7ac2cf2008-07-29 01:05:22 +0200402 sg_copy_from_buffer(sg, sg_len, test->scratch, BUFFER_SIZE);
Pierre Ossman6b174932008-06-30 09:09:27 +0200403 local_irq_restore(flags);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200404
405 ret = mmc_test_set_blksize(test, blksz);
406 if (ret)
407 return ret;
408
Pierre Ossman6b174932008-06-30 09:09:27 +0200409 ret = mmc_test_simple_transfer(test, sg, sg_len, dev_addr,
410 blocks, blksz, write);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200411 if (ret)
412 return ret;
413
414 if (write) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200415 int sectors;
416
Pierre Ossman88ae6002007-08-12 14:23:50 +0200417 ret = mmc_test_set_blksize(test, 512);
418 if (ret)
419 return ret;
420
421 sectors = (blocks * blksz + 511) / 512;
422 if ((sectors * 512) == (blocks * blksz))
423 sectors++;
424
425 if ((sectors * 512) > BUFFER_SIZE)
426 return -EINVAL;
427
428 memset(test->buffer, 0, sectors * 512);
429
430 for (i = 0;i < sectors;i++) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200431 ret = mmc_test_buffer_transfer(test,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200432 test->buffer + i * 512,
Johan Kristellc286d032010-02-10 13:56:34 -0800433 dev_addr + i, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200434 if (ret)
435 return ret;
436 }
437
438 for (i = 0;i < blocks * blksz;i++) {
439 if (test->buffer[i] != (u8)i)
440 return RESULT_FAIL;
441 }
442
443 for (;i < sectors * 512;i++) {
444 if (test->buffer[i] != 0xDF)
445 return RESULT_FAIL;
446 }
447 } else {
Pierre Ossman6b174932008-06-30 09:09:27 +0200448 local_irq_save(flags);
Pierre Ossmanb7ac2cf2008-07-29 01:05:22 +0200449 sg_copy_to_buffer(sg, sg_len, test->scratch, BUFFER_SIZE);
Pierre Ossman6b174932008-06-30 09:09:27 +0200450 local_irq_restore(flags);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200451 for (i = 0;i < blocks * blksz;i++) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200452 if (test->scratch[i] != (u8)i)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200453 return RESULT_FAIL;
454 }
455 }
456
457 return 0;
458}
459
Pierre Ossman88ae6002007-08-12 14:23:50 +0200460/*******************************************************************/
461/* Tests */
462/*******************************************************************/
463
464struct mmc_test_case {
465 const char *name;
466
467 int (*prepare)(struct mmc_test_card *);
468 int (*run)(struct mmc_test_card *);
469 int (*cleanup)(struct mmc_test_card *);
470};
471
472static int mmc_test_basic_write(struct mmc_test_card *test)
473{
474 int ret;
Pierre Ossman6b174932008-06-30 09:09:27 +0200475 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200476
477 ret = mmc_test_set_blksize(test, 512);
478 if (ret)
479 return ret;
480
Pierre Ossman6b174932008-06-30 09:09:27 +0200481 sg_init_one(&sg, test->buffer, 512);
482
483 ret = mmc_test_simple_transfer(test, &sg, 1, 0, 1, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200484 if (ret)
485 return ret;
486
487 return 0;
488}
489
490static int mmc_test_basic_read(struct mmc_test_card *test)
491{
492 int ret;
Pierre Ossman6b174932008-06-30 09:09:27 +0200493 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200494
495 ret = mmc_test_set_blksize(test, 512);
496 if (ret)
497 return ret;
498
Pierre Ossman6b174932008-06-30 09:09:27 +0200499 sg_init_one(&sg, test->buffer, 512);
500
Rabin Vincent58a5dd32009-02-13 22:55:26 +0530501 ret = mmc_test_simple_transfer(test, &sg, 1, 0, 1, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200502 if (ret)
503 return ret;
504
505 return 0;
506}
507
508static int mmc_test_verify_write(struct mmc_test_card *test)
509{
510 int ret;
Pierre Ossman6b174932008-06-30 09:09:27 +0200511 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200512
Pierre Ossman6b174932008-06-30 09:09:27 +0200513 sg_init_one(&sg, test->buffer, 512);
514
515 ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200516 if (ret)
517 return ret;
518
519 return 0;
520}
521
522static int mmc_test_verify_read(struct mmc_test_card *test)
523{
524 int ret;
Pierre Ossman6b174932008-06-30 09:09:27 +0200525 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200526
Pierre Ossman6b174932008-06-30 09:09:27 +0200527 sg_init_one(&sg, test->buffer, 512);
528
529 ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200530 if (ret)
531 return ret;
532
533 return 0;
534}
535
536static int mmc_test_multi_write(struct mmc_test_card *test)
537{
538 int ret;
539 unsigned int size;
Pierre Ossman6b174932008-06-30 09:09:27 +0200540 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200541
542 if (test->card->host->max_blk_count == 1)
543 return RESULT_UNSUP_HOST;
544
545 size = PAGE_SIZE * 2;
546 size = min(size, test->card->host->max_req_size);
547 size = min(size, test->card->host->max_seg_size);
548 size = min(size, test->card->host->max_blk_count * 512);
549
550 if (size < 1024)
551 return RESULT_UNSUP_HOST;
552
Pierre Ossman6b174932008-06-30 09:09:27 +0200553 sg_init_one(&sg, test->buffer, size);
554
555 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200556 if (ret)
557 return ret;
558
559 return 0;
560}
561
562static int mmc_test_multi_read(struct mmc_test_card *test)
563{
564 int ret;
565 unsigned int size;
Pierre Ossman6b174932008-06-30 09:09:27 +0200566 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200567
568 if (test->card->host->max_blk_count == 1)
569 return RESULT_UNSUP_HOST;
570
571 size = PAGE_SIZE * 2;
572 size = min(size, test->card->host->max_req_size);
573 size = min(size, test->card->host->max_seg_size);
574 size = min(size, test->card->host->max_blk_count * 512);
575
576 if (size < 1024)
577 return RESULT_UNSUP_HOST;
578
Pierre Ossman6b174932008-06-30 09:09:27 +0200579 sg_init_one(&sg, test->buffer, size);
580
581 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200582 if (ret)
583 return ret;
584
585 return 0;
586}
587
588static int mmc_test_pow2_write(struct mmc_test_card *test)
589{
590 int ret, i;
Pierre Ossman6b174932008-06-30 09:09:27 +0200591 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200592
593 if (!test->card->csd.write_partial)
594 return RESULT_UNSUP_CARD;
595
596 for (i = 1; i < 512;i <<= 1) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200597 sg_init_one(&sg, test->buffer, i);
598 ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200599 if (ret)
600 return ret;
601 }
602
603 return 0;
604}
605
606static int mmc_test_pow2_read(struct mmc_test_card *test)
607{
608 int ret, i;
Pierre Ossman6b174932008-06-30 09:09:27 +0200609 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200610
611 if (!test->card->csd.read_partial)
612 return RESULT_UNSUP_CARD;
613
614 for (i = 1; i < 512;i <<= 1) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200615 sg_init_one(&sg, test->buffer, i);
616 ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200617 if (ret)
618 return ret;
619 }
620
621 return 0;
622}
623
624static int mmc_test_weird_write(struct mmc_test_card *test)
625{
626 int ret, i;
Pierre Ossman6b174932008-06-30 09:09:27 +0200627 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200628
629 if (!test->card->csd.write_partial)
630 return RESULT_UNSUP_CARD;
631
632 for (i = 3; i < 512;i += 7) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200633 sg_init_one(&sg, test->buffer, i);
634 ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200635 if (ret)
636 return ret;
637 }
638
639 return 0;
640}
641
642static int mmc_test_weird_read(struct mmc_test_card *test)
643{
644 int ret, i;
Pierre Ossman6b174932008-06-30 09:09:27 +0200645 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200646
647 if (!test->card->csd.read_partial)
648 return RESULT_UNSUP_CARD;
649
650 for (i = 3; i < 512;i += 7) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200651 sg_init_one(&sg, test->buffer, i);
652 ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200653 if (ret)
654 return ret;
655 }
656
657 return 0;
658}
659
660static int mmc_test_align_write(struct mmc_test_card *test)
661{
662 int ret, i;
Pierre Ossman6b174932008-06-30 09:09:27 +0200663 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200664
665 for (i = 1;i < 4;i++) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200666 sg_init_one(&sg, test->buffer + i, 512);
667 ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200668 if (ret)
669 return ret;
670 }
671
672 return 0;
673}
674
675static int mmc_test_align_read(struct mmc_test_card *test)
676{
677 int ret, i;
Pierre Ossman6b174932008-06-30 09:09:27 +0200678 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200679
680 for (i = 1;i < 4;i++) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200681 sg_init_one(&sg, test->buffer + i, 512);
682 ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200683 if (ret)
684 return ret;
685 }
686
687 return 0;
688}
689
690static int mmc_test_align_multi_write(struct mmc_test_card *test)
691{
692 int ret, i;
693 unsigned int size;
Pierre Ossman6b174932008-06-30 09:09:27 +0200694 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200695
696 if (test->card->host->max_blk_count == 1)
697 return RESULT_UNSUP_HOST;
698
699 size = PAGE_SIZE * 2;
700 size = min(size, test->card->host->max_req_size);
701 size = min(size, test->card->host->max_seg_size);
702 size = min(size, test->card->host->max_blk_count * 512);
703
704 if (size < 1024)
705 return RESULT_UNSUP_HOST;
706
707 for (i = 1;i < 4;i++) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200708 sg_init_one(&sg, test->buffer + i, size);
709 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200710 if (ret)
711 return ret;
712 }
713
714 return 0;
715}
716
717static int mmc_test_align_multi_read(struct mmc_test_card *test)
718{
719 int ret, i;
720 unsigned int size;
Pierre Ossman6b174932008-06-30 09:09:27 +0200721 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200722
723 if (test->card->host->max_blk_count == 1)
724 return RESULT_UNSUP_HOST;
725
726 size = PAGE_SIZE * 2;
727 size = min(size, test->card->host->max_req_size);
728 size = min(size, test->card->host->max_seg_size);
729 size = min(size, test->card->host->max_blk_count * 512);
730
731 if (size < 1024)
732 return RESULT_UNSUP_HOST;
733
734 for (i = 1;i < 4;i++) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200735 sg_init_one(&sg, test->buffer + i, size);
736 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200737 if (ret)
738 return ret;
739 }
740
741 return 0;
742}
743
744static int mmc_test_xfersize_write(struct mmc_test_card *test)
745{
746 int ret;
747
748 ret = mmc_test_set_blksize(test, 512);
749 if (ret)
750 return ret;
751
Pierre Ossman6b174932008-06-30 09:09:27 +0200752 ret = mmc_test_broken_transfer(test, 1, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200753 if (ret)
754 return ret;
755
756 return 0;
757}
758
759static int mmc_test_xfersize_read(struct mmc_test_card *test)
760{
761 int ret;
762
763 ret = mmc_test_set_blksize(test, 512);
764 if (ret)
765 return ret;
766
Pierre Ossman6b174932008-06-30 09:09:27 +0200767 ret = mmc_test_broken_transfer(test, 1, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200768 if (ret)
769 return ret;
770
771 return 0;
772}
773
774static int mmc_test_multi_xfersize_write(struct mmc_test_card *test)
775{
776 int ret;
777
778 if (test->card->host->max_blk_count == 1)
779 return RESULT_UNSUP_HOST;
780
781 ret = mmc_test_set_blksize(test, 512);
782 if (ret)
783 return ret;
784
Pierre Ossman6b174932008-06-30 09:09:27 +0200785 ret = mmc_test_broken_transfer(test, 2, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200786 if (ret)
787 return ret;
788
789 return 0;
790}
791
792static int mmc_test_multi_xfersize_read(struct mmc_test_card *test)
793{
794 int ret;
795
796 if (test->card->host->max_blk_count == 1)
797 return RESULT_UNSUP_HOST;
798
799 ret = mmc_test_set_blksize(test, 512);
800 if (ret)
801 return ret;
802
Pierre Ossman6b174932008-06-30 09:09:27 +0200803 ret = mmc_test_broken_transfer(test, 2, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200804 if (ret)
805 return ret;
806
807 return 0;
808}
809
Pierre Ossman26610812008-07-04 18:17:13 +0200810#ifdef CONFIG_HIGHMEM
811
812static int mmc_test_write_high(struct mmc_test_card *test)
813{
814 int ret;
815 struct scatterlist sg;
816
817 sg_init_table(&sg, 1);
818 sg_set_page(&sg, test->highmem, 512, 0);
819
820 ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1);
821 if (ret)
822 return ret;
823
824 return 0;
825}
826
827static int mmc_test_read_high(struct mmc_test_card *test)
828{
829 int ret;
830 struct scatterlist sg;
831
832 sg_init_table(&sg, 1);
833 sg_set_page(&sg, test->highmem, 512, 0);
834
835 ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0);
836 if (ret)
837 return ret;
838
839 return 0;
840}
841
842static int mmc_test_multi_write_high(struct mmc_test_card *test)
843{
844 int ret;
845 unsigned int size;
846 struct scatterlist sg;
847
848 if (test->card->host->max_blk_count == 1)
849 return RESULT_UNSUP_HOST;
850
851 size = PAGE_SIZE * 2;
852 size = min(size, test->card->host->max_req_size);
853 size = min(size, test->card->host->max_seg_size);
854 size = min(size, test->card->host->max_blk_count * 512);
855
856 if (size < 1024)
857 return RESULT_UNSUP_HOST;
858
859 sg_init_table(&sg, 1);
860 sg_set_page(&sg, test->highmem, size, 0);
861
862 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
863 if (ret)
864 return ret;
865
866 return 0;
867}
868
869static int mmc_test_multi_read_high(struct mmc_test_card *test)
870{
871 int ret;
872 unsigned int size;
873 struct scatterlist sg;
874
875 if (test->card->host->max_blk_count == 1)
876 return RESULT_UNSUP_HOST;
877
878 size = PAGE_SIZE * 2;
879 size = min(size, test->card->host->max_req_size);
880 size = min(size, test->card->host->max_seg_size);
881 size = min(size, test->card->host->max_blk_count * 512);
882
883 if (size < 1024)
884 return RESULT_UNSUP_HOST;
885
886 sg_init_table(&sg, 1);
887 sg_set_page(&sg, test->highmem, size, 0);
888
889 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
890 if (ret)
891 return ret;
892
893 return 0;
894}
895
896#endif /* CONFIG_HIGHMEM */
897
Pierre Ossman88ae6002007-08-12 14:23:50 +0200898static const struct mmc_test_case mmc_test_cases[] = {
899 {
900 .name = "Basic write (no data verification)",
901 .run = mmc_test_basic_write,
902 },
903
904 {
905 .name = "Basic read (no data verification)",
906 .run = mmc_test_basic_read,
907 },
908
909 {
910 .name = "Basic write (with data verification)",
Pierre Ossman6b174932008-06-30 09:09:27 +0200911 .prepare = mmc_test_prepare_write,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200912 .run = mmc_test_verify_write,
Pierre Ossman6b174932008-06-30 09:09:27 +0200913 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200914 },
915
916 {
917 .name = "Basic read (with data verification)",
Pierre Ossman6b174932008-06-30 09:09:27 +0200918 .prepare = mmc_test_prepare_read,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200919 .run = mmc_test_verify_read,
Pierre Ossman6b174932008-06-30 09:09:27 +0200920 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200921 },
922
923 {
924 .name = "Multi-block write",
Pierre Ossman6b174932008-06-30 09:09:27 +0200925 .prepare = mmc_test_prepare_write,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200926 .run = mmc_test_multi_write,
Pierre Ossman6b174932008-06-30 09:09:27 +0200927 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200928 },
929
930 {
931 .name = "Multi-block read",
Pierre Ossman6b174932008-06-30 09:09:27 +0200932 .prepare = mmc_test_prepare_read,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200933 .run = mmc_test_multi_read,
Pierre Ossman6b174932008-06-30 09:09:27 +0200934 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200935 },
936
937 {
938 .name = "Power of two block writes",
Pierre Ossman6b174932008-06-30 09:09:27 +0200939 .prepare = mmc_test_prepare_write,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200940 .run = mmc_test_pow2_write,
Pierre Ossman6b174932008-06-30 09:09:27 +0200941 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200942 },
943
944 {
945 .name = "Power of two block reads",
Pierre Ossman6b174932008-06-30 09:09:27 +0200946 .prepare = mmc_test_prepare_read,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200947 .run = mmc_test_pow2_read,
Pierre Ossman6b174932008-06-30 09:09:27 +0200948 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200949 },
950
951 {
952 .name = "Weird sized block writes",
Pierre Ossman6b174932008-06-30 09:09:27 +0200953 .prepare = mmc_test_prepare_write,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200954 .run = mmc_test_weird_write,
Pierre Ossman6b174932008-06-30 09:09:27 +0200955 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200956 },
957
958 {
959 .name = "Weird sized block reads",
Pierre Ossman6b174932008-06-30 09:09:27 +0200960 .prepare = mmc_test_prepare_read,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200961 .run = mmc_test_weird_read,
Pierre Ossman6b174932008-06-30 09:09:27 +0200962 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200963 },
964
965 {
966 .name = "Badly aligned write",
Pierre Ossman6b174932008-06-30 09:09:27 +0200967 .prepare = mmc_test_prepare_write,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200968 .run = mmc_test_align_write,
Pierre Ossman6b174932008-06-30 09:09:27 +0200969 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200970 },
971
972 {
973 .name = "Badly aligned read",
Pierre Ossman6b174932008-06-30 09:09:27 +0200974 .prepare = mmc_test_prepare_read,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200975 .run = mmc_test_align_read,
Pierre Ossman6b174932008-06-30 09:09:27 +0200976 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200977 },
978
979 {
980 .name = "Badly aligned multi-block write",
Pierre Ossman6b174932008-06-30 09:09:27 +0200981 .prepare = mmc_test_prepare_write,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200982 .run = mmc_test_align_multi_write,
Pierre Ossman6b174932008-06-30 09:09:27 +0200983 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200984 },
985
986 {
987 .name = "Badly aligned multi-block read",
Pierre Ossman6b174932008-06-30 09:09:27 +0200988 .prepare = mmc_test_prepare_read,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200989 .run = mmc_test_align_multi_read,
Pierre Ossman6b174932008-06-30 09:09:27 +0200990 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200991 },
992
993 {
994 .name = "Correct xfer_size at write (start failure)",
995 .run = mmc_test_xfersize_write,
996 },
997
998 {
999 .name = "Correct xfer_size at read (start failure)",
1000 .run = mmc_test_xfersize_read,
1001 },
1002
1003 {
1004 .name = "Correct xfer_size at write (midway failure)",
1005 .run = mmc_test_multi_xfersize_write,
1006 },
1007
1008 {
1009 .name = "Correct xfer_size at read (midway failure)",
1010 .run = mmc_test_multi_xfersize_read,
1011 },
Pierre Ossman26610812008-07-04 18:17:13 +02001012
1013#ifdef CONFIG_HIGHMEM
1014
1015 {
1016 .name = "Highmem write",
1017 .prepare = mmc_test_prepare_write,
1018 .run = mmc_test_write_high,
1019 .cleanup = mmc_test_cleanup,
1020 },
1021
1022 {
1023 .name = "Highmem read",
1024 .prepare = mmc_test_prepare_read,
1025 .run = mmc_test_read_high,
1026 .cleanup = mmc_test_cleanup,
1027 },
1028
1029 {
1030 .name = "Multi-block highmem write",
1031 .prepare = mmc_test_prepare_write,
1032 .run = mmc_test_multi_write_high,
1033 .cleanup = mmc_test_cleanup,
1034 },
1035
1036 {
1037 .name = "Multi-block highmem read",
1038 .prepare = mmc_test_prepare_read,
1039 .run = mmc_test_multi_read_high,
1040 .cleanup = mmc_test_cleanup,
1041 },
1042
1043#endif /* CONFIG_HIGHMEM */
1044
Pierre Ossman88ae6002007-08-12 14:23:50 +02001045};
1046
Akinobu Mitaa6500312008-09-13 19:03:32 +09001047static DEFINE_MUTEX(mmc_test_lock);
Pierre Ossman88ae6002007-08-12 14:23:50 +02001048
Pierre Ossmanfd8c3262008-05-24 22:36:31 +02001049static void mmc_test_run(struct mmc_test_card *test, int testcase)
Pierre Ossman88ae6002007-08-12 14:23:50 +02001050{
1051 int i, ret;
1052
1053 printk(KERN_INFO "%s: Starting tests of card %s...\n",
1054 mmc_hostname(test->card->host), mmc_card_id(test->card));
1055
1056 mmc_claim_host(test->card->host);
1057
1058 for (i = 0;i < ARRAY_SIZE(mmc_test_cases);i++) {
Pierre Ossmanfd8c3262008-05-24 22:36:31 +02001059 if (testcase && ((i + 1) != testcase))
1060 continue;
1061
Pierre Ossman88ae6002007-08-12 14:23:50 +02001062 printk(KERN_INFO "%s: Test case %d. %s...\n",
1063 mmc_hostname(test->card->host), i + 1,
1064 mmc_test_cases[i].name);
1065
1066 if (mmc_test_cases[i].prepare) {
1067 ret = mmc_test_cases[i].prepare(test);
1068 if (ret) {
1069 printk(KERN_INFO "%s: Result: Prepare "
1070 "stage failed! (%d)\n",
1071 mmc_hostname(test->card->host),
1072 ret);
1073 continue;
1074 }
1075 }
1076
1077 ret = mmc_test_cases[i].run(test);
1078 switch (ret) {
1079 case RESULT_OK:
1080 printk(KERN_INFO "%s: Result: OK\n",
1081 mmc_hostname(test->card->host));
1082 break;
1083 case RESULT_FAIL:
1084 printk(KERN_INFO "%s: Result: FAILED\n",
1085 mmc_hostname(test->card->host));
1086 break;
1087 case RESULT_UNSUP_HOST:
1088 printk(KERN_INFO "%s: Result: UNSUPPORTED "
1089 "(by host)\n",
1090 mmc_hostname(test->card->host));
1091 break;
1092 case RESULT_UNSUP_CARD:
1093 printk(KERN_INFO "%s: Result: UNSUPPORTED "
1094 "(by card)\n",
1095 mmc_hostname(test->card->host));
1096 break;
1097 default:
1098 printk(KERN_INFO "%s: Result: ERROR (%d)\n",
1099 mmc_hostname(test->card->host), ret);
1100 }
1101
1102 if (mmc_test_cases[i].cleanup) {
1103 ret = mmc_test_cases[i].cleanup(test);
1104 if (ret) {
1105 printk(KERN_INFO "%s: Warning: Cleanup "
1106 "stage failed! (%d)\n",
1107 mmc_hostname(test->card->host),
1108 ret);
1109 }
1110 }
1111 }
1112
1113 mmc_release_host(test->card->host);
1114
1115 printk(KERN_INFO "%s: Tests completed.\n",
1116 mmc_hostname(test->card->host));
1117}
1118
1119static ssize_t mmc_test_show(struct device *dev,
1120 struct device_attribute *attr, char *buf)
1121{
1122 mutex_lock(&mmc_test_lock);
1123 mutex_unlock(&mmc_test_lock);
1124
1125 return 0;
1126}
1127
1128static ssize_t mmc_test_store(struct device *dev,
1129 struct device_attribute *attr, const char *buf, size_t count)
1130{
1131 struct mmc_card *card;
1132 struct mmc_test_card *test;
Pierre Ossmanfd8c3262008-05-24 22:36:31 +02001133 int testcase;
Pierre Ossman88ae6002007-08-12 14:23:50 +02001134
1135 card = container_of(dev, struct mmc_card, dev);
1136
Pierre Ossmanfd8c3262008-05-24 22:36:31 +02001137 testcase = simple_strtol(buf, NULL, 10);
1138
Pierre Ossman88ae6002007-08-12 14:23:50 +02001139 test = kzalloc(sizeof(struct mmc_test_card), GFP_KERNEL);
1140 if (!test)
1141 return -ENOMEM;
1142
1143 test->card = card;
1144
1145 test->buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL);
Pierre Ossman26610812008-07-04 18:17:13 +02001146#ifdef CONFIG_HIGHMEM
1147 test->highmem = alloc_pages(GFP_KERNEL | __GFP_HIGHMEM, BUFFER_ORDER);
1148#endif
1149
1150#ifdef CONFIG_HIGHMEM
1151 if (test->buffer && test->highmem) {
1152#else
Pierre Ossman88ae6002007-08-12 14:23:50 +02001153 if (test->buffer) {
Pierre Ossman26610812008-07-04 18:17:13 +02001154#endif
Pierre Ossman88ae6002007-08-12 14:23:50 +02001155 mutex_lock(&mmc_test_lock);
Pierre Ossmanfd8c3262008-05-24 22:36:31 +02001156 mmc_test_run(test, testcase);
Pierre Ossman88ae6002007-08-12 14:23:50 +02001157 mutex_unlock(&mmc_test_lock);
1158 }
1159
Pierre Ossman26610812008-07-04 18:17:13 +02001160#ifdef CONFIG_HIGHMEM
1161 __free_pages(test->highmem, BUFFER_ORDER);
1162#endif
Pierre Ossman88ae6002007-08-12 14:23:50 +02001163 kfree(test->buffer);
1164 kfree(test);
1165
1166 return count;
1167}
1168
1169static DEVICE_ATTR(test, S_IWUSR | S_IRUGO, mmc_test_show, mmc_test_store);
1170
1171static int mmc_test_probe(struct mmc_card *card)
1172{
1173 int ret;
1174
Pierre Ossman0121a982008-06-28 17:51:27 +02001175 if ((card->type != MMC_TYPE_MMC) && (card->type != MMC_TYPE_SD))
1176 return -ENODEV;
1177
Pierre Ossman88ae6002007-08-12 14:23:50 +02001178 ret = device_create_file(&card->dev, &dev_attr_test);
1179 if (ret)
1180 return ret;
1181
Pierre Ossman60c9c7b2008-07-22 14:38:35 +02001182 dev_info(&card->dev, "Card claimed for testing.\n");
1183
Pierre Ossman88ae6002007-08-12 14:23:50 +02001184 return 0;
1185}
1186
1187static void mmc_test_remove(struct mmc_card *card)
1188{
1189 device_remove_file(&card->dev, &dev_attr_test);
1190}
1191
1192static struct mmc_driver mmc_driver = {
1193 .drv = {
1194 .name = "mmc_test",
1195 },
1196 .probe = mmc_test_probe,
1197 .remove = mmc_test_remove,
1198};
1199
1200static int __init mmc_test_init(void)
1201{
1202 return mmc_register_driver(&mmc_driver);
1203}
1204
1205static void __exit mmc_test_exit(void)
1206{
1207 mmc_unregister_driver(&mmc_driver);
1208}
1209
1210module_init(mmc_test_init);
1211module_exit(mmc_test_exit);
1212
1213MODULE_LICENSE("GPL");
1214MODULE_DESCRIPTION("Multimedia Card (MMC) host test driver");
1215MODULE_AUTHOR("Pierre Ossman");