aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorSebastian Siewior <bigeasy@linutronix.de>2013-04-24 04:48:25 -0400
committerDavid S. Miller <davem@davemloft.net>2013-04-25 04:13:18 -0400
commita11fbba9a7d338c4a4e4be624af0334bbf2c9a5a (patch)
treef4e73a12264bc031cad97ff1bd9411ea0ee15f55 /drivers/net
parent6e6ceaedb5901c7ebd23e5222726dab5362938bd (diff)
net/cpsw: fix irq_disable() with threaded interrupts
During high throughput it is likely that we receive both: an RX and TX interrupt. The normal behaviour is that once we enter the ISR the interrupts are disabled in the IRQ chip and so the ISR is invoked only once and the interrupt line is disabled once. It will be re-enabled after napi completes. With threaded interrupts on the other hand the interrupt the interrupt is disabled immediately and the ISR is marked for "later". By having TX and RX interrupt marked pending we invoke them both and disable the interrupt line twice. The napi callback is still executed once and so after it completes we remain with interrupts disabled. The initial patch simply removed the cpsw_{enable|disable}_irq() calls and it worked well on my AM335X ES1.0 (beagle bone). On ES2.0 (beagle bone black) it caused an never ending interrupt (even after the mask via cpsw_intr_disable()) according to Mugunthan V N. Since I don't have the ES2.0 and no idea what is going on this patch tracks the state of the irq_disable() call and execute it only when not yet done. The book keeping is done on the first struct since with dual_emac we can have two of those and only one interrupt line. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Acked-by: Mugunthan V N <mugunthanvnm@ti.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/ethernet/ti/cpsw.c25
1 files changed, 22 insertions, 3 deletions
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 1c1e7a82f909..4e2d224dd680 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -348,6 +348,7 @@ struct cpsw_priv {
348 /* snapshot of IRQ numbers */ 348 /* snapshot of IRQ numbers */
349 u32 irqs_table[4]; 349 u32 irqs_table[4];
350 u32 num_irqs; 350 u32 num_irqs;
351 bool irq_enabled;
351 struct cpts *cpts; 352 struct cpts *cpts;
352 u32 emac_port; 353 u32 emac_port;
353}; 354};
@@ -515,7 +516,10 @@ static irqreturn_t cpsw_interrupt(int irq, void *dev_id)
515 return IRQ_NONE; 516 return IRQ_NONE;
516 517
517 cpsw_intr_disable(priv); 518 cpsw_intr_disable(priv);
518 cpsw_disable_irq(priv); 519 if (priv->irq_enabled == true) {
520 cpsw_disable_irq(priv);
521 priv->irq_enabled = false;
522 }
519 523
520 if (netif_running(priv->ndev)) { 524 if (netif_running(priv->ndev)) {
521 napi_schedule(&priv->napi); 525 napi_schedule(&priv->napi);
@@ -544,10 +548,16 @@ static int cpsw_poll(struct napi_struct *napi, int budget)
544 548
545 num_rx = cpdma_chan_process(priv->rxch, budget); 549 num_rx = cpdma_chan_process(priv->rxch, budget);
546 if (num_rx < budget) { 550 if (num_rx < budget) {
551 struct cpsw_priv *prim_cpsw;
552
547 napi_complete(napi); 553 napi_complete(napi);
548 cpsw_intr_enable(priv); 554 cpsw_intr_enable(priv);
549 cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX); 555 cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
550 cpsw_enable_irq(priv); 556 prim_cpsw = cpsw_get_slave_priv(priv, 0);
557 if (prim_cpsw->irq_enabled == false) {
558 cpsw_enable_irq(priv);
559 prim_cpsw->irq_enabled = true;
560 }
551 } 561 }
552 562
553 if (num_rx || num_tx) 563 if (num_rx || num_tx)
@@ -886,6 +896,7 @@ static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_priv *priv)
886static int cpsw_ndo_open(struct net_device *ndev) 896static int cpsw_ndo_open(struct net_device *ndev)
887{ 897{
888 struct cpsw_priv *priv = netdev_priv(ndev); 898 struct cpsw_priv *priv = netdev_priv(ndev);
899 struct cpsw_priv *prim_cpsw;
889 int i, ret; 900 int i, ret;
890 u32 reg; 901 u32 reg;
891 902
@@ -953,6 +964,14 @@ static int cpsw_ndo_open(struct net_device *ndev)
953 cpsw_set_coalesce(ndev, &coal); 964 cpsw_set_coalesce(ndev, &coal);
954 } 965 }
955 966
967 prim_cpsw = cpsw_get_slave_priv(priv, 0);
968 if (prim_cpsw->irq_enabled == false) {
969 if ((priv == prim_cpsw) || !netif_running(prim_cpsw->ndev)) {
970 prim_cpsw->irq_enabled = true;
971 cpsw_enable_irq(prim_cpsw);
972 }
973 }
974
956 cpdma_ctlr_start(priv->dma); 975 cpdma_ctlr_start(priv->dma);
957 cpsw_intr_enable(priv); 976 cpsw_intr_enable(priv);
958 napi_enable(&priv->napi); 977 napi_enable(&priv->napi);
@@ -1614,7 +1633,7 @@ static int cpsw_probe_dual_emac(struct platform_device *pdev,
1614 priv_sl2->irqs_table[i] = priv->irqs_table[i]; 1633 priv_sl2->irqs_table[i] = priv->irqs_table[i];
1615 priv_sl2->num_irqs = priv->num_irqs; 1634 priv_sl2->num_irqs = priv->num_irqs;
1616 } 1635 }
1617 1636 priv->irq_enabled = true;
1618 ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; 1637 ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
1619 1638
1620 ndev->netdev_ops = &cpsw_netdev_ops; 1639 ndev->netdev_ops = &cpsw_netdev_ops;