summaryrefslogtreecommitdiff
path: root/drivers/mmc/host/msm_sdcc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/host/msm_sdcc.c')
-rw-r--r--drivers/mmc/host/msm_sdcc.c132
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) {