diff options
Diffstat (limited to 'drivers/net/fs_enet')
-rw-r--r-- | drivers/net/fs_enet/mac-fcc.c | 49 |
1 files changed, 43 insertions, 6 deletions
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c index 714da967fa19..0ae65a2f1ab9 100644 --- a/drivers/net/fs_enet/mac-fcc.c +++ b/drivers/net/fs_enet/mac-fcc.c | |||
@@ -504,17 +504,54 @@ static int get_regs_len(struct net_device *dev) | |||
504 | } | 504 | } |
505 | 505 | ||
506 | /* Some transmit errors cause the transmitter to shut | 506 | /* Some transmit errors cause the transmitter to shut |
507 | * down. We now issue a restart transmit. Since the | 507 | * down. We now issue a restart transmit. |
508 | * errors close the BD and update the pointers, the restart | 508 | * Also, to workaround 8260 device erratum CPM37, we must |
509 | * _should_ pick up without having to reset any of our | 509 | * disable and then re-enable the transmitterfollowing a |
510 | * pointers either. Also, To workaround 8260 device erratum | 510 | * Late Collision, Underrun, or Retry Limit error. |
511 | * CPM37, we must disable and then re-enable the transmitter | 511 | * In addition, tbptr may point beyond BDs beyond still marked |
512 | * following a Late Collision, Underrun, or Retry Limit error. | 512 | * as ready due to internal pipelining, so we need to look back |
513 | * through the BDs and adjust tbptr to point to the last BD | ||
514 | * marked as ready. This may result in some buffers being | ||
515 | * retransmitted. | ||
513 | */ | 516 | */ |
514 | static void tx_restart(struct net_device *dev) | 517 | static void tx_restart(struct net_device *dev) |
515 | { | 518 | { |
516 | struct fs_enet_private *fep = netdev_priv(dev); | 519 | struct fs_enet_private *fep = netdev_priv(dev); |
517 | fcc_t __iomem *fccp = fep->fcc.fccp; | 520 | fcc_t __iomem *fccp = fep->fcc.fccp; |
521 | const struct fs_platform_info *fpi = fep->fpi; | ||
522 | fcc_enet_t __iomem *ep = fep->fcc.ep; | ||
523 | cbd_t __iomem *curr_tbptr; | ||
524 | cbd_t __iomem *recheck_bd; | ||
525 | cbd_t __iomem *prev_bd; | ||
526 | cbd_t __iomem *last_tx_bd; | ||
527 | |||
528 | last_tx_bd = fep->tx_bd_base + (fpi->tx_ring * sizeof(cbd_t)); | ||
529 | |||
530 | /* get the current bd held in TBPTR and scan back from this point */ | ||
531 | recheck_bd = curr_tbptr = (cbd_t __iomem *) | ||
532 | ((R32(ep, fen_genfcc.fcc_tbptr) - fep->ring_mem_addr) + | ||
533 | fep->ring_base); | ||
534 | |||
535 | prev_bd = (recheck_bd == fep->tx_bd_base) ? last_tx_bd : recheck_bd - 1; | ||
536 | |||
537 | /* Move through the bds in reverse, look for the earliest buffer | ||
538 | * that is not ready. Adjust TBPTR to the following buffer */ | ||
539 | while ((CBDR_SC(prev_bd) & BD_ENET_TX_READY) != 0) { | ||
540 | /* Go back one buffer */ | ||
541 | recheck_bd = prev_bd; | ||
542 | |||
543 | /* update the previous buffer */ | ||
544 | prev_bd = (prev_bd == fep->tx_bd_base) ? last_tx_bd : prev_bd - 1; | ||
545 | |||
546 | /* We should never see all bds marked as ready, check anyway */ | ||
547 | if (recheck_bd == curr_tbptr) | ||
548 | break; | ||
549 | } | ||
550 | /* Now update the TBPTR and dirty flag to the current buffer */ | ||
551 | W32(ep, fen_genfcc.fcc_tbptr, | ||
552 | (uint) (((void *)recheck_bd - fep->ring_base) + | ||
553 | fep->ring_mem_addr)); | ||
554 | fep->dirty_tx = recheck_bd; | ||
518 | 555 | ||
519 | C32(fccp, fcc_gfmr, FCC_GFMR_ENT); | 556 | C32(fccp, fcc_gfmr, FCC_GFMR_ENT); |
520 | udelay(10); | 557 | udelay(10); |