linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFT] BCM4312 users with DMA errors, please test!
@ 2010-08-16 17:59 Gábor Stefanik
       [not found] ` <AANLkTin0R6k0_GoSEN8aJ8t_fTJw9h_N_0etcxAokv6N@mail.gmail.com>
                   ` (2 more replies)
  0 siblings, 3 replies; 18+ messages in thread
From: Gábor Stefanik @ 2010-08-16 17:59 UTC (permalink / raw)
  To: b43-dev, linux-wireless

[-- Attachment #1: Type: text/plain, Size: 456 bytes --]

Hello Everyone!

If you are experiencing DMA errors on a BCM4312, please test the
attached patch. It implements the PCI-E SERDES workaround, which the
hybrid driver is applying during early init to LP-PHY cards, and which
is a good candidate for the cause of the DMA error.
Note that this is not a final patch & it may cause collateral damage
for non-4312 cards; if it helps the 4312 problem, I will submit a
cleaned-up version.

Thanks,
Gábor

[-- Attachment #2: pcie_serdes_workaround.diff --]
[-- Type: application/octet-stream, Size: 3421 bytes --]

diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c
index 0e8d352..9f5c5e2 100644
--- a/drivers/ssb/driver_pcicore.c
+++ b/drivers/ssb/driver_pcicore.c
@@ -446,13 +446,71 @@ static void ssb_pcie_write(struct ssb_pcicore *pc, u32 address, u32 data)
 	pcicore_write32(pc, 0x134, data);
 }
 
+static bool ssb_pcie_mdio_set_block(struct ssb_pcicore *pc, u8 device)
+{
+	const u16 mdio_control = 0x128;
+	const u16 mdio_data = 0x12C;
+
+	pcicore_write32(pc, mdio_data, 0x57C20000 | (device << 4));
+	udelay(10);
+
+	for (i = 0; i < 200; i++) {
+		if (pcicore_read32(pc, mdio_control) & 0x100)
+			return true;
+		msleep(1);
+	}
+
+	return false;
+}
+
+static u16 ssb_pcie_mdio_read(struct ssb_pcicore *pc, u8 device,
+				u8 address)
+{
+	const u16 mdio_control = 0x128;
+	const u16 mdio_data = 0x12C;
+	u32 v;
+	int i, imax;
+	u16 data;
+
+	v = 0x80; /* Enable Preamble Sequence */
+	v |= 0x2; /* MDIO Clock Divisor */
+	pcicore_write32(pc, mdio_control, v);
+
+	v = (1 << 30); /* Start of Transaction */
+	v |= (1 << 29); /* Read Transaction */
+	v |= (1 << 17); /* Turnaround */
+
+	if (pc->dev->id.revision >= 10) {
+		if (!ssb_pcie_mdio_set_block(pc, device))
+			return 0;
+		imax = 200;
+	} else {
+		v |= (u32)device << 22;
+		imax = 10;
+	}
+	v |= (u32)address << 18;
+	pcicore_write32(pc, mdio_data, v);
+	/* Wait for the device to complete the transaction */
+	udelay(10);
+	for (i = 0; i < imax; i++) {
+		v = pcicore_read32(pc, mdio_control);
+		if (v & 0x100 /* Trans complete */)
+			break;
+		msleep(1);
+	}
+	udelay(10);
+	data = pcicore_read32(pc, mdio_data) & 0xFFFF
+	pcicore_write32(pc, mdio_control, 0);
+	return data;
+}
+
 static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device,
 				u8 address, u16 data)
 {
 	const u16 mdio_control = 0x128;
 	const u16 mdio_data = 0x12C;
 	u32 v;
-	int i;
+	int i, imax;
 
 	v = 0x80; /* Enable Preamble Sequence */
 	v |= 0x2; /* MDIO Clock Divisor */
@@ -461,13 +519,21 @@ static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device,
 	v = (1 << 30); /* Start of Transaction */
 	v |= (1 << 28); /* Write Transaction */
 	v |= (1 << 17); /* Turnaround */
-	v |= (u32)device << 22;
+	
+	if (pc->dev->id.revision >= 10) {
+		if (!ssb_pcie_mdio_set_block(pc, device))
+			return;
+		imax = 200;
+	} else {
+		v |= (u32)device << 22;
+		imax = 10;
+	}
 	v |= (u32)address << 18;
 	v |= data;
 	pcicore_write32(pc, mdio_data, v);
 	/* Wait for the device to complete the transaction */
 	udelay(10);
-	for (i = 0; i < 10; i++) {
+	for (i = 0; i < imax; i++) {
 		v = pcicore_read32(pc, mdio_control);
 		if (v & 0x100 /* Trans complete */)
 			break;
@@ -591,6 +657,20 @@ int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
 			tmp = ssb_pcie_read(pc, 0x100);
 			tmp |= 0x40;
 			ssb_pcie_write(pc, 0x100, tmp);
+		} else {
+			const u8 serdes_pll_device = 0x1D;
+			const u8 serdes_rx_device = 0x1F;
+
+			/* PCI-E PHY Status register */
+			if (ssb_pcie_read(pc, 0x204) & 0x10)
+				ssb_pcie_mdio_write(pc, serdes_rx_device,
+						    1 /* Control */, 0xC0);
+			else
+				ssb_pcie_mdio_write(pc, serdes_rx_device,
+						    1 /* Control */, 0x80);
+			ssb_pcie_mdio_write(pc, serdes_pll_device, 1,
+				ssb_pcie_mdio_read(pc, serdes_pll_device, 1) &
+				~0x4000);
 		}
 	}
 	pc->setup_done = 1;

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

end of thread, other threads:[~2010-08-17 20:39 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-08-16 17:59 [RFT] BCM4312 users with DMA errors, please test! Gábor Stefanik
     [not found] ` <AANLkTin0R6k0_GoSEN8aJ8t_fTJw9h_N_0etcxAokv6N@mail.gmail.com>
2010-08-16 18:15   ` Gábor Stefanik
     [not found]     ` <AANLkTinkx+FjrAR48dziDR2kX48JRcjm3SF7jhhi4_oM@mail.gmail.com>
2010-08-16 18:45       ` Gábor Stefanik
2010-08-17 15:49         ` Arthur Moreira
2010-08-16 19:06 ` Larry Finger
2010-08-16 19:16   ` Gábor Stefanik
2010-08-16 19:30     ` Larry Finger
2010-08-16 19:32       ` Gábor Stefanik
2010-08-16 19:41 ` Chris Vine
2010-08-16 22:35   ` Chris Vine
2010-08-16 23:53     ` Larry Finger
2010-08-17  0:09       ` Chris Vine
2010-08-17  0:10         ` Chris Vine
2010-08-17  0:14         ` Chris Vine
2010-08-17  1:01           ` Larry Finger
2010-08-17 12:23             ` Chris Vine
2010-08-17 20:28               ` Chris Vine
2010-08-17 20:38                 ` Gábor Stefanik

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).