diff options
Diffstat (limited to 'drivers/mmc/host/sdhci.c')
| -rw-r--r-- | drivers/mmc/host/sdhci.c | 53 |
1 files changed, 33 insertions, 20 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index f2bc87ac24f7..20a7d89e01ba 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c | |||
| @@ -385,6 +385,9 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) | |||
| 385 | BUG_ON(data->blksz > host->mmc->max_blk_size); | 385 | BUG_ON(data->blksz > host->mmc->max_blk_size); |
| 386 | BUG_ON(data->blocks > 65535); | 386 | BUG_ON(data->blocks > 65535); |
| 387 | 387 | ||
| 388 | host->data = data; | ||
| 389 | host->data_early = 0; | ||
| 390 | |||
| 388 | /* timeout in us */ | 391 | /* timeout in us */ |
| 389 | target_timeout = data->timeout_ns / 1000 + | 392 | target_timeout = data->timeout_ns / 1000 + |
| 390 | data->timeout_clks / host->clock; | 393 | data->timeout_clks / host->clock; |
| @@ -443,11 +446,11 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host, | |||
| 443 | { | 446 | { |
| 444 | u16 mode; | 447 | u16 mode; |
| 445 | 448 | ||
| 446 | WARN_ON(host->data); | ||
| 447 | |||
| 448 | if (data == NULL) | 449 | if (data == NULL) |
| 449 | return; | 450 | return; |
| 450 | 451 | ||
| 452 | WARN_ON(!host->data); | ||
| 453 | |||
| 451 | mode = SDHCI_TRNS_BLK_CNT_EN; | 454 | mode = SDHCI_TRNS_BLK_CNT_EN; |
| 452 | if (data->blocks > 1) | 455 | if (data->blocks > 1) |
| 453 | mode |= SDHCI_TRNS_MULTI; | 456 | mode |= SDHCI_TRNS_MULTI; |
| @@ -477,8 +480,8 @@ static void sdhci_finish_data(struct sdhci_host *host) | |||
| 477 | /* | 480 | /* |
| 478 | * Controller doesn't count down when in single block mode. | 481 | * Controller doesn't count down when in single block mode. |
| 479 | */ | 482 | */ |
| 480 | if ((data->blocks == 1) && (data->error == MMC_ERR_NONE)) | 483 | if (data->blocks == 1) |
| 481 | blocks = 0; | 484 | blocks = (data->error == MMC_ERR_NONE) ? 0 : 1; |
| 482 | else | 485 | else |
| 483 | blocks = readw(host->ioaddr + SDHCI_BLOCK_COUNT); | 486 | blocks = readw(host->ioaddr + SDHCI_BLOCK_COUNT); |
| 484 | data->bytes_xfered = data->blksz * (data->blocks - blocks); | 487 | data->bytes_xfered = data->blksz * (data->blocks - blocks); |
| @@ -600,9 +603,10 @@ static void sdhci_finish_command(struct sdhci_host *host) | |||
| 600 | 603 | ||
| 601 | host->cmd->error = MMC_ERR_NONE; | 604 | host->cmd->error = MMC_ERR_NONE; |
| 602 | 605 | ||
| 603 | if (host->cmd->data) | 606 | if (host->data && host->data_early) |
| 604 | host->data = host->cmd->data; | 607 | sdhci_finish_data(host); |
| 605 | else | 608 | |
| 609 | if (!host->cmd->data) | ||
| 606 | tasklet_schedule(&host->finish_tasklet); | 610 | tasklet_schedule(&host->finish_tasklet); |
| 607 | 611 | ||
| 608 | host->cmd = NULL; | 612 | host->cmd = NULL; |
| @@ -929,9 +933,9 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) | |||
| 929 | BUG_ON(intmask == 0); | 933 | BUG_ON(intmask == 0); |
| 930 | 934 | ||
| 931 | if (!host->cmd) { | 935 | if (!host->cmd) { |
| 932 | printk(KERN_ERR "%s: Got command interrupt even though no " | 936 | printk(KERN_ERR "%s: Got command interrupt 0x%08x even " |
| 933 | "command operation was in progress.\n", | 937 | "though no command operation was in progress.\n", |
| 934 | mmc_hostname(host->mmc)); | 938 | mmc_hostname(host->mmc), (unsigned)intmask); |
| 935 | sdhci_dumpregs(host); | 939 | sdhci_dumpregs(host); |
| 936 | return; | 940 | return; |
| 937 | } | 941 | } |
| @@ -961,9 +965,9 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) | |||
| 961 | if (intmask & SDHCI_INT_DATA_END) | 965 | if (intmask & SDHCI_INT_DATA_END) |
| 962 | return; | 966 | return; |
| 963 | 967 | ||
| 964 | printk(KERN_ERR "%s: Got data interrupt even though no " | 968 | printk(KERN_ERR "%s: Got data interrupt 0x%08x even " |
| 965 | "data operation was in progress.\n", | 969 | "though no data operation was in progress.\n", |
| 966 | mmc_hostname(host->mmc)); | 970 | mmc_hostname(host->mmc), (unsigned)intmask); |
| 967 | sdhci_dumpregs(host); | 971 | sdhci_dumpregs(host); |
| 968 | 972 | ||
| 969 | return; | 973 | return; |
| @@ -991,8 +995,18 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) | |||
| 991 | writel(readl(host->ioaddr + SDHCI_DMA_ADDRESS), | 995 | writel(readl(host->ioaddr + SDHCI_DMA_ADDRESS), |
| 992 | host->ioaddr + SDHCI_DMA_ADDRESS); | 996 | host->ioaddr + SDHCI_DMA_ADDRESS); |
| 993 | 997 | ||
| 994 | if (intmask & SDHCI_INT_DATA_END) | 998 | if (intmask & SDHCI_INT_DATA_END) { |
| 995 | sdhci_finish_data(host); | 999 | if (host->cmd) { |
| 1000 | /* | ||
| 1001 | * Data managed to finish before the | ||
| 1002 | * command completed. Make sure we do | ||
| 1003 | * things in the proper order. | ||
| 1004 | */ | ||
| 1005 | host->data_early = 1; | ||
| 1006 | } else { | ||
| 1007 | sdhci_finish_data(host); | ||
| 1008 | } | ||
| 1009 | } | ||
| 996 | } | 1010 | } |
| 997 | } | 1011 | } |
| 998 | 1012 | ||
| @@ -1347,12 +1361,11 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) | |||
| 1347 | */ | 1361 | */ |
| 1348 | mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT; | 1362 | mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT; |
| 1349 | if (mmc->max_blk_size >= 3) { | 1363 | if (mmc->max_blk_size >= 3) { |
| 1350 | printk(KERN_ERR "%s: Invalid maximum block size.\n", | 1364 | printk(KERN_WARNING "%s: Invalid maximum block size, assuming 512\n", |
| 1351 | host->slot_descr); | 1365 | host->slot_descr); |
| 1352 | ret = -ENODEV; | 1366 | mmc->max_blk_size = 512; |
| 1353 | goto unmap; | 1367 | } else |
| 1354 | } | 1368 | mmc->max_blk_size = 512 << mmc->max_blk_size; |
| 1355 | mmc->max_blk_size = 512 << mmc->max_blk_size; | ||
| 1356 | 1369 | ||
| 1357 | /* | 1370 | /* |
| 1358 | * Maximum block count. | 1371 | * Maximum block count. |
