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/interrupt.h>
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h>
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/setup.h>
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h>
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/atarihw.h>
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/atariints.h>
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Debug level:
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  0 = silent, print only serious errors
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  1 = normal, print error messages
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  2 = debug, print debug infos
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  3 = debug, print even more debug infos (packet data)
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	LANCE_DEBUG	1
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef LANCE_DEBUG
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_debug = LANCE_DEBUG;
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_debug = 1;
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
808d3b33f67fdc0fb364a1ef6d8fbbea7c2e4e6c98Rusty Russellmodule_param(lance_debug, int, 0);
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(lance_debug, "atarilance debug level (0-3)");
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Print debug messages on probing? */
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef LANCE_DEBUG_PROBE
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DPRINTK(n,a)							\
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {										\
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (lance_debug >= n)					\
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk a;							\
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while( 0 )
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef LANCE_DEBUG_PROBE
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds# define PROBE_PRINT(a)	printk a
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds# define PROBE_PRINT(a)
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* These define the number of Rx and Tx buffers as log2. (Only powers
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of two are valid)
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Much more rx buffers (32) are reserved than tx buffers (8), since receiving
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is more time critical then sending and packets may have to remain in the
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * board's memory when main memory is low.
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_LOG_RING_SIZE			3
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_LOG_RING_SIZE			5
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* These are the derived values */
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_RING_SIZE			(1 << TX_LOG_RING_SIZE)
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_RING_LEN_BITS		(TX_LOG_RING_SIZE << 5)
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	TX_RING_MOD_MASK		(TX_RING_SIZE - 1)
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_RING_SIZE			(1 << RX_LOG_RING_SIZE)
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_RING_LEN_BITS		(RX_LOG_RING_SIZE << 5)
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	RX_RING_MOD_MASK		(RX_RING_SIZE - 1)
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
119c63fdf46ad0a7f8fe3c0252a0e763515617e0ea7Eric Dumazet#define TX_TIMEOUT	(HZ/5)
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The LANCE Rx and Tx ring descriptors. */
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_rx_head {
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short			base;		/* Low word of base addr */
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile unsigned char	flag;
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char			base_hi;	/* High word of base addr (unused) */
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	short					buf_length;	/* This length is 2s complement! */
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile short			msg_length;	/* This length is "normal". */
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_tx_head {
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short			base;		/* Low word of base addr */
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile unsigned char	flag;
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char			base_hi;	/* High word of base addr (unused) */
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	short					length;		/* Length is 2s complement! */
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile short			misc;
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct ringdesc {
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short	adr_lo;		/* Low 16 bits of address */
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char	len;		/* Length bits */
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char	adr_hi;		/* High 8 bits of address (unused) */
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The LANCE initialization block, described in databook. */
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_init_block {
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short	mode;		/* Pre-set mode */
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char	hwaddr[6];	/* Physical ethernet address */
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned		filter[2];	/* Multicast filter (unused). */
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Receive and transmit ring base, along with length bits. */
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ringdesc	rx_ring;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ringdesc	tx_ring;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The whole layout of the Lance shared memory */
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_memory {
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_init_block	init;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_tx_head	tx_head[TX_RING_SIZE];
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_rx_head	rx_head[RX_RING_SIZE];
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char					packet_area[0];	/* packet data follow after the
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds											 * init block and the ring
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds											 * descriptors and are located
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds											 * at runtime */
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* RieblCard specifics:
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The original TOS driver for these cards reserves the area from offset
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0xee70 to 0xeebb for storing configuration data. Of interest to us is the
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ethernet address there, and the magic for verifying the data's validity.
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The reserved area isn't touch by packet buffers. Furthermore, offset 0xfffe
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is reserved for the interrupt vector number.
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	RIEBL_RSVD_START	0xee70
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	RIEBL_RSVD_END		0xeec0
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RIEBL_MAGIC			0x09051990
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RIEBL_MAGIC_ADDR	((unsigned long *)(((char *)MEM) + 0xee8a))
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RIEBL_HWADDR_ADDR	((unsigned char *)(((char *)MEM) + 0xee8e))
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RIEBL_IVEC_ADDR		((unsigned short *)(((char *)MEM) + 0xfffe))
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This is a default address for the old RieblCards without a battery
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that have no ethernet address at boot time. 00:00:36:04 is the
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * prefix for Riebl cards, the 00:00 at the end is arbitrary.
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned char OldRieblDefHwaddr[6] = {
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x00, 0x00, 0x36, 0x04, 0x00, 0x00
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* I/O registers of the Lance chip */
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_ioreg {
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* base+0x0 */	volatile unsigned short	data;
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* base+0x2 */	volatile unsigned short	addr;
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unsigned char			_dummy1[3];
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* base+0x7 */	volatile unsigned char	ivec;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unsigned char			_dummy2[5];
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* base+0xd */	volatile unsigned char	eeprom;
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unsigned char			_dummy3;
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* base+0xf */	volatile unsigned char	mem;
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Types of boards this driver supports */
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum lance_type {
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	OLD_RIEBL,		/* old Riebl card without battery */
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	NEW_RIEBL,		/* new Riebl card with battery */
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PAM_CARD		/* PAM card with EEPROM */
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *lance_names[] = {
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"Riebl-Card (without battery)",
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"Riebl-Card (with battery)",
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"PAM intern card"
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The driver's private device structure */
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_private {
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enum lance_type		cardtype;
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_ioreg	*iobase;
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_memory	*mem;
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int		 	cur_rx, cur_tx;	/* The next free ring entry */
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			dirty_tx;		/* Ring entries to be freed. */
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* copy function */
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void			*(*memcpy_f)( void *, const void *, size_t );
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This must be long for set_bit() */
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long			tx_full;
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t		devlock;
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* I/O register access macros */
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	MEM		lp->mem
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	DREG	IO->data
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	AREG	IO->addr
236e345d5ef6d476cc236f64d90d9528143a70745c8Al Viro#define	REGA(a)	(*( AREG = (a), &DREG ))
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Definitions for packet buffer access: */
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PKT_BUF_SZ		1544
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Get the address of a packet buffer corresponding to a given buffer head */
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	PKTBUF_ADDR(head)	(((unsigned char *)(MEM)) + (head)->base)
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Possible memory/IO addresses for probing */
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2453cacd2a1ce5464b9874508927d561c0dfce74637Adrian Bunkstatic struct lance_addr {
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	memaddr;
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	ioaddr;
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int				slow_flag;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} lance_addr_list[] = {
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0xfe010000, 0xfe00fff0, 0 },	/* RieblCard VME in TT */
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0xffc10000, 0xffc0fff0, 0 },	/* RieblCard VME in MegaSTE
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds									   (highest byte stripped) */
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0xffe00000, 0xffff7000, 1 },	/* RieblCard in ST
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds									   (highest byte stripped) */
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0xffd00000, 0xffff7000, 1 },	/* RieblCard in ST with hw modif. to
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds									   avoid conflict with ROM
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds									   (highest byte stripped) */
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0xffcf0000, 0xffcffff0, 0 },	/* PAMCard VME in TT and MSTE
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds									   (highest byte stripped) */
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0xfecf0000, 0xfecffff0, 0 },	/* Rhotron's PAMCard VME in TT and MSTE
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds									   (highest byte stripped) */
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
264ff8ac60948ba819b89e9c87083e8050fc2f89999Denis Cheng#define	N_LANCE_ADDR	ARRAY_SIZE(lance_addr_list)
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Definitions for the Lance */
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* tx_head flags */
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_ENP		0x01	/* end of packet */
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_STP		0x02	/* start of packet */
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_DEF		0x04	/* deferred */
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_ONE		0x08	/* one retry needed */
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_MORE		0x10	/* more than one retry needed */
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_ERR		0x40	/* error summary */
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_OWN 		0x80	/* ownership (set: chip owns) */
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_OWN_CHIP	TMD1_OWN
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_OWN_HOST	0
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* tx_head misc field */
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_TDR		0x03FF	/* Time Domain Reflectometry counter */
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_RTRY		0x0400	/* failed after 16 retries */
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_LCAR		0x0800	/* carrier lost */
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_LCOL		0x1000	/* late collision */
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_UFLO		0x4000	/* underflow (late memory) */
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_BUFF		0x8000	/* buffering error (no ENP) */
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* rx_head flags */
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_ENP		0x01	/* end of packet */
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_STP		0x02	/* start of packet */
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_BUFF		0x04	/* buffer error */
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_CRC		0x08	/* CRC error */
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_OFLO		0x10	/* overflow */
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_FRAM		0x20	/* framing error */
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_ERR		0x40	/* error summary */
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_OWN 		0x80	/* ownership (set: ship owns) */
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_OWN_CHIP	RMD1_OWN
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_OWN_HOST	0
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* register names */
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0	0		/* mode/status */
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR1	1		/* init block addr (low) */
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR2	2		/* init block addr (high) */
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR3	3		/* misc */
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR8	8	  	/* address filter */
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR15	15		/* promiscuous mode */
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* CSR0 */
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* (R=readable, W=writeable, S=set on write, C=clear on write) */
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_INIT	0x0001		/* initialize (RS) */
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_STRT	0x0002		/* start (RS) */
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_STOP	0x0004		/* stop (RS) */
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_TDMD	0x0008		/* transmit demand (RS) */
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_TXON	0x0010		/* transmitter on (R) */
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_RXON	0x0020		/* receiver on (R) */
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_INEA	0x0040		/* interrupt enable (RW) */
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_INTR	0x0080		/* interrupt active (R) */
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_IDON	0x0100		/* initialization done (RC) */
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_TINT	0x0200		/* transmitter interrupt (RC) */
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_RINT	0x0400		/* receiver interrupt (RC) */
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_MERR	0x0800		/* memory error (RC) */
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_MISS	0x1000		/* missed frame (RC) */
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_CERR	0x2000		/* carrier error (no heartbeat :-) (RC) */
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_BABL	0x4000		/* babble: tx-ed too many bits (RC) */
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_ERR	0x8000		/* error (RC) */
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* CSR3 */
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR3_BCON	0x0001		/* byte control */
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR3_ACON	0x0002		/* ALE control */
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR3_BSWP	0x0004		/* byte swap (1=big endian) */
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/***************************** Prototypes *****************************/
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long lance_probe1( struct net_device *dev, struct lance_addr
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                                   *init_rec );
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_open( struct net_device *dev );
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lance_init_ring( struct net_device *dev );
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_start_xmit( struct sk_buff *skb, struct net_device *dev );
3437d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t lance_interrupt( int irq, void *dev_id );
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_rx( struct net_device *dev );
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_close( struct net_device *dev );
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void set_multicast_list( struct net_device *dev );
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_set_mac_address( struct net_device *dev, void *addr );
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lance_tx_timeout (struct net_device *dev);
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************* End of Prototypes **************************/
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3546aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void *slow_memcpy( void *dst, const void *src, size_t len )
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{	char *cto = dst;
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const char *cfrom = src;
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while( len-- ) {
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*cto++ = *cfrom++;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MFPDELAY();
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
365807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet	return dst;
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct net_device * __init atarilance_probe(int unit)
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static int found;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = -ENODEV;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!MACH_IS_ATARI || found)
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Assume there's only one board possible... That seems true, since
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * the Riebl/PAM board's address cannot be changed. */
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ERR_PTR(-ENODEV);
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev = alloc_etherdev(sizeof(struct lance_private));
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev)
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ERR_PTR(-ENOMEM);
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unit >= 0) {
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sprintf(dev->name, "eth%d", unit);
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netdev_boot_setup_check(dev);
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for( i = 0; i < N_LANCE_ADDR; ++i ) {
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (lance_probe1( dev, &lance_addr_list[i] )) {
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			found = 1;
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = register_netdev(dev);
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!err)
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return dev;
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			free_irq(dev->irq, dev);
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_netdev(dev);
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ERR_PTR(err);
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Derived from hwreg_present() in atari/config.c: */
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
406f37c768c39e3aeb8a508e1a45e461a506771445eAdrian Bunkstatic noinline int __init addr_accessible(volatile void *regp, int wordflag,
407f37c768c39e3aeb8a508e1a45e461a506771445eAdrian Bunk					   int writeflag)
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int		ret;
410d1abc9a9aca06ceb795eb5405264eaafe016ec5cGeert Uytterhoeven	unsigned long	flags;
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long	*vbr, save_berr;
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	local_irq_save(flags);
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__asm__ __volatile__ ( "movec	%/vbr,%0" : "=r" (vbr) : );
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	save_berr = vbr[2];
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__asm__ __volatile__
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(	"movel	%/sp,%/d1\n\t"
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"movel	#Lberr,%2@\n\t"
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"moveq	#0,%0\n\t"
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"tstl   %3\n\t"
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"bne	1f\n\t"
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"moveb	%1@,%/d0\n\t"
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"nop	\n\t"
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"bra	2f\n"
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"1:		 movew	%1@,%/d0\n\t"
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"nop	\n"
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"2:		 tstl   %4\n\t"
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"beq	2f\n\t"
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"tstl	%3\n\t"
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"bne	1f\n\t"
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"clrb	%1@\n\t"
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"nop	\n\t"
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"moveb	%/d0,%1@\n\t"
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"nop	\n\t"
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"bra	2f\n"
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"1:		 clrw	%1@\n\t"
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"nop	\n\t"
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"movew	%/d0,%1@\n\t"
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"nop	\n"
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"2:		 moveq	#1,%0\n"
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"Lberr:	 movel	%/d1,%/sp"
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		: "=&d" (ret)
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		: "a" (regp), "a" (&vbr[2]), "rm" (wordflag), "rm" (writeflag)
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		: "d0", "d1", "memory"
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	);
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vbr[2] = save_berr;
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	local_irq_restore(flags);
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
452807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet	return ret;
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4558e7678fe0992a6107041b839b08ac4af55d41592Alexander Beregalovstatic const struct net_device_ops lance_netdev_ops = {
4568e7678fe0992a6107041b839b08ac4af55d41592Alexander Beregalov	.ndo_open		= lance_open,
4578e7678fe0992a6107041b839b08ac4af55d41592Alexander Beregalov	.ndo_stop		= lance_close,
4588e7678fe0992a6107041b839b08ac4af55d41592Alexander Beregalov	.ndo_start_xmit		= lance_start_xmit,
459afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko	.ndo_set_rx_mode	= set_multicast_list,
4608e7678fe0992a6107041b839b08ac4af55d41592Alexander Beregalov	.ndo_set_mac_address	= lance_set_mac_address,
4618e7678fe0992a6107041b839b08ac4af55d41592Alexander Beregalov	.ndo_tx_timeout		= lance_tx_timeout,
4628e7678fe0992a6107041b839b08ac4af55d41592Alexander Beregalov	.ndo_validate_addr	= eth_validate_addr,
4638e7678fe0992a6107041b839b08ac4af55d41592Alexander Beregalov	.ndo_change_mtu		= eth_change_mtu,
4648e7678fe0992a6107041b839b08ac4af55d41592Alexander Beregalov};
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long __init lance_probe1( struct net_device *dev,
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					   struct lance_addr *init_rec )
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile unsigned short *memaddr =
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(volatile unsigned short *)init_rec->memaddr;
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile unsigned short *ioaddr =
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(volatile unsigned short *)init_rec->ioaddr;
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_private	*lp;
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_ioreg		*IO;
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int 					i;
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static int 				did_version;
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short			save1, save2;
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PROBE_PRINT(( "Probing for Lance card at mem %#lx io %#lx\n",
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  (long)memaddr, (long)ioaddr ));
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Test whether memory readable and writable */
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PROBE_PRINT(( "lance_probe1: testing memory to be accessible\n" ));
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!addr_accessible( memaddr, 1, 1 )) goto probe_fail;
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Written values should come back... */
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PROBE_PRINT(( "lance_probe1: testing memory to be writable (1)\n" ));
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	save1 = *memaddr;
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*memaddr = 0x0001;
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (*memaddr != 0x0001) goto probe_fail;
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PROBE_PRINT(( "lance_probe1: testing memory to be writable (2)\n" ));
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*memaddr = 0x0000;
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (*memaddr != 0x0000) goto probe_fail;
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*memaddr = save1;
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* First port should be readable and writable */
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PROBE_PRINT(( "lance_probe1: testing ioport to be accessible\n" ));
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!addr_accessible( ioaddr, 1, 1 )) goto probe_fail;
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* and written values should be readable */
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PROBE_PRINT(( "lance_probe1: testing ioport to be writeable\n" ));
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	save2 = ioaddr[1];
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ioaddr[1] = 0x0001;
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ioaddr[1] != 0x0001) goto probe_fail;
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* The CSR0_INIT bit should not be readable */
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PROBE_PRINT(( "lance_probe1: testing CSR0 register function (1)\n" ));
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	save1 = ioaddr[0];
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ioaddr[1] = CSR0;
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ioaddr[0] = CSR0_INIT | CSR0_STOP;
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ioaddr[0] != CSR0_STOP) {
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ioaddr[0] = save1;
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ioaddr[1] = save2;
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto probe_fail;
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PROBE_PRINT(( "lance_probe1: testing CSR0 register function (2)\n" ));
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ioaddr[0] = CSR0_STOP;
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ioaddr[0] != CSR0_STOP) {
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ioaddr[0] = save1;
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ioaddr[1] = save2;
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto probe_fail;
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Now ok... */
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PROBE_PRINT(( "lance_probe1: Lance card detected\n" ));
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto probe_ok;
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  probe_fail:
529807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet	return 0;
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  probe_ok:
532454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen	lp = netdev_priv(dev);
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM = (struct lance_memory *)memaddr;
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IO = lp->iobase = (struct lance_ioreg *)ioaddr;
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->base_addr = (unsigned long)ioaddr; /* informational only */
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->memcpy_f = init_rec->slow_flag ? slow_memcpy : memcpy;
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA( CSR0 ) = CSR0_STOP;
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Now test for type: If the eeprom I/O port is readable, it is a
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * PAM card */
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (addr_accessible( &(IO->eeprom), 0, 0 )) {
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Switch back to Ram */
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i = IO->mem;
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->cardtype = PAM_CARD;
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (*RIEBL_MAGIC_ADDR == RIEBL_MAGIC) {
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->cardtype = NEW_RIEBL;
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->cardtype = OLD_RIEBL;
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lp->cardtype == PAM_CARD ||
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memaddr == (unsigned short *)0xffe00000) {
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* PAMs card and Riebl on ST use level 5 autovector */
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (request_irq(IRQ_AUTO_5, lance_interrupt, IRQ_TYPE_PRIO,
55779abeed6ee93231d494c191a9251c0845bd71fddGeert Uytterhoeven		            "PAM,Riebl-ST Ethernet", dev)) {
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk( "Lance: request for irq %d failed\n", IRQ_AUTO_5 );
559807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet			return 0;
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->irq = (unsigned short)IRQ_AUTO_5;
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else {
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* For VME-RieblCards, request a free VME int;
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * (This must be unsigned long, since dev->irq is short and the
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * IRQ_MACHSPEC bit would be cut off...)
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned long irq = atari_register_vme_int();
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!irq) {
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk( "Lance: request for VME interrupt failed\n" );
571807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet			return 0;
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (request_irq(irq, lance_interrupt, IRQ_TYPE_PRIO,
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		            "Riebl-VME Ethernet", dev)) {
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk( "Lance: request for irq %ld failed\n", irq );
576807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet			return 0;
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->irq = irq;
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("%s: %s at io %#lx, mem %#lx, irq %d%s, hwaddr ",
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   dev->name, lance_names[lp->cardtype],
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   (unsigned long)ioaddr,
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   (unsigned long)memaddr,
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   dev->irq,
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   init_rec->slow_flag ? " (slow memcpy)" : "" );
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Get the ethernet address */
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch( lp->cardtype ) {
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  case OLD_RIEBL:
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* No ethernet address! (Set some default address) */
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy( dev->dev_addr, OldRieblDefHwaddr, 6 );
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  case NEW_RIEBL:
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->memcpy_f( dev->dev_addr, RIEBL_HWADDR_ADDR, 6 );
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  case PAM_CARD:
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i = IO->eeprom;
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for( i = 0; i < 6; ++i )
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->dev_addr[i] =
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				((((unsigned short *)MEM)[i*2] & 0x0f) << 4) |
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				((((unsigned short *)MEM)[i*2+1] & 0x0f));
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i = IO->mem;
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
606e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg	printk("%pM\n", dev->dev_addr);
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lp->cardtype == OLD_RIEBL) {
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk( "%s: Warning: This is a default ethernet address!\n",
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dev->name );
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk( "      Use \"ifconfig hw ether ...\" to set the address.\n" );
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_init(&lp->devlock);
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.mode = 0x0000;		/* Disable Rx and Tx. */
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for( i = 0; i < 6; i++ )
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->init.hwaddr[i] = dev->dev_addr[i^1]; /* <- 16 bit swap! */
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.filter[0] = 0x00000000;
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.filter[1] = 0x00000000;
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.rx_ring.adr_lo = offsetof( struct lance_memory, rx_head );
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.rx_ring.adr_hi = 0;
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.rx_ring.len    = RX_RING_LEN_BITS;
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.tx_ring.adr_lo = offsetof( struct lance_memory, tx_head );
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.tx_ring.adr_hi = 0;
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MEM->init.tx_ring.len    = TX_RING_LEN_BITS;
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lp->cardtype == PAM_CARD)
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		IO->ivec = IRQ_SOURCE_TO_VECTOR(dev->irq);
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*RIEBL_IVEC_ADDR = IRQ_SOURCE_TO_VECTOR(dev->irq);
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (did_version++ == 0)
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DPRINTK( 1, ( version ));
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6358e7678fe0992a6107041b839b08ac4af55d41592Alexander Beregalov	dev->netdev_ops = &lance_netdev_ops;
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* XXX MSch */
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->watchdog_timeo = TX_TIMEOUT;
6396aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
640807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet	return 1;
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6436aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_open( struct net_device *dev )
645454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen{
646454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen	struct lance_private *lp = netdev_priv(dev);
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_ioreg	 *IO = lp->iobase;
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK( 2, ( "%s: lance_open()\n", dev->name ));
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lance_init_ring(dev);
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Re-initialize the LANCE, and start it when done. */
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0);
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA( CSR2 ) = 0;
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA( CSR1 ) = 0;
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA( CSR0 ) = CSR0_INIT;
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* From now on, AREG is kept to point to CSR0 */
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i = 1000000;
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (--i > 0)
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (DREG & CSR0_IDON)
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
665e145b98484f5c7444151e90cc0853f14e6d396a4roel kluin	if (i <= 0 || (DREG & CSR0_ERR)) {
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DPRINTK( 2, ( "lance_open(): opening %s failed, i=%d, csr0=%04x\n",
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  dev->name, i, DREG ));
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DREG = CSR0_STOP;
669807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet		return -EIO;
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DREG = CSR0_IDON;
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DREG = CSR0_STRT;
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DREG = CSR0_INEA;
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_start_queue (dev);
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK( 2, ( "%s: LANCE is open, csr0 %04x\n", dev->name, DREG ));
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
679807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet	return 0;
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Initialize the LANCE Rx and Tx rings. */
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lance_init_ring( struct net_device *dev )
686454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen{
687454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen	struct lance_private *lp = netdev_priv(dev);
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned offset;
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->tx_full = 0;
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->cur_rx = lp->cur_tx = 0;
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->dirty_tx = 0;
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	offset = offsetof( struct lance_memory, packet_area );
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* If the packet buffer at offset 'o' would conflict with the reserved area
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of RieblCards, advance it */
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define	CHECK_OFFSET(o)														 \
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {																	 \
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (lp->cardtype == OLD_RIEBL || lp->cardtype == NEW_RIEBL) {		 \
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (((o) < RIEBL_RSVD_START) ? (o)+PKT_BUF_SZ > RIEBL_RSVD_START \
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds										 : (o) < RIEBL_RSVD_END)			 \
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				(o) = RIEBL_RSVD_END;										 \
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}																	 \
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while(0)
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for( i = 0; i < TX_RING_SIZE; i++ ) {
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CHECK_OFFSET(offset);
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->tx_head[i].base = offset;
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->tx_head[i].flag = TMD1_OWN_HOST;
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 		MEM->tx_head[i].base_hi = 0;
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->tx_head[i].length = 0;
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->tx_head[i].misc = 0;
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		offset += PKT_BUF_SZ;
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for( i = 0; i < RX_RING_SIZE; i++ ) {
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CHECK_OFFSET(offset);
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->rx_head[i].base = offset;
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->rx_head[i].flag = TMD1_OWN_CHIP;
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->rx_head[i].base_hi = 0;
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->rx_head[i].buf_length = -PKT_BUF_SZ;
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->rx_head[i].msg_length = 0;
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		offset += PKT_BUF_SZ;
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lance_tx_timeout (struct net_device *dev)
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
735454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen	struct lance_private *lp = netdev_priv(dev);
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_ioreg	 *IO = lp->iobase;
7376aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AREG = CSR0;
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK( 1, ( "%s: transmit timed out, status %04x, resetting.\n",
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  dev->name, DREG ));
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DREG = CSR0_STOP;
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Always set BSWP after a STOP as STOP puts it back into
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * little endian mode.
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0);
74709f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik	dev->stats.tx_errors++;
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef final_version
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{	int i;
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DPRINTK( 2, ( "Ring data: dirty_tx %d cur_tx %d%s cur_rx %d\n",
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						  lp->dirty_tx, lp->cur_tx,
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						  lp->tx_full ? " (full)" : "",
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						  lp->cur_rx ));
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for( i = 0 ; i < RX_RING_SIZE; i++ )
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				DPRINTK( 2, ( "rx #%d: base=%04x blen=%04x mlen=%04x\n",
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							  i, MEM->rx_head[i].base,
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							  -MEM->rx_head[i].buf_length,
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							  MEM->rx_head[i].msg_length ));
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for( i = 0 ; i < TX_RING_SIZE; i++ )
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				DPRINTK( 2, ( "tx #%d: base=%04x len=%04x misc=%04x\n",
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							  i, MEM->tx_head[i].base,
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							  -MEM->tx_head[i].length,
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							  MEM->tx_head[i].misc ));
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7656aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik#endif
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* XXX MSch: maybe purge/reinit ring here */
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* lance_restart, essentially */
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lance_init_ring(dev);
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA( CSR0 ) = CSR0_INEA | CSR0_INIT | CSR0_STRT;
7701ae5dc342ac78d7a42965fd1f323815f6f5ef2c1Eric Dumazet	dev->trans_start = jiffies; /* prevent tx timeout */
7711ae5dc342ac78d7a42965fd1f323815f6f5ef2c1Eric Dumazet	netif_wake_queue(dev);
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
777454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen{
778454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen	struct lance_private *lp = netdev_priv(dev);
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_ioreg	 *IO = lp->iobase;
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int entry, len;
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_tx_head *head;
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n",
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  dev->name, DREG ));
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* The old LANCE chips doesn't automatically pad buffers to min. size. */
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = skb->len;
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (len < ETH_ZLEN)
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = ETH_ZLEN;
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* PAM-Card has a bug: Can only send packets with even number of bytes! */
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (lp->cardtype == PAM_CARD && (len & 1))
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		++len;
7956aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (len > skb->len) {
7975b057c6b1a25d57edf2b4d1e956e50936480a9ffHerbert Xu		if (skb_padto(skb, len))
7986ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy			return NETDEV_TX_OK;
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8006aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_stop_queue (dev);
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Fill in a Tx ring entry */
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lance_debug >= 3) {
805e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg		printk( "%s: TX pkt type 0x%04x from %pM to %pM"
8060795af5729b18218767fab27c44b1384f72dc9adJoe Perches				" data at 0x%08x len %d\n",
8070795af5729b18218767fab27c44b1384f72dc9adJoe Perches				dev->name, ((u_short *)skb->data)[6],
808e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg				&skb->data[6], skb->data,
8090795af5729b18218767fab27c44b1384f72dc9adJoe Perches				(int)skb->data, (int)skb->len );
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We're not prepared for the int until the last flags are set/reset. And
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the int may happen already after setting the OWN_CHIP... */
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&lp->devlock, flags);
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Mask to ring buffer boundary. */
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	entry = lp->cur_tx & TX_RING_MOD_MASK;
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head  = &(MEM->tx_head[entry]);
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Caution: the write order is important here, set the "ownership" bits
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * last.
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head->length = -len;
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head->misc = 0;
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->memcpy_f( PKTBUF_ADDR(head), (void *)skb->data, skb->len );
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP;
82909f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik	dev->stats.tx_bytes += skb->len;
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_kfree_skb( skb );
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->cur_tx++;
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while( lp->cur_tx >= TX_RING_SIZE && lp->dirty_tx >= TX_RING_SIZE ) {
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->cur_tx -= TX_RING_SIZE;
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->dirty_tx -= TX_RING_SIZE;
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Trigger an immediate send poll. */
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DREG = CSR0_INEA | CSR0_TDMD;
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((MEM->tx_head[(entry+1) & TX_RING_MOD_MASK].flag & TMD1_OWN) ==
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		TMD1_OWN_HOST)
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_start_queue (dev);
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->tx_full = 1;
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&lp->devlock, flags);
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8476ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy	return NETDEV_TX_OK;
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The LANCE interrupt handler. */
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8527d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t lance_interrupt( int irq, void *dev_id )
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = dev_id;
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_private *lp;
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_ioreg	 *IO;
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int csr0, boguscnt = 10;
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int handled = 0;
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev == NULL) {
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DPRINTK( 1, ( "lance_interrupt(): interrupt for unknown device.\n" ));
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return IRQ_NONE;
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
865454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen	lp = netdev_priv(dev);
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IO = lp->iobase;
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock (&lp->devlock);
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AREG = CSR0;
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while( ((csr0 = DREG) & (CSR0_ERR | CSR0_TINT | CSR0_RINT)) &&
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   --boguscnt >= 0) {
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		handled = 1;
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Acknowledge all of the current interrupt sources ASAP. */
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DREG = csr0 & ~(CSR0_INIT | CSR0_STRT | CSR0_STOP |
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds									CSR0_TDMD | CSR0_INEA);
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DPRINTK( 2, ( "%s: interrupt  csr0=%04x new csr=%04x.\n",
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  dev->name, csr0, DREG ));
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (csr0 & CSR0_RINT)			/* Rx interrupt */
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lance_rx( dev );
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (csr0 & CSR0_TINT) {			/* Tx-done interrupt */
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int dirty_tx = lp->dirty_tx;
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			while( dirty_tx < lp->cur_tx) {
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				int entry = dirty_tx & TX_RING_MOD_MASK;
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				int status = MEM->tx_head[entry].flag;
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (status & TMD1_OWN_CHIP)
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;			/* It still hasn't been Txed */
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				MEM->tx_head[entry].flag = 0;
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (status & TMD1_ERR) {
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/* There was an major error, log it. */
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					int err_status = MEM->tx_head[entry].misc;
89909f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik					dev->stats.tx_errors++;
90009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik					if (err_status & TMD3_RTRY) dev->stats.tx_aborted_errors++;
90109f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik					if (err_status & TMD3_LCAR) dev->stats.tx_carrier_errors++;
90209f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik					if (err_status & TMD3_LCOL) dev->stats.tx_window_errors++;
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (err_status & TMD3_UFLO) {
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						/* Ackk!  On FIFO errors the Tx unit is turned off! */
90509f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik						dev->stats.tx_fifo_errors++;
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						/* Remove this verbosity later! */
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						DPRINTK( 1, ( "%s: Tx FIFO error! Status %04x\n",
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds									  dev->name, csr0 ));
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						/* Restart the chip. */
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						DREG = CSR0_STRT;
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else {
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (status & (TMD1_MORE | TMD1_ONE | TMD1_DEF))
91409f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik						dev->stats.collisions++;
91509f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik					dev->stats.tx_packets++;
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* XXX MSch: free skb?? */
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dirty_tx++;
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef final_version
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				DPRINTK( 0, ( "out-of-sync dirty pointer,"
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							  " %d vs. %d, full=%ld.\n",
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							  dirty_tx, lp->cur_tx, lp->tx_full ));
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dirty_tx += TX_RING_SIZE;
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9318e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches			if (lp->tx_full && (netif_queue_stopped(dev)) &&
9328e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches				dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* The ring is no longer full, clear tbusy. */
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lp->tx_full = 0;
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				netif_wake_queue (dev);
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lp->dirty_tx = dirty_tx;
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Log misc errors. */
94209f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik		if (csr0 & CSR0_BABL) dev->stats.tx_errors++; /* Tx babble. */
94309f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik		if (csr0 & CSR0_MISS) dev->stats.rx_errors++; /* Missed a Rx frame. */
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (csr0 & CSR0_MERR) {
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DPRINTK( 1, ( "%s: Bus master arbitration failure (?!?), "
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						  "status %04x.\n", dev->name, csr0 ));
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Restart the chip. */
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DREG = CSR0_STRT;
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Clear any other interrupt, and set interrupt enable. */
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DREG = CSR0_BABL | CSR0_CERR | CSR0_MISS | CSR0_MERR |
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   CSR0_IDON | CSR0_INEA;
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK( 2, ( "%s: exiting interrupt, csr0=%#04x.\n",
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  dev->name, DREG ));
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock (&lp->devlock);
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_RETVAL(handled);
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_rx( struct net_device *dev )
965454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen{
966454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen	struct lance_private *lp = netdev_priv(dev);
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int entry = lp->cur_rx & RX_RING_MOD_MASK;
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK( 2, ( "%s: rx int, flag=%04x\n", dev->name,
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  MEM->rx_head[entry].flag ));
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* If we own the next entry, it's a new packet. Send it up. */
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while( (MEM->rx_head[entry].flag & RMD1_OWN) == RMD1_OWN_HOST ) {
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct lance_rx_head *head = &(MEM->rx_head[entry]);
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int status = head->flag;
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status != (RMD1_ENP|RMD1_STP)) {		/* There was an error. */
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* There is a tricky error noted by John Murphy,
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   <murf@perftech.com> to Russ Nelson: Even with full-sized
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   buffers it's possible for a jabber packet to use two
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   buffers, with only the last correctly noting the error. */
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (status & RMD1_ENP)	/* Only count a general error at the */
98409f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik				dev->stats.rx_errors++; /* end of a packet.*/
98509f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik			if (status & RMD1_FRAM) dev->stats.rx_frame_errors++;
98609f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik			if (status & RMD1_OFLO) dev->stats.rx_over_errors++;
98709f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik			if (status & RMD1_CRC) dev->stats.rx_crc_errors++;
98809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik			if (status & RMD1_BUFF) dev->stats.rx_fifo_errors++;
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			head->flag &= (RMD1_ENP|RMD1_STP);
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Malloc up new buffer, compatible with net-3. */
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			short pkt_len = head->msg_length & 0xfff;
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct sk_buff *skb;
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (pkt_len < 60) {
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk( "%s: Runt packet!\n", dev->name );
99709f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik				dev->stats.rx_errors++;
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else {
10001d266430546acf01438ae42d0a7370db4817e2adPradeep A Dalvi				skb = netdev_alloc_skb(dev, pkt_len + 2);
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (skb == NULL) {
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					DPRINTK( 1, ( "%s: Memory squeeze, deferring packet.\n",
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								  dev->name ));
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					for( i = 0; i < RX_RING_SIZE; i++ )
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (MEM->rx_head[(entry+i) & RX_RING_MOD_MASK].flag &
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							RMD1_OWN_CHIP)
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							break;
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (i > RX_RING_SIZE - 2) {
101009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik						dev->stats.rx_dropped++;
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						head->flag |= RMD1_OWN_CHIP;
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						lp->cur_rx++;
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (lance_debug >= 3) {
10180795af5729b18218767fab27c44b1384f72dc9adJoe Perches					u_char *data = PKTBUF_ADDR(head);
10190795af5729b18218767fab27c44b1384f72dc9adJoe Perches
1020e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg					printk(KERN_DEBUG "%s: RX pkt type 0x%04x from %pM to %pM "
10210795af5729b18218767fab27c44b1384f72dc9adJoe Perches						   "data %02x %02x %02x %02x %02x %02x %02x %02x "
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						   "len %d\n",
10230795af5729b18218767fab27c44b1384f72dc9adJoe Perches						   dev->name, ((u_short *)data)[6],
1024e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg						   &data[6], data,
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						   data[15], data[16], data[17], data[18],
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						   data[19], data[20], data[21], data[22],
10270795af5729b18218767fab27c44b1384f72dc9adJoe Perches						   pkt_len);
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb_reserve( skb, 2 );	/* 16 byte align */
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb_put( skb, pkt_len );	/* Make room */
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lp->memcpy_f( skb->data, PKTBUF_ADDR(head), pkt_len );
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb->protocol = eth_type_trans( skb, dev );
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				netif_rx( skb );
103509f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik				dev->stats.rx_packets++;
103609f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik				dev->stats.rx_bytes += pkt_len;
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		head->flag |= RMD1_OWN_CHIP;
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		entry = (++lp->cur_rx) & RX_RING_MOD_MASK;
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->cur_rx &= RX_RING_MOD_MASK;
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* From lance.c (Donald Becker): */
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We should check that at least two ring entries are free.	 If not,
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   we should free one and mark stats->rx_dropped++. */
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_close( struct net_device *dev )
1054454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen{
1055454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen	struct lance_private *lp = netdev_priv(dev);
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_ioreg	 *IO = lp->iobase;
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_stop_queue (dev);
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AREG = CSR0;
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTK( 2, ( "%s: Shutting down ethercard, status was %2.2x.\n",
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  dev->name, DREG ));
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We stop the LANCE here -- it occasionally polls
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   memory if we don't. */
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DREG = CSR0_STOP;
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Set or clear the multicast filter for this adaptor.
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   num_addrs == -1		Promiscuous mode, receive all packets
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   num_addrs == 0		Normal mode, clear multicast list
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   num_addrs > 0		Multicast mode, receive normal and MC packets, and do
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						best-effort filtering.
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void set_multicast_list( struct net_device *dev )
1081454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen{
1082454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen	struct lance_private *lp = netdev_priv(dev);
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_ioreg	 *IO = lp->iobase;
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (netif_running(dev))
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Only possible if board is already started */
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We take the simple way out and always enable promiscuous mode. */
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DREG = CSR0_STOP; /* Temporarily stop the lance. */
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->flags & IFF_PROMISC) {
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Log any net taps. */
1094d5b20697ca37d80cc4ec2ba3c5ddf1339dc1d49aAndy Gospodarek		DPRINTK( 2, ( "%s: Promiscuous mode enabled.\n", dev->name ));
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		REGA( CSR15 ) = 0x8000; /* Set promiscuous mode */
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		short multicast_table[4];
10984cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko		int num_addrs = netdev_mc_count(dev);
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int i;
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* We don't use the multicast table, but rely on upper-layer
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * filtering. */
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memset( multicast_table, (num_addrs == 0) ? 0 : -1,
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sizeof(multicast_table) );
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for( i = 0; i < 4; i++ )
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			REGA( CSR8+i ) = multicast_table[i];
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		REGA( CSR15 ) = 0; /* Unset promiscuous mode */
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Always set BSWP after a STOP as STOP puts it back into
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * little endian mode.
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0);
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Resume normal operation and reset AREG to CSR0 */
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	REGA( CSR0 ) = CSR0_IDON | CSR0_INEA | CSR0_STRT;
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This is needed for old RieblCards and possible for new RieblCards */
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_set_mac_address( struct net_device *dev, void *addr )
1123454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen{
1124454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen	struct lance_private *lp = netdev_priv(dev);
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sockaddr *saddr = addr;
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lp->cardtype != OLD_RIEBL && lp->cardtype != NEW_RIEBL)
1129807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet		return -EOPNOTSUPP;
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (netif_running(dev)) {
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Only possible while card isn't started */
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DPRINTK( 1, ( "%s: hwaddr can be set only while card isn't open.\n",
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  dev->name ));
1135807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet		return -EIO;
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy( dev->dev_addr, saddr->sa_data, dev->addr_len );
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for( i = 0; i < 6; i++ )
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MEM->init.hwaddr[i] = dev->dev_addr[i^1]; /* <- 16 bit swap! */
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->memcpy_f( RIEBL_HWADDR_ADDR, dev->dev_addr, 6 );
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set also the magic for future sessions */
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*RIEBL_MAGIC_ADDR = RIEBL_MAGIC;
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1145807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet	return 0;
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11486aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef MODULE
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device *atarilance_dev;
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
115253e7c46b0680ccc3ac67a2b8cd7f050569836e44Jon Schindlerstatic int __init atarilance_module_init(void)
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	atarilance_dev = atarilance_probe(-1);
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (IS_ERR(atarilance_dev))
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return PTR_ERR(atarilance_dev);
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
116053e7c46b0680ccc3ac67a2b8cd7f050569836e44Jon Schindlerstatic void __exit atarilance_module_exit(void)
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unregister_netdev(atarilance_dev);
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_irq(atarilance_dev->irq, atarilance_dev);
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_netdev(atarilance_dev);
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
116653e7c46b0680ccc3ac67a2b8cd7f050569836e44Jon Schindlermodule_init(atarilance_module_init);
116753e7c46b0680ccc3ac67a2b8cd7f050569836e44Jon Schindlermodule_exit(atarilance_module_exit);
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* MODULE */
11696aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Local variables:
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  c-indent-level: 4
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  tab-width: 4
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * End:
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1177