11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* sun3lance.c: Ethernet driver for SUN3 Lance chip */
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik  Sun3 Lance ethernet driver, by Sam Creasey (sammy@users.qual.net).
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  This driver is a part of the linux kernel, and is thus distributed
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  under the GNU General Public License.
76aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  The values used in LANCE_OBIO and LANCE_IRQ seem to be empirically
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  true for the correct IRQ and address of the lance registers.  They
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  have not been widely tested, however.  What we probably need is a
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  "proper" way to search for a device in the sun3's prom, but, alas,
126aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik  linux has no such thing.
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  This driver is largely based on atarilance.c, by Roman Hodek.  Other
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  sources of inspiration were the NetBSD sun3 am7990 driver, and the
166aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik  linux sparc lance driver (sunlance.c).
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  There are more assumptions made throughout this driver, it almost
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  certainly still needs work, but it does work at least for RARP/BOOTP and
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  mounting the root NFS filesystem.
216aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *version = "sun3lance.c: v1.2 1/12/2001  Sam Creasey (sammy@sammy.net)\n";
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/stddef.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40a1f8e7f7fb9d7e2cbcb53170edca7c0ac4680697Al Viro#include <asm/cacheflush.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/setup.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pgtable.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/dvma.h>
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/idprom.h>
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/machines.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SUN3
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/sun3mmu.h>
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/sun3xprom.h>
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* sun3/60 addr/irq for the lance chip.  If your sun is different,
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   change this. */
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LANCE_OBIO 0x120000
584facfde9f1d7b8a61fb0017460da45e23e60115cRoman Zippel#define LANCE_IRQ IRQ_AUTO_3
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Debug level:
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  0 = silent, print only serious errors
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  1 = normal, print error messages
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  2 = debug, print debug infos
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  3 = debug, print even more debug infos (packet data)
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	LANCE_DEBUG	0
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef LANCE_DEBUG
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_debug = LANCE_DEBUG;
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_debug = 1;
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
748d3b33f67fdc0fb364a1ef6d8fbbea7c2e4e6c98Rusty Russellmodule_param(lance_debug, int, 0);
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(lance_debug, "SUN3 Lance debug level (0-3)");
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DPRINTK(n,a) \
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {  \
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (lance_debug >= n)  \
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk a; \
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while( 0 )
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* we're only using 32k of memory, so we use 4 TX
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   buffers and 16 RX buffers.  These values are expressed as log2. */
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_LOG_RING_SIZE			3
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_LOG_RING_SIZE			5
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* These are the derived values */
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_RING_SIZE			(1 << TX_LOG_RING_SIZE)
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_RING_LEN_BITS		(TX_LOG_RING_SIZE << 5)
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	TX_RING_MOD_MASK		(TX_RING_SIZE - 1)
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_RING_SIZE			(1 << RX_LOG_RING_SIZE)
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_RING_LEN_BITS		(RX_LOG_RING_SIZE << 5)
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	RX_RING_MOD_MASK		(RX_RING_SIZE - 1)
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Definitions for packet buffer access: */
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PKT_BUF_SZ		1544
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Get the address of a packet buffer corresponding to a given buffer head */
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	PKTBUF_ADDR(head)	(void *)((unsigned long)(MEM) | (head)->base)
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The LANCE Rx and Tx ring descriptors. */
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_rx_head {
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short	base;		/* Low word of base addr */
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile unsigned char	flag;
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char  base_hi;	/* High word of base addr (unused) */
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	short buf_length;	/* This length is 2s complement! */
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile short msg_length;	/* This length is "normal". */
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_tx_head {
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short base;		/* Low word of base addr */
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile unsigned char	flag;
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char base_hi;	/* High word of base addr (unused) */
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	short length;		/* Length is 2s complement! */
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile short misc;
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The LANCE initialization block, described in databook. */
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_init_block {
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short	mode;		/* Pre-set mode */
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char	hwaddr[6];	/* Physical ethernet address */
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int    filter[2];	/* Multicast filter (unused). */
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Receive and transmit ring base, along with length bits. */
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short rdra;
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short rlen;
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short tdra;
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short tlen;
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short pad[4]; /* is thie needed? */
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The whole layout of the Lance shared memory */
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_memory {
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_init_block	init;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_tx_head	tx_head[TX_RING_SIZE];
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_rx_head	rx_head[RX_RING_SIZE];
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char   rx_data[RX_RING_SIZE][PKT_BUF_SZ];
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char   tx_data[TX_RING_SIZE][PKT_BUF_SZ];
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The driver's private device structure */
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_private {
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile unsigned short	*iobase;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_memory	*mem;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     	int new_rx, new_tx;	/* The next free ring entry */
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int old_tx, old_rx;     /* ring entry to be processed */
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* These two must be longs for set_bit() */
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long	    tx_full;
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long	    lock;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* I/O register access macros */
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MEM	lp->mem
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DREG	lp->iobase[0]
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	AREG	lp->iobase[1]
164e345d5ef6d476cc236f64d90d9528143a70745c8Al Viro#define	REGA(a)	(*( AREG = (a), &DREG ))
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Definitions for the Lance */
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* tx_head flags */
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_ENP		0x01	/* end of packet */
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_STP		0x02	/* start of packet */
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_DEF		0x04	/* deferred */
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_ONE		0x08	/* one retry needed */
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_MORE		0x10	/* more than one retry needed */
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_ERR		0x40	/* error summary */
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_OWN 		0x80	/* ownership (set: chip owns) */
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_OWN_CHIP	TMD1_OWN
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_OWN_HOST	0
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* tx_head misc field */
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_TDR		0x03FF	/* Time Domain Reflectometry counter */
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_RTRY		0x0400	/* failed after 16 retries */
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_LCAR		0x0800	/* carrier lost */
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_LCOL		0x1000	/* late collision */
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_UFLO		0x4000	/* underflow (late memory) */
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_BUFF		0x8000	/* buffering error (no ENP) */
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* rx_head flags */
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_ENP		0x01	/* end of packet */
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_STP		0x02	/* start of packet */
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_BUFF		0x04	/* buffer error */
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_CRC		0x08	/* CRC error */
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_OFLO		0x10	/* overflow */
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_FRAM		0x20	/* framing error */
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_ERR		0x40	/* error summary */
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_OWN 		0x80	/* ownership (set: ship owns) */
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_OWN_CHIP	RMD1_OWN
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_OWN_HOST	0
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* register names */
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0	0		/* mode/status */
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR1	1		/* init block addr (low) */
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR2	2		/* init block addr (high) */
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR3	3		/* misc */
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR8	8	  	/* address filter */
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR15	15		/* promiscuous mode */
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* CSR0 */
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* (R=readable, W=writeable, S=set on write, C=clear on write) */
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_INIT	0x0001		/* initialize (RS) */
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_STRT	0x0002		/* start (RS) */
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_STOP	0x0004		/* stop (RS) */
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_TDMD	0x0008		/* transmit demand (RS) */
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_TXON	0x0010		/* transmitter on (R) */
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_RXON	0x0020		/* receiver on (R) */
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_INEA	0x0040		/* interrupt enable (RW) */
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_INTR	0x0080		/* interrupt active (R) */
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_IDON	0x0100		/* initialization done (RC) */
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_TINT	0x0200		/* transmitter interrupt (RC) */
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_RINT	0x0400		/* receiver interrupt (RC) */
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_MERR	0x0800		/* memory error (RC) */
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_MISS	0x1000		/* missed frame (RC) */
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_CERR	0x2000		/* carrier error (no heartbeat :-) (RC) */
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_BABL	0x4000		/* babble: tx-ed too many bits (RC) */
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_ERR	0x8000		/* error (RC) */
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* CSR3 */
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR3_BCON	0x0001		/* byte control */
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR3_ACON	0x0002		/* ALE control */
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR3_BSWP	0x0004		/* byte swap (1=big endian) */
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/***************************** Prototypes *****************************/
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_probe( struct net_device *dev);
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_open( struct net_device *dev );
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lance_init_ring( struct net_device *dev );
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_start_xmit( struct sk_buff *skb, struct net_device *dev );
2397d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t lance_interrupt( int irq, void *dev_id);
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_rx( struct net_device *dev );
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_close( struct net_device *dev );
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void set_multicast_list( struct net_device *dev );
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************* End of Prototypes **************************/
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct net_device * __init sun3lance_probe(int unit)
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static int found;
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = -ENODEV;
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2520f734484ac51711f6b9e48b42242e19e88eb2926Geert Uytterhoeven	if (!MACH_IS_SUN3 && !MACH_IS_SUN3X)
2530f734484ac51711f6b9e48b42242e19e88eb2926Geert Uytterhoeven		return ERR_PTR(-ENODEV);
2540f734484ac51711f6b9e48b42242e19e88eb2926Geert Uytterhoeven
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check that this machine has an onboard lance */
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch(idprom->id_machtype) {
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SM_SUN3|SM_3_50:
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SM_SUN3|SM_3_60:
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SM_SUN3X|SM_3_80:
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* these machines have lance */
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ERR_PTR(-ENODEV);
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (found)
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ERR_PTR(-ENODEV);
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev = alloc_etherdev(sizeof(struct lance_private));
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev)
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ERR_PTR(-ENOMEM);
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unit >= 0) {
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sprintf(dev->name, "eth%d", unit);
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netdev_boot_setup_check(dev);
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!lance_probe(dev))
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = register_netdev(dev);
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out1;
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	found = 1;
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return dev;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout1:
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SUN3
289437111ca381263520d23c877e55e0a83558e79daAl Viro	iounmap((void __iomem *)dev->base_addr);
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_netdev(dev);
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ERR_PTR(err);
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2962160187a0a1cdeeeff1d41f53333bea91c82f259Alexander Beregalovstatic const struct net_device_ops lance_netdev_ops = {
2972160187a0a1cdeeeff1d41f53333bea91c82f259Alexander Beregalov	.ndo_open		= lance_open,
2982160187a0a1cdeeeff1d41f53333bea91c82f259Alexander Beregalov	.ndo_stop		= lance_close,
2992160187a0a1cdeeeff1d41f53333bea91c82f259Alexander Beregalov	.ndo_start_xmit		= lance_start_xmit,
300afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko	.ndo_set_rx_mode	= set_multicast_list,
3012160187a0a1cdeeeff1d41f53333bea91c82f259Alexander Beregalov	.ndo_set_mac_address	= NULL,
3022160187a0a1cdeeeff1d41f53333bea91c82f259Alexander Beregalov	.ndo_change_mtu		= eth_change_mtu,
3032160187a0a1cdeeeff1d41f53333bea91c82f259Alexander Beregalov	.ndo_validate_addr	= eth_validate_addr,
3042160187a0a1cdeeeff1d41f53333bea91c82f259Alexander Beregalov};
3052160187a0a1cdeeeff1d41f53333bea91c82f259Alexander Beregalov
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init lance_probe( struct net_device *dev)
3076aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik{
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long ioaddr;
3096aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_private	*lp;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int 			i;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static int 		did_version;
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile unsigned short *ioaddr_probe;
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short tmp1, tmp2;
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SUN3
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ioaddr = (unsigned long)ioremap(LANCE_OBIO, PAGE_SIZE);
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ioaddr)
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ioaddr = SUN3X_LANCE;
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* test to see if there's really a lance here */
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* (CSRO_INIT shouldn't be readable) */
3266aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ioaddr_probe = (volatile unsigned short *)ioaddr;
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp1 = ioaddr_probe[0];
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp2 = ioaddr_probe[1];
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ioaddr_probe[1] = CSR0;
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ioaddr_probe[0] = CSR0_INIT | CSR0_STOP;
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(ioaddr_probe[0] != CSR0_STOP) {
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ioaddr_probe[0] = tmp1;
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ioaddr_probe[1] = tmp2;
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SUN3
339437111ca381263520d23c877e55e0a83558e79daAl Viro		iounmap((void __iomem *)ioaddr);
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp = netdev_priv(dev);
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* XXX - leak? */
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM = dvma_malloc_align(sizeof(struct lance_memory), 0x10000);
348c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov	if (MEM == NULL) {
349c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov#ifdef CONFIG_SUN3
350c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov		iounmap((void __iomem *)ioaddr);
351c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov#endif
352c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov		printk(KERN_WARNING "SUN3 Lance couldn't allocate DVMA memory\n");
353c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov		return 0;
354c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov	}
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->iobase = (volatile unsigned short *)ioaddr;
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->base_addr = (unsigned long)ioaddr; /* informational only */
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3596aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	REGA(CSR0) = CSR0_STOP;
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
361c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov	if (request_irq(LANCE_IRQ, lance_interrupt, IRQF_DISABLED, "SUN3 Lance", dev) < 0) {
362c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov#ifdef CONFIG_SUN3
363c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov		iounmap((void __iomem *)ioaddr);
364c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov#endif
365c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov		dvma_free((void *)MEM);
366c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov		printk(KERN_WARNING "SUN3 Lance unable to allocate IRQ\n");
367c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov		return 0;
368c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov	}
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->irq = (unsigned short)LANCE_IRQ;
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("%s: SUN3 Lance at io %#lx, mem %#lx, irq %d, hwaddr ",
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   dev->name,
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   (unsigned long)ioaddr,
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   (unsigned long)MEM,
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   dev->irq);
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* copy in the ethernet address from the prom */
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for(i = 0; i < 6 ; i++)
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     dev->dev_addr[i] = idprom->id_ethaddr[i];
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* tell the card it's ether address, bytes swapped */
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.hwaddr[0] = dev->dev_addr[1];
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.hwaddr[1] = dev->dev_addr[0];
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.hwaddr[2] = dev->dev_addr[3];
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.hwaddr[3] = dev->dev_addr[2];
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.hwaddr[4] = dev->dev_addr[5];
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.hwaddr[5] = dev->dev_addr[4];
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
390e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg	printk("%pM\n", dev->dev_addr);
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.mode = 0x0000;
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.filter[0] = 0x00000000;
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.filter[1] = 0x00000000;
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.rdra = dvma_vtob(MEM->rx_head);
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.rlen    = (RX_LOG_RING_SIZE << 13) |
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(dvma_vtob(MEM->rx_head) >> 16);
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.tdra = dvma_vtob(MEM->tx_head);
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.tlen    = (TX_LOG_RING_SIZE << 13) |
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(dvma_vtob(MEM->tx_head) >> 16);
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK(2, ("initaddr: %08lx rx_ring: %08lx tx_ring: %08lx\n",
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       dvma_vtob(&(MEM->init)), dvma_vtob(MEM->rx_head),
4046aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	       (dvma_vtob(MEM->tx_head))));
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (did_version++ == 0)
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk( version );
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4092160187a0a1cdeeeff1d41f53333bea91c82f259Alexander Beregalov	dev->netdev_ops = &lance_netdev_ops;
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//	KLUDGE -- REMOVE ME
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_bit(__LINK_STATE_PRESENT, &dev->state);
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_open( struct net_device *dev )
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_private *lp = netdev_priv(dev);
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK( 2, ( "%s: lance_open()\n", dev->name ));
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA(CSR0) = CSR0_STOP;
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lance_init_ring(dev);
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* From now on, AREG is kept to point to CSR0 */
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA(CSR0) = CSR0_INIT;
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i = 1000000;
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (--i > 0)
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (DREG & CSR0_IDON)
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
435cff71e89a8bd1175962b603f88f333883726b851Roel Kluin	if (i <= 0 || (DREG & CSR0_ERR)) {
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DPRINTK( 2, ( "lance_open(): opening %s failed, i=%d, csr0=%04x\n",
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  dev->name, i, DREG ));
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DREG = CSR0_STOP;
439807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet		return -EIO;
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DREG = CSR0_IDON | CSR0_STRT | CSR0_INEA;
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_start_queue(dev);
4456aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK( 2, ( "%s: LANCE is open, csr0 %04x\n", dev->name, DREG ));
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
448807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet	return 0;
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Initialize the LANCE Rx and Tx rings. */
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lance_init_ring( struct net_device *dev )
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_private *lp = netdev_priv(dev);
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->lock = 0;
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->tx_full = 0;
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->new_rx = lp->new_tx = 0;
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->old_rx = lp->old_tx = 0;
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for( i = 0; i < TX_RING_SIZE; i++ ) {
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->tx_head[i].base = dvma_vtob(MEM->tx_data[i]);
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->tx_head[i].flag = 0;
4676aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 		MEM->tx_head[i].base_hi =
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(dvma_vtob(MEM->tx_data[i])) >>16;
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->tx_head[i].length = 0;
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->tx_head[i].misc = 0;
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for( i = 0; i < RX_RING_SIZE; i++ ) {
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->rx_head[i].base = dvma_vtob(MEM->rx_data[i]);
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->rx_head[i].flag = RMD1_OWN_CHIP;
4766aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		MEM->rx_head[i].base_hi =
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(dvma_vtob(MEM->rx_data[i])) >> 16;
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->rx_head[i].buf_length = -PKT_BUF_SZ | 0xf000;
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->rx_head[i].msg_length = 0;
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* tell the card it's ether address, bytes swapped */
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.hwaddr[0] = dev->dev_addr[1];
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.hwaddr[1] = dev->dev_addr[0];
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.hwaddr[2] = dev->dev_addr[3];
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.hwaddr[3] = dev->dev_addr[2];
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.hwaddr[4] = dev->dev_addr[5];
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.hwaddr[5] = dev->dev_addr[4];
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.mode = 0x0000;
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.filter[0] = 0x00000000;
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.filter[1] = 0x00000000;
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.rdra = dvma_vtob(MEM->rx_head);
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.rlen    = (RX_LOG_RING_SIZE << 13) |
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(dvma_vtob(MEM->rx_head) >> 16);
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.tdra = dvma_vtob(MEM->tx_head);
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.tlen    = (TX_LOG_RING_SIZE << 13) |
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(dvma_vtob(MEM->tx_head) >> 16);
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* tell the lance the address of its init block */
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA(CSR1) = dvma_vtob(&(MEM->init));
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA(CSR2) = dvma_vtob(&(MEM->init)) >> 16;
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SUN3X
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA(CSR3) = CSR3_BSWP | CSR3_ACON | CSR3_BCON;
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA(CSR3) = CSR3_BSWP;
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_private *lp = netdev_priv(dev);
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int entry, len;
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_tx_head *head;
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK( 1, ( "%s: transmit start.\n",
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      dev->name));
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Transmitter timeout, serious problems. */
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (netif_queue_stopped(dev)) {
5261ae5dc342ac78d7a42965fd1f323815f6f5ef2c1Eric Dumazet		int tickssofar = jiffies - dev_trans_start(dev);
5271ae5dc342ac78d7a42965fd1f323815f6f5ef2c1Eric Dumazet		if (tickssofar < HZ/5)
5285b548140225c6bbbbd560551dd1048b2c0ce58bePatrick McHardy			return NETDEV_TX_BUSY;
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DPRINTK( 1, ( "%s: transmit timed out, status %04x, resetting.\n",
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  dev->name, DREG ));
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DREG = CSR0_STOP;
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Always set BSWP after a STOP as STOP puts it back into
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * little endian mode.
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		REGA(CSR3) = CSR3_BSWP;
53809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik		dev->stats.tx_errors++;
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(lance_debug >= 2) {
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int i;
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("Ring data: old_tx %d new_tx %d%s new_rx %d\n",
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       lp->old_tx, lp->new_tx,
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       lp->tx_full ? " (full)" : "",
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       lp->new_rx );
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for( i = 0 ; i < RX_RING_SIZE; i++ )
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk( "rx #%d: base=%04x blen=%04x mlen=%04x\n",
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					i, MEM->rx_head[i].base,
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					-MEM->rx_head[i].buf_length,
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					MEM->rx_head[i].msg_length);
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for( i = 0 ; i < TX_RING_SIZE; i++ )
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk("tx #%d: base=%04x len=%04x misc=%04x\n",
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       i, MEM->tx_head[i].base,
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       -MEM->tx_head[i].length,
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       MEM->tx_head[i].misc );
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lance_init_ring(dev);
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		REGA( CSR0 ) = CSR0_INEA | CSR0_INIT | CSR0_STRT;
5606aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_start_queue(dev);
5626aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
5636ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy		return NETDEV_TX_OK;
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5666aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Block a timer-based transmit from overlapping.  This could better be
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Block a timer-based transmit from overlapping with us by
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   stopping the queue for a bit... */
5726aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_stop_queue(dev);
5746aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (test_and_set_bit( 0, (void*)&lp->lock ) != 0) {
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk( "%s: tx queue lock!.\n", dev->name);
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* don't clear dev->tbusy flag. */
5785b548140225c6bbbbd560551dd1048b2c0ce58bePatrick McHardy		return NETDEV_TX_BUSY;
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AREG = CSR0;
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  	DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n",
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  				  dev->name, DREG ));
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SUN3X
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* this weirdness doesn't appear on sun3... */
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(!(DREG & CSR0_INIT)) {
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DPRINTK( 1, ("INIT not set, reinitializing...\n"));
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		REGA( CSR0 ) = CSR0_STOP;
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lance_init_ring(dev);
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		REGA( CSR0 ) = CSR0_INIT | CSR0_STRT;
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Fill in a Tx ring entry */
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lance_debug >= 2) {
5980795af5729b18218767fab27c44b1384f72dc9adJoe Perches		printk( "%s: TX pkt %d type 0x%04x"
5990795af5729b18218767fab27c44b1384f72dc9adJoe Perches			" from %s to %s"
6000795af5729b18218767fab27c44b1384f72dc9adJoe Perches			" data at 0x%08x len %d\n",
6010795af5729b18218767fab27c44b1384f72dc9adJoe Perches			dev->name, lp->new_tx, ((u_short *)skb->data)[6],
6020795af5729b18218767fab27c44b1384f72dc9adJoe Perches			DEV_ADDR(&skb->data[6]), DEV_ADDR(skb->data),
6030795af5729b18218767fab27c44b1384f72dc9adJoe Perches			(int)skb->data, (int)skb->len );
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6056aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik#endif
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We're not prepared for the int until the last flags are set/reset.
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * And the int may happen already after setting the OWN_CHIP... */
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	local_irq_save(flags);
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Mask to ring buffer boundary. */
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	entry = lp->new_tx;
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head  = &(MEM->tx_head[entry]);
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Caution: the write order is important here, set the "ownership" bits
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * last.
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* the sun3's lance needs it's buffer padded to the minimum
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   size */
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//	head->length = -len;
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head->length = (-len) | 0xf000;
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head->misc = 0;
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
626d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo	skb_copy_from_linear_data(skb, PKTBUF_ADDR(head), skb->len);
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (len != skb->len)
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memset(PKTBUF_ADDR(head) + skb->len, 0, len-skb->len);
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP;
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->new_tx = (lp->new_tx + 1) & TX_RING_MOD_MASK;
63209f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik	dev->stats.tx_bytes += skb->len;
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Trigger an immediate send poll. */
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA(CSR0) = CSR0_INEA | CSR0_TDMD | CSR0_STRT;
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AREG = CSR0;
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  	DPRINTK( 2, ( "%s: lance_start_xmit() exiting, csr0 %4.4x.\n",
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  				  dev->name, DREG ));
6391ae5dc342ac78d7a42965fd1f323815f6f5ef2c1Eric Dumazet	dev_kfree_skb(skb);
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->lock = 0;
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((MEM->tx_head[(entry+1) & TX_RING_MOD_MASK].flag & TMD1_OWN) ==
6436aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	    TMD1_OWN_HOST)
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_start_queue(dev);
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	local_irq_restore(flags);
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6486ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy	return NETDEV_TX_OK;
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The LANCE interrupt handler. */
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6537d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t lance_interrupt( int irq, void *dev_id)
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = dev_id;
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_private *lp = netdev_priv(dev);
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int csr0;
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static int in_interrupt;
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev == NULL) {
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DPRINTK( 1, ( "lance_interrupt(): invalid dev_id\n" ));
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return IRQ_NONE;
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (in_interrupt)
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DPRINTK( 2, ( "%s: Re-entering the interrupt handler.\n", dev->name ));
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	in_interrupt = 1;
6686aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds still_more:
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flush_cache_all();
6716aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AREG = CSR0;
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	csr0 = DREG;
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* ack interrupts */
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DREG = csr0 & (CSR0_TINT | CSR0_RINT | CSR0_IDON);
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* clear errors */
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(csr0 & CSR0_ERR)
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DREG = CSR0_BABL | CSR0_MERR | CSR0_CERR | CSR0_MISS;
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK( 2, ( "%s: interrupt  csr0=%04x new csr=%04x.\n",
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      dev->name, csr0, DREG ));
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (csr0 & CSR0_TINT) {			/* Tx-done interrupt */
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int old_tx = lp->old_tx;
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//		if(lance_debug >= 3) {
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//			int i;
6916aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik//
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//			printk("%s: tx int\n", dev->name);
6936aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik//
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//			for(i = 0; i < TX_RING_SIZE; i++)
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//				printk("ring %d flag=%04x\n", i,
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//				       MEM->tx_head[i].flag);
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//		}
6986aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while( old_tx != lp->new_tx) {
7006aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			struct lance_tx_head *head = &(MEM->tx_head[old_tx]);
7016aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DPRINTK(3, ("on tx_ring %d\n", old_tx));
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (head->flag & TMD1_OWN_CHIP)
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break; /* It still hasn't been Txed */
7066aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (head->flag & TMD1_ERR) {
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				int status = head->misc;
70909f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik				dev->stats.tx_errors++;
71009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik				if (status & TMD3_RTRY) dev->stats.tx_aborted_errors++;
71109f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik				if (status & TMD3_LCAR) dev->stats.tx_carrier_errors++;
71209f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik				if (status & TMD3_LCOL) dev->stats.tx_window_errors++;
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (status & (TMD3_UFLO | TMD3_BUFF)) {
71409f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik					dev->stats.tx_fifo_errors++;
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk("%s: Tx FIFO error\n",
7166aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik					       dev->name);
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					REGA(CSR0) = CSR0_STOP;
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					REGA(CSR3) = CSR3_BSWP;
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					lance_init_ring(dev);
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					REGA(CSR0) = CSR0_STRT | CSR0_INEA;
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return IRQ_HANDLED;
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if(head->flag & (TMD1_ENP | TMD1_STP)) {
7246aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				head->flag &= ~(TMD1_ENP | TMD1_STP);
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if(head->flag & (TMD1_ONE | TMD1_MORE))
72709f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik					dev->stats.collisions++;
7286aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
72909f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik				dev->stats.tx_packets++;
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				DPRINTK(3, ("cleared tx ring %d\n", old_tx));
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			old_tx = (old_tx +1) & TX_RING_MOD_MASK;
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->old_tx = old_tx;
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (netif_queue_stopped(dev)) {
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* The ring is no longer full, clear tbusy. */
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_start_queue(dev);
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_wake_queue(dev);
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (csr0 & CSR0_RINT)			/* Rx interrupt */
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lance_rx( dev );
7476aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Log misc errors. */
74909f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik	if (csr0 & CSR0_BABL) dev->stats.tx_errors++; /* Tx babble. */
75009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik	if (csr0 & CSR0_MISS) dev->stats.rx_errors++; /* Missed a Rx frame. */
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (csr0 & CSR0_MERR) {
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DPRINTK( 1, ( "%s: Bus master arbitration failure (?!?), "
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "status %04x.\n", dev->name, csr0 ));
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Restart the chip. */
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		REGA(CSR0) = CSR0_STOP;
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		REGA(CSR3) = CSR3_BSWP;
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lance_init_ring(dev);
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		REGA(CSR0) = CSR0_STRT | CSR0_INEA;
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Clear any other interrupt, and set interrupt enable. */
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//	DREG = CSR0_BABL | CSR0_CERR | CSR0_MISS | CSR0_MERR |
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//		   CSR0_IDON | CSR0_INEA;
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA(CSR0) = CSR0_INEA;
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(DREG & (CSR0_RINT | CSR0_TINT)) {
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     DPRINTK(2, ("restarting interrupt, csr0=%#04x\n", DREG));
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     goto still_more;
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK( 2, ( "%s: exiting interrupt, csr0=%#04x.\n",
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  dev->name, DREG ));
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	in_interrupt = 0;
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_HANDLED;
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* get packet, toss into skbuff */
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_rx( struct net_device *dev )
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_private *lp = netdev_priv(dev);
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int entry = lp->new_rx;
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* If we own the next entry, it's a new packet. Send it up. */
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while( (MEM->rx_head[entry].flag & RMD1_OWN) == RMD1_OWN_HOST ) {
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct lance_rx_head *head = &(MEM->rx_head[entry]);
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int status = head->flag;
7896aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status != (RMD1_ENP|RMD1_STP)) {  /* There was an error. */
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* There is a tricky error noted by John Murphy,
7926aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			   <murf@perftech.com> to Russ Nelson: Even with
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   full-sized buffers it's possible for a jabber packet to use two
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   buffers, with only the last correctly noting the error. */
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (status & RMD1_ENP)	/* Only count a general error at the */
79609f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik				dev->stats.rx_errors++; /* end of a packet.*/
79709f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik			if (status & RMD1_FRAM) dev->stats.rx_frame_errors++;
79809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik			if (status & RMD1_OFLO) dev->stats.rx_over_errors++;
79909f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik			if (status & RMD1_CRC) dev->stats.rx_crc_errors++;
80009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik			if (status & RMD1_BUFF) dev->stats.rx_fifo_errors++;
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			head->flag &= (RMD1_ENP|RMD1_STP);
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Malloc up new buffer, compatible with net-3. */
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//			short pkt_len = head->msg_length;// & 0xfff;
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			short pkt_len = (head->msg_length & 0xfff) - 4;
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct sk_buff *skb;
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (pkt_len < 60) {
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk( "%s: Runt packet!\n", dev->name );
81009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik				dev->stats.rx_errors++;
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else {
8131d266430546acf01438ae42d0a7370db4817e2adPradeep A Dalvi				skb = netdev_alloc_skb(dev, pkt_len + 2);
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (skb == NULL) {
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					DPRINTK( 1, ( "%s: Memory squeeze, deferring packet.\n",
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						      dev->name ));
8176aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
81809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik					dev->stats.rx_dropped++;
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					head->msg_length = 0;
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					head->flag |= RMD1_OWN_CHIP;
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					lp->new_rx = (lp->new_rx+1) &
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					     RX_RING_MOD_MASK;
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (lance_debug >= 3) {
8270795af5729b18218767fab27c44b1384f72dc9adJoe Perches					u_char *data = PKTBUF_ADDR(head);
8280795af5729b18218767fab27c44b1384f72dc9adJoe Perches					printk("%s: RX pkt %d type 0x%04x"
829e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg					       " from %pM to %pM",
8300795af5729b18218767fab27c44b1384f72dc9adJoe Perches					       dev->name, lp->new_tx, ((u_short *)data)[6],
831e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg					       &data[6], data);
8320795af5729b18218767fab27c44b1384f72dc9adJoe Perches
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk(" data %02x %02x %02x %02x %02x %02x %02x %02x "
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       "len %d at %08x\n",
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       data[15], data[16], data[17], data[18],
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       data[19], data[20], data[21], data[22],
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       pkt_len, data);
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (lance_debug >= 3) {
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					u_char *data = PKTBUF_ADDR(head);
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk( "%s: RX pkt %d type 0x%04x len %d\n ", dev->name, entry, ((u_short *)data)[6], pkt_len);
8436aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik				}
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb_reserve( skb, 2 );	/* 16 byte align */
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb_put( skb, pkt_len );	/* Make room */
8488c7b7faaa630fef7f68d8728cee1cce398cc9697David S. Miller				skb_copy_to_linear_data(skb,
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						 PKTBUF_ADDR(head),
8508c7b7faaa630fef7f68d8728cee1cce398cc9697David S. Miller						 pkt_len);
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb->protocol = eth_type_trans( skb, dev );
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				netif_rx( skb );
85409f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik				dev->stats.rx_packets++;
85509f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik				dev->stats.rx_bytes += pkt_len;
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//		head->buf_length = -PKT_BUF_SZ | 0xf000;
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		head->msg_length = 0;
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		head->flag = RMD1_OWN_CHIP;
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		entry = lp->new_rx = (lp->new_rx +1) & RX_RING_MOD_MASK;
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* From lance.c (Donald Becker): */
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We should check that at least two ring entries are free.
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   If not, we should free one and mark stats->rx_dropped++. */
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_close( struct net_device *dev )
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_private *lp = netdev_priv(dev);
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_stop_queue(dev);
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AREG = CSR0;
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK( 2, ( "%s: Shutting down ethercard, status was %2.2x.\n",
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  dev->name, DREG ));
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We stop the LANCE here -- it occasionally polls
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   memory if we don't. */
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DREG = CSR0_STOP;
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Set or clear the multicast filter for this adaptor.
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   num_addrs == -1		Promiscuous mode, receive all packets
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   num_addrs == 0		Normal mode, clear multicast list
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   num_addrs > 0		Multicast mode, receive normal and MC packets, and do
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						best-effort filtering.
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* completely untested on a sun3 */
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void set_multicast_list( struct net_device *dev )
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_private *lp = netdev_priv(dev);
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(netif_queue_stopped(dev))
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Only possible if board is already started */
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We take the simple way out and always enable promiscuous mode. */
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DREG = CSR0_STOP; /* Temporarily stop the lance. */
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->flags & IFF_PROMISC) {
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Log any net taps. */
913d5b20697ca37d80cc4ec2ba3c5ddf1339dc1d49aAndy Gospodarek		DPRINTK( 3, ( "%s: Promiscuous mode enabled.\n", dev->name ));
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		REGA( CSR15 ) = 0x8000; /* Set promiscuous mode */
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		short multicast_table[4];
9174cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko		int num_addrs = netdev_mc_count(dev);
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int i;
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* We don't use the multicast table, but rely on upper-layer
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * filtering. */
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memset( multicast_table, (num_addrs == 0) ? 0 : -1,
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sizeof(multicast_table) );
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for( i = 0; i < 4; i++ )
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			REGA( CSR8+i ) = multicast_table[i];
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		REGA( CSR15 ) = 0; /* Unset promiscuous mode */
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Always set BSWP after a STOP as STOP puts it back into
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * little endian mode.
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA( CSR3 ) = CSR3_BSWP;
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Resume normal operation and reset AREG to CSR0 */
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA( CSR0 ) = CSR0_IDON | CSR0_INEA | CSR0_STRT;
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef MODULE
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device *sun3lance_dev;
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
943afc8eb46c0ea2cab8bc28713b2e0614f015a7516Al Viroint __init init_module(void)
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sun3lance_dev = sun3lance_probe(-1);
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (IS_ERR(sun3lance_dev))
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return PTR_ERR(sun3lance_dev);
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
951afc8eb46c0ea2cab8bc28713b2e0614f015a7516Al Virovoid __exit cleanup_module(void)
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unregister_netdev(sun3lance_dev);
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SUN3
955437111ca381263520d23c877e55e0a83558e79daAl Viro	iounmap((void __iomem *)sun3lance_dev->base_addr);
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_netdev(sun3lance_dev);
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* MODULE */
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
962