📄 fs_enet-main.c
字号:
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, irqreturn_t (*irqf)(int irq, void *dev_id, struct pt_regs *regs)){ struct fs_enet_private *fep = netdev_priv(dev); (*fep->ops->pre_request_irq)(dev, irq); return request_irq(irq, irqf, SA_SHIRQ, 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);}/**********************************************************************************//* This interrupt occurs when the PHY detects a link change. */static irqreturn_tfs_mii_link_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct net_device *dev = dev_id; struct fs_enet_private *fep; const struct fs_platform_info *fpi; fep = netdev_priv(dev); fpi = fep->fpi; /* * Acknowledge the interrupt if possible. If we have not * found the PHY yet we can't process or acknowledge the * interrupt now. Instead we ignore this interrupt for now, * which we can do since it is edge triggered. It will be * acknowledged later by fs_enet_open(). */ if (!fep->phy) return IRQ_NONE; fs_mii_ack_int(dev); fs_mii_link_status_change_check(dev, 0); return IRQ_HANDLED;}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);}static int fs_enet_open(struct net_device *dev){ struct fs_enet_private *fep = netdev_priv(dev); const struct fs_platform_info *fpi = fep->fpi; int r; /* 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 FEC IRQ!", dev->name); return -EINVAL; } /* Install our phy interrupt handler */ if (fpi->phy_irq != -1) { r = fs_request_irq(dev, fpi->phy_irq, "fs_enet-phy", fs_mii_link_interrupt); if (r != 0) { printk(KERN_ERR DRV_MODULE_NAME ": %s Could not allocate PHY IRQ!", dev->name); fs_free_irq(dev, fep->interrupt); return -EINVAL; } } fs_mii_startup(dev); netif_carrier_off(dev); fs_mii_link_status_change_check(dev, 1); return 0;}static int fs_enet_close(struct net_device *dev){ struct fs_enet_private *fep = netdev_priv(dev); const struct fs_platform_info *fpi = fep->fpi; unsigned long flags; netif_stop_queue(dev); netif_carrier_off(dev); fs_mii_shutdown(dev); spin_lock_irqsave(&fep->lock, flags); (*fep->ops->stop)(dev); spin_unlock_irqrestore(&fep->lock, flags); /* release any irqs */ if (fpi->phy_irq != -1) fs_free_irq(dev, fpi->phy_irq); 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); unsigned long flags; int rc; spin_lock_irqsave(&fep->lock, flags); rc = mii_ethtool_gset(&fep->mii_if, cmd); spin_unlock_irqrestore(&fep->lock, flags); return rc;}static int fs_set_settings(struct net_device *dev, struct ethtool_cmd *cmd){ struct fs_enet_private *fep = netdev_priv(dev); unsigned long flags; int rc; spin_lock_irqsave(&fep->lock, flags); rc = mii_ethtool_sset(&fep->mii_if, cmd); spin_unlock_irqrestore(&fep->lock, flags); return rc;}static int fs_nway_reset(struct net_device *dev){ struct fs_enet_private *fep = netdev_priv(dev); return mii_nway_restart(&fep->mii_if);}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 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, .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_csum, /* local! */ .get_sg = ethtool_op_get_sg, .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 = generic_mii_ioctl(&fep->mii_if, mii, cmd, NULL); 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);static struct net_device *fs_init_instance(struct device *dev, const struct fs_platform_info *fpi){ struct net_device *ndev = NULL; struct fs_enet_private *fep = NULL; int privsize, i, r, err = 0, registered = 0; /* 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; } SET_MODULE_OWNER(ndev); fep = netdev_priv(ndev); memset(fep, 0, privsize); /* clear everything */ fep->dev = dev; dev_set_drvdata(dev, ndev); fep->fpi = fpi; if (fpi->init_ioports) fpi->init_ioports();#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", ndev->name); err = r; goto err; } /* point rx_skbuff, tx_skbuff */ fep->rx_skbuff = (struct sk_buff **)&fep[1]; fep->tx_skbuff = fep->rx_skbuff + fpi->rx_ring; /* init locks */ spin_lock_init(&fep->lock); spin_lock_init(&fep->tx_lock); /* * Set the Ethernet address. */ for (i = 0; i < 6; i++) ndev->dev_addr[i] = fpi->macaddr[i]; r = (*fep->ops->allocate_bd)(ndev); if (fep->ring_base == NULL) { printk(KERN_ERR DRV_MODULE_NAME ": %s buffer descriptor alloc failed (%d).\n", ndev->name, r); err = r; goto err; } /* * Set receive and transmit descriptor base. */ fep->rx_bd_base = fep->ring_base; fep->tx_bd_base = fep->rx_bd_base + fpi->rx_ring; /* initialize ring size variables */ fep->tx_ring = fpi->tx_ring; fep->rx_ring = fpi->rx_ring; /* * The FEC Ethernet specific entries in the device structure. */ ndev->open = fs_enet_open; ndev->hard_start_xmit = fs_enet_start_xmit; ndev->tx_timeout = fs_timeout; ndev->watchdog_timeo = 2 * HZ; ndev->stop = fs_enet_close; ndev->get_stats = fs_enet_get_stats; ndev->set_multicast_list = fs_set_multicast_list; if (fpi->use_napi) { ndev->poll = fs_enet_rx_napi; ndev->weight = fpi->napi_weight; } ndev->ethtool_ops = &fs_ethtool_ops; ndev->do_ioctl = fs_ioctl; init_timer(&fep->phy_timer_list); netif_carrier_off(ndev); err = register_netdev(ndev); if (err != 0) { printk(KERN_ERR DRV_MODULE_NAME ": %s register_netdev failed.\n", ndev->name); goto err; } registered = 1; err = fs_mii_connect(ndev); if (err != 0) { printk(KERN_ERR DRV_MODULE_NAME ": %s fs_mii_connect failed.\n", ndev->name); goto err; } return ndev; err: if (ndev != NULL) { if (registered) unregister_netdev(ndev); if (fep != NULL) { (*fep->ops->free_bd)(ndev); (*fep->ops->cleanup_data)(ndev); } free_netdev(ndev); } dev_set_drvdata(dev, NULL); return ERR_PTR(err);}static int fs_cleanup_instance(struct net_device *ndev){ struct fs_enet_private *fep; const struct fs_platform_info *fpi; struct device *dev; if (ndev == NULL) return -EINVAL; fep = netdev_priv(ndev); if (fep == NULL) return -EINVAL; fpi = fep->fpi; fs_mii_disconnect(ndev); unregister_netdev(ndev); dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), fep->ring_base, fep->ring_mem_addr); /* reset it */ (*fep->ops->cleanup_data)(ndev); dev = fep->dev; if (dev != NULL) { dev_set_drvdata(dev, NULL); fep->dev = NULL; } free_netdev(ndev); return 0;}/**************************************************************************************//* handy pointer to the immap */void *fs_enet_immap = NULL;static int setup_immap(void){ phys_addr_t paddr = 0; unsigned long size = 0;#ifdef CONFIG_CPM1 paddr = IMAP_ADDR; size = 0x10000; /* map 64K */#endif#ifdef CONFIG_CPM2 paddr = CPM_MAP_ADDR; size = 0x40000; /* map 256 K */#endif fs_enet_immap = ioremap(paddr, size); if (fs_enet_immap == NULL) return -EBADF; /* XXX ahem; maybe just BUG_ON? */ return 0;}static void cleanup_immap(void){ if (fs_enet_immap != NULL) { iounmap(fs_enet_immap); fs_enet_immap = NULL; }}/**************************************************************************************/static int __devinit fs_enet_probe(struct device *dev){ struct net_device *ndev; /* no fixup - no device */ if (dev->platform_data == NULL) { printk(KERN_INFO "fs_enet: " "probe called with no platform data; " "remove unused devices\n"); return -ENODEV; } ndev = fs_init_instance(dev, dev->platform_data); if (IS_ERR(ndev)) return PTR_ERR(ndev); return 0;}static int fs_enet_remove(struct device *dev){ return fs_cleanup_instance(dev_get_drvdata(dev));}static struct device_driver fs_enet_fec_driver = { .name = "fsl-cpm-fec", .bus = &platform_bus_type, .probe = fs_enet_probe, .remove = fs_enet_remove,#ifdef CONFIG_PM/* .suspend = fs_enet_suspend, TODO *//* .resume = fs_enet_resume, TODO */#endif};static struct device_driver fs_enet_scc_driver = { .name = "fsl-cpm-scc", .bus = &platform_bus_type, .probe = fs_enet_probe, .remove = fs_enet_remove,#ifdef CONFIG_PM/* .suspend = fs_enet_suspend, TODO *//* .resume = fs_enet_resume, TODO */#endif};static struct device_driver fs_enet_fcc_driver = { .name = "fsl-cpm-fcc", .bus = &platform_bus_type, .probe = fs_enet_probe, .remove = fs_enet_remove,#ifdef CONFIG_PM/* .suspend = fs_enet_suspend, TODO *//* .resume = fs_enet_resume, TODO */#endif};static int __init fs_init(void){ int r; printk(KERN_INFO "%s", version); r = setup_immap(); if (r != 0) return r; r = driver_register(&fs_enet_fec_driver); if (r != 0) goto err; r = driver_register(&fs_enet_fcc_driver); if (r != 0) goto err; r = driver_register(&fs_enet_scc_driver); if (r != 0) goto err; return 0;err: cleanup_immap(); return r; }static void __exit fs_cleanup(void){ driver_unregister(&fs_enet_fec_driver); driver_unregister(&fs_enet_fcc_driver); driver_unregister(&fs_enet_scc_driver); cleanup_immap();}/**************************************************************************************/module_init(fs_init);module_exit(fs_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -