Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mmc: mmc host test driver

A dummy driver that performs a series of requests that are often mis-
handled by host drivers.

Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

+905
+12
drivers/mmc/card/Kconfig
··· 39 39 SDIO function driver for SDIO cards that implements the UART 40 40 class, as well as the GPS class which appears like a UART. 41 41 42 + config MMC_TEST 43 + tristate "MMC host test driver" 44 + default n 45 + help 46 + Development driver that performs a series of reads and writes 47 + to a memory card in order to expose certain well known bugs 48 + in host controllers. The tests are executed by writing to the 49 + "test" file in sysfs under each card. Note that whatever is 50 + on your card will be overwritten by these tests. 51 + 52 + This driver is only of interest to those developing or 53 + testing a host driver. Most people should say N here.
+1
drivers/mmc/card/Makefile
··· 8 8 9 9 obj-$(CONFIG_MMC_BLOCK) += mmc_block.o 10 10 mmc_block-objs := block.o queue.o 11 + obj-$(CONFIG_MMC_TEST) += mmc_test.o 11 12 12 13 obj-$(CONFIG_SDIO_UART) += sdio_uart.o 13 14
+892
drivers/mmc/card/mmc_test.c
··· 1 + /* 2 + * linux/drivers/mmc/card/mmc_test.c 3 + * 4 + * Copyright 2007 Pierre Ossman 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or (at 9 + * your option) any later version. 10 + */ 11 + 12 + #include <linux/mmc/core.h> 13 + #include <linux/mmc/card.h> 14 + #include <linux/mmc/host.h> 15 + #include <linux/mmc/mmc.h> 16 + 17 + #include <linux/scatterlist.h> 18 + 19 + #define RESULT_OK 0 20 + #define RESULT_FAIL 1 21 + #define RESULT_UNSUP_HOST 2 22 + #define RESULT_UNSUP_CARD 3 23 + 24 + #define BUFFER_SIZE (PAGE_SIZE * 4) 25 + 26 + struct mmc_test_card { 27 + struct mmc_card *card; 28 + 29 + u8 *buffer; 30 + }; 31 + 32 + /*******************************************************************/ 33 + /* Helper functions */ 34 + /*******************************************************************/ 35 + 36 + static int mmc_test_set_blksize(struct mmc_test_card *test, unsigned size) 37 + { 38 + struct mmc_command cmd; 39 + int ret; 40 + 41 + cmd.opcode = MMC_SET_BLOCKLEN; 42 + cmd.arg = size; 43 + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; 44 + ret = mmc_wait_for_cmd(test->card->host, &cmd, 0); 45 + if (ret) 46 + return ret; 47 + 48 + return 0; 49 + } 50 + 51 + static int __mmc_test_transfer(struct mmc_test_card *test, int write, 52 + unsigned broken_xfer, u8 *buffer, unsigned addr, 53 + unsigned blocks, unsigned blksz) 54 + { 55 + int ret, busy; 56 + 57 + struct mmc_request mrq; 58 + struct mmc_command cmd; 59 + struct mmc_command stop; 60 + struct mmc_data data; 61 + 62 + struct scatterlist sg; 63 + 64 + memset(&mrq, 0, sizeof(struct mmc_request)); 65 + 66 + mrq.cmd = &cmd; 67 + mrq.data = &data; 68 + 69 + memset(&cmd, 0, sizeof(struct mmc_command)); 70 + 71 + if (broken_xfer) { 72 + if (blocks > 1) { 73 + cmd.opcode = write ? 74 + MMC_WRITE_BLOCK : MMC_READ_SINGLE_BLOCK; 75 + } else { 76 + cmd.opcode = MMC_SEND_STATUS; 77 + } 78 + } else { 79 + if (blocks > 1) { 80 + cmd.opcode = write ? 81 + MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK; 82 + } else { 83 + cmd.opcode = write ? 84 + MMC_WRITE_BLOCK : MMC_READ_SINGLE_BLOCK; 85 + } 86 + } 87 + 88 + if (broken_xfer && blocks == 1) 89 + cmd.arg = test->card->rca << 16; 90 + else 91 + cmd.arg = addr; 92 + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; 93 + 94 + memset(&stop, 0, sizeof(struct mmc_command)); 95 + 96 + if (!broken_xfer && (blocks > 1)) { 97 + stop.opcode = MMC_STOP_TRANSMISSION; 98 + stop.arg = 0; 99 + stop.flags = MMC_RSP_R1B | MMC_CMD_AC; 100 + 101 + mrq.stop = &stop; 102 + } 103 + 104 + memset(&data, 0, sizeof(struct mmc_data)); 105 + 106 + data.blksz = blksz; 107 + data.blocks = blocks; 108 + data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; 109 + data.sg = &sg; 110 + data.sg_len = 1; 111 + 112 + sg_init_one(&sg, buffer, blocks * blksz); 113 + 114 + mmc_set_data_timeout(&data, test->card); 115 + 116 + mmc_wait_for_req(test->card->host, &mrq); 117 + 118 + ret = 0; 119 + 120 + if (broken_xfer) { 121 + if (!ret && cmd.error) 122 + ret = cmd.error; 123 + if (!ret && data.error == 0) 124 + ret = RESULT_FAIL; 125 + if (!ret && data.error != -ETIMEDOUT) 126 + ret = data.error; 127 + if (!ret && stop.error) 128 + ret = stop.error; 129 + if (blocks > 1) { 130 + if (!ret && data.bytes_xfered > blksz) 131 + ret = RESULT_FAIL; 132 + } else { 133 + if (!ret && data.bytes_xfered > 0) 134 + ret = RESULT_FAIL; 135 + } 136 + } else { 137 + if (!ret && cmd.error) 138 + ret = cmd.error; 139 + if (!ret && data.error) 140 + ret = data.error; 141 + if (!ret && stop.error) 142 + ret = stop.error; 143 + if (!ret && data.bytes_xfered != blocks * blksz) 144 + ret = RESULT_FAIL; 145 + } 146 + 147 + if (ret == -EINVAL) 148 + ret = RESULT_UNSUP_HOST; 149 + 150 + busy = 0; 151 + do { 152 + int ret2; 153 + 154 + memset(&cmd, 0, sizeof(struct mmc_command)); 155 + 156 + cmd.opcode = MMC_SEND_STATUS; 157 + cmd.arg = test->card->rca << 16; 158 + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; 159 + 160 + ret2 = mmc_wait_for_cmd(test->card->host, &cmd, 0); 161 + if (ret2) 162 + break; 163 + 164 + if (!busy && !(cmd.resp[0] & R1_READY_FOR_DATA)) { 165 + busy = 1; 166 + printk(KERN_INFO "%s: Warning: Host did not " 167 + "wait for busy state to end.\n", 168 + mmc_hostname(test->card->host)); 169 + } 170 + } while (!(cmd.resp[0] & R1_READY_FOR_DATA)); 171 + 172 + return ret; 173 + } 174 + 175 + static int mmc_test_transfer(struct mmc_test_card *test, int write, 176 + u8 *buffer, unsigned addr, unsigned blocks, unsigned blksz) 177 + { 178 + return __mmc_test_transfer(test, write, 0, buffer, 179 + addr, blocks, blksz); 180 + } 181 + 182 + static int mmc_test_prepare_verify(struct mmc_test_card *test, int write) 183 + { 184 + int ret, i; 185 + 186 + ret = mmc_test_set_blksize(test, 512); 187 + if (ret) 188 + return ret; 189 + 190 + if (write) 191 + memset(test->buffer, 0xDF, BUFFER_SIZE); 192 + else { 193 + for (i = 0;i < BUFFER_SIZE;i++) 194 + test->buffer[i] = i; 195 + } 196 + 197 + for (i = 0;i < BUFFER_SIZE / 512;i++) { 198 + ret = mmc_test_transfer(test, 1, test->buffer + i * 512, 199 + i * 512, 1, 512); 200 + if (ret) 201 + return ret; 202 + } 203 + 204 + return 0; 205 + } 206 + 207 + static int mmc_test_prepare_verify_write(struct mmc_test_card *test) 208 + { 209 + return mmc_test_prepare_verify(test, 1); 210 + } 211 + 212 + static int mmc_test_prepare_verify_read(struct mmc_test_card *test) 213 + { 214 + return mmc_test_prepare_verify(test, 0); 215 + } 216 + 217 + static int mmc_test_verified_transfer(struct mmc_test_card *test, int write, 218 + u8 *buffer, unsigned addr, unsigned blocks, unsigned blksz) 219 + { 220 + int ret, i, sectors; 221 + 222 + /* 223 + * It is assumed that the above preparation has been done. 224 + */ 225 + 226 + memset(test->buffer, 0, BUFFER_SIZE); 227 + 228 + if (write) { 229 + for (i = 0;i < blocks * blksz;i++) 230 + buffer[i] = i; 231 + } 232 + 233 + ret = mmc_test_set_blksize(test, blksz); 234 + if (ret) 235 + return ret; 236 + 237 + ret = mmc_test_transfer(test, write, buffer, addr, blocks, blksz); 238 + if (ret) 239 + return ret; 240 + 241 + if (write) { 242 + ret = mmc_test_set_blksize(test, 512); 243 + if (ret) 244 + return ret; 245 + 246 + sectors = (blocks * blksz + 511) / 512; 247 + if ((sectors * 512) == (blocks * blksz)) 248 + sectors++; 249 + 250 + if ((sectors * 512) > BUFFER_SIZE) 251 + return -EINVAL; 252 + 253 + memset(test->buffer, 0, sectors * 512); 254 + 255 + for (i = 0;i < sectors;i++) { 256 + ret = mmc_test_transfer(test, 0, 257 + test->buffer + i * 512, 258 + addr + i * 512, 1, 512); 259 + if (ret) 260 + return ret; 261 + } 262 + 263 + for (i = 0;i < blocks * blksz;i++) { 264 + if (test->buffer[i] != (u8)i) 265 + return RESULT_FAIL; 266 + } 267 + 268 + for (;i < sectors * 512;i++) { 269 + if (test->buffer[i] != 0xDF) 270 + return RESULT_FAIL; 271 + } 272 + } else { 273 + for (i = 0;i < blocks * blksz;i++) { 274 + if (buffer[i] != (u8)i) 275 + return RESULT_FAIL; 276 + } 277 + } 278 + 279 + return 0; 280 + } 281 + 282 + static int mmc_test_cleanup_verify(struct mmc_test_card *test) 283 + { 284 + int ret, i; 285 + 286 + ret = mmc_test_set_blksize(test, 512); 287 + if (ret) 288 + return ret; 289 + 290 + memset(test->buffer, 0, BUFFER_SIZE); 291 + 292 + for (i = 0;i < BUFFER_SIZE / 512;i++) { 293 + ret = mmc_test_transfer(test, 1, test->buffer + i * 512, 294 + i * 512, 1, 512); 295 + if (ret) 296 + return ret; 297 + } 298 + 299 + return 0; 300 + } 301 + 302 + /*******************************************************************/ 303 + /* Tests */ 304 + /*******************************************************************/ 305 + 306 + struct mmc_test_case { 307 + const char *name; 308 + 309 + int (*prepare)(struct mmc_test_card *); 310 + int (*run)(struct mmc_test_card *); 311 + int (*cleanup)(struct mmc_test_card *); 312 + }; 313 + 314 + static int mmc_test_basic_write(struct mmc_test_card *test) 315 + { 316 + int ret; 317 + 318 + ret = mmc_test_set_blksize(test, 512); 319 + if (ret) 320 + return ret; 321 + 322 + ret = mmc_test_transfer(test, 1, test->buffer, 0, 1, 512); 323 + if (ret) 324 + return ret; 325 + 326 + return 0; 327 + } 328 + 329 + static int mmc_test_basic_read(struct mmc_test_card *test) 330 + { 331 + int ret; 332 + 333 + ret = mmc_test_set_blksize(test, 512); 334 + if (ret) 335 + return ret; 336 + 337 + ret = mmc_test_transfer(test, 0, test->buffer, 0, 1, 512); 338 + if (ret) 339 + return ret; 340 + 341 + return 0; 342 + } 343 + 344 + static int mmc_test_verify_write(struct mmc_test_card *test) 345 + { 346 + int ret; 347 + 348 + ret = mmc_test_verified_transfer(test, 1, test->buffer, 0, 1, 512); 349 + if (ret) 350 + return ret; 351 + 352 + return 0; 353 + } 354 + 355 + static int mmc_test_verify_read(struct mmc_test_card *test) 356 + { 357 + int ret; 358 + 359 + ret = mmc_test_verified_transfer(test, 0, test->buffer, 0, 1, 512); 360 + if (ret) 361 + return ret; 362 + 363 + return 0; 364 + } 365 + 366 + static int mmc_test_multi_write(struct mmc_test_card *test) 367 + { 368 + int ret; 369 + unsigned int size; 370 + 371 + if (test->card->host->max_blk_count == 1) 372 + return RESULT_UNSUP_HOST; 373 + 374 + size = PAGE_SIZE * 2; 375 + size = min(size, test->card->host->max_req_size); 376 + size = min(size, test->card->host->max_seg_size); 377 + size = min(size, test->card->host->max_blk_count * 512); 378 + 379 + if (size < 1024) 380 + return RESULT_UNSUP_HOST; 381 + 382 + ret = mmc_test_verified_transfer(test, 1, test->buffer, 0, 383 + size / 512, 512); 384 + if (ret) 385 + return ret; 386 + 387 + return 0; 388 + } 389 + 390 + static int mmc_test_multi_read(struct mmc_test_card *test) 391 + { 392 + int ret; 393 + unsigned int size; 394 + 395 + if (test->card->host->max_blk_count == 1) 396 + return RESULT_UNSUP_HOST; 397 + 398 + size = PAGE_SIZE * 2; 399 + size = min(size, test->card->host->max_req_size); 400 + size = min(size, test->card->host->max_seg_size); 401 + size = min(size, test->card->host->max_blk_count * 512); 402 + 403 + if (size < 1024) 404 + return RESULT_UNSUP_HOST; 405 + 406 + ret = mmc_test_verified_transfer(test, 0, test->buffer, 0, 407 + size / 512, 512); 408 + if (ret) 409 + return ret; 410 + 411 + return 0; 412 + } 413 + 414 + static int mmc_test_pow2_write(struct mmc_test_card *test) 415 + { 416 + int ret, i; 417 + 418 + if (!test->card->csd.write_partial) 419 + return RESULT_UNSUP_CARD; 420 + 421 + for (i = 1; i < 512;i <<= 1) { 422 + ret = mmc_test_verified_transfer(test, 1, 423 + test->buffer, 0, 1, i); 424 + if (ret) 425 + return ret; 426 + } 427 + 428 + return 0; 429 + } 430 + 431 + static int mmc_test_pow2_read(struct mmc_test_card *test) 432 + { 433 + int ret, i; 434 + 435 + if (!test->card->csd.read_partial) 436 + return RESULT_UNSUP_CARD; 437 + 438 + for (i = 1; i < 512;i <<= 1) { 439 + ret = mmc_test_verified_transfer(test, 0, 440 + test->buffer, 0, 1, i); 441 + if (ret) 442 + return ret; 443 + } 444 + 445 + return 0; 446 + } 447 + 448 + static int mmc_test_weird_write(struct mmc_test_card *test) 449 + { 450 + int ret, i; 451 + 452 + if (!test->card->csd.write_partial) 453 + return RESULT_UNSUP_CARD; 454 + 455 + for (i = 3; i < 512;i += 7) { 456 + ret = mmc_test_verified_transfer(test, 1, 457 + test->buffer, 0, 1, i); 458 + if (ret) 459 + return ret; 460 + } 461 + 462 + return 0; 463 + } 464 + 465 + static int mmc_test_weird_read(struct mmc_test_card *test) 466 + { 467 + int ret, i; 468 + 469 + if (!test->card->csd.read_partial) 470 + return RESULT_UNSUP_CARD; 471 + 472 + for (i = 3; i < 512;i += 7) { 473 + ret = mmc_test_verified_transfer(test, 0, 474 + test->buffer, 0, 1, i); 475 + if (ret) 476 + return ret; 477 + } 478 + 479 + return 0; 480 + } 481 + 482 + static int mmc_test_align_write(struct mmc_test_card *test) 483 + { 484 + int ret, i; 485 + 486 + for (i = 1;i < 4;i++) { 487 + ret = mmc_test_verified_transfer(test, 1, test->buffer + i, 488 + 0, 1, 512); 489 + if (ret) 490 + return ret; 491 + } 492 + 493 + return 0; 494 + } 495 + 496 + static int mmc_test_align_read(struct mmc_test_card *test) 497 + { 498 + int ret, i; 499 + 500 + for (i = 1;i < 4;i++) { 501 + ret = mmc_test_verified_transfer(test, 0, test->buffer + i, 502 + 0, 1, 512); 503 + if (ret) 504 + return ret; 505 + } 506 + 507 + return 0; 508 + } 509 + 510 + static int mmc_test_align_multi_write(struct mmc_test_card *test) 511 + { 512 + int ret, i; 513 + unsigned int size; 514 + 515 + if (test->card->host->max_blk_count == 1) 516 + return RESULT_UNSUP_HOST; 517 + 518 + size = PAGE_SIZE * 2; 519 + size = min(size, test->card->host->max_req_size); 520 + size = min(size, test->card->host->max_seg_size); 521 + size = min(size, test->card->host->max_blk_count * 512); 522 + 523 + if (size < 1024) 524 + return RESULT_UNSUP_HOST; 525 + 526 + for (i = 1;i < 4;i++) { 527 + ret = mmc_test_verified_transfer(test, 1, test->buffer + i, 528 + 0, size / 512, 512); 529 + if (ret) 530 + return ret; 531 + } 532 + 533 + return 0; 534 + } 535 + 536 + static int mmc_test_align_multi_read(struct mmc_test_card *test) 537 + { 538 + int ret, i; 539 + unsigned int size; 540 + 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 + 552 + for (i = 1;i < 4;i++) { 553 + ret = mmc_test_verified_transfer(test, 0, test->buffer + i, 554 + 0, size / 512, 512); 555 + if (ret) 556 + return ret; 557 + } 558 + 559 + return 0; 560 + } 561 + 562 + static int mmc_test_xfersize_write(struct mmc_test_card *test) 563 + { 564 + int ret; 565 + 566 + ret = mmc_test_set_blksize(test, 512); 567 + if (ret) 568 + return ret; 569 + 570 + ret = __mmc_test_transfer(test, 1, 1, test->buffer, 0, 1, 512); 571 + if (ret) 572 + return ret; 573 + 574 + return 0; 575 + } 576 + 577 + static int mmc_test_xfersize_read(struct mmc_test_card *test) 578 + { 579 + int ret; 580 + 581 + ret = mmc_test_set_blksize(test, 512); 582 + if (ret) 583 + return ret; 584 + 585 + ret = __mmc_test_transfer(test, 0, 1, test->buffer, 0, 1, 512); 586 + if (ret) 587 + return ret; 588 + 589 + return 0; 590 + } 591 + 592 + static int mmc_test_multi_xfersize_write(struct mmc_test_card *test) 593 + { 594 + int ret; 595 + 596 + if (test->card->host->max_blk_count == 1) 597 + return RESULT_UNSUP_HOST; 598 + 599 + ret = mmc_test_set_blksize(test, 512); 600 + if (ret) 601 + return ret; 602 + 603 + ret = __mmc_test_transfer(test, 1, 1, test->buffer, 0, 2, 512); 604 + if (ret) 605 + return ret; 606 + 607 + return 0; 608 + } 609 + 610 + static int mmc_test_multi_xfersize_read(struct mmc_test_card *test) 611 + { 612 + int ret; 613 + 614 + if (test->card->host->max_blk_count == 1) 615 + return RESULT_UNSUP_HOST; 616 + 617 + ret = mmc_test_set_blksize(test, 512); 618 + if (ret) 619 + return ret; 620 + 621 + ret = __mmc_test_transfer(test, 0, 1, test->buffer, 0, 2, 512); 622 + if (ret) 623 + return ret; 624 + 625 + return 0; 626 + } 627 + 628 + static const struct mmc_test_case mmc_test_cases[] = { 629 + { 630 + .name = "Basic write (no data verification)", 631 + .run = mmc_test_basic_write, 632 + }, 633 + 634 + { 635 + .name = "Basic read (no data verification)", 636 + .run = mmc_test_basic_read, 637 + }, 638 + 639 + { 640 + .name = "Basic write (with data verification)", 641 + .prepare = mmc_test_prepare_verify_write, 642 + .run = mmc_test_verify_write, 643 + .cleanup = mmc_test_cleanup_verify, 644 + }, 645 + 646 + { 647 + .name = "Basic read (with data verification)", 648 + .prepare = mmc_test_prepare_verify_read, 649 + .run = mmc_test_verify_read, 650 + .cleanup = mmc_test_cleanup_verify, 651 + }, 652 + 653 + { 654 + .name = "Multi-block write", 655 + .prepare = mmc_test_prepare_verify_write, 656 + .run = mmc_test_multi_write, 657 + .cleanup = mmc_test_cleanup_verify, 658 + }, 659 + 660 + { 661 + .name = "Multi-block read", 662 + .prepare = mmc_test_prepare_verify_read, 663 + .run = mmc_test_multi_read, 664 + .cleanup = mmc_test_cleanup_verify, 665 + }, 666 + 667 + { 668 + .name = "Power of two block writes", 669 + .prepare = mmc_test_prepare_verify_write, 670 + .run = mmc_test_pow2_write, 671 + .cleanup = mmc_test_cleanup_verify, 672 + }, 673 + 674 + { 675 + .name = "Power of two block reads", 676 + .prepare = mmc_test_prepare_verify_read, 677 + .run = mmc_test_pow2_read, 678 + .cleanup = mmc_test_cleanup_verify, 679 + }, 680 + 681 + { 682 + .name = "Weird sized block writes", 683 + .prepare = mmc_test_prepare_verify_write, 684 + .run = mmc_test_weird_write, 685 + .cleanup = mmc_test_cleanup_verify, 686 + }, 687 + 688 + { 689 + .name = "Weird sized block reads", 690 + .prepare = mmc_test_prepare_verify_read, 691 + .run = mmc_test_weird_read, 692 + .cleanup = mmc_test_cleanup_verify, 693 + }, 694 + 695 + { 696 + .name = "Badly aligned write", 697 + .prepare = mmc_test_prepare_verify_write, 698 + .run = mmc_test_align_write, 699 + .cleanup = mmc_test_cleanup_verify, 700 + }, 701 + 702 + { 703 + .name = "Badly aligned read", 704 + .prepare = mmc_test_prepare_verify_read, 705 + .run = mmc_test_align_read, 706 + .cleanup = mmc_test_cleanup_verify, 707 + }, 708 + 709 + { 710 + .name = "Badly aligned multi-block write", 711 + .prepare = mmc_test_prepare_verify_write, 712 + .run = mmc_test_align_multi_write, 713 + .cleanup = mmc_test_cleanup_verify, 714 + }, 715 + 716 + { 717 + .name = "Badly aligned multi-block read", 718 + .prepare = mmc_test_prepare_verify_read, 719 + .run = mmc_test_align_multi_read, 720 + .cleanup = mmc_test_cleanup_verify, 721 + }, 722 + 723 + { 724 + .name = "Correct xfer_size at write (start failure)", 725 + .run = mmc_test_xfersize_write, 726 + }, 727 + 728 + { 729 + .name = "Correct xfer_size at read (start failure)", 730 + .run = mmc_test_xfersize_read, 731 + }, 732 + 733 + { 734 + .name = "Correct xfer_size at write (midway failure)", 735 + .run = mmc_test_multi_xfersize_write, 736 + }, 737 + 738 + { 739 + .name = "Correct xfer_size at read (midway failure)", 740 + .run = mmc_test_multi_xfersize_read, 741 + }, 742 + }; 743 + 744 + static struct mutex mmc_test_lock; 745 + 746 + static void mmc_test_run(struct mmc_test_card *test) 747 + { 748 + int i, ret; 749 + 750 + printk(KERN_INFO "%s: Starting tests of card %s...\n", 751 + mmc_hostname(test->card->host), mmc_card_id(test->card)); 752 + 753 + mmc_claim_host(test->card->host); 754 + 755 + for (i = 0;i < ARRAY_SIZE(mmc_test_cases);i++) { 756 + printk(KERN_INFO "%s: Test case %d. %s...\n", 757 + mmc_hostname(test->card->host), i + 1, 758 + mmc_test_cases[i].name); 759 + 760 + if (mmc_test_cases[i].prepare) { 761 + ret = mmc_test_cases[i].prepare(test); 762 + if (ret) { 763 + printk(KERN_INFO "%s: Result: Prepare " 764 + "stage failed! (%d)\n", 765 + mmc_hostname(test->card->host), 766 + ret); 767 + continue; 768 + } 769 + } 770 + 771 + ret = mmc_test_cases[i].run(test); 772 + switch (ret) { 773 + case RESULT_OK: 774 + printk(KERN_INFO "%s: Result: OK\n", 775 + mmc_hostname(test->card->host)); 776 + break; 777 + case RESULT_FAIL: 778 + printk(KERN_INFO "%s: Result: FAILED\n", 779 + mmc_hostname(test->card->host)); 780 + break; 781 + case RESULT_UNSUP_HOST: 782 + printk(KERN_INFO "%s: Result: UNSUPPORTED " 783 + "(by host)\n", 784 + mmc_hostname(test->card->host)); 785 + break; 786 + case RESULT_UNSUP_CARD: 787 + printk(KERN_INFO "%s: Result: UNSUPPORTED " 788 + "(by card)\n", 789 + mmc_hostname(test->card->host)); 790 + break; 791 + default: 792 + printk(KERN_INFO "%s: Result: ERROR (%d)\n", 793 + mmc_hostname(test->card->host), ret); 794 + } 795 + 796 + if (mmc_test_cases[i].cleanup) { 797 + ret = mmc_test_cases[i].cleanup(test); 798 + if (ret) { 799 + printk(KERN_INFO "%s: Warning: Cleanup " 800 + "stage failed! (%d)\n", 801 + mmc_hostname(test->card->host), 802 + ret); 803 + } 804 + } 805 + } 806 + 807 + mmc_release_host(test->card->host); 808 + 809 + printk(KERN_INFO "%s: Tests completed.\n", 810 + mmc_hostname(test->card->host)); 811 + } 812 + 813 + static ssize_t mmc_test_show(struct device *dev, 814 + struct device_attribute *attr, char *buf) 815 + { 816 + mutex_lock(&mmc_test_lock); 817 + mutex_unlock(&mmc_test_lock); 818 + 819 + return 0; 820 + } 821 + 822 + static ssize_t mmc_test_store(struct device *dev, 823 + struct device_attribute *attr, const char *buf, size_t count) 824 + { 825 + struct mmc_card *card; 826 + struct mmc_test_card *test; 827 + 828 + card = container_of(dev, struct mmc_card, dev); 829 + 830 + test = kzalloc(sizeof(struct mmc_test_card), GFP_KERNEL); 831 + if (!test) 832 + return -ENOMEM; 833 + 834 + test->card = card; 835 + 836 + test->buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL); 837 + if (test->buffer) { 838 + mutex_lock(&mmc_test_lock); 839 + mmc_test_run(test); 840 + mutex_unlock(&mmc_test_lock); 841 + } 842 + 843 + kfree(test->buffer); 844 + kfree(test); 845 + 846 + return count; 847 + } 848 + 849 + static DEVICE_ATTR(test, S_IWUSR | S_IRUGO, mmc_test_show, mmc_test_store); 850 + 851 + static int mmc_test_probe(struct mmc_card *card) 852 + { 853 + int ret; 854 + 855 + mutex_init(&mmc_test_lock); 856 + 857 + ret = device_create_file(&card->dev, &dev_attr_test); 858 + if (ret) 859 + return ret; 860 + 861 + return 0; 862 + } 863 + 864 + static void mmc_test_remove(struct mmc_card *card) 865 + { 866 + device_remove_file(&card->dev, &dev_attr_test); 867 + } 868 + 869 + static struct mmc_driver mmc_driver = { 870 + .drv = { 871 + .name = "mmc_test", 872 + }, 873 + .probe = mmc_test_probe, 874 + .remove = mmc_test_remove, 875 + }; 876 + 877 + static int __init mmc_test_init(void) 878 + { 879 + return mmc_register_driver(&mmc_driver); 880 + } 881 + 882 + static void __exit mmc_test_exit(void) 883 + { 884 + mmc_unregister_driver(&mmc_driver); 885 + } 886 + 887 + module_init(mmc_test_init); 888 + module_exit(mmc_test_exit); 889 + 890 + MODULE_LICENSE("GPL"); 891 + MODULE_DESCRIPTION("Multimedia Card (MMC) host test driver"); 892 + MODULE_AUTHOR("Pierre Ossman");