From b46be45033679cf1da17c522ecea92fb7a1dbe44 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 15 Jun 2011 15:19:00 +0200 Subject: 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 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/25169 Reviewed-by: Sebastian RASMUSSEN Reviewed-by: P.Hanumath PRASAD Reviewed-by: Jonas ABERG --- drivers/mmc/card/block.c | 79 +++++++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 34 deletions(-) (limited to 'drivers/mmc') 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) { -- cgit v1.2.3