[U-Boot] TSEC ethernet controller problems (crc errors / corruption)

Ira Snyder iws at ovro.caltech.edu
Tue Jun 2 18:27:57 CEST 2009


Hello U-Boot users,

I've been working on a custom board, based heavily on the Freescale
MPC8349EMDS board. The only major difference is that the board has some
FPGAs connected to the local bus.

I've found that the TSEC / gianfar ethernet does not work for me in
1000mbit mode. I constantly get "got error 4" from U-Boot, which means
that a CRC error was detected by the TSEC controller.

I have tried running the TSEC in 100mbit mode, without any problems. I
can tftp as much data as I want in U-Boot, and I've transferred many,
many gigabytes without issue in Linux. The problem is only with 1000mbit
mode.

I initially suspected problems with the PHY, a Marvell 88E1111. To
diganose the problem, I set the PHY into loopback mode, then connected
my logic analyzer to the PHY's RX lines. This removes the external
network from the equation: I don't even have an ethernet cable
connected.

The logic analyzer traces show the correct, expected packet data coming
from the PHY. By the time the TSEC copies the data into a buffer
descriptor, the packet data has been corrupted. The problem is extra or
missing bytes in the packet data. I have added some code to dump the
packet contents on CRC error, and what I see in memory is not what the
PHY sent.

The corruption is not at a consistent offset in the packet. The number
of extra or missing bytes is not always the same.

The extra bytes that show up in the packet data seem like a FIFO issue
to me. It is as if the internal FIFO reported that more data was
available before the data was actually present. Something like that.

For reference, here is what a memory dump of a good packet looks like.
It has a length of 64 bytes. I have dumped 16 bytes past the end of the
packet data.

0fffcbe0: ff ff ff ff ff ff ae dc 30 45 e8 3a 08 06 00 01    ........0E.:....
0fffcbf0: 08 00 06 04 00 01 ae dc 30 45 e8 3a c0 a8 11 45    ........0E.:...E
0fffcc00: 00 00 00 00 00 00 c0 a8 11 39 00 00 00 00 00 00    .........9......
0fffcc10: 00 00 00 00 00 00 00 00 00 00 00 00 2c d1 57 03    ............,.W.
0fffcc20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................

And this is what a bad packet looks like in memory. The length was
reported by the TSEC as 64 bytes, but it was flagged as having a CRC
error. Notice the extra bytes starting at 0x0fffcc0c, "copied" from 16
bytes earlier in the packet. The CRC is shifted 4 bytes in the packet
due to the extra bytes.

0fffcbe0: ff ff ff ff ff ff ae dc 30 45 e8 3a 08 06 00 01    ........0E.:....
0fffcbf0: 08 00 06 04 00 01 ae dc 30 45 e8 3a c0 a8 11 45    ........0E.:...E
0fffcc00: 00 00 00 00 00 00 c0 a8 11 39 00 00 c0 a8 11 45    .........9.....E
0fffcc10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
0fffcc20: 2c d1 57 03 00 00 00 00 00 00 00 00 00 00 00 00    ,.W.............

I have been running U-Boot and Linux on this board for >6 months. I've
run plenty of stress tests, and I've been doing lots of work with the
DMA controller. I've stressed the memory pretty hard, and I'm fairly
confident that it is not a problem with RAM. The board has been
perfectly stable.

Other solutions I have tried, without any effect:
* slowing down the core frequency from 528 -> 264 MHz
* slowing down the RAM frequency from 266 -> 200 MHz

I am unable to reproduce the corruption on my MPC8349EMDS eval board,
but I'm running out of ideas to try and find the source of this problem.

Has anyone seen anything like this before?

Thanks for your help,
Ira

PS - Below is the patch of the debugging code I've added.

diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c
index 399116f..2f8f1bc 100644
--- a/drivers/net/tsec.c
+++ b/drivers/net/tsec.c
@@ -214,7 +214,9 @@ int tsec_init(struct eth_device *dev, bd_t * bd)
 	startup_tsec(dev);
 
 	/* If there's no link, fail */
-	return (priv->link ? 0 : -1);
+	printf("LINK: %d\n", priv->link);
+	return 0;
+	//return (priv->link ? 0 : -1);
 }
 
 /* Writes the given phy's reg with value, using the specified MDIO regs */
@@ -928,22 +930,44 @@ static int tsec_send(struct eth_device *dev, volatile void *packet, int length)
 	return result;
 }
 
+static unsigned char MYPACKET[4096];
+
 static int tsec_recv(struct eth_device *dev)
 {
 	int length;
 	struct tsec_private *priv = (struct tsec_private *)dev->priv;
 	volatile tsec_t *regs = priv->regs;
+	u32 hwcrc, swcrc, cpcrc, rxaddr;
 
 	while (!(rtx.rxbd[rxIdx].status & RXBD_EMPTY)) {
 
 		length = rtx.rxbd[rxIdx].length;
 
+		hwcrc = *(u32 *)(NetRxPackets[rxIdx] + length - 4);
+		memcpy(MYPACKET, NetRxPackets[rxIdx], length + 16);
+		swcrc = crc32(0, MYPACKET, length - 4);
+		swcrc = swab32(swcrc);
+		cpcrc = *(u32 *)(MYPACKET + length - 4);
+
+		printf("CRC HW 0x%.8x SW 0x%.8x CP 0x%.8x IEVENT 0x%.8x MACCFG1 0x%.8x\n",
+				hwcrc, swcrc, cpcrc, regs->ievent, regs->maccfg1);
+
 		/* Send the packet up if there were no errors */
 		if (!(rtx.rxbd[rxIdx].status & RXBD_STATS)) {
 			NetReceive(NetRxPackets[rxIdx], length - 4);
 		} else {
-			printf("Got error %x\n",
-			       (rtx.rxbd[rxIdx].status & RXBD_STATS));
+			rxaddr = (u32)NetRxPackets[rxIdx];
+			printf("Got error %x\n", (rtx.rxbd[rxIdx].status & RXBD_STATS));
+			printf("PACKET DATA START 0x%.8x END 0x%.8x LEN %d\n", rxaddr, rxaddr + length, length);
+			printf("RXIDX %d STAT 0x%.8x LEN %d\n", rxIdx, rtx.rxbd[rxIdx].status, length);
+			/* Print the buffer:
+			 * $1: start address (for display purposes)
+			 * $2: memory buffer to print
+			 * $3: access mode (byte, short, word)
+			 * $4: length to print
+			 * $5: line length
+			 */
+			print_buffer(rxaddr, MYPACKET, 1, length + 16, 0);
 		}
 
 		rtx.rxbd[rxIdx].length = 0;
diff --git a/include/configs/MPC8349EMDS.h b/include/configs/MPC8349EMDS.h
index 3c57403..1287829 100644
--- a/include/configs/MPC8349EMDS.h
+++ b/include/configs/MPC8349EMDS.h
@@ -53,6 +53,10 @@
 #define CONFIG_83XX_PCICLK	66666666	/* in Hz */
 #endif /* CONFIG_PCISLAVE */
 
+#define CONFIG_SYS_RX_ETH_BUFFER	16
+#define CONFIG_ARP_TIMEOUT		750UL
+#define CONFIG_NET_RETRY_COUNT		64
+
 #ifndef CONFIG_SYS_CLK_FREQ
 #ifdef PCI_66M
 #define CONFIG_SYS_CLK_FREQ	66000000


More information about the U-Boot mailing list