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:35:43 +0100
commit7e291d514886ac81463014078292fbe32f08ae76 (patch)
treee6dac90730b7a18f7f88eb2f9710c3ddab9a0c74
parent9f8008020a8293074a65f5f23ec1f40ac97d6beb (diff)
net:fec: unsorted hacks
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--drivers/net/ethernet/freescale/fec.h15
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c85
2 files changed, 63 insertions, 37 deletions
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 442fa513e000..377477f18d01 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -231,10 +231,17 @@ union bufdesc_u {
#define BD_ENET_TX_STATS ((ushort)0x0fff) /* All status bits */
/*enhanced buffer descriptor control/status used by Ethernet transmit*/
-#define BD_ENET_TX_INT 0x40000000
-#define BD_ENET_TX_TS 0x20000000
-#define BD_ENET_TX_PINS 0x10000000
-#define BD_ENET_TX_IINS 0x08000000
+#define BD_ENET_TX_INT BIT(30)
+#define BD_ENET_TX_TS BIT(29)
+#define BD_ENET_TX_PINS BIT(28)
+#define BD_ENET_TX_IINS BIT(27)
+#define BD_ENET_TX_TXE BIT(15)
+#define BD_ENET_TX_UE BIT(13)
+#define BD_ENET_TX_EE BIT(12)
+#define BD_ENET_TX_FE BIT(11)
+#define BD_ENET_TX_LCE BIT(10)
+#define BD_ENET_TX_OE BIT(9)
+#define BD_ENET_TX_TSE BIT(8)
/* This device has up to three irqs on some platforms */
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 95fad9862ef5..001db716cbf7 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -109,16 +109,6 @@ static void set_multicast_list(struct net_device *ndev);
#define FEC_QUIRK_HAS_CSUM (1 << 5)
/* Controller has hardware vlan support */
#define FEC_QUIRK_HAS_VLAN (1 << 6)
-/* ENET IP errata ERR006358
- *
- * If the ready bit in the transmit buffer descriptor (TxBD[R]) is previously
- * detected as not set during a prior frame transmission, then the
- * ENET_TDAR[TDAR] bit is cleared at a later time, even if additional TxBDs
- * were added to the ring and the ENET_TDAR[TDAR] bit is set. This results in
- * frames not being transmitted until there is a 0-to-1 transition on
- * ENET_TDAR[TDAR].
- */
-#define FEC_QUIRK_ERR006358 (1 << 7)
static struct platform_device_id fec_devtype[] = {
{
@@ -138,7 +128,7 @@ static struct platform_device_id fec_devtype[] = {
.name = "imx6q-fec",
.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
- FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358,
+ FEC_QUIRK_HAS_VLAN,
}, {
.name = "mvf600-fec",
.driver_data = FEC_QUIRK_ENET_MAC,
@@ -316,13 +306,16 @@ static void fec_dump(struct net_device *ndev)
for (index = 0; index < fep->tx_ring_size; index++) {
bdp = fec_enet_tx_get(index, fep);
- pr_info("%3u %c%c 0x%04x 0x%08lx %4u %p\n",
+ pr_info("%3u %c%c 0x%04x 0x%08lx %4u %p",
index,
index == fep->tx_next ? 'S' : ' ',
index == fep->tx_dirty ? 'H' : ' ',
bdp->bd.cbd_sc, bdp->bd.cbd_bufaddr,
bdp->bd.cbd_datlen,
fep->tx_skbuff[index]);
+ if (fep->flags & FEC_FLAG_BUFDESC_EX)
+ pr_cont(" %08lx", bdp->ebd.cbd_esc);
+ pr_cont("\n");
}
}
@@ -877,13 +870,14 @@ fec_enet_tx(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
union bufdesc_u *bdp;
- unsigned short status;
struct sk_buff *skb;
unsigned int index = fep->tx_dirty;
unsigned int pkts_compl, bytes_compl;
pkts_compl = bytes_compl = 0;
do {
+ unsigned status, cbd_esc;
+
if (++index >= fep->tx_ring_size)
index = 0;
@@ -904,25 +898,42 @@ fec_enet_tx(struct net_device *ndev)
continue;
/* Check for errors. */
- if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |
- BD_ENET_TX_RL | BD_ENET_TX_UN |
- BD_ENET_TX_CSL)) {
- ndev->stats.tx_errors++;
- if (status & BD_ENET_TX_HB) /* No heartbeat */
- ndev->stats.tx_heartbeat_errors++;
- if (status & BD_ENET_TX_LC) /* Late collision */
- ndev->stats.tx_window_errors++;
- if (status & BD_ENET_TX_RL) /* Retrans limit */
- ndev->stats.tx_aborted_errors++;
- if (status & BD_ENET_TX_UN) /* Underrun */
- ndev->stats.tx_fifo_errors++;
- if (status & BD_ENET_TX_CSL) /* Carrier lost */
- ndev->stats.tx_carrier_errors++;
+ if (fep->flags & FEC_FLAG_BUFDESC_EX) {
+ cbd_esc = bdp->ebd.cbd_esc;
+ if (cbd_esc & BD_ENET_TX_TXE) {
+ ndev->stats.tx_errors++;
+ if (cbd_esc & BD_ENET_TX_EE) { /* excess collision */
+ ndev->stats.collisions += 16;
+ ndev->stats.tx_aborted_errors++;
+ }
+ if (cbd_esc & BD_ENET_TX_LCE) /* late collision error */
+ ndev->stats.tx_window_errors++;
+ if (cbd_esc & (BD_ENET_TX_UE | BD_ENET_TX_FE | BD_ENET_TX_OE))
+ ndev->stats.tx_fifo_errors++;
+ goto next;
+ }
} else {
- ndev->stats.tx_packets++;
- ndev->stats.tx_bytes += skb->len;
+ if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |
+ BD_ENET_TX_RL | BD_ENET_TX_UN |
+ BD_ENET_TX_CSL)) {
+ ndev->stats.tx_errors++;
+ if (status & BD_ENET_TX_HB) /* No heartbeat */
+ ndev->stats.tx_heartbeat_errors++;
+ if (status & BD_ENET_TX_LC) /* Late collision */
+ ndev->stats.tx_window_errors++;
+ if (status & BD_ENET_TX_RL) /* Retrans limit */
+ ndev->stats.tx_aborted_errors++;
+ if (status & BD_ENET_TX_UN) /* Underrun */
+ ndev->stats.tx_fifo_errors++;
+ if (status & BD_ENET_TX_CSL) /* Carrier lost */
+ ndev->stats.tx_carrier_errors++;
+ goto next;
+ }
}
+ ndev->stats.tx_packets++;
+ ndev->stats.tx_bytes += skb->len;
+
if (fep->flags & FEC_FLAG_BUFDESC_EX &&
unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
struct skb_shared_hwtstamps shhwtstamps;
@@ -937,6 +948,7 @@ fec_enet_tx(struct net_device *ndev)
if (status & BD_ENET_TX_DEF)
ndev->stats.collisions++;
+ next:
pkts_compl++;
bytes_compl += skb->len;
@@ -969,7 +981,6 @@ fec_enet_rx(struct net_device *ndev, int budget)
struct fec_enet_private *fep = netdev_priv(ndev);
const struct platform_device_id *id_entry =
platform_get_device_id(fep->pdev);
- unsigned short status;
struct sk_buff *skb;
ushort pkt_len;
__u8 *data;
@@ -987,6 +998,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
*/
do {
union bufdesc_u *bdp = fec_enet_rx_get(index, fep);
+ unsigned status, cbd_esc;
status = bdp->bd.cbd_sc;
if (status & BD_ENET_RX_EMPTY)
@@ -1056,10 +1068,17 @@ fec_enet_rx(struct net_device *ndev, int budget)
if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
swap_buffer(data, pkt_len);
+ if (fep->flags & FEC_FLAG_BUFDESC_EX) {
+ cbd_esc = bdp->ebd.cbd_esc;
+ if (!(fep->flags & FEC_FLAG_RX_VLAN))
+ cbd_esc &= ~BD_ENET_RX_VLAN;
+ } else {
+ cbd_esc = 0;
+ }
+
/* If this is a VLAN packet remove the VLAN Tag */
vlan_packet_rcvd = false;
- if (fep->flags & FEC_FLAG_RX_VLAN &&
- bdp->ebd.cbd_esc & BD_ENET_RX_VLAN) {
+ if (cbd_esc & BD_ENET_RX_VLAN) {
/* Push and remove the vlan tag */
struct vlan_hdr *vlan_header =
(struct vlan_hdr *) (data + ETH_HLEN);
@@ -1096,7 +1115,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
skb_hwtstamps(skb));
if (fep->flags & FEC_FLAG_RX_CSUM) {
- if (!(bdp->ebd.cbd_esc & FLAG_RX_CSUM_ERROR)) {
+ if (!(cbd_esc & FLAG_RX_CSUM_ERROR)) {
/* don't check it */
skb->ip_summed = CHECKSUM_UNNECESSARY;
} else {