fs_enet-main.c
来自「linux 内核源代码」· C语言 代码 · 共 1,528 行 · 第 1/3 页
C
1,528 行
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; } 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); }}void fs_cleanup_bds(struct net_device *dev){ struct fs_enet_private *fep = netdev_priv(dev); struct sk_buff *skb; cbd_t __iomem *bdp; int i; /* * Reset SKB transmit buffers. */ for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) { if ((skb = fep->tx_skbuff[i]) == NULL) continue; /* unmap */ dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), skb->len, DMA_TO_DEVICE); fep->tx_skbuff[i] = NULL; dev_kfree_skb(skb); } /* * Reset SKB receive buffers */ for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) { if ((skb = fep->rx_skbuff[i]) == NULL) continue; /* unmap */ dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), DMA_FROM_DEVICE); fep->rx_skbuff[i] = NULL; dev_kfree_skb(skb); }}/**********************************************************************************/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; 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;}static int fs_request_irq(struct net_device *dev, int irq, const char *name, irq_handler_t irqf){ struct fs_enet_private *fep = netdev_priv(dev); (*fep->ops->pre_request_irq)(dev, irq); return request_irq(irq, irqf, IRQF_SHARED, name, dev);}static void fs_free_irq(struct net_device *dev, int irq){ struct fs_enet_private *fep = netdev_priv(dev); free_irq(irq, dev); (*fep->ops->post_free_irq)(dev, irq);}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) { phy_stop(fep->phydev); (*fep->ops->stop)(dev); (*fep->ops->restart)(dev); phy_start(fep->phydev); } phy_start(fep->phydev); 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);}/*----------------------------------------------------------------------------- * generic link-change handler - should be sufficient for most cases *-----------------------------------------------------------------------------*/static void generic_adjust_link(struct net_device *dev){ struct fs_enet_private *fep = netdev_priv(dev); struct phy_device *phydev = fep->phydev; int new_state = 0; if (phydev->link) { /* adjust to duplex mode */ if (phydev->duplex != fep->oldduplex) { new_state = 1; fep->oldduplex = phydev->duplex; } if (phydev->speed != fep->oldspeed) { new_state = 1; fep->oldspeed = phydev->speed; } if (!fep->oldlink) { new_state = 1; fep->oldlink = 1; netif_schedule(dev); netif_carrier_on(dev); netif_start_queue(dev); } if (new_state) fep->ops->restart(dev); } else if (fep->oldlink) { new_state = 1; fep->oldlink = 0; fep->oldspeed = 0; fep->oldduplex = -1; netif_carrier_off(dev); netif_stop_queue(dev); } if (new_state && netif_msg_link(fep)) phy_print_status(phydev);}static void fs_adjust_link(struct net_device *dev){ struct fs_enet_private *fep = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&fep->lock, flags); if(fep->ops->adjust_link) fep->ops->adjust_link(dev); else generic_adjust_link(dev); spin_unlock_irqrestore(&fep->lock, flags);}static int fs_init_phy(struct net_device *dev){ struct fs_enet_private *fep = netdev_priv(dev); struct phy_device *phydev; fep->oldlink = 0; fep->oldspeed = 0; fep->oldduplex = -1; if(fep->fpi->bus_id) phydev = phy_connect(dev, fep->fpi->bus_id, &fs_adjust_link, 0, PHY_INTERFACE_MODE_MII); else { printk("No phy bus ID specified in BSP code\n"); return -EINVAL; } if (IS_ERR(phydev)) { printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); return PTR_ERR(phydev); } fep->phydev = phydev; return 0;}static int fs_enet_open(struct net_device *dev){ struct fs_enet_private *fep = netdev_priv(dev); int r; int err; if (fep->fpi->use_napi) napi_enable(&fep->napi); /* Install our interrupt handler. */ r = fs_request_irq(dev, fep->interrupt, "fs_enet-mac", fs_enet_interrupt); if (r != 0) { printk(KERN_ERR DRV_MODULE_NAME ": %s Could not allocate FS_ENET IRQ!", dev->name); if (fep->fpi->use_napi) napi_disable(&fep->napi); return -EINVAL; } err = fs_init_phy(dev); if (err) { if (fep->fpi->use_napi) napi_disable(&fep->napi); return err; } phy_start(fep->phydev); return 0;}static int fs_enet_close(struct net_device *dev){ struct fs_enet_private *fep = netdev_priv(dev); unsigned long flags; netif_stop_queue(dev); netif_carrier_off(dev); napi_disable(&fep->napi); phy_stop(fep->phydev); spin_lock_irqsave(&fep->lock, flags); spin_lock(&fep->tx_lock); (*fep->ops->stop)(dev); spin_unlock(&fep->tx_lock); spin_unlock_irqrestore(&fep->lock, flags); /* release any irqs */ phy_disconnect(fep->phydev); fep->phydev = NULL; fs_free_irq(dev, fep->interrupt); return 0;}static struct net_device_stats *fs_enet_get_stats(struct net_device *dev){ struct fs_enet_private *fep = netdev_priv(dev); return &fep->stats;}/*************************************************************************/static void fs_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){ strcpy(info->driver, DRV_MODULE_NAME); strcpy(info->version, DRV_MODULE_VERSION);}static int fs_get_regs_len(struct net_device *dev){ struct fs_enet_private *fep = netdev_priv(dev); return (*fep->ops->get_regs_len)(dev);}static void fs_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p){ struct fs_enet_private *fep = netdev_priv(dev); unsigned long flags; int r, len; len = regs->len; spin_lock_irqsave(&fep->lock, flags); r = (*fep->ops->get_regs)(dev, p, &len); spin_unlock_irqrestore(&fep->lock, flags); if (r == 0) regs->version = 0;}static int fs_get_settings(struct net_device *dev, struct ethtool_cmd *cmd){ struct fs_enet_private *fep = netdev_priv(dev); if (!fep->phydev) return -ENODEV; return phy_ethtool_gset(fep->phydev, cmd);}static int fs_set_settings(struct net_device *dev, struct ethtool_cmd *cmd){ struct fs_enet_private *fep = netdev_priv(dev); if (!fep->phydev) return -ENODEV; return phy_ethtool_sset(fep->phydev, cmd);}static int fs_nway_reset(struct net_device *dev){ return 0;}static u32 fs_get_msglevel(struct net_device *dev){ struct fs_enet_private *fep = netdev_priv(dev); return fep->msg_enable;}static void fs_set_msglevel(struct net_device *dev, u32 value){ struct fs_enet_private *fep = netdev_priv(dev); fep->msg_enable = value;}static const struct ethtool_ops fs_ethtool_ops = { .get_drvinfo = fs_get_drvinfo, .get_regs_len = fs_get_regs_len, .get_settings = fs_get_settings, .set_settings = fs_set_settings, .nway_reset = fs_nway_reset, .get_link = ethtool_op_get_link, .get_msglevel = fs_get_msglevel, .set_msglevel = fs_set_msglevel, .set_tx_csum = ethtool_op_set_tx_csum, /* local! */ .set_sg = ethtool_op_set_sg, .get_regs = fs_get_regs,};static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){ struct fs_enet_private *fep = netdev_priv(dev); struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&rq->ifr_data; unsigned long flags; int rc; if (!netif_running(dev)) return -EINVAL; spin_lock_irqsave(&fep->lock, flags); rc = phy_mii_ioctl(fep->phydev, mii, cmd); spin_unlock_irqrestore(&fep->lock, flags); return rc;}extern int fs_mii_connect(struct net_device *dev);extern void fs_mii_disconnect(struct net_device *dev);#ifndef CONFIG_PPC_CPM_NEW_BINDINGstatic struct net_device *fs_init_instance(struct device *dev, struct fs_platform_info *fpi){ struct net_device *ndev = NULL; struct fs_enet_private *fep = NULL; int privsize, i, r, err = 0, registered = 0; fpi->fs_no = fs_get_id(fpi); /* guard */ if ((unsigned int)fpi->fs_no >= FS_MAX_INDEX) return ERR_PTR(-EINVAL); privsize = sizeof(*fep) + (sizeof(struct sk_buff **) * (fpi->rx_ring + fpi->tx_ring)); ndev = alloc_etherdev(privsize); if (!ndev) { err = -ENOMEM; goto err; } fep = netdev_priv(ndev); fep->dev = dev; dev_set_drvdata(dev, ndev); fep->fpi = fpi; if (fpi->init_ioports) fpi->init_ioports((struct fs_platform_info *)fpi);#ifdef CONFIG_FS_ENET_HAS_FEC if (fs_get_fec_index(fpi->fs_no) >= 0) fep->ops = &fs_fec_ops;#endif#ifdef CONFIG_FS_ENET_HAS_SCC if (fs_get_scc_index(fpi->fs_no) >=0) fep->ops = &fs_scc_ops;#endif#ifdef CONFIG_FS_ENET_HAS_FCC if (fs_get_fcc_index(fpi->fs_no) >= 0) fep->ops = &fs_fcc_ops;#endif if (fep->ops == NULL) { printk(KERN_ERR DRV_MODULE_NAME ": %s No matching ops found (%d).\n", ndev->name, fpi->fs_no); err = -EINVAL; goto err; } r = (*fep->ops->setup_data)(ndev); if (r != 0) { printk(KERN_ERR DRV_MODULE_NAME ": %s setup_data failed\n",
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?