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"); |
