static irqreturn_t msmsdcc_irq(int irq, void *dev_id) { struct msmsdcc_host *host = dev_id; void __iomem *base = host->base; u32 status; int ret = 0; int cardint = 0; spin_lock(&host->lock); do { struct mmc_data *data; status = readl(base + MMCISTATUS); #if IRQ_DEBUG msmsdcc_print_status(host, "irq0-r", status); #endif status &= (readl(base + MMCIMASK0) | MCI_DATABLOCKENDMASK); writel(status, base + MMCICLEAR); #if IRQ_DEBUG msmsdcc_print_status(host, "irq0-p", status); #endif 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); } } } if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT) && host->curr.cmd) { msmsdcc_do_cmdirq(host, status); } if (status & MCI_SDIOINTOPER) { cardint = 1; status &= ~MCI_SDIOINTOPER; } ret = 1; } while (status); spin_unlock(&host->lock); /* * We have to delay handling the card interrupt as it calls * back into the driver. */ if (cardint) { mmc_signal_sdio_irq(host->mmc); } return IRQ_RETVAL(ret); }
static irqreturn_t msmsdcc_pio_irq(int irq, void *dev_id) { struct msmsdcc_host *host = dev_id; void __iomem *base = host->base; uint32_t status; status = readl(base + MMCISTATUS); #if IRQ_DEBUG msmsdcc_print_status(host, "irq1-r", status); #endif /* SEMC_BEGIN (Crash on irq when data already handled - DMS00718508) */ // do { while (host->pio.sg) { /* SEMC_END (Crash on irq when data already handled - DMS00718508) */ unsigned long flags; unsigned int remain, len; char *buffer; if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_RXDATAAVLBL))) { if (host->curr.xfer_remain == 0 || !msmsdcc_piopoll) break; if (msmsdcc_spin_on_status(host, (MCI_TXFIFOHALFEMPTY | MCI_RXDATAAVLBL), PIO_SPINMAX)) { break; } } /* Map the current scatter buffer */ local_irq_save(flags); buffer = kmap_atomic(sg_page(host->pio.sg), KM_BIO_SRC_IRQ) + host->pio.sg->offset; buffer += host->pio.sg_off; remain = host->pio.sg->length - host->pio.sg_off; len = 0; if (status & MCI_RXACTIVE) len = msmsdcc_pio_read(host, buffer, remain); if (status & MCI_TXACTIVE) len = msmsdcc_pio_write(host, buffer, remain, status); /* Unmap the buffer */ kunmap_atomic(buffer, KM_BIO_SRC_IRQ); local_irq_restore(flags); host->pio.sg_off += len; host->curr.xfer_remain -= len; host->curr.data_xfered += len; remain -= len; if (remain == 0) { /* This sg page is full - do some housekeeping */ if (status & MCI_RXACTIVE && host->curr.user_pages) flush_dcache_page(sg_page(host->pio.sg)); if (!--host->pio.sg_len) { memset(&host->pio, 0, sizeof(host->pio)); break; } /* Advance to next sg */ host->pio.sg++; host->pio.sg_off = 0; } status = readl(base + MMCISTATUS); /* SEMC_BEGIN (Crash on irq when data already handled - DMS00718508) */ // } while (1); } /* SEMC_END (Crash on irq when data already handled - DMS00718508) */ if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1); if (!host->curr.xfer_remain) writel(0, base + MMCIMASK1); return IRQ_HANDLED; }
static irqreturn_t msmsdcc_irq(int irq, void *dev_id) { struct msmsdcc_host *host = dev_id; void __iomem *base = host->base; u32 status; int ret = 0; int timer = 0; spin_lock(&host->lock); do { struct mmc_command *cmd; struct mmc_data *data; if (timer) { timer = 0; msmsdcc_delay(host); } status = readl(host->base + MMCISTATUS); #if IRQ_DEBUG msmsdcc_print_status(host, "irq0-r", status); #endif status &= (readl(host->base + MMCIMASK0) | MCI_DATABLOCKENDMASK); writel(status, host->base + MMCICLEAR); #if IRQ_DEBUG msmsdcc_print_status(host, "irq0-p", status); #endif if ((host->plat->dummy52_required) && (host->dummy_52_state == DUMMY_52_STATE_SENT)) { if (status & MCI_PROGDONE) { host->dummy_52_state = DUMMY_52_STATE_NONE; host->curr.cmd = NULL; spin_unlock(&host->lock); msmsdcc_request_start(host, host->curr.mrq); return IRQ_HANDLED; } break; } data = host->curr.data; #ifdef CONFIG_MMC_MSM_SDIO_SUPPORT if (status & MCI_SDIOINTROPE) mmc_signal_sdio_irq(host->mmc); #endif /* * Check for proper command response */ cmd = host->curr.cmd; if ((status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT | MCI_PROGDONE)) && cmd) { host->curr.cmd = NULL; cmd->resp[0] = readl(base + MMCIRESPONSE0); cmd->resp[1] = readl(base + MMCIRESPONSE1); cmd->resp[2] = readl(base + MMCIRESPONSE2); cmd->resp[3] = readl(base + MMCIRESPONSE3); if (status & MCI_CMDTIMEOUT) { #if VERBOSE_COMMAND_TIMEOUTS pr_err("%s: Command timeout\n", mmc_hostname(host->mmc)); #endif cmd->error = -ETIMEDOUT; } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) { pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc)); cmd->error = -EILSEQ; } if (!cmd->data || cmd->error) { if (host->curr.data && host->dma.sg) msm_dmov_stop_cmd(host->dma.channel, &host->dma.hdr, 0); else if (host->curr.data) { /* Non DMA */ msmsdcc_stop_data(host); timer |= msmsdcc_request_end(host, cmd->mrq); } else { /* host->data == NULL */ if (!cmd->error && host->prog_enable) { if (status & MCI_PROGDONE) { host->prog_scan = 0; host->prog_enable = 0; timer |= msmsdcc_request_end( host, cmd->mrq); } else host->curr.cmd = cmd; } else { if (host->prog_enable) { host->prog_scan = 0; host->prog_enable = 0; } timer |= msmsdcc_request_end( host, cmd->mrq); } } } else if (cmd->data) { if (!(cmd->data->flags & MMC_DATA_READ)) msmsdcc_start_data(host, cmd->data, NULL, 0); } } 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_reset_and_restore(host); if (host->curr.data) msmsdcc_stop_data(host); if (!data->stop) timer |= msmsdcc_request_end(host, data->mrq); else { msmsdcc_start_command(host, data->stop, 0); timer = 1; } } } /* 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(host->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) timer |= msmsdcc_request_end( host, data->mrq); else { #if defined (CONFIG_MACH_ACER_A1) while ((host->pdev_id == 1) && (data->flags & MMC_DATA_WRITE) && (gpio_get_value(SDCC1_DATA_0) == 0)) { udelay(5); } #endif msmsdcc_start_command(host, data->stop, 0); timer = 1; } } } } ret = 1; } while (status); spin_unlock(&host->lock); return IRQ_RETVAL(ret); }
static int msmsdcc_pio_irq(int irq, void *dev_id) { struct msmsdcc_host *host = dev_id; void __iomem *base = host->base; uint32_t status; status = readl(base + MMCISTATUS); #if IRQ_DEBUG msmsdcc_print_status(host, "irq1-r", status); #endif /* SEMC:LC: Update for DMS00768370 start */ //do { /*original*/ while(host->pio.sg){ /* SEMC:LC: Update for DMS00768370 end */ unsigned long flags; unsigned int remain, len; char *buffer; if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_RXDATAAVLBL))) { if (host->curr.xfer_remain == 0 || !msmsdcc_piopoll) break; if (msmsdcc_spin_on_status(host, (MCI_TXFIFOHALFEMPTY | MCI_RXDATAAVLBL), PIO_SPINMAX)) { break; } } /* Map the current scatter buffer */ local_irq_save(flags); buffer = kmap_atomic(sg_page(host->pio.sg), KM_BIO_SRC_IRQ) + host->pio.sg->offset; buffer += host->pio.sg_off; remain = host->pio.sg->length - host->pio.sg_off; len = 0; if (status & MCI_RXACTIVE) len = msmsdcc_pio_read(host, buffer, remain); if (status & MCI_TXACTIVE) len = msmsdcc_pio_write(host, buffer, remain, status); /* Unmap the buffer */ kunmap_atomic(buffer, KM_BIO_SRC_IRQ); local_irq_restore(flags); host->pio.sg_off += len; host->curr.xfer_remain -= len; host->curr.data_xfered += len; remain -= len; if (remain == 0) { /* This sg page is full - do some housekeeping */ if (status & MCI_RXACTIVE && host->curr.user_pages) flush_dcache_page(sg_page(host->pio.sg)); if (!--host->pio.sg_len) { memset(&host->pio, 0, sizeof(host->pio)); break; } /* Advance to next sg */ host->pio.sg++; host->pio.sg_off = 0; } status = readl(base + MMCISTATUS); /* SEMC:LC: Update for DMS00768370 start */ //} while (1); /*original*/ } /* SEMC:LC: Update for DMS00768370 end */ if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1); /* ATHENV */ #ifdef ATH_PATCH if (!host->curr.xfer_remain) { if (host->pdev_id == ATH_WLAN_SLOT) { if (readl(host->base + MMCIMASK0) & MCI_SDIOINTOPERMASK) writel(MCI_SDIOINTOPERMASK, base + MMCIMASK1); else writel(0, base + MMCIMASK1); } else { writel(0, base + MMCIMASK1); } } #else if (!host->curr.xfer_remain) writel(0, base + MMCIMASK1); #endif /* ATHENV */ return IRQ_HANDLED; }
static irqreturn_t msmsdcc_pio_irq(int irq, void *dev_id) { struct msmsdcc_host *host = dev_id; void __iomem *base = host->base; uint32_t status; status = readl(base + MMCISTATUS); #if IRQ_DEBUG msmsdcc_print_status(host, "irq1-r", status); #endif do { unsigned long flags; unsigned int remain, len; char *buffer; if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_RXDATAAVLBL))) break; /* Map the current scatter buffer */ local_irq_save(flags); buffer = kmap_atomic(sg_page(host->pio.sg), KM_BIO_SRC_IRQ) + host->pio.sg->offset; buffer += host->pio.sg_off; remain = host->pio.sg->length - host->pio.sg_off; len = 0; if (status & MCI_RXACTIVE) len = msmsdcc_pio_read(host, buffer, remain); if (status & MCI_TXACTIVE) len = msmsdcc_pio_write(host, buffer, remain, status); /* Unmap the buffer */ kunmap_atomic(buffer, KM_BIO_SRC_IRQ); local_irq_restore(flags); host->pio.sg_off += len; host->curr.xfer_remain -= len; host->curr.data_xfered += len; remain -= len; if (remain) /* Done with this page? */ break; /* Nope */ if (status & MCI_RXACTIVE && host->curr.user_pages) flush_dcache_page(sg_page(host->pio.sg)); if (!--host->pio.sg_len) { memset(&host->pio, 0, sizeof(host->pio)); break; } /* Advance to next sg */ host->pio.sg++; host->pio.sg_off = 0; status = readl(base + MMCISTATUS); } while (1); if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) { writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1); if (!host->curr.xfer_remain) { /* Delay needed (same port was just written) */ msmsdcc_delay(host); writel(0, base + MMCIMASK1); } } else if (!host->curr.xfer_remain) writel(0, base + MMCIMASK1); return IRQ_HANDLED; }