Commit db53f28b authored by Russell King's avatar Russell King Committed by Russell King

[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: default avatarPierre Ossman <drzeus@drzeus.cx>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 132919ba
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <linux/mmc/card.h> #include <linux/mmc/card.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/protocol.h> #include <linux/mmc/protocol.h>
#include <linux/mmc/host.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -165,6 +166,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) ...@@ -165,6 +166,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
do { do {
struct mmc_blk_request brq; struct mmc_blk_request brq;
struct mmc_command cmd; struct mmc_command cmd;
u32 readcmd, writecmd;
memset(&brq, 0, sizeof(struct mmc_blk_request)); memset(&brq, 0, sizeof(struct mmc_blk_request));
brq.mrq.cmd = &brq.cmd; brq.mrq.cmd = &brq.cmd;
...@@ -180,20 +182,31 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) ...@@ -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); 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; * If the host doesn't support multiple block writes, force
brq.data.flags |= MMC_DATA_READ; * block writes to single block.
} else { */
brq.cmd.opcode = MMC_WRITE_BLOCK; if (rq_data_dir(req) != READ &&
brq.data.flags |= MMC_DATA_WRITE; !(card->host->caps & MMC_CAP_MULTIWRITE))
brq.data.blocks = 1; brq.data.blocks = 1;
}
if (brq.data.blocks > 1) { if (brq.data.blocks > 1) {
brq.data.flags |= MMC_DATA_MULTI; brq.data.flags |= MMC_DATA_MULTI;
brq.mrq.stop = &brq.stop; brq.mrq.stop = &brq.stop;
readcmd = MMC_READ_MULTIPLE_BLOCK;
writecmd = MMC_WRITE_MULTIPLE_BLOCK;
} else { } else {
brq.mrq.stop = NULL; 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; brq.data.sg = mq->sg;
......
...@@ -509,6 +509,7 @@ static int mmci_probe(struct amba_device *dev, void *id) ...@@ -509,6 +509,7 @@ static int mmci_probe(struct amba_device *dev, void *id)
mmc->f_min = (host->mclk + 511) / 512; mmc->f_min = (host->mclk + 511) / 512;
mmc->f_max = min(host->mclk, fmax); mmc->f_max = min(host->mclk, fmax);
mmc->ocr_avail = plat->ocr_mask; mmc->ocr_avail = plat->ocr_mask;
mmc->caps = MMC_CAP_MULTIWRITE;
/* /*
* We can do SGIO * We can do SGIO
......
...@@ -1262,7 +1262,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) ...@@ -1262,7 +1262,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
mmc->ops = &sdhci_ops; mmc->ops = &sdhci_ops;
mmc->f_min = host->max_clk / 256; mmc->f_min = host->max_clk / 256;
mmc->f_max = host->max_clk; 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; mmc->ocr_avail = 0;
if (caps & SDHCI_CAN_VDD_330) if (caps & SDHCI_CAN_VDD_330)
......
...@@ -1323,7 +1323,7 @@ static int __devinit wbsd_alloc_mmc(struct device *dev) ...@@ -1323,7 +1323,7 @@ static int __devinit wbsd_alloc_mmc(struct device *dev)
mmc->f_min = 375000; mmc->f_min = 375000;
mmc->f_max = 24000000; mmc->f_max = 24000000;
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; 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); spin_lock_init(&host->lock);
......
...@@ -85,6 +85,7 @@ struct mmc_host { ...@@ -85,6 +85,7 @@ struct mmc_host {
unsigned long caps; /* Host capabilities */ unsigned long caps; /* Host capabilities */
#define MMC_CAP_4_BIT_DATA (1 << 0) /* Can the host do 4 bit transfers */ #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 */ /* host specific block data */
unsigned int max_seg_size; /* see blk_queue_max_segment_size */ unsigned int max_seg_size; /* see blk_queue_max_segment_size */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment