diff options
author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2006-08-30 10:14:56 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2006-09-16 06:57:49 -0400 |
commit | db53f28b3a6d9338cca1b7e917dc063ac99e1871 (patch) | |
tree | e75578ec00cfe0fa8a3449dc97038e3bb621f01f /drivers/mmc | |
parent | 132919ba80ad207755fe271277bfefff865a54fe (diff) |
[MMC] Add multi block-write capability
Add a capability flag for drivers to set when they can perform multi-
block transfers to cards _and_ correctly report the number of bytes
transferred should an error occur.
The last point is very important - if a driver reports more bytes than
were actually accepted by the card and an error occurs, there is the
possibility for data loss.
Pierre Ossman provided the patch for wbsd and sdhci.
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/mmc_block.c | 27 | ||||
-rw-r--r-- | drivers/mmc/mmci.c | 1 | ||||
-rw-r--r-- | drivers/mmc/sdhci.c | 2 | ||||
-rw-r--r-- | drivers/mmc/wbsd.c | 2 |
4 files changed, 23 insertions, 9 deletions
diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index f3a99dd8df8f..8d18b87bfd34 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/mmc/card.h> | 32 | #include <linux/mmc/card.h> |
33 | #include <linux/mmc/host.h> | 33 | #include <linux/mmc/host.h> |
34 | #include <linux/mmc/protocol.h> | 34 | #include <linux/mmc/protocol.h> |
35 | #include <linux/mmc/host.h> | ||
35 | 36 | ||
36 | #include <asm/system.h> | 37 | #include <asm/system.h> |
37 | #include <asm/uaccess.h> | 38 | #include <asm/uaccess.h> |
@@ -165,6 +166,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) | |||
165 | do { | 166 | do { |
166 | struct mmc_blk_request brq; | 167 | struct mmc_blk_request brq; |
167 | struct mmc_command cmd; | 168 | struct mmc_command cmd; |
169 | u32 readcmd, writecmd; | ||
168 | 170 | ||
169 | memset(&brq, 0, sizeof(struct mmc_blk_request)); | 171 | memset(&brq, 0, sizeof(struct mmc_blk_request)); |
170 | brq.mrq.cmd = &brq.cmd; | 172 | brq.mrq.cmd = &brq.cmd; |
@@ -180,20 +182,31 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) | |||
180 | 182 | ||
181 | mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ); | 183 | mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ); |
182 | 184 | ||
183 | if (rq_data_dir(req) == READ) { | 185 | /* |
184 | brq.cmd.opcode = brq.data.blocks > 1 ? MMC_READ_MULTIPLE_BLOCK : MMC_READ_SINGLE_BLOCK; | 186 | * If the host doesn't support multiple block writes, force |
185 | brq.data.flags |= MMC_DATA_READ; | 187 | * block writes to single block. |
186 | } else { | 188 | */ |
187 | brq.cmd.opcode = MMC_WRITE_BLOCK; | 189 | if (rq_data_dir(req) != READ && |
188 | brq.data.flags |= MMC_DATA_WRITE; | 190 | !(card->host->caps & MMC_CAP_MULTIWRITE)) |
189 | brq.data.blocks = 1; | 191 | brq.data.blocks = 1; |
190 | } | ||
191 | 192 | ||
192 | if (brq.data.blocks > 1) { | 193 | if (brq.data.blocks > 1) { |
193 | brq.data.flags |= MMC_DATA_MULTI; | 194 | brq.data.flags |= MMC_DATA_MULTI; |
194 | brq.mrq.stop = &brq.stop; | 195 | brq.mrq.stop = &brq.stop; |
196 | readcmd = MMC_READ_MULTIPLE_BLOCK; | ||
197 | writecmd = MMC_WRITE_MULTIPLE_BLOCK; | ||
195 | } else { | 198 | } else { |
196 | brq.mrq.stop = NULL; | 199 | brq.mrq.stop = NULL; |
200 | readcmd = MMC_READ_SINGLE_BLOCK; | ||
201 | writecmd = MMC_WRITE_BLOCK; | ||
202 | } | ||
203 | |||
204 | if (rq_data_dir(req) == READ) { | ||
205 | brq.cmd.opcode = readcmd; | ||
206 | brq.data.flags |= MMC_DATA_READ; | ||
207 | } else { | ||
208 | brq.cmd.opcode = writecmd; | ||
209 | brq.data.flags |= MMC_DATA_WRITE; | ||
197 | } | 210 | } |
198 | 211 | ||
199 | brq.data.sg = mq->sg; | 212 | brq.data.sg = mq->sg; |
diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index 8419489e7744..2b5a0cc9ea56 100644 --- a/drivers/mmc/mmci.c +++ b/drivers/mmc/mmci.c | |||
@@ -509,6 +509,7 @@ static int mmci_probe(struct amba_device *dev, void *id) | |||
509 | mmc->f_min = (host->mclk + 511) / 512; | 509 | mmc->f_min = (host->mclk + 511) / 512; |
510 | mmc->f_max = min(host->mclk, fmax); | 510 | mmc->f_max = min(host->mclk, fmax); |
511 | mmc->ocr_avail = plat->ocr_mask; | 511 | mmc->ocr_avail = plat->ocr_mask; |
512 | mmc->caps = MMC_CAP_MULTIWRITE; | ||
512 | 513 | ||
513 | /* | 514 | /* |
514 | * We can do SGIO | 515 | * We can do SGIO |
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 4e21b3b9d330..dea4edd1c434 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c | |||
@@ -1262,7 +1262,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) | |||
1262 | mmc->ops = &sdhci_ops; | 1262 | mmc->ops = &sdhci_ops; |
1263 | mmc->f_min = host->max_clk / 256; | 1263 | mmc->f_min = host->max_clk / 256; |
1264 | mmc->f_max = host->max_clk; | 1264 | mmc->f_max = host->max_clk; |
1265 | mmc->caps = MMC_CAP_4_BIT_DATA; | 1265 | mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE; |
1266 | 1266 | ||
1267 | mmc->ocr_avail = 0; | 1267 | mmc->ocr_avail = 0; |
1268 | if (caps & SDHCI_CAN_VDD_330) | 1268 | if (caps & SDHCI_CAN_VDD_330) |
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index c351c6d1a18a..4a6617d9a49f 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c | |||
@@ -1323,7 +1323,7 @@ static int __devinit wbsd_alloc_mmc(struct device *dev) | |||
1323 | mmc->f_min = 375000; | 1323 | mmc->f_min = 375000; |
1324 | mmc->f_max = 24000000; | 1324 | mmc->f_max = 24000000; |
1325 | mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; | 1325 | mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; |
1326 | mmc->caps = MMC_CAP_4_BIT_DATA; | 1326 | mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE; |
1327 | 1327 | ||
1328 | spin_lock_init(&host->lock); | 1328 | spin_lock_init(&host->lock); |
1329 | 1329 | ||