[17/22] Cyclades PC300 driver: queue stop/start fix

From: Andrea Shepard
Date: Sun Jan 29 2012 - 21:57:53 EST


Change cpc_queue_xmit() to stop and restart the queue while it does things to
the DMA buffers and registers.

The Cyclades 4.1.0 release doesn't seem to function reliably without this; I
suspect it was a race condition bug that was always present.

Signed-off-by: Andrea Shepard <andrea@xxxxxxxxxxxxxxxxxxx>

diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c
index c44c26a..4d81507 100644
--- a/drivers/net/wan/pc300_drv.c
+++ b/drivers/net/wan/pc300_drv.c
@@ -2055,20 +2055,15 @@ static int cpc_queue_xmit(struct sk_buff *skb, struct net_device *dev)
if (d->trace_on) {
cpc_trace(dev, skb, 'T');
}
- dev->trans_start = jiffies;

/* Start transmission */
CPC_LOCK(card, flags);
- /* verify if it has more than one free descriptor */
- if (card->chan[ch].nfree_tx_bd <= 1) {
#ifdef PC300_DEBUG_QUEUE
- printk(KERN_DEBUG
- "%s: stopping queue for transmission\n",
- dev->name);
+ printk(KERN_DEBUG
+ "%s: stopping queue for transmission\n",
+ dev->name);
#endif
- /* don't have so stop the queue */
- netif_stop_queue(dev);
- }
+ netif_stop_queue(dev);
cpc_writel(card->hw.scabase + DTX_REG(EDAL, ch),
TX_BD_ADDR(ch, chan->tx_next_bd));
cpc_writeb(card->hw.scabase + M_REG(CMD, ch), CMD_TX_ENA);
@@ -2078,12 +2073,22 @@ static int cpc_queue_xmit(struct sk_buff *skb, struct net_device *dev)
cpc_readb(card->hw.falcbase + card->hw.cpld_reg2) |
(CPLD_REG2_FALC_LED1 << (2 * ch)));
}
+ /* verify if it has more than one free descriptor */
+ if (card->chan[ch].nfree_tx_bd > 1) {
+#ifdef PC300_DEBUG_QUEUE
+ printk(KERN_DEBUG
+ "%s: restarting queue\n",
+ dev->name);
+#endif
+ netif_wake_queue(dev);
+ }
CPC_UNLOCK(card, flags);
dev_kfree_skb(skb);

#ifdef PC300_DEBUG_TX
- printk(KERN_DEBUG "%s: cpc_queue_xmit returning normally\n",
- dev->name);
+ printk(KERN_DEBUG
+ "%s: cpc_queue_xmit returning normally\n",
+ dev->name);
#endif

return 0;
@@ -2221,7 +2226,9 @@ static void sca_tx_intr(pc300dev_t *dev)
#ifdef PC300_DEBUG_QUEUE
printk(KERN_DEBUG "Waking queue on TX interrupt\n");
#endif
- netif_wake_queue(dev->netdev);
+ if (chan->nfree_tx_bd > 1 &&
+ netif_queue_stopped(dev->netdev))
+ netif_wake_queue(dev->netdev);
#ifdef CONFIG_PC300_MLPPP
}
#endif
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/