diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2014-04-01 23:06:09 +0100 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2014-10-17 14:34:50 +0100 |
commit | 313c7fd3bb73c5ff942d48020bd6e3cc11a4f935 (patch) | |
tree | 14bf10f47cca05fb190901eb90ec7ee26641b048 /drivers/net/ethernet/freescale/fec_main.c | |
parent | bfe01a5ba2490f299e1d2d5508cbbbadd897bbe9 (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>
Diffstat (limited to 'drivers/net/ethernet/freescale/fec_main.c')
-rw-r--r-- | drivers/net/ethernet/freescale/fec_main.c | 47 |
1 files changed, 27 insertions, 20 deletions
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; } |