All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH V3 3.2 2/2] b43: fix DMA on some bugged hardware
@ 2011-08-14 18:16 ` Rafał Miłecki
  0 siblings, 0 replies; 6+ messages in thread
From: Rafał Miłecki @ 2011-08-14 18:16 UTC (permalink / raw)
  To: linux-wireless, John W. Linville; +Cc: b43-dev, Rafał Miłecki

Some hardware with 64-bit DMA uses lower address word for setting
routing (translation) bit. Add workaround for such boards.

Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
---
V2: use (u64) to fix compilation on 32-bit systems
V3: use ready macro instead of own shifting/masking upper/lower 32 bits

Larry: could you give it a try?

John: we gave it a chance, I failed. Please take it for 3.2, don't
want to risk more problems.
---
 drivers/net/wireless/b43/b43.h |    1 +
 drivers/net/wireless/b43/dma.c |  113 +++++++++++++++++++++++++++-------------
 drivers/net/wireless/b43/dma.h |    6 ++
 3 files changed, 84 insertions(+), 36 deletions(-)

diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index c818b0b..3aee322 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -594,6 +594,7 @@ struct b43_dma {
 	struct b43_dmaring *rx_ring;
 
 	u32 translation; /* Routing bits */
+	bool translation_in_low; /* Should translation bit go into low addr? */
 	bool parity; /* Check for parity */
 };
 
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index 481e534..c3f856b 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -47,6 +47,38 @@
  * into separate slots. */
 #define TX_SLOTS_PER_FRAME	2
 
+static u32 b43_dma_address(struct b43_dma *dma, dma_addr_t dmaaddr,
+			   enum b43_addrtype addrtype)
+{
+	u32 uninitialized_var(addr);
+
+	switch (addrtype) {
+	case B43_DMA_ADDR_LOW:
+		addr = lower_32_bits(dmaaddr);
+		if (dma->translation_in_low) {
+			addr &= ~SSB_DMA_TRANSLATION_MASK;
+			addr |= dma->translation;
+		}
+		break;
+	case B43_DMA_ADDR_HIGH:
+		addr = upper_32_bits(dmaaddr);
+		if (!dma->translation_in_low) {
+			addr &= ~SSB_DMA_TRANSLATION_MASK;
+			addr |= dma->translation;
+		}
+		break;
+	case B43_DMA_ADDR_EXT:
+		if (dma->translation_in_low)
+			addr = lower_32_bits(dmaaddr);
+		else
+			addr = upper_32_bits(dmaaddr);
+		addr &= SSB_DMA_TRANSLATION_MASK;
+		addr >>= SSB_DMA_TRANSLATION_SHIFT;
+		break;
+	}
+
+	return addr;
+}
 
 /* 32bit DMA ops. */
 static
@@ -77,10 +109,9 @@ static void op32_fill_descriptor(struct b43_dmaring *ring,
 	slot = (int)(&(desc->dma32) - descbase);
 	B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
 
-	addr = (u32) (dmaaddr & ~SSB_DMA_TRANSLATION_MASK);
-	addrext = (u32) (dmaaddr & SSB_DMA_TRANSLATION_MASK)
-	    >> SSB_DMA_TRANSLATION_SHIFT;
-	addr |= ring->dev->dma.translation;
+	addr = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_LOW);
+	addrext = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_EXT);
+
 	ctl = bufsize & B43_DMA32_DCTL_BYTECNT;
 	if (slot == ring->nr_slots - 1)
 		ctl |= B43_DMA32_DCTL_DTABLEEND;
@@ -170,11 +201,10 @@ static void op64_fill_descriptor(struct b43_dmaring *ring,
 	slot = (int)(&(desc->dma64) - descbase);
 	B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
 
-	addrlo = (u32) (dmaaddr & 0xFFFFFFFF);
-	addrhi = (((u64) dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK);
-	addrext = (((u64) dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK)
-	    >> SSB_DMA_TRANSLATION_SHIFT;
-	addrhi |= ring->dev->dma.translation;
+	addrlo = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_LOW);
+	addrhi = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_HIGH);
+	addrext = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_EXT);
+
 	if (slot == ring->nr_slots - 1)
 		ctl0 |= B43_DMA64_DCTL0_DTABLEEND;
 	if (start)
@@ -658,41 +688,37 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
 	int err = 0;
 	u32 value;
 	u32 addrext;
-	u32 trans = ring->dev->dma.translation;
 	bool parity = ring->dev->dma.parity;
+	u32 addrlo;
+	u32 addrhi;
 
 	if (ring->tx) {
 		if (ring->type == B43_DMA_64BIT) {
 			u64 ringbase = (u64) (ring->dmabase);
+			addrext = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_EXT);
+			addrlo = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_LOW);
+			addrhi = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_HIGH);
 
-			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;
 			if (!parity)
 				value |= B43_DMA64_TXPARITYDISABLE;
 			b43_dma_write(ring, B43_DMA64_TXCTL, value);
-			b43_dma_write(ring, B43_DMA64_TXRINGLO,
-				      (ringbase & 0xFFFFFFFF));
-			b43_dma_write(ring, B43_DMA64_TXRINGHI,
-				      ((ringbase >> 32) &
-				       ~SSB_DMA_TRANSLATION_MASK)
-				      | trans);
+			b43_dma_write(ring, B43_DMA64_TXRINGLO, addrlo);
+			b43_dma_write(ring, B43_DMA64_TXRINGHI, addrhi);
 		} else {
 			u32 ringbase = (u32) (ring->dmabase);
+			addrext = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_EXT);
+			addrlo = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_LOW);
 
-			addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
-			    >> SSB_DMA_TRANSLATION_SHIFT;
 			value = B43_DMA32_TXENABLE;
 			value |= (addrext << B43_DMA32_TXADDREXT_SHIFT)
 			    & B43_DMA32_TXADDREXT_MASK;
 			if (!parity)
 				value |= B43_DMA32_TXPARITYDISABLE;
 			b43_dma_write(ring, B43_DMA32_TXCTL, value);
-			b43_dma_write(ring, B43_DMA32_TXRING,
-				      (ringbase & ~SSB_DMA_TRANSLATION_MASK)
-				      | trans);
+			b43_dma_write(ring, B43_DMA32_TXRING, addrlo);
 		}
 	} else {
 		err = alloc_initial_descbuffers(ring);
@@ -700,9 +726,10 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
 			goto out;
 		if (ring->type == B43_DMA_64BIT) {
 			u64 ringbase = (u64) (ring->dmabase);
+			addrext = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_EXT);
+			addrlo = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_LOW);
+			addrhi = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_HIGH);
 
-			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)
@@ -710,19 +737,15 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
 			if (!parity)
 				value |= B43_DMA64_RXPARITYDISABLE;
 			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_RXRINGLO, addrlo);
+			b43_dma_write(ring, B43_DMA64_RXRINGHI, addrhi);
 			b43_dma_write(ring, B43_DMA64_RXINDEX, ring->nr_slots *
 				      sizeof(struct b43_dmadesc64));
 		} else {
 			u32 ringbase = (u32) (ring->dmabase);
+			addrext = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_EXT);
+			addrlo = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_LOW);
 
-			addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
-			    >> SSB_DMA_TRANSLATION_SHIFT;
 			value = (ring->frameoffset << B43_DMA32_RXFROFF_SHIFT);
 			value |= B43_DMA32_RXENABLE;
 			value |= (addrext << B43_DMA32_RXADDREXT_SHIFT)
@@ -730,9 +753,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
 			if (!parity)
 				value |= B43_DMA32_RXPARITYDISABLE;
 			b43_dma_write(ring, B43_DMA32_RXCTL, value);
-			b43_dma_write(ring, B43_DMA32_RXRING,
-				      (ringbase & ~SSB_DMA_TRANSLATION_MASK)
-				      | trans);
+			b43_dma_write(ring, B43_DMA32_RXRING, addrlo);
 			b43_dma_write(ring, B43_DMA32_RXINDEX, ring->nr_slots *
 				      sizeof(struct b43_dmadesc32));
 		}
@@ -1066,6 +1087,25 @@ static int b43_dma_set_mask(struct b43_wldev *dev, u64 mask)
 	return 0;
 }
 
+/* Some hardware with 64-bit DMA seems to be bugged and looks for translation
+ * bit in low address word instead of high one.
+ */
+static bool b43_dma_translation_in_low_word(struct b43_wldev *dev,
+					    enum b43_dmatype type)
+{
+	if (type != B43_DMA_64BIT)
+		return 1;
+
+#ifdef CONFIG_B43_SSB
+	if (dev->dev->bus_type == B43_BUS_SSB &&
+	    dev->dev->sdev->bus->bustype == SSB_BUSTYPE_PCI &&
+	    !(dev->dev->sdev->bus->host_pci->is_pcie &&
+	      ssb_read32(dev->dev->sdev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64))
+			return 1;
+#endif
+	return 0;
+}
+
 int b43_dma_init(struct b43_wldev *dev)
 {
 	struct b43_dma *dma = &dev->dma;
@@ -1091,6 +1131,7 @@ int b43_dma_init(struct b43_wldev *dev)
 		break;
 #endif
 	}
+	dma->translation_in_low = b43_dma_translation_in_low_word(dev, type);
 
 	dma->parity = true;
 #ifdef CONFIG_B43_BCMA
diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h
index cdf8709..1a5313d 100644
--- a/drivers/net/wireless/b43/dma.h
+++ b/drivers/net/wireless/b43/dma.h
@@ -212,6 +212,12 @@ enum b43_dmatype {
 	B43_DMA_64BIT	= 64,
 };
 
+enum b43_addrtype {
+	B43_DMA_ADDR_LOW,
+	B43_DMA_ADDR_HIGH,
+	B43_DMA_ADDR_EXT,
+};
+
 struct b43_dmaring {
 	/* Lowlevel DMA ops. */
 	const struct b43_dma_ops *ops;
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH V3 3.2 2/2] b43: fix DMA on some bugged hardware
@ 2011-08-14 18:16 ` Rafał Miłecki
  0 siblings, 0 replies; 6+ messages in thread
From: Rafał Miłecki @ 2011-08-14 18:16 UTC (permalink / raw)
  To: linux-wireless, John W. Linville; +Cc: b43-dev, Rafał Miłecki

Some hardware with 64-bit DMA uses lower address word for setting
routing (translation) bit. Add workaround for such boards.

Signed-off-by: Rafa? Mi?ecki <zajec5@gmail.com>
---
V2: use (u64) to fix compilation on 32-bit systems
V3: use ready macro instead of own shifting/masking upper/lower 32 bits

Larry: could you give it a try?

John: we gave it a chance, I failed. Please take it for 3.2, don't
want to risk more problems.
---
 drivers/net/wireless/b43/b43.h |    1 +
 drivers/net/wireless/b43/dma.c |  113 +++++++++++++++++++++++++++-------------
 drivers/net/wireless/b43/dma.h |    6 ++
 3 files changed, 84 insertions(+), 36 deletions(-)

diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index c818b0b..3aee322 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -594,6 +594,7 @@ struct b43_dma {
 	struct b43_dmaring *rx_ring;
 
 	u32 translation; /* Routing bits */
+	bool translation_in_low; /* Should translation bit go into low addr? */
 	bool parity; /* Check for parity */
 };
 
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index 481e534..c3f856b 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -47,6 +47,38 @@
  * into separate slots. */
 #define TX_SLOTS_PER_FRAME	2
 
+static u32 b43_dma_address(struct b43_dma *dma, dma_addr_t dmaaddr,
+			   enum b43_addrtype addrtype)
+{
+	u32 uninitialized_var(addr);
+
+	switch (addrtype) {
+	case B43_DMA_ADDR_LOW:
+		addr = lower_32_bits(dmaaddr);
+		if (dma->translation_in_low) {
+			addr &= ~SSB_DMA_TRANSLATION_MASK;
+			addr |= dma->translation;
+		}
+		break;
+	case B43_DMA_ADDR_HIGH:
+		addr = upper_32_bits(dmaaddr);
+		if (!dma->translation_in_low) {
+			addr &= ~SSB_DMA_TRANSLATION_MASK;
+			addr |= dma->translation;
+		}
+		break;
+	case B43_DMA_ADDR_EXT:
+		if (dma->translation_in_low)
+			addr = lower_32_bits(dmaaddr);
+		else
+			addr = upper_32_bits(dmaaddr);
+		addr &= SSB_DMA_TRANSLATION_MASK;
+		addr >>= SSB_DMA_TRANSLATION_SHIFT;
+		break;
+	}
+
+	return addr;
+}
 
 /* 32bit DMA ops. */
 static
@@ -77,10 +109,9 @@ static void op32_fill_descriptor(struct b43_dmaring *ring,
 	slot = (int)(&(desc->dma32) - descbase);
 	B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
 
-	addr = (u32) (dmaaddr & ~SSB_DMA_TRANSLATION_MASK);
-	addrext = (u32) (dmaaddr & SSB_DMA_TRANSLATION_MASK)
-	    >> SSB_DMA_TRANSLATION_SHIFT;
-	addr |= ring->dev->dma.translation;
+	addr = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_LOW);
+	addrext = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_EXT);
+
 	ctl = bufsize & B43_DMA32_DCTL_BYTECNT;
 	if (slot == ring->nr_slots - 1)
 		ctl |= B43_DMA32_DCTL_DTABLEEND;
@@ -170,11 +201,10 @@ static void op64_fill_descriptor(struct b43_dmaring *ring,
 	slot = (int)(&(desc->dma64) - descbase);
 	B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
 
-	addrlo = (u32) (dmaaddr & 0xFFFFFFFF);
-	addrhi = (((u64) dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK);
-	addrext = (((u64) dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK)
-	    >> SSB_DMA_TRANSLATION_SHIFT;
-	addrhi |= ring->dev->dma.translation;
+	addrlo = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_LOW);
+	addrhi = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_HIGH);
+	addrext = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_EXT);
+
 	if (slot == ring->nr_slots - 1)
 		ctl0 |= B43_DMA64_DCTL0_DTABLEEND;
 	if (start)
@@ -658,41 +688,37 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
 	int err = 0;
 	u32 value;
 	u32 addrext;
-	u32 trans = ring->dev->dma.translation;
 	bool parity = ring->dev->dma.parity;
+	u32 addrlo;
+	u32 addrhi;
 
 	if (ring->tx) {
 		if (ring->type == B43_DMA_64BIT) {
 			u64 ringbase = (u64) (ring->dmabase);
+			addrext = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_EXT);
+			addrlo = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_LOW);
+			addrhi = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_HIGH);
 
-			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;
 			if (!parity)
 				value |= B43_DMA64_TXPARITYDISABLE;
 			b43_dma_write(ring, B43_DMA64_TXCTL, value);
-			b43_dma_write(ring, B43_DMA64_TXRINGLO,
-				      (ringbase & 0xFFFFFFFF));
-			b43_dma_write(ring, B43_DMA64_TXRINGHI,
-				      ((ringbase >> 32) &
-				       ~SSB_DMA_TRANSLATION_MASK)
-				      | trans);
+			b43_dma_write(ring, B43_DMA64_TXRINGLO, addrlo);
+			b43_dma_write(ring, B43_DMA64_TXRINGHI, addrhi);
 		} else {
 			u32 ringbase = (u32) (ring->dmabase);
+			addrext = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_EXT);
+			addrlo = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_LOW);
 
-			addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
-			    >> SSB_DMA_TRANSLATION_SHIFT;
 			value = B43_DMA32_TXENABLE;
 			value |= (addrext << B43_DMA32_TXADDREXT_SHIFT)
 			    & B43_DMA32_TXADDREXT_MASK;
 			if (!parity)
 				value |= B43_DMA32_TXPARITYDISABLE;
 			b43_dma_write(ring, B43_DMA32_TXCTL, value);
-			b43_dma_write(ring, B43_DMA32_TXRING,
-				      (ringbase & ~SSB_DMA_TRANSLATION_MASK)
-				      | trans);
+			b43_dma_write(ring, B43_DMA32_TXRING, addrlo);
 		}
 	} else {
 		err = alloc_initial_descbuffers(ring);
@@ -700,9 +726,10 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
 			goto out;
 		if (ring->type == B43_DMA_64BIT) {
 			u64 ringbase = (u64) (ring->dmabase);
+			addrext = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_EXT);
+			addrlo = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_LOW);
+			addrhi = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_HIGH);
 
-			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)
@@ -710,19 +737,15 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
 			if (!parity)
 				value |= B43_DMA64_RXPARITYDISABLE;
 			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_RXRINGLO, addrlo);
+			b43_dma_write(ring, B43_DMA64_RXRINGHI, addrhi);
 			b43_dma_write(ring, B43_DMA64_RXINDEX, ring->nr_slots *
 				      sizeof(struct b43_dmadesc64));
 		} else {
 			u32 ringbase = (u32) (ring->dmabase);
+			addrext = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_EXT);
+			addrlo = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_LOW);
 
-			addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
-			    >> SSB_DMA_TRANSLATION_SHIFT;
 			value = (ring->frameoffset << B43_DMA32_RXFROFF_SHIFT);
 			value |= B43_DMA32_RXENABLE;
 			value |= (addrext << B43_DMA32_RXADDREXT_SHIFT)
@@ -730,9 +753,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
 			if (!parity)
 				value |= B43_DMA32_RXPARITYDISABLE;
 			b43_dma_write(ring, B43_DMA32_RXCTL, value);
-			b43_dma_write(ring, B43_DMA32_RXRING,
-				      (ringbase & ~SSB_DMA_TRANSLATION_MASK)
-				      | trans);
+			b43_dma_write(ring, B43_DMA32_RXRING, addrlo);
 			b43_dma_write(ring, B43_DMA32_RXINDEX, ring->nr_slots *
 				      sizeof(struct b43_dmadesc32));
 		}
@@ -1066,6 +1087,25 @@ static int b43_dma_set_mask(struct b43_wldev *dev, u64 mask)
 	return 0;
 }
 
+/* Some hardware with 64-bit DMA seems to be bugged and looks for translation
+ * bit in low address word instead of high one.
+ */
+static bool b43_dma_translation_in_low_word(struct b43_wldev *dev,
+					    enum b43_dmatype type)
+{
+	if (type != B43_DMA_64BIT)
+		return 1;
+
+#ifdef CONFIG_B43_SSB
+	if (dev->dev->bus_type == B43_BUS_SSB &&
+	    dev->dev->sdev->bus->bustype == SSB_BUSTYPE_PCI &&
+	    !(dev->dev->sdev->bus->host_pci->is_pcie &&
+	      ssb_read32(dev->dev->sdev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64))
+			return 1;
+#endif
+	return 0;
+}
+
 int b43_dma_init(struct b43_wldev *dev)
 {
 	struct b43_dma *dma = &dev->dma;
@@ -1091,6 +1131,7 @@ int b43_dma_init(struct b43_wldev *dev)
 		break;
 #endif
 	}
+	dma->translation_in_low = b43_dma_translation_in_low_word(dev, type);
 
 	dma->parity = true;
 #ifdef CONFIG_B43_BCMA
diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h
index cdf8709..1a5313d 100644
--- a/drivers/net/wireless/b43/dma.h
+++ b/drivers/net/wireless/b43/dma.h
@@ -212,6 +212,12 @@ enum b43_dmatype {
 	B43_DMA_64BIT	= 64,
 };
 
+enum b43_addrtype {
+	B43_DMA_ADDR_LOW,
+	B43_DMA_ADDR_HIGH,
+	B43_DMA_ADDR_EXT,
+};
+
 struct b43_dmaring {
 	/* Lowlevel DMA ops. */
 	const struct b43_dma_ops *ops;
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH V3 3.2 2/2] b43: fix DMA on some bugged hardware
  2011-08-14 18:16 ` Rafał Miłecki
  (?)
@ 2011-08-17  2:49 ` Vítor Ferreira
  2011-08-17  8:12   ` Rafał Miłecki
  -1 siblings, 1 reply; 6+ messages in thread
From: Vítor Ferreira @ 2011-08-17  2:49 UTC (permalink / raw)
  To: linux-wireless

Greetings! I'm a grateful Linux end-user, following up on the success of this
patch.
I can confirm that after applying the following patches:
- RESEND-3.2-1-2-ssb-fix-DMA-translation-for-some-specific-boards.patch
- RFC-RFT-V2-2-2-b43-fix-DMA-on-some-bugged-hardware.patch
- v2-08-46-net-wireless-b43-fix-DMA-direction-for-RX-buffers.patch
to a 3.0.1 fedora patched kernel, the problem reporting to these patches has
been solved (as far as I am concerned).

More than a year ago, when I started using Linux on my personal laptop, I
noticed that if I enabled the feature of Intel VT in the laptop BIOS (it comes
disabled by default), that it would trigger the b43 fatal DMA error, which is
described in many posts in different forums like this:
http://forums.fedoraforum.org/showthread.php?t=235182. The b43 driver would
encounter this error and stop working from then on, until I restarted the
computer and disabled Intel VT. This error would only occur if I enabled that
feature.

Recently, while searching again for a possible solution for this issue, I
stumbled on your submitted patches in May to address the DMA issue. Then, in the
b43 supported devices table, I found that my Broadcom wireless card (14e4:4315 -
LP-r1) is now fully supported since kernel version 3.0. However, incidently I
had received the kernel 3.0 as a Fedora kernel update and upon enabling again
Intel VT, the DMA error presented itself still, not better not worse. Again, I
found your recent patches to address the DMA error and followed its developpment
on the mailing list throughout the last few days.
Seeing the initial successful tests on 64-bit affected systems, I decided to
give them a shot on my own system.
To do so, I updated my 3.0 kernel to the latest in its series (3.0.3rc1?,
2.6.40.3 in fedora versioning) and downloaded the latest bleeding edge
compat-wireless (yesterday) and I applied the above patches to it without
problems. By the way, for anyone using Fedora and reading this, know that in
order to compile compat-wireless with Fedora patched 3.0.x kernel I had to
change the line #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)) to #if
(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,40)) in the file
include/linux/compat-3.0.h.

Right now, I am writing this with Intel VT enabled and a stable wireless
connection to my home AP, using the b43 driver. So, I am showing here my
appreciation and thanking for your great work in crushing a pesky bug that was
perhaps the only one stopping my computer from being fully Linux compatible (HP
Pavilion dv5t). Continue your great work!

Just a side note... Curiously with Intel VT, the b43 driver would start and work
for some short time before it crashed, while the wl proprietary driver (from
Broadcom) would not even fully load.

Right now, I am writing this with Intel VT enabled and a stable wireless
connection to my home AP, using the b43 driver. So, I am showing here my
appreciation and thanking for your great work in crushing a pesky bug that was
perhaps the only one stopping my computer from being fully Linux compatible (HP
Pavilion dv5t). Continue your great work!

Just a side note... Curiously with Intel VT, the b43 driver would start and work
for some short time before it crashed, while the wl proprietary driver (from
Broadcom) would not even fully load.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH V3 3.2 2/2] b43: fix DMA on some bugged hardware
  2011-08-17  2:49 ` Vítor Ferreira
@ 2011-08-17  8:12   ` Rafał Miłecki
  2011-08-17 23:32     ` Vítor Ferreira
  0 siblings, 1 reply; 6+ messages in thread
From: Rafał Miłecki @ 2011-08-17  8:12 UTC (permalink / raw)
  To: Vítor Ferreira; +Cc: linux-wireless

/me rearranged order of quoted fragments

2011/8/17 Vítor Ferreira <vitor.dominor@gmail.com>:
> Greetings! I'm a grateful Linux end-user, following up on the success of this
> patch.
> I can confirm that after applying the following patches:
> - RESEND-3.2-1-2-ssb-fix-DMA-translation-for-some-specific-boards.patch
> - RFC-RFT-V2-2-2-b43-fix-DMA-on-some-bugged-hardware.patch
> - v2-08-46-net-wireless-b43-fix-DMA-direction-for-RX-buffers.patch
> to a 3.0.1 fedora patched kernel, the problem reporting to these patches has
> been solved (as far as I am concerned).

I didn't expect that patches to affect your card.


> Just a side note... Curiously with Intel VT, the b43 driver would start and work
> for some short time before it crashed, while the wl proprietary driver (from
> Broadcom) would not even fully load.

I hope you mean DMA errors, not really crashing.
What you describe here sounds like standard LP-PHY DMA issue resolved
in 3.0 kernel. We got some timeouts-related bug, which didn't hit
right after loading b43, usually some time (seconds-minutes) later.
The last patches are supposed to fix situation where DMA does not work
at all. Not even for a second, not for a single packet. I'm really
sure of that, unless you have some *really* bugged hardware accepting
multiple "translation bits" (something my patches fix).
Moreover LP-PHY DMA problems (timeouts issue) was known to be somehow
CPU/BIOS-related. Which makes it even more probably that that's
exactly what you were experiencing.


> Recently, while searching again for a possible solution for this issue, I
> stumbled on your submitted patches in May to address the DMA issue. Then, in the
> b43 supported devices table, I found that my Broadcom wireless card (14e4:4315 -
> LP-r1) is now fully supported since kernel version 3.0. However, incidently I
> had received the kernel 3.0 as a Fedora kernel update and upon enabling again
> Intel VT, the DMA error presented itself still, not better not worse.

That's the tricky part. Kernel 3.0 should really work for you. Unless
Fedora got some problem (mistake?) in compiling/numbering...


> Again, I
> found your recent patches to address the DMA error and followed its developpment
> on the mailing list throughout the last few days.
> Seeing the initial successful tests on 64-bit affected systems, I decided to
> give them a shot on my own system.
> To do so, I updated my 3.0 kernel to the latest in its series (3.0.3rc1?,
> 2.6.40.3 in fedora versioning) and downloaded the latest bleeding edge
> compat-wireless (yesterday) and I applied the above patches to it without
> problems.

I think the important part was updating to the recent compat-wireless,
not applying my patches. If you wish, you can still use that
compat-wireless, revert my 2 patches and test again. I suspect card
will be still working for you.


> Right now, I am writing this with Intel VT enabled and a stable wireless
> connection to my home AP, using the b43 driver. So, I am showing here my
> appreciation and thanking for your great work in crushing a pesky bug that was
> perhaps the only one stopping my computer from being fully Linux compatible (HP
> Pavilion dv5t). Continue your great work!

I'm really glad it's working for you now :) We're recently getting
more hardware support and (as you can see) we can slowly focus on bug
fixes now. There still a lot to do, but I hope to have the most of the
hardware supported and bugs resolved still this yeah. Then we can
finally slow down our extremly-fast-recent development a little ;)

-- 
Rafał

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH V3 3.2 2/2] b43: fix DMA on some bugged hardware
  2011-08-17  8:12   ` Rafał Miłecki
@ 2011-08-17 23:32     ` Vítor Ferreira
  2011-08-18  7:44       ` Rafał Miłecki
  0 siblings, 1 reply; 6+ messages in thread
From: Vítor Ferreira @ 2011-08-17 23:32 UTC (permalink / raw)
  To: linux-wireless

>> Just a side note... Curiously with Intel VT, the b43 driver would start and
work
>> for some short time before it crashed, while the wl proprietary driver (from
>> Broadcom) would not even fully load.
> I hope you mean DMA errors, not really crashing.

Yes, I mean DMA errors. It just seems it crashed, because it never recovers
until reboot.

> What you describe here sounds like standard LP-PHY DMA issue resolved
> in 3.0 kernel. We got some timeouts-related bug, which didn't hit
> right after loading b43, usually some time (seconds-minutes) later.

Well, lately there wasn't always a timeout after loading b43. Sometimes, the DMA
error occured only after doing some more network intensive activity, like
downloading a file or watching a video on the web.

> The last patches are supposed to fix situation where DMA does not work
> at all. Not even for a second, not for a single packet. I'm really
> sure of that, unless you have some *really* bugged hardware accepting
> multiple "translation bits" (something my patches fix).
> Moreover LP-PHY DMA problems (timeouts issue) was known to be somehow
> CPU/BIOS-related. Which makes it even more probably that that's
> exactly what you were experiencing.

Honestly, I wouldn't know. I don't have quite fully understood what is that dma
translation bug causing the dma fatal errors.
However, I suspect it might be one of those *really* bugged hardware. I'm just
guessing, perhaps it has something to do with the DMA features enabled by the
Intel Virtualization Technology for Directed I/O. It's too much of a coincidence
that the DMA errors only happen when Intel VT is enabled.
Just for your reference, this is the system log extract regarding DMA on my
system.

kernel	[    0.257149] DMAR: Forcing write-buffer flush capability
kernel	[    0.257150] DMAR: Disabling IOMMU for graphics on this chipset
kernel	[    0.601514] PCI-DMA: Intel(R) Virtualization Technology for Directed
I/O
kernel	[    0.745975] ata1: SATA max UDMA/133 abar m2048@0xdf305000 port
0xdf305100 irq 49
kernel	[    0.745978] ata2: SATA max UDMA/133 abar m2048@0xdf305000 port
0xdf305180 irq 49
kernel	[    0.745983] ata5: SATA max UDMA/133 abar m2048@0xdf305000 port
0xdf305300 irq 49
kernel	[    0.745986] ata6: SATA max UDMA/133 abar m2048@0xdf305000 port
0xdf305380 irq 49
kernel	[    1.206589] ata1.00: ATA-8: FUJITSU MHZ2320BH G2, 8909, max UDMA/100
kernel	[    1.207251] ata1.00: configured for UDMA/100
kernel	[    1.682191] ata2.00: ATAPI: TSSTcorp CDDVDW TS-L633L, 0400, max
UDMA/100
kernel	[    1.695900] ata2.00: configured for UDMA/100
kernel	[    2.696557] mmc0: SDHCI controller on PCI [0000:06:00.1] using DMA
kernel	[   28.902798] DMAR:[DMA Read] Request device [02:00.0] fault addr
ffff4000 
kernel	[   28.902800] DMAR:[fault reason 06] PTE Read access is not set
kernel	[   28.902841] b43-phy0 ERROR: Fatal DMA error: 0x00000800, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000
kernel	[   28.902846] b43-phy0 ERROR: This device does not support DMA on your
system. It will now be switched to PIO.
kernel	[   28.902850] b43-phy0: Controller RESET (DMA error) ...

>From lspci, 02:00.0 refers to the Broadcom 4312 wireless card.

> That's the tricky part. Kernel 3.0 should really work for you. Unless
> Fedora got some problem (mistake?) in compiling/numbering...

> I think the important part was updating to the recent compat-wireless,
> not applying my patches. If you wish, you can still use that
> compat-wireless, revert my 2 patches and test again. I suspect card
> will be still working for you.

I booted back to the kernel 3.0 from fedora, without your patches and any
compat-wireless. I checked again and the DMA errors really continue in these
circunstances.
Then I booted again to my updated 3.0.3.rc1 kernel and I applied the same recent
compat-wireless without your last patches. Again, the same DMA errors occurred
after loading b43, as shown in the log above.
Only after patching the compat-wireless with your last patches and rebooting did
those DMA errors disappear. So I am afraid the recent (unpatched)
compat-wireless isn't the solution.



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH V3 3.2 2/2] b43: fix DMA on some bugged hardware
  2011-08-17 23:32     ` Vítor Ferreira
@ 2011-08-18  7:44       ` Rafał Miłecki
  0 siblings, 0 replies; 6+ messages in thread
From: Rafał Miłecki @ 2011-08-18  7:44 UTC (permalink / raw)
  To: Vítor Ferreira; +Cc: linux-wireless

2011/8/18 Vítor Ferreira <vitor.dominor@gmail.com>:
>>> Just a side note... Curiously with Intel VT, the b43 driver would start and
> work
>>> for some short time before it crashed, while the wl proprietary driver (from
>>> Broadcom) would not even fully load.
>> I hope you mean DMA errors, not really crashing.
>
> Yes, I mean DMA errors. It just seems it crashed, because it never recovers
> until reboot.
>
>> What you describe here sounds like standard LP-PHY DMA issue resolved
>> in 3.0 kernel. We got some timeouts-related bug, which didn't hit
>> right after loading b43, usually some time (seconds-minutes) later.
>
> Well, lately there wasn't always a timeout after loading b43. Sometimes, the DMA
> error occured only after doing some more network intensive activity, like
> downloading a file or watching a video on the web.
>
>> The last patches are supposed to fix situation where DMA does not work
>> at all. Not even for a second, not for a single packet. I'm really
>> sure of that, unless you have some *really* bugged hardware accepting
>> multiple "translation bits" (something my patches fix).
>> Moreover LP-PHY DMA problems (timeouts issue) was known to be somehow
>> CPU/BIOS-related. Which makes it even more probably that that's
>> exactly what you were experiencing.
>
> Honestly, I wouldn't know. I don't have quite fully understood what is that dma
> translation bug causing the dma fatal errors.
> However, I suspect it might be one of those *really* bugged hardware. I'm just
> guessing, perhaps it has something to do with the DMA features enabled by the
> Intel Virtualization Technology for Directed I/O. It's too much of a coincidence
> that the DMA errors only happen when Intel VT is enabled.
> Just for your reference, this is the system log extract regarding DMA on my
> system.
>
> kernel  [    0.257149] DMAR: Forcing write-buffer flush capability
> kernel  [    0.257150] DMAR: Disabling IOMMU for graphics on this chipset
> kernel  [    0.601514] PCI-DMA: Intel(R) Virtualization Technology for Directed
> I/O
> kernel  [    0.745975] ata1: SATA max UDMA/133 abar m2048@0xdf305000 port
> 0xdf305100 irq 49
> kernel  [    0.745978] ata2: SATA max UDMA/133 abar m2048@0xdf305000 port
> 0xdf305180 irq 49
> kernel  [    0.745983] ata5: SATA max UDMA/133 abar m2048@0xdf305000 port
> 0xdf305300 irq 49
> kernel  [    0.745986] ata6: SATA max UDMA/133 abar m2048@0xdf305000 port
> 0xdf305380 irq 49
> kernel  [    1.206589] ata1.00: ATA-8: FUJITSU MHZ2320BH G2, 8909, max UDMA/100
> kernel  [    1.207251] ata1.00: configured for UDMA/100
> kernel  [    1.682191] ata2.00: ATAPI: TSSTcorp CDDVDW TS-L633L, 0400, max
> UDMA/100
> kernel  [    1.695900] ata2.00: configured for UDMA/100
> kernel  [    2.696557] mmc0: SDHCI controller on PCI [0000:06:00.1] using DMA
> kernel  [   28.902798] DMAR:[DMA Read] Request device [02:00.0] fault addr
> ffff4000
> kernel  [   28.902800] DMAR:[fault reason 06] PTE Read access is not set
> kernel  [   28.902841] b43-phy0 ERROR: Fatal DMA error: 0x00000800, 0x00000000,
> 0x00000000, 0x00000000, 0x00000000, 0x00000000
> kernel  [   28.902846] b43-phy0 ERROR: This device does not support DMA on your
> system. It will now be switched to PIO.
> kernel  [   28.902850] b43-phy0: Controller RESET (DMA error) ...
>
> From lspci, 02:00.0 refers to the Broadcom 4312 wireless card.
>
>> That's the tricky part. Kernel 3.0 should really work for you. Unless
>> Fedora got some problem (mistake?) in compiling/numbering...
>
>> I think the important part was updating to the recent compat-wireless,
>> not applying my patches. If you wish, you can still use that
>> compat-wireless, revert my 2 patches and test again. I suspect card
>> will be still working for you.
>
> I booted back to the kernel 3.0 from fedora, without your patches and any
> compat-wireless. I checked again and the DMA errors really continue in these
> circunstances.
> Then I booted again to my updated 3.0.3.rc1 kernel and I applied the same recent
> compat-wireless without your last patches. Again, the same DMA errors occurred
> after loading b43, as shown in the log above.
> Only after patching the compat-wireless with your last patches and rebooting did
> those DMA errors disappear. So I am afraid the recent (unpatched)
> compat-wireless isn't the solution.

Hm, OK, it really seems you're right, there is something more we
wasn't aware of.

Thanks for your testing :)

-- 
Rafał

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2011-08-18  7:44 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-08-14 18:16 [PATCH V3 3.2 2/2] b43: fix DMA on some bugged hardware Rafał Miłecki
2011-08-14 18:16 ` Rafał Miłecki
2011-08-17  2:49 ` Vítor Ferreira
2011-08-17  8:12   ` Rafał Miłecki
2011-08-17 23:32     ` Vítor Ferreira
2011-08-18  7:44       ` Rafał Miłecki

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.