summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorian <ian@FreeBSD.org>2013-08-16 23:05:34 +0000
committerian <ian@FreeBSD.org>2013-08-16 23:05:34 +0000
commit11646cd458d5d97b110974c0794fd49d940f3a9b (patch)
tree572c6803497d19f5f427bd12166c0caad71e9034
parent3bfcb89de4b7ac6c54e2affe99eccd1482eb4327 (diff)
downloadFreeBSD-src-11646cd458d5d97b110974c0794fd49d940f3a9b.zip
FreeBSD-src-11646cd458d5d97b110974c0794fd49d940f3a9b.tar.gz
Handle command retries for commands originating at the mmc layer, and
ensure that all such commands have a non-zero retry count except for those that are expected to fail (for example, because they are used to probe for feature support). While it is possible to pass a retry count down to the hardware driver in the command request structure, no hardware driver currently implements any retry logic. The hardware doesn't know much about the context of a single request, so it makes more sense to handle retries at a layer that does. This adds retry loops to the mmc_wait_for_cmd() and mmc_wait_for_app_cmd() functions. These functions are the gateway from other code within mmc.c to the hardware. App commands are a sequence of two commands and a retry has to rerun both of them in order, so it needs its own retry loop. Retry looping is specifically NOT implemented in mmc_wait_for_request() because it is the gateway for children on the bus, and they have to implement their own retry logic depending on what makes sense for them.
-rw-r--r--sys/dev/mmc/mmc.c73
1 files changed, 41 insertions, 32 deletions
diff --git a/sys/dev/mmc/mmc.c b/sys/dev/mmc/mmc.c
index 70c26b1..acae496 100644
--- a/sys/dev/mmc/mmc.c
+++ b/sys/dev/mmc/mmc.c
@@ -393,8 +393,9 @@ mmc_wait_for_req(struct mmc_softc *sc, struct mmc_request *req)
while ((req->flags & MMC_REQ_DONE) == 0)
msleep(req, &sc->sc_mtx, 0, "mmcreq", 0);
MMC_UNLOCK(sc);
- if (mmc_debug > 2 || (mmc_debug > 1 && req->cmd->error))
- device_printf(sc->dev, "RESULT: %d\n", req->cmd->error);
+ if (mmc_debug > 2 || (mmc_debug > 0 && req->cmd->error != MMC_ERR_NONE))
+ device_printf(sc->dev, "CMD%d RESULT: %d\n",
+ req->cmd->opcode, req->cmd->error);
return (0);
}
@@ -410,14 +411,21 @@ static int
mmc_wait_for_cmd(struct mmc_softc *sc, struct mmc_command *cmd, int retries)
{
struct mmc_request mreq;
+ int err;
+
+ do {
+ memset(&mreq, 0, sizeof(mreq));
+ memset(cmd->resp, 0, sizeof(cmd->resp));
+ cmd->retries = 0; /* Retries done here, not in hardware. */
+ cmd->mrq = &mreq;
+ mreq.cmd = cmd;
+ if (mmc_wait_for_req(sc, &mreq) != 0)
+ err = MMC_ERR_FAILED;
+ else
+ err = cmd->error;
+ } while (err != MMC_ERR_NONE && retries-- > 0);
- memset(&mreq, 0, sizeof(mreq));
- memset(cmd->resp, 0, sizeof(cmd->resp));
- cmd->retries = retries;
- cmd->mrq = &mreq;
- mreq.cmd = cmd;
- mmc_wait_for_req(sc, &mreq);
- return (cmd->error);
+ return (err);
}
static int
@@ -425,24 +433,27 @@ mmc_wait_for_app_cmd(struct mmc_softc *sc, uint32_t rca,
struct mmc_command *cmd, int retries)
{
struct mmc_command appcmd;
- int err = MMC_ERR_NONE, i;
+ int err;
- for (i = 0; i <= retries; i++) {
+ do {
appcmd.opcode = MMC_APP_CMD;
appcmd.arg = rca << 16;
appcmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
appcmd.data = NULL;
- mmc_wait_for_cmd(sc, &appcmd, 0);
- err = appcmd.error;
- if (err != MMC_ERR_NONE)
- continue;
- if (!(appcmd.resp[0] & R1_APP_CMD))
- return MMC_ERR_FAILED;
- mmc_wait_for_cmd(sc, cmd, 0);
- err = cmd->error;
- if (err == MMC_ERR_NONE)
- break;
- }
+ if (mmc_wait_for_cmd(sc, &appcmd, 0) != 0)
+ err = MMC_ERR_FAILED;
+ else
+ err = appcmd.error;
+ if (err == MMC_ERR_NONE) {
+ if (!(appcmd.resp[0] & R1_APP_CMD))
+ return MMC_ERR_FAILED; /* Retries won't help. */
+ if (mmc_wait_for_cmd(sc, cmd, 0) != 0)
+ err = MMC_ERR_FAILED;
+ else
+ err = cmd->error;
+ }
+ } while (err != MMC_ERR_NONE && retries-- > 0);
+
return (err);
}
@@ -461,8 +472,6 @@ mmc_wait_for_command(struct mmc_softc *sc, uint32_t opcode,
err = mmc_wait_for_cmd(sc, &cmd, retries);
if (err)
return (err);
- if (cmd.error)
- return (cmd.error);
if (resp) {
if (flags & MMC_RSP_136)
memcpy(resp, cmd.resp, 4 * sizeof(uint32_t));
@@ -488,7 +497,7 @@ mmc_idle_cards(struct mmc_softc *sc)
cmd.arg = 0;
cmd.flags = MMC_RSP_NONE | MMC_CMD_BC;
cmd.data = NULL;
- mmc_wait_for_cmd(sc, &cmd, 0);
+ mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES);
mmc_ms_delay(1);
mmcbr_set_chip_select(dev, cs_dontcare);
@@ -625,7 +634,7 @@ mmc_switch(struct mmc_softc *sc, uint8_t set, uint8_t index, uint8_t value)
set;
cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
cmd.data = NULL;
- err = mmc_wait_for_cmd(sc, &cmd, 0);
+ err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES);
return (err);
}
@@ -1054,7 +1063,7 @@ mmc_all_send_cid(struct mmc_softc *sc, uint32_t *rawcid)
cmd.arg = 0;
cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
cmd.data = NULL;
- err = mmc_wait_for_cmd(sc, &cmd, 0);
+ err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES);
memcpy(rawcid, cmd.resp, 4 * sizeof(uint32_t));
return (err);
}
@@ -1069,7 +1078,7 @@ mmc_send_csd(struct mmc_softc *sc, uint16_t rca, uint32_t *rawcsd)
cmd.arg = rca << 16;
cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
cmd.data = NULL;
- err = mmc_wait_for_cmd(sc, &cmd, 0);
+ err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES);
memcpy(rawcsd, cmd.resp, 4 * sizeof(uint32_t));
return (err);
}
@@ -1160,7 +1169,7 @@ mmc_set_relative_addr(struct mmc_softc *sc, uint16_t resp)
cmd.arg = resp << 16;
cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
cmd.data = NULL;
- err = mmc_wait_for_cmd(sc, &cmd, 0);
+ err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES);
return (err);
}
@@ -1174,7 +1183,7 @@ mmc_send_relative_addr(struct mmc_softc *sc, uint32_t *resp)
cmd.arg = 0;
cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
cmd.data = NULL;
- err = mmc_wait_for_cmd(sc, &cmd, 0);
+ err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES);
*resp = cmd.resp[0];
return (err);
}
@@ -1189,7 +1198,7 @@ mmc_send_status(struct mmc_softc *sc, uint16_t rca, uint32_t *status)
cmd.arg = rca << 16;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
cmd.data = NULL;
- err = mmc_wait_for_cmd(sc, &cmd, 0);
+ err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES);
*status = cmd.resp[0];
return (err);
}
@@ -1204,7 +1213,7 @@ mmc_set_blocklen(struct mmc_softc *sc, uint32_t len)
cmd.arg = len;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
cmd.data = NULL;
- err = mmc_wait_for_cmd(sc, &cmd, 0);
+ err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES);
return (err);
}
OpenPOWER on IntegriCloud