patch-2.3.99-pre6 linux/drivers/net/3c59x.c

Next file: linux/drivers/net/8139too.c
Previous file: linux/drivers/net/3c515.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c
@@ -1,6 +1,6 @@
-/* 3c59x.c: A 3Com EtherLink PCI III/XL ethernet driver for linux. */
+/* EtherLinkXL.c: A 3Com EtherLink PCI III/XL ethernet driver for linux. */
 /*
-	Written 1996-1998 by Donald Becker.
+	Written 1996-1999 by Donald Becker.
 
 	This software may be used and distributed according to the terms
 	of the GNU Public License, incorporated herein by reference.
@@ -13,14 +13,51 @@
 	Center of Excellence in Space Data and Information Sciences
 	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
 
- Version history:
- 	0.99H+lk0.9 - David S. Miller - softnet, PCI DMA updates
- 	0.99H+lk1.0 - Jeff Garzik <jgarzik@mandrakesoft.com>
-		Remove compatibility defines for kernel versions < 2.2.x.
-		Update for new 2.3.x module interface
-		
+	Linux Kernel Additions:
+	
+	LK1.1.2 (March 19, 2000)
+	* New PCI interface (jgarzik)
+
+*/
+
+/*
+    22Apr00, Andrew Morton <andrewm@uow.edu.au>
+    - Merged with 3c575_cb.c
+    - Don't set RxComplete in boomerang interrupt enable reg
+    - spinlock in vortex_timer to protect mdio functions
+    - disable local interrupts around call to vortex_interrupt in
+      vortex_tx_timeout() (So vortex_interrupt can use spin_lock())
+    - Select window 3 in vortex_timer()'s write to Wn3_MAC_Ctrl
+    - In vortex_start_xmit(), move the lock to _after_ we've altered
+      vp->cur_tx and vp->tx_full.  This defeats the race between
+      vortex_start_xmit() and vortex_interrupt which was identified
+      by Bogdan Costescu.
+    - Merged back support for six new cards from various sources
+    - Set vortex_have_pci if pci_module_init returns zero (fixes cardbus
+      insertion oops)
+    - Tell it that 3c905C has NWAY for 100bT autoneg
+    - Fix handling of SetStatusEnd in 'Too much work..' code, as
+      per 2.3.99's 3c575_cb (Dave Hinds).
+    - Split ISR into two for vortex & boomerang
+    - Fix MOD_INC/DEC races
+    - Handle resource allocation failures.
+    - Fix 3CCFE575CT LED polarity
+    - Make tx_interrupt_mitigation the default
+    - Add extra TxReset to vortex_up() to fix 575_cb hotplug initialisation probs.
+    - See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3 for more details.
+*/
+
+/*
+ * FIXME: This driver _could_ support MTU changing, but doesn't.  See Don's hamaci.c implementation
+ * as well as other drivers
+ *
+ * NOTE: If you make 'vortex_debug' a constant (#define vortex_debug 0) the driver shrinks by 2k
+ * due to dead code elimination.  There will be some performance benefits from this due to
+ * elimination of all the tests and reduced cache footprint.
  */
 
+static char *version =
+"3c59x.c:v0.99L+LK1.1.2+AKPM  24 Apr 2000  Donald Becker and others  http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
 
 /* "Knobs" that adjust features and parameters. */
 /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
@@ -29,7 +66,13 @@
 /* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */
 static const int mtu = 1500;
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
+static int max_interrupt_work = 32;
+
+/* Allow aggregation of Tx interrupts.  Saves CPU load at the cost
+ * of possible Tx stalls if the system is blocking interrupts
+ * somewhere else.  Undefine this to disable.
+ */
+#define tx_interrupt_mitigation 1
 
 /* Put out somewhat more debugging messages. (0: no msg, 1 minimal .. 6). */
 #define vortex_debug debug
@@ -52,8 +95,12 @@
 #define RX_RING_SIZE	32
 #define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
 
-#include <linux/config.h>
-#include <linux/version.h>
+#ifndef __OPTIMIZE__
+#warning  You must compile this file with the correct options!
+#warning  See the last lines of the source file.
+#error You must compile this driver with "-O".
+#endif
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -61,11 +108,11 @@
 #include <linux/timer.h>
 #include <linux/errno.h>
 #include <linux/in.h>
-#include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/malloc.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
+#include <linux/init.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
@@ -80,14 +127,8 @@
 
 #include <linux/delay.h>
 
-#define PCI_SUPPORT_VER2
-#define DEV_FREE_SKB(skb) dev_kfree_skb(skb);
-
-static char *version __initdata =
-"3c59x.c:v0.99H+lk1.0 Feb 9, 2000 The Linux Kernel Team http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
-
 MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver");
+MODULE_DESCRIPTION("3Com 3c59x/3c90x/3c575 series Vortex/Boomerang/Cyclone driver");
 MODULE_PARM(debug, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
@@ -111,6 +152,10 @@
    code size of a per-interface flag is not worthwhile. */
 static char mii_preamble_required = 0;
 
+#define PFX "3c59x: "
+
+
+
 /*
 				Theory of Operation
 
@@ -168,7 +213,6 @@
 passing the full-sized skbuff to the queue layer for all frames vs. the
 copying cost of copying a frame to a correctly-sized skbuff.
 
-
 IIIC. Synchronization
 The driver runs as two independent, single-threaded flows of control.  One
 is the send-packet routine, which enforces single-threaded use by the
@@ -195,68 +239,163 @@
 	PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
 	PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
 };
-struct pci_id_info {
+
+enum {	IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4,
+	EEPROM_230=8,	/* AKPM: Uses 0x230 as the base bitmpas for EEPROM reads */
+	HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, };
+
+
+enum vortex_chips {
+	CH_3C590 = 0,
+	CH_3C592,
+	CH_3C597,
+	CH_3C595_1,
+	CH_3C595_2,
+
+	CH_3C595_3,
+	CH_VORTEX,
+	CH_3C900_1,
+	CH_3C900_2,
+	CH_3C900_3,
+
+	CH_3C900_4,
+	CH_3C900_5,
+	CH_3C900B_FL,
+	CH_3C905_1,
+	CH_3C905_2,
+
+	CH_3C905B_1,
+	CH_3C905B_2,
+	CH_3C905B_FX,
+	CH_3C905C,
+	CH_3C980,
+
+	CH_3CSOHO100_TX,
+	CH_3C555,
+	CH_3C575_1,
+	CH_3CCFE575,
+	CH_3CCFE575CT,
+
+	CH_3CCFE656,
+	CH_3CCFEM656,
+	CH_3C450,
+};
+
+
+/* note: this array directly indexed by above enums, and MUST
+ * be kept in sync with both the enums above, and the PCI device
+ * table below
+ */
+static struct vortex_chip_info {
 	const char *name;
-	u16	vendor_id, device_id, device_id_mask, flags;
-	int drv_flags, io_size;
-	struct net_device *(*probe1)(struct pci_dev *pdev, long ioaddr, int irq, int chip_idx, int fnd_cnt);
-};
-
-enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4,
-	   HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, };
-static struct net_device *vortex_probe1(struct pci_dev *pdev, long ioaddr, int irq, int dev_id, int card_idx);
-
-static struct pci_id_info pci_tbl[] = {
-	{"3c590 Vortex 10Mbps",			0x10B7, 0x5900, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
-	{"3c595 Vortex 100baseTx",		0x10B7, 0x5950, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
-	{"3c595 Vortex 100baseT4",		0x10B7, 0x5951, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
-	{"3c595 Vortex 100base-MII",	0x10B7, 0x5952, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
-	{"3Com Vortex",					0x10B7, 0x5900, 0xff00,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
-	{"3c900 Boomerang 10baseT",		0x10B7, 0x9000, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
-	{"3c900 Boomerang 10Mbps Combo", 0x10B7, 0x9001, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
-	{"3c900 Cyclone 10Mbps Combo", 0x10B7, 0x9005, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
-	{"3c900B-FL Cyclone 10base-FL",	0x10B7, 0x900A, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
-	{"3c905 Boomerang 100baseTx",	0x10B7, 0x9050, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
-	{"3c905 Boomerang 100baseT4",	0x10B7, 0x9051, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
-	{"3c905B Cyclone 100baseTx",	0x10B7, 0x9055, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1},
-	{"3c905B Cyclone 10/100/BNC",	0x10B7, 0x9058, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1},
-	{"3c905B-FX Cyclone 100baseFx",	0x10B7, 0x905A, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
-	{"3c905C Tornado",	0x10B7, 0x9200, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
-	{"3c980 Cyclone",	0x10B7, 0x9800, 0xfff0,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
-	{"3cSOHO100-TX Hurricane",	0x10B7, 0x7646, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
-	{"3c555 Laptop Hurricane",	0x10B7, 0x5055, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
-	{"3c575 Boomerang CardBus",		0x10B7, 0x5057, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
-	{"3CCFE575 Cyclone CardBus",	0x10B7, 0x5157, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS,
-	 128, vortex_probe1},
-	{"3CCFE656 Cyclone CardBus",	0x10B7, 0x6560, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS,
-	 128, vortex_probe1},
-	{"3c575 series CardBus (unknown version)", 0x10B7, 0x5057, 0xf0ff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
-	{"3Com Boomerang (unknown version)",	0x10B7, 0x9000, 0xff00,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
+	int flags;
+	int drv_flags;
+	int io_size;
+} vortex_info_tbl[] = {
+	{"3c590 Vortex 10Mbps",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+	{"3c592 EISA 10mbps Demon/Vortex",					/* AKPM: from Don's 3c59x_cb.c 0.49H */
+	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+	{"3c597 EISA Fast Demon/Vortex",					/* AKPM: from Don's 3c59x_cb.c 0.49H */
+	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+	{"3c595 Vortex 100baseTx",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+	{"3c595 Vortex 100baseT4",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+
+	{"3c595 Vortex 100base-MII",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+#define EISA_TBL_OFFSET	6		/* Offset of this entry for vortex_eisa_init */
+	{"3Com Vortex",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, },
+	{"3c900 Boomerang 10baseT",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, },
+	{"3c900 Boomerang 10Mbps Combo",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, },
+	{"3c900 Cyclone 10Mbps TPO",						/* AKPM: from Don's 0.99M */
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+
+	{"3c900 Cyclone 10Mbps Combo",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+	{"3c900 Cyclone 10Mbps TPC",						/* AKPM: from Don's 0.99M */
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+	{"3c900B-FL Cyclone 10base-FL",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+	{"3c905 Boomerang 100baseTx",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, },
+	{"3c905 Boomerang 100baseT4",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, },
+
+	{"3c905B Cyclone 100baseTx",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, },
+	{"3c905B Cyclone 10/100/BNC",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, },
+	{"3c905B-FX Cyclone 100baseFx",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+	{"3c905C Tornado",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, },
+	{"3c980 Cyclone",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+
+	{"3cSOHO100-TX Hurricane",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+	{"3c555 Laptop Hurricane",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+	{"3c575 Boomerang CardBus",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_230, 64, },
+	{"3CCFE575 Cyclone CardBus",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, },
+	{"3CCFE575CT Cyclone CardBus",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, },
+
+	{"3CCFE656 Cyclone CardBus",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, },
+	{"3CCFEM656 Cyclone CardBus",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, },
+	{"3c450 Cyclone/unknown",						/* AKPM: from Don's 0.99N */
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, },
+	{0,}, /* 0 terminated list. */
+};
+
+
+static struct pci_device_id vortex_pci_tbl[] __devinitdata = {
+	{ 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C590 },
+	{ 0x10B7, 0x5920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C592 },
+	{ 0x10B7, 0x5970, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C597 },
+	{ 0x10B7, 0x5950, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_1 },
+	{ 0x10B7, 0x5951, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_2 },
+
+	{ 0x10B7, 0x5952, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_3 },
+	{ 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VORTEX },
+	{ 0x10B7, 0x9000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_1 },
+	{ 0x10B7, 0x9001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_2 },
+	{ 0x10B7, 0x9004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_3 },
+
+	{ 0x10B7, 0x9005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_4 },
+	{ 0x10B7, 0x9006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_5 },
+	{ 0x10B7, 0x900A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900B_FL },
+	{ 0x10B7, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_1 },
+	{ 0x10B7, 0x9051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_2 },
+
+	{ 0x10B7, 0x9055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_1 },
+	{ 0x10B7, 0x9058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_2 },
+	{ 0x10B7, 0x905A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_FX },
+	{ 0x10B7, 0x9200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905C },
+	{ 0x10B7, 0x9800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C980 },
+
+	{ 0x10B7, 0x7646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CSOHO100_TX },
+	{ 0x10B7, 0x5055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C555 },
+	{ 0x10B7, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575_1 },
+	{ 0x10B7, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575 },
+	{ 0x10B7, 0x5257, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575CT },
+
+	{ 0x10B7, 0x6560, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE656 },
+	{ 0x10B7, 0x6562, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656 },
+	{ 0x10B7, 0x4500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C450 },
 	{0,},						/* 0 terminated list. */
 };
+MODULE_DEVICE_TABLE(pci, vortex_pci_tbl);
+
 
 /* Operational definitions.
    These are not used by other compilation units and thus are not
@@ -392,7 +531,7 @@
 };
 
 /* Chip features we care about in vp->capabilities, read from the EEPROM. */
-enum ChipCaps { CapBusMaster=0x20 };
+enum ChipCaps { CapBusMaster=0x20, CapPwrMgmt=0x2000 };
 
 struct vortex_private {
 	/* The Rx and Tx rings should be quad-word-aligned. */
@@ -403,36 +542,38 @@
 	/* The addresses of transmit- and receive-in-place skbuffs. */
 	struct sk_buff* rx_skbuff[RX_RING_SIZE];
 	struct sk_buff* tx_skbuff[TX_RING_SIZE];
-	struct net_device *next_module;
+	struct net_device *next_module;		/* NULL if PCI device */
 	unsigned int cur_rx, cur_tx;		/* The next free ring entry */
 	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
 	struct net_device_stats stats;
-	struct sk_buff *tx_skb;		/* Packet being eaten by bus master ctrl.  */
-	dma_addr_t tx_skb_dma;	/* Allocated DMA address for bus master ctrl DMA.   */
+	struct sk_buff *tx_skb;				/* Packet being eaten by bus master ctrl.  */
+	dma_addr_t tx_skb_dma;				/* Allocated DMA address for bus master ctrl DMA.   */
 
 	/* PCI configuration space information. */
-	u8 pci_bus, pci_devfn;		/* PCI bus location, for power management. */
+	struct pci_dev *pdev;
 	char *cb_fn_base;			/* CardBus function status addr space. */
 	int chip_id;
-	struct pci_dev *pdev;			/* Device for DMA mapping */
 
 	/* The remainder are related to chip state, mostly media selection. */
-	unsigned long in_interrupt;
-	struct timer_list timer;	/* Media selection timer. */
-	int options;				/* User-settable misc. driver options. */
-	unsigned int media_override:3, 			/* Passed-in media type. */
+	struct timer_list timer;			/* Media selection timer. */
+	int options;						/* User-settable misc. driver options. */
+	unsigned int media_override:4, 		/* Passed-in media type. */
 		default_media:4,				/* Read from the EEPROM/Wn3_Config. */
 		full_duplex:1, force_fd:1, autoselect:1,
-		bus_master:1,				/* Vortex can only do a fragment bus-m. */
+		bus_master:1,					/* Vortex can only do a fragment bus-m. */
 		full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang  */
-		hw_csums:1,				/* Has hardware checksums. */
-		tx_full:1;
+		hw_csums:1,						/* Has hardware checksums. */
+		tx_full:1,
+		open:1;
 	u16 status_enable;
 	u16 intr_enable;
 	u16 available_media;				/* From Wn3_Options. */
 	u16 capabilities, info1, info2;		/* Various, from EEPROM. */
 	u16 advertising;					/* NWay media advertisement */
 	unsigned char phys[2];				/* MII device addresses. */
+	u16 deferred;						/* Resend these interrupts when we
+										 * bale from the ISR */
+	spinlock_t lock;
 };
 
 /* The action to take with a media selection timer tick.
@@ -446,9 +587,9 @@
 static struct media_table {
 	char *name;
 	unsigned int media_bits:16,		/* Bits to set in Wn4_Media register. */
-		mask:8,				/* The transceiver-present bit in Wn3_Config.*/
-		next:8;				/* The media type to try next. */
-	int wait;			/* Time before we check media status. */
+		mask:8,						/* The transceiver-present bit in Wn3_Config.*/
+		next:8;						/* The media type to try next. */
+	int wait;						/* Time before we check media status. */
 } media_tbl[] = {
   {	"10baseT",   Media_10TP,0x08, XCVR_10base2, (14*HZ)/10},
   { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1*HZ)/10},
@@ -463,329 +604,245 @@
   { "Default",	 0,			0xFF, XCVR_10baseT, 10000},
 };
 
-#ifndef CARDBUS
-static int vortex_scan(struct pci_id_info pci_tbl[]);
-#endif
+static int vortex_probe1(struct pci_dev *pdev, long ioaddr, int irq,
+				   int chip_idx, int card_idx);
+static void vortex_up(struct net_device *dev);
+static void vortex_down(struct net_device *dev);
 static int vortex_open(struct net_device *dev);
 static void mdio_sync(long ioaddr, int bits);
 static int mdio_read(long ioaddr, int phy_id, int location);
 static void mdio_write(long ioaddr, int phy_id, int location, int value);
 static void vortex_timer(unsigned long arg);
 static int vortex_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static void vortex_tx_timeout(struct net_device *dev);
 static int boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static int vortex_rx(struct net_device *dev);
 static int boomerang_rx(struct net_device *dev);
 static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static int vortex_close(struct net_device *dev);
 static void update_stats(long ioaddr, struct net_device *dev);
 static struct net_device_stats *vortex_get_stats(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
 static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static void vortex_tx_timeout(struct net_device *dev);
+static void acpi_set_WOL(struct net_device *dev);
 
-
 /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
 /* Option count limit only -- unlimited interfaces are supported. */
 #define MAX_UNITS 8
 static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1,};
 static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-/* A list of all installed Vortex devices, for removing the driver module. */
-static struct net_device *root_vortex_dev = NULL;
 
-#ifndef CARDBUS
+
+/* A list of all installed Vortex EISA devices, for removing the driver module. */
+static struct net_device *root_vortex_eisa_dev = NULL;
+
 /* Variables to work-around the Compaq PCI BIOS32 problem. */
 static int compaq_ioaddr = 0, compaq_irq = 0, compaq_device_id = 0x5900;
-#endif
 
-#ifdef CARDBUS
+static int vortex_cards_found = 0;
 
-#include <pcmcia/driver_ops.h>
-
-static dev_node_t *vortex_attach(dev_locator_t *loc)
+static void vortex_suspend (struct pci_dev *pdev)
 {
-	u16 dev_id, vendor_id;
-	u32 io;
-	u8 irq;
-	struct net_device *dev;
-	struct pci_dev *pdev;
-	int chip_idx;
+	struct net_device *dev = pdev->driver_data;
 
-	if (loc->bus != LOC_PCI) return NULL;
-	pdev = pci_find_slot (loc->b.pci.bus, loc->b.pci.devfn);
-	if (!pdev) return NULL;
-	io = pdev->resource[0].start;
-	irq = pdev->irq;
-	vendor_id = pdev->vendor;
-	dev_id = pdev->device;
-	printk(KERN_INFO "vortex_attach(bus %d, function %d, device %4.4x)\n",
-		   pdev->bus->number, pdev->devfn, dev_id);
-	io &= ~3;
-	if (io == 0 || irq == 0) {
-		printk(KERN_ERR "The 3Com CardBus Ethernet interface was not "
-			   "assigned an %s.\n" KERN_ERR "  It will not be activated.\n",
-			   io == 0 ? "I/O address" : "IRQ");
-		return NULL;
-	}
-	for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
-		if (vendor_id == pci_tbl[chip_idx].vendor_id
-			&& (dev_id & pci_tbl[chip_idx].device_id_mask) ==
-			pci_tbl[chip_idx].device_id)
-			break;
-	if (pci_tbl[chip_idx].vendor_id == 0) { 		/* Compiled out! */
-		printk(KERN_INFO "Unable to match chip type %4.4x %4.4x in "
-			   "vortex_attach().\n", vendor_id, dev_id);
-		return NULL;
-	}
-	dev = vortex_probe1(pdev, io, irq, chip_idx, MAX_UNITS+1);
-	if (dev) {
-		dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
-		strcpy(node->dev_name, dev->name);
-		node->major = node->minor = 0;
-		node->next = NULL;
-		MOD_INC_USE_COUNT;
-		return node;
-	}
-	return NULL;
-}
+	printk(KERN_DEBUG "vortex_suspend(%s)\n", dev->name);
 
-static void vortex_detach(dev_node_t *node)
-{
-	struct net_device **devp, **next;
-	printk(KERN_INFO "vortex_detach(%s)\n", node->dev_name);
-	for (devp = &root_vortex_dev; *devp; devp = next) {
-		next = &((struct vortex_private *)(*devp)->priv)->next_module;
-		if (strcmp((*devp)->name, node->dev_name) == 0) break;
-	}
-	if (*devp) {
-		struct net_device *dev = *devp;
-		struct vortex_private *vp = dev->priv;
-		if (dev->flags & IFF_UP)
-			vortex_close(dev);
-		dev->flags &= ~(IFF_UP|IFF_RUNNING);
-		unregister_netdev(dev);
-		if (vp->cb_fn_base) iounmap(vp->cb_fn_base);
-		kfree(dev);
-		*devp = *next;
-		kfree(vp);
-		kfree(node);
-		MOD_DEC_USE_COUNT;
+	if (dev && dev->priv) {
+		struct vortex_private *vp = (struct vortex_private *)dev->priv;
+		if (vp->open) {
+			netif_device_detach(dev);
+			vortex_down(dev);
+		}
 	}
 }
 
-struct driver_operations vortex_ops = {
-	"3c575_cb", vortex_attach, NULL, NULL, vortex_detach
-};
-
-#endif  /* Cardbus support */
+static void vortex_resume (struct pci_dev *pdev)
+{
+	struct net_device *dev = pdev->driver_data;
 
+	printk(KERN_DEBUG "vortex_resume(%s)\n", dev->name);
 
-static int __init vortex_init_module (void)
-{
-	if (vortex_debug)
-		printk(KERN_INFO "%s", version);
-#ifdef CARDBUS
-	register_driver(&vortex_ops);
-	return 0;
-#else
-	return vortex_scan(pci_tbl);
-#endif
+	if (dev && dev->priv) {
+		struct vortex_private *vp = (struct vortex_private *)dev->priv;
+		if (vp->open) {
+			vortex_up(dev);
+			netif_device_attach(dev);
+		}
+	}
 }
 
-#ifndef CARDBUS
-static int vortex_scan(struct pci_id_info pci_tbl[])
+/* returns count found (>= 0), or negative on error */
+static int __init vortex_eisa_init (void)
 {
-	int cards_found = 0;
-	struct net_device *dev;
-
-	/* Allow an EISA-only driver. */
-#if defined(CONFIG_PCI) || (defined(MODULE) && !defined(NO_PCI))
-	/* Ideally we would detect all cards in slot order.  That would
-	   be best done a central PCI probe dispatch, which wouldn't work
-	   well with the current structure.  So instead we detect 3Com cards
-	   in slot order. */
-	if (pci_present()) {
-		static int pci_index = 0;
-		unsigned char pci_bus, pci_device_fn;
-
-		for (;pci_index < 0xff; pci_index++) {
-			u16 vendor, device, pci_command, new_command, pwr_cmd;
-			int chip_idx, irq;
-			long ioaddr;
-			struct pci_dev *pdev;
-
-			if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index,
-									&pci_bus, &pci_device_fn)
-				!= PCIBIOS_SUCCESSFUL)
-				break;
-			pdev = pci_find_slot (pci_bus, pci_device_fn);
-			if (!pdev) continue;
-			vendor = pdev->vendor;
-			device = pdev->device;
-			for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
-				if (vendor == pci_tbl[chip_idx].vendor_id
-					&& (device & pci_tbl[chip_idx].device_id_mask) ==
-					pci_tbl[chip_idx].device_id)
-					break;
-			if (pci_tbl[chip_idx].vendor_id == 0) 		/* Compiled out! */
-				continue;
-
-			{
-				struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
-				ioaddr = pdev->resource[0].start;
-				irq = pdev->irq;
-			}
-
-			/* Power-up the card. */
-			pci_read_config_word(pdev, 0xe0, &pwr_cmd);
-			
-			if (pwr_cmd & 0x3) {
-				/* Save the ioaddr and IRQ info! */
-				printk(KERN_INFO "  A 3Com network adapter is powered down!"
-					   "  Setting the power state %4.4x->%4.4x.\n",
-					   pwr_cmd, pwr_cmd & ~3);
-				pci_write_config_word(pdev, 0xe0, pwr_cmd & ~3);
-				printk(KERN_INFO "  Setting the IRQ to %d, IOADDR to %#lx.\n",
-					   irq, ioaddr);
-				pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
-				pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, ioaddr);
-			}
-
-			if (ioaddr == 0) {
-				printk(KERN_WARNING "  A 3Com network adapter has been found, "
-					   "however it has not been assigned an I/O address.\n"
-					   "  You may need to power-cycle the machine for this "
-					   "device to work!\n");
-				continue;
-			}
-
-			if (check_region(ioaddr, pci_tbl[chip_idx].io_size))
-				continue;
-
-			/* Activate the card. */
-			pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
+	long ioaddr;
+	int rc;
+	int orig_cards_found = vortex_cards_found;
 
-			new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
-			if (pci_command != new_command) {
-				printk(KERN_INFO "  The PCI BIOS has not enabled the device "
-					   "at %d/%d. Updating PCI command %4.4x->%4.4x.\n",
-					   pci_bus, pci_device_fn, pci_command, new_command);
-				pci_write_config_word(pdev, PCI_COMMAND, new_command);
-			}
+	/* Now check all slots of the EISA bus. */
+	if (!EISA_bus)
+		return 0;
 
-			dev = vortex_probe1(pdev, ioaddr, irq,
-					    chip_idx, cards_found);
+	for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
+		int device_id;
 
-			if (dev) {
-				/* Get and check the latency values.  On the 3c590 series
-				   the latency timer must be set to the maximum value to avoid
-				   data corruption that occurs when the timer expires during
-				   a transfer -- a bug in the Vortex chip only. */
-				u8 pci_latency;
-				u8 new_latency = (device & 0xff00) == 0x5900 ? 248 : 32;
-				
-				pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
-				if (pci_latency < new_latency) {
-					printk(KERN_INFO "%s: Overriding PCI latency"
-						   " timer (CFLT) setting of %d, new value is %d.\n",
-						   dev->name, pci_latency, new_latency);
-					pci_write_config_byte(pdev, PCI_LATENCY_TIMER, new_latency);
-				}
-				dev = 0;
-				cards_found++;
-			}
-		}
-	}
-#endif /* NO_PCI */
+		if (request_region(ioaddr, VORTEX_TOTAL_SIZE, "vortex") == NULL)
+			continue;
 
-	/* Now check all slots of the EISA bus. */
-	if (EISA_bus) {
-		static long ioaddr = 0x1000;
-		for ( ; ioaddr < 0x9000; ioaddr += 0x1000) {
-			int device_id;
-			if (check_region(ioaddr, VORTEX_TOTAL_SIZE))
-				continue;
-			/* Check the standard EISA ID register for an encoded '3Com'. */
-			if (inw(ioaddr + 0xC80) != 0x6d50)
-				continue;
-			/* Check for a product that we support, 3c59{2,7} any rev. */
-			device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83);
-			if ((device_id & 0xFF00) != 0x5900)
-				continue;
-			vortex_probe1(NULL, ioaddr, inw(ioaddr + 0xC88) >> 12,
-				      4, cards_found);
-			cards_found++;
-		}
+		/* Check the standard EISA ID register for an encoded '3Com'. */
+		if (inw(ioaddr + 0xC80) != 0x6d50) {
+			release_region (ioaddr, VORTEX_TOTAL_SIZE);
+			continue;
+		}
+
+		/* Check for a product that we support, 3c59{2,7} any rev. */
+		device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83);
+		if ((device_id & 0xFF00) != 0x5900) {
+			release_region (ioaddr, VORTEX_TOTAL_SIZE);
+			continue;
+		}
+
+		rc = vortex_probe1(NULL, ioaddr, inw(ioaddr + 0xC88) >> 12,
+				   EISA_TBL_OFFSET,
+				   vortex_cards_found);
+		if (rc == 0)
+			vortex_cards_found++;
+		else
+			release_region (ioaddr, VORTEX_TOTAL_SIZE);
 	}
 
 	/* Special code to work-around the Compaq PCI BIOS32 problem. */
 	if (compaq_ioaddr) {
 		vortex_probe1(NULL, compaq_ioaddr, compaq_irq,
-					  compaq_device_id, cards_found++);
-		dev = 0;
+					  compaq_device_id, vortex_cards_found++);
 	}
 
-	return cards_found ? 0 : -ENODEV;
+	return vortex_cards_found - orig_cards_found;
+}
+
+
+/* returns count (>= 0), or negative on error */
+static int __devinit vortex_init_one (struct pci_dev *pdev,
+				      const struct pci_device_id *ent)
+{
+	int rc;
+
+	rc = vortex_probe1 (pdev, pci_resource_start (pdev, 0), pdev->irq,
+			    ent->driver_data, vortex_cards_found);
+	if (rc == 0)
+		vortex_cards_found++;
+	return rc;
 }
-#endif  /* ! Cardbus */
 
 /*
- * vortex_probe1 - initialize one vortex board, after probing
- *		   has located one during bus scan.
+ * Start up the PCI device which is described by *pdev.
+ * Return 0 on success.
  *
- * NOTE: pdev==NULL is a valid condition, indicating
- * non-PCI (generally EISA) bus device
+ * NOTE: pdev can be NULL, for the case of an EISA driver
  */
-static struct net_device *vortex_probe1(struct pci_dev *pdev,
-					long ioaddr, int irq,
-					int chip_idx, int card_idx)
+static int __devinit vortex_probe1(struct pci_dev *pdev,
+				   long ioaddr, int irq,
+				   int chip_idx, int card_idx)
 {
 	struct vortex_private *vp;
 	int option;
 	unsigned int eeprom[0x40], checksum = 0;		/* EEPROM contents */
 	int i;
 	struct net_device *dev;
+	static int printed_version = 0;
+	int retval;
 
-	dev = init_etherdev(NULL, 0);
+	if (!printed_version) {
+		printk (KERN_INFO "%s", version);
+		printed_version = 1;
+	}
 
-	printk(KERN_INFO "%s: 3Com %s at 0x%lx, ",
-		   dev->name, pci_tbl[chip_idx].name, ioaddr);
+	dev = init_etherdev(NULL, sizeof(*vp));
+	if (!dev) {
+		printk (KERN_ERR PFX "unable to allocate etherdev, aborting\n");
+		retval = -ENOMEM;
+		goto out;
+	}
+	
+	printk(KERN_INFO "%s: 3Com %s %s at 0x%lx, ",
+	       dev->name,
+	       pdev ? "PCI" : "EISA",
+	       vortex_info_tbl[chip_idx].name,
+	       ioaddr);
 
+	/* private struct aligned and zeroed by init_etherdev */
+	vp = dev->priv;
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
 	dev->mtu = mtu;
 
-	/* Make certain the descriptor lists are aligned. */
-	vp = kmalloc(sizeof(*vp), GFP_KERNEL);
-
-	memset(vp, 0, sizeof(*vp));
-	dev->priv = vp;
-
-	vp->next_module = root_vortex_dev;
-	root_vortex_dev = dev;
+	/* module list only for EISA devices */
+	if (pdev == NULL) {
+		vp->next_module = root_vortex_eisa_dev;
+		root_vortex_eisa_dev = dev;
+	}
+	
+	/* PCI-only startup logic */
+	if (pdev) {
+		/* EISA resources already marked, so only PCI needs to do this here */
+		if (!request_region (ioaddr, vortex_info_tbl[chip_idx].io_size,
+				     dev->name)) {
+			printk (KERN_ERR "%s: Cannot reserve I/O resource 0x%x @ 0x%lx, aborting\n",
+				dev->name, vortex_info_tbl[chip_idx].io_size, ioaddr);
+			retval = -EBUSY;
+			goto free_dev;
+		}
+
+		/* wake up and enable device */		
+		if (pci_enable_device (pdev)) {
+			printk (KERN_ERR "%s: Cannot enable device, aborting\n", dev->name);
+			retval = -EIO;
+			goto free_region;
+		}
+
+		/* enable bus-mastering if necessary */		
+		if (vortex_info_tbl[chip_idx].flags & PCI_USES_MASTER)
+			pci_set_master (pdev);
+	}
 
+	vp->lock = SPIN_LOCK_UNLOCKED;
 	vp->chip_id = chip_idx;
-	vp->pci_bus = pdev == NULL ? 0 : pdev->bus->number;
-	vp->pci_devfn = pdev == NULL ? 0 : pdev->devfn;
 	vp->pdev = pdev;
 
 	/* Makes sure rings are at least 16 byte aligned. */
 	vp->rx_ring = pci_alloc_consistent(pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE
 					   + sizeof(struct boom_tx_desc) * TX_RING_SIZE,
 					   &vp->rx_ring_dma);
+	if (vp->rx_ring == 0)
+	{
+		retval = -ENOMEM;
+		goto free_region;
+	}
+
 	vp->tx_ring = (struct boom_tx_desc *)(vp->rx_ring + RX_RING_SIZE);
 	vp->tx_ring_dma = vp->rx_ring_dma + sizeof(struct boom_rx_desc) * RX_RING_SIZE;
 
+	/* if we are a PCI driver, we store info in pdev->driver_data
+	 * instead of a module list */	
+	if (pdev)
+		pdev->driver_data = dev;
+
 	/* The lower four bits are the media type. */
 	if (dev->mem_start)
+	{	/*
+		 * AKPM: ewww..  The 'options' param is passed in as the third arg to the
+		 * LILO 'ether=' argument for non-modular use
+		 */
 		option = dev->mem_start;
+	}
 	else if (card_idx < MAX_UNITS)
 		option = options[card_idx];
 	else
 		option = -1;
 
 	if (option >= 0) {
-		vp->media_override = ((option & 7) == 2)  ?  0  :  option & 7;
-		vp->full_duplex = (option & 8) ? 1 : 0;
+		vp->media_override = ((option & 7) == 2)  ?  0  :  option & 15;
+		vp->full_duplex = (option & 0x200) ? 1 : 0;
 		vp->bus_master = (option & 16) ? 1 : 0;
 	} else {
 		vp->media_override = 7;
@@ -797,23 +854,21 @@
 
 	vp->force_fd = vp->full_duplex;
 	vp->options = option;
-
 	/* Read the station address from the EEPROM. */
 	EL3WINDOW(0);
-	for (i = 0; i < 0x40; i++) {
-		int timer;
-#ifdef CARDBUS
-		outw(0x230 + i, ioaddr + Wn0EepromCmd);
-#else
-		outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd);
-#endif
-		/* Pause for at least 162 us. for the read to take place. */
-		for (timer = 10; timer >= 0; timer--) {
-			udelay(162);
-			if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0)
-				break;
+	{
+		int base = (vortex_info_tbl[chip_idx].drv_flags & EEPROM_230) ? 0x230 : EEPROM_Read;
+		for (i = 0; i < 0x40; i++) {
+			int timer;
+			outw(base + i, ioaddr + Wn0EepromCmd);
+			/* Pause for at least 162 us. for the read to take place. */
+			for (timer = 10; timer >= 0; timer--) {
+				udelay(162);
+				if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0)
+					break;
+			}
+			eeprom[i] = inw(ioaddr + Wn0EepromData);
 		}
-		eeprom[i] = inw(ioaddr + Wn0EepromData);
 	}
 	for (i = 0; i < 0x18; i++)
 		checksum ^= eeprom[i];
@@ -825,11 +880,14 @@
 	}
 	if (checksum != 0x00)
 		printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
-
 	for (i = 0; i < 3; i++)
 		((u16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]);
 	for (i = 0; i < 6; i++)
 		printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
+	EL3WINDOW(2);
+	for (i = 0; i < 6; i++)
+		outb(dev->dev_addr[i], ioaddr + i);
+
 #ifdef __sparc__
 	printk(", IRQ %s\n", __irq_itoa(dev->irq));
 #else
@@ -840,15 +898,19 @@
 			   dev->irq);
 #endif
 
-	if (pci_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) {
+	if (pdev && vortex_info_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) {
 		u32 fn_st_addr;			/* Cardbus function status space */
-		fn_st_addr = pdev == NULL ? 0 : pdev->resource[2].start;
+		fn_st_addr = pci_resource_start (pdev, 2);
 		if (fn_st_addr)
-			vp->cb_fn_base = ioremap(fn_st_addr & ~3, 128);
-		printk("%s: CardBus functions mapped %8.8x->%p (PCMCIA committee"
-			   " brain-damage).\n", dev->name, fn_st_addr, vp->cb_fn_base);
-		EL3WINDOW(2);
-		outw(0x10 | inw(ioaddr + Wn2_ResetOptions), ioaddr + Wn2_ResetOptions);
+			vp->cb_fn_base = ioremap(fn_st_addr, 128);
+		printk(KERN_INFO "%s: CardBus functions mapped %8.8x->%p\n",
+			   dev->name, fn_st_addr, vp->cb_fn_base);
+#if 0 /* AKPM */
+		if (vortex_pci_tbl[vp->chip_id].device != 0x5257) {
+			EL3WINDOW(2);
+			outw(0x10 | inw(ioaddr + Wn2_ResetOptions), ioaddr + Wn2_ResetOptions);
+		}
+#endif
 	}
 
 	/* Extract our information from the EEPROM data. */
@@ -857,10 +919,13 @@
 	vp->capabilities = eeprom[16];
 
 	if (vp->info1 & 0x8000)
+	{
 		vp->full_duplex = 1;
+		printk(KERN_INFO "Full duplex capable\n");
+	}
 
 	{
-		char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
+		static char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
 		union wn3_config config;
 		EL3WINDOW(3);
 		vp->available_media = inw(ioaddr + Wn3_Options);
@@ -919,38 +984,65 @@
 		}
 	}
 
+	if (vp->capabilities & CapPwrMgmt)
+		acpi_set_WOL(dev);
+
 	if (vp->capabilities & CapBusMaster) {
 		vp->full_bus_master_tx = 1;
 		printk(KERN_INFO"  Enabling bus-master transmits and %s receives.\n",
 			   (vp->info2 & 1) ? "early" : "whole-frame" );
 		vp->full_bus_master_rx = (vp->info2 & 1) ? 1 : 2;
+		vp->bus_master = 0;		/* AKPM: vortex only */
 	}
 
-	/* We do a request_region() to register /proc/ioports info. */
-	request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name);
-
 	/* The 3c59x-specific entries in the device structure. */
 	dev->open = &vortex_open;
 	dev->hard_start_xmit = &vortex_start_xmit;
-	dev->tx_timeout = &vortex_tx_timeout;
-	dev->watchdog_timeo = TX_TIMEOUT; 
 	dev->stop = &vortex_close;
 	dev->get_stats = &vortex_get_stats;
 	dev->do_ioctl = &vortex_ioctl;
 	dev->set_multicast_list = &set_rx_mode;
+	dev->tx_timeout = &vortex_tx_timeout;
+	dev->watchdog_timeo = TX_TIMEOUT;
+
+	return 0;
 
-	return dev;
+free_region:
+	release_region (ioaddr, vortex_info_tbl[chip_idx].io_size);
+free_dev:
+	kfree (dev);
+	printk(KERN_ERR PFX "vortex_probe1 fails.  Returns %d\n", retval);
+out:
+	return retval;
 }
 
-
-static int
-vortex_open(struct net_device *dev)
+static void wait_for_completion(struct net_device *dev, int cmd)
+{
+	int i = 2000;
+
+	outw(cmd, dev->base_addr + EL3_CMD);
+	while (--i > 0)
+	{
+		if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress))
+			return;
+	}
+	printk(KERN_ERR "%s: command 0x%04x did not complete! Status=0x%x\n",
+			   dev->name, cmd, inw(dev->base_addr + EL3_STATUS));
+}
+
+static void
+vortex_up(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	union wn3_config config;
-	int i;
+	int i, device_id;
 
+	if (vp->pdev)
+		device_id = vp->pdev->device;
+	else
+		device_id = 0x5900; /* EISA */
+	
 	/* Before initializing select the active media port. */
 	EL3WINDOW(3);
 	config.i = inl(ioaddr + Wn3_Config);
@@ -961,15 +1053,24 @@
 				   dev->name, vp->media_override,
 				   media_tbl[vp->media_override].name);
 		dev->if_port = vp->media_override;
-	} else if (vp->autoselect && pci_tbl[vp->chip_id].drv_flags & HAS_NWAY) {
-			dev->if_port = XCVR_NWAY;
 	} else if (vp->autoselect) {
-		/* Find first available media type, starting with 100baseTx. */
-		dev->if_port = XCVR_100baseTx;
-		while (! (vp->available_media & media_tbl[dev->if_port].mask))
-			dev->if_port = media_tbl[dev->if_port].next;
-	} else
+		if (vortex_info_tbl[vp->chip_id].drv_flags & HAS_NWAY) {
+			printk(KERN_INFO "%s: using NWAY autonegotiation\n", dev->name);
+			dev->if_port = XCVR_NWAY;
+		} else {
+			/* Find first available media type, starting with 100baseTx. */
+			dev->if_port = XCVR_100baseTx;
+			while (! (vp->available_media & media_tbl[dev->if_port].mask))
+				dev->if_port = media_tbl[dev->if_port].next;
+			printk(KERN_INFO "%s: first avaialble mdeia type: %s\n",
+					dev->name,
+					media_tbl[dev->if_port].name);
+		}
+	} else {
 		dev->if_port = vp->default_media;
+		printk(KERN_INFO "%s: using default media %s\n",
+				dev->name, media_tbl[dev->if_port].name);
+	}
 
 	init_timer(&vp->timer);
 	vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait);
@@ -983,7 +1084,13 @@
 
 	vp->full_duplex = vp->force_fd;
 	config.u.xcvr = dev->if_port;
-	outl(config.i, ioaddr + Wn3_Config);
+	if ( ! (vortex_info_tbl[vp->chip_id].drv_flags & HAS_NWAY))
+	{
+		if (vortex_debug > 6)
+			printk(KERN_DEBUG "vortex_up(): writing 0x%x to InternalConfig\n",
+				config.i);
+		outl(config.i, ioaddr + Wn3_Config);
+	}
 
 	if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
 		int mii_reg1, mii_reg5;
@@ -1008,31 +1115,18 @@
 		 (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
 
 	if (vortex_debug > 1) {
-		printk(KERN_DEBUG "%s: vortex_open() InternalConfig %8.8x.\n",
+		printk(KERN_DEBUG "%s: vortex_up() InternalConfig %8.8x.\n",
 			dev->name, config.i);
 	}
 
-	outw(TxReset, ioaddr + EL3_CMD);
-	for (i = 2000; i >= 0 ; i--)
-		if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-			break;
-
-	outw(RxReset, ioaddr + EL3_CMD);
-	/* Wait a few ticks for the RxReset command to complete. */
-	for (i = 2000; i >= 0 ; i--)
-		if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-			break;
+	wait_for_completion(dev, TxReset);
+	wait_for_completion(dev, RxReset);
 
 	outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
 
-	/* Use the now-standard shared IRQ implementation. */
-	if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ, dev->name, dev)) {
-		return -EAGAIN;
-	}
-
 	if (vortex_debug > 1) {
 		EL3WINDOW(4);
-		printk(KERN_DEBUG "%s: vortex_open() irq %d media status %4.4x.\n",
+		printk(KERN_DEBUG "%s: vortex_up() irq %d media status %4.4x.\n",
 			   dev->name, dev->irq, inw(ioaddr + Wn4_Media));
 	}
 
@@ -1042,6 +1136,19 @@
 		outb(dev->dev_addr[i], ioaddr + i);
 	for (; i < 12; i+=2)
 		outw(0, ioaddr + i);
+	if (vp->cb_fn_base) {
+		u_short n = inw(ioaddr + Wn2_ResetOptions);
+#if 0	/* AKPM: This is done in vortex_probe1, and seems to be wrong anyway... */
+		/* Inverted LED polarity */
+		if (device_id != 0x5257)
+			n |= 0x0010;
+#endif
+		/* Inverted polarity of MII power bit */
+		if ((device_id == 0x6560) || (device_id == 0x6562) ||
+			(device_id == 0x5257))
+			n |= 0x4000;
+		outw(n, ioaddr + Wn2_ResetOptions);
+	}
 
 	if (dev->if_port == XCVR_10base2)
 		/* Start the thinnet transceiver. We should really wait 50ms...*/
@@ -1073,39 +1180,24 @@
 		/* Initialize the RxEarly register as recommended. */
 		outw(SetRxThreshold + (1536>>2), ioaddr + EL3_CMD);
 		outl(0x0020, ioaddr + PktStatus);
-		if (vortex_debug > 2)
-			printk(KERN_DEBUG "%s:  Filling in the Rx ring.\n", dev->name);
-		for (i = 0; i < RX_RING_SIZE; i++) {
-			struct sk_buff *skb;
-			vp->rx_ring[i].next = cpu_to_le32(vp->rx_ring_dma + sizeof(struct boom_rx_desc) * (i+1));
-			vp->rx_ring[i].status = 0;	/* Clear complete bit. */
-			vp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LAST_FRAG);
-			skb = dev_alloc_skb(PKT_BUF_SZ);
-			vp->rx_skbuff[i] = skb;
-			if (skb == NULL)
-				break;			/* Bad news!  */
-			skb->dev = dev;			/* Mark as being used by this device. */
-			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
-			vp->rx_ring[i].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE));
-		}
-		/* Wrap the ring. */
-		vp->rx_ring[i-1].next = cpu_to_le32(vp->rx_ring_dma);
-		outl(vp->rx_ring_dma, ioaddr + UpListPtr);
+		outl(virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr);
 	}
 	if (vp->full_bus_master_tx) { 		/* Boomerang bus master Tx. */
 		dev->hard_start_xmit = &boomerang_start_xmit;
 		vp->cur_tx = vp->dirty_tx = 0;
 		outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */
-		/* Clear the Tx ring. */
+		/* Clear the Rx, Tx rings. */
+		for (i = 0; i < RX_RING_SIZE; i++)	/* AKPM: this is done in vortex_open, too */
+			vp->rx_ring[i].status = 0;
 		for (i = 0; i < TX_RING_SIZE; i++)
 			vp->tx_skbuff[i] = 0;
 		outl(0, ioaddr + DownListPtr);
 	}
-	/* Set reciever mode: presumably accept b-case and phys addr only. */
+	/* Set receiver mode: presumably accept b-case and phys addr only. */
 	set_rx_mode(dev);
 	outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
 
-	vp->in_interrupt = 0;
+	netif_start_queue (dev);
 
 	outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
 	outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
@@ -1114,7 +1206,8 @@
 		(vp->full_bus_master_tx ? DownComplete : TxAvailable) |
 		(vp->full_bus_master_rx ? UpComplete : RxComplete) |
 		(vp->bus_master ? DMADone : 0);
-	vp->intr_enable = SetIntrEnb | IntLatch | TxAvailable | RxComplete |
+	vp->intr_enable = SetIntrEnb | IntLatch | TxAvailable |
+		(vp->full_bus_master_rx ? 0 : RxComplete) |
 		StatsFull | HostError | TxComplete | IntReq
 		| (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete;
 	outw(vp->status_enable, ioaddr + EL3_CMD);
@@ -1125,11 +1218,55 @@
 	if (vp->cb_fn_base)			/* The PCMCIA people are idiots.  */
 		writel(0x8000, vp->cb_fn_base + 4);
 
-	netif_start_queue(dev);
+	/* AKPM: unjam the 3CCFE575CT */
+	wait_for_completion(dev, TxReset);
+	outw(TxEnable, ioaddr + EL3_CMD);
+}
+
+static int
+vortex_open(struct net_device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	int i;
+	int retval;
 
 	MOD_INC_USE_COUNT;
 
+	/* Use the now-standard shared IRQ implementation. */
+	if (request_irq(dev->irq, vp->full_bus_master_rx ? &boomerang_interrupt : &vortex_interrupt,
+					SA_SHIRQ, dev->name, dev)) {
+		retval = -EAGAIN;
+		goto out;
+	}
+
+	if (vp->full_bus_master_rx) { /* Boomerang bus master. */
+		if (vortex_debug > 2)
+			printk(KERN_DEBUG "%s:  Filling in the Rx ring.\n", dev->name);
+		for (i = 0; i < RX_RING_SIZE; i++) {
+			struct sk_buff *skb;
+			vp->rx_ring[i].next = cpu_to_le32(virt_to_bus(&vp->rx_ring[i+1]));
+			vp->rx_ring[i].status = 0;	/* Clear complete bit. */
+			vp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LAST_FRAG);
+			skb = dev_alloc_skb(PKT_BUF_SZ);
+			vp->rx_skbuff[i] = skb;
+			if (skb == NULL)
+				break;			/* Bad news!  */
+			skb->dev = dev;			/* Mark as being used by this device. */
+			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
+			vp->rx_ring[i].addr = cpu_to_le32(virt_to_bus(skb->tail));
+		}
+		/* Wrap the ring. */
+		vp->rx_ring[i-1].next = cpu_to_le32(virt_to_bus(&vp->rx_ring[0]));
+	}
+
+	vortex_up(dev);
+	vp->open = 1;
 	return 0;
+out:
+	MOD_DEC_USE_COUNT;
+	if (vortex_debug > 1)
+		printk(KERN_ERR PFX "vortex_open() fails: returning %d\n", retval);
+	return retval;
 }
 
 static void vortex_timer(unsigned long data)
@@ -1137,7 +1274,7 @@
 	struct net_device *dev = (struct net_device *)data;
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	long ioaddr = dev->base_addr;
-	int next_tick = 0;
+	int next_tick = 60*HZ;
 	int ok = 0;
 	int media_status, mii_status, old_window;
 
@@ -1152,43 +1289,50 @@
 	switch (dev->if_port) {
 	case XCVR_10baseT:  case XCVR_100baseTx:  case XCVR_100baseFx:
 		if (media_status & Media_LnkBeat) {
-		  ok = 1;
-		  if (vortex_debug > 1)
-			printk(KERN_DEBUG "%s: Media %s has link beat, %x.\n",
-				   dev->name, media_tbl[dev->if_port].name, media_status);
+			ok = 1;
+			if (vortex_debug > 1)
+				printk(KERN_DEBUG "%s: Media %s has link beat, %x.\n",
+					   dev->name, media_tbl[dev->if_port].name, media_status);
 		} else if (vortex_debug > 1)
-		  printk(KERN_DEBUG "%s: Media %s is has no link beat, %x.\n",
+			printk(KERN_DEBUG "%s: Media %s is has no link beat, %x.\n",
 				   dev->name, media_tbl[dev->if_port].name, media_status);
 		break;
-	  case XCVR_MII: case XCVR_NWAY:
-		  mii_status = mdio_read(ioaddr, vp->phys[0], 1);
-		  ok = 1;
-		  if (debug > 1)
-			  printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n",
-					 dev->name, mii_status);
-		  if (mii_status & 0x0004) {
-			  int mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
-			  if (! vp->force_fd  &&  mii_reg5 != 0xffff) {
-				  int duplex = (mii_reg5&0x0100) ||
-					  (mii_reg5 & 0x01C0) == 0x0040;
-				  if (vp->full_duplex != duplex) {
-					  vp->full_duplex = duplex;
-					  printk(KERN_INFO "%s: Setting %s-duplex based on MII "
-							 "#%d link partner capability of %4.4x.\n",
-							 dev->name, vp->full_duplex ? "full" : "half",
-							 vp->phys[0], mii_reg5);
-					  /* Set the full-duplex bit. */
-					  outb((vp->full_duplex ? 0x20 : 0) |
-						   (dev->mtu > 1500 ? 0x40 : 0),
-						   ioaddr + Wn3_MAC_Ctrl);
-				  }
-				  next_tick = 60*HZ;
-			  }
-		  }
-		  break;
+	case XCVR_MII: case XCVR_NWAY:
+		{
+			unsigned long flags;
+			spin_lock_irqsave(&vp->lock, flags);	/* AKPM: protect mdio state */
+
+			mii_status = mdio_read(ioaddr, vp->phys[0], 1);
+			ok = 1;
+			if (vortex_debug > 1)
+				printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n",
+					dev->name, mii_status);
+			if (mii_status & 0x0004) {
+				int mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
+				if (! vp->force_fd  &&  mii_reg5 != 0xffff) {
+					int duplex = (mii_reg5&0x0100) ||
+						(mii_reg5 & 0x01C0) == 0x0040;
+					if (vp->full_duplex != duplex) {
+						vp->full_duplex = duplex;
+						printk(KERN_INFO "%s: Setting %s-duplex based on MII "
+							"#%d link partner capability of %4.4x.\n",
+							dev->name, vp->full_duplex ? "full" : "half",
+							vp->phys[0], mii_reg5);
+						/* Set the full-duplex bit. */
+						EL3WINDOW(3);	/* AKPM: this was missing from 2.3.99 3c59x.c! */
+						outb((vp->full_duplex ? 0x20 : 0) |
+							(dev->mtu > 1500 ? 0x40 : 0),
+							ioaddr + Wn3_MAC_Ctrl);
+					}
+					next_tick = 60*HZ;
+				}
+			}
+			spin_unlock_irqrestore(&vp->lock, flags);
+		}
+		break;
 	  default:					/* Other media types handled by Tx timeouts. */
 		if (vortex_debug > 1)
-		  printk(KERN_DEBUG "%s: Media %s is has no indication, %x.\n",
+		  printk(KERN_DEBUG "%s: Media %s has no indication, %x.\n",
 				 dev->name, media_tbl[dev->if_port].name, media_status);
 		ok = 1;
 	}
@@ -1205,11 +1349,11 @@
 				   "%s port.\n",
 				   dev->name, media_tbl[dev->if_port].name);
 		} else {
-		  if (vortex_debug > 1)
-			printk(KERN_DEBUG "%s: Media selection failed, now trying "
-				   "%s port.\n",
-				   dev->name, media_tbl[dev->if_port].name);
-		  next_tick = media_tbl[dev->if_port].wait;
+			if (vortex_debug > 1)
+				printk(KERN_DEBUG "%s: Media selection failed, now trying "
+					   "%s port.\n",
+					   dev->name, media_tbl[dev->if_port].name);
+			next_tick = media_tbl[dev->if_port].wait;
 		}
 		outw((media_status & ~(Media_10TP|Media_SQE)) |
 			 media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
@@ -1225,14 +1369,14 @@
 	EL3WINDOW(old_window);
 	enable_irq(dev->irq);
 
-	if (vortex_debug > 2)
+	if (vortex_debug > 1)
 	  printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n",
 			 dev->name, media_tbl[dev->if_port].name);
 
-	if (next_tick) {
-		vp->timer.expires = RUN_AT(next_tick);
-		add_timer(&vp->timer);
-	}
+	vp->timer.expires = RUN_AT(next_tick);
+	add_timer(&vp->timer);
+	if (vp->deferred)
+		outw(FakeIntr, ioaddr + EL3_CMD);
 	return;
 }
 
@@ -1240,7 +1384,6 @@
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	long ioaddr = dev->base_addr;
-	int j;
 
 	printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
 		   dev->name, inb(ioaddr + TxStatus),
@@ -1253,30 +1396,41 @@
 		printk(KERN_ERR "%s: Interrupt posted but not delivered --"
 			   " IRQ blocked by another device?\n", dev->name);
 		/* Bad idea here.. but we might as well handle a few events. */
-		vortex_interrupt(dev->irq, dev, 0);
+		{
+			/*
+			 * AKPM: block interrupts because vortex_interrupt
+			 * does a bare spin_lock()
+			 */
+			unsigned long flags;
+			local_irq_save(flags);
+			if (vp->full_bus_master_tx)
+				boomerang_interrupt(dev->irq, dev, 0);
+			else
+				vortex_interrupt(dev->irq, dev, 0);
+			local_irq_restore(flags);
+		}
 	}
-	outw(TxReset, ioaddr + EL3_CMD);
-	for (j = 200; j >= 0 ; j--)
-		if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-			break;
 
-#if ! defined(final_version)
-	if (vp->full_bus_master_tx) {
-		int i;
-		printk(KERN_DEBUG "  Flags; bus-master %d, full %d; dirty %d "
-			   "current %d.\n",
-			   vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, vp->cur_tx);
-		printk(KERN_DEBUG "  Transmit list %8.8x vs. %p.\n",
-			   inl(ioaddr + DownListPtr),
-			   &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]);
-		for (i = 0; i < TX_RING_SIZE; i++) {
-			printk(KERN_DEBUG "  %d: @%p  length %8.8x status %8.8x\n", i,
-				   &vp->tx_ring[i],
-				   le32_to_cpu(vp->tx_ring[i].length),
-				   le32_to_cpu(vp->tx_ring[i].status));
+	if (vortex_debug > 0) {
+		if (vp->full_bus_master_tx) {
+			int i;
+			printk(KERN_DEBUG "  Flags; bus-master %d, full %d; dirty %d "
+				   "current %d.\n",
+				   vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, vp->cur_tx);
+			printk(KERN_DEBUG "  Transmit list %8.8x vs. %p.\n",
+				   inl(ioaddr + DownListPtr),
+				   &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]);
+			for (i = 0; i < TX_RING_SIZE; i++) {
+				printk(KERN_DEBUG "  %d: @%p  length %8.8x status %8.8x\n", i,
+					   &vp->tx_ring[i],
+					   le32_to_cpu(vp->tx_ring[i].length),
+					   le32_to_cpu(vp->tx_ring[i].status));
+			}
 		}
 	}
-#endif
+
+	wait_for_completion(dev, TxReset);
+
 	vp->stats.tx_errors++;
 	if (vp->full_bus_master_tx) {
 		if (vortex_debug > 0)
@@ -1287,8 +1441,10 @@
 				 ioaddr + DownListPtr);
 		if (vp->tx_full && (vp->cur_tx - vp->dirty_tx <= TX_RING_SIZE - 1)) {
 			vp->tx_full = 0;
-			netif_wake_queue(dev);
+			netif_start_queue (dev);
 		}
+		if (vp->tx_full)
+			netif_stop_queue (dev);
 		outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
 		outw(DownUnstall, ioaddr + EL3_CMD);
 	} else
@@ -1312,7 +1468,9 @@
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 	int do_tx_reset = 0;
-	int i;
+
+	if (vortex_debug > 2)
+		printk(KERN_DEBUG "%s: vortex_error(), status=0x%x\n", dev->name, status);
 
 	if (status & TxComplete) {			/* Really "TxError" for us. */
 		unsigned char tx_status = inb(ioaddr + TxStatus);
@@ -1358,25 +1516,18 @@
 		u16 fifo_diag;
 		EL3WINDOW(4);
 		fifo_diag = inw(ioaddr + Wn4_FIFODiag);
-		if (vortex_debug > 0)
-			printk(KERN_ERR "%s: Host error, FIFO diagnostic register %4.4x.\n",
-				   dev->name, fifo_diag);
+		printk(KERN_ERR "%s: Host error, FIFO diagnostic register %4.4x.\n",
+			   dev->name, fifo_diag);
 		/* Adapter failure requires Tx/Rx reset and reinit. */
 		if (vp->full_bus_master_tx) {
-			outw(TotalReset | 0xff, ioaddr + EL3_CMD);
-			for (i = 2000; i >= 0 ; i--)
-				if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-					break;
-			/* Re-enable the receiver. */
-			outw(RxEnable, ioaddr + EL3_CMD);
-			outw(TxEnable, ioaddr + EL3_CMD);
+			/* In this case, blow the card away */
+			vortex_down(dev);
+			wait_for_completion(dev, TotalReset | 0xff);
+			vortex_up(dev);
 		} else if (fifo_diag & 0x0400)
 			do_tx_reset = 1;
 		if (fifo_diag & 0x3000) {
-			outw(RxReset, ioaddr + EL3_CMD);
-			for (i = 2000; i >= 0 ; i--)
-				if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-					break;
+			wait_for_completion(dev, RxReset);
 			/* Set the Rx filter to the current state. */
 			set_rx_mode(dev);
 			outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
@@ -1384,40 +1535,37 @@
 		}
 	}
 	if (do_tx_reset) {
-		int j;
-		outw(TxReset, ioaddr + EL3_CMD);
-		for (j = 200; j >= 0 ; j--)
-			if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-				break;
+		wait_for_completion(dev, TxReset);
 		outw(TxEnable, ioaddr + EL3_CMD);
 	}
 
 }
 
-
 static int
 vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 
-	netif_stop_queue(dev);
-
+	netif_stop_queue (dev);
+	
 	/* Put out the doubleword header... */
 	outl(skb->len, ioaddr + TX_FIFO);
 	if (vp->bus_master) {
 		/* Set the bus-master controller to transfer the packet. */
 		int len = (skb->len + 3) & ~3;
-		outl(vp->tx_skb_dma = pci_map_single(vp->pdev, skb->data, len, PCI_DMA_TODEVICE), ioaddr + Wn7_MasterAddr);
+		outl(	vp->tx_skb_dma = pci_map_single(vp->pdev, skb->data, len, PCI_DMA_TODEVICE),
+				ioaddr + Wn7_MasterAddr);
 		outw(len, ioaddr + Wn7_MasterLen);
 		vp->tx_skb = skb;
 		outw(StartDMADown, ioaddr + EL3_CMD);
+		/* dev->tbusy will be cleared at the DMADone interrupt. */
 	} else {
 		/* ... and the packet rounded to a doubleword. */
 		outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
-		DEV_FREE_SKB(skb);
+		dev_kfree_skb (skb);
 		if (inw(ioaddr + TxFree) > 1536) {
-			netif_wake_queue(dev);
+			netif_start_queue (dev);
 		} else
 			/* Interrupt us when the FIFO has room for max-sized packet. */
 			outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
@@ -1438,18 +1586,13 @@
 				if (tx_status & 0x04) vp->stats.tx_fifo_errors++;
 				if (tx_status & 0x38) vp->stats.tx_aborted_errors++;
 				if (tx_status & 0x30) {
-					int j;
-					outw(TxReset, ioaddr + EL3_CMD);
-					for (j = 200; j >= 0 ; j--)
-						if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-							break;
+					wait_for_completion(dev, TxReset);
 				}
 				outw(TxEnable, ioaddr + EL3_CMD);
 			}
 			outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
 		}
 	}
-	vp->stats.tx_bytes += skb->len;
 	return 0;
 }
 
@@ -1459,21 +1602,22 @@
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 
-	netif_stop_queue(dev);
+	if (vortex_debug > 6)
+		printk(KERN_DEBUG "boomerang_start_xmit()\n");
 
-	if (1) {
+	netif_stop_queue (dev);
+	{
 		/* Calculate the next Tx descriptor entry. */
 		int entry = vp->cur_tx % TX_RING_SIZE;
 		struct boom_tx_desc *prev_entry =
 			&vp->tx_ring[(vp->cur_tx-1) % TX_RING_SIZE];
 		unsigned long flags;
-		int i;
 
 		if (vortex_debug > 3)
 			printk(KERN_DEBUG "%s: Trying to send a packet, Tx index %d.\n",
 				   dev->name, vp->cur_tx);
 		if (vp->tx_full) {
-			if (vortex_debug >0)
+			if (vortex_debug > 0)
 				printk(KERN_WARNING "%s: Tx Ring full, refusing to send buffer.\n",
 					   dev->name);
 			return 1;
@@ -1484,37 +1628,40 @@
 		vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG);
 		vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded);
 
-		/* Hmm... And some poor people try to use it on SMP machines 8) */
-		save_flags(flags);
-		cli();
-		outw(DownStall, ioaddr + EL3_CMD);
+		spin_lock_irqsave(&vp->lock, flags);
 		/* Wait for the stall to complete. */
-		for (i = 600; i >= 0 ; i--)
-			if ( (inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0)
-				break;
+		wait_for_completion(dev, DownStall);
 		prev_entry->next = cpu_to_le32(vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc));
 		if (inl(ioaddr + DownListPtr) == 0) {
 			outl(vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc), ioaddr + DownListPtr);
 			queued_packet++;
 		}
-		outw(DownUnstall, ioaddr + EL3_CMD);
-		restore_flags(flags);
 
 		vp->cur_tx++;
 		if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1) {
 			vp->tx_full = 1;
+			netif_stop_queue (dev);
 		} else {					/* Clear previous interrupt enable. */
+#if defined(tx_interrupt_mitigation)
 			prev_entry->status &= cpu_to_le32(~TxIntrUploaded);
-			netif_wake_queue(dev);
+#endif
+			netif_start_queue (dev);
 		}
+		outw(DownUnstall, ioaddr + EL3_CMD);
+		spin_unlock_irqrestore(&vp->lock, flags);
 		dev->trans_start = jiffies;
-		vp->stats.tx_bytes += skb->len;
 		return 0;
 	}
 }
 
 /* The interrupt handler does all of the Rx thread work and cleans up
    after the Tx thread. */
+
+/*
+ * This is the ISR for the vortex series chips.
+ * full_bus_master_tx == 0 && full_bus_master_rx == 0
+ */
+
 static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = dev_id;
@@ -1523,10 +1670,23 @@
 	int latency, status;
 	int work_done = max_interrupt_work;
 
+	spin_lock(&vp->lock);
+	
 	ioaddr = dev->base_addr;
 	latency = inb(ioaddr + Timer);
 	status = inw(ioaddr + EL3_STATUS);
 
+	if (vortex_debug > 6)
+		printk("AKPM: vortex_interrupt. status=0x%4x\n", status);
+
+	if (status & IntReq) {
+		status |= vp->deferred;
+		vp->deferred = 0;
+	}
+
+	if (status == 0xffff)		/* AKPM: h/w no longer present (hotplug)? */
+		goto handler_exit;
+
 	if (vortex_debug > 4)
 		printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n",
 			   dev->name, status, latency);
@@ -1536,22 +1696,117 @@
 					   dev->name, status);
 		if (status & RxComplete)
 			vortex_rx(dev);
-		if (status & UpComplete) {
-			outw(AckIntr | UpComplete, ioaddr + EL3_CMD);
-			boomerang_rx(dev);
-		}
 
 		if (status & TxAvailable) {
 			if (vortex_debug > 5)
 				printk(KERN_DEBUG "	TX room bit was handled.\n");
 			/* There's room in the FIFO for a full-sized packet. */
 			outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
-			netif_wake_queue(dev);
+			netif_wake_queue (dev);
+		}
+
+		if (status & DMADone) {
+			if (inw(ioaddr + Wn7_MasterStatus) & 0x1000) {
+				outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
+				pci_unmap_single(vp->pdev, vp->tx_skb_dma, (vp->tx_skb->len + 3) & ~3, PCI_DMA_TODEVICE);
+				dev_kfree_skb_irq(vp->tx_skb); /* Release the transfered buffer */
+				if (inw(ioaddr + TxFree) > 1536) {
+					netif_wake_queue (dev);
+				} else { /* Interrupt when FIFO has room for max-sized packet. */
+					outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
+					netif_stop_queue (dev);		/* AKPM: This is new */
+				}
+			}
+		}
+		/* Check for all uncommon interrupts at once. */
+		if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq)) {
+			if (status == 0xffff)
+				break;
+			vortex_error(dev, status);
+		}
+
+		if (--work_done < 0) {
+			printk(KERN_WARNING "%s: Too much work in interrupt, status "
+				   "%4.4x.\n", dev->name, status);
+			/* Disable all pending interrupts. */
+			do {
+				vp->deferred |= status;
+				outw(SetStatusEnb | (~vp->deferred & vp->status_enable),
+					 ioaddr + EL3_CMD);
+				outw(AckIntr | (vp->deferred & 0x7ff), ioaddr + EL3_CMD);
+			} while ((status = inw(ioaddr + EL3_CMD)) & IntLatch);
+			/* The timer will reenable interrupts. */
+			del_timer(&vp->timer);
+			vp->timer.expires = RUN_AT(1);
+			add_timer(&vp->timer);
+			break;
+		}
+		/* Acknowledge the IRQ. */
+		outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
+		if (vp->cb_fn_base)			/* The PCMCIA people are idiots.  */
+			writel(0x8000, vp->cb_fn_base + 4);
+
+	} while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
+
+	if (vortex_debug > 4)
+		printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n",
+			   dev->name, status);
+handler_exit:
+	spin_unlock(&vp->lock);
+}
+
+/*
+ * This is the ISR for the boomerang series chips.
+ * full_bus_master_tx == 1 && full_bus_master_rx == 1
+ */
+
+static void boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_id;
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	long ioaddr;
+	int latency, status;
+	int work_done = max_interrupt_work;
+
+	spin_lock(&vp->lock);
+	
+	ioaddr = dev->base_addr;
+	latency = inb(ioaddr + Timer);
+	status = inw(ioaddr + EL3_STATUS);
+
+	if (vortex_debug > 6)
+		printk(KERN_DEBUG "boomerang_interrupt. status=0x%4x\n", status);
+
+	if (status & IntReq) {
+		status |= vp->deferred;
+		vp->deferred = 0;
+	}
+
+	if (status == 0xffff)		/* AKPM: h/w no longer present (hotplug)? */
+	{
+		if (vortex_debug > 1)
+			printk(KERN_DEBUG "boomerang_interrupt(1): status = 0xffff\n");
+		goto handler_exit;
+	}
+
+	if (vortex_debug > 4)
+		printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n",
+			   dev->name, status, latency);
+	do {
+		if (vortex_debug > 5)
+				printk(KERN_DEBUG "%s: In interrupt loop, status %4.4x.\n",
+					   dev->name, status);
+		if (status & UpComplete) {
+			outw(AckIntr | UpComplete, ioaddr + EL3_CMD);
+			if (vortex_debug > 5)
+				printk(KERN_DEBUG "boomerang_interrupt->boomerang_rx\n");
+			boomerang_rx(dev);
 		}
 
 		if (status & DownComplete) {
 			unsigned int dirty_tx = vp->dirty_tx;
 
+			outw(AckIntr | DownComplete, ioaddr + EL3_CMD);
 			while (vp->cur_tx - dirty_tx > 0) {
 				int entry = dirty_tx % TX_RING_SIZE;
 				if (inl(ioaddr + DownListPtr) ==
@@ -1560,31 +1815,27 @@
 				if (vp->tx_skbuff[entry]) {
 					struct sk_buff *skb = vp->tx_skbuff[entry];
 					
-					pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[entry].addr), skb->len, PCI_DMA_TODEVICE);
-					dev_kfree_skb_irq(vp->tx_skbuff[entry]);
+					pci_unmap_single(vp->pdev,
+						le32_to_cpu(vp->tx_ring[entry].addr), skb->len, PCI_DMA_TODEVICE);
+					dev_kfree_skb_irq(skb);
 					vp->tx_skbuff[entry] = 0;
+				} else {
+					printk(KERN_DEBUG "boomerang_interrupt: no skb!\n");
 				}
 				/* vp->stats.tx_packets++;  Counted below. */
 				dirty_tx++;
 			}
 			vp->dirty_tx = dirty_tx;
-			outw(AckIntr | DownComplete, ioaddr + EL3_CMD);
 			if (vp->tx_full && (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {
-				vp->tx_full= 0;
-				netif_wake_queue(dev);
-			}
-		}
-		if (status & DMADone) {
-			if (inw(ioaddr + Wn7_MasterStatus) & 0x1000) {
-				outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
-				pci_unmap_single(vp->pdev, vp->tx_skb_dma, (vp->tx_skb->len + 3) & ~3, PCI_DMA_TODEVICE);
-				dev_kfree_skb_irq(vp->tx_skb); /* Release the transfered buffer */
-				if (inw(ioaddr + TxFree) > 1536) {
-					netif_wake_queue(dev);
-				} else /* Interrupt when FIFO has room for max-sized packet. */
-					outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
+				if (vortex_debug > 6)
+					printk(KERN_DEBUG "boomerang_interrupt: clearing tx_full\n");
+				vp->tx_full = 0;
+				netif_wake_queue (dev);
 			}
 		}
+		if (vp->tx_full)
+			netif_stop_queue (dev);
+
 		/* Check for all uncommon interrupts at once. */
 		if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq)) {
 			if (status == 0xffff)
@@ -1593,19 +1844,20 @@
 		}
 
 		if (--work_done < 0) {
-			if ((status & (0x7fe - (UpComplete | DownComplete))) == 0) {
-				/* Just ack these and return. */
-				outw(AckIntr | UpComplete | DownComplete, ioaddr + EL3_CMD);
-			} else {
-				printk(KERN_WARNING "%s: Too much work in interrupt, status "
-					   "%4.4x.  Temporarily disabling functions (%4.4x).\n",
-					   dev->name, status, SetStatusEnb | ((~status) & 0x7FE));
-				/* Disable all pending interrupts. */
-				outw(SetStatusEnb | ((~status) & 0x7FE), ioaddr + EL3_CMD);
-				outw(AckIntr | 0x7FF, ioaddr + EL3_CMD);
-				/* The timer will reenable interrupts. */
-				break;
-			}
+			printk(KERN_WARNING "%s: Too much work in interrupt, status "
+				   "%4.4x.\n", dev->name, status);
+			/* Disable all pending interrupts. */
+			do {
+				vp->deferred |= status;
+				outw(SetStatusEnb | (~vp->deferred & vp->status_enable),
+					 ioaddr + EL3_CMD);
+				outw(AckIntr | (vp->deferred & 0x7ff), ioaddr + EL3_CMD);
+			} while ((status = inw(ioaddr + EL3_CMD)) & IntLatch);
+			/* The timer will reenable interrupts. */
+			del_timer(&vp->timer);
+			vp->timer.expires = RUN_AT(1);
+			add_timer(&vp->timer);
+			break;
 		}
 		/* Acknowledge the IRQ. */
 		outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
@@ -1617,8 +1869,8 @@
 	if (vortex_debug > 4)
 		printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n",
 			   dev->name, status);
-
-	return;
+handler_exit:
+	spin_unlock(&vp->lock);
 }
 
 static int vortex_rx(struct net_device *dev)
@@ -1629,7 +1881,7 @@
 	short rx_status;
 
 	if (vortex_debug > 5)
-		printk(KERN_DEBUG"   In rx_packet(), status %4.4x, rx_status %4.4x.\n",
+		printk(KERN_DEBUG "vortex_rx(): status %4.4x, rx_status %4.4x.\n",
 			   inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
 	while ((rx_status = inw(ioaddr + RxStatus)) > 0) {
 		if (rx_status & 0x4000) { /* Error, update stats. */
@@ -1674,22 +1926,17 @@
 				netif_rx(skb);
 				dev->last_rx = jiffies;
 				vp->stats.rx_packets++;
-				vp->stats.rx_bytes += skb->len;
 				/* Wait a limited time to go to next packet. */
 				for (i = 200; i >= 0; i--)
 					if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
 						break;
 				continue;
-			} else if (vortex_debug)
+			} else if (vortex_debug > 0)
 				printk(KERN_NOTICE "%s: No memory to allocate a sk_buff of "
 					   "size %d.\n", dev->name, pkt_len);
 		}
-		outw(RxDiscard, ioaddr + EL3_CMD);
 		vp->stats.rx_dropped++;
-		/* Wait a limited time to skip this packet. */
-		for (i = 200; i >= 0; i--)
-			if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-				break;
+		wait_for_completion(dev, RxDiscard);
 	}
 
 	return 0;
@@ -1705,7 +1952,7 @@
 	int rx_work_limit = vp->dirty_rx + RX_RING_SIZE - vp->cur_rx;
 
 	if (vortex_debug > 5)
-		printk(KERN_DEBUG "  In boomerang_rx(), status %4.4x, rx_status "
+		printk(KERN_DEBUG "boomerang_rx(): status %4.4x, rx_status "
 			   "%4.4x.\n",
 			   inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
 	while ((rx_status = le32_to_cpu(vp->rx_ring[entry].status)) & RxDComplete){
@@ -1787,22 +2034,13 @@
 	return 0;
 }
 
-static int
-vortex_close(struct net_device *dev)
+static void
+vortex_down(struct net_device *dev)
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	long ioaddr = dev->base_addr;
-	int i;
-
-	netif_stop_queue(dev);
 
-	if (vortex_debug > 1) {
-		printk(KERN_DEBUG"%s: vortex_close() status %4.4x, Tx status %2.2x.\n",
-			   dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus));
-		printk(KERN_DEBUG "%s: vortex close stats: rx_nocopy %d rx_copy %d"
-			   " tx_queued %d Rx pre-checksummed %d.\n",
-			   dev->name, rx_nocopy, rx_copy, queued_packet, rx_csumhits);
-	}
+	netif_stop_queue (dev);
 
 	del_timer(&vp->timer);
 
@@ -1817,34 +2055,60 @@
 		/* Turn off thinnet power.  Green! */
 		outw(StopCoax, ioaddr + EL3_CMD);
 
-	free_irq(dev->irq, dev);
-
 	outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
 
 	update_stats(ioaddr, dev);
-	if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */
+	if (vp->full_bus_master_rx)
 		outl(0, ioaddr + UpListPtr);
+	if (vp->full_bus_master_tx)
+		outl(0, ioaddr + DownListPtr);
+
+	if (vp->capabilities & CapPwrMgmt)
+		acpi_set_WOL(dev);
+}
+
+static int
+vortex_close(struct net_device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int i;
+
+	if (netif_device_present(dev))
+		vortex_down(dev);
+
+	if (vortex_debug > 1) {
+		printk(KERN_DEBUG"%s: vortex_close() status %4.4x, Tx status %2.2x.\n",
+			   dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus));
+		printk(KERN_DEBUG "%s: vortex close stats: rx_nocopy %d rx_copy %d"
+			   " tx_queued %d Rx pre-checksummed %d.\n",
+			   dev->name, rx_nocopy, rx_copy, queued_packet, rx_csumhits);
+	}
+
+	free_irq(dev->irq, dev);
+
+	if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */
 		for (i = 0; i < RX_RING_SIZE; i++)
 			if (vp->rx_skbuff[i]) {
-				pci_unmap_single(vp->pdev, le32_to_cpu(vp->rx_ring[i].addr), PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
-				DEV_FREE_SKB(vp->rx_skbuff[i]);
+				pci_unmap_single(	vp->pdev, le32_to_cpu(vp->rx_ring[i].addr),
+									PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
+				dev_kfree_skb(vp->rx_skbuff[i]);
 				vp->rx_skbuff[i] = 0;
 			}
 	}
 	if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */
-		outl(0, ioaddr + DownListPtr);
 		for (i = 0; i < TX_RING_SIZE; i++)
 			if (vp->tx_skbuff[i]) {
 				struct sk_buff *skb = vp->tx_skbuff[i];
 
 				pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[i].addr), skb->len, PCI_DMA_TODEVICE);
-				DEV_FREE_SKB(skb);
+				dev_kfree_skb(skb);
 				vp->tx_skbuff[i] = 0;
 			}
 	}
 
 	MOD_DEC_USE_COUNT;
-
+	vp->open = 0;
 	return 0;
 }
 
@@ -1853,11 +2117,10 @@
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	unsigned long flags;
 
-	if (netif_running(dev)) {
-		save_flags(flags);
-		cli();
+	if (netif_device_present(dev)) {	/* AKPM: Used to be netif_running */
+		spin_lock_irqsave (&vp->lock, flags);
 		update_stats(dev->base_addr, dev);
-		restore_flags(flags);
+		spin_unlock_irqrestore (&vp->lock, flags);
 	}
 	return &vp->stats;
 }
@@ -1872,7 +2135,10 @@
 static void update_stats(long ioaddr, struct net_device *dev)
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	int old_window = inw(ioaddr + EL3_CMD);
 
+	if (old_window == 0xffff)	/* Chip suspended or ejected. */
+		return;
 	/* Unlike the 3c5x9 we need not turn off stats updates while reading. */
 	/* Switch to the stats window, and read everything. */
 	EL3WINDOW(6);
@@ -1889,14 +2155,21 @@
 	/* Don't bother with register 9, an extension of registers 6&7.
 	   If we do use the 6&7 values the atomic update assumption above
 	   is invalid. */
-	inw(ioaddr + 10);	/* Total Rx and Tx octets. */
-	inw(ioaddr + 12);
+	vp->stats.rx_bytes += inw(ioaddr + 10);
+	vp->stats.tx_bytes += inw(ioaddr + 12);
 	/* New: On the Vortex we must also clear the BadSSD counter. */
 	EL3WINDOW(4);
 	inb(ioaddr + 12);
 
+	{
+		u8 up = inb(ioaddr + 13);
+		vp->stats.rx_bytes += (up & 0x0f) << 16;
+		vp->stats.tx_bytes += (up & 0xf0) << 12;
+	}
+
 	/* We change back to window 7 (not 1) with the Vortex. */
-	EL3WINDOW(7);
+	/* AKPM: the previous comment is obsolete - we switch back to the old window */
+	EL3WINDOW(old_window >> 13);
 	return;
 }
 
@@ -1906,6 +2179,10 @@
 	long ioaddr = dev->base_addr;
 	u16 *data = (u16 *)&rq->ifr_data;
 	int phy = vp->phys[0] & 0x1f;
+	int retval;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vp->lock, flags);
 
 	switch(cmd) {
 	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
@@ -1913,16 +2190,24 @@
 	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
 		EL3WINDOW(4);
 		data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
-		return 0;
+		retval = 0;
+		break;
 	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		EL3WINDOW(4);
-		mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
-		return 0;
+		if (!capable(CAP_NET_ADMIN)) {
+			retval = -EPERM;
+		} else {
+			EL3WINDOW(4);
+			mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+			retval = 0;
+		}
+		break;
 	default:
-		return -EOPNOTSUPP;
+		retval = -EOPNOTSUPP;
+		break;
 	}
+
+	spin_unlock_irqrestore(&vp->lock, flags);
+	return retval;
 }
 
 /* Pre-Cyclone chips have no documented multicast filter, so the only
@@ -1945,7 +2230,6 @@
 	outw(new_mode, ioaddr + EL3_CMD);
 }
 
-
 /* MII transceiver control section.
    Read and write the MII registers using software-generated serial
    MDIO protocol.  See the MII specifications or DP83840A data sheet
@@ -2004,11 +2288,7 @@
 		outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
 		mdio_delay();
 	}
-#if 0
-	return (retval>>1) & 0x1ffff;
-#else
 	return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff;
-#endif
 }
 
 static void mdio_write(long ioaddr, int phy_id, int location, int value)
@@ -2038,42 +2318,131 @@
 
 	return;
 }
+
+/* ACPI: Advanced Configuration and Power Interface. */
+/* Set Wake-On-LAN mode and put the board into D3 (power-down) state. */
+static void acpi_set_WOL(struct net_device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+
+	/* AKPM: This kills the 905 */
+	if (vortex_debug > 0) {
+		printk(KERN_INFO PFX "Wake-on-LAN functions disabled\n");
+	}
+	return;
+
+	/* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */
+	EL3WINDOW(7);
+	outw(2, ioaddr + 0x0c);
+	/* The RxFilter must accept the WOL frames. */
+	outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
+	outw(RxEnable, ioaddr + EL3_CMD);
+	/* Change the power state to D3; RxEnable doesn't take effect. */
+	pci_write_config_word(vp->pdev, 0xe0, 0x8103);
+}
 
 
-static void __exit vortex_cleanup_module (void)
+static void __devexit vortex_remove_one (struct pci_dev *pdev)
 {
-	struct net_device *next_dev;
+	struct net_device *dev = pdev->driver_data;
+	struct vortex_private *vp;
 
-#ifdef CARDBUS
-	unregister_driver(&vortex_ops);
-#endif
+	if (!dev)
+		return;
+
+	vp = (void *)(dev->priv);
 
 	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-	while (root_vortex_dev) {
-		struct vortex_private *vp=(void *)(root_vortex_dev->priv);
-		next_dev = vp->next_module;
-		unregister_netdev(root_vortex_dev);
-		outw(TotalReset, root_vortex_dev->base_addr + EL3_CMD);
-		release_region(root_vortex_dev->base_addr,
-					   pci_tbl[vp->chip_id].io_size);
-		kfree(root_vortex_dev);
-		pci_free_consistent(vp->pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE
-					    + sizeof(struct boom_tx_desc) * TX_RING_SIZE
-					    + 15, vp->rx_ring, vp->rx_ring_dma);
-		kfree(vp);
-		root_vortex_dev = next_dev;
+	unregister_netdev(dev);
+	outw(TotalReset, dev->base_addr + EL3_CMD);
+	release_region(dev->base_addr, vortex_info_tbl[vp->chip_id].io_size);
+	kfree(dev);
+}
+
+
+static struct pci_driver vortex_driver = {
+	name:		"3c575_cb",
+	probe:		vortex_init_one,
+	remove:		vortex_remove_one,
+	suspend:	vortex_suspend,
+	resume:		vortex_resume,
+	id_table:	vortex_pci_tbl,
+};
+
+
+static int vortex_have_pci = 0;
+static int vortex_have_eisa = 0;
+
+
+static int __init vortex_init (void)
+{
+	int rc;
+	
+	MOD_INC_USE_COUNT;
+
+	rc = pci_module_init (&vortex_driver);
+	if (rc < 0)
+		goto out;
+
+	if (rc >= 0)	/* AKPM: had "> 0" */
+		vortex_have_pci = 1;
+
+	rc = vortex_eisa_init ();
+	if (rc < 0)
+		goto out;
+
+	if (rc > 0)
+		vortex_have_eisa = 1;
+
+out:
+	MOD_DEC_USE_COUNT;
+	return rc;
+}
+
+
+static void __exit vortex_eisa_cleanup (void)
+{
+	struct net_device *dev, *tmp;
+	struct vortex_private *vp;
+	long ioaddr;
+
+	dev = root_vortex_eisa_dev;
+
+	while (dev) {
+		vp = dev->priv;
+		ioaddr = dev->base_addr;
+
+		unregister_netdev (dev);
+		outw (TotalReset, ioaddr + EL3_CMD);
+		release_region (ioaddr, VORTEX_TOTAL_SIZE);
+
+		tmp = dev;
+		dev = vp->next_module;
+
+		kfree (tmp);
 	}
 }
 
-module_init(vortex_init_module);
-module_exit(vortex_cleanup_module);
+
+static void __exit vortex_cleanup (void)
+{
+	if (vortex_have_pci)
+		pci_unregister_driver (&vortex_driver);
+	if (vortex_have_eisa)
+		vortex_eisa_cleanup ();
+}
 
 
+module_init(vortex_init);
+module_exit(vortex_cleanup);
+
+
+
 /*
  * Local variables:
  *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c"
- *  cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/pcmcia-cs-3.0.5/include/"
+ *  cardbus-compile-command: "gcc -DCONFIG_HOTPLUG -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/linux/pcmcia-cs-3.0.9/include/"
  *  c-indent-level: 4
  *  c-basic-offset: 4
  *  tab-width: 4

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)