Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/sdmmc Ignore data inhibit for commands that do not u...
details: https://anonhg.NetBSD.org/src/rev/c7493fa44889
branches: trunk
changeset: 339783:c7493fa44889
user: mlelstv <mlelstv%NetBSD.org@localhost>
date: Sun Aug 09 13:46:50 2015 +0000
description:
Ignore data inhibit for commands that do not use the DAT line.
Do a soft reset when the inhibit condition persists for better
error recovery.
Simplify interrupt handling and print errors reported by the controller.
Add more specific debug messages for timeout errors.
diffstat:
sys/dev/sdmmc/sdhc.c | 101 +++++++++++++++++++++++++++++++++++++-------------
1 files changed, 74 insertions(+), 27 deletions(-)
diffs (233 lines):
diff -r f74b09a6f678 -r c7493fa44889 sys/dev/sdmmc/sdhc.c
--- a/sys/dev/sdmmc/sdhc.c Sun Aug 09 13:39:18 2015 +0000
+++ b/sys/dev/sdmmc/sdhc.c Sun Aug 09 13:46:50 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: sdhc.c,v 1.83 2015/08/09 13:39:18 mlelstv Exp $ */
+/* $NetBSD: sdhc.c,v 1.84 2015/08/09 13:46:50 mlelstv Exp $ */
/* $OpenBSD: sdhc.c,v 1.25 2009/01/13 19:44:20 grange Exp $ */
/*
@@ -23,7 +23,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.83 2015/08/09 13:39:18 mlelstv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.84 2015/08/09 13:46:50 mlelstv Exp $");
#ifdef _KERNEL_OPT
#include "opt_sdmmc.h"
@@ -1117,6 +1117,7 @@
}
if (timo == 0) {
error = ETIMEDOUT;
+ DPRINTF(1,("%s: timeout\n", __func__));
goto out;
}
}
@@ -1451,6 +1452,7 @@
* is marked done for any other reason.
*/
if (!sdhc_wait_intr(hp, SDHC_COMMAND_COMPLETE, SDHC_COMMAND_TIMEOUT)) {
+ DPRINTF(1,("%s: timeout for command\n", __func__));
cmd->c_error = ETIMEDOUT;
goto out;
}
@@ -1487,6 +1489,7 @@
sdhc_transfer_data(hp, cmd);
else if (ISSET(cmd->c_flags, SCF_RSP_BSY)) {
if (!sdhc_wait_intr(hp, SDHC_TRANSFER_COMPLETE, hz * 10)) {
+ DPRINTF(1,(hp->sc->sc_dev,"sdhc_exec_command: RSP_BSY\n"));
cmd->c_error = ETIMEDOUT;
goto out;
}
@@ -1515,6 +1518,7 @@
uint16_t blkcount = 0;
uint16_t mode;
uint16_t command;
+ uint32_t pmask;
int error;
KASSERT(mutex_owned(&hp->intr_lock));
@@ -1581,10 +1585,14 @@
else
command |= SDHC_RESP_LEN_48;
- /* Wait until command and data inhibit bits are clear. (1.5) */
- error = sdhc_wait_state(hp, SDHC_CMD_INHIBIT_MASK, 0);
+ /* Wait until command and optionally data inhibit bits are clear. (1.5) */
+ pmask = SDHC_CMD_INHIBIT_CMD;
+ if (cmd->c_flags & SCF_CMD_ADTC)
+ pmask |= SDHC_CMD_INHIBIT_DAT;
+ error = sdhc_wait_state(hp, pmask, 0);
if (error) {
- aprint_error_dev(sc->sc_dev, "command or data phase inhibited\n");
+ (void) sdhc_soft_reset(hp, SDHC_RESET_DAT|SDHC_RESET_CMD);
+ device_printf(sc->sc_dev, "command or data phase inhibited\n");
return error;
}
@@ -1699,6 +1707,7 @@
error = hp->sc->sc_vendor_transfer_data_dma(sc, cmd);
if (error == 0 && !sdhc_wait_intr(hp,
SDHC_TRANSFER_COMPLETE, SDHC_DMA_TIMEOUT)) {
+ DPRINTF(1,("%s: timeout\n", __func__));
error = ETIMEDOUT;
}
} else {
@@ -1740,6 +1749,7 @@
break;
}
if (!status) {
+ DPRINTF(1,("%s: timeout\n", __func__));
error = ETIMEDOUT;
break;
}
@@ -1820,6 +1830,7 @@
HSET2(hp, SDHC_NINTR_SIGNAL_EN, imask);
}
if (!sdhc_wait_intr(hp, imask, SDHC_BUFFER_TIMEOUT)) {
+ DPRINTF(1,("%s: timeout\n", __func__));
error = ETIMEDOUT;
break;
}
@@ -1839,8 +1850,10 @@
}
if (error == 0 && !sdhc_wait_intr(hp, SDHC_TRANSFER_COMPLETE,
- SDHC_TRANSFER_TIMEOUT))
+ SDHC_TRANSFER_TIMEOUT)) {
+ DPRINTF(1,("%s: timeout for transfer\n", __func__));
error = ETIMEDOUT;
+ }
return error;
}
@@ -2022,6 +2035,7 @@
sdmmc_delay(1);
}
if (timo == 0)
+ DPRINTF(1,("%s: timeout for reset on\n", __func__));
return ETIMEDOUT;
}
@@ -2050,33 +2064,73 @@
static int
sdhc_wait_intr(struct sdhc_host *hp, int mask, int timo)
{
- int status;
+ int status, error, nointr;
KASSERT(mutex_owned(&hp->intr_lock));
mask |= SDHC_ERROR_INTERRUPT;
+ nointr = 0;
status = hp->intr_status & mask;
while (status == 0) {
if (cv_timedwait(&hp->intr_cv, &hp->intr_lock, timo)
== EWOULDBLOCK) {
- status |= SDHC_ERROR_INTERRUPT;
+ nointr = 1;
break;
}
status = hp->intr_status & mask;
}
- hp->intr_status &= ~status;
+ error = hp->intr_error_status;
DPRINTF(2,("%s: intr status %#x error %#x\n", HDEVNAME(hp), status,
- hp->intr_error_status));
+ error));
+
+ hp->intr_status &= ~status;
+ hp->intr_error_status &= ~error;
- /* Command timeout has higher priority than command complete. */
- if (ISSET(status, SDHC_ERROR_INTERRUPT) || hp->intr_error_status) {
+ if (ISSET(status, SDHC_ERROR_INTERRUPT)) {
+ if (ISSET(error, SDHC_DMA_ERROR))
+ device_printf(hp->sc->sc_dev,"dma error\n");
+ if (ISSET(error, SDHC_ADMA_ERROR))
+ device_printf(hp->sc->sc_dev,"adma error\n");
+ if (ISSET(error, SDHC_AUTO_CMD12_ERROR))
+ device_printf(hp->sc->sc_dev,"auto_cmd12 error\n");
+ if (ISSET(error, SDHC_CURRENT_LIMIT_ERROR))
+ device_printf(hp->sc->sc_dev,"current limit error\n");
+ if (ISSET(error, SDHC_DATA_END_BIT_ERROR))
+ device_printf(hp->sc->sc_dev,"data end bit error\n");
+ if (ISSET(error, SDHC_DATA_CRC_ERROR))
+ device_printf(hp->sc->sc_dev,"data crc error\n");
+ if (ISSET(error, SDHC_DATA_TIMEOUT_ERROR))
+ device_printf(hp->sc->sc_dev,"data timeout error\n");
+ if (ISSET(error, SDHC_CMD_INDEX_ERROR))
+ device_printf(hp->sc->sc_dev,"cmd index error\n");
+ if (ISSET(error, SDHC_CMD_END_BIT_ERROR))
+ device_printf(hp->sc->sc_dev,"cmd end bit error\n");
+ if (ISSET(error, SDHC_CMD_CRC_ERROR))
+ device_printf(hp->sc->sc_dev,"cmd crc error\n");
+ if (ISSET(error, SDHC_CMD_TIMEOUT_ERROR))
+ device_printf(hp->sc->sc_dev,"cmd timeout error\n");
+ if ((error & ~SDHC_EINTR_STATUS_MASK) != 0)
+ device_printf(hp->sc->sc_dev,"vendor error %#x\n",
+ (error & ~SDHC_EINTR_STATUS_MASK));
+ if (error == 0)
+ device_printf(hp->sc->sc_dev,"no error\n");
+
+ /* Command timeout has higher priority than command complete. */
+ if (ISSET(error, SDHC_CMD_TIMEOUT_ERROR))
+ CLR(status, SDHC_COMMAND_COMPLETE);
+
+ /* Transfer complete has higher priority than data timeout. */
+ if (ISSET(status, SDHC_TRANSFER_COMPLETE))
+ CLR(error, SDHC_DATA_TIMEOUT_ERROR);
+ }
+
+ if (nointr ||
+ (ISSET(status, SDHC_ERROR_INTERRUPT) && error)) {
+ if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED))
+ (void)sdhc_soft_reset(hp, SDHC_RESET_CMD|SDHC_RESET_DAT);
hp->intr_error_status = 0;
- hp->intr_status &= ~SDHC_ERROR_INTERRUPT;
- if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) {
- (void)sdhc_soft_reset(hp, SDHC_RESET_DAT|SDHC_RESET_CMD);
- }
status = 0;
}
@@ -2135,23 +2189,14 @@
/* Claim this interrupt. */
done = 1;
- if (ISSET(error, SDHC_ADMA_ERROR)) {
+ if (ISSET(status, SDHC_ERROR_INTERRUPT) &&
+ ISSET(error, SDHC_ADMA_ERROR)) {
uint8_t adma_err = HREAD1(hp, SDHC_ADMA_ERROR_STATUS);
printf("%s: ADMA error, status %02x\n", HDEVNAME(hp),
adma_err);
}
/*
- * Service error interrupts.
- */
- if (ISSET(error, SDHC_CMD_TIMEOUT_ERROR|
- SDHC_DATA_TIMEOUT_ERROR)) {
- hp->intr_error_status |= error;
- hp->intr_status |= status;
- cv_broadcast(&hp->intr_cv);
- }
-
- /*
* Wake up the sdmmc event thread to scan for cards.
*/
if (ISSET(status, SDHC_CARD_REMOVAL|SDHC_CARD_INSERTION)) {
@@ -2178,8 +2223,10 @@
* related interrupt(s).
*/
if (ISSET(status, SDHC_COMMAND_COMPLETE|
+ SDHC_CMD_TIMEOUT_ERROR|SDHC_DATA_TIMEOUT_ERROR|
SDHC_BUFFER_READ_READY|SDHC_BUFFER_WRITE_READY|
SDHC_TRANSFER_COMPLETE|SDHC_DMA_INTERRUPT)) {
+ hp->intr_error_status |= error;
hp->intr_status |= status;
if (ISSET(sc->sc_flags, SDHC_FLAG_ENHANCED)) {
HCLR4(hp, SDHC_NINTR_SIGNAL_EN,
Home |
Main Index |
Thread Index |
Old Index