Module Name: src Committed By: mlelstv Date: Sun Aug 9 13:18:46 UTC 2015
Modified Files: src/sys/dev/sdmmc: sdmmc.c sdmmcvar.h Log Message: Send an explicit CMD12 (stop transmission) when there was an error in multi-sector I/O. The SDHC spec has a complex flowchart describing when an explicit CMD12 is necessary, so we probably use it too often. To generate a diff of this commit: cvs rdiff -u -r1.30 -r1.31 src/sys/dev/sdmmc/sdmmc.c cvs rdiff -u -r1.18 -r1.19 src/sys/dev/sdmmc/sdmmcvar.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/sdmmc/sdmmc.c diff -u src/sys/dev/sdmmc/sdmmc.c:1.30 src/sys/dev/sdmmc/sdmmc.c:1.31 --- src/sys/dev/sdmmc/sdmmc.c:1.30 Sun Aug 9 13:14:11 2015 +++ src/sys/dev/sdmmc/sdmmc.c Sun Aug 9 13:18:46 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: sdmmc.c,v 1.30 2015/08/09 13:14:11 mlelstv Exp $ */ +/* $NetBSD: sdmmc.c,v 1.31 2015/08/09 13:18:46 mlelstv Exp $ */ /* $OpenBSD: sdmmc.c,v 1.18 2009/01/09 10:58:38 jsg Exp $ */ /* @@ -49,7 +49,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sdmmc.c,v 1.30 2015/08/09 13:14:11 mlelstv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sdmmc.c,v 1.31 2015/08/09 13:18:46 mlelstv Exp $"); #ifdef _KERNEL_OPT #include "opt_sdmmc.h" @@ -817,10 +817,35 @@ sdmmc_mmc_command(struct sdmmc_softc *sc DPRINTF(1,("sdmmc_mmc_command: error=%d\n", error)); + if (error && + (cmd->c_opcode == MMC_READ_BLOCK_MULTIPLE || + cmd->c_opcode == MMC_WRITE_BLOCK_MULTIPLE)) { + sdmmc_stop_transmission(sc); + } + return error; } /* + * Send the "STOP TRANSMISSION" command + */ +void +sdmmc_stop_transmission(struct sdmmc_softc *sc) +{ + struct sdmmc_command cmd; + + DPRINTF(1,("sdmmc_stop_transmission\n")); + + /* Don't lock */ + + memset(&cmd, 0, sizeof(cmd)); + cmd.c_opcode = MMC_STOP_TRANSMISSION; + cmd.c_flags = SCF_CMD_AC | SCF_RSP_R1B | SCF_RSP_SPI_R1B; + + (void)sdmmc_mmc_command(sc, &cmd); +} + +/* * Send the "GO IDLE STATE" command. */ void Index: src/sys/dev/sdmmc/sdmmcvar.h diff -u src/sys/dev/sdmmc/sdmmcvar.h:1.18 src/sys/dev/sdmmc/sdmmcvar.h:1.19 --- src/sys/dev/sdmmc/sdmmcvar.h:1.18 Mon Aug 3 10:08:51 2015 +++ src/sys/dev/sdmmc/sdmmcvar.h Sun Aug 9 13:18:46 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: sdmmcvar.h,v 1.18 2015/08/03 10:08:51 jmcneill Exp $ */ +/* $NetBSD: sdmmcvar.h,v 1.19 2015/08/09 13:18:46 mlelstv Exp $ */ /* $OpenBSD: sdmmcvar.h,v 1.13 2009/01/09 10:55:22 jsg Exp $ */ /* @@ -306,6 +306,7 @@ int sdmmc_set_bus_power(struct sdmmc_sof int sdmmc_mmc_command(struct sdmmc_softc *, struct sdmmc_command *); int sdmmc_app_command(struct sdmmc_softc *, struct sdmmc_function *, struct sdmmc_command *); +void sdmmc_stop_transmission(struct sdmmc_softc *); void sdmmc_go_idle_state(struct sdmmc_softc *); int sdmmc_select_card(struct sdmmc_softc *, struct sdmmc_function *); int sdmmc_set_relative_addr(struct sdmmc_softc *, struct sdmmc_function *);