⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fec_main.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
		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)) {			fep->stats.tx_errors++;			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++;		} else			fep->stats.tx_packets++;		if (sc & BD_ENET_TX_READY)			printk(KERN_WARNING DRV_MODULE_NAME			       ": %s HEY! Enet xmit interrupt and TX_READY.\n",			       dev->name);		/*		 * Deferred means some collisions occurred during transmit,		 * but we eventually sent the packet OK.		 */		if (sc & BD_ENET_TX_DEF)			fep->stats.collisions++;		/*		 * 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;	spin_unlock(&fep->lock);	if (do_wake && netif_queue_stopped(dev))		netif_wake_queue(dev);}/* * The interrupt handler. * This is called from the MPC core interrupt. */static irqreturn_tfec_enet_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct net_device *dev = dev_id;	struct fec_enet_private *fep;	const struct fec_platform_info *fpi;	fec_t *fecp;	__u32 int_events;	__u32 int_events_napi;	if (unlikely(dev == NULL))		return IRQ_NONE;	fep = netdev_priv(dev);	fecp = fep->fecp;	fpi = fep->fpi;	/*	 * Get the interrupt events that caused us to be here.	 */	while ((int_events = FR(fecp, ievent) & FR(fecp, imask)) != 0) {		if (!fpi->use_napi)			FW(fecp, ievent, int_events);		else {			int_events_napi = int_events & ~(FEC_ENET_RXF | FEC_ENET_RXB);			FW(fecp, ievent, int_events_napi);		}		if ((int_events & (FEC_ENET_HBERR | FEC_ENET_BABR |				   FEC_ENET_BABT | FEC_ENET_EBERR)) != 0)			printk(KERN_WARNING DRV_MODULE_NAME			       ": %s FEC ERROR(s) 0x%x\n",			       dev->name, int_events);		if ((int_events & FEC_ENET_RXF) != 0) {			if (!fpi->use_napi)				fec_enet_rx_common(dev, NULL);			else {				if (netif_rx_schedule_prep(dev)) {					/* disable rx interrupts */					FC(fecp, imask, FEC_ENET_RXF | FEC_ENET_RXB);					__netif_rx_schedule(dev);				} else {					printk(KERN_ERR DRV_MODULE_NAME					       ": %s driver bug! interrupt while in poll!\n",					       dev->name);					FC(fecp, imask, FEC_ENET_RXF | FEC_ENET_RXB);				}			}		}		if ((int_events & FEC_ENET_TXF) != 0)			fec_enet_tx(dev);	}	return IRQ_HANDLED;}/* This interrupt occurs when the PHY detects a link change. */static irqreturn_tfec_mii_link_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct net_device *dev = dev_id;	struct fec_enet_private *fep;	const struct fec_platform_info *fpi;	if (unlikely(dev == NULL))		return IRQ_NONE;	fep = netdev_priv(dev);	fpi = fep->fpi;	if (!fpi->use_mdio)		return IRQ_NONE;	/*	 * 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 fec_enet_open().	 */	if (!fep->phy)		return IRQ_NONE;	fec_mii_ack_int(dev);	fec_mii_link_status_change_check(dev, 0);	return IRQ_HANDLED;}/**********************************************************************************/static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev){	struct fec_enet_private *fep = netdev_priv(dev);	fec_t *fecp = fep->fecp;	cbd_t *bdp;	int curidx;	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 1;	}	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(NULL, 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 	 */	CBDS_SC(bdp, BD_ENET_TX_READY | BD_ENET_TX_INTR |		BD_ENET_TX_LAST | BD_ENET_TX_TC);	FW(fecp, x_des_active, 0x01000000);	spin_unlock_irqrestore(&fep->tx_lock, flags);	return 0;}static void fec_timeout(struct net_device *dev){	struct fec_enet_private *fep = netdev_priv(dev);	fep->stats.tx_errors++;	if (fep->tx_free)		netif_wake_queue(dev);	/* check link status again */	fec_mii_link_status_change_check(dev, 0);}static int fec_enet_open(struct net_device *dev){	struct fec_enet_private *fep = netdev_priv(dev);	const struct fec_platform_info *fpi = fep->fpi;	unsigned long flags;	/* Install our interrupt handler. */	if (request_irq(fpi->fec_irq, fec_enet_interrupt, 0, "fec", dev) != 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 && 		request_irq(fpi->phy_irq, fec_mii_link_interrupt, 0, "fec-phy",				dev) != 0) {		printk(KERN_ERR DRV_MODULE_NAME		       ": %s Could not allocate PHY IRQ!", dev->name);		free_irq(fpi->fec_irq, dev);		return -EINVAL;	}	if (fpi->use_mdio) {		fec_mii_startup(dev);		netif_carrier_off(dev);		fec_mii_link_status_change_check(dev, 1);	} else {		spin_lock_irqsave(&fep->lock, flags);		fec_restart(dev, 1, 100);	/* XXX this sucks */		spin_unlock_irqrestore(&fep->lock, flags);		netif_carrier_on(dev);		netif_start_queue(dev);	}	return 0;}static int fec_enet_close(struct net_device *dev){	struct fec_enet_private *fep = netdev_priv(dev);	const struct fec_platform_info *fpi = fep->fpi;	unsigned long flags;	netif_stop_queue(dev);	netif_carrier_off(dev);	if (fpi->use_mdio)		fec_mii_shutdown(dev);	spin_lock_irqsave(&fep->lock, flags);	fec_stop(dev);	spin_unlock_irqrestore(&fep->lock, flags);	/* release any irqs */	if (fpi->phy_irq != -1)		free_irq(fpi->phy_irq, dev);	free_irq(fpi->fec_irq, dev);	return 0;}static struct net_device_stats *fec_enet_get_stats(struct net_device *dev){	struct fec_enet_private *fep = netdev_priv(dev);	return &fep->stats;}static int fec_enet_poll(struct net_device *dev, int *budget){	return fec_enet_rx_common(dev, budget);}/*************************************************************************/static void fec_get_drvinfo(struct net_device *dev,			    struct ethtool_drvinfo *info){	strcpy(info->driver, DRV_MODULE_NAME);	strcpy(info->version, DRV_MODULE_VERSION);}static int fec_get_regs_len(struct net_device *dev){	return sizeof(fec_t);}static void fec_get_regs(struct net_device *dev, struct ethtool_regs *regs,			 void *p){	struct fec_enet_private *fep = netdev_priv(dev);	unsigned long flags;	if (regs->len < sizeof(fec_t))		return;	regs->version = 0;	spin_lock_irqsave(&fep->lock, flags);	memcpy_fromio(p, fep->fecp, sizeof(fec_t));	spin_unlock_irqrestore(&fep->lock, flags);}static int fec_get_settings(struct net_device *dev, struct ethtool_cmd *cmd){	struct fec_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 fec_set_settings(struct net_device *dev, struct ethtool_cmd *cmd){	struct fec_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 fec_nway_reset(struct net_device *dev){	struct fec_enet_private *fep = netdev_priv(dev);	return mii_nway_restart(&fep->mii_if);}static __u32 fec_get_msglevel(struct net_device *dev){	struct fec_enet_private *fep = netdev_priv(dev);	return fep->msg_enable;}static void fec_set_msglevel(struct net_device *dev, __u32 value){	struct fec_enet_private *fep = netdev_priv(dev);	fep->msg_enable = value;}static struct ethtool_ops fec_ethtool_ops = {	.get_drvinfo = fec_get_drvinfo,	.get_regs_len = fec_get_regs_len,	.get_settings = fec_get_settings,	.set_settings = fec_set_settings,	.nway_reset = fec_nway_reset,	.get_link = ethtool_op_get_link,	.get_msglevel = fec_get_msglevel,	.set_msglevel = fec_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 = fec_get_regs,};static int fec_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){	struct fec_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;}int fec_8xx_init_one(const struct fec_platform_info *fpi,		     struct net_device **devp){	immap_t *immap = (immap_t *) IMAP_ADDR;	static int fec_8xx_version_printed = 0;	struct net_device *dev = NULL;	struct fec_enet_private *fep = NULL;	fec_t *fecp = NULL;	int i;	int err = 0;	int registered = 0;	__u32 siel;	*devp = NULL;	switch (fpi->fec_no) {	case 0:		fecp = &((immap_t *) IMAP_ADDR)->im_cpm.cp_fec;		break;#ifdef CONFIG_DUET	case 1:		fecp = &((immap_t *) IMAP_ADDR)->im_cpm.cp_fec2;		break;#endif	default:		return -EINVAL;	}	if (fec_8xx_version_printed++ == 0)		printk(KERN_INFO "%s", version);	i = sizeof(*fep) + (sizeof(struct sk_buff **) *			    (fpi->rx_ring + fpi->tx_ring));	dev = alloc_etherdev(i);	if (!dev) {		err = -ENOMEM;		goto err;	}	SET_MODULE_OWNER(dev);	fep = netdev_priv(dev);	/* partial reset of FEC */	fec_whack_reset(fecp);	/* point rx_skbuff, tx_skbuff */	fep->rx_skbuff = (struct sk_buff **)&fep[1];	fep->tx_skbuff = fep->rx_skbuff + fpi->rx_ring;	fep->fecp = fecp;	fep->fpi = fpi;	/* init locks */	spin_lock_init(&fep->lock);	spin_lock_init(&fep->tx_lock);	/*	 * Set the Ethernet address. 	 */	for (i = 0; i < 6; i++)		dev->dev_addr[i] = fpi->macaddr[i];	fep->ring_base = dma_alloc_coherent(NULL,					    (fpi->tx_ring + fpi->rx_ring) *					    sizeof(cbd_t), &fep->ring_mem_addr,					    GFP_KERNEL);	if (fep->ring_base == NULL) {		printk(KERN_ERR DRV_MODULE_NAME		       ": %s dma alloc failed.\n", dev->name);		err = -ENOMEM;		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;	/* SIU interrupt */	if (fpi->phy_irq != -1 &&		(fpi->phy_irq >= SIU_IRQ0 && fpi->phy_irq < SIU_LEVEL7)) {		siel = in_be32(&immap->im_siu_conf.sc_siel);		if ((fpi->phy_irq & 1) == 0)			siel |= (0x80000000 >> fpi->phy_irq);		else			siel &= ~(0x80000000 >> (fpi->phy_irq & ~1));		out_be32(&immap->im_siu_conf.sc_siel, siel);	}	/*	 * The FEC Ethernet specific entries in the device structure. 	 */	dev->open = fec_enet_open;	dev->hard_start_xmit = fec_enet_start_xmit;	dev->tx_timeout = fec_timeout;	dev->watchdog_timeo = TX_TIMEOUT;	dev->stop = fec_enet_close;	dev->get_stats = fec_enet_get_stats;	dev->set_multicast_list = fec_set_multicast_list;	dev->set_mac_address = fec_set_mac_address;	if (fpi->use_napi) {		dev->poll = fec_enet_poll;		dev->weight = fpi->napi_weight;	}	dev->ethtool_ops = &fec_ethtool_ops;	dev->do_ioctl = fec_ioctl;	fep->fec_phy_speed =	    ((((fpi->sys_clk + 4999999) / 2500000) / 2) & 0x3F) << 1;	init_timer(&fep->phy_timer_list);	/* partial reset of FEC so that only MII works */	FW(fecp, mii_speed, fep->fec_phy_speed);	FW(fecp, ievent, 0xffc0);	FW(fecp, ivec, (fpi->fec_irq / 2) << 29);	FW(fecp, imask, 0);	FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE);	/* MII enable */	FW(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);	netif_carrier_off(dev);	err = register_netdev(dev);	if (err != 0)		goto err;	registered = 1;	if (fpi->use_mdio) {		fep->mii_if.dev = dev;		fep->mii_if.mdio_read = fec_mii_read;		fep->mii_if.mdio_write = fec_mii_write;		fep->mii_if.phy_id_mask = 0x1f;		fep->mii_if.reg_num_mask = 0x1f;		fep->mii_if.phy_id = fec_mii_phy_id_detect(dev);	}	*devp = dev;	return 0;      err:	if (dev != NULL) {		if (fecp != NULL)			fec_whack_reset(fecp);		if (registered)			unregister_netdev(dev);		if (fep != NULL) {			if (fep->ring_base)				dma_free_coherent(NULL,						  (fpi->tx_ring +						   fpi->rx_ring) *						  sizeof(cbd_t), fep->ring_base,						  fep->ring_mem_addr);		}		free_netdev(dev);	}	return err;}int fec_8xx_cleanup_one(struct net_device *dev){	struct fec_enet_private *fep = netdev_priv(dev);	fec_t *fecp = fep->fecp;	const struct fec_platform_info *fpi = fep->fpi;	fec_whack_reset(fecp);	unregister_netdev(dev);	dma_free_coherent(NULL, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t),			  fep->ring_base, fep->ring_mem_addr);	free_netdev(dev);	return 0;}/**************************************************************************************//**************************************************************************************//**************************************************************************************/static int __init fec_8xx_init(void){	return fec_8xx_platform_init();}static void __exit fec_8xx_cleanup(void){	fec_8xx_platform_cleanup();}/**************************************************************************************//**************************************************************************************//**************************************************************************************/module_init(fec_8xx_init);module_exit(fec_8xx_cleanup);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -