aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorUlf Hansson <ulf.hansson@stericsson.com>2011-06-15 15:19:00 +0200
committersaid m bagheri <ebgheri@steludxu2848.(none)>2011-06-29 10:30:28 +0200
commitb46be45033679cf1da17c522ecea92fb7a1dbe44 (patch)
treeb2dc6d3644f932d74d4531ac7285a533f7653674 /drivers
parent8efcfdc3f679f7672540f36785431406d64d02be (diff)
mmc: Retry a read/write req when error is EAGAIN
If the error returned for a read/write operation is EAGAIN, execute the request again. A host driver may utilize this option to trigger a retry of the exact same request, which may be useful for HW workarounds. ST-Ericsson Linux next: ST-Ericsson ID: 342919 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: Ia14af2f2324fe8f2cbfe4b6cd07fb39b3209ec4f Signed-off-by: Ulf Hansson <ulf.hansson@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/25169 Reviewed-by: Sebastian RASMUSSEN <sebastian.rasmussen@stericsson.com> Reviewed-by: P.Hanumath PRASAD <hanumath.prasad@stericsson.com> Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/card/block.c79
1 files changed, 45 insertions, 34 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 61d233a7c11..10950dab1e9 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -245,7 +245,10 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
return result;
}
-static u32 get_card_status(struct mmc_card *card, struct request *req)
+static int get_card_status(struct mmc_card *card,
+ struct request *req,
+ u32 *status,
+ int retries)
{
struct mmc_command cmd;
int err;
@@ -255,11 +258,38 @@ static u32 get_card_status(struct mmc_card *card, struct request *req)
if (!mmc_host_is_spi(card->host))
cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
- err = mmc_wait_for_cmd(card->host, &cmd, 0);
+ err = mmc_wait_for_cmd(card->host, &cmd, retries);
if (err)
printk(KERN_ERR "%s: error %d sending status command",
req->rq_disk->disk_name, err);
- return cmd.resp[0];
+ else
+ *status = cmd.resp[0];
+
+ return err;
+}
+
+static int wait_for_ready_state(struct mmc_card *card, struct request *req)
+{
+ u32 status;
+ int err = 0;
+
+ if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
+
+ do {
+ err = get_card_status(card, req, &status, 5);
+ if (err)
+ break;
+
+ /*
+ * Some cards mishandle the status bits,
+ * so make sure to check both the busy
+ * indication and the card state.
+ */
+ } while (!(status & R1_READY_FOR_DATA) ||
+ (R1_CURRENT_STATE(status) == 7));
+ }
+
+ return err;
}
static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
@@ -341,7 +371,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
mmc_claim_host(card->host);
do {
- struct mmc_command cmd;
u32 readcmd, writecmd, status = 0;
memset(&brq, 0, sizeof(struct mmc_blk_request));
@@ -431,6 +460,15 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
* until later as we need to wait for the card to leave
* programming mode even when things go wrong.
*/
+ if (!brq.cmd.error && !brq.stop.error &&
+ brq.data.error == -EAGAIN) {
+ printk(KERN_WARNING "%s: retrying transfer\n",
+ req->rq_disk->disk_name);
+ if (wait_for_ready_state(card, req))
+ goto cmd_err;
+ continue;
+ }
+
if (brq.cmd.error || brq.data.error || brq.stop.error) {
if (brq.data.blocks > 1 && rq_data_dir(req) == READ) {
/* Redo read one sector at a time */
@@ -439,7 +477,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
disable_multi = 1;
continue;
}
- status = get_card_status(card, req);
+ get_card_status(card, req, &status, 0);
}
if (brq.cmd.error) {
@@ -467,35 +505,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
brq.stop.resp[0], status);
}
- if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
- do {
- int err;
-
- cmd.opcode = MMC_SEND_STATUS;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
- err = mmc_wait_for_cmd(card->host, &cmd, 5);
- if (err) {
- printk(KERN_ERR "%s: error %d requesting status\n",
- req->rq_disk->disk_name, err);
- goto cmd_err;
- }
- /*
- * Some cards mishandle the status bits,
- * so make sure to check both the busy
- * indication and the card state.
- */
- } while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
- (R1_CURRENT_STATE(cmd.resp[0]) == 7));
-
-#if 0
- if (cmd.resp[0] & ~0x00000900)
- printk(KERN_ERR "%s: status = %08x\n",
- req->rq_disk->disk_name, cmd.resp[0]);
- if (mmc_decode_status(cmd.resp))
- goto cmd_err;
-#endif
- }
+ if (wait_for_ready_state(card, req))
+ goto cmd_err;
if (brq.cmd.error || brq.stop.error || brq.data.error) {
if (rq_data_dir(req) == READ) {