diff options
Diffstat (limited to 'drivers/mmc/host/msm_sdcc.c')
-rw-r--r-- | drivers/mmc/host/msm_sdcc.c | 132 |
1 files changed, 63 insertions, 69 deletions
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 874de6a1e4e7..dba4600bcdb4 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -584,6 +584,67 @@ static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status) msmsdcc_start_data(host, cmd->data); } +static void +msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status, + void __iomem *base) +{ + struct mmc_data *data = host->curr.data; + + if (!data) + return; + + /* Check for data errors */ + if (status & (MCI_DATACRCFAIL | MCI_DATATIMEOUT | + MCI_TXUNDERRUN | MCI_RXOVERRUN)) { + msmsdcc_data_err(host, data, status); + host->curr.data_xfered = 0; + if (host->dma.sg) + msm_dmov_stop_cmd(host->dma.channel, + &host->dma.hdr, 0); + else { + msmsdcc_stop_data(host); + if (!data->stop) + msmsdcc_request_end(host, data->mrq); + else + msmsdcc_start_command(host, data->stop, 0); + } + } + + /* Check for data done */ + if (!host->curr.got_dataend && (status & MCI_DATAEND)) + host->curr.got_dataend = 1; + + if (!host->curr.got_datablkend && (status & MCI_DATABLOCKEND)) + host->curr.got_datablkend = 1; + + /* + * If DMA is still in progress, we complete via the completion handler + */ + if (host->curr.got_dataend && host->curr.got_datablkend && + !host->dma.busy) { + /* + * There appears to be an issue in the controller where + * if you request a small block transfer (< fifo size), + * you may get your DATAEND/DATABLKEND irq without the + * PIO data irq. + * + * Check to see if there is still data to be read, + * and simulate a PIO irq. + */ + if (readl(base + MMCISTATUS) & MCI_RXDATAAVLBL) + msmsdcc_pio_irq(1, host); + + msmsdcc_stop_data(host); + if (!data->error) + host->curr.data_xfered = host->curr.xfer_size; + + if (!data->stop) + msmsdcc_request_end(host, data->mrq); + else + msmsdcc_start_command(host, data->stop, 0); + } +} + static irqreturn_t msmsdcc_irq(int irq, void *dev_id) { @@ -596,79 +657,12 @@ msmsdcc_irq(int irq, void *dev_id) spin_lock(&host->lock); do { - struct mmc_data *data; status = readl(base + MMCISTATUS); - status &= (readl(base + MMCIMASK0) | - MCI_DATABLOCKENDMASK); + status &= (readl(base + MMCIMASK0) | MCI_DATABLOCKENDMASK); writel(status, base + MMCICLEAR); - data = host->curr.data; - if (data) { - /* Check for data errors */ - if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT| - MCI_TXUNDERRUN|MCI_RXOVERRUN)) { - msmsdcc_data_err(host, data, status); - host->curr.data_xfered = 0; - if (host->dma.sg) - msm_dmov_stop_cmd(host->dma.channel, - &host->dma.hdr, 0); - else { - msmsdcc_stop_data(host); - if (!data->stop) - msmsdcc_request_end(host, - data->mrq); - else - msmsdcc_start_command(host, - data->stop, - 0); - } - } - - /* Check for data done */ - if (!host->curr.got_dataend && (status & MCI_DATAEND)) - host->curr.got_dataend = 1; - - if (!host->curr.got_datablkend && - (status & MCI_DATABLOCKEND)) { - host->curr.got_datablkend = 1; - } - - if (host->curr.got_dataend && - host->curr.got_datablkend) { - /* - * If DMA is still in progress, we complete - * via the completion handler - */ - if (!host->dma.busy) { - /* - * There appears to be an issue in the - * controller where if you request a - * small block transfer (< fifo size), - * you may get your DATAEND/DATABLKEND - * irq without the PIO data irq. - * - * Check to see if theres still data - * to be read, and simulate a PIO irq. - */ - if (readl(base + MMCISTATUS) & - MCI_RXDATAAVLBL) - msmsdcc_pio_irq(1, host); - - msmsdcc_stop_data(host); - if (!data->error) - host->curr.data_xfered = - host->curr.xfer_size; - - if (!data->stop) - msmsdcc_request_end(host, - data->mrq); - else - msmsdcc_start_command(host, - data->stop, 0); - } - } - } + msmsdcc_handle_irq_data(host, status, base); if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT) && host->curr.cmd) { |