[PATCH] Fix alignment issues with DMA TX on BCM4331

David Woodhouse dwmw2 at infradead.org
Fri Aug 12 06:27:43 EDT 2011


When the TX descriptor ring is not aligned to 8KiB on BCM4331, we have
to write the full address to the TXINDEX register or the DMA engine gets
confused after the first time we wrap round to slot zero.

[ 7438.538945] Poked TX with address fe0 for slot 254
[ 7438.539077] Acking gen reason 20000000
[ 7438.539177] irq xmitstat 20fc1001 0000007f
[ 7438.607861] Poked TX with address 0 for slot 0
[ 7438.608567] Acking gen reason 20000000
[ 7438.608668] irq xmitstat 20fe1001 00000080
[ 7438.608709] irq xmitstat 20000011 00000080
[ 7438.608724] b43-phy2 debug: Out of order TX status report on DMA ring 1. Expected 256, but got 0
[ 7438.608739] irq xmitstat 20020011 00000080
[ 7438.608750] b43-phy2 debug: Out of order TX status report on DMA ring 1. Expected 256, but got 2
[ 7438.608765] irq xmitstat 20040011 00000080

We write 0xff0 to the TXADDRLO register to see if the DMA engine is
capable of unaligned operation. If it *is*, then it'll have this problem
and we have to write the full address to TXINDEX. Comments in brcmsmac
indicate that the low 13 bits are required.

If we're doing this, we *also* have to write to TXCTL to enable the DMA
engine *after* setting up the ring address.

Signed-off-by: David Woodhouse <David.Woodhouse at intel.com>
--
I've made that change to the initialisation order of TXCTL vs.
TXADDR{HI,LO} unconditional; is there a reason not to?

diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index 82168f8..92dd6d9 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -225,8 +225,10 @@ static void op64_fill_descriptor(struct b43_dmaring *ring,
 
 static void op64_poke_tx(struct b43_dmaring *ring, int slot)
 {
-	b43_dma_write(ring, B43_DMA64_TXINDEX,
-		      (u32) (slot * sizeof(struct b43_dmadesc64)));
+	u32 indexval = slot * sizeof(struct b43_dmadesc64);
+	if (ring->unaligned)
+		indexval |= (u32)ring->dmabase;
+	b43_dma_write(ring, B43_DMA64_TXINDEX, indexval);
 }
 
 static void op64_tx_suspend(struct b43_dmaring *ring)
@@ -704,9 +710,14 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
 			    & B43_DMA64_TXADDREXT_MASK;
 			if (!parity)
 				value |= B43_DMA64_TXPARITYDISABLE;
-			b43_dma_write(ring, B43_DMA64_TXCTL, value);
+
+			b43_dma_write(ring, B43_DMA64_TXRINGLO, 0xff0);
+			if (b43_dma_read(ring, B43_DMA64_TXRINGLO))
+				ring->unaligned = 1;
+
 			b43_dma_write(ring, B43_DMA64_TXRINGLO, addrlo);
 			b43_dma_write(ring, B43_DMA64_TXRINGHI, addrhi);
+			b43_dma_write(ring, B43_DMA64_TXCTL, value);
 		} else {
 			u32 ringbase = (u32) (ring->dmabase);
 			addrext = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_EXT);
diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h
index 7e20b04f..16dc565 100644
--- a/drivers/net/wireless/b43/dma.h
+++ b/drivers/net/wireless/b43/dma.h
@@ -251,6 +251,8 @@ struct b43_dmaring {
 	int index;
 	/* Boolean. Is this a TX ring? */
 	bool tx;
+	/* Boolean. Is this ring capable of 16-byte alignment? */
+	bool unaligned;
 	/* The type of DMA engine used. */
 	enum b43_dmatype type;
 	/* Boolean. Is this ring stopped at ieee80211 level? */

-- 
David Woodhouse                            Open Source Technology Centre
David.Woodhouse at intel.com                              Intel Corporation




More information about the b43-dev mailing list