aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorSeungwon Jeon <tgih.jun@samsung.com>2013-08-30 11:14:05 -0400
committerChris Ball <cjb@laptop.org>2013-09-25 21:35:40 -0400
commit90c2143a8f6d0cd1dbae1ea32fcd1befb81e4b0d (patch)
tree719fb73b4dd807f0aa673207ed62cbd170d2628d /drivers/mmc
parent71abb1339436160b6ab0ae2f816a4046c7328f28 (diff)
mmc: dw_mmc: guarantee stop-abort cmd in data errors
In error cases, DTO interrupt may or may not be generated depending on remained data. Stop/Abort command ensures DTO generation for that situation. Currently if 'stop' field of data is empty, there is no stop/abort command. So, it could hang waiting DTO. This change reinforces these cases. Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com> Tested-by: Alim Akhtar <alim.akhtar@samsung.com> Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/dw_mmc.c84
1 files changed, 64 insertions, 20 deletions
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 649127e71894..b4328ad59cf0 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -29,6 +29,7 @@
29#include <linux/irq.h> 29#include <linux/irq.h>
30#include <linux/mmc/host.h> 30#include <linux/mmc/host.h>
31#include <linux/mmc/mmc.h> 31#include <linux/mmc/mmc.h>
32#include <linux/mmc/sdio.h>
32#include <linux/mmc/dw_mmc.h> 33#include <linux/mmc/dw_mmc.h>
33#include <linux/bitops.h> 34#include <linux/bitops.h>
34#include <linux/regulator/consumer.h> 35#include <linux/regulator/consumer.h>
@@ -246,10 +247,15 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
246 247
247 cmdr = cmd->opcode; 248 cmdr = cmd->opcode;
248 249
249 if (cmdr == MMC_STOP_TRANSMISSION) 250 if (cmd->opcode == MMC_STOP_TRANSMISSION ||
251 cmd->opcode == MMC_GO_IDLE_STATE ||
252 cmd->opcode == MMC_GO_INACTIVE_STATE ||
253 (cmd->opcode == SD_IO_RW_DIRECT &&
254 ((cmd->arg >> 9) & 0x1FFFF) == SDIO_CCCR_ABORT))
250 cmdr |= SDMMC_CMD_STOP; 255 cmdr |= SDMMC_CMD_STOP;
251 else 256 else
252 cmdr |= SDMMC_CMD_PRV_DAT_WAIT; 257 if (cmd->opcode != MMC_SEND_STATUS && cmd->data)
258 cmdr |= SDMMC_CMD_PRV_DAT_WAIT;
253 259
254 if (cmd->flags & MMC_RSP_PRESENT) { 260 if (cmd->flags & MMC_RSP_PRESENT) {
255 /* We expect a response, so set this bit */ 261 /* We expect a response, so set this bit */
@@ -276,6 +282,40 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
276 return cmdr; 282 return cmdr;
277} 283}
278 284
285static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd)
286{
287 struct mmc_command *stop;
288 u32 cmdr;
289
290 if (!cmd->data)
291 return 0;
292
293 stop = &host->stop_abort;
294 cmdr = cmd->opcode;
295 memset(stop, 0, sizeof(struct mmc_command));
296
297 if (cmdr == MMC_READ_SINGLE_BLOCK ||
298 cmdr == MMC_READ_MULTIPLE_BLOCK ||
299 cmdr == MMC_WRITE_BLOCK ||
300 cmdr == MMC_WRITE_MULTIPLE_BLOCK) {
301 stop->opcode = MMC_STOP_TRANSMISSION;
302 stop->arg = 0;
303 stop->flags = MMC_RSP_R1B | MMC_CMD_AC;
304 } else if (cmdr == SD_IO_RW_EXTENDED) {
305 stop->opcode = SD_IO_RW_DIRECT;
306 stop->arg |= (1 << 31) | (0 << 28) | (SDIO_CCCR_ABORT << 9) |
307 ((cmd->arg >> 28) & 0x7);
308 stop->flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;
309 } else {
310 return 0;
311 }
312
313 cmdr = stop->opcode | SDMMC_CMD_STOP |
314 SDMMC_CMD_RESP_CRC | SDMMC_CMD_RESP_EXP;
315
316 return cmdr;
317}
318
279static void dw_mci_start_command(struct dw_mci *host, 319static void dw_mci_start_command(struct dw_mci *host,
280 struct mmc_command *cmd, u32 cmd_flags) 320 struct mmc_command *cmd, u32 cmd_flags)
281{ 321{
@@ -290,9 +330,10 @@ static void dw_mci_start_command(struct dw_mci *host,
290 mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START); 330 mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
291} 331}
292 332
293static void send_stop_cmd(struct dw_mci *host, struct mmc_data *data) 333static inline void send_stop_abort(struct dw_mci *host, struct mmc_data *data)
294{ 334{
295 dw_mci_start_command(host, data->stop, host->stop_cmdr); 335 struct mmc_command *stop = data->stop ? data->stop : &host->stop_abort;
336 dw_mci_start_command(host, stop, host->stop_cmdr);
296} 337}
297 338
298/* DMA interface functions */ 339/* DMA interface functions */
@@ -828,6 +869,8 @@ static void __dw_mci_start_request(struct dw_mci *host,
828 869
829 if (mrq->stop) 870 if (mrq->stop)
830 host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop); 871 host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop);
872 else
873 host->stop_cmdr = dw_mci_prep_stop_abort(host, cmd);
831} 874}
832 875
833static void dw_mci_start_request(struct dw_mci *host, 876static void dw_mci_start_request(struct dw_mci *host,
@@ -1190,13 +1233,9 @@ static void dw_mci_tasklet_func(unsigned long priv)
1190 1233
1191 if (cmd->data && cmd->error) { 1234 if (cmd->data && cmd->error) {
1192 dw_mci_stop_dma(host); 1235 dw_mci_stop_dma(host);
1193 if (data->stop) { 1236 send_stop_abort(host, data);
1194 send_stop_cmd(host, data); 1237 state = STATE_SENDING_STOP;
1195 state = STATE_SENDING_STOP; 1238 break;
1196 break;
1197 } else {
1198 host->data = NULL;
1199 }
1200 } 1239 }
1201 1240
1202 if (!host->mrq->data || cmd->error) { 1241 if (!host->mrq->data || cmd->error) {
@@ -1211,8 +1250,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
1211 if (test_and_clear_bit(EVENT_DATA_ERROR, 1250 if (test_and_clear_bit(EVENT_DATA_ERROR,
1212 &host->pending_events)) { 1251 &host->pending_events)) {
1213 dw_mci_stop_dma(host); 1252 dw_mci_stop_dma(host);
1214 if (data->stop) 1253 send_stop_abort(host, data);
1215 send_stop_cmd(host, data);
1216 state = STATE_DATA_ERROR; 1254 state = STATE_DATA_ERROR;
1217 break; 1255 break;
1218 } 1256 }
@@ -1272,7 +1310,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
1272 data->error = 0; 1310 data->error = 0;
1273 } 1311 }
1274 1312
1275 if (!data->stop) { 1313 if (!data->stop && !data->error) {
1276 dw_mci_request_end(host, host->mrq); 1314 dw_mci_request_end(host, host->mrq);
1277 goto unlock; 1315 goto unlock;
1278 } 1316 }
@@ -1284,8 +1322,10 @@ static void dw_mci_tasklet_func(unsigned long priv)
1284 } 1322 }
1285 1323
1286 prev_state = state = STATE_SENDING_STOP; 1324 prev_state = state = STATE_SENDING_STOP;
1287 if (!data->error) 1325 if (data->stop && !data->error) {
1288 send_stop_cmd(host, data); 1326 /* stop command for open-ended transfer*/
1327 send_stop_abort(host, data);
1328 }
1289 /* fall through */ 1329 /* fall through */
1290 1330
1291 case STATE_SENDING_STOP: 1331 case STATE_SENDING_STOP:
@@ -1304,7 +1344,12 @@ static void dw_mci_tasklet_func(unsigned long priv)
1304 1344
1305 host->cmd = NULL; 1345 host->cmd = NULL;
1306 host->data = NULL; 1346 host->data = NULL;
1307 dw_mci_command_complete(host, host->mrq->stop); 1347
1348 if (host->mrq->stop)
1349 dw_mci_command_complete(host, host->mrq->stop);
1350 else
1351 host->cmd_status = 0;
1352
1308 dw_mci_request_end(host, host->mrq); 1353 dw_mci_request_end(host, host->mrq);
1309 goto unlock; 1354 goto unlock;
1310 1355
@@ -1888,11 +1933,10 @@ static void dw_mci_work_routine_card(struct work_struct *work)
1888 case STATE_DATA_ERROR: 1933 case STATE_DATA_ERROR:
1889 if (mrq->data->error == -EINPROGRESS) 1934 if (mrq->data->error == -EINPROGRESS)
1890 mrq->data->error = -ENOMEDIUM; 1935 mrq->data->error = -ENOMEDIUM;
1891 if (!mrq->stop)
1892 break;
1893 /* fall through */ 1936 /* fall through */
1894 case STATE_SENDING_STOP: 1937 case STATE_SENDING_STOP:
1895 mrq->stop->error = -ENOMEDIUM; 1938 if (mrq->stop)
1939 mrq->stop->error = -ENOMEDIUM;
1896 break; 1940 break;
1897 } 1941 }
1898 1942