Module Name: src
Committed By: jmcneill
Date: Thu Jan 23 23:53:55 UTC 2020
Modified Files:
src/sys/dev/ic: dwc_mmc.c dwc_mmc_var.h
Log Message:
More SDIO stability and performance fixes
To generate a diff of this commit:
cvs rdiff -u -r1.21 -r1.22 src/sys/dev/ic/dwc_mmc.c
cvs rdiff -u -r1.12 -r1.13 src/sys/dev/ic/dwc_mmc_var.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/ic/dwc_mmc.c
diff -u src/sys/dev/ic/dwc_mmc.c:1.21 src/sys/dev/ic/dwc_mmc.c:1.22
--- src/sys/dev/ic/dwc_mmc.c:1.21 Wed Jan 22 23:19:12 2020
+++ src/sys/dev/ic/dwc_mmc.c Thu Jan 23 23:53:55 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: dwc_mmc.c,v 1.21 2020/01/22 23:19:12 jmcneill Exp $ */
+/* $NetBSD: dwc_mmc.c,v 1.22 2020/01/23 23:53:55 jmcneill Exp $ */
/*-
* Copyright (c) 2014-2017 Jared McNeill <[email protected]>
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dwc_mmc.c,v 1.21 2020/01/22 23:19:12 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dwc_mmc.c,v 1.22 2020/01/23 23:53:55 jmcneill Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -297,6 +297,11 @@ dwc_mmc_write_protect(sdmmc_chipset_hand
static int
dwc_mmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr)
{
+ struct dwc_mmc_softc *sc = sch;
+
+ if (ocr == 0)
+ sc->sc_card_inited = false;
+
return 0;
}
@@ -573,6 +578,7 @@ dwc_mmc_exec_command(sdmmc_chipset_handl
uint32_t cmdval = DWC_MMC_CMD_START;
int retry, error;
uint32_t imask;
+ u_int reg;
#ifdef DWC_MMC_DEBUG
aprint_normal_dev(sc->sc_dev,
@@ -581,24 +587,41 @@ dwc_mmc_exec_command(sdmmc_chipset_handl
cmd->c_blklen);
#endif
- mutex_enter(&sc->sc_intr_lock);
+ mutex_enter(&sc->sc_lock);
if (sc->sc_curcmd != NULL) {
device_printf(sc->sc_dev,
"WARNING: driver submitted a command while the controller was busy\n");
cmd->c_error = EBUSY;
SET(cmd->c_flags, SCF_ITSDONE);
- mutex_exit(&sc->sc_intr_lock);
+ mutex_exit(&sc->sc_lock);
return;
}
sc->sc_curcmd = cmd;
MMC_WRITE(sc, DWC_MMC_IDST, 0xffffffff);
+ if (!sc->sc_card_inited) {
+ cmdval |= DWC_MMC_CMD_SEND_INIT_SEQ;
+ sc->sc_card_inited = true;
+ }
+
if (ISSET(sc->sc_flags, DWC_MMC_F_USE_HOLD_REG))
cmdval |= DWC_MMC_CMD_USE_HOLD_REG;
- if (cmd->c_opcode == MMC_GO_IDLE_STATE)
- cmdval |= DWC_MMC_CMD_SEND_INIT_SEQ;
+ switch (cmd->c_opcode) {
+ case SD_IO_RW_DIRECT:
+ reg = (cmd->c_arg >> SD_ARG_CMD52_REG_SHIFT) &
+ SD_ARG_CMD52_REG_MASK;
+ if (reg != 0x6) /* func abort / card reset */
+ break;
+ /* FALLTHROUGH */
+ case MMC_GO_IDLE_STATE:
+ case MMC_STOP_TRANSMISSION:
+ case MMC_INACTIVE_STATE:
+ cmdval |= DWC_MMC_CMD_STOP_ABORT_CMD;
+ break;
+ }
+
if (cmd->c_flags & SCF_RSP_PRESENT)
cmdval |= DWC_MMC_CMD_RSP_EXP;
if (cmd->c_flags & SCF_RSP_136)
@@ -613,10 +636,10 @@ dwc_mmc_exec_command(sdmmc_chipset_handl
MMC_WRITE(sc, DWC_MMC_GCTRL,
MMC_READ(sc, DWC_MMC_GCTRL) | DWC_MMC_GCTRL_FIFORESET);
- for (retry = 0; retry < 100; retry++) {
+ for (retry = 0; retry < 100000; retry++) {
if (!(MMC_READ(sc, DWC_MMC_DMAC) & DWC_MMC_DMAC_SOFTRESET))
break;
- kpause("dwcmmcfifo", false, uimax(mstohz(1), 1), &sc->sc_intr_lock);
+ delay(1);
}
cmdval |= DWC_MMC_CMD_DATA_EXP | DWC_MMC_CMD_WAIT_PRE_OVER;
@@ -671,6 +694,16 @@ dwc_mmc_exec_command(sdmmc_chipset_handl
}
sc->sc_wait_cmd = true;
+ if ((cmdval & DWC_MMC_CMD_WAIT_PRE_OVER) != 0) {
+ for (retry = 0; retry < 10000; retry++) {
+ if (!(MMC_READ(sc, DWC_MMC_STATUS) & DWC_MMC_STATUS_CARD_DATA_BUSY))
+ break;
+ delay(1);
+ }
+ }
+
+ mutex_enter(&sc->sc_intr_lock);
+
MMC_WRITE(sc, DWC_MMC_CMD, cmdval | cmd->c_opcode);
if (sc->sc_wait_dma)
@@ -688,6 +721,8 @@ dwc_mmc_exec_command(sdmmc_chipset_handl
}
}
+ mutex_exit(&sc->sc_intr_lock);
+
if (cmd->c_error == 0 && cmd->c_datalen > 0)
dwc_mmc_dma_complete(sc, cmd);
@@ -720,8 +755,6 @@ done:
MMC_WRITE(sc, DWC_MMC_IDIE, 0);
MMC_WRITE(sc, DWC_MMC_RINT, 0x7fff);
MMC_WRITE(sc, DWC_MMC_IDST, 0xffffffff);
- sc->sc_curcmd = NULL;
- mutex_exit(&sc->sc_intr_lock);
if (cmd->c_error) {
#ifdef DWC_MMC_DEBUG
@@ -731,9 +764,12 @@ done:
for (retry = 0; retry < 100; retry++) {
if (!(MMC_READ(sc, DWC_MMC_DMAC) & DWC_MMC_DMAC_SOFTRESET))
break;
- kpause("dwcmmcrst", false, uimax(mstohz(1), 1), NULL);
+ kpause("dwcmmcrst", false, uimax(mstohz(1), 1), &sc->sc_lock);
}
}
+
+ sc->sc_curcmd = NULL;
+ mutex_exit(&sc->sc_lock);
}
static void
@@ -788,6 +824,7 @@ dwc_mmc_init(struct dwc_mmc_softc *sc)
if (sc->sc_intr_cardmask == 0)
sc->sc_intr_cardmask = DWC_MMC_INT_SDIO_INT(0);
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_BIO);
cv_init(&sc->sc_intr_cv, "dwcmmcirq");
Index: src/sys/dev/ic/dwc_mmc_var.h
diff -u src/sys/dev/ic/dwc_mmc_var.h:1.12 src/sys/dev/ic/dwc_mmc_var.h:1.13
--- src/sys/dev/ic/dwc_mmc_var.h:1.12 Wed Jan 22 23:19:12 2020
+++ src/sys/dev/ic/dwc_mmc_var.h Thu Jan 23 23:53:55 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: dwc_mmc_var.h,v 1.12 2020/01/22 23:19:12 jmcneill Exp $ */
+/* $NetBSD: dwc_mmc_var.h,v 1.13 2020/01/23 23:53:55 jmcneill Exp $ */
/*-
* Copyright (c) 2014-2017 Jared McNeill <[email protected]>
@@ -44,8 +44,10 @@ struct dwc_mmc_softc {
uint32_t sc_fifo_depth;
u_int sc_clock_freq;
u_int sc_bus_width;
+ bool sc_card_inited;
void *sc_ih;
+ kmutex_t sc_lock;
kmutex_t sc_intr_lock;
kcondvar_t sc_intr_cv;