aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLennert Buytenhek <buytenh@wantstofly.org>2008-06-01 19:47:21 -0400
committerLennert Buytenhek <buytenh@wantstofly.org>2008-06-12 02:40:37 -0400
commit226bb6b732f8c2cc7004279c509333fa41186a6d (patch)
tree8b94892772c21f3be5f22b844ed18cf49c438dd5 /drivers
parent3d6b35bc5090cf8d8b7e62eca1f9c21ca56fc6c7 (diff)
mv643xx_eth: work around TX hang hardware issue
Under some conditions, the TXQ ('TX queue being served') bit can clear before all packets queued for that TX queue have been transmitted. This patch enables TXend interrupts, and uses those to re-kick TX queues that claim to be idle but still have queued descriptors from the interrupt handler. Signed-off-by: Lennert Buytenhek <buytenh@marvell.com> Acked-by: Dale Farnsworth <dale@farnsworth.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/mv643xx_eth.c35
1 files changed, 30 insertions, 5 deletions
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index 287155ea9ce1..c99915740779 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -96,6 +96,7 @@ static char mv643xx_eth_driver_version[] = "1.0";
96#define TX_BW_MTU(p) (0x0458 + ((p) << 10)) 96#define TX_BW_MTU(p) (0x0458 + ((p) << 10))
97#define TX_BW_BURST(p) (0x045c + ((p) << 10)) 97#define TX_BW_BURST(p) (0x045c + ((p) << 10))
98#define INT_CAUSE(p) (0x0460 + ((p) << 10)) 98#define INT_CAUSE(p) (0x0460 + ((p) << 10))
99#define INT_TX_END 0x07f80000
99#define INT_RX 0x0007fbfc 100#define INT_RX 0x0007fbfc
100#define INT_EXT 0x00000002 101#define INT_EXT 0x00000002
101#define INT_CAUSE_EXT(p) (0x0464 + ((p) << 10)) 102#define INT_CAUSE_EXT(p) (0x0464 + ((p) << 10))
@@ -619,7 +620,7 @@ static int mv643xx_eth_poll(struct napi_struct *napi, int budget)
619 netif_rx_complete(mp->dev, napi); 620 netif_rx_complete(mp->dev, napi);
620 wrl(mp, INT_CAUSE(mp->port_num), 0); 621 wrl(mp, INT_CAUSE(mp->port_num), 0);
621 wrl(mp, INT_CAUSE_EXT(mp->port_num), 0); 622 wrl(mp, INT_CAUSE_EXT(mp->port_num), 0);
622 wrl(mp, INT_MASK(mp->port_num), INT_RX | INT_EXT); 623 wrl(mp, INT_MASK(mp->port_num), INT_TX_END | INT_RX | INT_EXT);
623 } 624 }
624 625
625 return rx; 626 return rx;
@@ -1622,8 +1623,10 @@ static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id)
1622 struct mv643xx_eth_private *mp = netdev_priv(dev); 1623 struct mv643xx_eth_private *mp = netdev_priv(dev);
1623 u32 int_cause; 1624 u32 int_cause;
1624 u32 int_cause_ext; 1625 u32 int_cause_ext;
1626 u32 txq_active;
1625 1627
1626 int_cause = rdl(mp, INT_CAUSE(mp->port_num)) & (INT_RX | INT_EXT); 1628 int_cause = rdl(mp, INT_CAUSE(mp->port_num)) &
1629 (INT_TX_END | INT_RX | INT_EXT);
1627 if (int_cause == 0) 1630 if (int_cause == 0)
1628 return IRQ_NONE; 1631 return IRQ_NONE;
1629 1632
@@ -1675,6 +1678,8 @@ static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id)
1675 } 1678 }
1676#endif 1679#endif
1677 1680
1681 txq_active = rdl(mp, TXQ_COMMAND(mp->port_num));
1682
1678 /* 1683 /*
1679 * TxBuffer or TxError set for any of the 8 queues? 1684 * TxBuffer or TxError set for any of the 8 queues?
1680 */ 1685 */
@@ -1684,8 +1689,28 @@ static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id)
1684 for (i = 0; i < 8; i++) 1689 for (i = 0; i < 8; i++)
1685 if (mp->txq_mask & (1 << i)) 1690 if (mp->txq_mask & (1 << i))
1686 txq_reclaim(mp->txq + i, 0); 1691 txq_reclaim(mp->txq + i, 0);
1692 }
1687 1693
1688 __txq_maybe_wake(mp->txq + mp->txq_primary); 1694 /*
1695 * Any TxEnd interrupts?
1696 */
1697 if (int_cause & INT_TX_END) {
1698 int i;
1699
1700 wrl(mp, INT_CAUSE(mp->port_num), ~(int_cause & INT_TX_END));
1701 for (i = 0; i < 8; i++) {
1702 struct tx_queue *txq = mp->txq + i;
1703 if (txq->tx_desc_count && !((txq_active >> i) & 1))
1704 txq_enable(txq);
1705 }
1706 }
1707
1708 /*
1709 * Enough space again in the primary TX queue for a full packet?
1710 */
1711 if (int_cause_ext & INT_EXT_TX) {
1712 struct tx_queue *txq = mp->txq + mp->txq_primary;
1713 __txq_maybe_wake(txq);
1689 } 1714 }
1690 1715
1691 return IRQ_HANDLED; 1716 return IRQ_HANDLED;
@@ -1869,7 +1894,7 @@ static int mv643xx_eth_open(struct net_device *dev)
1869 wrl(mp, INT_MASK_EXT(mp->port_num), 1894 wrl(mp, INT_MASK_EXT(mp->port_num),
1870 INT_EXT_LINK | INT_EXT_PHY | INT_EXT_TX); 1895 INT_EXT_LINK | INT_EXT_PHY | INT_EXT_TX);
1871 1896
1872 wrl(mp, INT_MASK(mp->port_num), INT_RX | INT_EXT); 1897 wrl(mp, INT_MASK(mp->port_num), INT_TX_END | INT_RX | INT_EXT);
1873 1898
1874 return 0; 1899 return 0;
1875 1900
@@ -2005,7 +2030,7 @@ static void mv643xx_eth_netpoll(struct net_device *dev)
2005 2030
2006 mv643xx_eth_irq(dev->irq, dev); 2031 mv643xx_eth_irq(dev->irq, dev);
2007 2032
2008 wrl(mp, INT_MASK(mp->port_num), INT_RX | INT_CAUSE_EXT); 2033 wrl(mp, INT_MASK(mp->port_num), INT_TX_END | INT_RX | INT_CAUSE_EXT);
2009} 2034}
2010#endif 2035#endif
2011 2036