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

📄 gianfar.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* gfar_clean_rx_ring() -- Processes each frame in the rx ring *   until the budget/quota has been reached. Returns the number *   of frames handled */int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit){	struct rxbd8 *bdp;	struct sk_buff *skb;	u16 pkt_len;	int howmany = 0;	struct gfar_private *priv = netdev_priv(dev);	/* Get the first full descriptor */	bdp = priv->cur_rx;	while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) {		rmb();		skb = priv->rx_skbuff[priv->skb_currx];		if (!(bdp->status &		      (RXBD_LARGE | RXBD_SHORT | RXBD_NONOCTET		       | RXBD_CRCERR | RXBD_OVERRUN | RXBD_TRUNCATED))) {			/* Increment the number of packets */			dev->stats.rx_packets++;			howmany++;			/* Remove the FCS from the packet length */			pkt_len = bdp->length - 4;			gfar_process_frame(dev, skb, pkt_len);			dev->stats.rx_bytes += pkt_len;		} else {			count_errors(bdp->status, dev);			if (skb)				dev_kfree_skb_any(skb);			priv->rx_skbuff[priv->skb_currx] = NULL;		}		dev->last_rx = jiffies;		/* Clear the status flags for this buffer */		bdp->status &= ~RXBD_STATS;		/* Add another skb for the future */		skb = gfar_new_skb(dev, bdp);		priv->rx_skbuff[priv->skb_currx] = skb;		/* Update to the next pointer */		if (bdp->status & RXBD_WRAP)			bdp = priv->rx_bd_base;		else			bdp++;		/* update to point at the next skb */		priv->skb_currx =		    (priv->skb_currx +		     1) & RX_RING_MOD_MASK(priv->rx_ring_size);	}	/* Update the current rxbd pointer to be the next one */	priv->cur_rx = bdp;	return howmany;}#ifdef CONFIG_GFAR_NAPIstatic int gfar_poll(struct napi_struct *napi, int budget){	struct gfar_private *priv = container_of(napi, struct gfar_private, napi);	struct net_device *dev = priv->dev;	int howmany;	howmany = gfar_clean_rx_ring(dev, budget);	if (howmany < budget) {		netif_rx_complete(dev, napi);		/* Clear the halt bit in RSTAT */		gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT);		gfar_write(&priv->regs->imask, IMASK_DEFAULT);		/* If we are coalescing interrupts, update the timer */		/* Otherwise, clear it */		if (priv->rxcoalescing)			gfar_write(&priv->regs->rxic,				   mk_ic_value(priv->rxcount, priv->rxtime));		else			gfar_write(&priv->regs->rxic, 0);	}	return howmany;}#endif#ifdef CONFIG_NET_POLL_CONTROLLER/* * Polling 'interrupt' - used by things like netconsole to send skbs * without having to re-enable interrupts. It's not called while * the interrupt routine is executing. */static void gfar_netpoll(struct net_device *dev){	struct gfar_private *priv = netdev_priv(dev);	/* If the device has multiple interrupts, run tx/rx */	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {		disable_irq(priv->interruptTransmit);		disable_irq(priv->interruptReceive);		disable_irq(priv->interruptError);		gfar_interrupt(priv->interruptTransmit, dev);		enable_irq(priv->interruptError);		enable_irq(priv->interruptReceive);		enable_irq(priv->interruptTransmit);	} else {		disable_irq(priv->interruptTransmit);		gfar_interrupt(priv->interruptTransmit, dev);		enable_irq(priv->interruptTransmit);	}}#endif/* The interrupt handler for devices with one interrupt */static irqreturn_t gfar_interrupt(int irq, void *dev_id){	struct net_device *dev = dev_id;	struct gfar_private *priv = netdev_priv(dev);	/* Save ievent for future reference */	u32 events = gfar_read(&priv->regs->ievent);	/* Check for reception */	if (events & IEVENT_RX_MASK)		gfar_receive(irq, dev_id);	/* Check for transmit completion */	if (events & IEVENT_TX_MASK)		gfar_transmit(irq, dev_id);	/* Check for errors */	if (events & IEVENT_ERR_MASK)		gfar_error(irq, dev_id);	return IRQ_HANDLED;}/* Called every time the controller might need to be made * aware of new link state.  The PHY code conveys this * information through variables in the phydev structure, and this * function converts those variables into the appropriate * register values, and can bring down the device if needed. */static void adjust_link(struct net_device *dev){	struct gfar_private *priv = netdev_priv(dev);	struct gfar __iomem *regs = priv->regs;	unsigned long flags;	struct phy_device *phydev = priv->phydev;	int new_state = 0;	spin_lock_irqsave(&priv->txlock, flags);	if (phydev->link) {		u32 tempval = gfar_read(&regs->maccfg2);		u32 ecntrl = gfar_read(&regs->ecntrl);		/* Now we make sure that we can be in full duplex mode.		 * If not, we operate in half-duplex mode. */		if (phydev->duplex != priv->oldduplex) {			new_state = 1;			if (!(phydev->duplex))				tempval &= ~(MACCFG2_FULL_DUPLEX);			else				tempval |= MACCFG2_FULL_DUPLEX;			priv->oldduplex = phydev->duplex;		}		if (phydev->speed != priv->oldspeed) {			new_state = 1;			switch (phydev->speed) {			case 1000:				tempval =				    ((tempval & ~(MACCFG2_IF)) | MACCFG2_GMII);				break;			case 100:			case 10:				tempval =				    ((tempval & ~(MACCFG2_IF)) | MACCFG2_MII);				/* Reduced mode distinguishes				 * between 10 and 100 */				if (phydev->speed == SPEED_100)					ecntrl |= ECNTRL_R100;				else					ecntrl &= ~(ECNTRL_R100);				break;			default:				if (netif_msg_link(priv))					printk(KERN_WARNING						"%s: Ack!  Speed (%d) is not 10/100/1000!\n",						dev->name, phydev->speed);				break;			}			priv->oldspeed = phydev->speed;		}		gfar_write(&regs->maccfg2, tempval);		gfar_write(&regs->ecntrl, ecntrl);		if (!priv->oldlink) {			new_state = 1;			priv->oldlink = 1;			netif_schedule(dev);		}	} else if (priv->oldlink) {		new_state = 1;		priv->oldlink = 0;		priv->oldspeed = 0;		priv->oldduplex = -1;	}	if (new_state && netif_msg_link(priv))		phy_print_status(phydev);	spin_unlock_irqrestore(&priv->txlock, flags);}/* Update the hash table based on the current list of multicast * addresses we subscribe to.  Also, change the promiscuity of * the device based on the flags (this function is called * whenever dev->flags is changed */static void gfar_set_multi(struct net_device *dev){	struct dev_mc_list *mc_ptr;	struct gfar_private *priv = netdev_priv(dev);	struct gfar __iomem *regs = priv->regs;	u32 tempval;	if(dev->flags & IFF_PROMISC) {		/* Set RCTRL to PROM */		tempval = gfar_read(&regs->rctrl);		tempval |= RCTRL_PROM;		gfar_write(&regs->rctrl, tempval);	} else {		/* Set RCTRL to not PROM */		tempval = gfar_read(&regs->rctrl);		tempval &= ~(RCTRL_PROM);		gfar_write(&regs->rctrl, tempval);	}	if(dev->flags & IFF_ALLMULTI) {		/* Set the hash to rx all multicast frames */		gfar_write(&regs->igaddr0, 0xffffffff);		gfar_write(&regs->igaddr1, 0xffffffff);		gfar_write(&regs->igaddr2, 0xffffffff);		gfar_write(&regs->igaddr3, 0xffffffff);		gfar_write(&regs->igaddr4, 0xffffffff);		gfar_write(&regs->igaddr5, 0xffffffff);		gfar_write(&regs->igaddr6, 0xffffffff);		gfar_write(&regs->igaddr7, 0xffffffff);		gfar_write(&regs->gaddr0, 0xffffffff);		gfar_write(&regs->gaddr1, 0xffffffff);		gfar_write(&regs->gaddr2, 0xffffffff);		gfar_write(&regs->gaddr3, 0xffffffff);		gfar_write(&regs->gaddr4, 0xffffffff);		gfar_write(&regs->gaddr5, 0xffffffff);		gfar_write(&regs->gaddr6, 0xffffffff);		gfar_write(&regs->gaddr7, 0xffffffff);	} else {		int em_num;		int idx;		/* zero out the hash */		gfar_write(&regs->igaddr0, 0x0);		gfar_write(&regs->igaddr1, 0x0);		gfar_write(&regs->igaddr2, 0x0);		gfar_write(&regs->igaddr3, 0x0);		gfar_write(&regs->igaddr4, 0x0);		gfar_write(&regs->igaddr5, 0x0);		gfar_write(&regs->igaddr6, 0x0);		gfar_write(&regs->igaddr7, 0x0);		gfar_write(&regs->gaddr0, 0x0);		gfar_write(&regs->gaddr1, 0x0);		gfar_write(&regs->gaddr2, 0x0);		gfar_write(&regs->gaddr3, 0x0);		gfar_write(&regs->gaddr4, 0x0);		gfar_write(&regs->gaddr5, 0x0);		gfar_write(&regs->gaddr6, 0x0);		gfar_write(&regs->gaddr7, 0x0);		/* If we have extended hash tables, we need to		 * clear the exact match registers to prepare for		 * setting them */		if (priv->extended_hash) {			em_num = GFAR_EM_NUM + 1;			gfar_clear_exact_match(dev);			idx = 1;		} else {			idx = 0;			em_num = 0;		}		if(dev->mc_count == 0)			return;		/* Parse the list, and set the appropriate bits */		for(mc_ptr = dev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) {			if (idx < em_num) {				gfar_set_mac_for_addr(dev, idx,						mc_ptr->dmi_addr);				idx++;			} else				gfar_set_hash_for_addr(dev, mc_ptr->dmi_addr);		}	}	return;}/* Clears each of the exact match registers to zero, so they * don't interfere with normal reception */static void gfar_clear_exact_match(struct net_device *dev){	int idx;	u8 zero_arr[MAC_ADDR_LEN] = {0,0,0,0,0,0};	for(idx = 1;idx < GFAR_EM_NUM + 1;idx++)		gfar_set_mac_for_addr(dev, idx, (u8 *)zero_arr);}/* Set the appropriate hash bit for the given addr *//* The algorithm works like so: * 1) Take the Destination Address (ie the multicast address), and * do a CRC on it (little endian), and reverse the bits of the * result. * 2) Use the 8 most significant bits as a hash into a 256-entry * table.  The table is controlled through 8 32-bit registers: * gaddr0-7.  gaddr0's MSB is entry 0, and gaddr7's LSB is * gaddr7.  This means that the 3 most significant bits in the * hash index which gaddr register to use, and the 5 other bits * indicate which bit (assuming an IBM numbering scheme, which * for PowerPC (tm) is usually the case) in the register holds * the entry. */static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr){	u32 tempval;	struct gfar_private *priv = netdev_priv(dev);	u32 result = ether_crc(MAC_ADDR_LEN, addr);	int width = priv->hash_width;	u8 whichbit = (result >> (32 - width)) & 0x1f;	u8 whichreg = result >> (32 - width + 5);	u32 value = (1 << (31-whichbit));	tempval = gfar_read(priv->hash_regs[whichreg]);	tempval |= value;	gfar_write(priv->hash_regs[whichreg], tempval);	return;}/* There are multiple MAC Address register pairs on some controllers * This function sets the numth pair to a given address */static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr){	struct gfar_private *priv = netdev_priv(dev);	int idx;	char tmpbuf[MAC_ADDR_LEN];	u32 tempval;	u32 __iomem *macptr = &priv->regs->macstnaddr1;	macptr += num*2;	/* Now copy it into the mac registers backwards, cuz */	/* little endian is silly */	for (idx = 0; idx < MAC_ADDR_LEN; idx++)		tmpbuf[MAC_ADDR_LEN - 1 - idx] = addr[idx];	gfar_write(macptr, *((u32 *) (tmpbuf)));	tempval = *((u32 *) (tmpbuf + 4));	gfar_write(macptr+1, tempval);}/* GFAR error interrupt handler */static irqreturn_t gfar_error(int irq, void *dev_id){	struct net_device *dev = dev_id;	struct gfar_private *priv = netdev_priv(dev);	/* Save ievent for future reference */	u32 events = gfar_read(&priv->regs->ievent);	/* Clear IEVENT */	gfar_write(&priv->regs->ievent, IEVENT_ERR_MASK);	/* Hmm... */	if (netif_msg_rx_err(priv) || netif_msg_tx_err(priv))		printk(KERN_DEBUG "%s: error interrupt (ievent=0x%08x imask=0x%08x)\n",		       dev->name, events, gfar_read(&priv->regs->imask));	/* Update the error counters */	if (events & IEVENT_TXE) {		dev->stats.tx_errors++;		if (events & IEVENT_LC)			dev->stats.tx_window_errors++;		if (events & IEVENT_CRL)			dev->stats.tx_aborted_errors++;		if (events & IEVENT_XFUN) {			if (netif_msg_tx_err(priv))				printk(KERN_DEBUG "%s: TX FIFO underrun, "				       "packet dropped.\n", dev->name);			dev->stats.tx_dropped++;			priv->extra_stats.tx_underrun++;			/* Reactivate the Tx Queues */			gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT);		}		if (netif_msg_tx_err(priv))			printk(KERN_DEBUG "%s: Transmit Error\n", dev->name);	}	if (events & IEVENT_BSY) {		dev->stats.rx_errors++;		priv->extra_stats.rx_bsy++;		gfar_receive(irq, dev_id);#ifndef CONFIG_GFAR_NAPI		/* Clear the halt bit in RSTAT */		gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT);#endif		if (netif_msg_rx_err(priv))			printk(KERN_DEBUG "%s: busy error (rstat: %x)\n",			       dev->name, gfar_read(&priv->regs->rstat));	}	if (events & IEVENT_BABR) {		dev->stats.rx_errors++;		priv->extra_stats.rx_babr++;		if (netif_msg_rx_err(priv))			printk(KERN_DEBUG "%s: babbling RX error\n", dev->name);	}	if (events & IEVENT_EBERR) {		priv->extra_stats.eberr++;		if (netif_msg_rx_err(priv))			printk(KERN_DEBUG "%s: bus error\n", dev->name);	}	if ((events & IEVENT_RXC) && netif_msg_rx_status(priv))		printk(KERN_DEBUG "%s: control frame\n", dev->name);	if (events & IEVENT_BABT) {		priv->extra_stats.tx_babt++;		if (netif_msg_tx_err(priv))			printk(KERN_DEBUG "%s: babbling TX error\n", dev->name);	}	return IRQ_HANDLED;}/* Structure for a device driver */static struct platform_driver gfar_driver = {	.probe = gfar_probe,	.remove = gfar_remove,	.driver	= {		.name = "fsl-gianfar",	},};static int __init gfar_init(void){	int err = gfar_mdio_init();	if (err)		return err;	err = platform_driver_register(&gfar_driver);	if (err)		gfar_mdio_exit();	return err;}static void __exit gfar_exit(void){	platform_driver_unregister(&gfar_driver);	gfar_mdio_exit();}module_init(gfar_init);module_exit(gfar_exit);

⌨️ 快捷键说明

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