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

📄 axnet_cs.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
  */static const char *version_8390 =    "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@scyld.com)\n";#include <linux/bitops.h>#include <asm/irq.h>#include <linux/fcntl.h>#include <linux/in.h>#include <linux/interrupt.h>#include <linux/etherdevice.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);/* *	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. */ /** * ax_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 ax_open(struct net_device *dev){	unsigned long flags;	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);#ifdef HAVE_TX_TIMEOUT	/* 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;#endif	/*	 *	Grab the page lock so we own the register set, then call	 *	the init function.	 */            	spin_lock_irqsave(&ei_local->page_lock, flags);	AX88190_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;}#define dev_lock(dev) (((struct ei_device *)netdev_priv(dev))->page_lock)/** * ax_close - shut down network device * @dev: network device to close * * Opposite of ax_open(). Only used when "ifconfig <devname> down" is done. */int ax_close(struct net_device *dev){	unsigned long flags;	/*	 *      Hold the page lock during close	 */	spin_lock_irqsave(&dev_lock(dev), flags);	AX88190_init(dev, 0);	spin_unlock_irqrestore(&dev_lock(dev), 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. */void ei_tx_timeout(struct net_device *dev){	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 = inb(e8390_base+EN0_TSR);	isr = 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(dev->irq);	spin_lock(&ei_local->page_lock);			/* Try to restart the card.  Perhaps the user has fixed something. */	ei_reset_8390(dev);	AX88190_init(dev, 1);			spin_unlock(&ei_local->page_lock);	enable_irq(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){	long e8390_base = dev->base_addr;	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);	int length, send_length, output_page;	unsigned long flags;	u8 packet[ETH_ZLEN];		netif_stop_queue(dev);	length = skb->len;	/* 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);	outb_p(0x00, e8390_base + EN0_IMR);	spin_unlock_irqrestore(&ei_local->page_lock, flags);		/*	 *	Slow phase with lock held.	 */	 	disable_irq_nosync(dev->irq);		spin_lock(&ei_local->page_lock);		ei_local->irqlock = 1;	send_length = ETH_ZLEN < length ? length : ETH_ZLEN;		/*	 * 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);		outb_p(ENISR_ALL, e8390_base + EN0_IMR);		spin_unlock(&ei_local->page_lock);		enable_irq(dev->irq);		ei_local->stat.tx_errors++;		return 1;	}	/*	 * Okay, now upload the packet and trigger a send if the transmitter	 * isn't already sending. If it is busy, the interrupt handler will	 * trigger the send later, upon receiving a Tx done interrupt.	 */	if (length == skb->len)		ei_block_output(dev, length, skb->data, output_page);	else {		memset(packet, 0, ETH_ZLEN);		memcpy(packet, skb->data, skb->len);		ei_block_output(dev, length, packet, output_page);	}		if (! ei_local->txing) 	{		ei_local->txing = 1;		NS8390_trigger_send(dev, send_length, output_page);		dev->trans_start = jiffies;		if (output_page == ei_local->tx_start_page) 		{			ei_local->tx1 = -1;			ei_local->lasttx = -1;		}		else 		{			ei_local->tx2 = -1;			ei_local->lasttx = -2;		}	}	else ei_local->txqueue++;	if (ei_local->tx1  &&  ei_local->tx2)		netif_stop_queue(dev);	else		netif_start_queue(dev);	/* Turn 8390 interrupts back on. */	ei_local->irqlock = 0;	outb_p(ENISR_ALL, e8390_base + EN0_IMR);		spin_unlock(&ei_local->page_lock);	enable_irq(dev->irq);	dev_kfree_skb (skb);	ei_local->stat.tx_bytes += send_length;    	return 0;}/** * ax_interrupt - handle the interrupts from an 8390 * @irq: interrupt number * @dev_id: a pointer to the net_device * @regs: unused * * Handle the ether interface interrupts. We pull packets from * the 8390 via the card specific functions and fire them at the networking * stack. We also handle transmit completions and wake the transmit path if * necessary. We also update the counters and do other housekeeping as * needed. */static irqreturn_t ax_interrupt(int irq, void *dev_id, struct pt_regs * regs){	struct net_device *dev = dev_id;	long e8390_base;	int interrupts, nr_serviced = 0, i;	struct ei_device *ei_local;    	int handled = 0;	if (dev == NULL) 	{		printk ("net_interrupt(): irq %d for unknown device.\n", irq);		return IRQ_NONE;	}    	e8390_base = dev->base_addr;	ei_local = (struct ei_device *) netdev_priv(dev);	/*	 *	Protect the irq test too.	 */	 	spin_lock(&ei_local->page_lock);	if (ei_local->irqlock) 	{#if 1 /* This might just be an interrupt for a PCI device sharing this line */		/* The "irqlock" check is only for testing. */		printk(ei_local->irqlock			   ? "%s: Interrupted while interrupts are masked! isr=%#2x imr=%#2x.\n"			   : "%s: Reentering the interrupt handler! isr=%#2x imr=%#2x.\n",			   dev->name, inb_p(e8390_base + EN0_ISR),			   inb_p(e8390_base + EN0_IMR));#endif		spin_unlock(&ei_local->page_lock);		return IRQ_NONE;	}    	if (ei_debug > 3)		printk(KERN_DEBUG "%s: interrupt(isr=%#2.2x).\n", dev->name,			   inb_p(e8390_base + EN0_ISR));	outb_p(0x00, e8390_base + EN0_ISR);	ei_local->irqlock = 1;   	/* !!Assumption!! -- we stay in page 0.	 Don't break this. */	while ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0		   && ++nr_serviced < MAX_SERVICE) 	{		if (!netif_running(dev) || (interrupts == 0xff)) {			if (ei_debug > 1)				printk(KERN_WARNING "%s: interrupt from stopped card\n", dev->name);			outb_p(interrupts, e8390_base + EN0_ISR);			interrupts = 0;			break;		}		handled = 1;		/* AX88190 bug fix. */		outb_p(interrupts, e8390_base + EN0_ISR);		for (i = 0; i < 10; i++) {			if (!(inb(e8390_base + EN0_ISR) & interrupts))				break;			outb_p(0, e8390_base + EN0_ISR);			outb_p(interrupts, e8390_base + EN0_ISR);		}		if (interrupts & ENISR_OVER) 			ei_rx_overrun(dev);		else if (interrupts & (ENISR_RX+ENISR_RX_ERR)) 		{			/* Got a good (?) packet. */			ei_receive(dev);		}		/* Push the next to-transmit packet through. */		if (interrupts & ENISR_TX)			ei_tx_intr(dev);		else if (interrupts & ENISR_TX_ERR)			ei_tx_err(dev);		if (interrupts & ENISR_COUNTERS) 		{			ei_local->stat.rx_frame_errors += inb_p(e8390_base + EN0_COUNTER0);			ei_local->stat.rx_crc_errors   += inb_p(e8390_base + EN0_COUNTER1);			ei_local->stat.rx_missed_errors+= inb_p(e8390_base + EN0_COUNTER2);		}	}    	if (interrupts && ei_debug) 	{		handled = 1;		if (nr_serviced >= MAX_SERVICE) 		{			/* 0xFF is valid for a card removal */			if(interrupts!=0xFF)				printk(KERN_WARNING "%s: Too much work at interrupt, status %#2.2x\n",				   dev->name, interrupts);			outb_p(ENISR_ALL, e8390_base + EN0_ISR); /* Ack. most intrs. */		} else {			printk(KERN_WARNING "%s: unknown interrupt %#2x\n", dev->name, interrupts);			outb_p(0xff, e8390_base + EN0_ISR); /* Ack. all intrs. */		}	}	/* Turn 8390 interrupts back on. */	ei_local->irqlock = 0;	outb_p(ENISR_ALL, e8390_base + EN0_IMR);	spin_unlock(&ei_local->page_lock);	return IRQ_RETVAL(handled);}/** * ei_tx_err - handle transmitter error * @dev: network device which threw the exception * * A transmitter error has happened. Most likely excess collisions (which * is a fairly normal condition). If the error is one where the Tx will * have been aborted, we try and send another one right away, instead of * letting the failed packet sit and collect dust in the Tx buffer. This * is a much better solution as it avoids kernel based Tx timeouts, and * an unnecessary card reset. * * Called with lock held. */static void ei_tx_err(struct net_device *dev){	long e8390_base = dev->base_addr;	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);	unsigned char txsr = inb_p(e8390_base+EN0_TSR);	unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU);#ifdef VERBOSE_ERROR_DUMP	printk(KERN_DEBUG "%s: transmitter error (%#2x): ", dev->name, txsr);	if (txsr & ENTSR_ABT)		printk("excess-collisions ");	if (txsr & ENTSR_ND)		printk("non-deferral ");	if (txsr & ENTSR_CRS)		printk("lost-carrier ");	if (txsr & ENTSR_FU)		printk("FIFO-underrun ");	if (txsr & ENTSR_CDH)		printk("lost-heartbeat ");

⌨️ 快捷键说明

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