lib8390.c

来自「linux 内核源代码」· C语言 代码 · 共 1,134 行 · 第 1/3 页

C
1,134
字号
/* 8390.c: A general NS8390 ethernet driver core for linux. *//*	Written 1992-94 by Donald Becker.	Copyright 1993 United States Government as represented by the	Director, National Security Agency.	This software may be used and distributed according to the terms	of the GNU General Public License, incorporated herein by reference.	The author may be reached as becker@scyld.com, or C/O	Scyld Computing Corporation	410 Severn Ave., Suite 210	Annapolis MD 21403  This is the chip-specific code for many 8390-based ethernet adaptors.  This is not a complete driver, it must be combined with board-specific  code such as ne.c, wd.c, 3c503.c, etc.  Seeing how at least eight drivers use this code, (not counting the  PCMCIA ones either) it is easy to break some card by what seems like  a simple innocent change. Please contact me or Donald if you think  you have found something that needs changing. -- PG  Changelog:  Paul Gortmaker	: remove set_bit lock, other cleanups.  Paul Gortmaker	: add ei_get_8390_hdr() so we can pass skb's to			  ei_block_input() for eth_io_copy_and_sum().  Paul Gortmaker	: exchange static int ei_pingpong for a #define,			  also add better Tx error handling.  Paul Gortmaker	: rewrite Rx overrun handling as per NS specs.  Alexey Kuznetsov	: use the 8390's six bit hash multicast filter.  Paul Gortmaker	: tweak ANK's above multicast changes a bit.  Paul Gortmaker	: update packet statistics for v2.1.x  Alan Cox		: support arbitary stupid port mappings on the  			  68K Macintosh. Support >16bit I/O spaces  Paul Gortmaker	: add kmod support for auto-loading of the 8390			  module by all drivers that require it.  Alan Cox		: Spinlocking work, added 'BUG_83C690'  Paul Gortmaker	: Separate out Tx timeout code from Tx path.  Paul Gortmaker	: Remove old unused single Tx buffer code.  Hayato Fujiwara	: Add m32r support.  Paul Gortmaker	: use skb_padto() instead of stack scratch area  Sources:  The National Semiconductor LAN Databook, and the 3Com 3c503 databook.  */#include <linux/module.h>#include <linux/kernel.h>#include <linux/jiffies.h>#include <linux/fs.h>#include <linux/types.h>#include <linux/string.h>#include <linux/bitops.h>#include <asm/system.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/irq.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/fcntl.h>#include <linux/in.h>#include <linux/interrupt.h>#include <linux/init.h>#include <linux/crc32.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#define NS8390_CORE#include "8390.h"#define BUG_83C690/* These are the operational function interfaces to board-specific   routines.	void reset_8390(struct net_device *dev)		Resets the board associated with DEV, including a hardware reset of		the 8390.  This is only called when there is a transmit timeout, and		it is always followed by 8390_init().	void block_output(struct net_device *dev, int count, const unsigned char *buf,					  int start_page)		Write the COUNT bytes of BUF to the packet buffer at START_PAGE.  The		"page" value uses the 8390's 256-byte pages.	void get_8390_hdr(struct net_device *dev, struct e8390_hdr *hdr, int ring_page)		Read the 4 byte, page aligned 8390 header. *If* there is a		subsequent read, it will be of the rest of the packet.	void block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)		Read COUNT bytes from the packet buffer into the skb data area. Start		reading from RING_OFFSET, the address as the 8390 sees it.  This will always		follow the read of the 8390 header.*/#define ei_reset_8390 (ei_local->reset_8390)#define ei_block_output (ei_local->block_output)#define ei_block_input (ei_local->block_input)#define ei_get_8390_hdr (ei_local->get_8390_hdr)/* use 0 for production, 1 for verification, >2 for debug */#ifndef ei_debugint ei_debug = 1;#endif/* Index to functions. */static void ei_tx_intr(struct net_device *dev);static void ei_tx_err(struct net_device *dev);static void ei_tx_timeout(struct net_device *dev);static void ei_receive(struct net_device *dev);static void ei_rx_overrun(struct net_device *dev);/* Routines generic to NS8390-based boards. */static void NS8390_trigger_send(struct net_device *dev, unsigned int length,								int start_page);static void set_multicast_list(struct net_device *dev);static void do_set_multicast_list(struct net_device *dev);static void __NS8390_init(struct net_device *dev, int startp);/* *	SMP and the 8390 setup. * *	The 8390 isnt exactly designed to be multithreaded on RX/TX. There is *	a page register that controls bank and packet buffer access. We guard *	this with ei_local->page_lock. Nobody should assume or set the page other *	than zero when the lock is not held. Lock holders must restore page 0 *	before unlocking. Even pure readers must take the lock to protect in *	page 0. * *	To make life difficult the chip can also be very slow. We therefore can't *	just use spinlocks. For the longer lockups we disable the irq the device *	sits on and hold the lock. We must hold the lock because there is a dual *	processor case other than interrupts (get stats/set multicast list in *	parallel with each other and transmit). * *	Note: in theory we can just disable the irq on the card _but_ there is *	a latency on SMP irq delivery. So we can easily go "disable irq" "sync irqs" *	enter lock, take the queued irq. So we waddle instead of flying. * *	Finally by special arrangement for the purpose of being generally *	annoying the transmit function is called bh atomic. That places *	restrictions on the user context callers as disable_irq won't save *	them. * *	Additional explanation of problems with locking by Alan Cox: * *	"The author (me) didn't use spin_lock_irqsave because the slowness of the *	card means that approach caused horrible problems like losing serial data *	at 38400 baud on some chips. Rememeber many 8390 nics on PCI were ISA *	chips with FPGA front ends. *	 *	Ok the logic behind the 8390 is very simple: *	 *	Things to know *		- IRQ delivery is asynchronous to the PCI bus *		- Blocking the local CPU IRQ via spin locks was too slow *		- The chip has register windows needing locking work *	 *	So the path was once (I say once as people appear to have changed it *	in the mean time and it now looks rather bogus if the changes to use *	disable_irq_nosync_irqsave are disabling the local IRQ) *	 *	 *		Take the page lock *		Mask the IRQ on chip *		Disable the IRQ (but not mask locally- someone seems to have *			broken this with the lock validator stuff) *			[This must be _nosync as the page lock may otherwise *				deadlock us] *		Drop the page lock and turn IRQs back on *		 *		At this point an existing IRQ may still be running but we can't *		get a new one *	 *		Take the lock (so we know the IRQ has terminated) but don't mask *	the IRQs on the processor *		Set irqlock [for debug] *	 *		Transmit (slow as ****) *	 *		re-enable the IRQ *	 *	 *	We have to use disable_irq because otherwise you will get delayed *	interrupts on the APIC bus deadlocking the transmit path. *	 *	Quite hairy but the chip simply wasn't designed for SMP and you can't *	even ACK an interrupt without risking corrupting other parallel *	activities on the chip." [lkml, 25 Jul 2007] *//** * ei_open - Open/initialize the board. * @dev: network device to initialize * * This routine goes all-out, setting everything * up anew at each open, even though many of these registers should only * need to be set once at boot. */static int __ei_open(struct net_device *dev){	unsigned long flags;	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);	/* The card I/O part of the driver (e.g. 3c503) can hook a Tx timeout	    wrapper that does e.g. media check & then calls ei_tx_timeout. */	if (dev->tx_timeout == NULL)		 dev->tx_timeout = ei_tx_timeout;	if (dev->watchdog_timeo <= 0)		 dev->watchdog_timeo = TX_TIMEOUT;	/*	 *	Grab the page lock so we own the register set, then call	 *	the init function.	 */      	spin_lock_irqsave(&ei_local->page_lock, flags);	__NS8390_init(dev, 1);	/* Set the flag before we drop the lock, That way the IRQ arrives	   after its set and we get no silly warnings */	netif_start_queue(dev);      	spin_unlock_irqrestore(&ei_local->page_lock, flags);	ei_local->irqlock = 0;	return 0;}/** * ei_close - shut down network device * @dev: network device to close * * Opposite of ei_open(). Only used when "ifconfig <devname> down" is done. */static int __ei_close(struct net_device *dev){	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);	unsigned long flags;	/*	 *	Hold the page lock during close	 */      	spin_lock_irqsave(&ei_local->page_lock, flags);	__NS8390_init(dev, 0);      	spin_unlock_irqrestore(&ei_local->page_lock, flags);	netif_stop_queue(dev);	return 0;}/** * ei_tx_timeout - handle transmit time out condition * @dev: network device which has apparently fallen asleep * * Called by kernel when device never acknowledges a transmit has * completed (or failed) - i.e. never posted a Tx related interrupt. */static void ei_tx_timeout(struct net_device *dev){	unsigned long e8390_base = dev->base_addr;	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);	int txsr, isr, tickssofar = jiffies - dev->trans_start;	unsigned long flags;	ei_local->stat.tx_errors++;	spin_lock_irqsave(&ei_local->page_lock, flags);	txsr = ei_inb(e8390_base+EN0_TSR);	isr = ei_inb(e8390_base+EN0_ISR);	spin_unlock_irqrestore(&ei_local->page_lock, flags);	printk(KERN_DEBUG "%s: Tx timed out, %s TSR=%#2x, ISR=%#2x, t=%d.\n",		dev->name, (txsr & ENTSR_ABT) ? "excess collisions." :		(isr) ? "lost interrupt?" : "cable problem?", txsr, isr, tickssofar);	if (!isr && !ei_local->stat.tx_packets)	{		/* The 8390 probably hasn't gotten on the cable yet. */		ei_local->interface_num ^= 1;   /* Try a different xcvr.  */	}	/* Ugly but a reset can be slow, yet must be protected */	disable_irq_nosync_lockdep(dev->irq);	spin_lock(&ei_local->page_lock);	/* Try to restart the card.  Perhaps the user has fixed something. */	ei_reset_8390(dev);	__NS8390_init(dev, 1);	spin_unlock(&ei_local->page_lock);	enable_irq_lockdep(dev->irq);	netif_wake_queue(dev);}/** * ei_start_xmit - begin packet transmission * @skb: packet to be sent * @dev: network device to which packet is sent * * Sends a packet to an 8390 network device. */static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev){	unsigned long e8390_base = dev->base_addr;	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);	int send_length = skb->len, output_page;	unsigned long flags;	char buf[ETH_ZLEN];	char *data = skb->data;	if (skb->len < ETH_ZLEN) {		memset(buf, 0, ETH_ZLEN);	/* more efficient than doing just the needed bits */		memcpy(buf, data, skb->len);		send_length = ETH_ZLEN;		data = buf;	}	/* Mask interrupts from the ethercard.	   SMP: We have to grab the lock here otherwise the IRQ handler	   on another CPU can flip window and race the IRQ mask set. We end	   up trashing the mcast filter not disabling irqs if we don't lock */	spin_lock_irqsave(&ei_local->page_lock, flags);	ei_outb_p(0x00, e8390_base + EN0_IMR);	spin_unlock_irqrestore(&ei_local->page_lock, flags);	/*	 *	Slow phase with lock held.	 */	disable_irq_nosync_lockdep_irqsave(dev->irq, &flags);	spin_lock(&ei_local->page_lock);	ei_local->irqlock = 1;	/*	 * We have two Tx slots available for use. Find the first free	 * slot, and then perform some sanity checks. With two Tx bufs,	 * you get very close to transmitting back-to-back packets. With	 * only one Tx buf, the transmitter sits idle while you reload the	 * card, leaving a substantial gap between each transmitted packet.	 */	if (ei_local->tx1 == 0)	{		output_page = ei_local->tx_start_page;		ei_local->tx1 = send_length;		if (ei_debug  &&  ei_local->tx2 > 0)			printk(KERN_DEBUG "%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n",				dev->name, ei_local->tx2, ei_local->lasttx, ei_local->txing);	}	else if (ei_local->tx2 == 0)	{		output_page = ei_local->tx_start_page + TX_PAGES/2;		ei_local->tx2 = send_length;		if (ei_debug  &&  ei_local->tx1 > 0)			printk(KERN_DEBUG "%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n",				dev->name, ei_local->tx1, ei_local->lasttx, ei_local->txing);	}	else	{	/* We should never get here. */		if (ei_debug)			printk(KERN_DEBUG "%s: No Tx buffers free! tx1=%d tx2=%d last=%d\n",				dev->name, ei_local->tx1, ei_local->tx2, ei_local->lasttx);		ei_local->irqlock = 0;		netif_stop_queue(dev);		ei_outb_p(ENISR_ALL, e8390_base + EN0_IMR);		spin_unlock(&ei_local->page_lock);		enable_irq_lockdep_irqrestore(dev->irq, &flags);		ei_local->stat.tx_errors++;		return 1;

⌨️ 快捷键说明

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