aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma/amba-pl08x.c
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@st.com>2011-08-05 06:02:36 -0400
committerVinod Koul <vinod.koul@intel.com>2011-08-25 10:03:38 -0400
commit28da28365da3f3bea1d4b7212a8a40e4b9ac3229 (patch)
treea754c7ca42975d547ee1a16c7a4f3582a4851b55 /drivers/dma/amba-pl08x.c
parent16ca8105040217acf5b4b506d04bb933fb3a76af (diff)
dmaengine/amba-pl08x: Schedule tasklet in case of error interrupt
Currently, if error interrupt occurs, nothing is done in interrupt handler (just clearing the interrupts). We must somehow indicate this to the user that DMA is over, due to ERR interrupt or TC interrupt. So, this patch just schedules existing tasklet, with a print showing error interrupt has occurred on which channels. Signed-off-by: Viresh Kumar <viresh.kumar@st.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'drivers/dma/amba-pl08x.c')
-rw-r--r--drivers/dma/amba-pl08x.c44
1 files changed, 23 insertions, 21 deletions
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 3653961b6088..6bba32e5ddb8 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -1619,38 +1619,40 @@ static void pl08x_tasklet(unsigned long data)
1619static irqreturn_t pl08x_irq(int irq, void *dev) 1619static irqreturn_t pl08x_irq(int irq, void *dev)
1620{ 1620{
1621 struct pl08x_driver_data *pl08x = dev; 1621 struct pl08x_driver_data *pl08x = dev;
1622 u32 mask = 0; 1622 u32 mask = 0, err, tc, i;
1623 u32 val; 1623
1624 int i; 1624 /* check & clear - ERR & TC interrupts */
1625 1625 err = readl(pl08x->base + PL080_ERR_STATUS);
1626 val = readl(pl08x->base + PL080_ERR_STATUS); 1626 if (err) {
1627 if (val) { 1627 dev_err(&pl08x->adev->dev, "%s error interrupt, register value 0x%08x\n",
1628 /* An error interrupt (on one or more channels) */ 1628 __func__, err);
1629 dev_err(&pl08x->adev->dev, 1629 writel(err, pl08x->base + PL080_ERR_CLEAR);
1630 "%s error interrupt, register value 0x%08x\n",
1631 __func__, val);
1632 /*
1633 * Simply clear ALL PL08X error interrupts,
1634 * regardless of channel and cause
1635 * FIXME: should be 0x00000003 on PL081 really.
1636 */
1637 writel(0x000000FF, pl08x->base + PL080_ERR_CLEAR);
1638 } 1630 }
1639 val = readl(pl08x->base + PL080_INT_STATUS); 1631 tc = readl(pl08x->base + PL080_INT_STATUS);
1632 if (tc)
1633 writel(tc, pl08x->base + PL080_TC_CLEAR);
1634
1635 if (!err && !tc)
1636 return IRQ_NONE;
1637
1640 for (i = 0; i < pl08x->vd->channels; i++) { 1638 for (i = 0; i < pl08x->vd->channels; i++) {
1641 if ((1 << i) & val) { 1639 if (((1 << i) & err) || ((1 << i) & tc)) {
1642 /* Locate physical channel */ 1640 /* Locate physical channel */
1643 struct pl08x_phy_chan *phychan = &pl08x->phy_chans[i]; 1641 struct pl08x_phy_chan *phychan = &pl08x->phy_chans[i];
1644 struct pl08x_dma_chan *plchan = phychan->serving; 1642 struct pl08x_dma_chan *plchan = phychan->serving;
1645 1643
1644 if (!plchan) {
1645 dev_err(&pl08x->adev->dev,
1646 "%s Error TC interrupt on unused channel: 0x%08x\n",
1647 __func__, i);
1648 continue;
1649 }
1650
1646 /* Schedule tasklet on this channel */ 1651 /* Schedule tasklet on this channel */
1647 tasklet_schedule(&plchan->tasklet); 1652 tasklet_schedule(&plchan->tasklet);
1648
1649 mask |= (1 << i); 1653 mask |= (1 << i);
1650 } 1654 }
1651 } 1655 }
1652 /* Clear only the terminal interrupts on channels we processed */
1653 writel(mask, pl08x->base + PL080_TC_CLEAR);
1654 1656
1655 return mask ? IRQ_HANDLED : IRQ_NONE; 1657 return mask ? IRQ_HANDLED : IRQ_NONE;
1656} 1658}