drivers: net: davinci_cpdma: acknowledge interrupt properly
authorMugunthan V N <mugunthanvnm@ti.com>
Sun, 17 Feb 2013 22:19:20 +0000 (22:19 +0000)
committerDavid S. Miller <davem@davemloft.net>
Mon, 18 Feb 2013 19:51:50 +0000 (14:51 -0500)
CPDMA interrupts are not properly acknowledged which leads to interrupt
storm, only cpdma interrupt 0 is acknowledged in Davinci CPDMA driver.
Changed cpdma_ctlr_eoi api to acknowledge 1 and 2 interrupts which are
used for rx and tx respectively.

Reported-by: Pantelis Antoniou <panto@antoniou-consulting.com>
Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/ti/davinci_cpdma.c
drivers/net/ethernet/ti/davinci_cpdma.h

index 4ceed6e..7e93df6 100644 (file)
@@ -510,19 +510,21 @@ static int cpsw_poll(struct napi_struct *napi, int budget)
        int                     num_tx, num_rx;
 
        num_tx = cpdma_chan_process(priv->txch, 128);
-       num_rx = cpdma_chan_process(priv->rxch, budget);
-
-       if (num_rx || num_tx)
-               cpsw_dbg(priv, intr, "poll %d rx, %d tx pkts\n",
-                        num_rx, num_tx);
+       if (num_tx)
+               cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX);
 
+       num_rx = cpdma_chan_process(priv->rxch, budget);
        if (num_rx < budget) {
                napi_complete(napi);
                cpsw_intr_enable(priv);
-               cpdma_ctlr_eoi(priv->dma);
+               cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
                cpsw_enable_irq(priv);
        }
 
+       if (num_rx || num_tx)
+               cpsw_dbg(priv, intr, "poll %d rx, %d tx pkts\n",
+                        num_rx, num_tx);
+
        return num_rx;
 }
 
@@ -835,7 +837,8 @@ static int cpsw_ndo_open(struct net_device *ndev)
        cpdma_ctlr_start(priv->dma);
        cpsw_intr_enable(priv);
        napi_enable(&priv->napi);
-       cpdma_ctlr_eoi(priv->dma);
+       cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
+       cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX);
 
        if (priv->data.dual_emac)
                priv->slaves[priv->emac_port].open_stat = true;
@@ -1075,7 +1078,9 @@ static void cpsw_ndo_tx_timeout(struct net_device *ndev)
        cpdma_chan_start(priv->txch);
        cpdma_ctlr_int_ctrl(priv->dma, true);
        cpsw_intr_enable(priv);
-       cpdma_ctlr_eoi(priv->dma);
+       cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
+       cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX);
+
 }
 
 static struct net_device_stats *cpsw_ndo_get_stats(struct net_device *ndev)
@@ -1094,7 +1099,9 @@ static void cpsw_ndo_poll_controller(struct net_device *ndev)
        cpsw_interrupt(ndev->irq, priv);
        cpdma_ctlr_int_ctrl(priv->dma, true);
        cpsw_intr_enable(priv);
-       cpdma_ctlr_eoi(priv->dma);
+       cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
+       cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX);
+
 }
 #endif
 
index 7d3bffd..68c3418 100644 (file)
@@ -493,9 +493,9 @@ int cpdma_ctlr_int_ctrl(struct cpdma_ctlr *ctlr, bool enable)
        return 0;
 }
 
-void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr)
+void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr, u32 value)
 {
-       dma_reg_write(ctlr, CPDMA_MACEOIVECTOR, 0);
+       dma_reg_write(ctlr, CPDMA_MACEOIVECTOR, value);
 }
 
 struct cpdma_chan *cpdma_chan_create(struct cpdma_ctlr *ctlr, int chan_num,
index a97d6ab..d9bcc60 100644 (file)
 
 #define CPDMA_RX_SOURCE_PORT(__status__)       ((__status__ >> 16) & 0x7)
 
+#define CPDMA_EOI_RX_THRESH    0x0
+#define CPDMA_EOI_RX           0x1
+#define CPDMA_EOI_TX           0x2
+#define CPDMA_EOI_MISC         0x3
+
 struct cpdma_params {
        struct device           *dev;
        void __iomem            *dmaregs;
@@ -88,7 +93,7 @@ int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
 int cpdma_chan_process(struct cpdma_chan *chan, int quota);
 
 int cpdma_ctlr_int_ctrl(struct cpdma_ctlr *ctlr, bool enable);
-void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr);
+void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr, u32 value);
 int cpdma_chan_int_ctrl(struct cpdma_chan *chan, bool enable);
 bool cpdma_check_free_tx_desc(struct cpdma_chan *chan);