summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorPaul Walmsley <paul@pwsan.com>2011-10-06 14:50:33 -0600
committerChris Ball <cjb@laptop.org>2011-10-27 09:10:57 -0400
commit2bf22b39823c1d173dda31111a4eb2ce36daaf39 (patch)
tree54575fedfd2b032c3113b55dea5e2fd5d0c7eb38 /drivers
parentb6ad726e3fe69e1ff3c3b2ad272ba3e4c376cd6a (diff)
downloadlinux-2bf22b39823c1d173dda31111a4eb2ce36daaf39.tar.bz2
mmc: core: add workaround for controllers with broken multiblock reads
Due to hardware bugs, some MMC host controllers don't support multiple-block reads[1]. To resolve, add a new MMC capability flag, MMC_CAP2_NO_MULTI_READ, which can be set by affected host controller drivers. When this capability is set, all reads will be issued one sector at a time. 1. See for example Advisory 2.1.1.128 "MMC: Multiple Block Read Operation Issue" in _OMAP3530/3525/3515/3503 Silicon Errata_ Revision F (October 2010) (SPRZ278F), available from http://focus.ti.com/lit/er/sprz278f/sprz278f.pdf Signed-off-by: Paul Walmsley <paul@pwsan.com> Cc: Dave Hylands <dhylands@gmail.com> Tested-by: Steve Sakoman <sakoman@gmail.com> Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/card/block.c21
1 files changed, 14 insertions, 7 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index c0cb225bbb47..a1cb21f95302 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -1030,13 +1030,20 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
if (brq->data.blocks > card->host->max_blk_count)
brq->data.blocks = card->host->max_blk_count;
- /*
- * After a read error, we redo the request one sector at a time
- * in order to accurately determine which sectors can be read
- * successfully.
- */
- if (disable_multi && brq->data.blocks > 1)
- brq->data.blocks = 1;
+ if (brq->data.blocks > 1) {
+ /*
+ * After a read error, we redo the request one sector
+ * at a time in order to accurately determine which
+ * sectors can be read successfully.
+ */
+ if (disable_multi)
+ brq->data.blocks = 1;
+
+ /* Some controllers can't do multiblock reads due to hw bugs */
+ if (card->host->caps2 & MMC_CAP2_NO_MULTI_READ &&
+ rq_data_dir(req) == READ)
+ brq->data.blocks = 1;
+ }
if (brq->data.blocks > 1 || do_rel_wr) {
/* SPI multiblock writes terminate using a special