BCM4312 / b43 DMA transmission sequence errors

ISE Development isedev at gmail.com
Thu Mar 14 09:08:33 EDT 2013


On Wednesday 13 Mar 2013 21:37:52 Larry Finger wrote:
> On 03/13/2013 08:06 PM, ISE Development wrote:
> 
> >
> > I've hacked the driver to 'skip' one header and data frame if receiving an interrupt for the first slot + 2. It's not pretty and I have literally no idea if it will causes other problems, but it has allowed me to keep the Wifi connection up for a little over 3 hours now (as compared to the 45 seconds previously). It does not appear to be corrupting the data stream (checked by download large signed binaries and verifying the signature) and as far as my limited knowledge can tell, it should not be causing a memory leak.
> >
> > The patch is listed below, for reference. However, I do not claim that it is valid, safe or even reasonsable. It does provide me with much needed relief though.
> >
> > The diff is against the current head of linville/wireless-testing.git (d41d9c7419e3ac9c81841f43bbd7639dd0a5819e).
> >
> 
> I am testing the patch on BCM4312 and other cards.
> 
> Larry
> 

Here's a slighted cleaner version, with comments, in case you are considering integrating it.

diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index 38bc5a7..edc759d 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -1489,6 +1489,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
        struct b43_dmadesc_meta *meta;
        int slot, firstused;
        bool frame_succeed;
+       int skip;
 
        ring = parse_cookie(dev, status->cookie, &slot);
        if (unlikely(!ring))
@@ -1501,13 +1502,22 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
        firstused = ring->current_slot - ring->used_slots + 1;
        if (firstused < 0)
                firstused = ring->nr_slots + firstused;
+
+       skip = 0;
        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;
+               if(slot == firstused + 2) {
+                       /* If a single header/data pair was missed, skip over the first
+                        * two slots in an attempt to recover. */
+                       slot = firstused;
+                       skip = 2;
+               } else {
+                       return;
+               }
        }
 
        ops = ring->ops;
@@ -1522,6 +1532,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
                               slot, firstused, ring->index);
                        break;
                }
+
                if (meta->skb) {
                        struct b43_private_tx_info *priv_info =
                                b43_get_priv_tx_info(IEEE80211_SKB_CB(meta->skb));
@@ -1552,7 +1563,18 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
                         * Call back to inform the ieee80211 subsystem about
                         * the status of the transmission.
                         */
-                       frame_succeed = b43_fill_txstatus_report(dev, info, status);
+                       if(!skip)
+                       {
+                               frame_succeed = b43_fill_txstatus_report(dev, info, status);
+                       }
+                       else
+                       {
+                           /* When skipping over a missed TX status report, use a status
+                            * structure which indicates that the frame was not sent
+                            * (frame_count 0) and not acknowledged */
+                               struct b43_txstatus fake = B43_FAKE_TXSTATUS;
+                               frame_succeed = b43_fill_txstatus_report(dev, info, &fake);
+                       }
 #ifdef CONFIG_B43_DEBUG
                        if (frame_succeed)
                                ring->nr_succeed_tx_packets++;
@@ -1580,12 +1602,14 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
                /* Everything unmapped and free'd. So it's not used anymore. */
                ring->used_slots--;
 
-               if (meta->is_last_fragment) {
+               if (meta->is_last_fragment && !skip) {
                        /* This is the last scatter-gather
                         * fragment of the frame. We are done. */
                        break;
                }
                slot = next_slot(ring, slot);
+               if(skip > 0)
+                       --skip;
        }
        if (ring->stopped) {
                B43_WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME);
diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h
index 98d9074..eae730c 100644
--- a/drivers/net/wireless/b43/xmit.h
+++ b/drivers/net/wireless/b43/xmit.h
@@ -218,6 +218,9 @@ struct b43_txstatus {
        u8 acked;               /* Wireless ACK received */
 };
 
+/* This needs to match the b43_txstatus structure above, all zeroed-out */
+#define B43_FAKE_TXSTATUS { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+
 /* txstatus supp_reason values */
 enum {
        B43_TXST_SUPP_NONE,     /* Not suppressed */


-- 
-- isedev



More information about the b43-dev mailing list