aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk@dyn-67.arm.linux.org.uk>2006-08-30 10:14:56 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2006-09-16 06:57:49 -0400
commitdb53f28b3a6d9338cca1b7e917dc063ac99e1871 (patch)
treee75578ec00cfe0fa8a3449dc97038e3bb621f01f
parent132919ba80ad207755fe271277bfefff865a54fe (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>
-rw-r--r--drivers/mmc/mmc_block.c27
-rw-r--r--drivers/mmc/mmci.c1
-rw-r--r--drivers/mmc/sdhci.c2
-rw-r--r--drivers/mmc/wbsd.c2
-rw-r--r--include/linux/mmc/host.h1
5 files changed, 24 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
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index ba095aebedff..b282ec9bba08 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -85,6 +85,7 @@ struct mmc_host {
85 unsigned long caps; /* Host capabilities */ 85 unsigned long caps; /* Host capabilities */
86 86
87#define MMC_CAP_4_BIT_DATA (1 << 0) /* Can the host do 4 bit transfers */ 87#define MMC_CAP_4_BIT_DATA (1 << 0) /* Can the host do 4 bit transfers */
88#define MMC_CAP_MULTIWRITE (1 << 1) /* Can accurately report bytes sent to card on error */
88 89
89 /* host specific block data */ 90 /* host specific block data */
90 unsigned int max_seg_size; /* see blk_queue_max_segment_size */ 91 unsigned int max_seg_size; /* see blk_queue_max_segment_size */