示例#1
0
/*
 *      hsu_dma_do_irq() - DMA interrupt handler
 *      @chip: HSUART DMA chip
 *      @nr: DMA channel number
 *      @status: Channel Status Register value
 *
 *      Description:
 *      This function handles Channel Error and Descriptor Done interrupts.
 *      This function should be called after determining that the DMA interrupt
 *      is not a normal timeout interrupt, ie. hsu_dma_get_status() returned 0.
 *
 *      Return:
 *      0 for invalid channel number, 1 otherwise.
 */
int hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr, u32 status)
{
    struct hsu_dma_chan *hsuc;
    struct hsu_dma_desc *desc;
    unsigned long flags;

    /* Sanity check */
    if (nr >= chip->hsu->nr_channels)
        return 0;

    hsuc = &chip->hsu->chan[nr];

    spin_lock_irqsave(&hsuc->vchan.lock, flags);
    desc = hsuc->desc;
    if (desc) {
        if (status & HSU_CH_SR_CHE) {
            desc->status = DMA_ERROR;
        } else if (desc->active < desc->nents) {
            hsu_dma_start_channel(hsuc);
        } else {
            vchan_cookie_complete(&desc->vdesc);
            desc->status = DMA_COMPLETE;
            hsu_dma_start_transfer(hsuc);
        }
    }
    spin_unlock_irqrestore(&hsuc->vchan.lock, flags);

    return 1;
}
示例#2
0
文件: hsu.c 项目: 1888/linux
irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr)
{
	struct hsu_dma_chan *hsuc;
	struct hsu_dma_desc *desc;
	unsigned long flags;
	u32 sr;

	/* Sanity check */
	if (nr >= chip->hsu->nr_channels)
		return IRQ_NONE;

	hsuc = &chip->hsu->chan[nr];

	/*
	 * No matter what situation, need read clear the IRQ status
	 * There is a bug, see Errata 5, HSD 2900918
	 */
	sr = hsu_dma_chan_get_sr(hsuc);
	if (!sr)
		return IRQ_NONE;

	/* Timeout IRQ, need wait some time, see Errata 2 */
	if (hsuc->direction == DMA_DEV_TO_MEM && (sr & HSU_CH_SR_DESCTO_ANY))
		udelay(2);

	sr &= ~HSU_CH_SR_DESCTO_ANY;
	if (!sr)
		return IRQ_HANDLED;

	spin_lock_irqsave(&hsuc->vchan.lock, flags);
	desc = hsuc->desc;
	if (desc) {
		if (sr & HSU_CH_SR_CHE) {
			desc->status = DMA_ERROR;
		} else if (desc->active < desc->nents) {
			hsu_dma_start_channel(hsuc);
		} else {
			vchan_cookie_complete(&desc->vdesc);
			desc->status = DMA_COMPLETE;
			hsu_dma_start_transfer(hsuc);
		}
	}
	spin_unlock_irqrestore(&hsuc->vchan.lock, flags);

	return IRQ_HANDLED;
}
示例#3
0
文件: hsu.c 项目: 1888/linux
static void hsu_dma_start_transfer(struct hsu_dma_chan *hsuc)
{
	struct virt_dma_desc *vdesc;

	/* Get the next descriptor */
	vdesc = vchan_next_desc(&hsuc->vchan);
	if (!vdesc) {
		hsuc->desc = NULL;
		return;
	}

	list_del(&vdesc->node);
	hsuc->desc = to_hsu_dma_desc(vdesc);

	/* Start the channel with a new descriptor */
	hsu_dma_start_channel(hsuc);
}