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

📄 3c527.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 3 页
字号:
/* 3c527.c: 3Com Etherlink/MC32 driver for Linux 2.4 * *	(c) Copyright 1998 Red Hat Software Inc *	Written by Alan Cox.  *	Further debugging by Carl Drougge. *      Modified by Richard Procter (rnp@netlink.co.nz) * *	Based on skeleton.c written 1993-94 by Donald Becker and ne2.c *	(for the MCA stuff) written by Wim Dumon. * *	Thanks to 3Com for making this possible by providing me with the *	documentation. * *	This software may be used and distributed according to the terms *	of the GNU General Public License, incorporated herein by reference. * */#define DRV_NAME		"3c527"#define DRV_VERSION		"0.6a"#define DRV_RELDATE		"2001/11/17"static const char *version =DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Richard Proctor (rnp@netlink.co.nz)\n";/** * DOC: Traps for the unwary * *	The diagram (Figure 1-1) and the POS summary disagree with the *	"Interrupt Level" section in the manual. * *	The manual contradicts itself when describing the minimum number  *	buffers in the 'configure lists' command.  *	My card accepts a buffer config of 4/4.  * *	Setting the SAV BP bit does not save bad packets, but *	only enables RX on-card stats collection.  * *	The documentation in places seems to miss things. In actual fact *	I've always eventually found everything is documented, it just *	requires careful study. * * DOC: Theory Of Operation * *	The 3com 3c527 is a 32bit MCA bus mastering adapter with a large *	amount of on board intelligence that housekeeps a somewhat dumber *	Intel NIC. For performance we want to keep the transmit queue deep *	as the card can transmit packets while fetching others from main *	memory by bus master DMA. Transmission and reception are driven by *	circular buffer queues. * *	The mailboxes can be used for controlling how the card traverses *	its buffer rings, but are used only for inital setup in this *	implementation.  The exec mailbox allows a variety of commands to *	be executed. Each command must complete before the next is *	executed. Primarily we use the exec mailbox for controlling the *	multicast lists.  We have to do a certain amount of interesting *	hoop jumping as the multicast list changes can occur in interrupt *	state when the card has an exec command pending. We defer such *	events until the command completion interrupt. * *	A copy break scheme (taken from 3c59x.c) is employed whereby *	received frames exceeding a configurable length are passed *	directly to the higher networking layers without incuring a copy, *	in what amounts to a time/space trade-off. *	  *	The card also keeps a large amount of statistical information *	on-board. In a perfect world, these could be used safely at no *	cost. However, lacking information to the contrary, processing *	them without races would involve so much extra complexity as to *	make it unworthwhile to do so. In the end, a hybrid SW/HW *	implementation was made necessary --- see mc32_update_stats().   * * DOC: Notes *	 *	It should be possible to use two or more cards, but at this stage *	only by loading two copies of the same module. * *	The on-board 82586 NIC has trouble receiving multiple *	back-to-back frames and so is likely to drop packets from fast *	senders.**/#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/mca.h>#include <linux/ioport.h>#include <linux/in.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/ethtool.h>#include <asm/uaccess.h>#include <asm/system.h>#include <asm/bitops.h>#include <asm/io.h>#include <asm/dma.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/if_ether.h>#include "3c527.h"/* * The name of the card. Is used for messages and in the requests for * io regions, irqs and dma channels */static const char* cardname = DRV_NAME;/* use 0 for production, 1 for verification, >2 for debug */#ifndef NET_DEBUG#define NET_DEBUG 2#endif#undef DEBUG_IRQstatic unsigned int mc32_debug = NET_DEBUG;/* The number of low I/O ports used by the ethercard. */#define MC32_IO_EXTENT	8/* As implemented, values must be a power-of-2 -- 4/8/16/32 */ #define TX_RING_LEN     32       /* Typically the card supports 37  */#define RX_RING_LEN     8        /*     "       "        "          *//* Copy break point, see above for details.  * Setting to > 1512 effectively disables this feature.	*/	    #define RX_COPYBREAK    200      /* Value from 3c59x.c *//* Issue the 82586 workaround command - this is for "busy lans", but * basically means for all lans now days - has a performance (latency)  * cost, but best set. */ static const int WORKAROUND_82586=1;/* Pointers to buffers and their on-card records */struct mc32_ring_desc {	volatile struct skb_header *p;                    	struct sk_buff *skb;          };/* Information that needs to be kept for each board. */struct mc32_local {	struct net_device_stats net_stats;	int slot;	volatile struct mc32_mailbox *rx_box;	volatile struct mc32_mailbox *tx_box;	volatile struct mc32_mailbox *exec_box;        volatile struct mc32_stats *stats;    /* Start of on-card statistics */        u16 tx_chain;           /* Transmit list start offset */	u16 rx_chain;           /* Receive list start offset */        u16 tx_len;             /* Transmit list count */         u16 rx_len;             /* Receive list count */	u32 base;	u16 exec_pending;	u16 mc_reload_wait;	/* a multicast load request is pending */	u32 mc_list_valid;	/* True when the mclist is set */	u16 xceiver_state;      /* Current transceiver state. bitmapped */ 	u16 desired_state;      /* The state we want the transceiver to be in */ 	atomic_t tx_count;	/* buffers left */	wait_queue_head_t event;	struct mc32_ring_desc tx_ring[TX_RING_LEN];	/* Host Transmit ring */	struct mc32_ring_desc rx_ring[RX_RING_LEN];	/* Host Receive ring */	u16 tx_ring_tail;       /* index to tx de-queue end */	u16 tx_ring_head;       /* index to tx en-queue end */	u16 rx_ring_tail;       /* index to rx de-queue end */ };/* The station (ethernet) address prefix, used for a sanity check. */#define SA_ADDR0 0x02#define SA_ADDR1 0x60#define SA_ADDR2 0xACstruct mca_adapters_t {	unsigned int	id;	char		*name;};const struct mca_adapters_t mc32_adapters[] = {	{ 0x0041, "3COM EtherLink MC/32" },	{ 0x8EF5, "IBM High Performance Lan Adapter" },	{ 0x0000, NULL }};/* Macros for ring index manipulations */ static inline u16 next_rx(u16 rx) { return (rx+1)&(RX_RING_LEN-1); };static inline u16 prev_rx(u16 rx) { return (rx-1)&(RX_RING_LEN-1); };static inline u16 next_tx(u16 tx) { return (tx+1)&(TX_RING_LEN-1); };/* Index to functions, as function prototypes. */extern int mc32_probe(struct net_device *dev);static int	mc32_probe1(struct net_device *dev, int ioaddr);static int      mc32_command(struct net_device *dev, u16 cmd, void *data, int len);static int	mc32_open(struct net_device *dev);static void	mc32_timeout(struct net_device *dev);static int	mc32_send_packet(struct sk_buff *skb, struct net_device *dev);static void	mc32_interrupt(int irq, void *dev_id, struct pt_regs *regs);static int	mc32_close(struct net_device *dev);static struct	net_device_stats *mc32_get_stats(struct net_device *dev);static void	mc32_set_multicast_list(struct net_device *dev);static void	mc32_reset_multicast_list(struct net_device *dev);static int	netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);/** * mc32_probe 	-	Search for supported boards * @dev: device to probe * * Because MCA bus is a real bus and we can scan for cards we could do a * single scan for all boards here. Right now we use the passed in device * structure and scan for only one board. This needs fixing for modules * in paticular. */int __init mc32_probe(struct net_device *dev){	static int current_mca_slot = -1;	int i;	int adapter_found = 0;	SET_MODULE_OWNER(dev);	/* Do not check any supplied i/o locations. 	   POS registers usually don't fail :) */	/* MCA cards have POS registers.  	   Autodetecting MCA cards is extremely simple. 	   Just search for the card. */	for(i = 0; (mc32_adapters[i].name != NULL) && !adapter_found; i++) {		current_mca_slot = 			mca_find_unused_adapter(mc32_adapters[i].id, 0);		if((current_mca_slot != MCA_NOTFOUND) && !adapter_found) {			if(!mc32_probe1(dev, current_mca_slot))			{				mca_set_adapter_name(current_mca_slot, 						mc32_adapters[i].name);				mca_mark_as_used(current_mca_slot);				return 0;			}					}	}	return -ENODEV;}/** * mc32_probe1	-	Check a given slot for a board and test the card * @dev:  Device structure to fill in * @slot: The MCA bus slot being used by this card * * Decode the slot data and configure the card structures. Having done this we * can reset the card and configure it. The card does a full self test cycle * in firmware so we have to wait for it to return and post us either a  * failure case or some addresses we use to find the board internals. */static int __init mc32_probe1(struct net_device *dev, int slot){	static unsigned version_printed;	int i, err;	u8 POS;	u32 base;	struct mc32_local *lp;	static u16 mca_io_bases[]={		0x7280,0x7290,		0x7680,0x7690,		0x7A80,0x7A90,		0x7E80,0x7E90	};	static u32 mca_mem_bases[]={		0x00C0000,		0x00C4000,		0x00C8000,		0x00CC000,		0x00D0000,		0x00D4000,		0x00D8000,		0x00DC000	};	static char *failures[]={		"Processor instruction",		"Processor data bus",		"Processor data bus",		"Processor data bus",		"Adapter bus",		"ROM checksum",		"Base RAM",		"Extended RAM",		"82586 internal loopback",		"82586 initialisation failure",		"Adapter list configuration error"	};	/* Time to play MCA games */	if (mc32_debug  &&  version_printed++ == 0)		printk(KERN_DEBUG "%s", version);	printk(KERN_INFO "%s: %s found in slot %d:", dev->name, cardname, slot);	POS = mca_read_stored_pos(slot, 2);		if(!(POS&1))	{		printk(" disabled.\n");		return -ENODEV;	}	/* Fill in the 'dev' fields. */	dev->base_addr = mca_io_bases[(POS>>1)&7];	dev->mem_start = mca_mem_bases[(POS>>4)&7];		POS = mca_read_stored_pos(slot, 4);	if(!(POS&1))	{		printk("memory window disabled.\n");		return -ENODEV;	}	POS = mca_read_stored_pos(slot, 5);		i=(POS>>4)&3;	if(i==3)	{		printk("invalid memory window.\n");		return -ENODEV;	}		i*=16384;	i+=16384;		dev->mem_end=dev->mem_start + i;		dev->irq = ((POS>>2)&3)+9;		if(!request_region(dev->base_addr, MC32_IO_EXTENT, cardname))	{		printk("io 0x%3lX, which is busy.\n", dev->base_addr);		return -EBUSY;	}	printk("io 0x%3lX irq %d mem 0x%lX (%dK)\n",		dev->base_addr, dev->irq, dev->mem_start, i/1024);			/* We ought to set the cache line size here.. */			/*	 *	Go PROM browsing	 */	 	printk("%s: Address ", dev->name);	 	/* Retrieve and print the ethernet address. */	for (i = 0; i < 6; i++)	{		mca_write_pos(slot, 6, i+12);		mca_write_pos(slot, 7, 0);			printk(" %2.2x", dev->dev_addr[i] = mca_read_pos(slot,3));	}	mca_write_pos(slot, 6, 0);	mca_write_pos(slot, 7, 0);	POS = mca_read_stored_pos(slot, 4);		if(POS&2)		printk(" : BNC port selected.\n");	else 		printk(" : AUI port selected.\n");			POS=inb(dev->base_addr+HOST_CTRL);	POS|=HOST_CTRL_ATTN|HOST_CTRL_RESET;	POS&=~HOST_CTRL_INTE;	outb(POS, dev->base_addr+HOST_CTRL);	/* Reset adapter */	udelay(100);	/* Reset off */	POS&=~(HOST_CTRL_ATTN|HOST_CTRL_RESET);	outb(POS, dev->base_addr+HOST_CTRL);		udelay(300);		/*	 *	Grab the IRQ	 */	i = request_irq(dev->irq, &mc32_interrupt, SA_SHIRQ, dev->name, dev);	if (i) {		release_region(dev->base_addr, MC32_IO_EXTENT);		printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq);		return i;	}	/* Initialize the device structure. */	dev->priv = kmalloc(sizeof(struct mc32_local), GFP_KERNEL);	if (dev->priv == NULL)	{		err = -ENOMEM;		goto err_exit_irq; 	}	memset(dev->priv, 0, sizeof(struct mc32_local));	lp = dev->priv;	lp->slot = slot;	i=0;	base = inb(dev->base_addr);		while(base == 0xFF)	{		i++;		if(i == 1000)		{			printk(KERN_ERR "%s: failed to boot adapter.\n", dev->name);			err = -ENODEV; 			goto err_exit_free;		}		udelay(1000);		if(inb(dev->base_addr+2)&(1<<5))			base = inb(dev->base_addr);	}	if(base>0)	{		if(base < 0x0C)			printk(KERN_ERR "%s: %s%s.\n", dev->name, failures[base-1],				base<0x0A?" test failure":"");		else			printk(KERN_ERR "%s: unknown failure %d.\n", dev->name, base);		err = -ENODEV; 		goto err_exit_free;	}		base=0;	for(i=0;i<4;i++)	{		int n=0;			while(!(inb(dev->base_addr+2)&(1<<5)))		{			n++;			udelay(50);			if(n>100)			{				printk(KERN_ERR "%s: mailbox read fail (%d).\n", dev->name, i);				err = -ENODEV;				goto err_exit_free;			}		}		base|=(inb(dev->base_addr)<<(8*i));	}		lp->exec_box=bus_to_virt(dev->mem_start+base);		base=lp->exec_box->data[1]<<16|lp->exec_box->data[0];  		lp->base = dev->mem_start+base;		lp->rx_box=bus_to_virt(lp->base + lp->exec_box->data[2]); 	lp->tx_box=bus_to_virt(lp->base + lp->exec_box->data[3]);		lp->stats = bus_to_virt(lp->base + lp->exec_box->data[5]);	/*	 *	Descriptor chains (card relative)	 */	 	lp->tx_chain 		= lp->exec_box->data[8];   /* Transmit list start offset */	lp->rx_chain 		= lp->exec_box->data[10];  /* Receive list start offset */	lp->tx_len 		= lp->exec_box->data[9];   /* Transmit list count */ 	lp->rx_len 		= lp->exec_box->data[11];  /* Receive list count */	init_waitqueue_head(&lp->event);		printk("%s: Firmware Rev %d. %d RX buffers, %d TX buffers. Base of 0x%08X.\n",		dev->name, lp->exec_box->data[12], lp->rx_len, lp->tx_len, lp->base);	dev->open		= mc32_open;	dev->stop		= mc32_close;	dev->hard_start_xmit	= mc32_send_packet;	dev->get_stats		= mc32_get_stats;	dev->set_multicast_list = mc32_set_multicast_list;	dev->tx_timeout		= mc32_timeout;	dev->watchdog_timeo	= HZ*5;	/* Board does all the work */	dev->do_ioctl		= netdev_ioctl;		lp->xceiver_state = HALTED; 		lp->tx_ring_tail=lp->tx_ring_head=0;	/* Fill in the fields of the device structure with ethernet values. */	ether_setup(dev);		return 0;err_exit_free:	kfree(dev->priv);err_exit_irq:	free_irq(dev->irq, dev);	release_region(dev->base_addr, MC32_IO_EXTENT);	return err;}/** *	mc32_ready_poll		-	wait until we can feed it a command *	@dev:	The device to wait for *	 *	Wait until the card becomes ready to accept a command via the *	command register. This tells us nothing about the completion *	status of any pending commands and takes very little time at all. */ static void mc32_ready_poll(struct net_device *dev){	int ioaddr = dev->base_addr;	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));}/** *	mc32_command_nowait	-	send a command non blocking *	@dev: The 3c527 to issue the command to *	@cmd: The command word to write to the mailbox *	@data: A data block if the command expects one *	@len: Length of the data block * *	Send a command from interrupt state. If there is a command *	currently being executed then we return an error of -1. It simply *	isn't viable to wait around as commands may be slow. Providing we *	get in, we busy wait for the board to become ready to accept the *	command and issue it. We do not wait for the command to complete *	--- the card will interrupt us when it's done. */static int mc32_command_nowait(struct net_device *dev, u16 cmd, void *data, int len){	struct mc32_local *lp = (struct mc32_local *)dev->priv;	int ioaddr = dev->base_addr;	if(lp->exec_pending)		return -1;		lp->exec_pending=3;	lp->exec_box->mbox=0;	lp->exec_box->mbox=cmd;	memcpy((void *)lp->exec_box->data, data, len);	barrier();	/* the memcpy forgot the volatile so be sure */	/* Send the command */	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));	outb(1<<6, ioaddr+HOST_CMD);		return 0;}/** *	mc32_command	-	send a command and sleep until completion *	@dev: The 3c527 card to issue the command to *	@cmd: The command word to write to the mailbox *	@data: A data block if the command expects one *	@len: Length of the data block * *	Sends exec commands in a user context. This permits us to wait around *	for the replies and also to wait for the command buffer to complete *	from a previous command before we execute our command. After our  *	command completes we will complete any pending multicast reload *	we blocked off by hogging the exec buffer. * *	You feed the card a command, you wait, it interrupts you get a 

⌨️ 快捷键说明

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