Browse Source

mac80211: b43: Handle DMA RX descriptor underrun

SVN-Revision: 36474
Hauke Mehrtens 12 years ago
parent
commit
c807a7737f

+ 145 - 0
package/mac80211/patches/840-b43-Handle-DMA-RX-descriptor-underrun.patch

@@ -0,0 +1,145 @@
+From 5921f167baf30255ebc079c6e751a7ed31cd986d Mon Sep 17 00:00:00 2001
+From: Thommy Jakobsson <[email protected]>
+Date: Tue, 23 Apr 2013 21:45:11 +0200
+Subject: [PATCH 2/3] B43: Handle DMA RX descriptor underrun
+
+Add handling of rx descriptor underflow. This fixes a fault that could
+happen on slow machines, where data is received faster than the CPU can
+handle. In such a case the device will use up all rx descriptors and
+refuse to send any more data before confirming that it is ok. This
+patch enables necessary interrupt to discover such a situation and will
+handle them by dropping everything in the ring buffer.
+
+Reviewed-by: Michael Buesch <[email protected]>
+Signed-off-by: Thommy Jakobsson <[email protected]>
+Cc: stable <[email protected]>
+---
+ drivers/net/wireless/b43/dma.c  |   19 +++++++++++++++++
+ drivers/net/wireless/b43/dma.h  |    4 +++-
+ drivers/net/wireless/b43/main.c |   43 ++++++++++++++++-----------------------
+ 3 files changed, 40 insertions(+), 26 deletions(-)
+
+--- a/drivers/net/wireless/b43/dma.c
++++ b/drivers/net/wireless/b43/dma.c
+@@ -1733,6 +1733,25 @@ drop_recycle_buffer:
+ 	sync_descbuffer_for_device(ring, dmaaddr, ring->rx_buffersize);
+ }
+ 
++void b43_dma_handle_rx_overflow(struct b43_dmaring *ring)
++{
++	int current_slot, previous_slot;
++
++	B43_WARN_ON(ring->tx);
++
++	/* Device has filled all buffers, drop all packets and let TCP
++	 * decrease speed.
++	 * Decrement RX index by one will let the device to see all slots
++	 * as free again
++	 */
++	/*
++	*TODO: How to increase rx_drop in mac80211?
++	*/
++	current_slot = ring->ops->get_current_rxslot(ring);
++	previous_slot = prev_slot(ring, current_slot);
++	ring->ops->set_current_rxslot(ring, previous_slot);
++}
++
+ void b43_dma_rx(struct b43_dmaring *ring)
+ {
+ 	const struct b43_dma_ops *ops = ring->ops;
+--- a/drivers/net/wireless/b43/dma.h
++++ b/drivers/net/wireless/b43/dma.h
+@@ -9,7 +9,7 @@
+ /* DMA-Interrupt reasons. */
+ #define B43_DMAIRQ_FATALMASK	((1 << 10) | (1 << 11) | (1 << 12) \
+ 					 | (1 << 14) | (1 << 15))
+-#define B43_DMAIRQ_NONFATALMASK	(1 << 13)
++#define B43_DMAIRQ_RDESC_UFLOW		(1 << 13)
+ #define B43_DMAIRQ_RX_DONE		(1 << 16)
+ 
+ /*** 32-bit DMA Engine. ***/
+@@ -295,6 +295,8 @@ int b43_dma_tx(struct b43_wldev *dev,
+ void b43_dma_handle_txstatus(struct b43_wldev *dev,
+ 			     const struct b43_txstatus *status);
+ 
++void b43_dma_handle_rx_overflow(struct b43_dmaring *ring);
++
+ void b43_dma_rx(struct b43_dmaring *ring);
+ 
+ void b43_dma_direct_fifo_rx(struct b43_wldev *dev,
+--- a/drivers/net/wireless/b43/main.c
++++ b/drivers/net/wireless/b43/main.c
+@@ -1907,32 +1907,20 @@ static void b43_do_interrupt_thread(stru
+ 		}
+ 	}
+ 
+-	if (unlikely(merged_dma_reason & (B43_DMAIRQ_FATALMASK |
+-					  B43_DMAIRQ_NONFATALMASK))) {
+-		if (merged_dma_reason & B43_DMAIRQ_FATALMASK) {
+-			b43err(dev->wl, "Fatal DMA error: "
+-			       "0x%08X, 0x%08X, 0x%08X, "
+-			       "0x%08X, 0x%08X, 0x%08X\n",
+-			       dma_reason[0], dma_reason[1],
+-			       dma_reason[2], dma_reason[3],
+-			       dma_reason[4], dma_reason[5]);
++	if (unlikely(merged_dma_reason & (B43_DMAIRQ_FATALMASK))) {
++		b43err(dev->wl,
++			"Fatal DMA error: 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X\n",
++			dma_reason[0], dma_reason[1],
++			dma_reason[2], dma_reason[3],
++			dma_reason[4], dma_reason[5]);
+ #ifdef CONFIG_B43_PIO
+-			b43err(dev->wl, "This device does not support DMA "
++		b43err(dev->wl, "This device does not support DMA "
+ 			       "on your system. It will now be switched to PIO.\n");
+-			/* Fall back to PIO transfers if we get fatal DMA errors! */
+-			dev->use_pio = true;
++		/* Fall back to PIO transfers if we get fatal DMA errors! */
++		dev->use_pio = true;
+ #endif
+-			b43_controller_restart(dev, "DMA error");
+-			return;
+-		}
+-		if (merged_dma_reason & B43_DMAIRQ_NONFATALMASK) {
+-			b43err(dev->wl, "DMA error: "
+-			       "0x%08X, 0x%08X, 0x%08X, "
+-			       "0x%08X, 0x%08X, 0x%08X\n",
+-			       dma_reason[0], dma_reason[1],
+-			       dma_reason[2], dma_reason[3],
+-			       dma_reason[4], dma_reason[5]);
+-		}
++		b43_controller_restart(dev, "DMA error");
++		return;
+ 	}
+ 
+ 	if (unlikely(reason & B43_IRQ_UCODE_DEBUG))
+@@ -1951,6 +1939,11 @@ static void b43_do_interrupt_thread(stru
+ 		handle_irq_noise(dev);
+ 
+ 	/* Check the DMA reason registers for received data. */
++	if (dma_reason[0] & B43_DMAIRQ_RDESC_UFLOW) {
++		if (B43_DEBUG)
++			b43warn(dev->wl, "RX descriptor underrun\n");
++		b43_dma_handle_rx_overflow(dev->dma.rx_ring);
++	}
+ 	if (dma_reason[0] & B43_DMAIRQ_RX_DONE) {
+ 		if (b43_using_pio_transfers(dev))
+ 			b43_pio_rx(dev->pio.rx_queue);
+@@ -2008,7 +2001,7 @@ static irqreturn_t b43_do_interrupt(stru
+ 		return IRQ_NONE;
+ 
+ 	dev->dma_reason[0] = b43_read32(dev, B43_MMIO_DMA0_REASON)
+-	    & 0x0001DC00;
++	    & 0x0001FC00;
+ 	dev->dma_reason[1] = b43_read32(dev, B43_MMIO_DMA1_REASON)
+ 	    & 0x0000DC00;
+ 	dev->dma_reason[2] = b43_read32(dev, B43_MMIO_DMA2_REASON)
+@@ -3137,7 +3130,7 @@ static int b43_chip_init(struct b43_wlde
+ 		b43_write32(dev, 0x018C, 0x02000000);
+ 	}
+ 	b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, 0x00004000);
+-	b43_write32(dev, B43_MMIO_DMA0_IRQ_MASK, 0x0001DC00);
++	b43_write32(dev, B43_MMIO_DMA0_IRQ_MASK, 0x0001FC00);
+ 	b43_write32(dev, B43_MMIO_DMA1_IRQ_MASK, 0x0000DC00);
+ 	b43_write32(dev, B43_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
+ 	b43_write32(dev, B43_MMIO_DMA3_IRQ_MASK, 0x0001DC00);

+ 11 - 0
package/mac80211/patches/841-b43-reduce-number-of-RX-slots.patch

@@ -0,0 +1,11 @@
+--- a/drivers/net/wireless/b43/dma.h
++++ b/drivers/net/wireless/b43/dma.h
+@@ -169,7 +169,7 @@ struct b43_dmadesc_generic {
+ 
+ /* DMA engine tuning knobs */
+ #define B43_TXRING_SLOTS		256
+-#define B43_RXRING_SLOTS		256
++#define B43_RXRING_SLOTS		32
+ #define B43_DMA0_RX_FW598_BUFSIZE	(B43_DMA0_RX_FW598_FO + IEEE80211_MAX_FRAME_LEN)
+ #define B43_DMA0_RX_FW351_BUFSIZE	(B43_DMA0_RX_FW351_FO + IEEE80211_MAX_FRAME_LEN)
+