aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorSeungwon Jeon <tgih.jun@samsung.com>2013-08-30 11:13:59 -0400
committerChris Ball <cjb@laptop.org>2013-09-25 21:34:57 -0400
commit71abb1339436160b6ab0ae2f816a4046c7328f28 (patch)
tree93e970bca8253e586a96d9b228b4f082a46693ec /drivers/mmc
parentf1d2736c815629f3b43d8eebf73a81b581438e65 (diff)
mmc: dw_mmc: fix error handling on response error
Even if response error is detected in case data command, data transfer is continued. It means that data can live in FIFO. Current handling just breaks out the request when seeing the command error. This causes kernel panic in dw_mci_read_data_pio() [host->data = NULL]. And also, FIFO should be guaranteed to be empty. Unable to handle kernel NULL pointer dereference at virtual address 00000018 <...> [<c02af814>] (dw_mci_read_data_pio+0x68/0x198) from [<c02b04b4>] (dw_mci_interrupt+0x374/0x3a0) [<c02b04b4>] (dw_mci_interrupt+0x374/0x3a0) from [<c006b094>] (handle_irq_event_percpu+0x50/0x194) [<c006b094>] (handle_irq_event_percpu+0x50/0x194) from [<c006b214>] (handle_irq_event+0x3c/0x5c) [<c006b214>] (handle_irq_event+0x3c/0x5c) from [<c006de1c>] (handle_fasteoi_irq+0xa4/0x148) [<c006de1c>] (handle_fasteoi_irq+0xa4/0x148) from [<c006aa88>] (generic_handle_irq+0x20/0x30) [<c006aa88>] (generic_handle_irq+0x20/0x30) from [<c000f154>] (handle_IRQ+0x38/0x90) [<c000f154>] (handle_IRQ+0x38/0x90) from [<c00085bc>] (gic_handle_irq+0x34/0x68) [<c00085bc>] (gic_handle_irq+0x34/0x68) from [<c0011f40>] (__irq_svc+0x40/0x70) Exception stack(0xef0b1c00 to 0xef0b1c48) 1c00: 000eb0cf ffffffff 00001300 c01a7738 ef295e10 0000000a c04df298 ef0b1dc0 1c20: ef295ec0 00000000 00000000 00000006 00000000 ef0b1c48 c02b1274 c01a7764 1c40: 20000113 ffffffff [<c0011f40>] (__irq_svc+0x40/0x70) from [<c01a7764>] (__loop_delay+0x0/0xc) Code: e1a00005 e0891006 e0662004 e12fff33 (e59a3018) ---[ end trace a7043b9ba9aed1db ]--- Kernel panic - not syncing: Fatal exception in interrupt 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.c26
1 files changed, 21 insertions, 5 deletions
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 8eb37983a72a..649127e71894 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1148,11 +1148,6 @@ static void dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd
1148 /* newer ip versions need a delay between retries */ 1148 /* newer ip versions need a delay between retries */
1149 if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY) 1149 if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY)
1150 mdelay(20); 1150 mdelay(20);
1151
1152 if (cmd->data) {
1153 dw_mci_stop_dma(host);
1154 host->data = NULL;
1155 }
1156 } 1151 }
1157} 1152}
1158 1153
@@ -1193,6 +1188,17 @@ static void dw_mci_tasklet_func(unsigned long priv)
1193 goto unlock; 1188 goto unlock;
1194 } 1189 }
1195 1190
1191 if (cmd->data && cmd->error) {
1192 dw_mci_stop_dma(host);
1193 if (data->stop) {
1194 send_stop_cmd(host, data);
1195 state = STATE_SENDING_STOP;
1196 break;
1197 } else {
1198 host->data = NULL;
1199 }
1200 }
1201
1196 if (!host->mrq->data || cmd->error) { 1202 if (!host->mrq->data || cmd->error) {
1197 dw_mci_request_end(host, host->mrq); 1203 dw_mci_request_end(host, host->mrq);
1198 goto unlock; 1204 goto unlock;
@@ -1287,7 +1293,17 @@ static void dw_mci_tasklet_func(unsigned long priv)
1287 &host->pending_events)) 1293 &host->pending_events))
1288 break; 1294 break;
1289 1295
1296 /* CMD error in data command */
1297 if (host->mrq->cmd->error && host->mrq->data) {
1298 sg_miter_stop(&host->sg_miter);
1299 host->sg = NULL;
1300 ctrl = mci_readl(host, CTRL);
1301 ctrl |= SDMMC_CTRL_FIFO_RESET;
1302 mci_writel(host, CTRL, ctrl);
1303 }
1304
1290 host->cmd = NULL; 1305 host->cmd = NULL;
1306 host->data = NULL;
1291 dw_mci_command_complete(host, host->mrq->stop); 1307 dw_mci_command_complete(host, host->mrq->stop);
1292 dw_mci_request_end(host, host->mrq); 1308 dw_mci_request_end(host, host->mrq);
1293 goto unlock; 1309 goto unlock;