void fs_init_bds(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); cbd_t *bdp; struct sk_buff *skb; int i; fs_cleanup_bds(dev); fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; fep->tx_free = fep->tx_ring; fep->cur_rx = fep->rx_bd_base; /* * Initialize the receive buffer descriptors. */ for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) { skb = dev_alloc_skb(ENET_RX_FRSIZE); if (skb == NULL) { printk(KERN_WARNING DRV_MODULE_NAME ": %s Memory squeeze, unable to allocate skb\n", dev->name); break; } fep->rx_skbuff[i] = skb; skb->dev = dev; CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skb->data, L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), DMA_FROM_DEVICE)); CBDW_DATLEN(bdp, 0); /* zero */ CBDW_SC(bdp, BD_ENET_RX_EMPTY | ((i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP)); } /* * if we failed, fillup remainder */ for (; i < fep->rx_ring; i++, bdp++) { fep->rx_skbuff[i] = NULL; CBDW_SC(bdp, (i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP); } /* * ...and the same for transmit. */ for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) { fep->tx_skbuff[i] = NULL; CBDW_BUFADDR(bdp, 0); CBDW_DATLEN(bdp, 0); CBDW_SC(bdp, (i < fep->tx_ring - 1) ? 0 : BD_SC_WRAP); } }
void fs_init_bds(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); cbd_t __iomem *bdp; struct sk_buff *skb; int i; fs_cleanup_bds(dev); fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; fep->tx_free = fep->tx_ring; fep->cur_rx = fep->rx_bd_base; /* * Initialize the receive buffer descriptors. */ for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) { skb = netdev_alloc_skb(dev, ENET_RX_FRSIZE); if (skb == NULL) break; skb_align(skb, ENET_RX_ALIGN); fep->rx_skbuff[i] = skb; CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skb->data, L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), DMA_FROM_DEVICE)); CBDW_DATLEN(bdp, 0); /* zero */ CBDW_SC(bdp, BD_ENET_RX_EMPTY | ((i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP)); } /* * if we failed, fillup remainder */ for (; i < fep->rx_ring; i++, bdp++) { fep->rx_skbuff[i] = NULL; CBDW_SC(bdp, (i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP); } /* * ...and the same for transmit. */ for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) { fep->tx_skbuff[i] = NULL; CBDW_BUFADDR(bdp, 0); CBDW_DATLEN(bdp, 0); CBDW_SC(bdp, (i < fep->tx_ring - 1) ? 0 : BD_SC_WRAP); } }
/* 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; }
/* 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; }