static int s3c64xx_dma_flush(struct s3c2410_dma_chan *chan) { struct s3c64xx_dma_buff *buff, *next; u32 config; dbg_showchan(chan); pr_debug("%s: flushing channel\n", __func__); config = readl(chan->regs + PL080S_CH_CONFIG); config &= ~PL080_CONFIG_ENABLE; writel(config, chan->regs + PL080S_CH_CONFIG); /* dump all the buffers associated with this channel */ for (buff = chan->curr; buff != NULL; buff = next) { next = buff->next; pr_debug("%s: buff %p (next %p)\n", __func__, buff, buff->next); s3c64xx_dma_bufffdone(chan, buff, S3C2410_RES_ABORT); s3c64xx_dma_freebuff(buff); } chan->curr = chan->next = chan->end = NULL; return 0; }
static irqreturn_t s3c64xx_dma_irq(int irq, void *pw) { struct s3c64xx_dmac *dmac = pw; struct s3c2410_dma_chan *chan; enum s3c2410_dma_buffresult res; u32 tcstat, errstat; u32 bit; int offs; tcstat = readl(dmac->regs + PL080_TC_STATUS); errstat = readl(dmac->regs + PL080_ERR_STATUS); for (offs = 0, bit = 1; offs < 8; offs++, bit <<= 1) { struct s3c64xx_dma_buff *buff; if (!(errstat & bit) && !(tcstat & bit)) continue; chan = dmac->channels + offs; res = S3C2410_RES_ERR; if (tcstat & bit) { writel(bit, dmac->regs + PL080_TC_CLEAR); res = S3C2410_RES_OK; } if (errstat & bit) writel(bit, dmac->regs + PL080_ERR_CLEAR); buff = chan->curr; while (buff && buff != chan->next && buff->next != chan->next) buff = buff->next; if (!buff) BUG(); if (buff == chan->next) buff = chan->end; s3c64xx_dma_bufffdone(chan, buff, res); if (!(chan->flags & S3C2410_DMAF_CIRCULAR)) { chan->curr = buff->next; s3c64xx_dma_freebuff(buff); } buff = chan->next; if (chan->next == chan->end) { chan->next = chan->curr; if (!(chan->flags & S3C2410_DMAF_CIRCULAR)) chan->end = NULL; } else { chan->next = buff->next; } } return IRQ_HANDLED; }
static irqreturn_t s3c64xx_dma_irq(int irq, void *pw) { struct s3c64xx_dmac *dmac = pw; struct s3c2410_dma_chan *chan; enum s3c2410_dma_buffresult res; u32 tcstat, errstat; u32 bit; int offs; tcstat = readl(dmac->regs + PL080_TC_STATUS); errstat = readl(dmac->regs + PL080_ERR_STATUS); for (offs = 0, bit = 1; offs < 8; offs++, bit <<= 1) { struct s3c64xx_dma_buff *buff; if (!(errstat & bit) && !(tcstat & bit)) continue; chan = dmac->channels + offs; res = S3C2410_RES_ERR; if (tcstat & bit) { writel(bit, dmac->regs + PL080_TC_CLEAR); res = S3C2410_RES_OK; } if (errstat & bit) writel(bit, dmac->regs + PL080_ERR_CLEAR); /* 'next' points to the buffer that is next to the * currently active buffer. * For CIRCULAR queues, 'next' will be same as 'curr' * when 'end' is the active buffer. */ buff = chan->curr; while (buff && buff != chan->next && buff->next != chan->next) buff = buff->next; if (!buff) BUG(); if (buff == chan->next) buff = chan->end; s3c64xx_dma_bufffdone(chan, buff, res); /* Free the node and update curr, if non-circular queue */ if (!(chan->flags & S3C2410_DMAF_CIRCULAR)) { chan->curr = buff->next; s3c64xx_dma_freebuff(buff); } /* Update 'next' */ buff = chan->next; if (chan->next == chan->end) { chan->next = chan->curr; if (!(chan->flags & S3C2410_DMAF_CIRCULAR)) chan->end = NULL; } else { chan->next = buff->next; } } return IRQ_HANDLED; }