diff options
Diffstat (limited to 'drivers/net/ethernet/freescale/fec_main.c')
-rw-r--r-- | drivers/net/ethernet/freescale/fec_main.c | 38 |
1 files changed, 31 insertions, 7 deletions
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index d3ad5ea711d3..77ea0db0bbfc 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c | |||
@@ -93,6 +93,20 @@ static void set_multicast_list(struct net_device *ndev); | |||
93 | #define FEC_QUIRK_HAS_CSUM (1 << 5) | 93 | #define FEC_QUIRK_HAS_CSUM (1 << 5) |
94 | /* Controller has hardware vlan support */ | 94 | /* Controller has hardware vlan support */ |
95 | #define FEC_QUIRK_HAS_VLAN (1 << 6) | 95 | #define FEC_QUIRK_HAS_VLAN (1 << 6) |
96 | /* ENET IP errata ERR006358 | ||
97 | * | ||
98 | * If the ready bit in the transmit buffer descriptor (TxBD[R]) is previously | ||
99 | * detected as not set during a prior frame transmission, then the | ||
100 | * ENET_TDAR[TDAR] bit is cleared at a later time, even if additional TxBDs | ||
101 | * were added to the ring and the ENET_TDAR[TDAR] bit is set. This results in | ||
102 | * If the ready bit in the transmit buffer descriptor (TxBD[R]) is previously | ||
103 | * detected as not set during a prior frame transmission, then the | ||
104 | * ENET_TDAR[TDAR] bit is cleared at a later time, even if additional TxBDs | ||
105 | * were added to the ring and the ENET_TDAR[TDAR] bit is set. This results in | ||
106 | * frames not being transmitted until there is a 0-to-1 transition on | ||
107 | * ENET_TDAR[TDAR]. | ||
108 | */ | ||
109 | #define FEC_QUIRK_ERR006358 (1 << 7) | ||
96 | 110 | ||
97 | static struct platform_device_id fec_devtype[] = { | 111 | static struct platform_device_id fec_devtype[] = { |
98 | { | 112 | { |
@@ -112,7 +126,7 @@ static struct platform_device_id fec_devtype[] = { | |||
112 | .name = "imx6q-fec", | 126 | .name = "imx6q-fec", |
113 | .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | | 127 | .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | |
114 | FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | | 128 | FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | |
115 | FEC_QUIRK_HAS_VLAN, | 129 | FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358, |
116 | }, { | 130 | }, { |
117 | .name = "mvf600-fec", | 131 | .name = "mvf600-fec", |
118 | .driver_data = FEC_QUIRK_ENET_MAC, | 132 | .driver_data = FEC_QUIRK_ENET_MAC, |
@@ -275,16 +289,11 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
275 | struct fec_enet_private *fep = netdev_priv(ndev); | 289 | struct fec_enet_private *fep = netdev_priv(ndev); |
276 | const struct platform_device_id *id_entry = | 290 | const struct platform_device_id *id_entry = |
277 | platform_get_device_id(fep->pdev); | 291 | platform_get_device_id(fep->pdev); |
278 | struct bufdesc *bdp; | 292 | struct bufdesc *bdp, *bdp_pre; |
279 | void *bufaddr; | 293 | void *bufaddr; |
280 | unsigned short status; | 294 | unsigned short status; |
281 | unsigned int index; | 295 | unsigned int index; |
282 | 296 | ||
283 | if (!fep->link) { | ||
284 | /* Link is down or auto-negotiation is in progress. */ | ||
285 | return NETDEV_TX_BUSY; | ||
286 | } | ||
287 | |||
288 | /* Fill in a Tx ring entry */ | 297 | /* Fill in a Tx ring entry */ |
289 | bdp = fep->cur_tx; | 298 | bdp = fep->cur_tx; |
290 | 299 | ||
@@ -370,6 +379,15 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
370 | ebdp->cbd_esc |= BD_ENET_TX_PINS; | 379 | ebdp->cbd_esc |= BD_ENET_TX_PINS; |
371 | } | 380 | } |
372 | } | 381 | } |
382 | |||
383 | bdp_pre = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex); | ||
384 | if ((id_entry->driver_data & FEC_QUIRK_ERR006358) && | ||
385 | !(bdp_pre->cbd_sc & BD_ENET_TX_READY)) { | ||
386 | fep->delay_work.trig_tx = true; | ||
387 | schedule_delayed_work(&(fep->delay_work.delay_work), | ||
388 | msecs_to_jiffies(1)); | ||
389 | } | ||
390 | |||
373 | /* If this was the last BD in the ring, start at the beginning again. */ | 391 | /* If this was the last BD in the ring, start at the beginning again. */ |
374 | if (status & BD_ENET_TX_WRAP) | 392 | if (status & BD_ENET_TX_WRAP) |
375 | bdp = fep->tx_bd_base; | 393 | bdp = fep->tx_bd_base; |
@@ -689,6 +707,11 @@ static void fec_enet_work(struct work_struct *work) | |||
689 | fec_restart(fep->netdev, fep->full_duplex); | 707 | fec_restart(fep->netdev, fep->full_duplex); |
690 | netif_wake_queue(fep->netdev); | 708 | netif_wake_queue(fep->netdev); |
691 | } | 709 | } |
710 | |||
711 | if (fep->delay_work.trig_tx) { | ||
712 | fep->delay_work.trig_tx = false; | ||
713 | writel(0, fep->hwp + FEC_X_DES_ACTIVE); | ||
714 | } | ||
692 | } | 715 | } |
693 | 716 | ||
694 | static void | 717 | static void |
@@ -2279,4 +2302,5 @@ static struct platform_driver fec_driver = { | |||
2279 | 2302 | ||
2280 | module_platform_driver(fec_driver); | 2303 | module_platform_driver(fec_driver); |
2281 | 2304 | ||
2305 | MODULE_ALIAS("platform:"DRIVER_NAME); | ||
2282 | MODULE_LICENSE("GPL"); | 2306 | MODULE_LICENSE("GPL"); |