3c501.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 941 行 · 第 1/2 页

C
941
字号
			while(pad--)		/* Zero fill buffer tail */				outb(0, DATAPORT);		}		outw(gp_start, GP_LOW);		/* the board reuses the same register */			if(lp->loading != 2)		{			outb(AX_XMIT, AX_CMD);		/* fire ... Trigger xmit.  */			lp->loading=0;			dev->trans_start = jiffies;			if (el_debug > 2)				printk(KERN_DEBUG " queued xmit.\n");			dev_kfree_skb (skb);			return 0;		}		/* A receive upset our load, despite our best efforts */		if(el_debug>2)			printk(KERN_DEBUG "%s: burped during tx load.\n", dev->name);		spin_lock_irqsave(&lp->lock, flags);	}	while(1);}/** * el_interrupt: * @irq: Interrupt number * @dev_id: The 3c501 that burped * @regs: Register data (surplus to our requirements) * * Handle the ether interface interrupts. The 3c501 needs a lot more  * hand holding than most cards. In particular we get a transmit interrupt * with a collision error because the board firmware isnt capable of rewinding * its own transmit buffer pointers. It can however count to 16 for us. * * On the receive side the card is also very dumb. It has no buffering to * speak of. We simply pull the packet out of its PIO buffer (which is slow) * and queue it for the kernel. Then we reset the card for the next packet. * * We sometimes get suprise interrupts late both because the SMP IRQ delivery * is message passing and because the card sometimes seems to deliver late. I * think if it is part way through a receive and the mode is changed it carries * on receiving and sends us an interrupt. We have to band aid all these cases * to get a sensible 150kbytes/second performance. Even then you want a small * TCP window. */static irqreturn_t el_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct net_device *dev = dev_id;	struct net_local *lp;	int ioaddr;	int axsr;			/* Aux. status reg. */	ioaddr = dev->base_addr;	lp = netdev_priv(dev);	spin_lock(&lp->lock);		/*	 *	What happened ?	 */	axsr = inb(AX_STATUS);	/*	 *	Log it	 */	if (el_debug > 3)		printk(KERN_DEBUG "%s: el_interrupt() aux=%#02x", dev->name, axsr);        if(lp->loading==1 && !lp->txing)        	printk(KERN_WARNING "%s: Inconsistent state loading while not in tx\n",        		dev->name);	if (lp->txing)	{    		/*    		 *	Board in transmit mode. May be loading. If we are    		 *	loading we shouldn't have got this.    		 */		int txsr = inb(TX_STATUS);		if(lp->loading==1)		{			if(el_debug > 2)			{				printk(KERN_DEBUG "%s: Interrupt while loading [", dev->name);				printk(KERN_DEBUG " txsr=%02x gp=%04x rp=%04x]\n", txsr, inw(GP_LOW),inw(RX_LOW));			}			lp->loading=2;		/* Force a reload */			spin_unlock(&lp->lock);			goto out;		}		if (el_debug > 6)			printk(KERN_DEBUG " txsr=%02x gp=%04x rp=%04x", txsr, inw(GP_LOW),inw(RX_LOW));		if ((axsr & 0x80) && (txsr & TX_READY) == 0)		{			/*			 *	FIXME: is there a logic to whether to keep on trying or			 *	reset immediately ?			 */			if(el_debug>1)				printk(KERN_DEBUG "%s: Unusual interrupt during Tx, txsr=%02x axsr=%02x"			  		" gp=%03x rp=%03x.\n", dev->name, txsr, axsr,			inw(ioaddr + EL1_DATAPTR), inw(ioaddr + EL1_RXPTR));			lp->txing = 0;			netif_wake_queue(dev);		}		else if (txsr & TX_16COLLISIONS)		{			/*			 *	Timed out			 */			if (el_debug)				printk (KERN_DEBUG "%s: Transmit failed 16 times, Ethernet jammed?\n",dev->name);			outb(AX_SYS, AX_CMD);			lp->txing = 0;			lp->stats.tx_aborted_errors++;			netif_wake_queue(dev);		}		else if (txsr & TX_COLLISION)		{			/*			 *	Retrigger xmit.			 */			if (el_debug > 6)				printk(KERN_DEBUG " retransmitting after a collision.\n");			/*			 *	Poor little chip can't reset its own start pointer			 */			outb(AX_SYS, AX_CMD);			outw(lp->tx_pkt_start, GP_LOW);			outb(AX_XMIT, AX_CMD);			lp->stats.collisions++;			spin_unlock(&lp->lock);			goto out;		}		else		{			/*			 *	It worked.. we will now fall through and receive			 */			lp->stats.tx_packets++;			if (el_debug > 6)				printk(KERN_DEBUG " Tx succeeded %s\n",		       			(txsr & TX_RDY) ? "." : "but tx is busy!");			/*			 *	This is safe the interrupt is atomic WRT itself.			 */			lp->txing = 0;			netif_wake_queue(dev);	/* In case more to transmit */		}	}	else	{    		/*    		 *	In receive mode.    		 */		int rxsr = inb(RX_STATUS);		if (el_debug > 5)			printk(KERN_DEBUG " rxsr=%02x txsr=%02x rp=%04x", rxsr, inb(TX_STATUS),inw(RX_LOW));		/*		 *	Just reading rx_status fixes most errors.		 */		if (rxsr & RX_MISSED)			lp->stats.rx_missed_errors++;		else if (rxsr & RX_RUNT)		{	/* Handled to avoid board lock-up. */			lp->stats.rx_length_errors++;			if (el_debug > 5)				printk(KERN_DEBUG " runt.\n");		}		else if (rxsr & RX_GOOD)		{			/*			 *	Receive worked.			 */			el_receive(dev);		}		else		{			/*			 *	Nothing?  Something is broken!			 */			if (el_debug > 2)				printk(KERN_DEBUG "%s: No packet seen, rxsr=%02x **resetting 3c501***\n",					dev->name, rxsr);			el_reset(dev);		}		if (el_debug > 3)			printk(KERN_DEBUG ".\n");	}	/*	 *	Move into receive mode	 */	outb(AX_RX, AX_CMD);	outw(0x00, RX_BUF_CLR);	inb(RX_STATUS);		/* Be certain that interrupts are cleared. */	inb(TX_STATUS);	spin_unlock(&lp->lock);out:	return IRQ_HANDLED;}/** * el_receive: * @dev: Device to pull the packets from * * We have a good packet. Well, not really "good", just mostly not broken. * We must check everything to see if it is good. In particular we occasionally * get wild packet sizes from the card. If the packet seems sane we PIO it * off the card and queue it for the protocol layers. */static void el_receive(struct net_device *dev){	struct net_local *lp = netdev_priv(dev);	int ioaddr = dev->base_addr;	int pkt_len;	struct sk_buff *skb;	pkt_len = inw(RX_LOW);	if (el_debug > 4)		printk(KERN_DEBUG " el_receive %d.\n", pkt_len);	if ((pkt_len < 60)  ||  (pkt_len > 1536))	{		if (el_debug)			printk(KERN_DEBUG "%s: bogus packet, length=%d\n", dev->name, pkt_len);		lp->stats.rx_over_errors++;		return;	}	/*	 *	Command mode so we can empty the buffer	 */	outb(AX_SYS, AX_CMD);	skb = dev_alloc_skb(pkt_len+2);	/*	 *	Start of frame	 */	outw(0x00, GP_LOW);	if (skb == NULL)	{		printk(KERN_INFO "%s: Memory squeeze, dropping packet.\n", dev->name);		lp->stats.rx_dropped++;		return;	}	else	{    		skb_reserve(skb,2);	/* Force 16 byte alignment */		skb->dev = dev;		/*		 *	The read increments through the bytes. The interrupt		 *	handler will fix the pointer when it returns to		 *	receive mode.		 */		insb(DATAPORT, skb_put(skb,pkt_len), pkt_len);		skb->protocol=eth_type_trans(skb,dev);		netif_rx(skb);		dev->last_rx = jiffies;		lp->stats.rx_packets++;		lp->stats.rx_bytes+=pkt_len;	}	return;}/** * el_reset: Reset a 3c501 card * @dev: The 3c501 card about to get zapped * * Even resetting a 3c501 isnt simple. When you activate reset it loses all * its configuration. You must hold the lock when doing this. The function * cannot take the lock itself as it is callable from the irq handler. */static void  el_reset(struct net_device *dev){	struct net_local *lp = netdev_priv(dev);	int ioaddr = dev->base_addr;	if (el_debug> 2)		printk(KERN_INFO "3c501 reset...");	outb(AX_RESET, AX_CMD);		/* Reset the chip */	outb(AX_LOOP, AX_CMD);		/* Aux control, irq and loopback enabled */	{		int i;		for (i = 0; i < 6; i++)	/* Set the station address. */			outb(dev->dev_addr[i], ioaddr + i);	}	outw(0, RX_BUF_CLR);		/* Set rx packet area to 0. */	outb(TX_NORM, TX_CMD);		/* tx irq on done, collision */	outb(RX_NORM, RX_CMD);		/* Set Rx commands. */	inb(RX_STATUS);			/* Clear status. */	inb(TX_STATUS);	lp->txing = 0;}/** * el1_close: * @dev: 3c501 card to shut down * * Close a 3c501 card. The IFF_UP flag has been cleared by the user via * the SIOCSIFFLAGS ioctl. We stop any further transmissions being queued, * and then disable the interrupts. Finally we reset the chip. The effects * of the rest will be cleaned up by #el1_open. Always returns 0 indicating * a success. */ static int el1_close(struct net_device *dev){	int ioaddr = dev->base_addr;	if (el_debug > 2)		printk(KERN_INFO "%s: Shutting down Ethernet card at %#x.\n", dev->name, ioaddr);	netif_stop_queue(dev);		/*	 *	Free and disable the IRQ.	 */	free_irq(dev->irq, dev);	outb(AX_RESET, AX_CMD);		/* Reset the chip */	return 0;}/** * el1_get_stats: * @dev: The card to get the statistics for * * In smarter devices this function is needed to pull statistics off the * board itself. The 3c501 has no hardware statistics. We maintain them all * so they are by definition always up to date. * * Returns the statistics for the card from the card private data */ static struct net_device_stats *el1_get_stats(struct net_device *dev){	struct net_local *lp = netdev_priv(dev);	return &lp->stats;}/** * set_multicast_list: * @dev: The device to adjust * * Set or clear the multicast filter for this adaptor to use the best-effort  * filtering supported. The 3c501 supports only three modes of filtering. * It always receives broadcasts and packets for itself. You can choose to * optionally receive all packets, or all multicast packets on top of this. */static void set_multicast_list(struct net_device *dev){	int ioaddr = dev->base_addr;	if(dev->flags&IFF_PROMISC)	{		outb(RX_PROM, RX_CMD);		inb(RX_STATUS);	}	else if (dev->mc_list || dev->flags&IFF_ALLMULTI)	{		outb(RX_MULT, RX_CMD);	/* Multicast or all multicast is the same */		inb(RX_STATUS);		/* Clear status. */	}	else	{		outb(RX_NORM, RX_CMD);		inb(RX_STATUS);	}}static void netdev_get_drvinfo(struct net_device *dev,			       struct ethtool_drvinfo *info){	strcpy(info->driver, DRV_NAME);	strcpy(info->version, DRV_VERSION);	sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);}static u32 netdev_get_msglevel(struct net_device *dev){	return debug;}static void netdev_set_msglevel(struct net_device *dev, u32 level){	debug = level;}static struct ethtool_ops netdev_ethtool_ops = {	.get_drvinfo		= netdev_get_drvinfo,	.get_msglevel		= netdev_get_msglevel,	.set_msglevel		= netdev_set_msglevel,};#ifdef MODULEstatic struct net_device *dev_3c501;MODULE_PARM(io, "i");MODULE_PARM(irq, "i");MODULE_PARM_DESC(io, "EtherLink I/O base address");MODULE_PARM_DESC(irq, "EtherLink IRQ number");/** * init_module: * * When the driver is loaded as a module this function is called. We fake up * a device structure with the base I/O and interrupt set as if it were being * called from Space.c. This minimises the extra code that would otherwise * be required. * * Returns 0 for success or -EIO if a card is not found. Returning an error * here also causes the module to be unloaded */ int init_module(void){	dev_3c501 = el1_probe(-1);	if (IS_ERR(dev_3c501))		return PTR_ERR(dev_3c501);	return 0;}/** * cleanup_module: *  * The module is being unloaded. We unhook our network device from the system * and then free up the resources we took when the card was found. */ void cleanup_module(void){	struct net_device *dev = dev_3c501;	unregister_netdev(dev);	release_region(dev->base_addr, EL1_IO_EXTENT);	free_netdev(dev);}#endif /* MODULE */MODULE_AUTHOR("Donald Becker, Alan Cox");MODULE_DESCRIPTION("Support for the ancient 3Com 3c501 ethernet card");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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