aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorMichael Buesch <mb@bu3sch.de>2006-10-28 18:52:34 -0400
committerJohn W. Linville <linville@laptop.(none)>2006-10-31 22:15:40 -0500
commit81e171b95d2d06a64465a1e6ab1e2fb864ea2448 (patch)
tree5154832a9d5f54901163f50445324910dcb22d93 /drivers/net
parent115e222d538e7838bffa0f76409acd9816a0ef32 (diff)
[PATCH] bcm43xx: Fix low-traffic netdev watchdog TX timeouts
This fixes a netdev watchdog timeout problem. The software needs to call netif_tx_disable before running the hardware calibration code. The problem condition can be shown by the following timegraph. |---5secs - ~10 jiffies time---|---|OOPS ^ ^ last real TX periodic work stops netif At OOPS, the following happens: The watchdog timer triggers, because the timeout of 5secs is over. The watchdog first checks for stopped TX. _Usually_ TX is only stopped from the TX handler to indicate a full TX queue. But this is different. We need to stop TX here, regardless of the TX queue state. So the watchdog recognizes the stopped device and assumes it is stopped due to full TX queues (Which is a _wrong_ assumption in this case). It then tests how far the last TX has been in the past. If it's more than 5secs (which is the case for low or no traffic), it will fire a TX timeout. Signed-off-by: Michael Buesch <mb@bu3sch.de> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index a94c6d8826f8..65edb56107fd 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -3163,9 +3163,11 @@ static int estimate_periodic_work_badness(unsigned int state)
3163static void bcm43xx_periodic_work_handler(void *d) 3163static void bcm43xx_periodic_work_handler(void *d)
3164{ 3164{
3165 struct bcm43xx_private *bcm = d; 3165 struct bcm43xx_private *bcm = d;
3166 struct net_device *net_dev = bcm->net_dev;
3166 unsigned long flags; 3167 unsigned long flags;
3167 u32 savedirqs = 0; 3168 u32 savedirqs = 0;
3168 int badness; 3169 int badness;
3170 unsigned long orig_trans_start = 0;
3169 3171
3170 mutex_lock(&bcm->mutex); 3172 mutex_lock(&bcm->mutex);
3171 badness = estimate_periodic_work_badness(bcm->periodic_state); 3173 badness = estimate_periodic_work_badness(bcm->periodic_state);
@@ -3173,7 +3175,18 @@ static void bcm43xx_periodic_work_handler(void *d)
3173 /* Periodic work will take a long time, so we want it to 3175 /* Periodic work will take a long time, so we want it to
3174 * be preemtible. 3176 * be preemtible.
3175 */ 3177 */
3176 netif_tx_disable(bcm->net_dev); 3178
3179 netif_tx_lock_bh(net_dev);
3180 /* We must fake a started transmission here, as we are going to
3181 * disable TX. If we wouldn't fake a TX, it would be possible to
3182 * trigger the netdev watchdog, if the last real TX is already
3183 * some time on the past (slightly less than 5secs)
3184 */
3185 orig_trans_start = net_dev->trans_start;
3186 net_dev->trans_start = jiffies;
3187 netif_stop_queue(net_dev);
3188 netif_tx_unlock_bh(net_dev);
3189
3177 spin_lock_irqsave(&bcm->irq_lock, flags); 3190 spin_lock_irqsave(&bcm->irq_lock, flags);
3178 bcm43xx_mac_suspend(bcm); 3191 bcm43xx_mac_suspend(bcm);
3179 if (bcm43xx_using_pio(bcm)) 3192 if (bcm43xx_using_pio(bcm))
@@ -3198,6 +3211,7 @@ static void bcm43xx_periodic_work_handler(void *d)
3198 bcm43xx_pio_thaw_txqueues(bcm); 3211 bcm43xx_pio_thaw_txqueues(bcm);
3199 bcm43xx_mac_enable(bcm); 3212 bcm43xx_mac_enable(bcm);
3200 netif_wake_queue(bcm->net_dev); 3213 netif_wake_queue(bcm->net_dev);
3214 net_dev->trans_start = orig_trans_start;
3201 } 3215 }
3202 mmiowb(); 3216 mmiowb();
3203 spin_unlock_irqrestore(&bcm->irq_lock, flags); 3217 spin_unlock_irqrestore(&bcm->irq_lock, flags);