atarilance.c revision 6ed106549d17474ca17a16057f4c0ed4eba5a7ca
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* atarilance.c: Ethernet driver for VME Lance cards on the Atari */
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Written 1995/96 by Roman Hodek (Roman.Hodek@informatik.uni-erlangen.de)
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	This software may be used and distributed according to the terms
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	of the GNU General Public License, incorporated herein by reference.
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	This drivers was written with the following sources of reference:
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 - The driver for the Riebl Lance card by the TU Vienna.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 - The modified TUW driver for PAM's VME cards
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 - The PC-Linux driver for Lance cards (but this is for bus master
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds       cards, not the shared memory ones)
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 - The Amiga Ariadne driver
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	v1.0: (in 1.2.13pl4/0.9.13)
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      Initial version
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	v1.1: (in 1.2.13pl5)
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      more comments
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  deleted some debugging stuff
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  optimized register access (keep AREG pointing to CSR0)
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  following AMD, CSR0_STRT should be set only after IDON is detected
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  use memcpy() for data transfers, that also employs long word moves
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  better probe procedure for 24-bit systems
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds          non-VME-RieblCards need extra delays in memcpy
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  must also do write test, since 0xfxe00000 may hit ROM
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  use 8/32 tx/rx buffers, which should give better NFS performance;
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    this is made possible by shifting the last packet buffer after the
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    RieblCard reserved area
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    v1.2: (in 1.2.13pl8)
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      again fixed probing for the Falcon; 0xfe01000 hits phys. 0x00010000
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  and thus RAM, in case of no Lance found all memory contents have to
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  be restored!
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  Now possible to compile as module.
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	v1.3: 03/30/96 Jes Sorensen, Roman (in 1.3)
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      Several little 1.3 adaptions
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  When the lance is stopped it jumps back into little-endian
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  mode. It is therefore necessary to put it back where it
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  belongs, in big endian mode, in order to make things work.
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  This might be the reason why multicast-mode didn't work
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  before, but I'm not able to test it as I only got an Amiga
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  (we had similar problems with the A2065 driver).
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char version[] = "atarilance.c: v1.3 04/04/96 "
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					   "Roman.Hodek@informatik.uni-erlangen.de\n";
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h>
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/stddef.h>
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h>
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h>
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/setup.h>
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h>
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/atarihw.h>
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/atariints.h>
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Debug level:
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  0 = silent, print only serious errors
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  1 = normal, print error messages
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  2 = debug, print debug infos
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  3 = debug, print even more debug infos (packet data)
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	LANCE_DEBUG	1
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef LANCE_DEBUG
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_debug = LANCE_DEBUG;
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_debug = 1;
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
818d3b33f67fdc0fb364a1ef6d8fbbea7c2e4e6c98Rusty Russellmodule_param(lance_debug, int, 0);
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(lance_debug, "atarilance debug level (0-3)");
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Print debug messages on probing? */
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef LANCE_DEBUG_PROBE
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DPRINTK(n,a)							\
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {										\
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (lance_debug >= n)					\
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk a;							\
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while( 0 )
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef LANCE_DEBUG_PROBE
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds# define PROBE_PRINT(a)	printk a
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds# define PROBE_PRINT(a)
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* These define the number of Rx and Tx buffers as log2. (Only powers
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of two are valid)
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Much more rx buffers (32) are reserved than tx buffers (8), since receiving
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is more time critical then sending and packets may have to remain in the
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * board's memory when main memory is low.
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_LOG_RING_SIZE			3
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_LOG_RING_SIZE			5
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* These are the derived values */
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_RING_SIZE			(1 << TX_LOG_RING_SIZE)
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_RING_LEN_BITS		(TX_LOG_RING_SIZE << 5)
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	TX_RING_MOD_MASK		(TX_RING_SIZE - 1)
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_RING_SIZE			(1 << RX_LOG_RING_SIZE)
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_RING_LEN_BITS		(RX_LOG_RING_SIZE << 5)
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	RX_RING_MOD_MASK		(RX_RING_SIZE - 1)
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_TIMEOUT	20
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The LANCE Rx and Tx ring descriptors. */
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_rx_head {
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short			base;		/* Low word of base addr */
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile unsigned char	flag;
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char			base_hi;	/* High word of base addr (unused) */
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	short					buf_length;	/* This length is 2s complement! */
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile short			msg_length;	/* This length is "normal". */
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_tx_head {
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short			base;		/* Low word of base addr */
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile unsigned char	flag;
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char			base_hi;	/* High word of base addr (unused) */
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	short					length;		/* Length is 2s complement! */
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile short			misc;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct ringdesc {
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short	adr_lo;		/* Low 16 bits of address */
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char	len;		/* Length bits */
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char	adr_hi;		/* High 8 bits of address (unused) */
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The LANCE initialization block, described in databook. */
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_init_block {
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short	mode;		/* Pre-set mode */
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char	hwaddr[6];	/* Physical ethernet address */
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned		filter[2];	/* Multicast filter (unused). */
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Receive and transmit ring base, along with length bits. */
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ringdesc	rx_ring;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ringdesc	tx_ring;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The whole layout of the Lance shared memory */
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_memory {
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_init_block	init;
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_tx_head	tx_head[TX_RING_SIZE];
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_rx_head	rx_head[RX_RING_SIZE];
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char					packet_area[0];	/* packet data follow after the
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds											 * init block and the ring
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds											 * descriptors and are located
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds											 * at runtime */
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* RieblCard specifics:
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The original TOS driver for these cards reserves the area from offset
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0xee70 to 0xeebb for storing configuration data. Of interest to us is the
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ethernet address there, and the magic for verifying the data's validity.
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The reserved area isn't touch by packet buffers. Furthermore, offset 0xfffe
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is reserved for the interrupt vector number.
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	RIEBL_RSVD_START	0xee70
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	RIEBL_RSVD_END		0xeec0
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RIEBL_MAGIC			0x09051990
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RIEBL_MAGIC_ADDR	((unsigned long *)(((char *)MEM) + 0xee8a))
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RIEBL_HWADDR_ADDR	((unsigned char *)(((char *)MEM) + 0xee8e))
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RIEBL_IVEC_ADDR		((unsigned short *)(((char *)MEM) + 0xfffe))
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This is a default address for the old RieblCards without a battery
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that have no ethernet address at boot time. 00:00:36:04 is the
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * prefix for Riebl cards, the 00:00 at the end is arbitrary.
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned char OldRieblDefHwaddr[6] = {
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x00, 0x00, 0x36, 0x04, 0x00, 0x00
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* I/O registers of the Lance chip */
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_ioreg {
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* base+0x0 */	volatile unsigned short	data;
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* base+0x2 */	volatile unsigned short	addr;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unsigned char			_dummy1[3];
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* base+0x7 */	volatile unsigned char	ivec;
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unsigned char			_dummy2[5];
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* base+0xd */	volatile unsigned char	eeprom;
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unsigned char			_dummy3;
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* base+0xf */	volatile unsigned char	mem;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Types of boards this driver supports */
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum lance_type {
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	OLD_RIEBL,		/* old Riebl card without battery */
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	NEW_RIEBL,		/* new Riebl card with battery */
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PAM_CARD		/* PAM card with EEPROM */
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *lance_names[] = {
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"Riebl-Card (without battery)",
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"Riebl-Card (with battery)",
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"PAM intern card"
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The driver's private device structure */
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_private {
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enum lance_type		cardtype;
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_ioreg	*iobase;
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_memory	*mem;
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int		 	cur_rx, cur_tx;	/* The next free ring entry */
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			dirty_tx;		/* Ring entries to be freed. */
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* copy function */
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void			*(*memcpy_f)( void *, const void *, size_t );
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This must be long for set_bit() */
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long			tx_full;
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t		devlock;
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* I/O register access macros */
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MEM		lp->mem
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DREG	IO->data
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	AREG	IO->addr
237e345d5ef6d476cc236f64d90d9528143a70745c8Al Viro#define	REGA(a)	(*( AREG = (a), &DREG ))
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Definitions for packet buffer access: */
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PKT_BUF_SZ		1544
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Get the address of a packet buffer corresponding to a given buffer head */
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	PKTBUF_ADDR(head)	(((unsigned char *)(MEM)) + (head)->base)
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Possible memory/IO addresses for probing */
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2463cacd2a1ce5464b9874508927d561c0dfce74637Adrian Bunkstatic struct lance_addr {
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	memaddr;
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	ioaddr;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int				slow_flag;
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} lance_addr_list[] = {
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0xfe010000, 0xfe00fff0, 0 },	/* RieblCard VME in TT */
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0xffc10000, 0xffc0fff0, 0 },	/* RieblCard VME in MegaSTE
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds									   (highest byte stripped) */
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0xffe00000, 0xffff7000, 1 },	/* RieblCard in ST
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds									   (highest byte stripped) */
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0xffd00000, 0xffff7000, 1 },	/* RieblCard in ST with hw modif. to
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds									   avoid conflict with ROM
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds									   (highest byte stripped) */
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0xffcf0000, 0xffcffff0, 0 },	/* PAMCard VME in TT and MSTE
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds									   (highest byte stripped) */
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0xfecf0000, 0xfecffff0, 0 },	/* Rhotron's PAMCard VME in TT and MSTE
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds									   (highest byte stripped) */
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
265ff8ac60948ba819b89e9c87083e8050fc2f89999Denis Cheng#define	N_LANCE_ADDR	ARRAY_SIZE(lance_addr_list)
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Definitions for the Lance */
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* tx_head flags */
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_ENP		0x01	/* end of packet */
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_STP		0x02	/* start of packet */
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_DEF		0x04	/* deferred */
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_ONE		0x08	/* one retry needed */
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_MORE		0x10	/* more than one retry needed */
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_ERR		0x40	/* error summary */
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_OWN 		0x80	/* ownership (set: chip owns) */
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_OWN_CHIP	TMD1_OWN
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_OWN_HOST	0
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* tx_head misc field */
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_TDR		0x03FF	/* Time Domain Reflectometry counter */
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_RTRY		0x0400	/* failed after 16 retries */
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_LCAR		0x0800	/* carrier lost */
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_LCOL		0x1000	/* late collision */
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_UFLO		0x4000	/* underflow (late memory) */
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_BUFF		0x8000	/* buffering error (no ENP) */
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* rx_head flags */
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_ENP		0x01	/* end of packet */
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_STP		0x02	/* start of packet */
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_BUFF		0x04	/* buffer error */
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_CRC		0x08	/* CRC error */
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_OFLO		0x10	/* overflow */
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_FRAM		0x20	/* framing error */
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_ERR		0x40	/* error summary */
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_OWN 		0x80	/* ownership (set: ship owns) */
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_OWN_CHIP	RMD1_OWN
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_OWN_HOST	0
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* register names */
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0	0		/* mode/status */
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR1	1		/* init block addr (low) */
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR2	2		/* init block addr (high) */
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR3	3		/* misc */
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR8	8	  	/* address filter */
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR15	15		/* promiscuous mode */
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* CSR0 */
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* (R=readable, W=writeable, S=set on write, C=clear on write) */
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_INIT	0x0001		/* initialize (RS) */
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_STRT	0x0002		/* start (RS) */
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_STOP	0x0004		/* stop (RS) */
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_TDMD	0x0008		/* transmit demand (RS) */
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_TXON	0x0010		/* transmitter on (R) */
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_RXON	0x0020		/* receiver on (R) */
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_INEA	0x0040		/* interrupt enable (RW) */
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_INTR	0x0080		/* interrupt active (R) */
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_IDON	0x0100		/* initialization done (RC) */
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_TINT	0x0200		/* transmitter interrupt (RC) */
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_RINT	0x0400		/* receiver interrupt (RC) */
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_MERR	0x0800		/* memory error (RC) */
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_MISS	0x1000		/* missed frame (RC) */
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_CERR	0x2000		/* carrier error (no heartbeat :-) (RC) */
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_BABL	0x4000		/* babble: tx-ed too many bits (RC) */
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_ERR	0x8000		/* error (RC) */
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* CSR3 */
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR3_BCON	0x0001		/* byte control */
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR3_ACON	0x0002		/* ALE control */
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR3_BSWP	0x0004		/* byte swap (1=big endian) */
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/***************************** Prototypes *****************************/
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long lance_probe1( struct net_device *dev, struct lance_addr
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                   *init_rec );
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_open( struct net_device *dev );
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lance_init_ring( struct net_device *dev );
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_start_xmit( struct sk_buff *skb, struct net_device *dev );
3447d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t lance_interrupt( int irq, void *dev_id );
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_rx( struct net_device *dev );
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_close( struct net_device *dev );
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void set_multicast_list( struct net_device *dev );
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_set_mac_address( struct net_device *dev, void *addr );
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lance_tx_timeout (struct net_device *dev);
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************* End of Prototypes **************************/
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3556aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void *slow_memcpy( void *dst, const void *src, size_t len )
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{	char *cto = dst;
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const char *cfrom = src;
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while( len-- ) {
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*cto++ = *cfrom++;
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MFPDELAY();
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return( dst );
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct net_device * __init atarilance_probe(int unit)
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static int found;
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = -ENODEV;
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!MACH_IS_ATARI || found)
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Assume there's only one board possible... That seems true, since
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * the Riebl/PAM board's address cannot be changed. */
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ERR_PTR(-ENODEV);
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev = alloc_etherdev(sizeof(struct lance_private));
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev)
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ERR_PTR(-ENOMEM);
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unit >= 0) {
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sprintf(dev->name, "eth%d", unit);
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netdev_boot_setup_check(dev);
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for( i = 0; i < N_LANCE_ADDR; ++i ) {
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (lance_probe1( dev, &lance_addr_list[i] )) {
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			found = 1;
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = register_netdev(dev);
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!err)
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return dev;
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			free_irq(dev->irq, dev);
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_netdev(dev);
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ERR_PTR(err);
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Derived from hwreg_present() in atari/config.c: */
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
407f37c768c39e3aeb8a508e1a45e461a506771445eAdrian Bunkstatic noinline int __init addr_accessible(volatile void *regp, int wordflag,
408f37c768c39e3aeb8a508e1a45e461a506771445eAdrian Bunk					   int writeflag)
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int		ret;
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long	flags;
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long	*vbr, save_berr;
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	local_irq_save(flags);
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__asm__ __volatile__ ( "movec	%/vbr,%0" : "=r" (vbr) : );
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	save_berr = vbr[2];
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__asm__ __volatile__
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(	"movel	%/sp,%/d1\n\t"
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"movel	#Lberr,%2@\n\t"
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"moveq	#0,%0\n\t"
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"tstl   %3\n\t"
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"bne	1f\n\t"
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"moveb	%1@,%/d0\n\t"
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"nop	\n\t"
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"bra	2f\n"
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"1:		 movew	%1@,%/d0\n\t"
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"nop	\n"
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"2:		 tstl   %4\n\t"
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"beq	2f\n\t"
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"tstl	%3\n\t"
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"bne	1f\n\t"
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"clrb	%1@\n\t"
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"nop	\n\t"
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"moveb	%/d0,%1@\n\t"
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"nop	\n\t"
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"bra	2f\n"
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"1:		 clrw	%1@\n\t"
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"nop	\n\t"
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"movew	%/d0,%1@\n\t"
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"nop	\n"
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"2:		 moveq	#1,%0\n"
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"Lberr:	 movel	%/d1,%/sp"
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		: "=&d" (ret)
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		: "a" (regp), "a" (&vbr[2]), "rm" (wordflag), "rm" (writeflag)
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		: "d0", "d1", "memory"
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	);
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vbr[2] = save_berr;
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	local_irq_restore(flags);
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return( ret );
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4568e7678fe0992a6107041b839b08ac4af55d41592Alexander Beregalovstatic const struct net_device_ops lance_netdev_ops = {
4578e7678fe0992a6107041b839b08ac4af55d41592Alexander Beregalov	.ndo_open		= lance_open,
4588e7678fe0992a6107041b839b08ac4af55d41592Alexander Beregalov	.ndo_stop		= lance_close,
4598e7678fe0992a6107041b839b08ac4af55d41592Alexander Beregalov	.ndo_start_xmit		= lance_start_xmit,
4608e7678fe0992a6107041b839b08ac4af55d41592Alexander Beregalov	.ndo_set_multicast_list	= set_multicast_list,
4618e7678fe0992a6107041b839b08ac4af55d41592Alexander Beregalov	.ndo_set_mac_address	= lance_set_mac_address,
4628e7678fe0992a6107041b839b08ac4af55d41592Alexander Beregalov	.ndo_tx_timeout		= lance_tx_timeout,
4638e7678fe0992a6107041b839b08ac4af55d41592Alexander Beregalov	.ndo_validate_addr	= eth_validate_addr,
4648e7678fe0992a6107041b839b08ac4af55d41592Alexander Beregalov	.ndo_change_mtu		= eth_change_mtu,
4658e7678fe0992a6107041b839b08ac4af55d41592Alexander Beregalov};
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long __init lance_probe1( struct net_device *dev,
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					   struct lance_addr *init_rec )
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile unsigned short *memaddr =
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(volatile unsigned short *)init_rec->memaddr;
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile unsigned short *ioaddr =
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(volatile unsigned short *)init_rec->ioaddr;
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_private	*lp;
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_ioreg		*IO;
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int 					i;
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static int 				did_version;
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short			save1, save2;
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PROBE_PRINT(( "Probing for Lance card at mem %#lx io %#lx\n",
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  (long)memaddr, (long)ioaddr ));
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Test whether memory readable and writable */
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PROBE_PRINT(( "lance_probe1: testing memory to be accessible\n" ));
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!addr_accessible( memaddr, 1, 1 )) goto probe_fail;
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Written values should come back... */
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PROBE_PRINT(( "lance_probe1: testing memory to be writable (1)\n" ));
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	save1 = *memaddr;
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*memaddr = 0x0001;
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (*memaddr != 0x0001) goto probe_fail;
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PROBE_PRINT(( "lance_probe1: testing memory to be writable (2)\n" ));
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*memaddr = 0x0000;
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (*memaddr != 0x0000) goto probe_fail;
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*memaddr = save1;
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* First port should be readable and writable */
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PROBE_PRINT(( "lance_probe1: testing ioport to be accessible\n" ));
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!addr_accessible( ioaddr, 1, 1 )) goto probe_fail;
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* and written values should be readable */
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PROBE_PRINT(( "lance_probe1: testing ioport to be writeable\n" ));
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	save2 = ioaddr[1];
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ioaddr[1] = 0x0001;
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ioaddr[1] != 0x0001) goto probe_fail;
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* The CSR0_INIT bit should not be readable */
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PROBE_PRINT(( "lance_probe1: testing CSR0 register function (1)\n" ));
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	save1 = ioaddr[0];
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ioaddr[1] = CSR0;
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ioaddr[0] = CSR0_INIT | CSR0_STOP;
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ioaddr[0] != CSR0_STOP) {
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ioaddr[0] = save1;
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ioaddr[1] = save2;
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto probe_fail;
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PROBE_PRINT(( "lance_probe1: testing CSR0 register function (2)\n" ));
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ioaddr[0] = CSR0_STOP;
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ioaddr[0] != CSR0_STOP) {
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ioaddr[0] = save1;
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ioaddr[1] = save2;
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto probe_fail;
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Now ok... */
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PROBE_PRINT(( "lance_probe1: Lance card detected\n" ));
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto probe_ok;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  probe_fail:
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return( 0 );
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  probe_ok:
533454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen	lp = netdev_priv(dev);
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM = (struct lance_memory *)memaddr;
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IO = lp->iobase = (struct lance_ioreg *)ioaddr;
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->base_addr = (unsigned long)ioaddr; /* informational only */
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->memcpy_f = init_rec->slow_flag ? slow_memcpy : memcpy;
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA( CSR0 ) = CSR0_STOP;
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Now test for type: If the eeprom I/O port is readable, it is a
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * PAM card */
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (addr_accessible( &(IO->eeprom), 0, 0 )) {
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Switch back to Ram */
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i = IO->mem;
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->cardtype = PAM_CARD;
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (*RIEBL_MAGIC_ADDR == RIEBL_MAGIC) {
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->cardtype = NEW_RIEBL;
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->cardtype = OLD_RIEBL;
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lp->cardtype == PAM_CARD ||
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memaddr == (unsigned short *)0xffe00000) {
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* PAMs card and Riebl on ST use level 5 autovector */
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (request_irq(IRQ_AUTO_5, lance_interrupt, IRQ_TYPE_PRIO,
5586aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		            "PAM/Riebl-ST Ethernet", dev)) {
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk( "Lance: request for irq %d failed\n", IRQ_AUTO_5 );
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return( 0 );
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->irq = (unsigned short)IRQ_AUTO_5;
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else {
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For VME-RieblCards, request a free VME int;
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * (This must be unsigned long, since dev->irq is short and the
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * IRQ_MACHSPEC bit would be cut off...)
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned long irq = atari_register_vme_int();
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!irq) {
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk( "Lance: request for VME interrupt failed\n" );
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return( 0 );
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (request_irq(irq, lance_interrupt, IRQ_TYPE_PRIO,
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		            "Riebl-VME Ethernet", dev)) {
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk( "Lance: request for irq %ld failed\n", irq );
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return( 0 );
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->irq = irq;
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("%s: %s at io %#lx, mem %#lx, irq %d%s, hwaddr ",
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   dev->name, lance_names[lp->cardtype],
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   (unsigned long)ioaddr,
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   (unsigned long)memaddr,
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   dev->irq,
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   init_rec->slow_flag ? " (slow memcpy)" : "" );
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Get the ethernet address */
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch( lp->cardtype ) {
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  case OLD_RIEBL:
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* No ethernet address! (Set some default address) */
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy( dev->dev_addr, OldRieblDefHwaddr, 6 );
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  case NEW_RIEBL:
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->memcpy_f( dev->dev_addr, RIEBL_HWADDR_ADDR, 6 );
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  case PAM_CARD:
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i = IO->eeprom;
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for( i = 0; i < 6; ++i )
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->dev_addr[i] =
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				((((unsigned short *)MEM)[i*2] & 0x0f) << 4) |
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				((((unsigned short *)MEM)[i*2+1] & 0x0f));
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i = IO->mem;
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
607e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg	printk("%pM\n", dev->dev_addr);
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lp->cardtype == OLD_RIEBL) {
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk( "%s: Warning: This is a default ethernet address!\n",
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dev->name );
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk( "      Use \"ifconfig hw ether ...\" to set the address.\n" );
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_init(&lp->devlock);
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.mode = 0x0000;		/* Disable Rx and Tx. */
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for( i = 0; i < 6; i++ )
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->init.hwaddr[i] = dev->dev_addr[i^1]; /* <- 16 bit swap! */
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.filter[0] = 0x00000000;
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.filter[1] = 0x00000000;
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.rx_ring.adr_lo = offsetof( struct lance_memory, rx_head );
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.rx_ring.adr_hi = 0;
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.rx_ring.len    = RX_RING_LEN_BITS;
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.tx_ring.adr_lo = offsetof( struct lance_memory, tx_head );
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.tx_ring.adr_hi = 0;
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.tx_ring.len    = TX_RING_LEN_BITS;
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lp->cardtype == PAM_CARD)
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IO->ivec = IRQ_SOURCE_TO_VECTOR(dev->irq);
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*RIEBL_IVEC_ADDR = IRQ_SOURCE_TO_VECTOR(dev->irq);
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (did_version++ == 0)
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DPRINTK( 1, ( version ));
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6368e7678fe0992a6107041b839b08ac4af55d41592Alexander Beregalov	dev->netdev_ops = &lance_netdev_ops;
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* XXX MSch */
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->watchdog_timeo = TX_TIMEOUT;
6406aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return( 1 );
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6446aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_open( struct net_device *dev )
646454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen{
647454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen	struct lance_private *lp = netdev_priv(dev);
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_ioreg	 *IO = lp->iobase;
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK( 2, ( "%s: lance_open()\n", dev->name ));
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lance_init_ring(dev);
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Re-initialize the LANCE, and start it when done. */
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0);
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA( CSR2 ) = 0;
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA( CSR1 ) = 0;
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA( CSR0 ) = CSR0_INIT;
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* From now on, AREG is kept to point to CSR0 */
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i = 1000000;
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (--i > 0)
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (DREG & CSR0_IDON)
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (i < 0 || (DREG & CSR0_ERR)) {
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DPRINTK( 2, ( "lance_open(): opening %s failed, i=%d, csr0=%04x\n",
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  dev->name, i, DREG ));
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DREG = CSR0_STOP;
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return( -EIO );
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DREG = CSR0_IDON;
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DREG = CSR0_STRT;
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DREG = CSR0_INEA;
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_start_queue (dev);
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK( 2, ( "%s: LANCE is open, csr0 %04x\n", dev->name, DREG ));
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return( 0 );
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Initialize the LANCE Rx and Tx rings. */
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lance_init_ring( struct net_device *dev )
687454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen{
688454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen	struct lance_private *lp = netdev_priv(dev);
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned offset;
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->tx_full = 0;
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->cur_rx = lp->cur_tx = 0;
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->dirty_tx = 0;
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	offset = offsetof( struct lance_memory, packet_area );
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* If the packet buffer at offset 'o' would conflict with the reserved area
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of RieblCards, advance it */
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	CHECK_OFFSET(o)														 \
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {																	 \
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (lp->cardtype == OLD_RIEBL || lp->cardtype == NEW_RIEBL) {		 \
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (((o) < RIEBL_RSVD_START) ? (o)+PKT_BUF_SZ > RIEBL_RSVD_START \
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds										 : (o) < RIEBL_RSVD_END)			 \
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				(o) = RIEBL_RSVD_END;										 \
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}																	 \
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while(0)
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for( i = 0; i < TX_RING_SIZE; i++ ) {
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CHECK_OFFSET(offset);
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->tx_head[i].base = offset;
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->tx_head[i].flag = TMD1_OWN_HOST;
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 		MEM->tx_head[i].base_hi = 0;
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->tx_head[i].length = 0;
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->tx_head[i].misc = 0;
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		offset += PKT_BUF_SZ;
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for( i = 0; i < RX_RING_SIZE; i++ ) {
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CHECK_OFFSET(offset);
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->rx_head[i].base = offset;
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->rx_head[i].flag = TMD1_OWN_CHIP;
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->rx_head[i].base_hi = 0;
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->rx_head[i].buf_length = -PKT_BUF_SZ;
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->rx_head[i].msg_length = 0;
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		offset += PKT_BUF_SZ;
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lance_tx_timeout (struct net_device *dev)
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
736454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen	struct lance_private *lp = netdev_priv(dev);
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_ioreg	 *IO = lp->iobase;
7386aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AREG = CSR0;
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK( 1, ( "%s: transmit timed out, status %04x, resetting.\n",
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  dev->name, DREG ));
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DREG = CSR0_STOP;
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Always set BSWP after a STOP as STOP puts it back into
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * little endian mode.
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0);
74809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik	dev->stats.tx_errors++;
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef final_version
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{	int i;
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DPRINTK( 2, ( "Ring data: dirty_tx %d cur_tx %d%s cur_rx %d\n",
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						  lp->dirty_tx, lp->cur_tx,
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						  lp->tx_full ? " (full)" : "",
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						  lp->cur_rx ));
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for( i = 0 ; i < RX_RING_SIZE; i++ )
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				DPRINTK( 2, ( "rx #%d: base=%04x blen=%04x mlen=%04x\n",
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							  i, MEM->rx_head[i].base,
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							  -MEM->rx_head[i].buf_length,
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							  MEM->rx_head[i].msg_length ));
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for( i = 0 ; i < TX_RING_SIZE; i++ )
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				DPRINTK( 2, ( "tx #%d: base=%04x len=%04x misc=%04x\n",
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							  i, MEM->tx_head[i].base,
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							  -MEM->tx_head[i].length,
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							  MEM->tx_head[i].misc ));
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7666aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik#endif
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* XXX MSch: maybe purge/reinit ring here */
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* lance_restart, essentially */
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lance_init_ring(dev);
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA( CSR0 ) = CSR0_INEA | CSR0_INIT | CSR0_STRT;
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->trans_start = jiffies;
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_wake_queue (dev);
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
778454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen{
779454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen	struct lance_private *lp = netdev_priv(dev);
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_ioreg	 *IO = lp->iobase;
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int entry, len;
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_tx_head *head;
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n",
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  dev->name, DREG ));
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* The old LANCE chips doesn't automatically pad buffers to min. size. */
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = skb->len;
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (len < ETH_ZLEN)
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = ETH_ZLEN;
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* PAM-Card has a bug: Can only send packets with even number of bytes! */
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (lp->cardtype == PAM_CARD && (len & 1))
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		++len;
7966aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (len > skb->len) {
7985b057c6b1a25d57edf2b4d1e956e50936480a9ffHerbert Xu		if (skb_padto(skb, len))
7996ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy			return NETDEV_TX_OK;
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8016aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_stop_queue (dev);
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Fill in a Tx ring entry */
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lance_debug >= 3) {
806e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg		printk( "%s: TX pkt type 0x%04x from %pM to %pM"
8070795af5729b18218767fab27c44b1384f72dc9adJoe Perches				" data at 0x%08x len %d\n",
8080795af5729b18218767fab27c44b1384f72dc9adJoe Perches				dev->name, ((u_short *)skb->data)[6],
809e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg				&skb->data[6], skb->data,
8100795af5729b18218767fab27c44b1384f72dc9adJoe Perches				(int)skb->data, (int)skb->len );
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We're not prepared for the int until the last flags are set/reset. And
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the int may happen already after setting the OWN_CHIP... */
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&lp->devlock, flags);
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Mask to ring buffer boundary. */
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	entry = lp->cur_tx & TX_RING_MOD_MASK;
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head  = &(MEM->tx_head[entry]);
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Caution: the write order is important here, set the "ownership" bits
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * last.
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head->length = -len;
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head->misc = 0;
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->memcpy_f( PKTBUF_ADDR(head), (void *)skb->data, skb->len );
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP;
83009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik	dev->stats.tx_bytes += skb->len;
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_kfree_skb( skb );
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->cur_tx++;
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while( lp->cur_tx >= TX_RING_SIZE && lp->dirty_tx >= TX_RING_SIZE ) {
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->cur_tx -= TX_RING_SIZE;
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->dirty_tx -= TX_RING_SIZE;
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Trigger an immediate send poll. */
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DREG = CSR0_INEA | CSR0_TDMD;
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->trans_start = jiffies;
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((MEM->tx_head[(entry+1) & TX_RING_MOD_MASK].flag & TMD1_OWN) ==
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		TMD1_OWN_HOST)
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_start_queue (dev);
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->tx_full = 1;
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&lp->devlock, flags);
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8496ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy	return NETDEV_TX_OK;
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The LANCE interrupt handler. */
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8547d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t lance_interrupt( int irq, void *dev_id )
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = dev_id;
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_private *lp;
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_ioreg	 *IO;
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int csr0, boguscnt = 10;
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int handled = 0;
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev == NULL) {
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DPRINTK( 1, ( "lance_interrupt(): interrupt for unknown device.\n" ));
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return IRQ_NONE;
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
867454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen	lp = netdev_priv(dev);
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IO = lp->iobase;
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock (&lp->devlock);
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AREG = CSR0;
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while( ((csr0 = DREG) & (CSR0_ERR | CSR0_TINT | CSR0_RINT)) &&
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   --boguscnt >= 0) {
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		handled = 1;
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Acknowledge all of the current interrupt sources ASAP. */
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DREG = csr0 & ~(CSR0_INIT | CSR0_STRT | CSR0_STOP |
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds									CSR0_TDMD | CSR0_INEA);
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DPRINTK( 2, ( "%s: interrupt  csr0=%04x new csr=%04x.\n",
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  dev->name, csr0, DREG ));
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (csr0 & CSR0_RINT)			/* Rx interrupt */
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lance_rx( dev );
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (csr0 & CSR0_TINT) {			/* Tx-done interrupt */
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int dirty_tx = lp->dirty_tx;
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			while( dirty_tx < lp->cur_tx) {
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				int entry = dirty_tx & TX_RING_MOD_MASK;
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				int status = MEM->tx_head[entry].flag;
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (status & TMD1_OWN_CHIP)
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;			/* It still hasn't been Txed */
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				MEM->tx_head[entry].flag = 0;
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (status & TMD1_ERR) {
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/* There was an major error, log it. */
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					int err_status = MEM->tx_head[entry].misc;
90109f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik					dev->stats.tx_errors++;
90209f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik					if (err_status & TMD3_RTRY) dev->stats.tx_aborted_errors++;
90309f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik					if (err_status & TMD3_LCAR) dev->stats.tx_carrier_errors++;
90409f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik					if (err_status & TMD3_LCOL) dev->stats.tx_window_errors++;
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (err_status & TMD3_UFLO) {
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						/* Ackk!  On FIFO errors the Tx unit is turned off! */
90709f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik						dev->stats.tx_fifo_errors++;
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						/* Remove this verbosity later! */
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						DPRINTK( 1, ( "%s: Tx FIFO error! Status %04x\n",
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds									  dev->name, csr0 ));
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						/* Restart the chip. */
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						DREG = CSR0_STRT;
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else {
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (status & (TMD1_MORE | TMD1_ONE | TMD1_DEF))
91609f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik						dev->stats.collisions++;
91709f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik					dev->stats.tx_packets++;
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* XXX MSch: free skb?? */
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dirty_tx++;
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef final_version
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				DPRINTK( 0, ( "out-of-sync dirty pointer,"
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							  " %d vs. %d, full=%ld.\n",
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							  dirty_tx, lp->cur_tx, lp->tx_full ));
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dirty_tx += TX_RING_SIZE;
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (lp->tx_full && (netif_queue_stopped(dev))
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				&& dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* The ring is no longer full, clear tbusy. */
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lp->tx_full = 0;
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				netif_wake_queue (dev);
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lp->dirty_tx = dirty_tx;
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Log misc errors. */
94409f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik		if (csr0 & CSR0_BABL) dev->stats.tx_errors++; /* Tx babble. */
94509f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik		if (csr0 & CSR0_MISS) dev->stats.rx_errors++; /* Missed a Rx frame. */
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (csr0 & CSR0_MERR) {
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DPRINTK( 1, ( "%s: Bus master arbitration failure (?!?), "
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						  "status %04x.\n", dev->name, csr0 ));
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Restart the chip. */
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DREG = CSR0_STRT;
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Clear any other interrupt, and set interrupt enable. */
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DREG = CSR0_BABL | CSR0_CERR | CSR0_MISS | CSR0_MERR |
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   CSR0_IDON | CSR0_INEA;
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK( 2, ( "%s: exiting interrupt, csr0=%#04x.\n",
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  dev->name, DREG ));
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock (&lp->devlock);
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_RETVAL(handled);
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_rx( struct net_device *dev )
967454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen{
968454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen	struct lance_private *lp = netdev_priv(dev);
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int entry = lp->cur_rx & RX_RING_MOD_MASK;
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK( 2, ( "%s: rx int, flag=%04x\n", dev->name,
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  MEM->rx_head[entry].flag ));
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* If we own the next entry, it's a new packet. Send it up. */
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while( (MEM->rx_head[entry].flag & RMD1_OWN) == RMD1_OWN_HOST ) {
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct lance_rx_head *head = &(MEM->rx_head[entry]);
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int status = head->flag;
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status != (RMD1_ENP|RMD1_STP)) {		/* There was an error. */
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* There is a tricky error noted by John Murphy,
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   <murf@perftech.com> to Russ Nelson: Even with full-sized
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   buffers it's possible for a jabber packet to use two
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   buffers, with only the last correctly noting the error. */
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (status & RMD1_ENP)	/* Only count a general error at the */
98609f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik				dev->stats.rx_errors++; /* end of a packet.*/
98709f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik			if (status & RMD1_FRAM) dev->stats.rx_frame_errors++;
98809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik			if (status & RMD1_OFLO) dev->stats.rx_over_errors++;
98909f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik			if (status & RMD1_CRC) dev->stats.rx_crc_errors++;
99009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik			if (status & RMD1_BUFF) dev->stats.rx_fifo_errors++;
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			head->flag &= (RMD1_ENP|RMD1_STP);
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Malloc up new buffer, compatible with net-3. */
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			short pkt_len = head->msg_length & 0xfff;
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct sk_buff *skb;
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (pkt_len < 60) {
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk( "%s: Runt packet!\n", dev->name );
99909f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik				dev->stats.rx_errors++;
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else {
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb = dev_alloc_skb( pkt_len+2 );
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (skb == NULL) {
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					DPRINTK( 1, ( "%s: Memory squeeze, deferring packet.\n",
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								  dev->name ));
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					for( i = 0; i < RX_RING_SIZE; i++ )
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (MEM->rx_head[(entry+i) & RX_RING_MOD_MASK].flag &
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							RMD1_OWN_CHIP)
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							break;
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (i > RX_RING_SIZE - 2) {
101209f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik						dev->stats.rx_dropped++;
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						head->flag |= RMD1_OWN_CHIP;
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						lp->cur_rx++;
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (lance_debug >= 3) {
10200795af5729b18218767fab27c44b1384f72dc9adJoe Perches					u_char *data = PKTBUF_ADDR(head);
10210795af5729b18218767fab27c44b1384f72dc9adJoe Perches
1022e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg					printk(KERN_DEBUG "%s: RX pkt type 0x%04x from %pM to %pM "
10230795af5729b18218767fab27c44b1384f72dc9adJoe Perches						   "data %02x %02x %02x %02x %02x %02x %02x %02x "
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						   "len %d\n",
10250795af5729b18218767fab27c44b1384f72dc9adJoe Perches						   dev->name, ((u_short *)data)[6],
1026e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg						   &data[6], data,
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						   data[15], data[16], data[17], data[18],
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						   data[19], data[20], data[21], data[22],
10290795af5729b18218767fab27c44b1384f72dc9adJoe Perches						   pkt_len);
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb_reserve( skb, 2 );	/* 16 byte align */
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb_put( skb, pkt_len );	/* Make room */
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lp->memcpy_f( skb->data, PKTBUF_ADDR(head), pkt_len );
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb->protocol = eth_type_trans( skb, dev );
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				netif_rx( skb );
103709f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik				dev->stats.rx_packets++;
103809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik				dev->stats.rx_bytes += pkt_len;
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		head->flag |= RMD1_OWN_CHIP;
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		entry = (++lp->cur_rx) & RX_RING_MOD_MASK;
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->cur_rx &= RX_RING_MOD_MASK;
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* From lance.c (Donald Becker): */
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We should check that at least two ring entries are free.	 If not,
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   we should free one and mark stats->rx_dropped++. */
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_close( struct net_device *dev )
1056454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen{
1057454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen	struct lance_private *lp = netdev_priv(dev);
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_ioreg	 *IO = lp->iobase;
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_stop_queue (dev);
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AREG = CSR0;
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK( 2, ( "%s: Shutting down ethercard, status was %2.2x.\n",
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  dev->name, DREG ));
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We stop the LANCE here -- it occasionally polls
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   memory if we don't. */
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DREG = CSR0_STOP;
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Set or clear the multicast filter for this adaptor.
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   num_addrs == -1		Promiscuous mode, receive all packets
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   num_addrs == 0		Normal mode, clear multicast list
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   num_addrs > 0		Multicast mode, receive normal and MC packets, and do
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						best-effort filtering.
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void set_multicast_list( struct net_device *dev )
1083454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen{
1084454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen	struct lance_private *lp = netdev_priv(dev);
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_ioreg	 *IO = lp->iobase;
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (netif_running(dev))
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Only possible if board is already started */
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We take the simple way out and always enable promiscuous mode. */
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DREG = CSR0_STOP; /* Temporarily stop the lance. */
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->flags & IFF_PROMISC) {
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Log any net taps. */
1096d5b20697ca37d80cc4ec2ba3c5ddf1339dc1d49aAndy Gospodarek		DPRINTK( 2, ( "%s: Promiscuous mode enabled.\n", dev->name ));
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		REGA( CSR15 ) = 0x8000; /* Set promiscuous mode */
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		short multicast_table[4];
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int num_addrs = dev->mc_count;
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int i;
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* We don't use the multicast table, but rely on upper-layer
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * filtering. */
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memset( multicast_table, (num_addrs == 0) ? 0 : -1,
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sizeof(multicast_table) );
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for( i = 0; i < 4; i++ )
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			REGA( CSR8+i ) = multicast_table[i];
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		REGA( CSR15 ) = 0; /* Unset promiscuous mode */
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Always set BSWP after a STOP as STOP puts it back into
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * little endian mode.
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0);
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Resume normal operation and reset AREG to CSR0 */
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA( CSR0 ) = CSR0_IDON | CSR0_INEA | CSR0_STRT;
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This is needed for old RieblCards and possible for new RieblCards */
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_set_mac_address( struct net_device *dev, void *addr )
1125454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen{
1126454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen	struct lance_private *lp = netdev_priv(dev);
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sockaddr *saddr = addr;
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lp->cardtype != OLD_RIEBL && lp->cardtype != NEW_RIEBL)
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return( -EOPNOTSUPP );
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (netif_running(dev)) {
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Only possible while card isn't started */
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DPRINTK( 1, ( "%s: hwaddr can be set only while card isn't open.\n",
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  dev->name ));
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return( -EIO );
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy( dev->dev_addr, saddr->sa_data, dev->addr_len );
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for( i = 0; i < 6; i++ )
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->init.hwaddr[i] = dev->dev_addr[i^1]; /* <- 16 bit swap! */
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->memcpy_f( RIEBL_HWADDR_ADDR, dev->dev_addr, 6 );
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set also the magic for future sessions */
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*RIEBL_MAGIC_ADDR = RIEBL_MAGIC;
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return( 0 );
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11506aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef MODULE
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device *atarilance_dev;
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
115453e7c46b0680ccc3ac67a2b8cd7f050569836e44Jon Schindlerstatic int __init atarilance_module_init(void)
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atarilance_dev = atarilance_probe(-1);
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (IS_ERR(atarilance_dev))
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return PTR_ERR(atarilance_dev);
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
116253e7c46b0680ccc3ac67a2b8cd7f050569836e44Jon Schindlerstatic void __exit atarilance_module_exit(void)
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unregister_netdev(atarilance_dev);
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_irq(atarilance_dev->irq, atarilance_dev);
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_netdev(atarilance_dev);
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
116853e7c46b0680ccc3ac67a2b8cd7f050569836e44Jon Schindlermodule_init(atarilance_module_init);
116953e7c46b0680ccc3ac67a2b8cd7f050569836e44Jon Schindlermodule_exit(atarilance_module_exit);
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* MODULE */
11716aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Local variables:
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  c-indent-level: 4
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  tab-width: 4
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * End:
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1179