Skip to content

Commit 25f8203

Browse files
vwaxstorulf
authored andcommitted
mmc: dw_mmc: Fix hang on data CRC error
When a Data CRC interrupt is received, the driver disables the DMA, then sends the stop/abort command and then waits for Data Transfer Over. However, sometimes, when a data CRC error is received in the middle of a multi-block write transfer, the Data Transfer Over interrupt is never received, and the driver hangs and never completes the request. The driver sets the BMOD.SWR bit (SDMMC_IDMAC_SWRESET) when stopping the DMA, but according to the manual CMD.STOP_ABORT_CMD should be programmed "before assertion of SWR". Do these operations in the recommended order. With this change the Data Transfer Over is always received correctly in my tests. Signed-off-by: Vincent Whitchurch <[email protected]> Reviewed-by: Jaehoon Chung <[email protected]> Cc: [email protected] Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Ulf Hansson <[email protected]>
1 parent c500bee commit 25f8203

File tree

1 file changed

+3
-3
lines changed

1 file changed

+3
-3
lines changed

drivers/mmc/host/dw_mmc.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2018,8 +2018,8 @@ static void dw_mci_tasklet_func(struct tasklet_struct *t)
20182018
continue;
20192019
}
20202020

2021-
dw_mci_stop_dma(host);
20222021
send_stop_abort(host, data);
2022+
dw_mci_stop_dma(host);
20232023
state = STATE_SENDING_STOP;
20242024
break;
20252025
}
@@ -2043,10 +2043,10 @@ static void dw_mci_tasklet_func(struct tasklet_struct *t)
20432043
*/
20442044
if (test_and_clear_bit(EVENT_DATA_ERROR,
20452045
&host->pending_events)) {
2046-
dw_mci_stop_dma(host);
20472046
if (!(host->data_status & (SDMMC_INT_DRTO |
20482047
SDMMC_INT_EBE)))
20492048
send_stop_abort(host, data);
2049+
dw_mci_stop_dma(host);
20502050
state = STATE_DATA_ERROR;
20512051
break;
20522052
}
@@ -2079,10 +2079,10 @@ static void dw_mci_tasklet_func(struct tasklet_struct *t)
20792079
*/
20802080
if (test_and_clear_bit(EVENT_DATA_ERROR,
20812081
&host->pending_events)) {
2082-
dw_mci_stop_dma(host);
20832082
if (!(host->data_status & (SDMMC_INT_DRTO |
20842083
SDMMC_INT_EBE)))
20852084
send_stop_abort(host, data);
2085+
dw_mci_stop_dma(host);
20862086
state = STATE_DATA_ERROR;
20872087
break;
20882088
}

0 commit comments

Comments
 (0)