From db53f28b3a6d9338cca1b7e917dc063ac99e1871 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 30 Aug 2006 15:14:56 +0100 Subject: [PATCH] [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 Signed-off-by: Russell King --- drivers/mmc/mmc_block.c | 27 ++++++++++++++++++++------- drivers/mmc/mmci.c | 1 + drivers/mmc/sdhci.c | 2 +- drivers/mmc/wbsd.c | 2 +- include/linux/mmc/host.h | 1 + 5 files changed, 24 insertions(+), 9 deletions(-) diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index f3a99dd8df..8d18b87bfd 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -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; diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index 8419489e77..2b5a0cc9ea 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) 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 diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 4e21b3b9d3..dea4edd1c4 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) 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) diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index c351c6d1a1..4a6617d9a4 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -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); diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index ba095aebed..b282ec9bba 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -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 */ -- 2.39.5