Pull MMC host fixes from Ulf Hansson: - alcor: Stabilize data write requests - sdhci-omap: Fix command error path during tuning * tag 'mmc-v5.1-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: mmc: sdhci-omap: Don't finish_mrq() on a command error during tuning mmc: alcor: don't write data before command has completed
Unified · Split
| @@ -48,7 +48,6 @@ struct alcor_sdmmc_host { · 47 unmodified lines | |||
| 48 | struct mmc_command *cmd; | 48 | struct mmc_command *cmd; |
| 49 | struct mmc_data *data; | 49 | struct mmc_data *data; |
| 50 | unsigned int dma_on:1; | 50 | unsigned int dma_on:1; |
| 51 | unsigned int early_data:1; | ||
| 52 | 51 | ||
| 53 | struct mutex cmd_mutex; | 52 | struct mutex cmd_mutex; |
| 54 | 53 | ||
| @@ -144,8 +143,7 @@ static void alcor_data_set_dma(struct alcor_sdmmc_host *host) · 89 unmodified lines | |||
| 144 | host->sg_count--; | 143 | host->sg_count--; |
| 145 | } | 144 | } |
| 146 | 145 | ||
| 147 | static void alcor_trigger_data_transfer(struct alcor_sdmmc_host *host, | 146 | static void alcor_trigger_data_transfer(struct alcor_sdmmc_host *host) |
| 148 | bool early) | ||
| 149 | { | 147 | { |
| 150 | struct alcor_pci_priv *priv = host->alcor_pci; | 148 | struct alcor_pci_priv *priv = host->alcor_pci; |
| 151 | struct mmc_data *data = host->data; | 149 | struct mmc_data *data = host->data; |
| @@ -155,13 +153,6 @@ static void alcor_trigger_data_transfer(struct alcor_sdmmc_host *host, · 3 unmodified lines | |||
| 155 | ctrl |= AU6601_DATA_WRITE; | 153 | ctrl |= AU6601_DATA_WRITE; |
| 156 | 154 | ||
| 157 | if (data->host_cookie == COOKIE_MAPPED) { | 155 | if (data->host_cookie == COOKIE_MAPPED) { |
| 158 | if (host->early_data) { | ||
| 159 | host->early_data = false; | ||
| 160 | return; | ||
| 161 | } | ||
| 162 | |||
| 163 | host->early_data = early; | ||
| 164 | |||
| 165 | alcor_data_set_dma(host); | 156 | alcor_data_set_dma(host); |
| 166 | ctrl |= AU6601_DATA_DMA_MODE; | 157 | ctrl |= AU6601_DATA_DMA_MODE; |
| 167 | host->dma_on = 1; | 158 | host->dma_on = 1; |
| @@ -231,6 +222,7 @@ static void alcor_prepare_sg_miter(struct alcor_sdmmc_host *host) · 63 unmodified lines | |||
| 231 | static void alcor_prepare_data(struct alcor_sdmmc_host *host, | 222 | static void alcor_prepare_data(struct alcor_sdmmc_host *host, |
| 232 | struct mmc_command *cmd) | 223 | struct mmc_command *cmd) |
| 233 | { | 224 | { |
| 225 | struct alcor_pci_priv *priv = host->alcor_pci; | ||
| 234 | struct mmc_data *data = cmd->data; | 226 | struct mmc_data *data = cmd->data; |
| 235 | 227 | ||
| 236 | if (!data) | 228 | if (!data) |
| @@ -248,7 +240,7 @@ static void alcor_prepare_data(struct alcor_sdmmc_host *host, · 11 unmodified lines | |||
| 248 | if (data->host_cookie != COOKIE_MAPPED) | 240 | if (data->host_cookie != COOKIE_MAPPED) |
| 249 | alcor_prepare_sg_miter(host); | 241 | alcor_prepare_sg_miter(host); |
| 250 | 242 | ||
| 251 | alcor_trigger_data_transfer(host, true); | 243 | alcor_write8(priv, 0, AU6601_DATA_XFER_CTRL); |
| 252 | } | 244 | } |
| 253 | 245 | ||
| 254 | static void alcor_send_cmd(struct alcor_sdmmc_host *host, | 246 | static void alcor_send_cmd(struct alcor_sdmmc_host *host, |
| @@ -435,7 +427,7 @@ static int alcor_cmd_irq_done(struct alcor_sdmmc_host *host, u32 intmask) · 180 unmodified lines | |||
| 435 | if (!host->data) | 427 | if (!host->data) |
| 436 | return false; | 428 | return false; |
| 437 | 429 | ||
| 438 | alcor_trigger_data_transfer(host, false); | 430 | alcor_trigger_data_transfer(host); |
| 439 | host->cmd = NULL; | 431 | host->cmd = NULL; |
| 440 | return true; | 432 | return true; |
| 441 | } | 433 | } |
| @@ -456,7 +448,7 @@ static void alcor_cmd_irq_thread(struct alcor_sdmmc_host *host, u32 intmask) · 14 unmodified lines | |||
| 456 | if (!host->data) | 448 | if (!host->data) |
| 457 | alcor_request_complete(host, 1); | 449 | alcor_request_complete(host, 1); |
| 458 | else | 450 | else |
| 459 | alcor_trigger_data_transfer(host, false); | 451 | alcor_trigger_data_transfer(host); |
| 460 | host->cmd = NULL; | 452 | host->cmd = NULL; |
| 461 | } | 453 | } |
| 462 | 454 | ||
| @@ -487,15 +479,9 @@ static int alcor_data_irq_done(struct alcor_sdmmc_host *host, u32 intmask) · 24 unmodified lines | |||
| 487 | break; | 479 | break; |
| 488 | case AU6601_INT_READ_BUF_RDY: | 480 | case AU6601_INT_READ_BUF_RDY: |
| 489 | alcor_trf_block_pio(host, true); | 481 | alcor_trf_block_pio(host, true); |
| 490 | if (!host->blocks) | ||
| 491 | break; | ||
| 492 | alcor_trigger_data_transfer(host, false); | ||
| 493 | return 1; | 482 | return 1; |
| 494 | case AU6601_INT_WRITE_BUF_RDY: | 483 | case AU6601_INT_WRITE_BUF_RDY: |
| 495 | alcor_trf_block_pio(host, false); | 484 | alcor_trf_block_pio(host, false); |
| 496 | if (!host->blocks) | ||
| 497 | break; | ||
| 498 | alcor_trigger_data_transfer(host, false); | ||
| 499 | return 1; | 485 | return 1; |
| 500 | case AU6601_INT_DMA_END: | 486 | case AU6601_INT_DMA_END: |
| 501 | if (!host->sg_count) | 487 | if (!host->sg_count) |
| @@ -508,8 +494,14 @@ static int alcor_data_irq_done(struct alcor_sdmmc_host *host, u32 intmask) · 6 unmodified lines | |||
| 508 | break; | 494 | break; |
| 509 | } | 495 | } |
| 510 | 496 | ||
| 511 | if (intmask & AU6601_INT_DATA_END) | 497 | if (intmask & AU6601_INT_DATA_END) { |
| 512 | return 0; | 498 | if (!host->dma_on && host->blocks) { |
| 499 | alcor_trigger_data_transfer(host); | ||
| 500 | return 1; | ||
| 501 | } else { | ||
| 502 | return 0; | ||
| 503 | } | ||
| 504 | } | ||
| 513 | 505 | ||
| 514 | return 1; | 506 | return 1; |
| 515 | } | 507 | } |
| @@ -797,6 +797,43 @@ void sdhci_omap_reset(struct sdhci_host *host, u8 mask) · 796 unmodified lines | |||
| 797 | sdhci_reset(host, mask); | 797 | sdhci_reset(host, mask); |
| 798 | } | 798 | } |
| 799 | 799 | ||
| 800 | #define CMD_ERR_MASK (SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX |\ | ||
| 801 | SDHCI_INT_TIMEOUT) | ||
| 802 | #define CMD_MASK (CMD_ERR_MASK | SDHCI_INT_RESPONSE) | ||
| 803 | |||
| 804 | static u32 sdhci_omap_irq(struct sdhci_host *host, u32 intmask) | ||
| 805 | { | ||
| 806 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | ||
| 807 | struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); | ||
| 808 | |||
| 809 | if (omap_host->is_tuning && host->cmd && !host->data_early && | ||
| 810 | (intmask & CMD_ERR_MASK)) { | ||
| 811 | |||
| 812 | /* | ||
| 813 | * Since we are not resetting data lines during tuning | ||
| 814 | * operation, data error or data complete interrupts | ||
| 815 | * might still arrive. Mark this request as a failure | ||
| 816 | * but still wait for the data interrupt | ||
| 817 | */ | ||
| 818 | if (intmask & SDHCI_INT_TIMEOUT) | ||
| 819 | host->cmd->error = -ETIMEDOUT; | ||
| 820 | else | ||
| 821 | host->cmd->error = -EILSEQ; | ||
| 822 | |||
| 823 | host->cmd = NULL; | ||
| 824 | |||
| 825 | /* | ||
| 826 | * Sometimes command error interrupts and command complete | ||
| 827 | * interrupt will arrive together. Clear all command related | ||
| 828 | * interrupts here. | ||
| 829 | */ | ||
| 830 | sdhci_writel(host, intmask & CMD_MASK, SDHCI_INT_STATUS); | ||
| 831 | intmask &= ~CMD_MASK; | ||
| 832 | } | ||
| 833 | |||
| 834 | return intmask; | ||
| 835 | } | ||
| 836 | |||
| 800 | static struct sdhci_ops sdhci_omap_ops = { | 837 | static struct sdhci_ops sdhci_omap_ops = { |
| 801 | .set_clock = sdhci_omap_set_clock, | 838 | .set_clock = sdhci_omap_set_clock, |
| 802 | .set_power = sdhci_omap_set_power, | 839 | .set_power = sdhci_omap_set_power, |
| @@ -807,6 +844,7 @@ static struct sdhci_ops sdhci_omap_ops = { · 4 unmodified lines | |||
| 807 | .platform_send_init_74_clocks = sdhci_omap_init_74_clocks, | 844 | .platform_send_init_74_clocks = sdhci_omap_init_74_clocks, |
| 808 | .reset = sdhci_omap_reset, | 845 | .reset = sdhci_omap_reset, |
| 809 | .set_uhs_signaling = sdhci_omap_set_uhs_signaling, | 846 | .set_uhs_signaling = sdhci_omap_set_uhs_signaling, |
| 847 | .irq = sdhci_omap_irq, | ||
| 810 | }; | 848 | }; |
| 811 | 849 | ||
| 812 | static int sdhci_omap_set_capabilities(struct sdhci_omap_host *omap_host) | 850 | static int sdhci_omap_set_capabilities(struct sdhci_omap_host *omap_host) |