From c1be5152860218dffea6a47cff5ea31a56c6cff5 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sat, 1 Aug 2009 22:32:48 -0500 Subject: 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 Signed-off-by: John W. Linville --- drivers/net/wireless/b43legacy/dma.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/b43legacy') diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c index 2f90fb9f536..86640341581 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, ring = priority_to_txring(dev, skb_get_queue_mapping(skb)); spin_lock_irqsave(&ring->lock, flags); B43legacy_WARN_ON(!ring->tx); - if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) { - b43legacywarn(dev->wl, "DMA queue overflow\n"); + + if (unlikely(ring->stopped)) { + /* We get here only because of a bug in mac80211. + * Because of a race, one packet may be queued after + * the queue is stopped, thus we got called when we shouldn't. + * For now, just refuse the transmit. */ + if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE)) + b43legacyerr(dev->wl, "Packet after queue stopped\n"); + err = -ENOSPC; + goto out_unlock; + } + + if (unlikely(WARN_ON(free_slots(ring) < SLOTS_PER_PACKET))) { + /* If we get here, we have a real error with the queue + * full, but queues not stopped. */ + b43legacyerr(dev->wl, "DMA queue overflow\n"); err = -ENOSPC; goto out_unlock; } - /* Check if the queue was stopped in mac80211, - * but we got called nevertheless. - * That would be a mac80211 bug. */ - B43legacy_BUG_ON(ring->stopped); err = dma_tx_fragment(ring, skb); if (unlikely(err == -ENOKEY)) { -- cgit v1.2.3-70-g09d2