|
@@ -504,17 +504,54 @@ static int get_regs_len(struct net_device *dev)
|
|
|
}
|
|
|
|
|
|
/* Some transmit errors cause the transmitter to shut
|
|
|
- * down. We now issue a restart transmit. Since the
|
|
|
- * errors close the BD and update the pointers, the restart
|
|
|
- * _should_ pick up without having to reset any of our
|
|
|
- * pointers either. Also, To workaround 8260 device erratum
|
|
|
- * CPM37, we must disable and then re-enable the transmitter
|
|
|
- * following a Late Collision, Underrun, or Retry Limit error.
|
|
|
+ * down. We now issue a restart transmit.
|
|
|
+ * Also, to workaround 8260 device erratum CPM37, we must
|
|
|
+ * disable and then re-enable the transmitterfollowing a
|
|
|
+ * Late Collision, Underrun, or Retry Limit error.
|
|
|
+ * In addition, tbptr may point beyond BDs beyond still marked
|
|
|
+ * as ready due to internal pipelining, so we need to look back
|
|
|
+ * through the BDs and adjust tbptr to point to the last BD
|
|
|
+ * marked as ready. This may result in some buffers being
|
|
|
+ * retransmitted.
|
|
|
*/
|
|
|
static void tx_restart(struct net_device *dev)
|
|
|
{
|
|
|
struct fs_enet_private *fep = netdev_priv(dev);
|
|
|
fcc_t __iomem *fccp = fep->fcc.fccp;
|
|
|
+ const struct fs_platform_info *fpi = fep->fpi;
|
|
|
+ fcc_enet_t __iomem *ep = fep->fcc.ep;
|
|
|
+ cbd_t __iomem *curr_tbptr;
|
|
|
+ cbd_t __iomem *recheck_bd;
|
|
|
+ cbd_t __iomem *prev_bd;
|
|
|
+ cbd_t __iomem *last_tx_bd;
|
|
|
+
|
|
|
+ last_tx_bd = fep->tx_bd_base + (fpi->tx_ring * sizeof(cbd_t));
|
|
|
+
|
|
|
+ /* get the current bd held in TBPTR and scan back from this point */
|
|
|
+ recheck_bd = curr_tbptr = (cbd_t __iomem *)
|
|
|
+ ((R32(ep, fen_genfcc.fcc_tbptr) - fep->ring_mem_addr) +
|
|
|
+ fep->ring_base);
|
|
|
+
|
|
|
+ prev_bd = (recheck_bd == fep->tx_bd_base) ? last_tx_bd : recheck_bd - 1;
|
|
|
+
|
|
|
+ /* Move through the bds in reverse, look for the earliest buffer
|
|
|
+ * that is not ready. Adjust TBPTR to the following buffer */
|
|
|
+ while ((CBDR_SC(prev_bd) & BD_ENET_TX_READY) != 0) {
|
|
|
+ /* Go back one buffer */
|
|
|
+ recheck_bd = prev_bd;
|
|
|
+
|
|
|
+ /* update the previous buffer */
|
|
|
+ prev_bd = (prev_bd == fep->tx_bd_base) ? last_tx_bd : prev_bd - 1;
|
|
|
+
|
|
|
+ /* We should never see all bds marked as ready, check anyway */
|
|
|
+ if (recheck_bd == curr_tbptr)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ /* Now update the TBPTR and dirty flag to the current buffer */
|
|
|
+ W32(ep, fen_genfcc.fcc_tbptr,
|
|
|
+ (uint) (((void *)recheck_bd - fep->ring_base) +
|
|
|
+ fep->ring_mem_addr));
|
|
|
+ fep->dirty_tx = recheck_bd;
|
|
|
|
|
|
C32(fccp, fcc_gfmr, FCC_GFMR_ENT);
|
|
|
udelay(10);
|