Search Linux Wireless

[PATCH] b43: Changes to enable BCM4311 rev 02 with wireless core revision 13

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The BCM94311MCG rev 02 chip has an 802.11 core with revision 13 and
has not been supported until now. The changes include the following:

(1) Add the 802.11 rev 13 device to the ssb_device_id table to load b43.
(2) Add PHY revision 9 to the supported list.
(3) Fix 64-bit addressing errors.
(4) Remove some magic numbers in the DMA setup.

The DMA implementation for this chip supports full 64-bit addressing with
one exception. Whenever the Descriptor Ring Buffer is in high memory, a
fatal DMA error occurs. This problem was not present in 2.6.24-rc2 due
to code to "Bias the placement of kernel pages at lower PFNs". When
commit 44048d70 reverted that code, the DMA error appeared. As a "fix",
use the GFP_DMA flag when allocating the buffer for 64-bit DMA. At present,
this problem is thought to arise from a hardware error. The present driver
allocates one ring buffer for RX and six for TX; however, only one of the
TX buffers is used. To minimize any system impact associated with using low
memory, this patch removes the allocation of the unused buffers.

This patch has been tested by Cédric Caumont <icare40@xxxxxxxxxxx>.

Signed-off-by: Larry Finger <Larry.Finger@xxxxxxxxxxxx>
---

John,

This patch is intended for the everything branch of wireless-2.6.

Larry
---

 dma.c  |   86 ++++++++++++++++++++++++++++++++++-------------------------------
 main.c |    3 +-
 wa.c   |    1
 3 files changed, 49 insertions(+), 41 deletions(-)

Index: wireless-2.6/drivers/net/wireless/b43/dma.c
===================================================================
--- wireless-2.6.orig/drivers/net/wireless/b43/dma.c
+++ wireless-2.6/drivers/net/wireless/b43/dma.c
@@ -165,7 +165,7 @@ static void op64_fill_descriptor(struct 
 	addrhi = (((u64) dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK);
 	addrext = (((u64) dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK)
 	    >> SSB_DMA_TRANSLATION_SHIFT;
-	addrhi |= ssb_dma_translation(ring->dev->dev);
+	addrhi |= (ssb_dma_translation(ring->dev->dev) << 1);
 	if (slot == ring->nr_slots - 1)
 		ctl0 |= B43_DMA64_DCTL0_DTABLEEND;
 	if (start)
@@ -426,9 +426,20 @@ static inline
 static int alloc_ringmemory(struct b43_dmaring *ring)
 {
 	struct device *dev = ring->dev->dev->dev;
+	gfp_t flags = GFP_KERNEL;
 
+	/* The specs call for 4K buffers for 30- and 32-bit DMA
+	 * and 8K buffers for 64-bit DMA; however, 4K is sufficient for
+	 * the latter as long as the buffer does not cross an 8K boundary.
+	 *
+	 * For unknown reasons - possibly a hardware error - the BCM4311 rev
+	 * 02, which uses 64-bit DMA, needs the ring buffer in very low memory,
+	 * which accounts for the GFP_DMA flag below.
+	 */
+	if (ring->dma64)
+		flags = GFP_DMA;
 	ring->descbase = dma_alloc_coherent(dev, B43_DMA_RINGMEMSIZE,
-					    &(ring->dmabase), GFP_KERNEL);
+					    &(ring->dmabase), flags);
 	if (!ring->descbase) {
 		b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
 		return -ENOMEM;
@@ -483,7 +494,7 @@ int b43_dmacontroller_rx_reset(struct b4
 	return 0;
 }
 
-/* Reset the RX DMA channel */
+/* Reset the TX DMA channel */
 int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
 {
 	int i;
@@ -636,18 +647,12 @@ static int dmacontroller_setup(struct b4
 		if (ring->dma64) {
 			u64 ringbase = (u64) (ring->dmabase);
 
-			addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
-			    >> SSB_DMA_TRANSLATION_SHIFT;
-			value = B43_DMA64_TXENABLE;
-			value |= (addrext << B43_DMA64_TXADDREXT_SHIFT)
-			    & B43_DMA64_TXADDREXT_MASK;
-			b43_dma_write(ring, B43_DMA64_TXCTL, value);
+			b43_dma_write(ring, B43_DMA64_TXCTL,
+				      B43_DMA64_TXENABLE);
 			b43_dma_write(ring, B43_DMA64_TXRINGLO,
 				      (ringbase & 0xFFFFFFFF));
 			b43_dma_write(ring, B43_DMA64_TXRINGHI,
-				      ((ringbase >> 32) &
-				       ~SSB_DMA_TRANSLATION_MASK)
-				      | trans);
+				      (ringbase >> 32));
 		} else {
 			u32 ringbase = (u32) (ring->dmabase);
 
@@ -668,20 +673,15 @@ static int dmacontroller_setup(struct b4
 		if (ring->dma64) {
 			u64 ringbase = (u64) (ring->dmabase);
 
-			addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
-			    >> SSB_DMA_TRANSLATION_SHIFT;
-			value = (ring->frameoffset << B43_DMA64_RXFROFF_SHIFT);
-			value |= B43_DMA64_RXENABLE;
-			value |= (addrext << B43_DMA64_RXADDREXT_SHIFT)
-			    & B43_DMA64_RXADDREXT_MASK;
+			value = (ring->frameoffset << B43_DMA64_RXFROFF_SHIFT)
+				| B43_DMA64_RXENABLE;
 			b43_dma_write(ring, B43_DMA64_RXCTL, value);
 			b43_dma_write(ring, B43_DMA64_RXRINGLO,
 				      (ringbase & 0xFFFFFFFF));
 			b43_dma_write(ring, B43_DMA64_RXRINGHI,
-				      ((ringbase >> 32) &
-				       ~SSB_DMA_TRANSLATION_MASK)
-				      | trans);
-			b43_dma_write(ring, B43_DMA64_RXINDEX, 200);
+				      (ringbase >> 32));
+			b43_dma_write(ring, B43_DMA64_RXINDEX, ring->nr_slots *
+				      sizeof(struct b43_dmadesc64));
 		} else {
 			u32 ringbase = (u32) (ring->dmabase);
 
@@ -695,11 +695,12 @@ static int dmacontroller_setup(struct b4
 			b43_dma_write(ring, B43_DMA32_RXRING,
 				      (ringbase & ~SSB_DMA_TRANSLATION_MASK)
 				      | trans);
-			b43_dma_write(ring, B43_DMA32_RXINDEX, 200);
+			b43_dma_write(ring, B43_DMA32_RXINDEX, ring->nr_slots *
+				      sizeof(struct b43_dmadesc32));
 		}
 	}
 
-      out:
+out:
 	return err;
 }
 
@@ -954,19 +955,21 @@ int b43_dma_init(struct b43_wldev *dev)
 
 	err = -ENOMEM;
 	/* setup TX DMA channels. */
-	ring = b43_setup_dmaring(dev, 0, 1, dma64);
+	ring = b43_setup_dmaring(dev, 1, 1, dma64);
 	if (!ring)
 		goto out;
-	dma->tx_ring0 = ring;
+	dma->tx_ring1 = ring;
 
-	ring = b43_setup_dmaring(dev, 1, 1, dma64);
+	/* The driver only uses ring1 for TX - skip setup for the rest */
+#if 0
+	ring = b43_setup_dmaring(dev, 0, 1, dma64);
 	if (!ring)
-		goto err_destroy_tx0;
-	dma->tx_ring1 = ring;
+		goto err_destroy_tx1;
+	dma->tx_ring0 = ring;
 
 	ring = b43_setup_dmaring(dev, 2, 1, dma64);
 	if (!ring)
-		goto err_destroy_tx1;
+		goto err_destroy_tx0;
 	dma->tx_ring2 = ring;
 
 	ring = b43_setup_dmaring(dev, 3, 1, dma64);
@@ -983,6 +986,7 @@ int b43_dma_init(struct b43_wldev *dev)
 	if (!ring)
 		goto err_destroy_tx4;
 	dma->tx_ring5 = ring;
+#endif
 
 	/* setup RX DMA channels. */
 	ring = b43_setup_dmaring(dev, 0, 0, dma64);
@@ -1001,30 +1005,32 @@ int b43_dma_init(struct b43_wldev *dev)
 	       (dmamask == DMA_64BIT_MASK) ? 64 :
 	       (dmamask == DMA_32BIT_MASK) ? 32 : 30);
 	err = 0;
-      out:
+out:
 	return err;
 
-      err_destroy_rx0:
+err_destroy_rx0:
 	b43_destroy_dmaring(dma->rx_ring0);
 	dma->rx_ring0 = NULL;
-      err_destroy_tx5:
+err_destroy_tx5:
+#if 0
 	b43_destroy_dmaring(dma->tx_ring5);
 	dma->tx_ring5 = NULL;
-      err_destroy_tx4:
+err_destroy_tx4:
 	b43_destroy_dmaring(dma->tx_ring4);
 	dma->tx_ring4 = NULL;
-      err_destroy_tx3:
+err_destroy_tx3:
 	b43_destroy_dmaring(dma->tx_ring3);
 	dma->tx_ring3 = NULL;
-      err_destroy_tx2:
+err_destroy_tx2:
 	b43_destroy_dmaring(dma->tx_ring2);
 	dma->tx_ring2 = NULL;
-      err_destroy_tx1:
-	b43_destroy_dmaring(dma->tx_ring1);
-	dma->tx_ring1 = NULL;
-      err_destroy_tx0:
+err_destroy_tx0:
 	b43_destroy_dmaring(dma->tx_ring0);
 	dma->tx_ring0 = NULL;
+err_destroy_tx1:
+#endif
+	b43_destroy_dmaring(dma->tx_ring1);
+	dma->tx_ring1 = NULL;
 	goto out;
 }
 
Index: wireless-2.6/drivers/net/wireless/b43/main.c
===================================================================
--- wireless-2.6.orig/drivers/net/wireless/b43/main.c
+++ wireless-2.6/drivers/net/wireless/b43/main.c
@@ -93,6 +93,7 @@ static const struct ssb_device_id b43_ss
 	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 7),
 	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 9),
 	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 10),
+	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 13),
 	SSB_DEVTABLE_END
 };
 
@@ -3064,7 +3065,7 @@ static int b43_phy_versioning(struct b43
 			unsupported = 1;
 		break;
 	case B43_PHYTYPE_G:
-		if (phy_rev > 8)
+		if (phy_rev > 9)
 			unsupported = 1;
 		break;
 	default:
Index: wireless-2.6/drivers/net/wireless/b43/wa.c
===================================================================
--- wireless-2.6.orig/drivers/net/wireless/b43/wa.c
+++ wireless-2.6/drivers/net/wireless/b43/wa.c
@@ -642,6 +642,7 @@ void b43_wa_all(struct b43_wldev *dev)
 		case 6:
 		case 7:
 		case 8:
+		case 9:
 			b43_wa_tr_ltov(dev);
 			b43_wa_crs_ed(dev);
 			b43_wa_rssi_lt(dev);
-
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux