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 + -
显示快捷键?