11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* lance.c: An AMD LANCE/PCnet ethernet driver for Linux. */
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Written/copyright 1993-1998 by Donald Becker.
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Copyright 1993 United States Government as represented by the
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Director, National Security Agency.
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	This software may be used and distributed according to the terms
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	of the GNU General Public License, incorporated herein by reference.
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	This driver is for the Allied Telesis AT1500 and HP J2405A, and should work
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	with most other LANCE-based bus-master (NE2100/NE2500) ethercards.
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	The author may be reached as becker@scyld.com, or C/O
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Scyld Computing Corporation
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	410 Severn Ave., Suite 210
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Annapolis MD 21403
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Andrey V. Savochkin:
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	- alignment problem with 1.3.* kernel and some minor changes.
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Thomas Bogendoerfer (tsbogend@bigbug.franken.de):
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	- added support for Linux/Alpha, but removed most of it, because
226aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik        it worked only for the PCI chip.
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      - added hook for the 32bit lance driver
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds      - added PCnetPCI II (79C970A) to chip table
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Paul Gortmaker (gpg109@rsphy1.anu.edu.au):
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	- hopefully fix above so Linux/Alpha can use ISA cards too.
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    8/20/96 Fixed 7990 autoIRQ failure and reversed unneeded alignment -djb
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    v1.12 10/27/97 Module support -djb
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    v1.14  2/3/98 Module support modified, made PCI support optional -djb
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    v1.15 5/27/99 Fixed bug in the cleanup_module(). dev->priv was freed
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                  before unregister_netdev() which caused NULL pointer
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                  reference later in the chain (in rtnetlink_fill_ifinfo())
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                  -- Mika Kuoppala <miku@iki.fi>
346aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Forward ported v1.14 to 2.1.129, merged the PCI and misc changes from
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    the 2.1 version of the old driver - Alan Cox
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Get rid of check_region, check kmalloc return in lance_probe1
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 11/01/2001
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Reworked detection, added support for Racal InterLan EtherBlaster cards
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Vesselin Kostadinov <vesok at yahoo dot com > - 22/4/2004
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45d5b20697ca37d80cc4ec2ba3c5ddf1339dc1d49aAndy Gospodarekstatic const char version[] = "lance.c:v1.16 2006/11/09 dplatt@3do.com, becker@cesdis.gsfc.nasa.gov\n";
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h>
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h>
60d7fe0f241dceade9c8d4af75498765c5ff7f27e6Al Viro#include <linux/mm.h>
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h>
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/dma.h>
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int lance_portlist[] __initdata = { 0x300, 0x320, 0x340, 0x360, 0};
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_probe1(struct net_device *dev, int ioaddr, int irq, int options);
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init do_lance_probe(struct net_device *dev);
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct card {
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char id_offset14;
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char id_offset15;
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} cards[] = {
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{	//"normal"
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.id_offset14 = 0x57,
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.id_offset15 = 0x57,
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	},
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{	//NI6510EB
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.id_offset14 = 0x52,
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.id_offset15 = 0x44,
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	},
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{	//Racal InterLan EtherBlaster
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.id_offset14 = 0x52,
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.id_offset15 = 0x49,
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	},
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NUM_CARDS 3
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef LANCE_DEBUG
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_debug = LANCE_DEBUG;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_debug = 1;
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				Theory of Operation
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsI. Board Compatibility
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsThis device driver is designed for the AMD 79C960, the "PCnet-ISA
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssingle-chip ethernet controller for ISA".  This chip is used in a wide
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvariety of boards from vendors such as Allied Telesis, HP, Kingston,
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsand Boca.  This driver is also intended to work with older AMD 7990
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdesigns, such as the NE1500 and NE2100, and newer 79C961.  For convenience,
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsI use the name LANCE to refer to all of the AMD chips, even though it properly
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsrefers only to the original 7990.
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsII. Board-specific settings
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsThe driver is designed to work the boards that use the faster
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsbus-master mode, rather than in shared memory mode.	 (Only older designs
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldshave on-board buffer memory needed to support the slower shared memory mode.)
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMost ISA boards have jumpered settings for the I/O base, IRQ line, and DMA
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldschannel.  This driver probes the likely base addresses:
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{0x300, 0x320, 0x340, 0x360}.
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsAfter the board is found it generates a DMA-timeout interrupt and uses
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsautoIRQ to find the IRQ line.  The DMA channel can be set with the low bits
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsof the otherwise-unused dev->mem_start value (aka PARAM1).  If unset it is
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsprobed for by enabling each free DMA channel in turn and checking if
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsinitialization succeeds.
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsThe HP-J2405A board is an exception: with this board it is easy to read the
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEEPROM-set values for the base, IRQ, and DMA.  (Of course you must already
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds_know_ the base address -- that field is for writing the EEPROM.)
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsIII. Driver operation
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsIIIa. Ring buffers
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsThe LANCE uses ring buffers of Tx and Rx descriptors.  Each entry describes
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsthe base and length of the data buffer, along with status bits.	 The length
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsof these buffers is set by LANCE_LOG_{RX,TX}_BUFFERS, which is log_2() of
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsthe buffer length (rather than being directly the buffer length) for
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsimplementation ease.  The current values are 2 (Tx) and 4 (Rx), which leads to
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsring sizes of 4 (Tx) and 16 (Rx).  Increasing the number of ring entries
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsneedlessly uses extra space and reduces the chance that an upper layer will
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsbe able to reorder queued Tx packets based on priority.	 Decreasing the number
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsof entries makes it more difficult to achieve back-to-back packet transmission
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsand increases the chance that Rx ring will overflow.  (Consider the worst case
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsof receiving back-to-back minimum-sized packets.)
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsThe LANCE has the capability to "chain" both Rx and Tx buffers, but this driver
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatically allocates full-sized (slightly oversized -- PKT_BUF_SZ) buffers to
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsavoid the administrative overhead. For the Rx side this avoids dynamically
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsallocating full-sized buffers "just in case", at the expense of a
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmemory-to-memory data copy for each packet received.  For most systems this
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsis a good tradeoff: the Rx buffer will always be in low memory, the copy
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsis inexpensive, and it primes the cache for later packet processing.  For Tx
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsthe buffers are only used when needed as low-memory bounce buffers.
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsIIIB. 16M memory limitations.
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsFor the ISA bus master mode all structures used directly by the LANCE,
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsthe initialization block, Rx and Tx rings, and data buffers, must be
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsaccessible from the ISA bus, i.e. in the lower 16M of real memory.
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsThis is a problem for current Linux kernels on >16M machines. The network
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevices are initialized after memory initialization, and the kernel doles out
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmemory from the top of memory downward.	 The current solution is to have a
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsspecial network initialization routine that's called before memory
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsinitialization; this will eventually be generalized for all network devices.
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsAs mentioned before, low-memory "bounce-buffers" are used when needed.
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsIIIC. Synchronization
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsThe driver runs as two independent, single-threaded flows of control.  One
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsis the send-packet routine, which enforces single-threaded use by the
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdev->tbusy flag.  The other thread is the interrupt handler, which is single
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsthreaded by the hardware and other software.
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsThe send packet thread has partial control over the Tx ring and 'dev->tbusy'
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsflag.  It sets the tbusy flag whenever it's queuing a Tx packet. If the next
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsqueue slot is empty, it clears the tbusy flag when finished otherwise it sets
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsthe 'lp->tx_full' flag.
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsThe interrupt handler has exclusive control over the Rx ring and records stats
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfrom the Tx ring. (The Tx-done interrupt can't be selectively turned off, so
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldswe can't avoid the interrupt overhead by having the Tx routine reap the Tx
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstats.)	 After reaping the stats, it marks the queue entry as empty by setting
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsthe 'base' to zero. Iff the 'lp->tx_full' flag is set, it clears both the
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstx_full and tbusy flags.
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Set the number of Tx and Rx buffers, using Log_2(# buffers).
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Reasonable default values are 16 Tx buffers, and 16 Rx buffers.
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   That translates to 4 and 4 (16 == 2^^4).
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   This is a compile-time option for efficiency.
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   */
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef LANCE_LOG_TX_BUFFERS
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LANCE_LOG_TX_BUFFERS 4
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LANCE_LOG_RX_BUFFERS 4
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_RING_SIZE			(1 << (LANCE_LOG_TX_BUFFERS))
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_RING_MOD_MASK		(TX_RING_SIZE - 1)
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_RING_LEN_BITS		((LANCE_LOG_TX_BUFFERS) << 29)
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_RING_SIZE			(1 << (LANCE_LOG_RX_BUFFERS))
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_RING_MOD_MASK		(RX_RING_SIZE - 1)
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_RING_LEN_BITS		((LANCE_LOG_RX_BUFFERS) << 29)
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PKT_BUF_SZ		1544
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Offsets from base I/O address. */
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LANCE_DATA 0x10
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LANCE_ADDR 0x12
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LANCE_RESET 0x14
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LANCE_BUS_IF 0x16
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LANCE_TOTAL_SIZE 0x18
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
210c63fdf46ad0a7f8fe3c0252a0e763515617e0ea7Eric Dumazet#define TX_TIMEOUT	(HZ/5)
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The LANCE Rx and Tx ring descriptors. */
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_rx_head {
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s32 base;
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s16 buf_length;			/* This length is 2s complement (negative)! */
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s16 msg_length;			/* This length is "normal". */
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_tx_head {
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s32 base;
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s16 length;				/* Length is 2s complement (negative)! */
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	s16 misc;
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The LANCE initialization block, described in databook. */
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_init_block {
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 mode;		/* Pre-set mode (reg. 15) */
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8  phys_addr[6]; /* Physical ethernet address */
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 filter[2];			/* Multicast filter (unused). */
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Receive and transmit ring base, along with extra bits. */
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32  rx_ring;			/* Tx and Rx ring base pointers */
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32  tx_ring;
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_private {
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* The Tx and Rx ring entries must be aligned on 8-byte boundaries. */
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_rx_head rx_ring[RX_RING_SIZE];
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_tx_head tx_ring[TX_RING_SIZE];
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_init_block	init_block;
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const char *name;
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff* tx_skbuff[TX_RING_SIZE];
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* The addresses of receive-in-place skbuffs. */
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff* rx_skbuff[RX_RING_SIZE];
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long rx_buffs;		/* Address of Rx and Tx buffers. */
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Tx low-memory "bounce buffer" address. */
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char (*tx_bounce_buffs)[PKT_BUF_SZ];
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int cur_rx, cur_tx;			/* The next free ring entry */
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int dirty_rx, dirty_tx;		/* The ring entries to be free()ed. */
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int dma;
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char chip_version;	/* See lance_chip_type. */
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t devlock;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LANCE_MUST_PAD          0x00000001
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LANCE_ENABLE_AUTOSELECT 0x00000002
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LANCE_MUST_REINIT_RING  0x00000004
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LANCE_MUST_UNRESET      0x00000008
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LANCE_HAS_MISSED_FRAME  0x00000010
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* A mapping from the chip ID number to the part number and features.
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   These are from the datasheets -- in real life the '970 version
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   reportedly has the same ID as the '965. */
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct lance_chip_type {
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int id_number;
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const char *name;
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int flags;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} chip_table[] = {
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{0x0000, "LANCE 7990",				/* Ancient lance chip.  */
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		LANCE_MUST_PAD + LANCE_MUST_UNRESET},
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{0x0003, "PCnet/ISA 79C960",		/* 79C960 PCnet/ISA.  */
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			LANCE_HAS_MISSED_FRAME},
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{0x2260, "PCnet/ISA+ 79C961",		/* 79C961 PCnet/ISA+, Plug-n-Play.  */
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			LANCE_HAS_MISSED_FRAME},
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{0x2420, "PCnet/PCI 79C970",		/* 79C970 or 79C974 PCnet-SCSI, PCI. */
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			LANCE_HAS_MISSED_FRAME},
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Bug: the PCnet/PCI actually uses the PCnet/VLB ID number, so just call
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		it the PCnet32. */
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{0x2430, "PCnet32",					/* 79C965 PCnet for VL bus. */
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			LANCE_HAS_MISSED_FRAME},
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        {0x2621, "PCnet/PCI-II 79C970A",        /* 79C970A PCInetPCI II. */
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                        LANCE_HAS_MISSED_FRAME},
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{0x0, 	 "PCnet (unknown)",
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			LANCE_HAS_MISSED_FRAME},
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum {OLD_LANCE = 0, PCNET_ISA=1, PCNET_ISAP=2, PCNET_PCI=3, PCNET_VLB=4, PCNET_PCI_II=5, LANCE_UNKNOWN=6};
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Non-zero if lance_probe1() needs to allocate low-memory bounce buffers.
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Assume yes until we know the memory size. */
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned char lance_need_isa_bounce_buffers = 1;
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_open(struct net_device *dev);
3019e24974db6b01ec067c24de09588282b6a1407f0Al Virostatic void lance_init_ring(struct net_device *dev, gfp_t mode);
30261357325f377889a1daffa14962d705dc814dd0eStephen Hemmingerstatic netdev_tx_t lance_start_xmit(struct sk_buff *skb,
30361357325f377889a1daffa14962d705dc814dd0eStephen Hemminger				    struct net_device *dev);
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_rx(struct net_device *dev);
3057d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t lance_interrupt(int irq, void *dev_id);
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_close(struct net_device *dev);
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device_stats *lance_get_stats(struct net_device *dev);
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void set_multicast_list(struct net_device *dev);
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lance_tx_timeout (struct net_device *dev);
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3116aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef MODULE
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX_CARDS		8	/* Max number of interfaces (cards) per module */
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device *dev_lance[MAX_CARDS];
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int io[MAX_CARDS];
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dma[MAX_CARDS];
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int irq[MAX_CARDS];
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_array(io, int, NULL, 0);
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_array(dma, int, NULL, 0);
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_array(irq, int, NULL, 0);
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(lance_debug, int, 0);
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(io, "LANCE/PCnet I/O base address(es),required");
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(dma, "LANCE/PCnet ISA DMA channel (ignored for some devices)");
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(irq, "LANCE/PCnet IRQ number (ignored for some devices)");
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(lance_debug, "LANCE/PCnet debug level (0-7)");
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3303805f0e28ca313893b87e881201561d5c1857dd8Andrew Mortonint __init init_module(void)
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int this_dev, found = 0;
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) {
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (io[this_dev] == 0)  {
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (this_dev != 0) /* only complain once */
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_NOTICE "lance.c: Module autoprobing not allowed. Append \"io=0xNNN\" value(s).\n");
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EPERM;
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev = alloc_etherdev(0);
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!dev)
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->irq = irq[this_dev];
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->base_addr = io[this_dev];
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->dma = dma[this_dev];
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (do_lance_probe(dev) == 0) {
349b1fc5505e0dbcc3fd7c75bfe6bee39ec50080963<herbert@gondor.apana.org.au>			dev_lance[found++] = dev;
350b1fc5505e0dbcc3fd7c75bfe6bee39ec50080963<herbert@gondor.apana.org.au>			continue;
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free_netdev(dev);
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (found != 0)
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENXIO;
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36064916f1ebe93592153c72bcdb189a31e4d40049aDenis Vlasenkostatic void cleanup_card(struct net_device *dev)
36164916f1ebe93592153c72bcdb189a31e4d40049aDenis Vlasenko{
362c0103606b7e3db191dcbaf988f28fa26aa711230Wang Chen	struct lance_private *lp = dev->ml_priv;
36364916f1ebe93592153c72bcdb189a31e4d40049aDenis Vlasenko	if (dev->dma != 4)
36464916f1ebe93592153c72bcdb189a31e4d40049aDenis Vlasenko		free_dma(dev->dma);
36564916f1ebe93592153c72bcdb189a31e4d40049aDenis Vlasenko	release_region(dev->base_addr, LANCE_TOTAL_SIZE);
36664916f1ebe93592153c72bcdb189a31e4d40049aDenis Vlasenko	kfree(lp->tx_bounce_buffs);
36764916f1ebe93592153c72bcdb189a31e4d40049aDenis Vlasenko	kfree((void*)lp->rx_buffs);
36864916f1ebe93592153c72bcdb189a31e4d40049aDenis Vlasenko	kfree(lp);
36964916f1ebe93592153c72bcdb189a31e4d40049aDenis Vlasenko}
37064916f1ebe93592153c72bcdb189a31e4d40049aDenis Vlasenko
371afc8eb46c0ea2cab8bc28713b2e0614f015a7516Al Virovoid __exit cleanup_module(void)
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int this_dev;
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) {
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct net_device *dev = dev_lance[this_dev];
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (dev) {
3786aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik			unregister_netdev(dev);
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cleanup_card(dev);
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			free_netdev(dev);
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* MODULE */
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Starting in v2.1.*, the LANCE/PCnet probe is now similar to the other
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   board probes now that kmalloc() can allocate ISA DMA-able regions.
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   This also allows the LANCE driver to be used as a module.
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   */
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init do_lance_probe(struct net_device *dev)
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
39400137dad17707f0d14dbf7e193761220f1c2fe03Hannes Eder	unsigned int *port;
39500137dad17707f0d14dbf7e193761220f1c2fe03Hannes Eder	int result;
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (high_memory <= phys_to_virt(16*1024*1024))
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lance_need_isa_bounce_buffers = 0;
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (port = lance_portlist; *port; port++) {
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int ioaddr = *port;
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct resource *r = request_region(ioaddr, LANCE_TOTAL_SIZE,
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							"lance-probe");
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (r) {
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Detect the card with minimal I/O reads */
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			char offset14 = inb(ioaddr + 14);
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int card;
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (card = 0; card < NUM_CARDS; ++card)
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (cards[card].id_offset14 == offset14)
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (card < NUM_CARDS) {/*yes, the first byte matches*/
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				char offset15 = inb(ioaddr + 15);
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				for (card = 0; card < NUM_CARDS; ++card)
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if ((cards[card].id_offset14 == offset14) &&
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						(cards[card].id_offset15 == offset15))
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						break;
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (card < NUM_CARDS) { /*Signature OK*/
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				result = lance_probe1(dev, ioaddr, 0, 0);
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!result) {
422c0103606b7e3db191dcbaf988f28fa26aa711230Wang Chen					struct lance_private *lp = dev->ml_priv;
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					int ver = lp->chip_version;
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					r->name = chip_table[ver].name;
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return 0;
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			release_region(ioaddr, LANCE_TOTAL_SIZE);
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENODEV;
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef MODULE
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct net_device * __init lance_probe(int unit)
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = alloc_etherdev(0);
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev)
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ERR_PTR(-ENODEV);
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sprintf(dev->name, "eth%d", unit);
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netdev_boot_setup_check(dev);
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = do_lance_probe(dev);
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return dev;
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_netdev(dev);
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ERR_PTR(err);
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
457462540bdb2f08d465a2416764fc628520f82939fStephen Hemmingerstatic const struct net_device_ops lance_netdev_ops = {
458462540bdb2f08d465a2416764fc628520f82939fStephen Hemminger	.ndo_open 		= lance_open,
459462540bdb2f08d465a2416764fc628520f82939fStephen Hemminger	.ndo_start_xmit		= lance_start_xmit,
460462540bdb2f08d465a2416764fc628520f82939fStephen Hemminger	.ndo_stop		= lance_close,
461462540bdb2f08d465a2416764fc628520f82939fStephen Hemminger	.ndo_get_stats		= lance_get_stats,
462afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko	.ndo_set_rx_mode	= set_multicast_list,
463462540bdb2f08d465a2416764fc628520f82939fStephen Hemminger	.ndo_tx_timeout		= lance_tx_timeout,
464462540bdb2f08d465a2416764fc628520f82939fStephen Hemminger	.ndo_change_mtu		= eth_change_mtu,
465462540bdb2f08d465a2416764fc628520f82939fStephen Hemminger	.ndo_set_mac_address 	= eth_mac_addr,
466462540bdb2f08d465a2416764fc628520f82939fStephen Hemminger	.ndo_validate_addr	= eth_validate_addr,
467462540bdb2f08d465a2416764fc628520f82939fStephen Hemminger};
468462540bdb2f08d465a2416764fc628520f82939fStephen Hemminger
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int options)
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_private *lp;
47200137dad17707f0d14dbf7e193761220f1c2fe03Hannes Eder	unsigned long dma_channels;	/* Mark spuriously-busy DMA channels */
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, reset_val, lance_version;
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const char *chipname;
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Flags for specific chips or boards. */
47600137dad17707f0d14dbf7e193761220f1c2fe03Hannes Eder	unsigned char hpJ2405A = 0;	/* HP ISA adaptor */
47700137dad17707f0d14dbf7e193761220f1c2fe03Hannes Eder	int hp_builtin = 0;		/* HP on-board ethernet. */
47800137dad17707f0d14dbf7e193761220f1c2fe03Hannes Eder	static int did_version;		/* Already printed version info. */
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = -ENOMEM;
481c44fec118b62baad3fc70e2ef3447729a1d9b194Al Viro	void __iomem *bios;
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* First we look for special cases.
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   Check for HP's on-board ethernet by looking for 'HP' in the BIOS.
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   There are two HP versions, check the BIOS for the configuration port.
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   This method provided by L. Julliard, Laurent_Julliard@grenoble.hp.com.
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   */
488c44fec118b62baad3fc70e2ef3447729a1d9b194Al Viro	bios = ioremap(0xf00f0, 0x14);
489c44fec118b62baad3fc70e2ef3447729a1d9b194Al Viro	if (!bios)
490c44fec118b62baad3fc70e2ef3447729a1d9b194Al Viro		return -ENOMEM;
491c44fec118b62baad3fc70e2ef3447729a1d9b194Al Viro	if (readw(bios + 0x12) == 0x5048)  {
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		static const short ioaddr_table[] = { 0x300, 0x320, 0x340, 0x360};
493c44fec118b62baad3fc70e2ef3447729a1d9b194Al Viro		int hp_port = (readl(bios + 1) & 1)  ? 0x499 : 0x99;
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* We can have boards other than the built-in!  Verify this is on-board. */
4958e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches		if ((inb(hp_port) & 0xc0) == 0x80 &&
4968e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches		    ioaddr_table[inb(hp_port) & 3] == ioaddr)
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			hp_builtin = hp_port;
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
499c44fec118b62baad3fc70e2ef3447729a1d9b194Al Viro	iounmap(bios);
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We also recognize the HP Vectra on-board here, but check below. */
5018e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches	hpJ2405A = (inb(ioaddr) == 0x08 && inb(ioaddr+1) == 0x00 &&
5028e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches		    inb(ioaddr+2) == 0x09);
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Reset the LANCE.	 */
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reset_val = inw(ioaddr+LANCE_RESET); /* Reset the LANCE */
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* The Un-Reset needed is only needed for the real NE2100, and will
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   confuse the HP board. */
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!hpJ2405A)
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outw(reset_val, ioaddr+LANCE_RESET);
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0x0000, ioaddr+LANCE_ADDR); /* Switch to window 0 */
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (inw(ioaddr+LANCE_DATA) != 0x0004)
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Get the version of the chip. */
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(88, ioaddr+LANCE_ADDR);
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (inw(ioaddr+LANCE_ADDR) != 88) {
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lance_version = 0;
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {			/* Good, it's a newer chip. */
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int chip_version = inw(ioaddr+LANCE_DATA);
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outw(89, ioaddr+LANCE_ADDR);
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		chip_version |= inw(ioaddr+LANCE_DATA) << 16;
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (lance_debug > 2)
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("  LANCE chip version is %#x.\n", chip_version);
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((chip_version & 0xfff) != 0x003)
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENODEV;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		chip_version = (chip_version >> 12) & 0xffff;
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (lance_version = 1; chip_table[lance_version].id_number; lance_version++) {
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (chip_table[lance_version].id_number == chip_version)
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
535b74ca3a896b9ab5f952bc440154758e708c48884Wang Chen	/* We can't allocate private data from alloc_etherdev() because it must
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   a ISA DMA-able region. */
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	chipname = chip_table[lance_version].name;
5380795af5729b18218767fab27c44b1384f72dc9adJoe Perches	printk("%s: %s at %#3x, ", dev->name, chipname, ioaddr);
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* There is a 16 byte station address PROM at the base address.
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   The first six bytes are the station address. */
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 6; i++)
5430795af5729b18218767fab27c44b1384f72dc9adJoe Perches		dev->dev_addr[i] = inb(ioaddr + i);
544e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg	printk("%pM", dev->dev_addr);
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->base_addr = ioaddr;
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Make certain the data structures used by the LANCE are aligned and DMAble. */
5486aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
549dd00cc486ab1c17049a535413d1751ef3482141cYoann Padioleau	lp = kzalloc(sizeof(*lp), GFP_DMA | GFP_KERNEL);
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(lp==NULL)
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp);
553c0103606b7e3db191dcbaf988f28fa26aa711230Wang Chen	dev->ml_priv = lp;
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->name = chipname;
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->rx_buffs = (unsigned long)kmalloc(PKT_BUF_SZ*RX_RING_SIZE,
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						  GFP_DMA | GFP_KERNEL);
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!lp->rx_buffs)
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_lp;
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lance_need_isa_bounce_buffers) {
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->tx_bounce_buffs = kmalloc(PKT_BUF_SZ*TX_RING_SIZE,
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						  GFP_DMA | GFP_KERNEL);
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!lp->tx_bounce_buffs)
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out_rx;
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->tx_bounce_buffs = NULL;
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->chip_version = lance_version;
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_init(&lp->devlock);
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->init_block.mode = 0x0003;		/* Disable Rx and Tx. */
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 6; i++)
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->init_block.phys_addr[i] = dev->dev_addr[i];
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->init_block.filter[0] = 0x00000000;
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->init_block.filter[1] = 0x00000000;
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->init_block.rx_ring = ((u32)isa_virt_to_bus(lp->rx_ring) & 0xffffff) | RX_RING_LEN_BITS;
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->init_block.tx_ring = ((u32)isa_virt_to_bus(lp->tx_ring) & 0xffffff) | TX_RING_LEN_BITS;
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0x0001, ioaddr+LANCE_ADDR);
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inw(ioaddr+LANCE_ADDR);
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw((short) (u32) isa_virt_to_bus(&lp->init_block), ioaddr+LANCE_DATA);
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0x0002, ioaddr+LANCE_ADDR);
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inw(ioaddr+LANCE_ADDR);
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(((u32)isa_virt_to_bus(&lp->init_block)) >> 16, ioaddr+LANCE_DATA);
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0x0000, ioaddr+LANCE_ADDR);
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inw(ioaddr+LANCE_ADDR);
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (irq) {					/* Set iff PCI card. */
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->dma = 4;			/* Native bus-master, no DMA channel needed. */
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->irq = irq;
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (hp_builtin) {
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		static const char dma_tbl[4] = {3, 5, 6, 0};
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		static const char irq_tbl[4] = {3, 4, 5, 9};
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned char port_val = inb(hp_builtin);
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->dma = dma_tbl[(port_val >> 4) & 3];
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->irq = irq_tbl[(port_val >> 2) & 3];
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(" HP Vectra IRQ %d DMA %d.\n", dev->irq, dev->dma);
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (hpJ2405A) {
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		static const char dma_tbl[4] = {3, 5, 6, 7};
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		static const char irq_tbl[8] = {3, 4, 5, 9, 10, 11, 12, 15};
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		short reset_val = inw(ioaddr+LANCE_RESET);
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->dma = dma_tbl[(reset_val >> 2) & 3];
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->irq = irq_tbl[(reset_val >> 4) & 7];
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(" HP J2405A IRQ %d DMA %d.\n", dev->irq, dev->dma);
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (lance_version == PCNET_ISAP) {		/* The plug-n-play version. */
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		short bus_info;
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outw(8, ioaddr+LANCE_ADDR);
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bus_info = inw(ioaddr+LANCE_BUS_IF);
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->dma = bus_info & 0x07;
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->irq = (bus_info >> 4) & 0x0F;
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* The DMA channel may be passed in PARAM1. */
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (dev->mem_start & 0x07)
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->dma = dev->mem_start & 0x07;
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->dma == 0) {
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Read the DMA channel status register, so that we can avoid
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   stuck DMA channels in the DMA detection below. */
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dma_channels = ((inb(DMA1_STAT_REG) >> 4) & 0x0f) |
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(inb(DMA2_STAT_REG) & 0xf0);
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = -ENODEV;
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->irq >= 2)
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(" assigned IRQ %d", dev->irq);
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (lance_version != 0)  {	/* 7990 boards need DMA detection first. */
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned long irq_mask;
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* To auto-IRQ we enable the initialization-done and DMA error
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   interrupts. For ISA boards we get a DMA error, but VLB and PCI
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   boards will work. */
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irq_mask = probe_irq_on();
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Trigger an initialization just for the interrupt. */
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outw(0x0041, ioaddr+LANCE_DATA);
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mdelay(20);
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->irq = probe_irq_off(irq_mask);
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (dev->irq)
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(", probed IRQ %d", dev->irq);
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(", failed to detect IRQ line.\n");
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out_tx;
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Check for the initialization done bit, 0x0100, which means
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   that we don't need a DMA channel. */
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (inw(ioaddr+LANCE_DATA) & 0x0100)
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->dma = 4;
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->dma == 4) {
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(", no DMA needed.\n");
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (dev->dma) {
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (request_dma(dev->dma, chipname)) {
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("DMA %d allocation failed.\n", dev->dma);
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out_tx;
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(", assigned DMA %d.\n", dev->dma);
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {			/* OK, we have to auto-DMA. */
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < 4; i++) {
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			static const char dmas[] = { 5, 6, 7, 3 };
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int dma = dmas[i];
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int boguscnt;
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Don't enable a permanently busy DMA channel, or the machine
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   will hang. */
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (test_bit(dma, &dma_channels))
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outw(0x7f04, ioaddr+LANCE_DATA); /* Clear the memory error bits. */
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (request_dma(dma, chipname))
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
6726aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			flags=claim_dma_lock();
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_dma_mode(dma, DMA_MODE_CASCADE);
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			enable_dma(dma);
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			release_dma_lock(flags);
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Trigger an initialization. */
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outw(0x0001, ioaddr+LANCE_DATA);
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (boguscnt = 100; boguscnt > 0; --boguscnt)
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (inw(ioaddr+LANCE_DATA) & 0x0900)
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (inw(ioaddr+LANCE_DATA) & 0x0100) {
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dev->dma = dma;
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk(", DMA %d.\n", dev->dma);
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				flags=claim_dma_lock();
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				disable_dma(dma);
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				release_dma_lock(flags);
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				free_dma(dma);
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (i == 4) {			/* Failure: bail. */
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("DMA detection failed.\n");
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out_tx;
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lance_version == 0 && dev->irq == 0) {
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* We may auto-IRQ now that we have a DMA channel. */
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Trigger an initialization just for the interrupt. */
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned long irq_mask;
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irq_mask = probe_irq_on();
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outw(0x0041, ioaddr+LANCE_DATA);
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mdelay(40);
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->irq = probe_irq_off(irq_mask);
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (dev->irq == 0) {
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("  Failed to detect the 7990 IRQ line.\n");
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out_dma;
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("  Auto-IRQ detected IRQ%d.\n", dev->irq);
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (chip_table[lp->chip_version].flags & LANCE_ENABLE_AUTOSELECT) {
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Turn on auto-select of media (10baseT or BNC) so that the user
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   can watch the LEDs even if the board isn't opened. */
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outw(0x0002, ioaddr+LANCE_ADDR);
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Don't touch 10base2 power bit. */
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outw(inw(ioaddr+LANCE_BUS_IF) | 0x0002, ioaddr+LANCE_BUS_IF);
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lance_debug > 0  &&  did_version++ == 0)
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(version);
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* The LANCE-specific entries in the device structure. */
729462540bdb2f08d465a2416764fc628520f82939fStephen Hemminger	dev->netdev_ops = &lance_netdev_ops;
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->watchdog_timeo = TX_TIMEOUT;
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
732b1fc5505e0dbcc3fd7c75bfe6bee39ec50080963<herbert@gondor.apana.org.au>	err = register_netdev(dev);
733b1fc5505e0dbcc3fd7c75bfe6bee39ec50080963<herbert@gondor.apana.org.au>	if (err)
734b1fc5505e0dbcc3fd7c75bfe6bee39ec50080963<herbert@gondor.apana.org.au>		goto out_dma;
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_dma:
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->dma != 4)
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free_dma(dev->dma);
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_tx:
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(lp->tx_bounce_buffs);
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_rx:
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree((void*)lp->rx_buffs);
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_lp:
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(lp);
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7486aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslance_open(struct net_device *dev)
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
752c0103606b7e3db191dcbaf988f28fa26aa711230Wang Chen	struct lance_private *lp = dev->ml_priv;
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ioaddr = dev->base_addr;
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->irq == 0 ||
757a0607fd3a25ba1848a63a0d925e36d914735ab47Joe Perches		request_irq(dev->irq, lance_interrupt, 0, lp->name, dev)) {
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EAGAIN;
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We used to allocate DMA here, but that was silly.
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   DMA lines can't be shared!  We now permanently allocate them. */
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Reset the LANCE */
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inw(ioaddr+LANCE_RESET);
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* The DMA controller is used as a no-operation slave, "cascade mode". */
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->dma != 4) {
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned long flags=claim_dma_lock();
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		enable_dma(dev->dma);
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_dma_mode(dev->dma, DMA_MODE_CASCADE);
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		release_dma_lock(flags);
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Un-Reset the LANCE, needed only for the NE2100. */
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (chip_table[lp->chip_version].flags & LANCE_MUST_UNRESET)
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outw(0, ioaddr+LANCE_RESET);
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (chip_table[lp->chip_version].flags & LANCE_ENABLE_AUTOSELECT) {
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* This is 79C960-specific: Turn on auto-select of media (AUI, BNC). */
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outw(0x0002, ioaddr+LANCE_ADDR);
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Only touch autoselect bit. */
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outw(inw(ioaddr+LANCE_BUS_IF) | 0x0002, ioaddr+LANCE_BUS_IF);
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 	}
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lance_debug > 1)
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("%s: lance_open() irq %d dma %d tx/rx rings %#x/%#x init %#x.\n",
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   dev->name, dev->irq, dev->dma,
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		           (u32) isa_virt_to_bus(lp->tx_ring),
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		           (u32) isa_virt_to_bus(lp->rx_ring),
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   (u32) isa_virt_to_bus(&lp->init_block));
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lance_init_ring(dev, GFP_KERNEL);
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Re-initialize the LANCE, and start it when done. */
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0x0001, ioaddr+LANCE_ADDR);
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw((short) (u32) isa_virt_to_bus(&lp->init_block), ioaddr+LANCE_DATA);
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0x0002, ioaddr+LANCE_ADDR);
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(((u32)isa_virt_to_bus(&lp->init_block)) >> 16, ioaddr+LANCE_DATA);
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0x0004, ioaddr+LANCE_ADDR);
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0x0915, ioaddr+LANCE_DATA);
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0x0000, ioaddr+LANCE_ADDR);
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0x0001, ioaddr+LANCE_DATA);
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_start_queue (dev);
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i = 0;
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (i++ < 100)
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (inw(ioaddr+LANCE_DATA) & 0x0100)
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8126aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	/*
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We used to clear the InitDone bit, 0x0100, here but Mark Stockton
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * reports that doing so triggers a bug in the '974.
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 	outw(0x0042, ioaddr+LANCE_DATA);
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lance_debug > 2)
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("%s: LANCE open after %d ticks, init block %#x csr0 %4.4x.\n",
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   dev->name, i, (u32) isa_virt_to_bus(&lp->init_block), inw(ioaddr+LANCE_DATA));
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;					/* Always succeed */
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The LANCE has been halted for one reason or another (busmaster memory
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   arbitration error, Tx FIFO underflow, driver stopped it to reconfigure,
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   etc.).  Modern LANCE variants always reload their ring-buffer
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   configuration when restarted, so we must reinitialize our ring
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   context before restarting.  As part of this reinitialization,
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   find all packets still on the Tx ring and pretend that they had been
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   sent (in effect, drop the packets on the floor) - the higher-level
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   protocols will time out and retransmit.  It'd be better to shuffle
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   these skbs to a temp list and then actually re-Tx them after
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   restarting the chip, but I'm too lazy to do so right now.  dplatt@3do.com
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8376aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzikstatic void
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslance_purge_ring(struct net_device *dev)
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
840c0103606b7e3db191dcbaf988f28fa26aa711230Wang Chen	struct lance_private *lp = dev->ml_priv;
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Free all the skbuffs in the Rx and Tx queues. */
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < RX_RING_SIZE; i++) {
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct sk_buff *skb = lp->rx_skbuff[i];
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->rx_skbuff[i] = NULL;
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->rx_ring[i].base = 0;		/* Not owned by LANCE chip. */
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (skb)
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_kfree_skb_any(skb);
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < TX_RING_SIZE; i++) {
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (lp->tx_skbuff[i]) {
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_kfree_skb_any(lp->tx_skbuff[i]);
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lp->tx_skbuff[i] = NULL;
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Initialize the LANCE Rx and Tx rings. */
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
8629e24974db6b01ec067c24de09588282b6a1407f0Al Virolance_init_ring(struct net_device *dev, gfp_t gfp)
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
864c0103606b7e3db191dcbaf988f28fa26aa711230Wang Chen	struct lance_private *lp = dev->ml_priv;
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->cur_rx = lp->cur_tx = 0;
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->dirty_rx = lp->dirty_tx = 0;
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < RX_RING_SIZE; i++) {
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct sk_buff *skb;
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		void *rx_buff;
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb = alloc_skb(PKT_BUF_SZ, GFP_DMA | gfp);
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->rx_skbuff[i] = skb;
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (skb) {
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			skb->dev = dev;
878689be43945e9ca7dd704522e55af1b8a73a994d3David S. Miller			rx_buff = skb->data;
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rx_buff = kmalloc(PKT_BUF_SZ, GFP_DMA | gfp);
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rx_buff == NULL)
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lp->rx_ring[i].base = 0;
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lp->rx_ring[i].base = (u32)isa_virt_to_bus(rx_buff) | 0x80000000;
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->rx_ring[i].buf_length = -PKT_BUF_SZ;
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* The Tx buffer address is filled in as needed, but we do need to clear
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   the upper ownership bit. */
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < TX_RING_SIZE; i++) {
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->tx_skbuff[i] = NULL;
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->tx_ring[i].base = 0;
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->init_block.mode = 0x0000;
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 6; i++)
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->init_block.phys_addr[i] = dev->dev_addr[i];
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->init_block.filter[0] = 0x00000000;
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->init_block.filter[1] = 0x00000000;
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->init_block.rx_ring = ((u32)isa_virt_to_bus(lp->rx_ring) & 0xffffff) | RX_RING_LEN_BITS;
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->init_block.tx_ring = ((u32)isa_virt_to_bus(lp->tx_ring) & 0xffffff) | TX_RING_LEN_BITS;
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslance_restart(struct net_device *dev, unsigned int csr0_bits, int must_reinit)
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
906c0103606b7e3db191dcbaf988f28fa26aa711230Wang Chen	struct lance_private *lp = dev->ml_priv;
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (must_reinit ||
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(chip_table[lp->chip_version].flags & LANCE_MUST_REINIT_RING)) {
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lance_purge_ring(dev);
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lance_init_ring(dev, GFP_ATOMIC);
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0x0000,    dev->base_addr + LANCE_ADDR);
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(csr0_bits, dev->base_addr + LANCE_DATA);
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lance_tx_timeout (struct net_device *dev)
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
920c0103606b7e3db191dcbaf988f28fa26aa711230Wang Chen	struct lance_private *lp = (struct lance_private *) dev->ml_priv;
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ioaddr = dev->base_addr;
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw (0, ioaddr + LANCE_ADDR);
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk ("%s: transmit timed out, status %4.4x, resetting.\n",
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->name, inw (ioaddr + LANCE_DATA));
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw (0x0004, ioaddr + LANCE_DATA);
9277bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy	dev->stats.tx_errors++;
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef final_version
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lance_debug > 3) {
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int i;
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk (" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.",
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  lp->dirty_tx, lp->cur_tx, netif_queue_stopped(dev) ? " (full)" : "",
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lp->cur_rx);
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < RX_RING_SIZE; i++)
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk ("%s %08x %04x %04x", i & 0x3 ? "" : "\n ",
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 lp->rx_ring[i].base, -lp->rx_ring[i].buf_length,
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lp->rx_ring[i].msg_length);
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < TX_RING_SIZE; i++)
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk ("%s %08x %04x %04x", i & 0x3 ? "" : "\n ",
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     lp->tx_ring[i].base, -lp->tx_ring[i].length,
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lp->tx_ring[i].misc);
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk ("\n");
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lance_restart (dev, 0x0043, 1);
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9471ae5dc342ac78d7a42965fd1f323815f6f5ef2c1Eric Dumazet	dev->trans_start = jiffies; /* prevent tx timeout */
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_wake_queue (dev);
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
95261357325f377889a1daffa14962d705dc814dd0eStephen Hemmingerstatic netdev_tx_t lance_start_xmit(struct sk_buff *skb,
95361357325f377889a1daffa14962d705dc814dd0eStephen Hemminger				    struct net_device *dev)
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
955c0103606b7e3db191dcbaf988f28fa26aa711230Wang Chen	struct lance_private *lp = dev->ml_priv;
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ioaddr = dev->base_addr;
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int entry;
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&lp->devlock, flags);
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lance_debug > 3) {
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outw(0x0000, ioaddr+LANCE_ADDR);
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("%s: lance_start_xmit() called, csr0 %4.4x.\n", dev->name,
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   inw(ioaddr+LANCE_DATA));
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outw(0x0000, ioaddr+LANCE_DATA);
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Fill in a Tx ring entry */
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Mask to ring buffer boundary. */
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	entry = lp->cur_tx & TX_RING_MOD_MASK;
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Caution: the write order is important here, set the base address
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   with the "ownership" bits last. */
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* The old LANCE chips doesn't automatically pad buffers to min. size. */
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (chip_table[lp->chip_version].flags & LANCE_MUST_PAD) {
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (skb->len < ETH_ZLEN) {
9805b057c6b1a25d57edf2b4d1e956e50936480a9ffHerbert Xu			if (skb_padto(skb, ETH_ZLEN))
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto out;
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lp->tx_ring[entry].length = -ETH_ZLEN;
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9846aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		else
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lp->tx_ring[entry].length = -skb->len;
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->tx_ring[entry].length = -skb->len;
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->tx_ring[entry].misc = 0x0000;
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9917bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy	dev->stats.tx_bytes += skb->len;
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* If any part of this buffer is >16M we must copy it to a low-memory
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   buffer. */
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((u32)isa_virt_to_bus(skb->data) + skb->len > 0x01000000) {
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (lance_debug > 5)
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("%s: bouncing a high-memory packet (%#x).\n",
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   dev->name, (u32)isa_virt_to_bus(skb->data));
999d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo		skb_copy_from_linear_data(skb, &lp->tx_bounce_buffs[entry], skb->len);
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->tx_ring[entry].base =
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			((u32)isa_virt_to_bus((lp->tx_bounce_buffs + entry)) & 0xffffff) | 0x83000000;
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_kfree_skb(skb);
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->tx_skbuff[entry] = skb;
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->tx_ring[entry].base = ((u32)isa_virt_to_bus(skb->data) & 0xffffff) | 0x83000000;
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lp->cur_tx++;
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Trigger an immediate send poll. */
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0x0000, ioaddr+LANCE_ADDR);
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0x0048, ioaddr+LANCE_DATA);
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((lp->cur_tx - lp->dirty_tx) >= TX_RING_SIZE)
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_stop_queue(dev);
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&lp->devlock, flags);
10186ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy	return NETDEV_TX_OK;
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The LANCE interrupt handler. */
10227d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t lance_interrupt(int irq, void *dev_id)
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = dev_id;
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lance_private *lp;
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int csr0, ioaddr, boguscnt=10;
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int must_restart;
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ioaddr = dev->base_addr;
1030c0103606b7e3db191dcbaf988f28fa26aa711230Wang Chen	lp = dev->ml_priv;
10316aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock (&lp->devlock);
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0x00, dev->base_addr + LANCE_ADDR);
10358e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches	while ((csr0 = inw(dev->base_addr + LANCE_DATA)) & 0x8600 &&
10368e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches	       --boguscnt >= 0) {
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Acknowledge all of the current interrupt sources ASAP. */
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outw(csr0 & ~0x004f, dev->base_addr + LANCE_DATA);
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		must_restart = 0;
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (lance_debug > 5)
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("%s: interrupt  csr0=%#2.2x new csr=%#2.2x.\n",
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   dev->name, csr0, inw(dev->base_addr + LANCE_DATA));
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (csr0 & 0x0400)			/* Rx interrupt */
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lance_rx(dev);
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (csr0 & 0x0200) {		/* Tx-done interrupt */
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int dirty_tx = lp->dirty_tx;
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			while (dirty_tx < lp->cur_tx) {
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				int entry = dirty_tx & TX_RING_MOD_MASK;
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				int status = lp->tx_ring[entry].base;
10556aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (status < 0)
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;			/* It still hasn't been Txed */
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				lp->tx_ring[entry].base = 0;
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (status & 0x40000000) {
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/* There was an major error, log it. */
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					int err_status = lp->tx_ring[entry].misc;
10647bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy					dev->stats.tx_errors++;
10657bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy					if (err_status & 0x0400)
10667bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy						dev->stats.tx_aborted_errors++;
10677bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy					if (err_status & 0x0800)
10687bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy						dev->stats.tx_carrier_errors++;
10697bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy					if (err_status & 0x1000)
10707bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy						dev->stats.tx_window_errors++;
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (err_status & 0x4000) {
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						/* Ackk!  On FIFO errors the Tx unit is turned off! */
10737bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy						dev->stats.tx_fifo_errors++;
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						/* Remove this verbosity later! */
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						printk("%s: Tx FIFO error! Status %4.4x.\n",
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							   dev->name, csr0);
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						/* Restart the chip. */
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						must_restart = 1;
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else {
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (status & 0x18000000)
10827bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy						dev->stats.collisions++;
10837bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy					dev->stats.tx_packets++;
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* We must free the original skb if it's not a data-only copy
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   in the bounce buffer. */
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (lp->tx_skbuff[entry]) {
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dev_kfree_skb_irq(lp->tx_skbuff[entry]);
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					lp->tx_skbuff[entry] = NULL;
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dirty_tx++;
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef final_version
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk("out-of-sync dirty pointer, %d vs. %d, full=%s.\n",
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					   dirty_tx, lp->cur_tx,
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					   netif_queue_stopped(dev) ? "yes" : "no");
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dirty_tx += TX_RING_SIZE;
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* if the ring is no longer full, accept more packets */
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (netif_queue_stopped(dev) &&
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    dirty_tx > lp->cur_tx - TX_RING_SIZE + 2)
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				netif_wake_queue (dev);
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lp->dirty_tx = dirty_tx;
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Log misc errors. */
11137bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy		if (csr0 & 0x4000)
11147bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy			dev->stats.tx_errors++; /* Tx babble. */
11157bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy		if (csr0 & 0x1000)
11167bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy			dev->stats.rx_errors++; /* Missed a Rx frame. */
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (csr0 & 0x0800) {
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("%s: Bus master arbitration failure, status %4.4x.\n",
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   dev->name, csr0);
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Restart the chip. */
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			must_restart = 1;
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (must_restart) {
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* stop the chip to clear the error condition, then restart */
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outw(0x0000, dev->base_addr + LANCE_ADDR);
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outw(0x0004, dev->base_addr + LANCE_DATA);
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lance_restart(dev, 0x0002, 0);
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Clear any other interrupt, and set interrupt enable. */
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0x0000, dev->base_addr + LANCE_ADDR);
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0x7940, dev->base_addr + LANCE_DATA);
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lance_debug > 4)
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("%s: exiting interrupt, csr%d=%#4.4x.\n",
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   dev->name, inw(ioaddr + LANCE_ADDR),
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   inw(dev->base_addr + LANCE_DATA));
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock (&lp->devlock);
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_HANDLED;
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslance_rx(struct net_device *dev)
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1148c0103606b7e3db191dcbaf988f28fa26aa711230Wang Chen	struct lance_private *lp = dev->ml_priv;
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int entry = lp->cur_rx & RX_RING_MOD_MASK;
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
11516aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* If we own the next entry, it's a new packet. Send it up. */
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (lp->rx_ring[entry].base >= 0) {
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int status = lp->rx_ring[entry].base >> 24;
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status != 0x03) {			/* There was an error. */
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* There is a tricky error noted by John Murphy,
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   <murf@perftech.com> to Russ Nelson: Even with full-sized
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   buffers it's possible for a jabber packet to use two
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   buffers, with only the last correctly noting the error. */
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (status & 0x01)	/* Only count a general error at the */
11627bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy				dev->stats.rx_errors++; /* end of a packet.*/
11637bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy			if (status & 0x20)
11647bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy				dev->stats.rx_frame_errors++;
11657bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy			if (status & 0x10)
11667bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy				dev->stats.rx_over_errors++;
11677bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy			if (status & 0x08)
11687bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy				dev->stats.rx_crc_errors++;
11697bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy			if (status & 0x04)
11707bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy				dev->stats.rx_fifo_errors++;
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			lp->rx_ring[entry].base &= 0x03ffffff;
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11736aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik		else
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Malloc up new buffer, compatible with net3. */
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			short pkt_len = (lp->rx_ring[entry].msg_length & 0xfff)-4;
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct sk_buff *skb;
11786aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(pkt_len<60)
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			{
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk("%s: Runt packet!\n",dev->name);
11827bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy				dev->stats.rx_errors++;
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			{
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb = dev_alloc_skb(pkt_len+2);
11876aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik				if (skb == NULL)
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				{
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk("%s: Memory squeeze, deferring packet.\n", dev->name);
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					for (i=0; i < RX_RING_SIZE; i++)
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].base < 0)
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							break;
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11946aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik					if (i > RX_RING_SIZE -2)
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					{
11967bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy						dev->stats.rx_dropped++;
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						lp->rx_ring[entry].base |= 0x80000000;
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						lp->cur_rx++;
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb_reserve(skb,2);	/* 16 byte align */
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb_put(skb,pkt_len);	/* Make room */
12048c7b7faaa630fef7f68d8728cee1cce398cc9697David S. Miller				skb_copy_to_linear_data(skb,
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					(unsigned char *)isa_bus_to_virt((lp->rx_ring[entry].base & 0x00ffffff)),
12068c7b7faaa630fef7f68d8728cee1cce398cc9697David S. Miller					pkt_len);
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				skb->protocol=eth_type_trans(skb,dev);
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				netif_rx(skb);
12097bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy				dev->stats.rx_packets++;
12107bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy				dev->stats.rx_bytes += pkt_len;
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* The docs say that the buffer length isn't touched, but Andrew Boyd
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   of QNX reports that some revs of the 79C965 clear it. */
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->rx_ring[entry].buf_length = -PKT_BUF_SZ;
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		lp->rx_ring[entry].base |= 0x80000000;
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		entry = (++lp->cur_rx) & RX_RING_MOD_MASK;
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We should check that at least two ring entries are free.	 If not,
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   we should free one and mark stats->rx_dropped++. */
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldslance_close(struct net_device *dev)
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ioaddr = dev->base_addr;
1230c0103606b7e3db191dcbaf988f28fa26aa711230Wang Chen	struct lance_private *lp = dev->ml_priv;
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_stop_queue (dev);
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (chip_table[lp->chip_version].flags & LANCE_HAS_MISSED_FRAME) {
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outw(112, ioaddr+LANCE_ADDR);
12367bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy		dev->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA);
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0, ioaddr+LANCE_ADDR);
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lance_debug > 1)
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("%s: Shutting down ethercard, status was %2.2x.\n",
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   dev->name, inw(ioaddr+LANCE_DATA));
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We stop the LANCE here -- it occasionally polls
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   memory if we don't. */
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0x0004, ioaddr+LANCE_DATA);
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->dma != 4)
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned long flags=claim_dma_lock();
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		disable_dma(dev->dma);
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		release_dma_lock(flags);
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_irq(dev->irq, dev);
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lance_purge_ring(dev);
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device_stats *lance_get_stats(struct net_device *dev)
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1263c0103606b7e3db191dcbaf988f28fa26aa711230Wang Chen	struct lance_private *lp = dev->ml_priv;
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (chip_table[lp->chip_version].flags & LANCE_HAS_MISSED_FRAME) {
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		short ioaddr = dev->base_addr;
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		short saved_addr;
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned long flags;
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock_irqsave(&lp->devlock, flags);
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		saved_addr = inw(ioaddr+LANCE_ADDR);
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outw(112, ioaddr+LANCE_ADDR);
12737bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy		dev->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA);
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outw(saved_addr, ioaddr+LANCE_ADDR);
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&lp->devlock, flags);
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12787bfba0b0c15962265950ac0efe6bd4f42414db6dKulikov Vasiliy	return &dev->stats;
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Set or clear the multicast filter for this adaptor.
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void set_multicast_list(struct net_device *dev)
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	short ioaddr = dev->base_addr;
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0, ioaddr+LANCE_ADDR);
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outw(0x0004, ioaddr+LANCE_DATA); /* Temporarily stop the lance.	 */
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->flags&IFF_PROMISC) {
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outw(15, ioaddr+LANCE_ADDR);
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outw(0x8000, ioaddr+LANCE_DATA); /* Set promiscuous mode */
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		short multicast_table[4];
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int i;
12974cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko		int num_addrs=netdev_mc_count(dev);
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(dev->flags&IFF_ALLMULTI)
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			num_addrs=1;
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FIXIT: We don't use the multicast table, but rely on upper-layer filtering. */
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memset(multicast_table, (num_addrs == 0) ? 0 : -1, sizeof(multicast_table));
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < 4; i++) {
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outw(8 + i, ioaddr+LANCE_ADDR);
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outw(multicast_table[i], ioaddr+LANCE_DATA);
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outw(15, ioaddr+LANCE_ADDR);
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outw(0x0000, ioaddr+LANCE_DATA); /* Unset promiscuous mode */
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lance_restart(dev, 0x0142, 0); /*  Resume normal operation */
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1314