diff options
author | Jesse Keating <jkeating@redhat.com> | 2010-07-29 17:18:45 -0700 |
---|---|---|
committer | Jesse Keating <jkeating@redhat.com> | 2010-07-29 17:18:45 -0700 |
commit | 2f82dda4a9bf41e64e864889bf06564bdf826e25 (patch) | |
tree | 118a7b483ae5de4dbf83d20001302f1404866ef0 /linux-2.6-b43_-Rewrite-DMA-Tx-status-handling-sanity-checks.patch | |
parent | 64ba2e5ffde5f2418eb26c700cb0ab62b04e5013 (diff) | |
download | dom0-kernel-2f82dda4a9bf41e64e864889bf06564bdf826e25.tar.gz dom0-kernel-2f82dda4a9bf41e64e864889bf06564bdf826e25.tar.xz dom0-kernel-2f82dda4a9bf41e64e864889bf06564bdf826e25.zip |
initial srpm import
Diffstat (limited to 'linux-2.6-b43_-Rewrite-DMA-Tx-status-handling-sanity-checks.patch')
-rw-r--r-- | linux-2.6-b43_-Rewrite-DMA-Tx-status-handling-sanity-checks.patch | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/linux-2.6-b43_-Rewrite-DMA-Tx-status-handling-sanity-checks.patch b/linux-2.6-b43_-Rewrite-DMA-Tx-status-handling-sanity-checks.patch new file mode 100644 index 0000000..441213c --- /dev/null +++ b/linux-2.6-b43_-Rewrite-DMA-Tx-status-handling-sanity-checks.patch @@ -0,0 +1,182 @@ +Back-port of the following upstream commit... + +commit 07681e211d736ba2394ab7f29f77e93adecd22c5 +Author: Michael Buesch <mb@bu3sch.de> +Date: Thu Nov 19 22:24:29 2009 +0100 + + b43: Rewrite DMA Tx status handling sanity checks + + This rewrites the error handling policies in the TX status handler. + It tries to be error-tolerant as in "try hard to not crash the machine". + It won't recover from errors (that are bugs in the firmware or driver), + because that's impossible. However, it will return a more or less useful + error message and bail out. It also tries hard to use rate-limited messages + to not flood the syslog in case of a failure. + + Signed-off-by: Michael Buesch <mb@bu3sch.de> + Signed-off-by: John W. Linville <linville@tuxdriver.com> + +diff -up linux-2.6.32.noarch/drivers/net/wireless/b43/dma.c.orig linux-2.6.32.noarch/drivers/net/wireless/b43/dma.c +--- linux-2.6.32.noarch/drivers/net/wireless/b43/dma.c.orig 2009-12-02 22:51:21.000000000 -0500 ++++ linux-2.6.32.noarch/drivers/net/wireless/b43/dma.c 2010-03-17 14:02:28.000000000 -0400 +@@ -770,7 +770,7 @@ static void free_all_descbuffers(struct + for (i = 0; i < ring->nr_slots; i++) { + desc = ring->ops->idx2desc(ring, i, &meta); + +- if (!meta->skb) { ++ if (!meta->skb || b43_dma_ptr_is_poisoned(meta->skb)) { + B43_WARN_ON(!ring->tx); + continue; + } +@@ -822,7 +822,7 @@ struct b43_dmaring *b43_setup_dmaring(st + enum b43_dmatype type) + { + struct b43_dmaring *ring; +- int err; ++ int i, err; + dma_addr_t dma_test; + + ring = kzalloc(sizeof(*ring), GFP_KERNEL); +@@ -837,6 +837,8 @@ struct b43_dmaring *b43_setup_dmaring(st + GFP_KERNEL); + if (!ring->meta) + goto err_kfree_ring; ++ for (i = 0; i < ring->nr_slots; i++) ++ ring->meta->skb = B43_DMA_PTR_POISON; + + ring->type = type; + ring->dev = dev; +@@ -1147,11 +1149,13 @@ struct b43_dmaring *parse_cookie(struct + case 0x5000: + ring = dma->tx_ring_mcast; + break; +- default: +- B43_WARN_ON(1); + } + *slot = (cookie & 0x0FFF); +- B43_WARN_ON(!(ring && *slot >= 0 && *slot < ring->nr_slots)); ++ if (unlikely(!ring || *slot < 0 || *slot >= ring->nr_slots)) { ++ b43dbg(dev->wl, "TX-status contains " ++ "invalid cookie: 0x%04X\n", cookie); ++ return NULL; ++ } + + return ring; + } +@@ -1400,19 +1404,40 @@ void b43_dma_handle_txstatus(struct b43_ + struct b43_dmaring *ring; + struct b43_dmadesc_generic *desc; + struct b43_dmadesc_meta *meta; +- int slot; ++ int slot, firstused; + bool frame_succeed; + + ring = parse_cookie(dev, status->cookie, &slot); + if (unlikely(!ring)) + return; +- + B43_WARN_ON(!ring->tx); ++ ++ /* Sanity check: TX packets are processed in-order on one ring. ++ * Check if the slot deduced from the cookie really is the first ++ * used slot. */ ++ firstused = ring->current_slot - ring->used_slots + 1; ++ if (firstused < 0) ++ firstused = ring->nr_slots + firstused; ++ if (unlikely(slot != firstused)) { ++ /* This possibly is a firmware bug and will result in ++ * malfunction, memory leaks and/or stall of DMA functionality. */ ++ b43dbg(dev->wl, "Out of order TX status report on DMA ring %d. " ++ "Expected %d, but got %d\n", ++ ring->index, firstused, slot); ++ return; ++ } ++ + ops = ring->ops; + while (1) { +- B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); ++ B43_WARN_ON(slot < 0 || slot >= ring->nr_slots); + desc = ops->idx2desc(ring, slot, &meta); + ++ if (b43_dma_ptr_is_poisoned(meta->skb)) { ++ b43dbg(dev->wl, "Poisoned TX slot %d (first=%d) " ++ "on ring %d\n", ++ slot, firstused, ring->index); ++ break; ++ } + if (meta->skb) + unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, + 1); +@@ -1423,7 +1448,14 @@ void b43_dma_handle_txstatus(struct b43_ + if (meta->is_last_fragment) { + struct ieee80211_tx_info *info; + +- BUG_ON(!meta->skb); ++ if (unlikely(!meta->skb)) { ++ /* This is a scatter-gather fragment of a frame, so ++ * the skb pointer must not be NULL. */ ++ b43dbg(dev->wl, "TX status unexpected NULL skb " ++ "at slot %d (first=%d) on ring %d\n", ++ slot, firstused, ring->index); ++ break; ++ } + + info = IEEE80211_SKB_CB(meta->skb); + +@@ -1441,20 +1473,29 @@ void b43_dma_handle_txstatus(struct b43_ + #endif /* DEBUG */ + ieee80211_tx_status(dev->wl->hw, meta->skb); + +- /* skb is freed by ieee80211_tx_status() */ +- meta->skb = NULL; ++ /* skb will be freed by ieee80211_tx_status(). ++ * Poison our pointer. */ ++ meta->skb = B43_DMA_PTR_POISON; + } else { + /* No need to call free_descriptor_buffer here, as + * this is only the txhdr, which is not allocated. + */ +- B43_WARN_ON(meta->skb); ++ if (unlikely(meta->skb)) { ++ b43dbg(dev->wl, "TX status unexpected non-NULL skb " ++ "at slot %d (first=%d) on ring %d\n", ++ slot, firstused, ring->index); ++ break; ++ } + } + + /* Everything unmapped and free'd. So it's not used anymore. */ + ring->used_slots--; + +- if (meta->is_last_fragment) ++ if (meta->is_last_fragment) { ++ /* This is the last scatter-gather ++ * fragment of the frame. We are done. */ + break; ++ } + slot = next_slot(ring, slot); + } + if (ring->stopped) { +diff -up linux-2.6.32.noarch/drivers/net/wireless/b43/dma.h.orig linux-2.6.32.noarch/drivers/net/wireless/b43/dma.h +--- linux-2.6.32.noarch/drivers/net/wireless/b43/dma.h.orig 2009-12-02 22:51:21.000000000 -0500 ++++ linux-2.6.32.noarch/drivers/net/wireless/b43/dma.h 2010-03-17 13:57:57.000000000 -0400 +@@ -1,7 +1,7 @@ + #ifndef B43_DMA_H_ + #define B43_DMA_H_ + +-#include <linux/ieee80211.h> ++#include <linux/err.h> + + #include "b43.h" + +@@ -165,6 +165,10 @@ struct b43_dmadesc_generic { + #define B43_RXRING_SLOTS 64 + #define B43_DMA0_RX_BUFFERSIZE IEEE80211_MAX_FRAME_LEN + ++/* Pointer poison */ ++#define B43_DMA_PTR_POISON ((void *)ERR_PTR(-ENOMEM)) ++#define b43_dma_ptr_is_poisoned(ptr) (unlikely((ptr) == B43_DMA_PTR_POISON)) ++ + + struct sk_buff; + struct b43_private; |