blob: a067fe436301d2853bcc50be9f8a7d09d79fbfe0 [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;
77 mrq->cmd->flags = MMC_RSP_R1 | MMC_CMD_ADTC;
78
79 if (blocks == 1)
80 mrq->stop = NULL;
81 else {
82 mrq->stop->opcode = MMC_STOP_TRANSMISSION;
83 mrq->stop->arg = 0;
84 mrq->stop->flags = MMC_RSP_R1B | MMC_CMD_AC;
85 }
86
87 mrq->data->blksz = blksz;
88 mrq->data->blocks = blocks;
89 mrq->data->flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
90 mrq->data->sg = sg;
91 mrq->data->sg_len = sg_len;
92
93 mmc_set_data_timeout(mrq->data, test->card);
94}
95
96/*
97 * Wait for the card to finish the busy state
98 */
99static int mmc_test_wait_busy(struct mmc_test_card *test)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200100{
101 int ret, busy;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200102 struct mmc_command cmd;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200103
104 busy = 0;
105 do {
Pierre Ossman88ae6002007-08-12 14:23:50 +0200106 memset(&cmd, 0, sizeof(struct mmc_command));
107
108 cmd.opcode = MMC_SEND_STATUS;
109 cmd.arg = test->card->rca << 16;
110 cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
111
Pierre Ossman6b174932008-06-30 09:09:27 +0200112 ret = mmc_wait_for_cmd(test->card->host, &cmd, 0);
113 if (ret)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200114 break;
115
116 if (!busy && !(cmd.resp[0] & R1_READY_FOR_DATA)) {
117 busy = 1;
118 printk(KERN_INFO "%s: Warning: Host did not "
119 "wait for busy state to end.\n",
120 mmc_hostname(test->card->host));
121 }
122 } while (!(cmd.resp[0] & R1_READY_FOR_DATA));
123
124 return ret;
125}
126
Pierre Ossman6b174932008-06-30 09:09:27 +0200127/*
128 * Transfer a single sector of kernel addressable data
129 */
130static int mmc_test_buffer_transfer(struct mmc_test_card *test,
131 u8 *buffer, unsigned addr, unsigned blksz, int write)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200132{
Pierre Ossman6b174932008-06-30 09:09:27 +0200133 int ret;
134
135 struct mmc_request mrq;
136 struct mmc_command cmd;
137 struct mmc_command stop;
138 struct mmc_data data;
139
140 struct scatterlist sg;
141
142 memset(&mrq, 0, sizeof(struct mmc_request));
143 memset(&cmd, 0, sizeof(struct mmc_command));
144 memset(&data, 0, sizeof(struct mmc_data));
145 memset(&stop, 0, sizeof(struct mmc_command));
146
147 mrq.cmd = &cmd;
148 mrq.data = &data;
149 mrq.stop = &stop;
150
151 sg_init_one(&sg, buffer, blksz);
152
153 mmc_test_prepare_mrq(test, &mrq, &sg, 1, addr, 1, blksz, write);
154
155 mmc_wait_for_req(test->card->host, &mrq);
156
157 if (cmd.error)
158 return cmd.error;
159 if (data.error)
160 return data.error;
161
162 ret = mmc_test_wait_busy(test);
163 if (ret)
164 return ret;
165
166 return 0;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200167}
168
Pierre Ossman6b174932008-06-30 09:09:27 +0200169/*******************************************************************/
170/* Test preparation and cleanup */
171/*******************************************************************/
172
173/*
174 * Fill the first couple of sectors of the card with known data
175 * so that bad reads/writes can be detected
176 */
177static int __mmc_test_prepare(struct mmc_test_card *test, int write)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200178{
179 int ret, i;
180
181 ret = mmc_test_set_blksize(test, 512);
182 if (ret)
183 return ret;
184
185 if (write)
Pierre Ossman6b174932008-06-30 09:09:27 +0200186 memset(test->buffer, 0xDF, 512);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200187 else {
Pierre Ossman6b174932008-06-30 09:09:27 +0200188 for (i = 0;i < 512;i++)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200189 test->buffer[i] = i;
190 }
191
192 for (i = 0;i < BUFFER_SIZE / 512;i++) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200193 ret = mmc_test_buffer_transfer(test, test->buffer, i * 512, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200194 if (ret)
195 return ret;
196 }
197
198 return 0;
199}
200
Pierre Ossman6b174932008-06-30 09:09:27 +0200201static int mmc_test_prepare_write(struct mmc_test_card *test)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200202{
Pierre Ossman6b174932008-06-30 09:09:27 +0200203 return __mmc_test_prepare(test, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200204}
205
Pierre Ossman6b174932008-06-30 09:09:27 +0200206static int mmc_test_prepare_read(struct mmc_test_card *test)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200207{
Pierre Ossman6b174932008-06-30 09:09:27 +0200208 return __mmc_test_prepare(test, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200209}
210
Pierre Ossman6b174932008-06-30 09:09:27 +0200211static int mmc_test_cleanup(struct mmc_test_card *test)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200212{
Pierre Ossman6b174932008-06-30 09:09:27 +0200213 int ret, i;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200214
Pierre Ossman6b174932008-06-30 09:09:27 +0200215 ret = mmc_test_set_blksize(test, 512);
216 if (ret)
217 return ret;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200218
Pierre Ossman6b174932008-06-30 09:09:27 +0200219 memset(test->buffer, 0, 512);
220
221 for (i = 0;i < BUFFER_SIZE / 512;i++) {
222 ret = mmc_test_buffer_transfer(test, test->buffer, i * 512, 512, 1);
223 if (ret)
224 return ret;
225 }
226
227 return 0;
228}
229
230/*******************************************************************/
231/* Test execution helpers */
232/*******************************************************************/
233
234/*
235 * Modifies the mmc_request to perform the "short transfer" tests
236 */
237static void mmc_test_prepare_broken_mrq(struct mmc_test_card *test,
238 struct mmc_request *mrq, int write)
239{
240 BUG_ON(!mrq || !mrq->cmd || !mrq->data);
241
242 if (mrq->data->blocks > 1) {
243 mrq->cmd->opcode = write ?
244 MMC_WRITE_BLOCK : MMC_READ_SINGLE_BLOCK;
245 mrq->stop = NULL;
246 } else {
247 mrq->cmd->opcode = MMC_SEND_STATUS;
248 mrq->cmd->arg = test->card->rca << 16;
249 }
250}
251
252/*
253 * Checks that a normal transfer didn't have any errors
254 */
255static int mmc_test_check_result(struct mmc_test_card *test,
256 struct mmc_request *mrq)
257{
258 int ret;
259
260 BUG_ON(!mrq || !mrq->cmd || !mrq->data);
261
262 ret = 0;
263
264 if (!ret && mrq->cmd->error)
265 ret = mrq->cmd->error;
266 if (!ret && mrq->data->error)
267 ret = mrq->data->error;
268 if (!ret && mrq->stop && mrq->stop->error)
269 ret = mrq->stop->error;
270 if (!ret && mrq->data->bytes_xfered !=
271 mrq->data->blocks * mrq->data->blksz)
272 ret = RESULT_FAIL;
273
274 if (ret == -EINVAL)
275 ret = RESULT_UNSUP_HOST;
276
277 return ret;
278}
279
280/*
281 * Checks that a "short transfer" behaved as expected
282 */
283static int mmc_test_check_broken_result(struct mmc_test_card *test,
284 struct mmc_request *mrq)
285{
286 int ret;
287
288 BUG_ON(!mrq || !mrq->cmd || !mrq->data);
289
290 ret = 0;
291
292 if (!ret && mrq->cmd->error)
293 ret = mrq->cmd->error;
294 if (!ret && mrq->data->error == 0)
295 ret = RESULT_FAIL;
296 if (!ret && mrq->data->error != -ETIMEDOUT)
297 ret = mrq->data->error;
298 if (!ret && mrq->stop && mrq->stop->error)
299 ret = mrq->stop->error;
300 if (mrq->data->blocks > 1) {
301 if (!ret && mrq->data->bytes_xfered > mrq->data->blksz)
302 ret = RESULT_FAIL;
303 } else {
304 if (!ret && mrq->data->bytes_xfered > 0)
305 ret = RESULT_FAIL;
306 }
307
308 if (ret == -EINVAL)
309 ret = RESULT_UNSUP_HOST;
310
311 return ret;
312}
313
314/*
315 * Tests a basic transfer with certain parameters
316 */
317static int mmc_test_simple_transfer(struct mmc_test_card *test,
318 struct scatterlist *sg, unsigned sg_len, unsigned dev_addr,
319 unsigned blocks, unsigned blksz, int write)
320{
321 struct mmc_request mrq;
322 struct mmc_command cmd;
323 struct mmc_command stop;
324 struct mmc_data data;
325
326 memset(&mrq, 0, sizeof(struct mmc_request));
327 memset(&cmd, 0, sizeof(struct mmc_command));
328 memset(&data, 0, sizeof(struct mmc_data));
329 memset(&stop, 0, sizeof(struct mmc_command));
330
331 mrq.cmd = &cmd;
332 mrq.data = &data;
333 mrq.stop = &stop;
334
335 mmc_test_prepare_mrq(test, &mrq, sg, sg_len, dev_addr,
336 blocks, blksz, write);
337
338 mmc_wait_for_req(test->card->host, &mrq);
339
340 mmc_test_wait_busy(test);
341
342 return mmc_test_check_result(test, &mrq);
343}
344
345/*
346 * Tests a transfer where the card will fail completely or partly
347 */
348static int mmc_test_broken_transfer(struct mmc_test_card *test,
349 unsigned blocks, unsigned blksz, int write)
350{
351 struct mmc_request mrq;
352 struct mmc_command cmd;
353 struct mmc_command stop;
354 struct mmc_data data;
355
356 struct scatterlist sg;
357
358 memset(&mrq, 0, sizeof(struct mmc_request));
359 memset(&cmd, 0, sizeof(struct mmc_command));
360 memset(&data, 0, sizeof(struct mmc_data));
361 memset(&stop, 0, sizeof(struct mmc_command));
362
363 mrq.cmd = &cmd;
364 mrq.data = &data;
365 mrq.stop = &stop;
366
367 sg_init_one(&sg, test->buffer, blocks * blksz);
368
369 mmc_test_prepare_mrq(test, &mrq, &sg, 1, 0, blocks, blksz, write);
370 mmc_test_prepare_broken_mrq(test, &mrq, write);
371
372 mmc_wait_for_req(test->card->host, &mrq);
373
374 mmc_test_wait_busy(test);
375
376 return mmc_test_check_broken_result(test, &mrq);
377}
378
379/*
380 * Does a complete transfer test where data is also validated
381 *
382 * Note: mmc_test_prepare() must have been done before this call
383 */
384static int mmc_test_transfer(struct mmc_test_card *test,
385 struct scatterlist *sg, unsigned sg_len, unsigned dev_addr,
386 unsigned blocks, unsigned blksz, int write)
387{
388 int ret, i;
389 unsigned long flags;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200390
Pierre Ossman48b53522008-07-21 00:14:52 +0200391 BUG_ON(blocks * blksz > BUFFER_SIZE);
392
Pierre Ossman88ae6002007-08-12 14:23:50 +0200393 if (write) {
394 for (i = 0;i < blocks * blksz;i++)
Pierre Ossman6b174932008-06-30 09:09:27 +0200395 test->scratch[i] = i;
396 } else {
Pierre Ossman48b53522008-07-21 00:14:52 +0200397 memset(test->scratch, 0, blocks * blksz);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200398 }
Pierre Ossman6b174932008-06-30 09:09:27 +0200399 local_irq_save(flags);
Pierre Ossman48b53522008-07-21 00:14:52 +0200400 sg_copy_from_buffer(sg, sg_len, test->scratch, blocks * blksz);
Pierre Ossman6b174932008-06-30 09:09:27 +0200401 local_irq_restore(flags);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200402
403 ret = mmc_test_set_blksize(test, blksz);
404 if (ret)
405 return ret;
406
Pierre Ossman6b174932008-06-30 09:09:27 +0200407 ret = mmc_test_simple_transfer(test, sg, sg_len, dev_addr,
408 blocks, blksz, write);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200409 if (ret)
410 return ret;
411
412 if (write) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200413 int sectors;
414
Pierre Ossman88ae6002007-08-12 14:23:50 +0200415 ret = mmc_test_set_blksize(test, 512);
416 if (ret)
417 return ret;
418
419 sectors = (blocks * blksz + 511) / 512;
420 if ((sectors * 512) == (blocks * blksz))
421 sectors++;
422
423 if ((sectors * 512) > BUFFER_SIZE)
424 return -EINVAL;
425
426 memset(test->buffer, 0, sectors * 512);
427
428 for (i = 0;i < sectors;i++) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200429 ret = mmc_test_buffer_transfer(test,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200430 test->buffer + i * 512,
Pierre Ossman6b174932008-06-30 09:09:27 +0200431 dev_addr + i * 512, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200432 if (ret)
433 return ret;
434 }
435
436 for (i = 0;i < blocks * blksz;i++) {
437 if (test->buffer[i] != (u8)i)
438 return RESULT_FAIL;
439 }
440
441 for (;i < sectors * 512;i++) {
442 if (test->buffer[i] != 0xDF)
443 return RESULT_FAIL;
444 }
445 } else {
Pierre Ossman6b174932008-06-30 09:09:27 +0200446 local_irq_save(flags);
Pierre Ossman48b53522008-07-21 00:14:52 +0200447 sg_copy_to_buffer(sg, sg_len, test->scratch, blocks * blksz);
Pierre Ossman6b174932008-06-30 09:09:27 +0200448 local_irq_restore(flags);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200449 for (i = 0;i < blocks * blksz;i++) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200450 if (test->scratch[i] != (u8)i)
Pierre Ossman88ae6002007-08-12 14:23:50 +0200451 return RESULT_FAIL;
452 }
453 }
454
455 return 0;
456}
457
Pierre Ossman88ae6002007-08-12 14:23:50 +0200458/*******************************************************************/
459/* Tests */
460/*******************************************************************/
461
462struct mmc_test_case {
463 const char *name;
464
465 int (*prepare)(struct mmc_test_card *);
466 int (*run)(struct mmc_test_card *);
467 int (*cleanup)(struct mmc_test_card *);
468};
469
470static int mmc_test_basic_write(struct mmc_test_card *test)
471{
472 int ret;
Pierre Ossman6b174932008-06-30 09:09:27 +0200473 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200474
475 ret = mmc_test_set_blksize(test, 512);
476 if (ret)
477 return ret;
478
Pierre Ossman6b174932008-06-30 09:09:27 +0200479 sg_init_one(&sg, test->buffer, 512);
480
481 ret = mmc_test_simple_transfer(test, &sg, 1, 0, 1, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200482 if (ret)
483 return ret;
484
485 return 0;
486}
487
488static int mmc_test_basic_read(struct mmc_test_card *test)
489{
490 int ret;
Pierre Ossman6b174932008-06-30 09:09:27 +0200491 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200492
493 ret = mmc_test_set_blksize(test, 512);
494 if (ret)
495 return ret;
496
Pierre Ossman6b174932008-06-30 09:09:27 +0200497 sg_init_one(&sg, test->buffer, 512);
498
499 ret = mmc_test_simple_transfer(test, &sg, 1, 0, 1, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200500 if (ret)
501 return ret;
502
503 return 0;
504}
505
506static int mmc_test_verify_write(struct mmc_test_card *test)
507{
508 int ret;
Pierre Ossman6b174932008-06-30 09:09:27 +0200509 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200510
Pierre Ossman6b174932008-06-30 09:09:27 +0200511 sg_init_one(&sg, test->buffer, 512);
512
513 ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200514 if (ret)
515 return ret;
516
517 return 0;
518}
519
520static int mmc_test_verify_read(struct mmc_test_card *test)
521{
522 int ret;
Pierre Ossman6b174932008-06-30 09:09:27 +0200523 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200524
Pierre Ossman6b174932008-06-30 09:09:27 +0200525 sg_init_one(&sg, test->buffer, 512);
526
527 ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200528 if (ret)
529 return ret;
530
531 return 0;
532}
533
534static int mmc_test_multi_write(struct mmc_test_card *test)
535{
536 int ret;
537 unsigned int size;
Pierre Ossman6b174932008-06-30 09:09:27 +0200538 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200539
540 if (test->card->host->max_blk_count == 1)
541 return RESULT_UNSUP_HOST;
542
543 size = PAGE_SIZE * 2;
544 size = min(size, test->card->host->max_req_size);
545 size = min(size, test->card->host->max_seg_size);
546 size = min(size, test->card->host->max_blk_count * 512);
547
548 if (size < 1024)
549 return RESULT_UNSUP_HOST;
550
Pierre Ossman6b174932008-06-30 09:09:27 +0200551 sg_init_one(&sg, test->buffer, size);
552
553 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200554 if (ret)
555 return ret;
556
557 return 0;
558}
559
560static int mmc_test_multi_read(struct mmc_test_card *test)
561{
562 int ret;
563 unsigned int size;
Pierre Ossman6b174932008-06-30 09:09:27 +0200564 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200565
566 if (test->card->host->max_blk_count == 1)
567 return RESULT_UNSUP_HOST;
568
569 size = PAGE_SIZE * 2;
570 size = min(size, test->card->host->max_req_size);
571 size = min(size, test->card->host->max_seg_size);
572 size = min(size, test->card->host->max_blk_count * 512);
573
574 if (size < 1024)
575 return RESULT_UNSUP_HOST;
576
Pierre Ossman6b174932008-06-30 09:09:27 +0200577 sg_init_one(&sg, test->buffer, size);
578
579 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200580 if (ret)
581 return ret;
582
583 return 0;
584}
585
586static int mmc_test_pow2_write(struct mmc_test_card *test)
587{
588 int ret, i;
Pierre Ossman6b174932008-06-30 09:09:27 +0200589 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200590
591 if (!test->card->csd.write_partial)
592 return RESULT_UNSUP_CARD;
593
594 for (i = 1; i < 512;i <<= 1) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200595 sg_init_one(&sg, test->buffer, i);
596 ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200597 if (ret)
598 return ret;
599 }
600
601 return 0;
602}
603
604static int mmc_test_pow2_read(struct mmc_test_card *test)
605{
606 int ret, i;
Pierre Ossman6b174932008-06-30 09:09:27 +0200607 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200608
609 if (!test->card->csd.read_partial)
610 return RESULT_UNSUP_CARD;
611
612 for (i = 1; i < 512;i <<= 1) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200613 sg_init_one(&sg, test->buffer, i);
614 ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200615 if (ret)
616 return ret;
617 }
618
619 return 0;
620}
621
622static int mmc_test_weird_write(struct mmc_test_card *test)
623{
624 int ret, i;
Pierre Ossman6b174932008-06-30 09:09:27 +0200625 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200626
627 if (!test->card->csd.write_partial)
628 return RESULT_UNSUP_CARD;
629
630 for (i = 3; i < 512;i += 7) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200631 sg_init_one(&sg, test->buffer, i);
632 ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200633 if (ret)
634 return ret;
635 }
636
637 return 0;
638}
639
640static int mmc_test_weird_read(struct mmc_test_card *test)
641{
642 int ret, i;
Pierre Ossman6b174932008-06-30 09:09:27 +0200643 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200644
645 if (!test->card->csd.read_partial)
646 return RESULT_UNSUP_CARD;
647
648 for (i = 3; i < 512;i += 7) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200649 sg_init_one(&sg, test->buffer, i);
650 ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200651 if (ret)
652 return ret;
653 }
654
655 return 0;
656}
657
658static int mmc_test_align_write(struct mmc_test_card *test)
659{
660 int ret, i;
Pierre Ossman6b174932008-06-30 09:09:27 +0200661 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200662
663 for (i = 1;i < 4;i++) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200664 sg_init_one(&sg, test->buffer + i, 512);
665 ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200666 if (ret)
667 return ret;
668 }
669
670 return 0;
671}
672
673static int mmc_test_align_read(struct mmc_test_card *test)
674{
675 int ret, i;
Pierre Ossman6b174932008-06-30 09:09:27 +0200676 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200677
678 for (i = 1;i < 4;i++) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200679 sg_init_one(&sg, test->buffer + i, 512);
680 ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200681 if (ret)
682 return ret;
683 }
684
685 return 0;
686}
687
688static int mmc_test_align_multi_write(struct mmc_test_card *test)
689{
690 int ret, i;
691 unsigned int size;
Pierre Ossman6b174932008-06-30 09:09:27 +0200692 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200693
694 if (test->card->host->max_blk_count == 1)
695 return RESULT_UNSUP_HOST;
696
697 size = PAGE_SIZE * 2;
698 size = min(size, test->card->host->max_req_size);
699 size = min(size, test->card->host->max_seg_size);
700 size = min(size, test->card->host->max_blk_count * 512);
701
702 if (size < 1024)
703 return RESULT_UNSUP_HOST;
704
705 for (i = 1;i < 4;i++) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200706 sg_init_one(&sg, test->buffer + i, size);
707 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200708 if (ret)
709 return ret;
710 }
711
712 return 0;
713}
714
715static int mmc_test_align_multi_read(struct mmc_test_card *test)
716{
717 int ret, i;
718 unsigned int size;
Pierre Ossman6b174932008-06-30 09:09:27 +0200719 struct scatterlist sg;
Pierre Ossman88ae6002007-08-12 14:23:50 +0200720
721 if (test->card->host->max_blk_count == 1)
722 return RESULT_UNSUP_HOST;
723
724 size = PAGE_SIZE * 2;
725 size = min(size, test->card->host->max_req_size);
726 size = min(size, test->card->host->max_seg_size);
727 size = min(size, test->card->host->max_blk_count * 512);
728
729 if (size < 1024)
730 return RESULT_UNSUP_HOST;
731
732 for (i = 1;i < 4;i++) {
Pierre Ossman6b174932008-06-30 09:09:27 +0200733 sg_init_one(&sg, test->buffer + i, size);
734 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200735 if (ret)
736 return ret;
737 }
738
739 return 0;
740}
741
742static int mmc_test_xfersize_write(struct mmc_test_card *test)
743{
744 int ret;
745
746 ret = mmc_test_set_blksize(test, 512);
747 if (ret)
748 return ret;
749
Pierre Ossman6b174932008-06-30 09:09:27 +0200750 ret = mmc_test_broken_transfer(test, 1, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200751 if (ret)
752 return ret;
753
754 return 0;
755}
756
757static int mmc_test_xfersize_read(struct mmc_test_card *test)
758{
759 int ret;
760
761 ret = mmc_test_set_blksize(test, 512);
762 if (ret)
763 return ret;
764
Pierre Ossman6b174932008-06-30 09:09:27 +0200765 ret = mmc_test_broken_transfer(test, 1, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200766 if (ret)
767 return ret;
768
769 return 0;
770}
771
772static int mmc_test_multi_xfersize_write(struct mmc_test_card *test)
773{
774 int ret;
775
776 if (test->card->host->max_blk_count == 1)
777 return RESULT_UNSUP_HOST;
778
779 ret = mmc_test_set_blksize(test, 512);
780 if (ret)
781 return ret;
782
Pierre Ossman6b174932008-06-30 09:09:27 +0200783 ret = mmc_test_broken_transfer(test, 2, 512, 1);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200784 if (ret)
785 return ret;
786
787 return 0;
788}
789
790static int mmc_test_multi_xfersize_read(struct mmc_test_card *test)
791{
792 int ret;
793
794 if (test->card->host->max_blk_count == 1)
795 return RESULT_UNSUP_HOST;
796
797 ret = mmc_test_set_blksize(test, 512);
798 if (ret)
799 return ret;
800
Pierre Ossman6b174932008-06-30 09:09:27 +0200801 ret = mmc_test_broken_transfer(test, 2, 512, 0);
Pierre Ossman88ae6002007-08-12 14:23:50 +0200802 if (ret)
803 return ret;
804
805 return 0;
806}
807
Pierre Ossman48b53522008-07-21 00:14:52 +0200808static int mmc_test_bigsg_write(struct mmc_test_card *test)
809{
810 int ret;
811 unsigned int size;
812 struct scatterlist sg;
813
814 if (test->card->host->max_blk_count == 1)
815 return RESULT_UNSUP_HOST;
816
817 size = PAGE_SIZE * 2;
818 size = min(size, test->card->host->max_req_size);
819 size = min(size, test->card->host->max_seg_size);
820 size = min(size, test->card->host->max_blk_count * 512);
821
822 memset(test->buffer, 0, BUFFER_SIZE);
823
824 if (size < 1024)
825 return RESULT_UNSUP_HOST;
826
827 sg_init_table(&sg, 1);
828 sg_init_one(&sg, test->buffer, BUFFER_SIZE);
829
830 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
831 if (ret)
832 return ret;
833
834 return 0;
835}
836
837static int mmc_test_bigsg_read(struct mmc_test_card *test)
838{
839 int ret, i;
840 unsigned int size;
841 struct scatterlist sg;
842
843 if (test->card->host->max_blk_count == 1)
844 return RESULT_UNSUP_HOST;
845
846 size = PAGE_SIZE * 2;
847 size = min(size, test->card->host->max_req_size);
848 size = min(size, test->card->host->max_seg_size);
849 size = min(size, test->card->host->max_blk_count * 512);
850
851 if (size < 1024)
852 return RESULT_UNSUP_HOST;
853
854 memset(test->buffer, 0xCD, BUFFER_SIZE);
855
856 sg_init_table(&sg, 1);
857 sg_init_one(&sg, test->buffer, BUFFER_SIZE);
858 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
859 if (ret)
860 return ret;
861
862 /* mmc_test_transfer() doesn't check for read overflows */
863 for (i = size;i < BUFFER_SIZE;i++) {
864 if (test->buffer[i] != 0xCD)
865 return RESULT_FAIL;
866 }
867
868 return 0;
869}
870
Pierre Ossman26610812008-07-04 18:17:13 +0200871#ifdef CONFIG_HIGHMEM
872
873static int mmc_test_write_high(struct mmc_test_card *test)
874{
875 int ret;
876 struct scatterlist sg;
877
878 sg_init_table(&sg, 1);
879 sg_set_page(&sg, test->highmem, 512, 0);
880
881 ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1);
882 if (ret)
883 return ret;
884
885 return 0;
886}
887
888static int mmc_test_read_high(struct mmc_test_card *test)
889{
890 int ret;
891 struct scatterlist sg;
892
893 sg_init_table(&sg, 1);
894 sg_set_page(&sg, test->highmem, 512, 0);
895
896 ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0);
897 if (ret)
898 return ret;
899
900 return 0;
901}
902
903static int mmc_test_multi_write_high(struct mmc_test_card *test)
904{
905 int ret;
906 unsigned int size;
907 struct scatterlist sg;
908
909 if (test->card->host->max_blk_count == 1)
910 return RESULT_UNSUP_HOST;
911
912 size = PAGE_SIZE * 2;
913 size = min(size, test->card->host->max_req_size);
914 size = min(size, test->card->host->max_seg_size);
915 size = min(size, test->card->host->max_blk_count * 512);
916
917 if (size < 1024)
918 return RESULT_UNSUP_HOST;
919
920 sg_init_table(&sg, 1);
921 sg_set_page(&sg, test->highmem, size, 0);
922
923 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
924 if (ret)
925 return ret;
926
927 return 0;
928}
929
930static int mmc_test_multi_read_high(struct mmc_test_card *test)
931{
932 int ret;
933 unsigned int size;
934 struct scatterlist sg;
935
936 if (test->card->host->max_blk_count == 1)
937 return RESULT_UNSUP_HOST;
938
939 size = PAGE_SIZE * 2;
940 size = min(size, test->card->host->max_req_size);
941 size = min(size, test->card->host->max_seg_size);
942 size = min(size, test->card->host->max_blk_count * 512);
943
944 if (size < 1024)
945 return RESULT_UNSUP_HOST;
946
947 sg_init_table(&sg, 1);
948 sg_set_page(&sg, test->highmem, size, 0);
949
950 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
951 if (ret)
952 return ret;
953
954 return 0;
955}
956
957#endif /* CONFIG_HIGHMEM */
958
Pierre Ossman88ae6002007-08-12 14:23:50 +0200959static const struct mmc_test_case mmc_test_cases[] = {
960 {
961 .name = "Basic write (no data verification)",
962 .run = mmc_test_basic_write,
963 },
964
965 {
966 .name = "Basic read (no data verification)",
967 .run = mmc_test_basic_read,
968 },
969
970 {
971 .name = "Basic write (with data verification)",
Pierre Ossman6b174932008-06-30 09:09:27 +0200972 .prepare = mmc_test_prepare_write,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200973 .run = mmc_test_verify_write,
Pierre Ossman6b174932008-06-30 09:09:27 +0200974 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200975 },
976
977 {
978 .name = "Basic read (with data verification)",
Pierre Ossman6b174932008-06-30 09:09:27 +0200979 .prepare = mmc_test_prepare_read,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200980 .run = mmc_test_verify_read,
Pierre Ossman6b174932008-06-30 09:09:27 +0200981 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200982 },
983
984 {
985 .name = "Multi-block write",
Pierre Ossman6b174932008-06-30 09:09:27 +0200986 .prepare = mmc_test_prepare_write,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200987 .run = mmc_test_multi_write,
Pierre Ossman6b174932008-06-30 09:09:27 +0200988 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200989 },
990
991 {
992 .name = "Multi-block read",
Pierre Ossman6b174932008-06-30 09:09:27 +0200993 .prepare = mmc_test_prepare_read,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200994 .run = mmc_test_multi_read,
Pierre Ossman6b174932008-06-30 09:09:27 +0200995 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +0200996 },
997
998 {
999 .name = "Power of two block writes",
Pierre Ossman6b174932008-06-30 09:09:27 +02001000 .prepare = mmc_test_prepare_write,
Pierre Ossman88ae6002007-08-12 14:23:50 +02001001 .run = mmc_test_pow2_write,
Pierre Ossman6b174932008-06-30 09:09:27 +02001002 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +02001003 },
1004
1005 {
1006 .name = "Power of two block reads",
Pierre Ossman6b174932008-06-30 09:09:27 +02001007 .prepare = mmc_test_prepare_read,
Pierre Ossman88ae6002007-08-12 14:23:50 +02001008 .run = mmc_test_pow2_read,
Pierre Ossman6b174932008-06-30 09:09:27 +02001009 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +02001010 },
1011
1012 {
1013 .name = "Weird sized block writes",
Pierre Ossman6b174932008-06-30 09:09:27 +02001014 .prepare = mmc_test_prepare_write,
Pierre Ossman88ae6002007-08-12 14:23:50 +02001015 .run = mmc_test_weird_write,
Pierre Ossman6b174932008-06-30 09:09:27 +02001016 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +02001017 },
1018
1019 {
1020 .name = "Weird sized block reads",
Pierre Ossman6b174932008-06-30 09:09:27 +02001021 .prepare = mmc_test_prepare_read,
Pierre Ossman88ae6002007-08-12 14:23:50 +02001022 .run = mmc_test_weird_read,
Pierre Ossman6b174932008-06-30 09:09:27 +02001023 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +02001024 },
1025
1026 {
1027 .name = "Badly aligned write",
Pierre Ossman6b174932008-06-30 09:09:27 +02001028 .prepare = mmc_test_prepare_write,
Pierre Ossman88ae6002007-08-12 14:23:50 +02001029 .run = mmc_test_align_write,
Pierre Ossman6b174932008-06-30 09:09:27 +02001030 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +02001031 },
1032
1033 {
1034 .name = "Badly aligned read",
Pierre Ossman6b174932008-06-30 09:09:27 +02001035 .prepare = mmc_test_prepare_read,
Pierre Ossman88ae6002007-08-12 14:23:50 +02001036 .run = mmc_test_align_read,
Pierre Ossman6b174932008-06-30 09:09:27 +02001037 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +02001038 },
1039
1040 {
1041 .name = "Badly aligned multi-block write",
Pierre Ossman6b174932008-06-30 09:09:27 +02001042 .prepare = mmc_test_prepare_write,
Pierre Ossman88ae6002007-08-12 14:23:50 +02001043 .run = mmc_test_align_multi_write,
Pierre Ossman6b174932008-06-30 09:09:27 +02001044 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +02001045 },
1046
1047 {
1048 .name = "Badly aligned multi-block read",
Pierre Ossman6b174932008-06-30 09:09:27 +02001049 .prepare = mmc_test_prepare_read,
Pierre Ossman88ae6002007-08-12 14:23:50 +02001050 .run = mmc_test_align_multi_read,
Pierre Ossman6b174932008-06-30 09:09:27 +02001051 .cleanup = mmc_test_cleanup,
Pierre Ossman88ae6002007-08-12 14:23:50 +02001052 },
1053
1054 {
1055 .name = "Correct xfer_size at write (start failure)",
1056 .run = mmc_test_xfersize_write,
1057 },
1058
1059 {
1060 .name = "Correct xfer_size at read (start failure)",
1061 .run = mmc_test_xfersize_read,
1062 },
1063
1064 {
1065 .name = "Correct xfer_size at write (midway failure)",
1066 .run = mmc_test_multi_xfersize_write,
1067 },
1068
1069 {
1070 .name = "Correct xfer_size at read (midway failure)",
1071 .run = mmc_test_multi_xfersize_read,
1072 },
Pierre Ossman26610812008-07-04 18:17:13 +02001073
Pierre Ossman48b53522008-07-21 00:14:52 +02001074 {
1075 .name = "Over-sized SG list write",
1076 .prepare = mmc_test_prepare_write,
1077 .run = mmc_test_bigsg_write,
1078 .cleanup = mmc_test_cleanup,
1079 },
1080
1081 {
1082 .name = "Over-sized SG list read",
1083 .prepare = mmc_test_prepare_read,
1084 .run = mmc_test_bigsg_read,
1085 .cleanup = mmc_test_cleanup,
1086 },
1087
Pierre Ossman26610812008-07-04 18:17:13 +02001088#ifdef CONFIG_HIGHMEM
1089
1090 {
1091 .name = "Highmem write",
1092 .prepare = mmc_test_prepare_write,
1093 .run = mmc_test_write_high,
1094 .cleanup = mmc_test_cleanup,
1095 },
1096
1097 {
1098 .name = "Highmem read",
1099 .prepare = mmc_test_prepare_read,
1100 .run = mmc_test_read_high,
1101 .cleanup = mmc_test_cleanup,
1102 },
1103
1104 {
1105 .name = "Multi-block highmem write",
1106 .prepare = mmc_test_prepare_write,
1107 .run = mmc_test_multi_write_high,
1108 .cleanup = mmc_test_cleanup,
1109 },
1110
1111 {
1112 .name = "Multi-block highmem read",
1113 .prepare = mmc_test_prepare_read,
1114 .run = mmc_test_multi_read_high,
1115 .cleanup = mmc_test_cleanup,
1116 },
1117
1118#endif /* CONFIG_HIGHMEM */
1119
Pierre Ossman88ae6002007-08-12 14:23:50 +02001120};
1121
1122static struct mutex mmc_test_lock;
1123
Pierre Ossmanfd8c3262008-05-24 22:36:31 +02001124static void mmc_test_run(struct mmc_test_card *test, int testcase)
Pierre Ossman88ae6002007-08-12 14:23:50 +02001125{
1126 int i, ret;
1127
1128 printk(KERN_INFO "%s: Starting tests of card %s...\n",
1129 mmc_hostname(test->card->host), mmc_card_id(test->card));
1130
1131 mmc_claim_host(test->card->host);
1132
1133 for (i = 0;i < ARRAY_SIZE(mmc_test_cases);i++) {
Pierre Ossmanfd8c3262008-05-24 22:36:31 +02001134 if (testcase && ((i + 1) != testcase))
1135 continue;
1136
Pierre Ossman88ae6002007-08-12 14:23:50 +02001137 printk(KERN_INFO "%s: Test case %d. %s...\n",
1138 mmc_hostname(test->card->host), i + 1,
1139 mmc_test_cases[i].name);
1140
1141 if (mmc_test_cases[i].prepare) {
1142 ret = mmc_test_cases[i].prepare(test);
1143 if (ret) {
1144 printk(KERN_INFO "%s: Result: Prepare "
1145 "stage failed! (%d)\n",
1146 mmc_hostname(test->card->host),
1147 ret);
1148 continue;
1149 }
1150 }
1151
1152 ret = mmc_test_cases[i].run(test);
1153 switch (ret) {
1154 case RESULT_OK:
1155 printk(KERN_INFO "%s: Result: OK\n",
1156 mmc_hostname(test->card->host));
1157 break;
1158 case RESULT_FAIL:
1159 printk(KERN_INFO "%s: Result: FAILED\n",
1160 mmc_hostname(test->card->host));
1161 break;
1162 case RESULT_UNSUP_HOST:
1163 printk(KERN_INFO "%s: Result: UNSUPPORTED "
1164 "(by host)\n",
1165 mmc_hostname(test->card->host));
1166 break;
1167 case RESULT_UNSUP_CARD:
1168 printk(KERN_INFO "%s: Result: UNSUPPORTED "
1169 "(by card)\n",
1170 mmc_hostname(test->card->host));
1171 break;
1172 default:
1173 printk(KERN_INFO "%s: Result: ERROR (%d)\n",
1174 mmc_hostname(test->card->host), ret);
1175 }
1176
1177 if (mmc_test_cases[i].cleanup) {
1178 ret = mmc_test_cases[i].cleanup(test);
1179 if (ret) {
1180 printk(KERN_INFO "%s: Warning: Cleanup "
1181 "stage failed! (%d)\n",
1182 mmc_hostname(test->card->host),
1183 ret);
1184 }
1185 }
1186 }
1187
1188 mmc_release_host(test->card->host);
1189
1190 printk(KERN_INFO "%s: Tests completed.\n",
1191 mmc_hostname(test->card->host));
1192}
1193
1194static ssize_t mmc_test_show(struct device *dev,
1195 struct device_attribute *attr, char *buf)
1196{
1197 mutex_lock(&mmc_test_lock);
1198 mutex_unlock(&mmc_test_lock);
1199
1200 return 0;
1201}
1202
1203static ssize_t mmc_test_store(struct device *dev,
1204 struct device_attribute *attr, const char *buf, size_t count)
1205{
1206 struct mmc_card *card;
1207 struct mmc_test_card *test;
Pierre Ossmanfd8c3262008-05-24 22:36:31 +02001208 int testcase;
Pierre Ossman88ae6002007-08-12 14:23:50 +02001209
1210 card = container_of(dev, struct mmc_card, dev);
1211
Pierre Ossmanfd8c3262008-05-24 22:36:31 +02001212 testcase = simple_strtol(buf, NULL, 10);
1213
Pierre Ossman88ae6002007-08-12 14:23:50 +02001214 test = kzalloc(sizeof(struct mmc_test_card), GFP_KERNEL);
1215 if (!test)
1216 return -ENOMEM;
1217
1218 test->card = card;
1219
1220 test->buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL);
Pierre Ossman26610812008-07-04 18:17:13 +02001221#ifdef CONFIG_HIGHMEM
1222 test->highmem = alloc_pages(GFP_KERNEL | __GFP_HIGHMEM, BUFFER_ORDER);
1223#endif
1224
1225#ifdef CONFIG_HIGHMEM
1226 if (test->buffer && test->highmem) {
1227#else
Pierre Ossman88ae6002007-08-12 14:23:50 +02001228 if (test->buffer) {
Pierre Ossman26610812008-07-04 18:17:13 +02001229#endif
Pierre Ossman88ae6002007-08-12 14:23:50 +02001230 mutex_lock(&mmc_test_lock);
Pierre Ossmanfd8c3262008-05-24 22:36:31 +02001231 mmc_test_run(test, testcase);
Pierre Ossman88ae6002007-08-12 14:23:50 +02001232 mutex_unlock(&mmc_test_lock);
1233 }
1234
Pierre Ossman26610812008-07-04 18:17:13 +02001235#ifdef CONFIG_HIGHMEM
1236 __free_pages(test->highmem, BUFFER_ORDER);
1237#endif
Pierre Ossman88ae6002007-08-12 14:23:50 +02001238 kfree(test->buffer);
1239 kfree(test);
1240
1241 return count;
1242}
1243
1244static DEVICE_ATTR(test, S_IWUSR | S_IRUGO, mmc_test_show, mmc_test_store);
1245
1246static int mmc_test_probe(struct mmc_card *card)
1247{
1248 int ret;
1249
Pierre Ossman0121a982008-06-28 17:51:27 +02001250 if ((card->type != MMC_TYPE_MMC) && (card->type != MMC_TYPE_SD))
1251 return -ENODEV;
1252
Pierre Ossman88ae6002007-08-12 14:23:50 +02001253 mutex_init(&mmc_test_lock);
1254
1255 ret = device_create_file(&card->dev, &dev_attr_test);
1256 if (ret)
1257 return ret;
1258
Pierre Ossman60c9c7b2008-07-22 14:38:35 +02001259 dev_info(&card->dev, "Card claimed for testing.\n");
1260
Pierre Ossman88ae6002007-08-12 14:23:50 +02001261 return 0;
1262}
1263
1264static void mmc_test_remove(struct mmc_card *card)
1265{
1266 device_remove_file(&card->dev, &dev_attr_test);
1267}
1268
1269static struct mmc_driver mmc_driver = {
1270 .drv = {
1271 .name = "mmc_test",
1272 },
1273 .probe = mmc_test_probe,
1274 .remove = mmc_test_remove,
1275};
1276
1277static int __init mmc_test_init(void)
1278{
1279 return mmc_register_driver(&mmc_driver);
1280}
1281
1282static void __exit mmc_test_exit(void)
1283{
1284 mmc_unregister_driver(&mmc_driver);
1285}
1286
1287module_init(mmc_test_init);
1288module_exit(mmc_test_exit);
1289
1290MODULE_LICENSE("GPL");
1291MODULE_DESCRIPTION("Multimedia Card (MMC) host test driver");
1292MODULE_AUTHOR("Pierre Ossman");