]> err.no Git - linux-2.6/commitdiff
[MMC] Add multi block-write capability
authorRussell King <rmk@dyn-67.arm.linux.org.uk>
Wed, 30 Aug 2006 14:14:56 +0000 (15:14 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Sat, 16 Sep 2006 10:57:49 +0000 (11:57 +0100)
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>
drivers/mmc/mmc_block.c
drivers/mmc/mmci.c
drivers/mmc/sdhci.c
drivers/mmc/wbsd.c
include/linux/mmc/host.h

index f3a99dd8df8f4158740ed7c1a22d54e9ed448ac3..8d18b87bfd342e702c0edd79a932c247ea938ed1 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/protocol.h>
+#include <linux/mmc/host.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -165,6 +166,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
        do {
                struct mmc_blk_request brq;
                struct mmc_command cmd;
+               u32 readcmd, writecmd;
 
                memset(&brq, 0, sizeof(struct mmc_blk_request));
                brq.mrq.cmd = &brq.cmd;
@@ -180,20 +182,31 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 
                mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ);
 
-               if (rq_data_dir(req) == READ) {
-                       brq.cmd.opcode = brq.data.blocks > 1 ? MMC_READ_MULTIPLE_BLOCK : MMC_READ_SINGLE_BLOCK;
-                       brq.data.flags |= MMC_DATA_READ;
-               } else {
-                       brq.cmd.opcode = MMC_WRITE_BLOCK;
-                       brq.data.flags |= MMC_DATA_WRITE;
+               /*
+                * If the host doesn't support multiple block writes, force
+                * block writes to single block.
+                */
+               if (rq_data_dir(req) != READ &&
+                   !(card->host->caps & MMC_CAP_MULTIWRITE))
                        brq.data.blocks = 1;
-               }
 
                if (brq.data.blocks > 1) {
                        brq.data.flags |= MMC_DATA_MULTI;
                        brq.mrq.stop = &brq.stop;
+                       readcmd = MMC_READ_MULTIPLE_BLOCK;
+                       writecmd = MMC_WRITE_MULTIPLE_BLOCK;
                } else {
                        brq.mrq.stop = NULL;
+                       readcmd = MMC_READ_SINGLE_BLOCK;
+                       writecmd = MMC_WRITE_BLOCK;
+               }
+
+               if (rq_data_dir(req) == READ) {
+                       brq.cmd.opcode = readcmd;
+                       brq.data.flags |= MMC_DATA_READ;
+               } else {
+                       brq.cmd.opcode = writecmd;
+                       brq.data.flags |= MMC_DATA_WRITE;
                }
 
                brq.data.sg = mq->sg;
index 8419489e7744fcc9eb9d6567193d0b202ef3e6ac..2b5a0cc9ea56392efc4a82e040ab67fe66ce1617 100644 (file)
@@ -509,6 +509,7 @@ static int mmci_probe(struct amba_device *dev, void *id)
        mmc->f_min = (host->mclk + 511) / 512;
        mmc->f_max = min(host->mclk, fmax);
        mmc->ocr_avail = plat->ocr_mask;
+       mmc->caps = MMC_CAP_MULTIWRITE;
 
        /*
         * We can do SGIO
index 4e21b3b9d330e4abf9834c22951cb18f8062828d..dea4edd1c434dd7d69e61f23bc0e34107a07bfd4 100644 (file)
@@ -1262,7 +1262,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
        mmc->ops = &sdhci_ops;
        mmc->f_min = host->max_clk / 256;
        mmc->f_max = host->max_clk;
-       mmc->caps = MMC_CAP_4_BIT_DATA;
+       mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE;
 
        mmc->ocr_avail = 0;
        if (caps & SDHCI_CAN_VDD_330)
index c351c6d1a18a11ee8ed712c77248b4337c5729d5..4a6617d9a49f4eee7347c610850d49e7bc82a5fc 100644 (file)
@@ -1323,7 +1323,7 @@ static int __devinit wbsd_alloc_mmc(struct device *dev)
        mmc->f_min = 375000;
        mmc->f_max = 24000000;
        mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
-       mmc->caps = MMC_CAP_4_BIT_DATA;
+       mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE;
 
        spin_lock_init(&host->lock);
 
index ba095aebedffb67cf060fa2fc5e0c56c9483a05c..b282ec9bba08202b3b2ac4145a5b2e2ba42781e5 100644 (file)
@@ -85,6 +85,7 @@ struct mmc_host {
        unsigned long           caps;           /* Host capabilities */
 
 #define MMC_CAP_4_BIT_DATA     (1 << 0)        /* Can the host do 4 bit transfers */
+#define MMC_CAP_MULTIWRITE     (1 << 1)        /* Can accurately report bytes sent to card on error */
 
        /* host specific block data */
        unsigned int            max_seg_size;   /* see blk_queue_max_segment_size */