diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-05-19 19:40:30 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-05-19 19:40:30 -0400 |
| commit | 8033c6e9736c29cce5f0d0abbca9a44dffb20c39 (patch) | |
| tree | 7691061eecc2884c617f56ab69af1e0592268d61 | |
| parent | 2d3cf588e9bf6df0a22581baece7edeacfbbc9f5 (diff) | |
| parent | e5c0ef90e6cfd40c819bd70748d675067ff862e7 (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc:
at91_mci: minor cleanup
mmc: mmc host test driver
mmc: Fix omap compile by replacing dev_name with dma_dev_name
| -rw-r--r-- | drivers/mmc/card/Kconfig | 12 | ||||
| -rw-r--r-- | drivers/mmc/card/Makefile | 1 | ||||
| -rw-r--r-- | drivers/mmc/card/mmc_test.c | 892 | ||||
| -rw-r--r-- | drivers/mmc/host/at91_mci.c | 5 | ||||
| -rw-r--r-- | drivers/mmc/host/omap.c | 12 |
5 files changed, 915 insertions, 7 deletions
diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig index aa8a4e461942..dd0f398ee2f5 100644 --- a/drivers/mmc/card/Kconfig +++ b/drivers/mmc/card/Kconfig | |||
| @@ -39,3 +39,15 @@ config SDIO_UART | |||
| 39 | SDIO function driver for SDIO cards that implements the UART | 39 | SDIO function driver for SDIO cards that implements the UART |
| 40 | class, as well as the GPS class which appears like a UART. | 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. | ||
diff --git a/drivers/mmc/card/Makefile b/drivers/mmc/card/Makefile index fc5a784cfa1a..0d407514f67d 100644 --- a/drivers/mmc/card/Makefile +++ b/drivers/mmc/card/Makefile | |||
| @@ -8,6 +8,7 @@ endif | |||
| 8 | 8 | ||
| 9 | obj-$(CONFIG_MMC_BLOCK) += mmc_block.o | 9 | obj-$(CONFIG_MMC_BLOCK) += mmc_block.o |
| 10 | mmc_block-objs := block.o queue.o | 10 | mmc_block-objs := block.o queue.o |
| 11 | obj-$(CONFIG_MMC_TEST) += mmc_test.o | ||
| 11 | 12 | ||
| 12 | obj-$(CONFIG_SDIO_UART) += sdio_uart.o | 13 | obj-$(CONFIG_SDIO_UART) += sdio_uart.o |
| 13 | 14 | ||
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c new file mode 100644 index 000000000000..ffadee549a41 --- /dev/null +++ b/drivers/mmc/card/mmc_test.c | |||
| @@ -0,0 +1,892 @@ | |||
| 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.ar | ||
