Beispiel #1
0
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);
}
Beispiel #2
0
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);
    }
}
Beispiel #3
0
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);
}
Beispiel #4
0
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);
	}
}