summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2014-04-01 23:06:09 +0100
committerRussell King <rmk+kernel@arm.linux.org.uk>2014-10-17 14:34:50 +0100
commit313c7fd3bb73c5ff942d48020bd6e3cc11a4f935 (patch)
tree14bf10f47cca05fb190901eb90ec7ee26641b048
parentbfe01a5ba2490f299e1d2d5508cbbbadd897bbe9 (diff)
net: fec: fix receive error handling
The FEC receive error handling suffers from several problems: 1. When a FIFO overrun error occurs, the descriptor is closed and reception stops. The remainder of the packet is discarded by the MAC. The documentation states that other status bits are invalid, and they will be zero. However, practical experience on iMX6 shows this is not the case - the CR (crc error) bit will also be set. This leads to each FIFO overrun event incrementing both the fifo error count and the crc error count, which makes the error statistics less useful. Fix this by ignoring all other status bits of the FIFO overrun is set, and add a comment to that effect. 2. A late collision invalidates all but the overrun condition; the remaining error conditions must be ignored. 3. Despite accounting for errors, it continues to receive the errored packets and pass them into the network stack as if they were correctly received. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--drivers/net/ethernet/freescale/fec.h1
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c47
2 files changed, 28 insertions, 20 deletions
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index ee41d98b44b6..ec4c76264eb9 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -202,6 +202,7 @@ struct bufdesc_ex {
#define BD_ENET_RX_OV ((ushort)0x0002)
#define BD_ENET_RX_CL ((ushort)0x0001)
#define BD_ENET_RX_STATS ((ushort)0x013f) /* All status bits */
+#define BD_ENET_RX_ERROR ((ushort)0x003f)
/* Enhanced buffer descriptor control/status used by Ethernet receive */
#define BD_ENET_RX_VLAN 0x00000004
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 89355a719625..fd49bd70d15d 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1218,28 +1218,35 @@ fec_enet_rx(struct net_device *ndev, int budget)
writel(FEC_ENET_RXF, fep->hwp + FEC_IEVENT);
/* Check for errors. */
- if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
- BD_ENET_RX_CR | BD_ENET_RX_OV)) {
+ if (status & BD_ENET_RX_ERROR) {
ndev->stats.rx_errors++;
- if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) {
- /* Frame too long or too short. */
- ndev->stats.rx_length_errors++;
- }
- if (status & BD_ENET_RX_NO) /* Frame alignment */
- ndev->stats.rx_frame_errors++;
- if (status & BD_ENET_RX_CR) /* CRC Error */
- ndev->stats.rx_crc_errors++;
- if (status & BD_ENET_RX_OV) /* FIFO overrun */
- ndev->stats.rx_fifo_errors++;
- }
- /* Report late collisions as a frame error.
- * On this error, the BD is closed, but we don't know what we
- * have in the buffer. So, just drop this frame on the floor.
- */
- if (status & BD_ENET_RX_CL) {
- ndev->stats.rx_errors++;
- ndev->stats.rx_frame_errors++;
+ if (status & BD_ENET_RX_OV) {
+ /*
+ * FIFO overrun - stored frame and the other
+ * status (M, LG, NO, CR, CL) are invalid.
+ * Although docs say these status bits will
+ * be zero, it has been observed on iMX6 FEC
+ * that OV is always accompanied by CR set.
+ */
+ ndev->stats.rx_fifo_errors++;
+ } else if (status & BD_ENET_RX_CL) {
+ /*
+ * Report late collisions as a frame error.
+ * On this error, the BD is closed, but we
+ * don't know what we have in the buffer.
+ * So, just drop this frame on the floor.
+ */
+ ndev->stats.rx_frame_errors++;
+ } else {
+ if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH))
+ /* Frame too long or too short. */
+ ndev->stats.rx_length_errors++;
+ if (status & BD_ENET_RX_NO) /* Frame alignment */
+ ndev->stats.rx_frame_errors++;
+ if (status & BD_ENET_RX_CR) /* CRC Error */
+ ndev->stats.rx_crc_errors++;
+ }
goto rx_processing_done;
}