aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/mmc_block.c
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 /drivers/mmc/mmc_block.c
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>
Diffstat (limited to 'drivers/mmc/mmc_block.c')
-rw-r--r--drivers/mmc/mmc_block.c27
1 files changed, 20 insertions, 7 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;