static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) { struct mmci_host *host = mmc_priv(mmc); WARN_ON(host->mrq != NULL); if (mrq->data && !is_power_of_2(mrq->data->blksz)) { printk(KERN_ERR "%s: Unsupported block size (%d bytes)\n", mmc_hostname(mmc), mrq->data->blksz); mrq->cmd->error = -EINVAL; mmc_request_done(mmc, mrq); return; } spin_lock_irq(&host->lock); host->mrq = mrq; if (mrq->data && mrq->data->flags & MMC_DATA_READ) mmci_start_data(host, mrq->data); mmci_start_command(host, mrq->cmd, 0); spin_unlock_irq(&host->lock); }
static void mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, unsigned int status) { void __iomem *base = host->base; host->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) { cmd->error = -ETIMEDOUT; } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) { cmd->error = -EILSEQ; } if (!cmd->data || cmd->error) { if (host->data) mmci_stop_data(host); mmci_request_end(host, cmd->mrq); } else if (!(cmd->data->flags & MMC_DATA_READ)) { mmci_start_data(host, cmd->data); } }
static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) { struct mmci_host *host = mmc_priv(mmc); WARN_ON(host->mrq != NULL); spin_lock_irq(&host->lock); host->mrq = mrq; if (mrq->data && mrq->data->flags & MMC_DATA_READ) mmci_start_data(host, mrq->data); mmci_start_command(host, mrq->cmd, 0); spin_unlock_irq(&host->lock); }
static void mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, unsigned int status) { void __iomem *base = host->base; bool sbc; if (!cmd) return; sbc = (cmd == host->mrq->sbc); /* * We need to be one of these interrupts to be considered worth * handling. Note that we tag on any latent IRQs postponed * due to waiting for busy status. */ if (!((status|host->busy_status) & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND))) return; /* * ST Micro variant: handle busy detection. */ if (host->variant->busy_detect) { bool busy_resp = !!(cmd->flags & MMC_RSP_BUSY); /* We are busy with a command, return */ if (host->busy_status && (status & host->variant->busy_detect_flag)) return; /* * We were not busy, but we now got a busy response on * something that was not an error, and we double-check * that the special busy status bit is still set before * proceeding. */ if (!host->busy_status && busy_resp && !(status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT)) && (readl(base + MMCISTATUS) & host->variant->busy_detect_flag)) { /* Clear the busy start IRQ */ writel(host->variant->busy_detect_mask, host->base + MMCICLEAR); /* Unmask the busy end IRQ */ writel(readl(base + MMCIMASK0) | host->variant->busy_detect_mask, base + MMCIMASK0); /* * Now cache the last response status code (until * the busy bit goes low), and return. */ host->busy_status = status & (MCI_CMDSENT|MCI_CMDRESPEND); return; } /* * At this point we are not busy with a command, we have * not received a new busy request, clear and mask the busy * end IRQ and fall through to process the IRQ. */ if (host->busy_status) { writel(host->variant->busy_detect_mask, host->base + MMCICLEAR); writel(readl(base + MMCIMASK0) & ~host->variant->busy_detect_mask, base + MMCIMASK0); host->busy_status = 0; } } host->cmd = NULL; if (status & MCI_CMDTIMEOUT) { cmd->error = -ETIMEDOUT; } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) { cmd->error = -EILSEQ; } else { 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 ((!sbc && !cmd->data) || cmd->error) { if (host->data) { /* Terminate the DMA transfer */ if (dma_inprogress(host)) { mmci_dma_data_error(host); mmci_dma_unmap(host, host->data); } mmci_stop_data(host); } mmci_request_end(host, host->mrq); } else if (sbc) { mmci_start_command(host, host->mrq->cmd, 0); } else if (!(cmd->data->flags & MMC_DATA_READ)) { mmci_start_data(host, cmd->data); } }