diff options
author | ian <ian@FreeBSD.org> | 2013-08-16 23:05:34 +0000 |
---|---|---|
committer | ian <ian@FreeBSD.org> | 2013-08-16 23:05:34 +0000 |
commit | 11646cd458d5d97b110974c0794fd49d940f3a9b (patch) | |
tree | 572c6803497d19f5f427bd12166c0caad71e9034 | |
parent | 3bfcb89de4b7ac6c54e2affe99eccd1482eb4327 (diff) | |
download | FreeBSD-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.c | 73 |
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); } |