コード例 #1
0
ファイル: mmci.c プロジェクト: liuyang201666/linux-akae
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);
    }
}
コード例 #2
0
ファイル: mmci.c プロジェクト: liuyang201666/linux-akae
static void
mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
              unsigned int status)
{
    if (status & MCI_DATABLOCKEND) {
        host->data_xfered += data->blksz;
    }
    if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
        if (status & MCI_DATACRCFAIL)
            data->error = -EILSEQ;
        else if (status & MCI_DATATIMEOUT)
            data->error = -ETIMEDOUT;
        else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN))
            data->error = -EIO;
        status |= MCI_DATAEND;

        /*
         * We hit an error condition.  Ensure that any data
         * partially written to a page is properly coherent.
         */
        if (host->sg_len && data->flags & MMC_DATA_READ)
            flush_dcache_page(sg_page(host->sg_ptr));
    }
    if (status & MCI_DATAEND) {
        mmci_stop_data(host);

        if (!data->stop) {
            mmci_request_end(host, data->mrq);
        } else {
            mmci_start_command(host, data->stop, 0);
        }
    }
}
コード例 #3
0
static void
mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
	      unsigned int status)
{
	if (status & MCI_DATABLOCKEND) {
		host->data_xfered += 1 << data->blksz_bits;
	}
	if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
		if (status & MCI_DATACRCFAIL)
			data->error = MMC_ERR_BADCRC;
		else if (status & MCI_DATATIMEOUT)
			data->error = MMC_ERR_TIMEOUT;
		else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN))
			data->error = MMC_ERR_FIFO;
		status |= MCI_DATAEND;
	}
	if (status & MCI_DATAEND) {
		mmci_stop_data(host);

		if (!data->stop) {
			mmci_request_end(host, data->mrq);
		} else {
			mmci_start_command(host, data->stop, 0);
		}
	}
}
コード例 #4
0
ファイル: mmci.c プロジェクト: Lyude/linux
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);
	}
}
コード例 #5
0
ファイル: mmci.c プロジェクト: Lyude/linux
static void
mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
	      unsigned int status)
{
	/* Make sure we have data to handle */
	if (!data)
		return;

	/* First check for errors */
	if (status & (MCI_DATACRCFAIL | MCI_DATATIMEOUT |
		      host->variant->start_err |
		      MCI_TXUNDERRUN | MCI_RXOVERRUN)) {
		u32 remain, success;

		/* Terminate the DMA transfer */
		if (dma_inprogress(host)) {
			mmci_dma_data_error(host);
			mmci_dma_unmap(host, data);
		}

		/*
		 * Calculate how far we are into the transfer.  Note that
		 * the data counter gives the number of bytes transferred
		 * on the MMC bus, not on the host side.  On reads, this
		 * can be as much as a FIFO-worth of data ahead.  This
		 * matters for FIFO overruns only.
		 */
		remain = readl(host->base + MMCIDATACNT);
		success = data->blksz * data->blocks - remain;

		dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ, status 0x%08x at 0x%08x\n",
			status, success);
		if (status & MCI_DATACRCFAIL) {
			/* Last block was not successful */
			success -= 1;
			data->error = -EILSEQ;
		} else if (status & MCI_DATATIMEOUT) {
			data->error = -ETIMEDOUT;
		} else if (status & MCI_STARTBITERR) {
			data->error = -ECOMM;
		} else if (status & MCI_TXUNDERRUN) {
			data->error = -EIO;
		} else if (status & MCI_RXOVERRUN) {
			if (success > host->variant->fifosize)
				success -= host->variant->fifosize;
			else
				success = 0;
			data->error = -EIO;
		}
		data->bytes_xfered = round_down(success, data->blksz);
	}

	if (status & MCI_DATABLOCKEND)
		dev_err(mmc_dev(host->mmc), "stray MCI_DATABLOCKEND interrupt\n");

	if (status & MCI_DATAEND || data->error) {
		if (dma_inprogress(host))
			mmci_dma_finalize(host, data);
		mmci_stop_data(host);

		if (!data->error)
			/* The error clause is handled above, success! */
			data->bytes_xfered = data->blksz * data->blocks;

		if (!data->stop || host->mrq->sbc) {
			mmci_request_end(host, data->mrq);
		} else {
			mmci_start_command(host, data->stop, 0);
		}
	}
}