sun3lance.c revision afc8eb46c0ea2cab8bc28713b2e0614f015a7516
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/slab.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41a1f8e7f7fb9d7e2cbcb53170edca7c0ac4680697Al Viro#include <asm/cacheflush.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/setup.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pgtable.h>
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/dvma.h>
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/idprom.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/machines.h>
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SUN3
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/sun3mmu.h>
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/sun3xprom.h>
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* sun3/60 addr/irq for the lance chip.  If your sun is different,
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   change this. */
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LANCE_OBIO 0x120000
594facfde9f1d7b8a61fb0017460da45e23e60115cRoman Zippel#define LANCE_IRQ IRQ_AUTO_3
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Debug level:
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  0 = silent, print only serious errors
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  1 = normal, print error messages
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  2 = debug, print debug infos
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  3 = debug, print even more debug infos (packet data)
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	LANCE_DEBUG	0
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef LANCE_DEBUG
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_debug = LANCE_DEBUG;
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_debug = 1;
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
758d3b33f67fdc0fb364a1ef6d8fbbea7c2e4e6c98Rusty Russellmodule_param(lance_debug, int, 0);
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(lance_debug, "SUN3 Lance debug level (0-3)");
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DPRINTK(n,a) \
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {  \
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (lance_debug >= n)  \
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk a; \
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while( 0 )
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* we're only using 32k of memory, so we use 4 TX
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   buffers and 16 RX buffers.  These values are expressed as log2. */
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_LOG_RING_SIZE			3
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_LOG_RING_SIZE			5
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* These are the derived values */
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_RING_SIZE			(1 << TX_LOG_RING_SIZE)
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_RING_LEN_BITS		(TX_LOG_RING_SIZE << 5)
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	TX_RING_MOD_MASK		(TX_RING_SIZE - 1)
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_RING_SIZE			(1 << RX_LOG_RING_SIZE)
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_RING_LEN_BITS		(RX_LOG_RING_SIZE << 5)
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	RX_RING_MOD_MASK		(RX_RING_SIZE - 1)
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Definitions for packet buffer access: */
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PKT_BUF_SZ		1544
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Get the address of a packet buffer corresponding to a given buffer head */
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	PKTBUF_ADDR(head)	(void *)((unsigned long)(MEM) | (head)->base)
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The LANCE Rx and Tx ring descriptors. */
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_rx_head {
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short	base;		/* Low word of base addr */
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile unsigned char	flag;
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char  base_hi;	/* High word of base addr (unused) */
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	short buf_length;	/* This length is 2s complement! */
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile short msg_length;	/* This length is "normal". */
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_tx_head {
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short base;		/* Low word of base addr */
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile unsigned char	flag;
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char base_hi;	/* High word of base addr (unused) */
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	short length;		/* Length is 2s complement! */
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile short misc;
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The LANCE initialization block, described in databook. */
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_init_block {
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short	mode;		/* Pre-set mode */
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char	hwaddr[6];	/* Physical ethernet address */
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int    filter[2];	/* Multicast filter (unused). */
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Receive and transmit ring base, along with length bits. */
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short rdra;
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short rlen;
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short tdra;
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short tlen;
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short pad[4]; /* is thie needed? */
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The whole layout of the Lance shared memory */
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_memory {
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_init_block	init;
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_tx_head	tx_head[TX_RING_SIZE];
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_rx_head	rx_head[RX_RING_SIZE];
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char   rx_data[RX_RING_SIZE][PKT_BUF_SZ];
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char   tx_data[TX_RING_SIZE][PKT_BUF_SZ];
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The driver's private device structure */
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_private {
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile unsigned short	*iobase;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_memory	*mem;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds     	int new_rx, new_tx;	/* The next free ring entry */
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int old_tx, old_rx;     /* ring entry to be processed */
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device_stats stats;
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* These two must be longs for set_bit() */
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long	    tx_full;
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long	    lock;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* I/O register access macros */
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MEM	lp->mem
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DREG	lp->iobase[0]
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	AREG	lp->iobase[1]
166e345d5ef6d476cc236f64d90d9528143a70745c8Al Viro#define	REGA(a)	(*( AREG = (a), &DREG ))
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Definitions for the Lance */
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* tx_head flags */
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_ENP		0x01	/* end of packet */
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_STP		0x02	/* start of packet */
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_DEF		0x04	/* deferred */
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_ONE		0x08	/* one retry needed */
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_MORE		0x10	/* more than one retry needed */
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_ERR		0x40	/* error summary */
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_OWN 		0x80	/* ownership (set: chip owns) */
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_OWN_CHIP	TMD1_OWN
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_OWN_HOST	0
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* tx_head misc field */
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_TDR		0x03FF	/* Time Domain Reflectometry counter */
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_RTRY		0x0400	/* failed after 16 retries */
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_LCAR		0x0800	/* carrier lost */
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_LCOL		0x1000	/* late collision */
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_UFLO		0x4000	/* underflow (late memory) */
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_BUFF		0x8000	/* buffering error (no ENP) */
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* rx_head flags */
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_ENP		0x01	/* end of packet */
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_STP		0x02	/* start of packet */
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_BUFF		0x04	/* buffer error */
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_CRC		0x08	/* CRC error */
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_OFLO		0x10	/* overflow */
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_FRAM		0x20	/* framing error */
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_ERR		0x40	/* error summary */
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_OWN 		0x80	/* ownership (set: ship owns) */
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_OWN_CHIP	RMD1_OWN
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_OWN_HOST	0
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* register names */
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0	0		/* mode/status */
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR1	1		/* init block addr (low) */
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR2	2		/* init block addr (high) */
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR3	3		/* misc */
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR8	8	  	/* address filter */
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR15	15		/* promiscuous mode */
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* CSR0 */
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* (R=readable, W=writeable, S=set on write, C=clear on write) */
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_INIT	0x0001		/* initialize (RS) */
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_STRT	0x0002		/* start (RS) */
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_STOP	0x0004		/* stop (RS) */
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_TDMD	0x0008		/* transmit demand (RS) */
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_TXON	0x0010		/* transmitter on (R) */
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_RXON	0x0020		/* receiver on (R) */
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_INEA	0x0040		/* interrupt enable (RW) */
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_INTR	0x0080		/* interrupt active (R) */
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_IDON	0x0100		/* initialization done (RC) */
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_TINT	0x0200		/* transmitter interrupt (RC) */
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_RINT	0x0400		/* receiver interrupt (RC) */
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_MERR	0x0800		/* memory error (RC) */
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_MISS	0x1000		/* missed frame (RC) */
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_CERR	0x2000		/* carrier error (no heartbeat :-) (RC) */
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_BABL	0x4000		/* babble: tx-ed too many bits (RC) */
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_ERR	0x8000		/* error (RC) */
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* CSR3 */
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR3_BCON	0x0001		/* byte control */
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR3_ACON	0x0002		/* ALE control */
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR3_BSWP	0x0004		/* byte swap (1=big endian) */
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/***************************** Prototypes *****************************/
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_probe( struct net_device *dev);
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_open( struct net_device *dev );
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lance_init_ring( struct net_device *dev );
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_start_xmit( struct sk_buff *skb, struct net_device *dev );
2417d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t lance_interrupt( int irq, void *dev_id);
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_rx( struct net_device *dev );
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_close( struct net_device *dev );
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device_stats *lance_get_stats( struct net_device *dev );
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void set_multicast_list( struct net_device *dev );
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************* End of Prototypes **************************/
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct net_device * __init sun3lance_probe(int unit)
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static int found;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = -ENODEV;
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
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	SET_MODULE_OWNER(dev);
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!lance_probe(dev))
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = register_netdev(dev);
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out1;
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	found = 1;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return dev;
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout1:
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SUN3
290437111ca381263520d23c877e55e0a83558e79daAl Viro	iounmap((void __iomem *)dev->base_addr);
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_netdev(dev);
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ERR_PTR(err);
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init lance_probe( struct net_device *dev)
2986aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik{
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long ioaddr;
3006aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_private	*lp;
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int 			i;
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static int 		did_version;
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile unsigned short *ioaddr_probe;
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short tmp1, tmp2;
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SUN3
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ioaddr = (unsigned long)ioremap(LANCE_OBIO, PAGE_SIZE);
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ioaddr)
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ioaddr = SUN3X_LANCE;
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* test to see if there's really a lance here */
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* (CSRO_INIT shouldn't be readable) */
3176aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ioaddr_probe = (volatile unsigned short *)ioaddr;
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp1 = ioaddr_probe[0];
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp2 = ioaddr_probe[1];
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ioaddr_probe[1] = CSR0;
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ioaddr_probe[0] = CSR0_INIT | CSR0_STOP;
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(ioaddr_probe[0] != CSR0_STOP) {
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ioaddr_probe[0] = tmp1;
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ioaddr_probe[1] = tmp2;
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SUN3
330437111ca381263520d23c877e55e0a83558e79daAl Viro		iounmap((void __iomem *)ioaddr);
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp = netdev_priv(dev);
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* XXX - leak? */
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM = dvma_malloc_align(sizeof(struct lance_memory), 0x10000);
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->iobase = (volatile unsigned short *)ioaddr;
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->base_addr = (unsigned long)ioaddr; /* informational only */
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3436aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	REGA(CSR0) = CSR0_STOP;
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3451fb9df5d3069064c037c81c0ab8bf783ffa5e373Thomas Gleixner	request_irq(LANCE_IRQ, lance_interrupt, IRQF_DISABLED, "SUN3 Lance", dev);
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->irq = (unsigned short)LANCE_IRQ;
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("%s: SUN3 Lance at io %#lx, mem %#lx, irq %d, hwaddr ",
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   dev->name,
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   (unsigned long)ioaddr,
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   (unsigned long)MEM,
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   dev->irq);
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* copy in the ethernet address from the prom */
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for(i = 0; i < 6 ; i++)
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     dev->dev_addr[i] = idprom->id_ethaddr[i];
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* tell the card it's ether address, bytes swapped */
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.hwaddr[0] = dev->dev_addr[1];
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.hwaddr[1] = dev->dev_addr[0];
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.hwaddr[2] = dev->dev_addr[3];
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.hwaddr[3] = dev->dev_addr[2];
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.hwaddr[4] = dev->dev_addr[5];
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.hwaddr[5] = dev->dev_addr[4];
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for( i = 0; i < 6; ++i )
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk( "%02x%s", dev->dev_addr[i], (i < 5) ? ":" : "\n" );
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.mode = 0x0000;
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.filter[0] = 0x00000000;
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.filter[1] = 0x00000000;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.rdra = dvma_vtob(MEM->rx_head);
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.rlen    = (RX_LOG_RING_SIZE << 13) |
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(dvma_vtob(MEM->rx_head) >> 16);
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.tdra = dvma_vtob(MEM->tx_head);
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.tlen    = (TX_LOG_RING_SIZE << 13) |
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(dvma_vtob(MEM->tx_head) >> 16);
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK(2, ("initaddr: %08lx rx_ring: %08lx tx_ring: %08lx\n",
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       dvma_vtob(&(MEM->init)), dvma_vtob(MEM->rx_head),
3826aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	       (dvma_vtob(MEM->tx_head))));
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (did_version++ == 0)
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk( version );
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* The LANCE-specific entries in the device structure. */
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->open = &lance_open;
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->hard_start_xmit = &lance_start_xmit;
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->stop = &lance_close;
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->get_stats = &lance_get_stats;
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->set_multicast_list = &set_multicast_list;
393a5d361fc24b75ea51e219367ee32c64422a2134fAl Viro	dev->set_mac_address = NULL;
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//	KLUDGE -- REMOVE ME
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_bit(__LINK_STATE_PRESENT, &dev->state);
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset( &lp->stats, 0, sizeof(lp->stats) );
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_open( struct net_device *dev )
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_private *lp = netdev_priv(dev);
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK( 2, ( "%s: lance_open()\n", dev->name ));
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA(CSR0) = CSR0_STOP;
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lance_init_ring(dev);
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* From now on, AREG is kept to point to CSR0 */
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA(CSR0) = CSR0_INIT;
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i = 1000000;
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (--i > 0)
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (DREG & CSR0_IDON)
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (i < 0 || (DREG & CSR0_ERR)) {
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DPRINTK( 2, ( "lance_open(): opening %s failed, i=%d, csr0=%04x\n",
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  dev->name, i, DREG ));
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DREG = CSR0_STOP;
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return( -EIO );
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DREG = CSR0_IDON | CSR0_STRT | CSR0_INEA;
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_start_queue(dev);
4316aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK( 2, ( "%s: LANCE is open, csr0 %04x\n", dev->name, DREG ));
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return( 0 );
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Initialize the LANCE Rx and Tx rings. */
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lance_init_ring( struct net_device *dev )
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_private *lp = netdev_priv(dev);
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->lock = 0;
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->tx_full = 0;
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->new_rx = lp->new_tx = 0;
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->old_rx = lp->old_tx = 0;
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for( i = 0; i < TX_RING_SIZE; i++ ) {
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->tx_head[i].base = dvma_vtob(MEM->tx_data[i]);
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->tx_head[i].flag = 0;
4536aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 		MEM->tx_head[i].base_hi =
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(dvma_vtob(MEM->tx_data[i])) >>16;
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->tx_head[i].length = 0;
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->tx_head[i].misc = 0;
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for( i = 0; i < RX_RING_SIZE; i++ ) {
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->rx_head[i].base = dvma_vtob(MEM->rx_data[i]);
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->rx_head[i].flag = RMD1_OWN_CHIP;
4626aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		MEM->rx_head[i].base_hi =
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(dvma_vtob(MEM->rx_data[i])) >> 16;
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->rx_head[i].buf_length = -PKT_BUF_SZ | 0xf000;
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->rx_head[i].msg_length = 0;
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* tell the card it's ether address, bytes swapped */
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.hwaddr[0] = dev->dev_addr[1];
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.hwaddr[1] = dev->dev_addr[0];
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.hwaddr[2] = dev->dev_addr[3];
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.hwaddr[3] = dev->dev_addr[2];
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.hwaddr[4] = dev->dev_addr[5];
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.hwaddr[5] = dev->dev_addr[4];
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.mode = 0x0000;
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.filter[0] = 0x00000000;
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.filter[1] = 0x00000000;
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.rdra = dvma_vtob(MEM->rx_head);
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.rlen    = (RX_LOG_RING_SIZE << 13) |
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(dvma_vtob(MEM->rx_head) >> 16);
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.tdra = dvma_vtob(MEM->tx_head);
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.tlen    = (TX_LOG_RING_SIZE << 13) |
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(dvma_vtob(MEM->tx_head) >> 16);
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* tell the lance the address of its init block */
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA(CSR1) = dvma_vtob(&(MEM->init));
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA(CSR2) = dvma_vtob(&(MEM->init)) >> 16;
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SUN3X
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA(CSR3) = CSR3_BSWP | CSR3_ACON | CSR3_BCON;
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA(CSR3) = CSR3_BSWP;
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_private *lp = netdev_priv(dev);
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int entry, len;
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_tx_head *head;
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK( 1, ( "%s: transmit start.\n",
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      dev->name));
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Transmitter timeout, serious problems. */
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (netif_queue_stopped(dev)) {
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int tickssofar = jiffies - dev->trans_start;
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tickssofar < 20)
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return( 1 );
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DPRINTK( 1, ( "%s: transmit timed out, status %04x, resetting.\n",
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  dev->name, DREG ));
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DREG = CSR0_STOP;
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Always set BSWP after a STOP as STOP puts it back into
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * little endian mode.
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		REGA(CSR3) = CSR3_BSWP;
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->stats.tx_errors++;
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(lance_debug >= 2) {
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int i;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("Ring data: old_tx %d new_tx %d%s new_rx %d\n",
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       lp->old_tx, lp->new_tx,
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       lp->tx_full ? " (full)" : "",
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       lp->new_rx );
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for( i = 0 ; i < RX_RING_SIZE; i++ )
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk( "rx #%d: base=%04x blen=%04x mlen=%04x\n",
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					i, MEM->rx_head[i].base,
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					-MEM->rx_head[i].buf_length,
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					MEM->rx_head[i].msg_length);
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for( i = 0 ; i < TX_RING_SIZE; i++ )
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk("tx #%d: base=%04x len=%04x misc=%04x\n",
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       i, MEM->tx_head[i].base,
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       -MEM->tx_head[i].length,
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       MEM->tx_head[i].misc );
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lance_init_ring(dev);
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		REGA( CSR0 ) = CSR0_INEA | CSR0_INIT | CSR0_STRT;
5466aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_start_queue(dev);
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->trans_start = jiffies;
5496aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5536aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Block a timer-based transmit from overlapping.  This could better be
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Block a timer-based transmit from overlapping with us by
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   stopping the queue for a bit... */
5596aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_stop_queue(dev);
5616aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (test_and_set_bit( 0, (void*)&lp->lock ) != 0) {
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk( "%s: tx queue lock!.\n", dev->name);
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* don't clear dev->tbusy flag. */
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AREG = CSR0;
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  	DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n",
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  				  dev->name, DREG ));
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SUN3X
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* this weirdness doesn't appear on sun3... */
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(!(DREG & CSR0_INIT)) {
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DPRINTK( 1, ("INIT not set, reinitializing...\n"));
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		REGA( CSR0 ) = CSR0_STOP;
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lance_init_ring(dev);
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		REGA( CSR0 ) = CSR0_INIT | CSR0_STRT;
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Fill in a Tx ring entry */
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lance_debug >= 2) {
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u_char *p;
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int i;
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk( "%s: TX pkt %d type 0x%04x from ", dev->name,
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lp->new_tx, ((u_short *)skb->data)[6]);
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for( p = &((u_char *)skb->data)[6], i = 0; i < 6; i++ )
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("%02x%s", *p++, i != 5 ? ":" : "" );
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(" to ");
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for( p = (u_char *)skb->data, i = 0; i < 6; i++ )
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("%02x%s", *p++, i != 5 ? ":" : "" );
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(" data at 0x%08x len %d\n", (int)skb->data,
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       (int)skb->len );
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5976aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik#endif
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We're not prepared for the int until the last flags are set/reset.
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * And the int may happen already after setting the OWN_CHIP... */
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	local_irq_save(flags);
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Mask to ring buffer boundary. */
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	entry = lp->new_tx;
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head  = &(MEM->tx_head[entry]);
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Caution: the write order is important here, set the "ownership" bits
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * last.
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* the sun3's lance needs it's buffer padded to the minimum
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   size */
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//	head->length = -len;
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head->length = (-len) | 0xf000;
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head->misc = 0;
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy( PKTBUF_ADDR(head), (void *)skb->data, skb->len );
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (len != skb->len)
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memset(PKTBUF_ADDR(head) + skb->len, 0, len-skb->len);
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP;
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->new_tx = (lp->new_tx + 1) & TX_RING_MOD_MASK;
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->stats.tx_bytes += skb->len;
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Trigger an immediate send poll. */
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA(CSR0) = CSR0_INEA | CSR0_TDMD | CSR0_STRT;
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AREG = CSR0;
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  	DPRINTK( 2, ( "%s: lance_start_xmit() exiting, csr0 %4.4x.\n",
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  				  dev->name, DREG ));
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->trans_start = jiffies;
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_kfree_skb( skb );
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->lock = 0;
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((MEM->tx_head[(entry+1) & TX_RING_MOD_MASK].flag & TMD1_OWN) ==
6366aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	    TMD1_OWN_HOST)
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_start_queue(dev);
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	local_irq_restore(flags);
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The LANCE interrupt handler. */
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6467d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t lance_interrupt( int irq, void *dev_id)
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = dev_id;
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_private *lp = netdev_priv(dev);
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int csr0;
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static int in_interrupt;
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev == NULL) {
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DPRINTK( 1, ( "lance_interrupt(): invalid dev_id\n" ));
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return IRQ_NONE;
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (in_interrupt)
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DPRINTK( 2, ( "%s: Re-entering the interrupt handler.\n", dev->name ));
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	in_interrupt = 1;
6616aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds still_more:
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flush_cache_all();
6646aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AREG = CSR0;
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	csr0 = DREG;
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* ack interrupts */
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DREG = csr0 & (CSR0_TINT | CSR0_RINT | CSR0_IDON);
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* clear errors */
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(csr0 & CSR0_ERR)
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DREG = CSR0_BABL | CSR0_MERR | CSR0_CERR | CSR0_MISS;
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK( 2, ( "%s: interrupt  csr0=%04x new csr=%04x.\n",
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      dev->name, csr0, DREG ));
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (csr0 & CSR0_TINT) {			/* Tx-done interrupt */
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int old_tx = lp->old_tx;
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//		if(lance_debug >= 3) {
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//			int i;
6846aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik//
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//			printk("%s: tx int\n", dev->name);
6866aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik//
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//			for(i = 0; i < TX_RING_SIZE; i++)
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//				printk("ring %d flag=%04x\n", i,
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//				       MEM->tx_head[i].flag);
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//		}
6916aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while( old_tx != lp->new_tx) {
6936aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			struct lance_tx_head *head = &(MEM->tx_head[old_tx]);
6946aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DPRINTK(3, ("on tx_ring %d\n", old_tx));
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (head->flag & TMD1_OWN_CHIP)
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break; /* It still hasn't been Txed */
6996aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (head->flag & TMD1_ERR) {
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				int status = head->misc;
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lp->stats.tx_errors++;
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (status & TMD3_RTRY) lp->stats.tx_aborted_errors++;
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (status & TMD3_LCAR) lp->stats.tx_carrier_errors++;
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (status & TMD3_LCOL) lp->stats.tx_window_errors++;
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (status & (TMD3_UFLO | TMD3_BUFF)) {
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					lp->stats.tx_fifo_errors++;
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk("%s: Tx FIFO error\n",
7096aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik					       dev->name);
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					REGA(CSR0) = CSR0_STOP;
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					REGA(CSR3) = CSR3_BSWP;
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					lance_init_ring(dev);
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					REGA(CSR0) = CSR0_STRT | CSR0_INEA;
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return IRQ_HANDLED;
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if(head->flag & (TMD1_ENP | TMD1_STP)) {
7176aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				head->flag &= ~(TMD1_ENP | TMD1_STP);
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if(head->flag & (TMD1_ONE | TMD1_MORE))
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					lp->stats.collisions++;
7216aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lp->stats.tx_packets++;
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				DPRINTK(3, ("cleared tx ring %d\n", old_tx));
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			old_tx = (old_tx +1) & TX_RING_MOD_MASK;
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->old_tx = old_tx;
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (netif_queue_stopped(dev)) {
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* The ring is no longer full, clear tbusy. */
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_start_queue(dev);
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_wake_queue(dev);
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (csr0 & CSR0_RINT)			/* Rx interrupt */
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lance_rx( dev );
7406aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Log misc errors. */
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (csr0 & CSR0_BABL) lp->stats.tx_errors++; /* Tx babble. */
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (csr0 & CSR0_MISS) lp->stats.rx_errors++; /* Missed a Rx frame. */
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (csr0 & CSR0_MERR) {
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DPRINTK( 1, ( "%s: Bus master arbitration failure (?!?), "
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      "status %04x.\n", dev->name, csr0 ));
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Restart the chip. */
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		REGA(CSR0) = CSR0_STOP;
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		REGA(CSR3) = CSR3_BSWP;
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lance_init_ring(dev);
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		REGA(CSR0) = CSR0_STRT | CSR0_INEA;
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Clear any other interrupt, and set interrupt enable. */
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//	DREG = CSR0_BABL | CSR0_CERR | CSR0_MISS | CSR0_MERR |
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//		   CSR0_IDON | CSR0_INEA;
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA(CSR0) = CSR0_INEA;
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(DREG & (CSR0_RINT | CSR0_TINT)) {
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     DPRINTK(2, ("restarting interrupt, csr0=%#04x\n", DREG));
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     goto still_more;
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK( 2, ( "%s: exiting interrupt, csr0=%#04x.\n",
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  dev->name, DREG ));
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	in_interrupt = 0;
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_HANDLED;
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* get packet, toss into skbuff */
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_rx( struct net_device *dev )
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_private *lp = netdev_priv(dev);
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int entry = lp->new_rx;
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* If we own the next entry, it's a new packet. Send it up. */
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while( (MEM->rx_head[entry].flag & RMD1_OWN) == RMD1_OWN_HOST ) {
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct lance_rx_head *head = &(MEM->rx_head[entry]);
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int status = head->flag;
7826aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status != (RMD1_ENP|RMD1_STP)) {  /* There was an error. */
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* There is a tricky error noted by John Murphy,
7856aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			   <murf@perftech.com> to Russ Nelson: Even with
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   full-sized buffers it's possible for a jabber packet to use two
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   buffers, with only the last correctly noting the error. */
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (status & RMD1_ENP)	/* Only count a general error at the */
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lp->stats.rx_errors++; /* end of a packet.*/
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (status & RMD1_FRAM) lp->stats.rx_frame_errors++;
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (status & RMD1_OFLO) lp->stats.rx_over_errors++;
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (status & RMD1_CRC) lp->stats.rx_crc_errors++;
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (status & RMD1_BUFF) lp->stats.rx_fifo_errors++;
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			head->flag &= (RMD1_ENP|RMD1_STP);
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Malloc up new buffer, compatible with net-3. */
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//			short pkt_len = head->msg_length;// & 0xfff;
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			short pkt_len = (head->msg_length & 0xfff) - 4;
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct sk_buff *skb;
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (pkt_len < 60) {
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk( "%s: Runt packet!\n", dev->name );
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lp->stats.rx_errors++;
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else {
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb = dev_alloc_skb( pkt_len+2 );
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (skb == NULL) {
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					DPRINTK( 1, ( "%s: Memory squeeze, deferring packet.\n",
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						      dev->name ));
8106aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					lp->stats.rx_dropped++;
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					head->msg_length = 0;
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					head->flag |= RMD1_OWN_CHIP;
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					lp->new_rx = (lp->new_rx+1) &
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					     RX_RING_MOD_MASK;
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (lance_debug >= 3) {
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					u_char *data = PKTBUF_ADDR(head), *p;
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk( "%s: RX pkt %d type 0x%04x from ", dev->name, entry, ((u_short *)data)[6]);
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					for( p = &data[6], i = 0; i < 6; i++ )
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						printk("%02x%s", *p++, i != 5 ? ":" : "" );
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk(" to ");
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					for( p = data, i = 0; i < 6; i++ )
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						printk("%02x%s", *p++, i != 5 ? ":" : "" );
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk(" data %02x %02x %02x %02x %02x %02x %02x %02x "
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       "len %d at %08x\n",
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       data[15], data[16], data[17], data[18],
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       data[19], data[20], data[21], data[22],
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       pkt_len, data);
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (lance_debug >= 3) {
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					u_char *data = PKTBUF_ADDR(head);
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk( "%s: RX pkt %d type 0x%04x len %d\n ", dev->name, entry, ((u_short *)data)[6], pkt_len);
8376aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik				}
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb->dev = dev;
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb_reserve( skb, 2 );	/* 16 byte align */
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb_put( skb, pkt_len );	/* Make room */
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//			        memcpy( skb->data, PKTBUF_ADDR(head), pkt_len );
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				eth_copy_and_sum(skb,
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						 PKTBUF_ADDR(head),
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						 pkt_len, 0);
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb->protocol = eth_type_trans( skb, dev );
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				netif_rx( skb );
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dev->last_rx = jiffies;
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lp->stats.rx_packets++;
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lp->stats.rx_bytes += pkt_len;
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//		head->buf_length = -PKT_BUF_SZ | 0xf000;
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		head->msg_length = 0;
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		head->flag = RMD1_OWN_CHIP;
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		entry = lp->new_rx = (lp->new_rx +1) & RX_RING_MOD_MASK;
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* From lance.c (Donald Becker): */
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We should check that at least two ring entries are free.
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   If not, we should free one and mark stats->rx_dropped++. */
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_close( struct net_device *dev )
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_private *lp = netdev_priv(dev);
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_stop_queue(dev);
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AREG = CSR0;
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK( 2, ( "%s: Shutting down ethercard, status was %2.2x.\n",
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  dev->name, DREG ));
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We stop the LANCE here -- it occasionally polls
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   memory if we don't. */
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DREG = CSR0_STOP;
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device_stats *lance_get_stats( struct net_device *dev )
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_private *lp = netdev_priv(dev);
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return &lp->stats;
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Set or clear the multicast filter for this adaptor.
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   num_addrs == -1		Promiscuous mode, receive all packets
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   num_addrs == 0		Normal mode, clear multicast list
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   num_addrs > 0		Multicast mode, receive normal and MC packets, and do
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						best-effort filtering.
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* completely untested on a sun3 */
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void set_multicast_list( struct net_device *dev )
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_private *lp = netdev_priv(dev);
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(netif_queue_stopped(dev))
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Only possible if board is already started */
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We take the simple way out and always enable promiscuous mode. */
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DREG = CSR0_STOP; /* Temporarily stop the lance. */
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->flags & IFF_PROMISC) {
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Log any net taps. */
918d5b20697ca37d80cc4ec2ba3c5ddf1339dc1d49aAndy Gospodarek		DPRINTK( 3, ( "%s: Promiscuous mode enabled.\n", dev->name ));
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		REGA( CSR15 ) = 0x8000; /* Set promiscuous mode */
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		short multicast_table[4];
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int num_addrs = dev->mc_count;
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int i;
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* We don't use the multicast table, but rely on upper-layer
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * filtering. */
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memset( multicast_table, (num_addrs == 0) ? 0 : -1,
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sizeof(multicast_table) );
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for( i = 0; i < 4; i++ )
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			REGA( CSR8+i ) = multicast_table[i];
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		REGA( CSR15 ) = 0; /* Unset promiscuous mode */
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Always set BSWP after a STOP as STOP puts it back into
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * little endian mode.
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA( CSR3 ) = CSR3_BSWP;
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Resume normal operation and reset AREG to CSR0 */
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA( CSR0 ) = CSR0_IDON | CSR0_INEA | CSR0_STRT;
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef MODULE
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device *sun3lance_dev;
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
948afc8eb46c0ea2cab8bc28713b2e0614f015a7516Al Viroint __init init_module(void)
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sun3lance_dev = sun3lance_probe(-1);
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (IS_ERR(sun3lance_dev))
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return PTR_ERR(sun3lance_dev);
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
956afc8eb46c0ea2cab8bc28713b2e0614f015a7516Al Virovoid __exit cleanup_module(void)
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unregister_netdev(sun3lance_dev);
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SUN3
960437111ca381263520d23c877e55e0a83558e79daAl Viro	iounmap((void __iomem *)sun3lance_dev->base_addr);
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_netdev(sun3lance_dev);
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* MODULE */
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
967