|
@@ -96,6 +96,7 @@ static char mv643xx_eth_driver_version[] = "1.0";
|
|
|
#define TX_BW_MTU(p) (0x0458 + ((p) << 10))
|
|
|
#define TX_BW_BURST(p) (0x045c + ((p) << 10))
|
|
|
#define INT_CAUSE(p) (0x0460 + ((p) << 10))
|
|
|
+#define INT_TX_END 0x07f80000
|
|
|
#define INT_RX 0x0007fbfc
|
|
|
#define INT_EXT 0x00000002
|
|
|
#define INT_CAUSE_EXT(p) (0x0464 + ((p) << 10))
|
|
@@ -619,7 +620,7 @@ static int mv643xx_eth_poll(struct napi_struct *napi, int budget)
|
|
|
netif_rx_complete(mp->dev, napi);
|
|
|
wrl(mp, INT_CAUSE(mp->port_num), 0);
|
|
|
wrl(mp, INT_CAUSE_EXT(mp->port_num), 0);
|
|
|
- wrl(mp, INT_MASK(mp->port_num), INT_RX | INT_EXT);
|
|
|
+ wrl(mp, INT_MASK(mp->port_num), INT_TX_END | INT_RX | INT_EXT);
|
|
|
}
|
|
|
|
|
|
return rx;
|
|
@@ -1622,8 +1623,10 @@ static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id)
|
|
|
struct mv643xx_eth_private *mp = netdev_priv(dev);
|
|
|
u32 int_cause;
|
|
|
u32 int_cause_ext;
|
|
|
+ u32 txq_active;
|
|
|
|
|
|
- int_cause = rdl(mp, INT_CAUSE(mp->port_num)) & (INT_RX | INT_EXT);
|
|
|
+ int_cause = rdl(mp, INT_CAUSE(mp->port_num)) &
|
|
|
+ (INT_TX_END | INT_RX | INT_EXT);
|
|
|
if (int_cause == 0)
|
|
|
return IRQ_NONE;
|
|
|
|
|
@@ -1675,6 +1678,8 @@ static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
+ txq_active = rdl(mp, TXQ_COMMAND(mp->port_num));
|
|
|
+
|
|
|
/*
|
|
|
* TxBuffer or TxError set for any of the 8 queues?
|
|
|
*/
|
|
@@ -1684,8 +1689,28 @@ static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id)
|
|
|
for (i = 0; i < 8; i++)
|
|
|
if (mp->txq_mask & (1 << i))
|
|
|
txq_reclaim(mp->txq + i, 0);
|
|
|
+ }
|
|
|
|
|
|
- __txq_maybe_wake(mp->txq + mp->txq_primary);
|
|
|
+ /*
|
|
|
+ * Any TxEnd interrupts?
|
|
|
+ */
|
|
|
+ if (int_cause & INT_TX_END) {
|
|
|
+ int i;
|
|
|
+
|
|
|
+ wrl(mp, INT_CAUSE(mp->port_num), ~(int_cause & INT_TX_END));
|
|
|
+ for (i = 0; i < 8; i++) {
|
|
|
+ struct tx_queue *txq = mp->txq + i;
|
|
|
+ if (txq->tx_desc_count && !((txq_active >> i) & 1))
|
|
|
+ txq_enable(txq);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Enough space again in the primary TX queue for a full packet?
|
|
|
+ */
|
|
|
+ if (int_cause_ext & INT_EXT_TX) {
|
|
|
+ struct tx_queue *txq = mp->txq + mp->txq_primary;
|
|
|
+ __txq_maybe_wake(txq);
|
|
|
}
|
|
|
|
|
|
return IRQ_HANDLED;
|
|
@@ -1869,7 +1894,7 @@ static int mv643xx_eth_open(struct net_device *dev)
|
|
|
wrl(mp, INT_MASK_EXT(mp->port_num),
|
|
|
INT_EXT_LINK | INT_EXT_PHY | INT_EXT_TX);
|
|
|
|
|
|
- wrl(mp, INT_MASK(mp->port_num), INT_RX | INT_EXT);
|
|
|
+ wrl(mp, INT_MASK(mp->port_num), INT_TX_END | INT_RX | INT_EXT);
|
|
|
|
|
|
return 0;
|
|
|
|
|
@@ -2005,7 +2030,7 @@ static void mv643xx_eth_netpoll(struct net_device *dev)
|
|
|
|
|
|
mv643xx_eth_irq(dev->irq, dev);
|
|
|
|
|
|
- wrl(mp, INT_MASK(mp->port_num), INT_RX | INT_CAUSE_EXT);
|
|
|
+ wrl(mp, INT_MASK(mp->port_num), INT_TX_END | INT_RX | INT_CAUSE_EXT);
|
|
|
}
|
|
|
#endif
|
|
|
|