aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/msm_sdcc.c
diff options
context:
space:
mode:
authorSan Mehat <san@google.com>2009-11-21 15:29:46 -0500
committerDaniel Walker <dwalker@codeaurora.org>2010-03-18 16:16:09 -0400
commit56a8b5b8ae81bd766e527a0e5274a087c3c1109d (patch)
treed87ed81abc7a0e7cbe35156d7069d5acab64fb4c /drivers/mmc/host/msm_sdcc.c
parent51905dcbcf1f72a17f491c64485d513986110a6f (diff)
mmc: msm_sdcc: Reduce command timeouts and improve reliability.
Based on an original patch by Brent DeGraaf: "Previous versions of the SD driver were beset with excessive command timeouts. These timeouts were silent by default, but happened frequently, especially during heavy system activity and concurrent access of two or more SD devices. Worst case, these timeouts would occasionally hit at the end of a successful write, resulting in false failures that could adversely affect journaling file systems if timing was unfortunate. This update tightens the association and timing between dma transfers and the commands that trigger them by utilizing a new api implemented in the datamover. In addition, it also fixes a dma cache coherency issue that was exposed during testing of this fix that occasionally resulted in card corruption. Processing of results in the interrupt status routine was modified to process command results prior to data because overwritten command results were observed during testing since the data section can result in command issuances of its own. This change also eliminates the software command timeout, relying entirely on the hardware version, since the software timeout was found to cause problems of its own after extensive testing (having hardware timer and software timers addressing the same issue was found to cause a race condition under heavy system load)." This change originally added PROG_DONE handling, which has been split out into a separate patch. Also on our platform, the data mover driver maintains coherency to ensure API reliability, so the above mentioned cache corruption issue was not an issue for us. Signed-off-by: San Mehat <san@google.com> Cc: Brian Swetland <swetland@google.com> Change-Id: Ifbf17cfafb858106d73bf49af52b5161a265a484 Signed-off-by: San Mehat <san@google.com> Signed-off-by: Daniel Walker <dwalker@codeaurora.org>
Diffstat (limited to 'drivers/mmc/host/msm_sdcc.c')
-rw-r--r--drivers/mmc/host/msm_sdcc.c267
1 files changed, 148 insertions, 119 deletions
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 84b284e3a288..524858597901 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -3,6 +3,7 @@
3 * 3 *
4 * Copyright (C) 2007 Google Inc, 4 * Copyright (C) 2007 Google Inc,
5 * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. 5 * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
6 * Copyright (C) 2009, Code Aurora Forum. All Rights Reserved.
6 * 7 *
7 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as 9 * it under the terms of the GNU General Public License version 2 as
@@ -47,6 +48,7 @@
47 48
48#define DRIVER_NAME "msm-sdcc" 49#define DRIVER_NAME "msm-sdcc"
49 50
51#define BUSCLK_TIMEOUT (HZ * 5)
50static unsigned int msmsdcc_fmin = 144000; 52static unsigned int msmsdcc_fmin = 144000;
51static unsigned int msmsdcc_fmax = 50000000; 53static unsigned int msmsdcc_fmax = 50000000;
52static unsigned int msmsdcc_4bit = 1; 54static unsigned int msmsdcc_4bit = 1;
@@ -106,8 +108,6 @@ msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
106static void 108static void
107msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) 109msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
108{ 110{
109 msmsdcc_writel(host, 0, MMCICOMMAND);
110
111 BUG_ON(host->curr.data); 111 BUG_ON(host->curr.data);
112 112
113 host->curr.mrq = NULL; 113 host->curr.mrq = NULL;
@@ -119,7 +119,7 @@ msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
119 mdelay(5); 119 mdelay(5);
120 120
121 if (host->use_bustimer) 121 if (host->use_bustimer)
122 mod_timer(&host->busclk_timer, jiffies + HZ); 122 mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT);
123 /* 123 /*
124 * Need to drop the host lock here; mmc_request_done may call 124 * Need to drop the host lock here; mmc_request_done may call
125 * back into the driver... 125 * back into the driver...
@@ -132,7 +132,6 @@ msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
132static void 132static void
133msmsdcc_stop_data(struct msmsdcc_host *host) 133msmsdcc_stop_data(struct msmsdcc_host *host)
134{ 134{
135 msmsdcc_writel(host, 0, MMCIDATACTRL);
136 host->curr.data = NULL; 135 host->curr.data = NULL;
137 host->curr.got_dataend = host->curr.got_datablkend = 0; 136 host->curr.got_dataend = host->curr.got_datablkend = 0;
138} 137}
@@ -153,6 +152,29 @@ uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
153 return 0; 152 return 0;
154} 153}
155 154
155static inline void
156msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c) {
157 msmsdcc_writel(host, arg, MMCIARGUMENT);
158 msmsdcc_writel(host, c, MMCICOMMAND);
159}
160
161static void
162msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
163{
164 struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->data;
165
166 writel(host->cmd_timeout, host->base + MMCIDATATIMER);
167 writel((unsigned int)host->curr.xfer_size, host->base + MMCIDATALENGTH);
168 writel(host->cmd_pio_irqmask, host->base + MMCIMASK1);
169 writel(host->cmd_datactrl, host->base + MMCIDATACTRL);
170
171 if (host->cmd_cmd) {
172 msmsdcc_start_command_exec(host,
173 (u32)host->cmd_cmd->arg, (u32)host->cmd_c);
174 }
175 host->dma.active = 1;
176}
177
156static void 178static void
157msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, 179msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
158 unsigned int result, 180 unsigned int result,
@@ -165,6 +187,8 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
165 struct mmc_request *mrq; 187 struct mmc_request *mrq;
166 188
167 spin_lock_irqsave(&host->lock, flags); 189 spin_lock_irqsave(&host->lock, flags);
190 host->dma.active = 0;
191
168 mrq = host->curr.mrq; 192 mrq = host->curr.mrq;
169 BUG_ON(!mrq); 193 BUG_ON(!mrq);
170 194
@@ -190,7 +214,6 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
190 if (!mrq->data->error) 214 if (!mrq->data->error)
191 mrq->data->error = -EIO; 215 mrq->data->error = -EIO;
192 } 216 }
193 host->dma.busy = 0;
194 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents, 217 dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
195 host->dma.dir); 218 host->dma.dir);
196 219
@@ -203,6 +226,7 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
203 } 226 }
204 227
205 host->dma.sg = NULL; 228 host->dma.sg = NULL;
229 host->dma.busy = 0;
206 230
207 if ((host->curr.got_dataend && host->curr.got_datablkend) 231 if ((host->curr.got_dataend && host->curr.got_datablkend)
208 || mrq->data->error) { 232 || mrq->data->error) {
@@ -262,6 +286,8 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
262 host->dma.sg = data->sg; 286 host->dma.sg = data->sg;
263 host->dma.num_ents = data->sg_len; 287 host->dma.num_ents = data->sg_len;
264 288
289 BUG_ON(host->dma.num_ents > NR_SG); /* Prevent memory corruption */
290
265 nc = host->dma.nc; 291 nc = host->dma.nc;
266 292
267 switch (host->pdev_id) { 293 switch (host->pdev_id) {
@@ -290,22 +316,15 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
290 316
291 host->curr.user_pages = 0; 317 host->curr.user_pages = 0;
292 318
293 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
294 host->dma.num_ents, host->dma.dir);
295
296 if (n != host->dma.num_ents) {
297 pr_err("%s: Unable to map in all sg elements\n",
298 mmc_hostname(host->mmc));
299 host->dma.sg = NULL;
300 host->dma.num_ents = 0;
301 return -ENOMEM;
302 }
303
304 box = &nc->cmd[0]; 319 box = &nc->cmd[0];
305 for (i = 0; i < host->dma.num_ents; i++) { 320 for (i = 0; i < host->dma.num_ents; i++) {
306 box->cmd = CMD_MODE_BOX; 321 box->cmd = CMD_MODE_BOX;
307 322
308 if (i == (host->dma.num_ents - 1)) 323 /* Initialize sg dma address */
324 sg->dma_address = page_to_dma(mmc_dev(host->mmc), sg_page(sg))
325 + sg->offset;
326
327 if (i == (host->dma.num_ents - 1))
309 box->cmd |= CMD_LC; 328 box->cmd |= CMD_LC;
310 rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ? 329 rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ?
311 (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 : 330 (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 :
@@ -343,13 +362,68 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
343 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST | 362 host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
344 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr); 363 DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
345 host->dma.hdr.complete_func = msmsdcc_dma_complete_func; 364 host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
346 host->dma.hdr.execute_func = NULL;
347 365
366 n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
367 host->dma.num_ents, host->dma.dir);
368/* dsb inside dma_map_sg will write nc out to mem as well */
369
370 if (n != host->dma.num_ents) {
371 printk(KERN_ERR "%s: Unable to map in all sg elements\n",
372 mmc_hostname(host->mmc));
373 host->dma.sg = NULL;
374 host->dma.num_ents = 0;
375 return -ENOMEM;
376 }
377
378 return 0;
379}
380
381static int
382snoop_cccr_abort(struct mmc_command *cmd)
383{
384 if ((cmd->opcode == 52) &&
385 (cmd->arg & 0x80000000) &&
386 (((cmd->arg >> 9) & 0x1ffff) == SDIO_CCCR_ABORT))
387 return 1;
348 return 0; 388 return 0;
349} 389}
350 390
351static void 391static void
352msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data) 392msmsdcc_start_command_deferred(struct msmsdcc_host *host,
393 struct mmc_command *cmd, u32 *c)
394{
395 *c |= (cmd->opcode | MCI_CPSM_ENABLE);
396
397 if (cmd->flags & MMC_RSP_PRESENT) {
398 if (cmd->flags & MMC_RSP_136)
399 *c |= MCI_CPSM_LONGRSP;
400 *c |= MCI_CPSM_RESPONSE;
401 }
402
403 if (/*interrupt*/0)
404 *c |= MCI_CPSM_INTERRUPT;
405
406 if ((((cmd->opcode == 17) || (cmd->opcode == 18)) ||
407 ((cmd->opcode == 24) || (cmd->opcode == 25))) ||
408 (cmd->opcode == 53))
409 *c |= MCI_CSPM_DATCMD;
410
411 if (cmd == cmd->mrq->stop)
412 *c |= MCI_CSPM_MCIABORT;
413
414 if (snoop_cccr_abort(cmd))
415 *c |= MCI_CSPM_MCIABORT;
416
417 if (host->curr.cmd != NULL) {
418 printk(KERN_ERR "%s: Overlapping command requests\n",
419 mmc_hostname(host->mmc));
420 }
421 host->curr.cmd = cmd;
422}
423
424static void
425msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
426 struct mmc_command *cmd, u32 c)
353{ 427{
354 unsigned int datactrl, timeout; 428 unsigned int datactrl, timeout;
355 unsigned long long clks; 429 unsigned long long clks;
@@ -364,13 +438,6 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data)
364 438
365 memset(&host->pio, 0, sizeof(host->pio)); 439 memset(&host->pio, 0, sizeof(host->pio));
366 440
367 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
368 do_div(clks, NSEC_PER_SEC);
369 timeout = data->timeout_clks + (unsigned int)clks;
370 msmsdcc_writel(host, timeout, MMCIDATATIMER);
371
372 msmsdcc_writel(host, host->curr.xfer_size, MMCIDATALENGTH);
373
374 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4); 441 datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
375 442
376 if (!msmsdcc_config_dma(host, data)) 443 if (!msmsdcc_config_dma(host, data))
@@ -391,56 +458,51 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data)
391 if (data->flags & MMC_DATA_READ) 458 if (data->flags & MMC_DATA_READ)
392 datactrl |= MCI_DPSM_DIRECTION; 459 datactrl |= MCI_DPSM_DIRECTION;
393 460
394 msmsdcc_writel(host, pio_irqmask, MMCIMASK1); 461 clks = (unsigned long long)data->timeout_ns * host->clk_rate;
395 msmsdcc_writel(host, datactrl, MMCIDATACTRL); 462 do_div(clks, NSEC_PER_SEC);
463 timeout = data->timeout_clks + (unsigned int)clks*2 ;
396 464
397 if (datactrl & MCI_DPSM_DMAENABLE) { 465 if (datactrl & MCI_DPSM_DMAENABLE) {
466 /* Save parameters for the exec function */
467 host->cmd_timeout = timeout;
468 host->cmd_pio_irqmask = pio_irqmask;
469 host->cmd_datactrl = datactrl;
470 host->cmd_cmd = cmd;
471
472 host->dma.hdr.execute_func = msmsdcc_dma_exec_func;
473 host->dma.hdr.data = (void *)host;
398 host->dma.busy = 1; 474 host->dma.busy = 1;
475
476 if (cmd) {
477 msmsdcc_start_command_deferred(host, cmd, &c);
478 host->cmd_c = c;
479 }
399 msm_dmov_enqueue_cmd(host->dma.channel, &host->dma.hdr); 480 msm_dmov_enqueue_cmd(host->dma.channel, &host->dma.hdr);
400 } 481 } else {
401} 482 msmsdcc_writel(host, timeout, MMCIDATATIMER);
402 483
403static int 484 msmsdcc_writel(host, host->curr.xfer_size, MMCIDATALENGTH);
404snoop_cccr_abort(struct mmc_command *cmd) 485
405{ 486 msmsdcc_writel(host, pio_irqmask, MMCIMASK1);
406 if ((cmd->opcode == 52) && 487 msmsdcc_writel(host, datactrl, MMCIDATACTRL);
407 (cmd->arg & 0x80000000) && 488
408 (((cmd->arg >> 9) & 0x1ffff) == SDIO_CCCR_ABORT)) 489 if (cmd) {
409 return 1; 490 /* Daisy-chain the command if requested */
410 return 0; 491 msmsdcc_start_command(host, cmd, c);
492 }
493 }
411} 494}
412 495
413static void 496static void
414msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c) 497msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
415{ 498{
416 if (msmsdcc_readl(host, MMCICOMMAND) & MCI_CPSM_ENABLE)
417 msmsdcc_writel(host, 0, MMCICOMMAND);
418
419 c |= cmd->opcode | MCI_CPSM_ENABLE;
420
421 if (cmd->flags & MMC_RSP_PRESENT) {
422 if (cmd->flags & MMC_RSP_136)
423 c |= MCI_CPSM_LONGRSP;
424 c |= MCI_CPSM_RESPONSE;
425 }
426
427 if (cmd->opcode == 17 || cmd->opcode == 18 ||
428 cmd->opcode == 24 || cmd->opcode == 25 ||
429 cmd->opcode == 53)
430 c |= MCI_CSPM_DATCMD;
431
432 if (cmd == cmd->mrq->stop) 499 if (cmd == cmd->mrq->stop)
433 c |= MCI_CSPM_MCIABORT; 500 c |= MCI_CSPM_MCIABORT;
434 501
435 if (snoop_cccr_abort(cmd))
436 c |= MCI_CSPM_MCIABORT;
437
438 host->curr.cmd = cmd;
439
440 host->stats.cmds++; 502 host->stats.cmds++;
441 503
442 msmsdcc_writel(host, cmd->arg, MMCIARGUMENT); 504 msmsdcc_start_command_deferred(host, cmd, &c);
443 msmsdcc_writel(host, c, MMCICOMMAND); 505 msmsdcc_start_command_exec(host, cmd->arg, c);
444} 506}
445 507
446static void 508static void
@@ -611,7 +673,6 @@ static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
611 cmd->resp[2] = msmsdcc_readl(host, MMCIRESPONSE2); 673 cmd->resp[2] = msmsdcc_readl(host, MMCIRESPONSE2);
612 cmd->resp[3] = msmsdcc_readl(host, MMCIRESPONSE3); 674 cmd->resp[3] = msmsdcc_readl(host, MMCIRESPONSE3);
613 675
614 del_timer(&host->command_timer);
615 if (status & MCI_CMDTIMEOUT) { 676 if (status & MCI_CMDTIMEOUT) {
616 cmd->error = -ETIMEDOUT; 677 cmd->error = -ETIMEDOUT;
617 } else if (status & MCI_CMDCRCFAIL && 678 } else if (status & MCI_CMDCRCFAIL &&
@@ -629,16 +690,24 @@ static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
629 msmsdcc_request_end(host, cmd->mrq); 690 msmsdcc_request_end(host, cmd->mrq);
630 } else /* host->data == NULL */ 691 } else /* host->data == NULL */
631 msmsdcc_request_end(host, cmd->mrq); 692 msmsdcc_request_end(host, cmd->mrq);
632 } else if (!(cmd->data->flags & MMC_DATA_READ)) 693 } else if (cmd->data)
633 msmsdcc_start_data(host, cmd->data); 694 if (!(cmd->data->flags & MMC_DATA_READ))
695 msmsdcc_start_data(host, cmd->data,
696 NULL, 0);
634} 697}
635 698
636static void 699static void
637msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status, 700msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status,
638 void __iomem *base) 701 void __iomem *base)
639{ 702{
640 struct mmc_data *data = host->curr.data; 703 struct mmc_data *data;
641 704
705 if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
706 MCI_CMDTIMEOUT) && host->curr.cmd) {
707 msmsdcc_do_cmdirq(host, status);
708 }
709
710 data = host->curr.data;
642 if (!data) 711 if (!data)
643 return; 712 return;
644 713
@@ -720,11 +789,6 @@ msmsdcc_irq(int irq, void *dev_id)
720 789
721 msmsdcc_handle_irq_data(host, status, base); 790 msmsdcc_handle_irq_data(host, status, base);
722 791
723 if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
724 MCI_CMDTIMEOUT) && host->curr.cmd) {
725 msmsdcc_do_cmdirq(host, status);
726 }
727
728 if (status & MCI_SDIOINTOPER) { 792 if (status & MCI_SDIOINTOPER) {
729 cardint = 1; 793 cardint = 1;
730 status &= ~MCI_SDIOINTOPER; 794 status &= ~MCI_SDIOINTOPER;
@@ -775,9 +839,10 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
775 msmsdcc_enable_clocks(host, 1); 839 msmsdcc_enable_clocks(host, 1);
776 840
777 if (mrq->data && mrq->data->flags & MMC_DATA_READ) 841 if (mrq->data && mrq->data->flags & MMC_DATA_READ)
778 msmsdcc_start_data(host, mrq->data); 842 /* Queue/read data, daisy-chain command when data starts */
779 843 msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
780 msmsdcc_start_command(host, mrq->cmd, 0); 844 else
845 msmsdcc_start_command(host, mrq->cmd, 0);
781 846
782 if (host->cmdpoll && !msmsdcc_spin_on_status(host, 847 if (host->cmdpoll && !msmsdcc_spin_on_status(host,
783 MCI_CMDRESPEND|MCI_CMDCRCFAIL|MCI_CMDTIMEOUT, 848 MCI_CMDRESPEND|MCI_CMDCRCFAIL|MCI_CMDTIMEOUT,
@@ -790,7 +855,6 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
790 host->stats.cmdpoll_hits++; 855 host->stats.cmdpoll_hits++;
791 } else { 856 } else {
792 host->stats.cmdpoll_misses++; 857 host->stats.cmdpoll_misses++;
793 mod_timer(&host->command_timer, jiffies + HZ);
794 } 858 }
795 spin_unlock_irqrestore(&host->lock, flags); 859 spin_unlock_irqrestore(&host->lock, flags);
796} 860}
@@ -943,42 +1007,6 @@ msmsdcc_busclk_expired(unsigned long _data)
943 spin_unlock_irqrestore(&host->lock, flags); 1007 spin_unlock_irqrestore(&host->lock, flags);
944} 1008}
945 1009
946/*
947 * called when a command expires.
948 * Dump some debugging, and then error
949 * out the transaction.
950 */
951static void
952msmsdcc_command_expired(unsigned long _data)
953{
954 struct msmsdcc_host *host = (struct msmsdcc_host *) _data;
955 struct mmc_request *mrq;
956 unsigned long flags;
957
958 spin_lock_irqsave(&host->lock, flags);
959 mrq = host->curr.mrq;
960
961 if (!mrq) {
962 spin_unlock_irqrestore(&host->lock, flags);
963 return;
964 }
965
966 pr_err("%s: Controller lockup detected\n",
967 mmc_hostname(host->mmc));
968 mrq->cmd->error = -ETIMEDOUT;
969 msmsdcc_stop_data(host);
970
971 msmsdcc_writel(host, 0, MMCICOMMAND);
972
973 host->curr.mrq = NULL;
974 host->curr.cmd = NULL;
975
976 if (host->clks_on)
977 msmsdcc_enable_clocks(host, 0);
978 spin_unlock_irqrestore(&host->lock, flags);
979 mmc_request_done(host->mmc, mrq);
980}
981
982static int 1010static int
983msmsdcc_init_dma(struct msmsdcc_host *host) 1011msmsdcc_init_dma(struct msmsdcc_host *host)
984{ 1012{
@@ -1078,6 +1106,7 @@ msmsdcc_probe(struct platform_device *pdev)
1078 host->pdev_id = pdev->id; 1106 host->pdev_id = pdev->id;
1079 host->plat = plat; 1107 host->plat = plat;
1080 host->mmc = mmc; 1108 host->mmc = mmc;
1109 host->curr.cmd = NULL;
1081 1110
1082 host->cmdpoll = 1; 1111 host->cmdpoll = 1;
1083 1112
@@ -1194,14 +1223,6 @@ msmsdcc_probe(struct platform_device *pdev)
1194 host->eject = !host->oldstat; 1223 host->eject = !host->oldstat;
1195 } 1224 }
1196 1225
1197 /*
1198 * Setup a command timer. We currently need this due to
1199 * some 'strange' timeout / error handling situations.
1200 */
1201 init_timer(&host->command_timer);
1202 host->command_timer.data = (unsigned long) host;
1203 host->command_timer.function = msmsdcc_command_expired;
1204
1205 init_timer(&host->busclk_timer); 1226 init_timer(&host->busclk_timer);
1206 host->busclk_timer.data = (unsigned long) host; 1227 host->busclk_timer.data = (unsigned long) host;
1207 host->busclk_timer.function = msmsdcc_busclk_expired; 1228 host->busclk_timer.function = msmsdcc_busclk_expired;
@@ -1243,7 +1264,7 @@ msmsdcc_probe(struct platform_device *pdev)
1243 pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc)); 1264 pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc));
1244 1265
1245 if (host->use_bustimer) 1266 if (host->use_bustimer)
1246 mod_timer(&host->busclk_timer, jiffies + HZ); 1267 mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT);
1247 return 0; 1268 return 0;
1248 cmd_irq_free: 1269 cmd_irq_free:
1249 free_irq(cmd_irqres->start, host); 1270 free_irq(cmd_irqres->start, host);
@@ -1267,10 +1288,14 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state)
1267{ 1288{
1268 struct mmc_host *mmc = mmc_get_drvdata(dev); 1289 struct mmc_host *mmc = mmc_get_drvdata(dev);
1269 int rc = 0; 1290 int rc = 0;
1291 unsigned long flags;
1270 1292
1271 if (mmc) { 1293 if (mmc) {
1272 struct msmsdcc_host *host = mmc_priv(mmc); 1294 struct msmsdcc_host *host = mmc_priv(mmc);
1273 1295
1296 if (host->use_bustimer)
1297 del_timer_sync(&host->busclk_timer);
1298 spin_lock_irqsave(&host->lock, flags);
1274 if (host->stat_irq) 1299 if (host->stat_irq)
1275 disable_irq(host->stat_irq); 1300 disable_irq(host->stat_irq);
1276 1301
@@ -1282,6 +1307,7 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state)
1282 if (host->clks_on) 1307 if (host->clks_on)
1283 msmsdcc_enable_clocks(host, 0); 1308 msmsdcc_enable_clocks(host, 0);
1284 } 1309 }
1310 spin_unlock_irqrestore(&host->lock, flags);
1285 } 1311 }
1286 return rc; 1312 return rc;
1287} 1313}
@@ -1300,6 +1326,9 @@ msmsdcc_resume(struct platform_device *dev)
1300 if (!host->clks_on) 1326 if (!host->clks_on)
1301 msmsdcc_enable_clocks(host, 1); 1327 msmsdcc_enable_clocks(host, 1);
1302 1328
1329 if (host->use_bustimer)
1330 mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT);
1331
1303 msmsdcc_writel(host, host->saved_irq0mask, MMCIMASK0); 1332 msmsdcc_writel(host, host->saved_irq0mask, MMCIMASK0);
1304 1333
1305 spin_unlock_irqrestore(&host->lock, flags); 1334 spin_unlock_irqrestore(&host->lock, flags);