/* Some transmit errors cause the transmitter to shut * 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); S32(fccp, fcc_gfmr, FCC_GFMR_ENT); fcc_cr_cmd(fep, CPM_CR_RESTART_TX); }
static void fs_timeout(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); unsigned long flags; int wake = 0; fep->stats.tx_errors++; spin_lock_irqsave(&fep->lock, flags); if (dev->flags & IFF_UP) { (*fep->ops->stop)(dev); (*fep->ops->restart)(dev); } wake = fep->tx_free && !(CBDR_SC(fep->cur_tx) & BD_ENET_TX_READY); spin_unlock_irqrestore(&fep->lock, flags); if (wake) netif_wake_queue(dev); }
/* NAPI receive function */ static int fs_enet_rx_napi(struct napi_struct *napi, int budget) { struct fs_enet_private *fep = container_of(napi, struct fs_enet_private, napi); struct net_device *dev = fep->ndev; const struct fs_platform_info *fpi = fep->fpi; cbd_t __iomem *bdp; struct sk_buff *skb, *skbn, *skbt; int received = 0; u16 pkt_len, sc; int curidx; if (budget <= 0) return received; /* * First, grab all of the stats for the incoming packet. * These get messed up if we get called due to a busy condition. */ bdp = fep->cur_rx; /* clear RX status bits for napi*/ (*fep->ops->napi_clear_rx_event)(dev); while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) { curidx = bdp - fep->rx_bd_base; /* * Since we have allocated space to hold a complete frame, * the last indicator should be set. */ if ((sc & BD_ENET_RX_LAST) == 0) dev_warn(fep->dev, "rcv is not +last\n"); /* * Check for errors. */ if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL | BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { fep->stats.rx_errors++; /* Frame too long or too short. */ if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) fep->stats.rx_length_errors++; /* Frame alignment */ if (sc & (BD_ENET_RX_NO | BD_ENET_RX_CL)) fep->stats.rx_frame_errors++; /* CRC Error */ if (sc & BD_ENET_RX_CR) fep->stats.rx_crc_errors++; /* FIFO overrun */ if (sc & BD_ENET_RX_OV) fep->stats.rx_crc_errors++; skb = fep->rx_skbuff[curidx]; dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), DMA_FROM_DEVICE); skbn = skb; } else { skb = fep->rx_skbuff[curidx]; dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), DMA_FROM_DEVICE); /* * Process the incoming frame. */ fep->stats.rx_packets++; pkt_len = CBDR_DATLEN(bdp) - 4; /* remove CRC */ fep->stats.rx_bytes += pkt_len + 4; if (pkt_len <= fpi->rx_copybreak) { /* +2 to make IP header L1 cache aligned */ skbn = netdev_alloc_skb(dev, pkt_len + 2); if (skbn != NULL) { skb_reserve(skbn, 2); /* align IP header */ skb_copy_from_linear_data(skb, skbn->data, pkt_len); /* swap */ skbt = skb; skb = skbn; skbn = skbt; } } else { skbn = netdev_alloc_skb(dev, ENET_RX_FRSIZE); if (skbn) skb_align(skbn, ENET_RX_ALIGN); } if (skbn != NULL) { skb_put(skb, pkt_len); /* Make room */ skb->protocol = eth_type_trans(skb, dev); received++; netif_receive_skb(skb); } else { fep->stats.rx_dropped++; skbn = skb; } } fep->rx_skbuff[curidx] = skbn; CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skbn->data, L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), DMA_FROM_DEVICE)); CBDW_DATLEN(bdp, 0); CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY); /* * Update BD pointer to next entry. */ if ((sc & BD_ENET_RX_WRAP) == 0) bdp++; else bdp = fep->rx_bd_base; (*fep->ops->rx_bd_done)(dev); if (received >= budget) break; } fep->cur_rx = bdp; if (received < budget) { /* done */ napi_complete(napi); (*fep->ops->napi_enable_rx)(dev); } return received; }
static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); cbd_t __iomem *bdp; int curidx; u16 sc; unsigned long flags; #ifdef CONFIG_FS_ENET_MPC5121_FEC if (((unsigned long)skb->data) & 0x3) { skb = tx_skb_align_workaround(dev, skb); if (!skb) { /* * We have lost packet due to memory allocation error * in tx_skb_align_workaround(). Hopefully original * skb is still valid, so try transmit it later. */ return NETDEV_TX_BUSY; } } #endif spin_lock_irqsave(&fep->tx_lock, flags); /* * Fill in a Tx ring entry */ bdp = fep->cur_tx; if (!fep->tx_free || (CBDR_SC(bdp) & BD_ENET_TX_READY)) { netif_stop_queue(dev); spin_unlock_irqrestore(&fep->tx_lock, flags); /* * Ooops. All transmit buffers are full. Bail out. * This should not happen, since the tx queue should be stopped. */ dev_warn(fep->dev, "tx queue full!.\n"); return NETDEV_TX_BUSY; } curidx = bdp - fep->tx_bd_base; /* * Clear all of the status flags. */ CBDC_SC(bdp, BD_ENET_TX_STATS); /* * Save skb pointer. */ fep->tx_skbuff[curidx] = skb; fep->stats.tx_bytes += skb->len; /* * Push the data cache so the CPM does not get stale memory data. */ CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skb->data, skb->len, DMA_TO_DEVICE)); CBDW_DATLEN(bdp, skb->len); /* * If this was the last BD in the ring, start at the beginning again. */ if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0) fep->cur_tx++; else fep->cur_tx = fep->tx_bd_base; if (!--fep->tx_free) netif_stop_queue(dev); /* Trigger transmission start */ sc = BD_ENET_TX_READY | BD_ENET_TX_INTR | BD_ENET_TX_LAST | BD_ENET_TX_TC; /* note that while FEC does not have this bit * it marks it as available for software use * yay for hw reuse :) */ if (skb->len <= 60) sc |= BD_ENET_TX_PAD; CBDS_SC(bdp, sc); skb_tx_timestamp(skb); (*fep->ops->tx_kickstart)(dev); spin_unlock_irqrestore(&fep->tx_lock, flags); return NETDEV_TX_OK; }
static void fs_enet_tx(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); cbd_t __iomem *bdp; struct sk_buff *skb; int dirtyidx, do_wake, do_restart; u16 sc; spin_lock(&fep->tx_lock); bdp = fep->dirty_tx; do_wake = do_restart = 0; while (((sc = CBDR_SC(bdp)) & BD_ENET_TX_READY) == 0) { dirtyidx = bdp - fep->tx_bd_base; if (fep->tx_free == fep->tx_ring) break; skb = fep->tx_skbuff[dirtyidx]; /* * Check for errors. */ if (sc & (BD_ENET_TX_HB | BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN | BD_ENET_TX_CSL)) { if (sc & BD_ENET_TX_HB) /* No heartbeat */ fep->stats.tx_heartbeat_errors++; if (sc & BD_ENET_TX_LC) /* Late collision */ fep->stats.tx_window_errors++; if (sc & BD_ENET_TX_RL) /* Retrans limit */ fep->stats.tx_aborted_errors++; if (sc & BD_ENET_TX_UN) /* Underrun */ fep->stats.tx_fifo_errors++; if (sc & BD_ENET_TX_CSL) /* Carrier lost */ fep->stats.tx_carrier_errors++; if (sc & (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) { fep->stats.tx_errors++; do_restart = 1; } } else fep->stats.tx_packets++; if (sc & BD_ENET_TX_READY) { dev_warn(fep->dev, "HEY! Enet xmit interrupt and TX_READY.\n"); } /* * Deferred means some collisions occurred during transmit, * but we eventually sent the packet OK. */ if (sc & BD_ENET_TX_DEF) fep->stats.collisions++; /* unmap */ dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), skb->len, DMA_TO_DEVICE); /* * Free the sk buffer associated with this last transmit. */ dev_kfree_skb_irq(skb); fep->tx_skbuff[dirtyidx] = NULL; /* * Update pointer to next buffer descriptor to be transmitted. */ if ((sc & BD_ENET_TX_WRAP) == 0) bdp++; else bdp = fep->tx_bd_base; /* * Since we have freed up a buffer, the ring is no longer * full. */ if (!fep->tx_free++) do_wake = 1; } fep->dirty_tx = bdp; if (do_restart) (*fep->ops->tx_restart)(dev); spin_unlock(&fep->tx_lock); if (do_wake) netif_wake_queue(dev); }
/* NAPI receive function */ static int fs_enet_rx_napi(struct net_device *dev, int *budget) { struct fs_enet_private *fep = netdev_priv(dev); const struct fs_platform_info *fpi = fep->fpi; cbd_t *bdp; struct sk_buff *skb, *skbn, *skbt; int received = 0; u16 pkt_len, sc; int curidx; int rx_work_limit = 0; /* pacify gcc */ rx_work_limit = min(dev->quota, *budget); if (!netif_running(dev)) return 0; /* * First, grab all of the stats for the incoming packet. * These get messed up if we get called due to a busy condition. */ bdp = fep->cur_rx; /* clear RX status bits for napi*/ (*fep->ops->napi_clear_rx_event)(dev); while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) { curidx = bdp - fep->rx_bd_base; /* * Since we have allocated space to hold a complete frame, * the last indicator should be set. */ if ((sc & BD_ENET_RX_LAST) == 0) printk(KERN_WARNING DRV_MODULE_NAME ": %s rcv is not +last\n", dev->name); /* * Check for errors. */ if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL | BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { fep->stats.rx_errors++; /* Frame too long or too short. */ if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) fep->stats.rx_length_errors++; /* Frame alignment */ if (sc & (BD_ENET_RX_NO | BD_ENET_RX_CL)) fep->stats.rx_frame_errors++; /* CRC Error */ if (sc & BD_ENET_RX_CR) fep->stats.rx_crc_errors++; /* FIFO overrun */ if (sc & BD_ENET_RX_OV) fep->stats.rx_crc_errors++; skb = fep->rx_skbuff[curidx]; dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), DMA_FROM_DEVICE); skbn = skb; } else { /* napi, got packet but no quota */ if (--rx_work_limit < 0) break; skb = fep->rx_skbuff[curidx]; dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), DMA_FROM_DEVICE); /* * Process the incoming frame. */ fep->stats.rx_packets++; pkt_len = CBDR_DATLEN(bdp) - 4; /* remove CRC */ fep->stats.rx_bytes += pkt_len + 4; if (pkt_len <= fpi->rx_copybreak) { /* +2 to make IP header L1 cache aligned */ skbn = dev_alloc_skb(pkt_len + 2); if (skbn != NULL) { skb_reserve(skbn, 2); /* align IP header */ memcpy(skbn->data, skb->data, pkt_len); /* swap */ skbt = skb; skb = skbn; skbn = skbt; } } else skbn = dev_alloc_skb(ENET_RX_FRSIZE); if (skbn != NULL) { skb->dev = dev; skb_put(skb, pkt_len); /* Make room */ skb->protocol = eth_type_trans(skb, dev); received++; netif_receive_skb(skb); } else { printk(KERN_WARNING DRV_MODULE_NAME ": %s Memory squeeze, dropping packet.\n", dev->name); fep->stats.rx_dropped++; skbn = skb; } } fep->rx_skbuff[curidx] = skbn; CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skbn->data, L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), DMA_FROM_DEVICE)); CBDW_DATLEN(bdp, 0); CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY); /* * Update BD pointer to next entry. */ if ((sc & BD_ENET_RX_WRAP) == 0) bdp++; else bdp = fep->rx_bd_base; (*fep->ops->rx_bd_done)(dev); } fep->cur_rx = bdp; dev->quota -= received; *budget -= received; if (rx_work_limit < 0) return 1; /* not done */ /* done */ netif_rx_complete(dev); (*fep->ops->napi_enable_rx)(dev); return 0; }
static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); cbd_t *bdp; int curidx; u16 sc; unsigned long flags; spin_lock_irqsave(&fep->tx_lock, flags); /* * Fill in a Tx ring entry */ bdp = fep->cur_tx; if (!fep->tx_free || (CBDR_SC(bdp) & BD_ENET_TX_READY)) { netif_stop_queue(dev); spin_unlock_irqrestore(&fep->tx_lock, flags); /* * Ooops. All transmit buffers are full. Bail out. * This should not happen, since the tx queue should be stopped. */ printk(KERN_WARNING DRV_MODULE_NAME ": %s tx queue full!.\n", dev->name); return NETDEV_TX_BUSY; } curidx = bdp - fep->tx_bd_base; /* * Clear all of the status flags. */ CBDC_SC(bdp, BD_ENET_TX_STATS); /* * Save skb pointer. */ fep->tx_skbuff[curidx] = skb; fep->stats.tx_bytes += skb->len; /* * Push the data cache so the CPM does not get stale memory data. */ CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skb->data, skb->len, DMA_TO_DEVICE)); CBDW_DATLEN(bdp, skb->len); dev->trans_start = jiffies; /* * If this was the last BD in the ring, start at the beginning again. */ if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0) fep->cur_tx++; else fep->cur_tx = fep->tx_bd_base; if (!--fep->tx_free) netif_stop_queue(dev); /* Trigger transmission start */ sc = BD_ENET_TX_READY | BD_ENET_TX_INTR | BD_ENET_TX_LAST | BD_ENET_TX_TC; /* note that while FEC does not have this bit * it marks it as available for software use * yay for hw reuse :) */ if (skb->len <= 60) sc |= BD_ENET_TX_PAD; CBDS_SC(bdp, sc); (*fep->ops->tx_kickstart)(dev); spin_unlock_irqrestore(&fep->tx_lock, flags); return NETDEV_TX_OK; }