aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/b43legacy
diff options
context:
space:
mode:
authorLarry Finger <Larry.Finger@lwfinger.net>2009-08-01 23:32:48 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-04 16:44:24 -0400
commitc1be5152860218dffea6a47cff5ea31a56c6cff5 (patch)
treecd903db6abd58139b8b0628cbeabf5e0a83d9a9f /drivers/net/wireless/b43legacy
parent3ad201496badddd8e1cda87ee6d29e8b3b8e1279 (diff)
b43legacy: Work around mac80211 race condition
As shown in http://thread.gmane.org/gmane.linux.kernel.wireless.general/36497, mac80211 has a bug that allows a call to the TX routine after the queues have been stopped. This situation will only occur under extreme stress. Although b43legacy does not crash when this condition occurs, it does generate a WARN_ON and also logs a queue overrun message. This patch recognizes b43legacy is not at fault and logs a message only when the most verbose debugging mode is enabled. In the unlikely event that the queue is not stopped when the DMA queue becomes full, then a warning is issued. This patch is based on the one used by b43. Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/b43legacy')
-rw-r--r--drivers/net/wireless/b43legacy/dma.c22
1 files changed, 16 insertions, 6 deletions
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c
index 2f90fb9f5367..866403415811 100644
--- a/drivers/net/wireless/b43legacy/dma.c
+++ b/drivers/net/wireless/b43legacy/dma.c
@@ -1366,15 +1366,25 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev,
1366 ring = priority_to_txring(dev, skb_get_queue_mapping(skb)); 1366 ring = priority_to_txring(dev, skb_get_queue_mapping(skb));
1367 spin_lock_irqsave(&ring->lock, flags); 1367 spin_lock_irqsave(&ring->lock, flags);
1368 B43legacy_WARN_ON(!ring->tx); 1368 B43legacy_WARN_ON(!ring->tx);
1369 if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) { 1369
1370 b43legacywarn(dev->wl, "DMA queue overflow\n"); 1370 if (unlikely(ring->stopped)) {
1371 /* We get here only because of a bug in mac80211.
1372 * Because of a race, one packet may be queued after
1373 * the queue is stopped, thus we got called when we shouldn't.
1374 * For now, just refuse the transmit. */
1375 if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE))
1376 b43legacyerr(dev->wl, "Packet after queue stopped\n");
1377 err = -ENOSPC;
1378 goto out_unlock;
1379 }
1380
1381 if (unlikely(WARN_ON(free_slots(ring) < SLOTS_PER_PACKET))) {
1382 /* If we get here, we have a real error with the queue
1383 * full, but queues not stopped. */
1384 b43legacyerr(dev->wl, "DMA queue overflow\n");
1371 err = -ENOSPC; 1385 err = -ENOSPC;
1372 goto out_unlock; 1386 goto out_unlock;
1373 } 1387 }
1374 /* Check if the queue was stopped in mac80211,
1375 * but we got called nevertheless.
1376 * That would be a mac80211 bug. */
1377 B43legacy_BUG_ON(ring->stopped);
1378 1388
1379 err = dma_tx_fragment(ring, skb); 1389 err = dma_tx_fragment(ring, skb);
1380 if (unlikely(err == -ENOKEY)) { 1390 if (unlikely(err == -ENOKEY)) {