diff options
| -rw-r--r-- | drivers/mmc/host/msm_sdcc.c | 267 | ||||
| -rw-r--r-- | drivers/mmc/host/msm_sdcc.h | 14 |
2 files changed, 161 insertions, 120 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) | ||
| 50 | static unsigned int msmsdcc_fmin = 144000; | 52 | static unsigned int msmsdcc_fmin = 144000; |
| 51 | static unsigned int msmsdcc_fmax = 50000000; | 53 | static unsigned int msmsdcc_fmax = 50000000; |
| 52 | static unsigned int msmsdcc_4bit = 1; | 54 | static unsigned int msmsdcc_4bit = 1; |
| @@ -106,8 +108,6 @@ msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, | |||
| 106 | static void | 108 | static void |
| 107 | msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) | 109 | msmsdcc_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) | |||
| 132 | static void | 132 | static void |
| 133 | msmsdcc_stop_data(struct msmsdcc_host *host) | 133 | msmsdcc_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 | ||
| 155 | static inline void | ||
| 156 | msmsdcc_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 | |||
| 161 | static void | ||
| 162 | msmsdcc_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 | |||
| 156 | static void | 178 | static void |
| 157 | msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, | 179 | msmsdcc_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 | |||
| 381 | static int | ||
| 382 | snoop_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 | ||
| 351 | static void | 391 | static void |
| 352 | msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data) | 392 | msmsdcc_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 | |||
| 424 | static void | ||
| 425 | msmsdcc_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 | ||
| 403 | static int | 484 | msmsdcc_writel(host, host->curr.xfer_size, MMCIDATALENGTH); |
| 404 | snoop_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 | ||
| 413 | static void | 496 | static void |
| 414 | msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c) | 497 | msmsdcc_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 | ||
| 446 | static void | 508 | static 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 | ||
| 636 | static void | 699 | static void |
| 637 | msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status, | 700 | msmsdcc_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 | */ | ||
| 951 | static void | ||
| 952 | msmsdcc_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 | |||
| 982 | static int | 1010 | static int |
| 983 | msmsdcc_init_dma(struct msmsdcc_host *host) | 1011 | msmsdcc_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); |
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h index 6846bd7dff22..361cb6efd248 100644 --- a/drivers/mmc/host/msm_sdcc.h +++ b/drivers/mmc/host/msm_sdcc.h | |||
| @@ -171,6 +171,7 @@ struct msmsdcc_dma_data { | |||
| 171 | int channel; | 171 | int channel; |
| 172 | struct msmsdcc_host *host; | 172 | struct msmsdcc_host *host; |
| 173 | int busy; /* Set if DM is busy */ | 173 | int busy; /* Set if DM is busy */ |
| 174 | int active; | ||
| 174 | }; | 175 | }; |
| 175 | 176 | ||
| 176 | struct msmsdcc_pio_data { | 177 | struct msmsdcc_pio_data { |
| @@ -213,7 +214,6 @@ struct msmsdcc_host { | |||
| 213 | struct clk *clk; /* main MMC bus clock */ | 214 | struct clk *clk; /* main MMC bus clock */ |
| 214 | struct clk *pclk; /* SDCC peripheral bus clock */ | 215 | struct clk *pclk; /* SDCC peripheral bus clock */ |
| 215 | unsigned int clks_on; /* set if clocks are enabled */ | 216 | unsigned int clks_on; /* set if clocks are enabled */ |
| 216 | struct timer_list command_timer; | ||
| 217 | struct timer_list busclk_timer; | 217 | struct timer_list busclk_timer; |
| 218 | int use_bustimer; | 218 | int use_bustimer; |
| 219 | 219 | ||
| @@ -235,6 +235,18 @@ struct msmsdcc_host { | |||
| 235 | struct msmsdcc_pio_data pio; | 235 | struct msmsdcc_pio_data pio; |
| 236 | int cmdpoll; | 236 | int cmdpoll; |
| 237 | struct msmsdcc_stats stats; | 237 | struct msmsdcc_stats stats; |
| 238 | |||
| 239 | #ifdef CONFIG_MMC_MSM7X00A_RESUME_IN_WQ | ||
| 240 | struct work_struct resume_task; | ||
| 241 | #endif | ||
| 242 | |||
| 243 | /* Command parameters */ | ||
| 244 | unsigned int cmd_timeout; | ||
| 245 | unsigned int cmd_pio_irqmask; | ||
| 246 | unsigned int cmd_datactrl; | ||
| 247 | struct mmc_command *cmd_cmd; | ||
| 248 | u32 cmd_c; | ||
| 249 | |||
| 238 | }; | 250 | }; |
| 239 | 251 | ||
| 240 | #endif | 252 | #endif |
