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

📄 sunlance.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* $Id: sunlance.c,v 1.105 2000/10/22 16:08:38 davem Exp $ * lance.c: Linux/Sparc/Lance driver * *	Written 1995, 1996 by Miguel de Icaza * Sources: *	The Linux  depca driver *	The Linux  lance driver. *	The Linux  skeleton driver. *	The NetBSD Sparc/Lance driver. *	Theo de Raadt (deraadt@openbsd.org) *	NCR92C990 Lan Controller manual * * 1.4: *	Added support to run with a ledma on the Sun4m * * 1.5: *	Added multiple card detection. * *	 4/17/96: Burst sizes and tpe selection on sun4m by Eddie C. Dost *		  (ecd@skynet.be) * *	 5/15/96: auto carrier detection on sun4m by Eddie C. Dost *		  (ecd@skynet.be) * *	 5/17/96: lebuffer on scsi/ether cards now work David S. Miller *		  (davem@caip.rutgers.edu) * *	 5/29/96: override option 'tpe-link-test?', if it is 'false', as *		  this disables auto carrier detection on sun4m. Eddie C. Dost *		  (ecd@skynet.be) * * 1.7: *	 6/26/96: Bug fix for multiple ledmas, miguel. * * 1.8: *		  Stole multicast code from depca.c, fixed lance_tx. * * 1.9: *	 8/21/96: Fixed the multicast code (Pedro Roque) * *	 8/28/96: Send fake packet in lance_open() if auto_select is true, *		  so we can detect the carrier loss condition in time. *		  Eddie C. Dost (ecd@skynet.be) * *	 9/15/96: Align rx_buf so that eth_copy_and_sum() won't cause an *		  MNA trap during chksum_partial_copy(). (ecd@skynet.be) * *	11/17/96: Handle LE_C0_MERR in lance_interrupt(). (ecd@skynet.be) * *	12/22/96: Don't loop forever in lance_rx() on incomplete packets. *		  This was the sun4c killer. Shit, stupid bug. *		  (ecd@skynet.be) * * 1.10: *	 1/26/97: Modularize driver. (ecd@skynet.be) * * 1.11: *	12/27/97: Added sun4d support. (jj@sunsite.mff.cuni.cz) * * 1.12: * 	 11/3/99: Fixed SMP race in lance_start_xmit found by davem. * 	          Anton Blanchard (anton@progsoc.uts.edu.au) * 2.00: 11/9/99: Massive overhaul and port to new SBUS driver interfaces. *		  David S. Miller (davem@redhat.com) */#undef DEBUG_DRIVERstatic char *version =	"sunlance.c:v2.00 11/Sep/99 Miguel de Icaza (miguel@nuclecu.unam.mx)\n";static char *lancestr = "LANCE";#include <linux/config.h>#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/in.h>#include <linux/malloc.h>#include <linux/string.h>#include <linux/delay.h>#include <linux/init.h>#include <asm/system.h>#include <asm/bitops.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/pgtable.h>#include <linux/errno.h>#include <asm/byteorder.h>	/* Used by the checksum routines *//* Used for the temporal inet entries and routing */#include <linux/socket.h>#include <linux/route.h>#include <asm/idprom.h>#include <asm/sbus.h>#include <asm/openprom.h>#include <asm/oplib.h>#include <asm/auxio.h>		/* For tpe-link-test? setting */#include <asm/irq.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>/* Define: 2^4 Tx buffers and 2^4 Rx buffers */#ifndef LANCE_LOG_TX_BUFFERS#define LANCE_LOG_TX_BUFFERS 4#define LANCE_LOG_RX_BUFFERS 4#endif#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */#define LE_CSR0 0#define LE_CSR1 1#define LE_CSR2 2#define LE_CSR3 3#define LE_MO_PROM      0x8000  /* Enable promiscuous mode */#define	LE_C0_ERR	0x8000	/* Error: set if BAB, SQE, MISS or ME is set */#define	LE_C0_BABL	0x4000	/* BAB:  Babble: tx timeout. */#define	LE_C0_CERR	0x2000	/* SQE:  Signal quality error */#define	LE_C0_MISS	0x1000	/* MISS: Missed a packet */#define	LE_C0_MERR	0x0800	/* ME:   Memory error */#define	LE_C0_RINT	0x0400	/* Received interrupt */#define	LE_C0_TINT	0x0200	/* Transmitter Interrupt */#define	LE_C0_IDON	0x0100	/* IFIN: Init finished. */#define	LE_C0_INTR	0x0080	/* Interrupt or error */#define	LE_C0_INEA	0x0040	/* Interrupt enable */#define	LE_C0_RXON	0x0020	/* Receiver on */#define	LE_C0_TXON	0x0010	/* Transmitter on */#define	LE_C0_TDMD	0x0008	/* Transmitter demand */#define	LE_C0_STOP	0x0004	/* Stop the card */#define	LE_C0_STRT	0x0002	/* Start the card */#define	LE_C0_INIT	0x0001	/* Init the card */#define	LE_C3_BSWP	0x4     /* SWAP */#define	LE_C3_ACON	0x2	/* ALE Control */#define	LE_C3_BCON	0x1	/* Byte control *//* Receive message descriptor 1 */#define LE_R1_OWN       0x80    /* Who owns the entry */#define LE_R1_ERR       0x40    /* Error: if FRA, OFL, CRC or BUF is set */#define LE_R1_FRA       0x20    /* FRA: Frame error */#define LE_R1_OFL       0x10    /* OFL: Frame overflow */#define LE_R1_CRC       0x08    /* CRC error */#define LE_R1_BUF       0x04    /* BUF: Buffer error */#define LE_R1_SOP       0x02    /* Start of packet */#define LE_R1_EOP       0x01    /* End of packet */#define LE_R1_POK       0x03    /* Packet is complete: SOP + EOP */#define LE_T1_OWN       0x80    /* Lance owns the packet */#define LE_T1_ERR       0x40    /* Error summary */#define LE_T1_EMORE     0x10    /* Error: more than one retry needed */#define LE_T1_EONE      0x08    /* Error: one retry needed */#define LE_T1_EDEF      0x04    /* Error: deferred */#define LE_T1_SOP       0x02    /* Start of packet */#define LE_T1_EOP       0x01    /* End of packet */#define LE_T1_POK	0x03	/* Packet is complete: SOP + EOP */#define LE_T3_BUF       0x8000  /* Buffer error */#define LE_T3_UFL       0x4000  /* Error underflow */#define LE_T3_LCOL      0x1000  /* Error late collision */#define LE_T3_CLOS      0x0800  /* Error carrier loss */#define LE_T3_RTY       0x0400  /* Error retry */#define LE_T3_TDR       0x03ff  /* Time Domain Reflectometry counter */#define TX_RING_SIZE			(1 << (LANCE_LOG_TX_BUFFERS))#define TX_RING_MOD_MASK		(TX_RING_SIZE - 1)#define TX_RING_LEN_BITS		((LANCE_LOG_TX_BUFFERS) << 29)#define TX_NEXT(__x)			(((__x)+1) & TX_RING_MOD_MASK)#define RX_RING_SIZE			(1 << (LANCE_LOG_RX_BUFFERS))#define RX_RING_MOD_MASK		(RX_RING_SIZE - 1)#define RX_RING_LEN_BITS		((LANCE_LOG_RX_BUFFERS) << 29)#define RX_NEXT(__x)			(((__x)+1) & RX_RING_MOD_MASK)#define PKT_BUF_SZ		1544#define RX_BUFF_SIZE            PKT_BUF_SZ#define TX_BUFF_SIZE            PKT_BUF_SZstruct lance_rx_desc {	u16	rmd0;		/* low address of packet */	u8	rmd1_bits;	/* descriptor bits */	u8	rmd1_hadr;	/* high address of packet */	s16	length;		/* This length is 2s complement (negative)!				 * Buffer length				 */	u16	mblength;	/* This is the actual number of bytes received */};struct lance_tx_desc {	u16	tmd0;		/* low address of packet */	u8 	tmd1_bits;	/* descriptor bits */	u8 	tmd1_hadr;	/* high address of packet */	s16 	length;		/* Length is 2s complement (negative)! */	u16 	misc;};		/* The LANCE initialization block, described in databook. *//* On the Sparc, this block should be on a DMA region     */struct lance_init_block {	u16	mode;		/* Pre-set mode (reg. 15) */	u8	phys_addr[6];	/* Physical ethernet address */	u32	filter[2];	/* Multicast filter. */	/* Receive and transmit ring base, along with extra bits. */	u16	rx_ptr;		/* receive descriptor addr */	u16	rx_len;		/* receive len and high addr */	u16	tx_ptr;		/* transmit descriptor addr */	u16	tx_len;		/* transmit len and high addr */    	/* The Tx and Rx ring entries must aligned on 8-byte boundaries. */	struct lance_rx_desc brx_ring[RX_RING_SIZE];	struct lance_tx_desc btx_ring[TX_RING_SIZE];    	u8	tx_buf [TX_RING_SIZE][TX_BUFF_SIZE];	u8	pad[2];		/* align rx_buf for copy_and_sum(). */	u8	rx_buf [RX_RING_SIZE][RX_BUFF_SIZE];};#define libdesc_offset(rt, elem) \((__u32)(((unsigned long)(&(((struct lance_init_block *)0)->rt[elem])))))#define libbuff_offset(rt, elem) \((__u32)(((unsigned long)(&(((struct lance_init_block *)0)->rt[elem][0])))))struct lance_private {	unsigned long	lregs;		/* Lance RAP/RDP regs.		*/	unsigned long	dregs;		/* DMA controller regs.		*/	volatile struct lance_init_block *init_block;    	spinlock_t	lock;	int		rx_new, tx_new;	int		rx_old, tx_old;    	struct net_device_stats	stats;	struct sbus_dma *ledma;	/* If set this points to ledma	*/	char		tpe;		/* cable-selection is TPE	*/	char		auto_select;	/* cable-selection by carrier	*/	char		burst_sizes;	/* ledma SBus burst sizes	*/	char		pio_buffer;	/* init block in PIO space?	*/	unsigned short	busmaster_regval;	void (*init_ring)(struct net_device *);	void (*rx)(struct net_device *);	void (*tx)(struct net_device *);	char	       	       *name;	__u32			init_block_dvma;	struct net_device      *dev;		  /* Backpointer	*/	struct lance_private   *next_module;	struct sbus_dev	       *sdev;	struct timer_list       multicast_timer;};#define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\			lp->tx_old+TX_RING_MOD_MASK-lp->tx_new:\			lp->tx_old - lp->tx_new-1)/* Lance registers. */#define RDP		0x00UL		/* register data port		*/#define RAP		0x02UL		/* register address port	*/#define LANCE_REG_SIZE	0x04UL#define STOP_LANCE(__lp) \do {	unsigned long __base = (__lp)->lregs; \	sbus_writew(LE_CSR0,	__base + RAP); \	sbus_writew(LE_C0_STOP,	__base + RDP); \} while (0)int sparc_lance_debug = 2;/* The Lance uses 24 bit addresses *//* On the Sun4c the DVMA will provide the remaining bytes for us *//* On the Sun4m we have to instruct the ledma to provide them    *//* Even worse, on scsi/ether SBUS cards, the init block and the * transmit/receive buffers are addresses as offsets from absolute * zero on the lebuffer PIO area. -DaveM */#define LANCE_ADDR(x) ((long)(x) & ~0xff000000)static struct lance_private *root_lance_dev = NULL;/* Load the CSR registers */static void load_csrs(struct lance_private *lp){	u32 leptr;	if (lp->pio_buffer)		leptr = 0;	else		leptr = LANCE_ADDR(lp->init_block_dvma);	sbus_writew(LE_CSR1,		  lp->lregs + RAP);	sbus_writew(leptr & 0xffff,	  lp->lregs + RDP);	sbus_writew(LE_CSR2,		  lp->lregs + RAP);	sbus_writew(leptr >> 16,	  lp->lregs + RDP);	sbus_writew(LE_CSR3,		  lp->lregs + RAP);	sbus_writew(lp->busmaster_regval, lp->lregs + RDP);	/* Point back to csr0 */	sbus_writew(LE_CSR0, lp->lregs + RAP);}/* Setup the Lance Rx and Tx rings */static void lance_init_ring_dvma(struct net_device *dev){	struct lance_private *lp = (struct lance_private *) dev->priv;	volatile struct lance_init_block *ib = lp->init_block;	__u32 aib = lp->init_block_dvma;	__u32 leptr;	int i;    	/* Lock out other processes while setting up hardware */	netif_stop_queue(dev);	lp->rx_new = lp->tx_new = 0;	lp->rx_old = lp->tx_old = 0;	/* Copy the ethernet address to the lance init block	 * Note that on the sparc you need to swap the ethernet address.	 */	ib->phys_addr [0] = dev->dev_addr [1];	ib->phys_addr [1] = dev->dev_addr [0];	ib->phys_addr [2] = dev->dev_addr [3];	ib->phys_addr [3] = dev->dev_addr [2];	ib->phys_addr [4] = dev->dev_addr [5];	ib->phys_addr [5] = dev->dev_addr [4];	/* Setup the Tx ring entries */	for (i = 0; i <= TX_RING_SIZE; i++) {		leptr = LANCE_ADDR(aib + libbuff_offset(tx_buf, i));		ib->btx_ring [i].tmd0      = leptr;		ib->btx_ring [i].tmd1_hadr = leptr >> 16;		ib->btx_ring [i].tmd1_bits = 0;		ib->btx_ring [i].length    = 0xf000; /* The ones required by tmd2 */		ib->btx_ring [i].misc      = 0;	}	/* Setup the Rx ring entries */	for (i = 0; i < RX_RING_SIZE; i++) {		leptr = LANCE_ADDR(aib + libbuff_offset(rx_buf, i));		ib->brx_ring [i].rmd0      = leptr;		ib->brx_ring [i].rmd1_hadr = leptr >> 16;		ib->brx_ring [i].rmd1_bits = LE_R1_OWN;		ib->brx_ring [i].length    = -RX_BUFF_SIZE | 0xf000;		ib->brx_ring [i].mblength  = 0;	}	/* Setup the initialization block */    	/* Setup rx descriptor pointer */	leptr = LANCE_ADDR(aib + libdesc_offset(brx_ring, 0));	ib->rx_len = (LANCE_LOG_RX_BUFFERS << 13) | (leptr >> 16);	ib->rx_ptr = leptr;    	/* Setup tx descriptor pointer */	leptr = LANCE_ADDR(aib + libdesc_offset(btx_ring, 0));	ib->tx_len = (LANCE_LOG_TX_BUFFERS << 13) | (leptr >> 16);	ib->tx_ptr = leptr;}static void lance_init_ring_pio(struct net_device *dev){	struct lance_private *lp = (struct lance_private *) dev->priv;	volatile struct lance_init_block *ib = lp->init_block;	u32 leptr;	int i;    	/* Lock out other processes while setting up hardware */	netif_stop_queue(dev);	lp->rx_new = lp->tx_new = 0;	lp->rx_old = lp->tx_old = 0;	/* Copy the ethernet address to the lance init block	 * Note that on the sparc you need to swap the ethernet address.	 */	sbus_writeb(dev->dev_addr[1], &ib->phys_addr[0]);	sbus_writeb(dev->dev_addr[0], &ib->phys_addr[1]);	sbus_writeb(dev->dev_addr[3], &ib->phys_addr[2]);	sbus_writeb(dev->dev_addr[2], &ib->phys_addr[3]);	sbus_writeb(dev->dev_addr[5], &ib->phys_addr[4]);	sbus_writeb(dev->dev_addr[4], &ib->phys_addr[5]);	/* Setup the Tx ring entries */	for (i = 0; i <= TX_RING_SIZE; i++) {		leptr = libbuff_offset(tx_buf, i);		sbus_writew(leptr,	&ib->btx_ring [i].tmd0);		sbus_writeb(leptr >> 16,&ib->btx_ring [i].tmd1_hadr);		sbus_writeb(0,		&ib->btx_ring [i].tmd1_bits);		/* The ones required by tmd2 */		sbus_writew(0xf000,	&ib->btx_ring [i].length);		sbus_writew(0,		&ib->btx_ring [i].misc);	}	/* Setup the Rx ring entries */	for (i = 0; i < RX_RING_SIZE; i++) {		leptr = libbuff_offset(rx_buf, i);		sbus_writew(leptr,	&ib->brx_ring [i].rmd0);		sbus_writeb(leptr >> 16,&ib->brx_ring [i].rmd1_hadr);		sbus_writeb(LE_R1_OWN,	&ib->brx_ring [i].rmd1_bits);		sbus_writew(-RX_BUFF_SIZE|0xf000,			    &ib->brx_ring [i].length);		sbus_writew(0,		&ib->brx_ring [i].mblength);	}	/* Setup the initialization block */    	/* Setup rx descriptor pointer */	leptr = libdesc_offset(brx_ring, 0);	sbus_writew((LANCE_LOG_RX_BUFFERS << 13) | (leptr >> 16),		    &ib->rx_len);	sbus_writew(leptr, &ib->rx_ptr);    	/* Setup tx descriptor pointer */	leptr = libdesc_offset(btx_ring, 0);	sbus_writew((LANCE_LOG_TX_BUFFERS << 13) | (leptr >> 16),		    &ib->tx_len);	sbus_writew(leptr, &ib->tx_ptr);}static void init_restart_ledma(struct lance_private *lp){	u32 csr = sbus_readl(lp->dregs + DMA_CSR);	if (!(csr & DMA_HNDL_ERROR)) {		/* E-Cache draining */		while (sbus_readl(lp->dregs + DMA_CSR) & DMA_FIFO_ISDRAIN)			barrier();	}	csr = sbus_readl(lp->dregs + DMA_CSR);	csr &= ~DMA_E_BURSTS;	if (lp->burst_sizes & DMA_BURST32)		csr |= DMA_E_BURST32;	else		csr |= DMA_E_BURST16;	csr |= (DMA_DSBL_RD_DRN | DMA_DSBL_WR_INV | DMA_FIFO_INV);	if (lp->tpe)		csr |= DMA_EN_ENETAUI;	else		csr &= ~DMA_EN_ENETAUI;	udelay(20);	sbus_writel(csr, lp->dregs + DMA_CSR);	udelay(200);}static int init_restart_lance(struct lance_private *lp){	u16 regval = 0;	int i;	if (lp->dregs)		init_restart_ledma(lp);	sbus_writew(LE_CSR0,	lp->lregs + RAP);	sbus_writew(LE_C0_INIT,	lp->lregs + RDP);	/* Wait for the lance to complete initialization */	for (i = 0; i < 100; i++) {		regval = sbus_readw(lp->lregs + RDP);		if (regval & (LE_C0_ERR | LE_C0_IDON))			break;		barrier();	}	if (i == 100 || (regval & LE_C0_ERR)) {		printk(KERN_ERR "LANCE unopened after %d ticks, csr0=%4.4x.\n",		       i, regval);		if (lp->dregs)			printk("dcsr=%8.8x\n", sbus_readl(lp->dregs + DMA_CSR));		return -1;	}	/* Clear IDON by writing a "1", enable interrupts and start lance */	sbus_writew(LE_C0_IDON,			lp->lregs + RDP);	sbus_writew(LE_C0_INEA | LE_C0_STRT,	lp->lregs + RDP);	if (lp->dregs) {		u32 csr = sbus_readl(lp->dregs + DMA_CSR);		csr |= DMA_INT_ENAB;		sbus_writel(csr, lp->dregs + DMA_CSR);	}	return 0;}static void lance_rx_dvma(struct net_device *dev){	struct lance_private *lp = (struct lance_private *) dev->priv;	volatile struct lance_init_block *ib = lp->init_block;	volatile struct lance_rx_desc *rd;	u8 bits;	int len, entry = lp->rx_new;	struct sk_buff *skb;	for (rd = &ib->brx_ring [entry];	     !((bits = rd->rmd1_bits) & LE_R1_OWN);	     rd = &ib->brx_ring [entry]) {		/* We got an incomplete frame? */		if ((bits & LE_R1_POK) != LE_R1_POK) {			lp->stats.rx_over_errors++;			lp->stats.rx_errors++;		} else if (bits & LE_R1_ERR) {			/* Count only the end frame as a rx error,			 * not the beginning			 */			if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++;			if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++;			if (bits & LE_R1_OFL) lp->stats.rx_over_errors++;			if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++;			if (bits & LE_R1_EOP) lp->stats.rx_errors++;		} else {			len = (rd->mblength & 0xfff) - 4;			skb = dev_alloc_skb(len + 2);			if (skb == NULL) {				printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n",

⌨️ 快捷键说明

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