Beispiel #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;
}
Beispiel #2
0
Datei: hsu.c Projekt: 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;
}
Beispiel #3
0
static irqreturn_t st_fdma_irq_handler(int irq, void *dev_id)
{
    struct st_fdma_dev *fdev = dev_id;
    irqreturn_t ret = IRQ_NONE;
    struct st_fdma_chan *fchan = &fdev->chans[0];
    unsigned long int_sta, clr;

    int_sta = fdma_read(fdev, FDMA_INT_STA_OFST);
    clr = int_sta;

    for (; int_sta != 0 ; int_sta >>= 2, fchan++) {
        if (!(int_sta & (FDMA_INT_STA_CH | FDMA_INT_STA_ERR)))
            continue;

        spin_lock(&fchan->vchan.lock);
        st_fdma_ch_sta_update(fchan, int_sta);

        if (fchan->fdesc) {
            if (!fchan->fdesc->iscyclic) {
                list_del(&fchan->fdesc->vdesc.node);
                vchan_cookie_complete(&fchan->fdesc->vdesc);
                fchan->fdesc = NULL;
                fchan->status = DMA_COMPLETE;
            } else {
                vchan_cyclic_callback(&fchan->fdesc->vdesc);
            }

            /* Start the next descriptor (if available) */
            if (!fchan->fdesc)
                st_fdma_xfer_desc(fchan);
        }

        spin_unlock(&fchan->vchan.lock);
        ret = IRQ_HANDLED;
    }

    fdma_write(fdev, clr, FDMA_INT_CLR_OFST);

    return ret;
}