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

📄 eexpress.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 3 页
字号:
/* $Id: eexpress.c,v 1.1 1999/04/26 05:52:09 tb Exp $ * * Intel EtherExpress device driver for Linux * * Original version written 1993 by Donald Becker * Modularized by Pauline Middelink <middelin@polyware.iaf.nl> * Changed to support io= irq= by Alan Cox <Alan.Cox@linux.org> * Reworked 1995 by John Sullivan <js10039@cam.ac.uk> * More fixes by Philip Blundell <pjb27@cam.ac.uk> * Added the Compaq LTE  Alan Cox <alan@redhat.com> * * Note - this driver is experimental still - it has problems on faster * machines. Someone needs to sit down and go through it line by line with * a databook... *//* * The original EtherExpress driver was just about usable, but * suffered from a long startup delay, a hard limit of 16k memory * usage on the card (EtherExpress 16s have either 32k or 64k), * and random locks under load. The last was particularly annoying * and made running eXceed/W preferable to Linux/XFree. After hacking * through the driver for a couple of days, I had fixed most of the * card handling errors, at the expense of turning the code into * a complete jungle, but still hadn't tracked down the lock-ups. * I had hoped these would be an IP bug, but failed to reproduce them * under other drivers, so decided to start from scratch and rewrite * the driver cleanly. And here it is. * * It's still not quite there, but self-corrects a lot more problems. * the 'CU wedged, resetting...' message shouldn't happen at all, but * at least we recover. It still locks occasionally, any ideas welcome. * * The original startup delay experienced by some people was due to the * first ARP request for the address of the default router getting lost. * (mostly the reply we were getting back was arriving before our * hardware address was set up, or before the configuration sequence * had told the card NOT to strip of the frame header). If you a long * startup delay, you may have lost this ARP request/reply, although * the original cause has been fixed. However, it is more likely that * you've just locked under this version. * * The main changes are in the 586 initialization procedure (which was * just broken before - the EExp is a strange beasty and needs careful * handling) the receive buffer handling (we now use a non-terminating * circular list of buffers, which stops the card giving us out-of- * resources errors), and the transmit code. The driver is also more * structured, and I have tried to keep the kernel interface separate * from the hardware interface (although some routines naturally want * to do both). * * John Sullivan * * 18/5/95: * * The lock-ups seem to happen when you access card memory after a 586 * reset. This happens only 1 in 12 resets, on a random basis, and * completely locks the machine. As far as I can see there is no * workaround possible - the only thing to be done is make sure we * never reset the card *after* booting the kernel - once at probe time * must be sufficient, and we'll just have to put up with that failing * occasionally (or buy a new NIC). By the way, this looks like a  * definite card bug, since Intel's own driver for DOS does exactly the * same. * * This bug makes switching in and out of promiscuous mode a risky * business, since we must do a 586 reset each time. *//* * Sources: * * The original eexpress.c by Donald Becker *   Sources: the Crynwr EtherExpress driver source. *            the Intel Microcommunications Databook Vol.1 1990 * * wavelan.c and i82586.h *   This was invaluable for the complete '586 configuration details *   and command format. * * The Crynwr sources (again) *   Not as useful as the Wavelan driver, but then I had eexpress.c to *   go off. * * The Intel EtherExpress 16 ethernet card *   Provided the only reason I want to see a working etherexpress driver. *   A lot of fixes came from just observing how the card (mis)behaves when *   you prod it. * */static char version[] = "eexpress.c: v0.10 04-May-95 John Sullivan <js10039@cam.ac.uk>\n""            v0.14 19-May-96 Philip Blundell <phil@tazenda.demon.co.uk>\n""            v0.15 04-Aug-98 Alan Cox <alan@redhat.com>\n";#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/interrupt.h>#include <linux/ptrace.h>#include <linux/ioport.h>#include <linux/string.h>#include <linux/in.h>#include <asm/system.h>#include <asm/bitops.h>#include <asm/io.h>#include <asm/dma.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/malloc.h>/* * Not actually used yet - may be implemented when the driver has * been debugged! * * Debug Level		Driver Status *	0		Final release *	1		Beta test *	2 *	3 * 	4		Report timeouts & 586 errors (normal debug level) *	5		Report all major events *	6		Dump sent/received packet contents *	7		Report function entry/exit */#ifndef NET_DEBUG#define NET_DEBUG 4#endifstatic unsigned int net_debug = NET_DEBUG;#undef F_DEB#include "eth82586.h"#define PRIV(x)         ((struct net_local *)(x)->priv)#define EEXP_IO_EXTENT  16/* * Private data declarations */struct net_local {	struct enet_statistics stats;	unsigned long init_time;        /* jiffies when eexp_hw_init586 called */	unsigned short rx_first;        /* first rx buf, same as RX_BUF_START */	unsigned short rx_last;         /* last rx buf */	unsigned short tx_head;         /* next free tx buf */	unsigned short tx_reap;         /* first in-use tx buf */	unsigned short tx_tail;         /* previous tx buf to tx_head */	unsigned short tx_link;         /* last known-executing tx buf */	unsigned short last_tx_restart; /* set to tx_link when we restart the CU */	unsigned char started;	unsigned char promisc;	unsigned short rx_buf_start;	unsigned short rx_buf_end;	unsigned short num_tx_bufs;	unsigned short num_rx_bufs;};unsigned short start_code[] = {	0x0000,                 /* SCP: set bus to 16 bits */	0x0000,0x0000,          /* junk */	0x0000,0x0000,          /* address of ISCP (lo,hi) */	0x0001,                 /* ISCP: busy - cleared after reset */	0x0008,0x0000,0x0000,   /* offset,address (lo,hi) of SCB */	0x0000,0x0000,          /* SCB: status, commands */	0x0000,0x0000,          /* links to first command block, first receive descriptor */	0x0000,0x0000,          /* CRC error, alignment error counts */	0x0000,0x0000,          /* out of resources, overrun error counts */	0x0000,0x0000,          /* pad */	0x0000,0x0000,	0x0000,Cmd_Config,      /* startup configure sequence, at 0x0020 */	0x0032,                 /* link to next command */	0x080c,                 /* 12 bytes follow : fifo threshold=8 */	0x2e40,                 /* don't rx bad frames : SRDY/ARDY => ext. sync. : preamble len=8	                         * take addresses from data buffers : 6 bytes/address */	0x6000,                 /* default backoff method & priority : interframe spacing = 0x60 */	0xf200,                 /* slot time=0x200 : max collision retry = 0xf */	0x0000,                 /* no HDLC : normal CRC : enable broadcast : disable promiscuous/multicast modes */	0x003c,                 /* minimum frame length = 60 octets) */	0x0000,Cmd_INT|Cmd_SetAddr,	0x003e,                 /* link to next command */	0x0000,0x0000,0x0000,   /* hardware address placed here, 0x0038 */	0x0000,Cmd_END|Cmd_Nop, /* end of configure sequence */	0x003e,	0x0000};#define CONF_LINK 0x0020#define CONF_HW_ADDR 0x0038/* maps irq number to EtherExpress magic value */static char irqrmap[] = { 0,0,1,2,3,4,0,0,0,1,5,6,0,0,0,0 };/* * Prototypes for Linux interface */extern int                  express_probe(struct device *dev);static int                     eexp_open (struct device *dev);static int                     eexp_close(struct device *dev);static struct enet_statistics *eexp_stats(struct device *dev);static int                     eexp_xmit (struct sk_buff *buf, struct device *dev);static void                    eexp_irq  (int irq, void *dev_addr, struct pt_regs *regs);static void                    eexp_set_multicast(struct device *dev);/* * Prototypes for hardware access functions */static void           eexp_hw_rx        (struct device *dev);static void           eexp_hw_tx        (struct device *dev, unsigned short *buf, unsigned short len);static int            eexp_hw_probe     (struct device *dev,unsigned short ioaddr);static unsigned short eexp_hw_readeeprom(unsigned short ioaddr, unsigned char location);static unsigned short eexp_hw_lasttxstat(struct device *dev);static void           eexp_hw_txrestart (struct device *dev);static void           eexp_hw_txinit    (struct device *dev);static void           eexp_hw_rxinit    (struct device *dev);static void           eexp_hw_init586   (struct device *dev);static void           eexp_hw_ASICrst   (struct device *dev);/* * Linux interface *//* * checks for presence of EtherExpress card */int express_probe(struct device *dev){	unsigned short *port,ports[] = { 0x0300,0x0270,0x0320,0x0340,0 };	unsigned short ioaddr = dev->base_addr;	if (ioaddr&0xfe00)		return eexp_hw_probe(dev,ioaddr);	else if (ioaddr)		return ENXIO;	for ( port=&ports[0] ; *port ; port++ ) 	{		unsigned short sum = 0;		int i;		for ( i=0 ; i<4 ; i++ ) 		{			unsigned short t;			t = inb(*port + ID_PORT);			sum |= (t>>4) << ((t & 0x03)<<2);		}		if (sum==0xbaba && !eexp_hw_probe(dev,*port)) 			return 0;	}	return ENODEV;}/* * open and initialize the adapter, ready for use */static int eexp_open(struct device *dev){	int irq = dev->irq;	unsigned short ioaddr = dev->base_addr;#if NET_DEBUG > 6	printk(KERN_DEBUG "%s: eexp_open()\n", dev->name);#endif	if (!irq || !irqrmap[irq]) 		return -ENXIO;	if (irq2dev_map[irq] ||	      /* more consistent, surely? */	   ((irq2dev_map[irq]=dev),0) ||	     request_irq(irq,&eexp_irq,0,"eexpress",NULL)) 		return -EAGAIN;	request_region(ioaddr, EEXP_IO_EXTENT, "eexpress");	dev->tbusy = 0;	dev->interrupt = 0;	eexp_hw_init586(dev);	dev->start = 1;	MOD_INC_USE_COUNT;#if NET_DEBUG > 6	printk(KERN_DEBUG "%s: leaving eexp_open()\n", dev->name);#endif	return 0;}/* * close and disable the interface, leaving * the 586 in reset */static int eexp_close(struct device *dev){	unsigned short ioaddr = dev->base_addr;	int irq = dev->irq;	dev->tbusy = 1; 	dev->start = 0;  	outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ);	PRIV(dev)->started = 0;	outw(SCB_CUsuspend|SCB_RUsuspend,ioaddr+SCB_CMD);	outb(0,ioaddr+SIGNAL_CA);	free_irq(irq,NULL);	irq2dev_map[irq] = NULL;	outb(i586_RST,ioaddr+EEPROM_Ctrl);	release_region(ioaddr,16);	MOD_DEC_USE_COUNT;	return 0;}/* * Return interface stats */static struct enet_statistics *eexp_stats(struct device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	/* 	 * Hmmm, this looks a little too easy... The card maintains	 * some stats in the SCB, and I'm not convinced we're	 * incrementing the most sensible statistics when the card	 * returns an error (esp. slow DMA, out-of-resources)	 */	return &lp->stats;}/* * Called to transmit a packet, or to allow us to right ourselves * if the kernel thinks we've died. */static int eexp_xmit(struct sk_buff *buf, struct device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	unsigned short ioaddr = dev->base_addr;#if NET_DEBUG > 6	printk(KERN_DEBUG "%s: eexp_xmit()\n", dev->name);#endif	outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);	if (dev->tbusy) 	{		/* This will happen, but hopefully not as often as when		 * tbusy==0. If it happens too much, we probably ought		 * to think about unwedging ourselves...		 */		if (test_bit(0,(void *)&PRIV(dev)->started)) 		{			if ((jiffies - dev->trans_start)>5) 			{				if (lp->tx_link==lp->last_tx_restart) 				{					unsigned short boguscount=200,rsst;					printk(KERN_WARNING "%s: Retransmit timed out, status %04x, resetting...\n",						dev->name,inw(ioaddr+SCB_STATUS));					eexp_hw_txinit(dev);					lp->last_tx_restart = 0;					outw(lp->tx_link,ioaddr+SCB_CBL);					outw(0,ioaddr+SCB_STATUS);					outw(SCB_CUstart,ioaddr+SCB_CMD);					outb(0,ioaddr+SIGNAL_CA);					while (!SCB_complete(rsst=inw(ioaddr+SCB_STATUS))) 					{						if (!--boguscount) 						{							boguscount=200;							printk(KERN_WARNING "%s: Reset timed out status %04x, retrying...\n",								dev->name,rsst);							outw(lp->tx_link,ioaddr+SCB_CBL);							outw(0,ioaddr+SCB_STATUS);							outw(SCB_CUstart,ioaddr+SCB_CMD);							outb(0,ioaddr+SIGNAL_CA);						}					}					dev->tbusy = 0;					mark_bh(NET_BH);				}				else				{					unsigned short status = inw(ioaddr+SCB_STATUS);					if (SCB_CUdead(status)) 					{						unsigned short txstatus = eexp_hw_lasttxstat(dev);						printk(KERN_WARNING "%s: Transmit timed out, CU not active status %04x %04x, restarting...\n",							dev->name, status, txstatus);						eexp_hw_txrestart(dev);					}					else					{						unsigned short txstatus = eexp_hw_lasttxstat(dev);						if (dev->tbusy && !txstatus) 						{							printk(KERN_WARNING "%s: CU wedged, status %04x %04x, resetting...\n",								dev->name,status,txstatus);							eexp_hw_init586(dev); 							dev->tbusy = 0;							mark_bh(NET_BH);						}					}				}			}		}		else

⌨️ 快捷键说明

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