@@ -1791,9 +1791,36 @@ static void sdhci_read_rsp_136(struct sdhci_host *host, struct mmc_command *cmd)
}
}
+static struct mmc_command *sdhci_get_sbc_ext(struct sdhci_host *host,
+ struct mmc_command *cmd)
+{
+ if (mmc_card_is_sduc(host->mmc)) {
+ /* Finished CMD22, now send actual command */
+ if (cmd == cmd->mrq->ext)
+ return cmd->mrq->cmd;
+ }
+
+ /* Finished CMD23 */
+ if (cmd == cmd->mrq->sbc) {
+ if (mmc_card_is_sduc(host->mmc)) {
+ /* send CMD22 after CMD23 */
+ if (WARN_ON(!cmd->mrq->ext))
+ return NULL;
+ else
+ return cmd->mrq->ext;
+ } else {
+ /* Finished CMD23, now send actual command */
+ return cmd->mrq->cmd;
+ }
+ }
+
+ return NULL;
+}
+
static void sdhci_finish_command(struct sdhci_host *host)
{
struct mmc_command *cmd = host->cmd;
+ struct mmc_command *sbc_ext = NULL;
host->cmd = NULL;
@@ -1828,14 +1855,13 @@ static void sdhci_finish_command(struct sdhci_host *host)
}
}
- /* Finished CMD23, now send actual command. */
- if (cmd == cmd->mrq->sbc) {
- if (!sdhci_send_command(host, cmd->mrq->cmd)) {
+ sbc_ext = sdhci_get_sbc_ext(host, cmd);
+ if (sbc_ext) {
+ if (!sdhci_send_command(host, sbc_ext)) {
WARN_ON(host->deferred_cmd);
host->deferred_cmd = cmd->mrq->cmd;
}
} else {
-
/* Processed actual command. */
if (host->data && host->data_early)
sdhci_finish_data(host);
In a close-ended multi-block data transfer, CMD23 shall precede CMD22. Handle that logic once the sbc is done. Host drivers that handle their own sbc logic, e.g. bcm2835 etc. are out of scope of this change. Signed-off-by: Avri Altman <avri.altman@wdc.com> --- drivers/mmc/host/sdhci.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-)