Merge branch 'upstream-fixes' into upstream
diff --git a/Documentation/networking/LICENSE.qla3xxx b/Documentation/networking/LICENSE.qla3xxx
new file mode 100644
index 0000000..2f2077e
--- /dev/null
+++ b/Documentation/networking/LICENSE.qla3xxx
@@ -0,0 +1,46 @@
+Copyright (c)  2003-2006 QLogic Corporation
+QLogic Linux Networking HBA Driver
+
+This program includes a device driver for Linux 2.6 that may be
+distributed with QLogic hardware specific firmware binary file.
+You may modify and redistribute the device driver code under the
+GNU General Public License as published by the Free Software
+Foundation (version 2 or a later version).
+
+You may redistribute the hardware specific firmware binary file
+under the following terms:
+
+	1. Redistribution of source code (only if applicable),
+	   must retain the above copyright notice, this list of
+	   conditions and the following disclaimer.
+
+	2. Redistribution in binary form must reproduce the above
+	   copyright notice, this list of conditions and the
+	   following disclaimer in the documentation and/or other
+	   materials provided with the distribution.
+
+	3. The name of QLogic Corporation may not be used to
+	   endorse or promote products derived from this software
+	   without specific prior written permission
+
+REGARDLESS OF WHAT LICENSING MECHANISM IS USED OR APPLICABLE,
+THIS PROGRAM IS PROVIDED BY QLOGIC CORPORATION "AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+USER ACKNOWLEDGES AND AGREES THAT USE OF THIS PROGRAM WILL NOT
+CREATE OR GIVE GROUNDS FOR A LICENSE BY IMPLICATION, ESTOPPEL, OR
+OTHERWISE IN ANY INTELLECTUAL PROPERTY RIGHTS (PATENT, COPYRIGHT,
+TRADE SECRET, MASK WORK, OR OTHER PROPRIETARY RIGHT) EMBODIED IN
+ANY OTHER QLOGIC HARDWARE OR SOFTWARE EITHER SOLELY OR IN
+COMBINATION WITH THIS PROGRAM.
+
diff --git a/MAINTAINERS b/MAINTAINERS
index 21116cc..d3315a5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2360,6 +2360,12 @@
 L:	linux-scsi@vger.kernel.org
 S:	Supported
 
+QLOGIC QLA3XXX NETWORK DRIVER
+P:	Ron Mercer
+M:	linux-driver@qlogic.com
+L:	netdev@vger.kernel.org
+S:	Supported
+
 QNX4 FILESYSTEM
 P:	Anders Larsen
 M:	al@alarsen.net
@@ -2610,6 +2616,18 @@
 M:	nico@cam.org
 S:	Maintained
 
+SOFTMAC LAYER (IEEE 802.11)
+P:	Johannes Berg
+M:	johannes@sipsolutions.net
+P:	Joe Jezak
+M:	josejx@gentoo.org
+P:	Daniel Drake
+M:	dsd@gentoo.org
+W:	http://softmac.sipsolutions.net/
+L:	softmac-dev@sipsolutions.net
+L:	netdev@vger.kernel.org
+S:	Maintained
+
 SOFTWARE RAID (Multiple Disks) SUPPORT
 P:	Ingo Molnar
 M:	mingo@redhat.com
@@ -3334,6 +3352,15 @@
 L:	linux-hams@vger.kernel.org
 S:	Maintained
 
+ZD1211RW WIRELESS DRIVER
+P:	Daniel Drake
+M:	dsd@gentoo.org
+P:	Ulrich Kunitz
+M:	kune@deine-taler.de
+W:	http://zd1211.ath.cx/wiki/DriverRewrite
+L:	zd1211-devs@lists.sourceforge.net (subscribers-only)
+S:	Maintained
+
 ZF MACHZ WATCHDOG
 P:	Fernando Fuganti
 M:	fuganti@netbank.com.br
diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig
index a4f7288..3ef567b 100644
--- a/drivers/isdn/i4l/Kconfig
+++ b/drivers/isdn/i4l/Kconfig
@@ -5,6 +5,7 @@
 config ISDN_PPP
 	bool "Support synchronous PPP"
 	depends on INET
+	select SLHC
 	help
 	  Over digital connections such as ISDN, there is no need to
 	  synchronize sender and recipient's clocks with start and stop bits
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
index 07136ec..d7b115a 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/3c501.c
@@ -120,7 +120,6 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/errno.h>
-#include <linux/config.h>	/* for CONFIG_IP_MULTICAST */
 #include <linux/spinlock.h>
 #include <linux/ethtool.h>
 #include <linux/delay.h>
diff --git a/drivers/net/8390.c b/drivers/net/8390.c
index d2935ae..3eb7048 100644
--- a/drivers/net/8390.c
+++ b/drivers/net/8390.c
@@ -299,7 +299,7 @@
 	 *	Slow phase with lock held.
 	 */
 	 
-	disable_irq_nosync(dev->irq);
+	disable_irq_nosync_lockdep(dev->irq);
 	
 	spin_lock(&ei_local->page_lock);
 	
@@ -338,7 +338,7 @@
 		netif_stop_queue(dev);
 		outb_p(ENISR_ALL, e8390_base + EN0_IMR);
 		spin_unlock(&ei_local->page_lock);
-		enable_irq(dev->irq);
+		enable_irq_lockdep(dev->irq);
 		ei_local->stat.tx_errors++;
 		return 1;
 	}
@@ -379,7 +379,7 @@
 	outb_p(ENISR_ALL, e8390_base + EN0_IMR);
 	
 	spin_unlock(&ei_local->page_lock);
-	enable_irq(dev->irq);
+	enable_irq_lockdep(dev->irq);
 
 	dev_kfree_skb (skb);
 	ei_local->stat.tx_bytes += send_length;
@@ -505,9 +505,9 @@
 #ifdef CONFIG_NET_POLL_CONTROLLER
 void ei_poll(struct net_device *dev)
 {
-	disable_irq(dev->irq);
+	disable_irq_lockdep(dev->irq);
 	ei_interrupt(dev->irq, dev, NULL);
-	enable_irq(dev->irq);
+	enable_irq_lockdep(dev->irq);
 }
 #endif
 
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 30b3671..6f388d9 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1411,6 +1411,22 @@
 	  <file:Documentation/networking/net-modules.txt>.  The module will be
 	  called forcedeth.
 
+config FORCEDETH_NAPI
+	bool "Use Rx and Tx Polling (NAPI) (EXPERIMENTAL)"
+	depends on FORCEDETH && EXPERIMENTAL
+	help
+	  NAPI is a new driver API designed to reduce CPU and interrupt load
+	  when the driver is receiving lots of packets from the card. It is
+	  still somewhat experimental and thus not yet enabled by default.
+
+	  If your estimated Rx load is 10kpps or more, or if the card will be
+	  deployed on potentially unfriendly networks (e.g. in a firewall),
+	  then say Y here.
+
+	  See <file:Documentation/networking/NAPI_HOWTO.txt> for more
+	  information.
+
+	  If in doubt, say N.
 
 config CS89x0
 	tristate "CS89x0 support"
@@ -2290,6 +2306,15 @@
 	  This enables support for Port 2 of the Marvell MV643XX Gigabit
 	  Ethernet.
 
+config QLA3XXX
+	tristate "QLogic QLA3XXX Network Driver Support"
+	depends on PCI
+	help
+	  This driver supports QLogic ISP3XXX gigabit Ethernet cards.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called qla3xxx.
+
 endmenu
 
 #
@@ -2550,6 +2575,7 @@
 
 config PPP
 	tristate "PPP (point-to-point protocol) support"
+	select SLHC
 	---help---
 	  PPP (Point to Point Protocol) is a newer and better SLIP.  It serves
 	  the same purpose: sending Internet traffic over telephone (and other
@@ -2730,6 +2756,7 @@
 config SLIP_COMPRESSED
 	bool "CSLIP compressed headers"
 	depends on SLIP
+	select SLHC
 	---help---
 	  This protocol is faster than SLIP because it uses compression on the
 	  TCP/IP headers (not on the data itself), but it has to be supported
@@ -2742,6 +2769,12 @@
 	  <http://www.tldp.org/docs.html#howto>, explains how to configure
 	  CSLIP. This won't enlarge your kernel.
 
+config SLHC
+	tristate
+	help
+	  This option enables Van Jacobsen serial line header compression
+	  routines.
+
 config SLIP_SMART
 	bool "Keepalive and linefill"
 	depends on SLIP
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 8427bf9..6ff1764 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -2,10 +2,6 @@
 # Makefile for the Linux network (ethercard) device drivers.
 #
 
-ifeq ($(CONFIG_ISDN_PPP),y)
-  obj-$(CONFIG_ISDN) += slhc.o
-endif
-
 obj-$(CONFIG_E1000) += e1000/
 obj-$(CONFIG_IBM_EMAC) += ibm_emac/
 obj-$(CONFIG_IXGB) += ixgb/
@@ -113,8 +109,9 @@
 obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o
 
 obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o
+obj-$(CONFIG_QLA3XXX) += qla3xxx.o
 
-obj-$(CONFIG_PPP) += ppp_generic.o slhc.o
+obj-$(CONFIG_PPP) += ppp_generic.o
 obj-$(CONFIG_PPP_ASYNC) += ppp_async.o
 obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o
 obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o
@@ -123,9 +120,7 @@
 obj-$(CONFIG_PPPOE) += pppox.o pppoe.o
 
 obj-$(CONFIG_SLIP) += slip.o
-ifeq ($(CONFIG_SLIP_COMPRESSED),y)
-  obj-$(CONFIG_SLIP) += slhc.o
-endif
+obj-$(CONFIG_SLHC) += slhc.o
 
 obj-$(CONFIG_DUMMY) += dummy.o
 obj-$(CONFIG_IFB) += ifb.o
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 11b8f1b..a2aca92 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -109,6 +109,7 @@
  *	0.54: 21 Mar 2006: Fix spin locks for multi irqs and cleanup.
  *	0.55: 22 Mar 2006: Add flow control (pause frame).
  *	0.56: 22 Mar 2006: Additional ethtool config and moduleparam support.
+ *	0.57: 14 May 2006: Mac address set in probe/remove and order corrections.
  *
  * Known bugs:
  * We suspect that on some hardware no TX done interrupts are generated.
@@ -120,7 +121,12 @@
  * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
  * superfluous timer interrupts from the nic.
  */
-#define FORCEDETH_VERSION		"0.56"
+#ifdef CONFIG_FORCEDETH_NAPI
+#define DRIVERNAPI "-NAPI"
+#else
+#define DRIVERNAPI
+#endif
+#define FORCEDETH_VERSION		"0.57"
 #define DRV_NAME			"forcedeth"
 
 #include <linux/module.h>
@@ -262,7 +268,8 @@
 	NvRegRingSizes = 0x108,
 #define NVREG_RINGSZ_TXSHIFT 0
 #define NVREG_RINGSZ_RXSHIFT 16
-	NvRegUnknownTransmitterReg = 0x10c,
+	NvRegTransmitPoll = 0x10c,
+#define NVREG_TRANSMITPOLL_MAC_ADDR_REV	0x00008000
 	NvRegLinkSpeed = 0x110,
 #define NVREG_LINKSPEED_FORCE 0x10000
 #define NVREG_LINKSPEED_10	1000
@@ -381,21 +388,21 @@
 
 /* Big endian: should work, but is untested */
 struct ring_desc {
-	u32 PacketBuffer;
-	u32 FlagLen;
+	__le32 buf;
+	__le32 flaglen;
 };
 
 struct ring_desc_ex {
-	u32 PacketBufferHigh;
-	u32 PacketBufferLow;
-	u32 TxVlan;
-	u32 FlagLen;
+	__le32 bufhigh;
+	__le32 buflow;
+	__le32 txvlan;
+	__le32 flaglen;
 };
 
-typedef union _ring_type {
+union ring_type {
 	struct ring_desc* orig;
 	struct ring_desc_ex* ex;
-} ring_type;
+};
 
 #define FLAG_MASK_V1 0xffff0000
 #define FLAG_MASK_V2 0xffffc000
@@ -653,8 +660,8 @@
 };
 
 struct register_test {
-	u32 reg;
-	u32 mask;
+	__le32 reg;
+	__le32 mask;
 };
 
 static const struct register_test nv_registers_test[] = {
@@ -713,7 +720,7 @@
 	/* rx specific fields.
 	 * Locking: Within irq hander or disable_irq+spin_lock(&np->lock);
 	 */
-	ring_type rx_ring;
+	union ring_type rx_ring;
 	unsigned int cur_rx, refill_rx;
 	struct sk_buff **rx_skbuff;
 	dma_addr_t *rx_dma;
@@ -733,7 +740,7 @@
 	/*
 	 * tx specific fields.
 	 */
-	ring_type tx_ring;
+	union ring_type tx_ring;
 	unsigned int next_tx, nic_tx;
 	struct sk_buff **tx_skbuff;
 	dma_addr_t *tx_dma;
@@ -826,13 +833,13 @@
 
 static inline u32 nv_descr_getlength(struct ring_desc *prd, u32 v)
 {
-	return le32_to_cpu(prd->FlagLen)
+	return le32_to_cpu(prd->flaglen)
 		& ((v == DESC_VER_1) ? LEN_MASK_V1 : LEN_MASK_V2);
 }
 
 static inline u32 nv_descr_getlength_ex(struct ring_desc_ex *prd, u32 v)
 {
-	return le32_to_cpu(prd->FlagLen) & LEN_MASK_V2;
+	return le32_to_cpu(prd->flaglen) & LEN_MASK_V2;
 }
 
 static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target,
@@ -885,7 +892,7 @@
 	struct fe_priv *np = get_nvpriv(dev);
 
 	if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-		if(np->rx_ring.orig)
+		if (np->rx_ring.orig)
 			pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (np->rx_ring_size + np->tx_ring_size),
 					    np->rx_ring.orig, np->ring_addr);
 	} else {
@@ -1178,7 +1185,7 @@
 			KERN_INFO "nv_stop_tx: TransmitterStatus remained busy");
 
 	udelay(NV_TXSTOP_DELAY2);
-	writel(0, base + NvRegUnknownTransmitterReg);
+	writel(readl(base + NvRegTransmitPoll) & NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll);
 }
 
 static void nv_txrx_reset(struct net_device *dev)
@@ -1258,14 +1265,14 @@
 		np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data,
 					skb->end-skb->data, PCI_DMA_FROMDEVICE);
 		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-			np->rx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->rx_dma[nr]);
+			np->rx_ring.orig[nr].buf = cpu_to_le32(np->rx_dma[nr]);
 			wmb();
-			np->rx_ring.orig[nr].FlagLen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL);
+			np->rx_ring.orig[nr].flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL);
 		} else {
-			np->rx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->rx_dma[nr]) >> 32;
-			np->rx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->rx_dma[nr]) & 0x0FFFFFFFF;
+			np->rx_ring.ex[nr].bufhigh = cpu_to_le64(np->rx_dma[nr]) >> 32;
+			np->rx_ring.ex[nr].buflow = cpu_to_le64(np->rx_dma[nr]) & 0x0FFFFFFFF;
 			wmb();
-			np->rx_ring.ex[nr].FlagLen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL);
+			np->rx_ring.ex[nr].flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL);
 		}
 		dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n",
 					dev->name, refill_rx);
@@ -1277,6 +1284,16 @@
 	return 0;
 }
 
+/* If rx bufs are exhausted called after 50ms to attempt to refresh */
+#ifdef CONFIG_FORCEDETH_NAPI
+static void nv_do_rx_refill(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *) data;
+
+	/* Just reschedule NAPI rx processing */
+	netif_rx_schedule(dev);
+}
+#else
 static void nv_do_rx_refill(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *) data;
@@ -1305,6 +1322,7 @@
 		enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
 	}
 }
+#endif
 
 static void nv_init_rx(struct net_device *dev)
 {
@@ -1315,9 +1333,9 @@
 	np->refill_rx = 0;
 	for (i = 0; i < np->rx_ring_size; i++)
 		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
-			np->rx_ring.orig[i].FlagLen = 0;
+			np->rx_ring.orig[i].flaglen = 0;
 	        else
-			np->rx_ring.ex[i].FlagLen = 0;
+			np->rx_ring.ex[i].flaglen = 0;
 }
 
 static void nv_init_tx(struct net_device *dev)
@@ -1328,9 +1346,9 @@
 	np->next_tx = np->nic_tx = 0;
 	for (i = 0; i < np->tx_ring_size; i++) {
 		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
-			np->tx_ring.orig[i].FlagLen = 0;
+			np->tx_ring.orig[i].flaglen = 0;
 	        else
-			np->tx_ring.ex[i].FlagLen = 0;
+			np->tx_ring.ex[i].flaglen = 0;
 		np->tx_skbuff[i] = NULL;
 		np->tx_dma[i] = 0;
 	}
@@ -1373,9 +1391,9 @@
 
 	for (i = 0; i < np->tx_ring_size; i++) {
 		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
-			np->tx_ring.orig[i].FlagLen = 0;
+			np->tx_ring.orig[i].flaglen = 0;
 		else
-			np->tx_ring.ex[i].FlagLen = 0;
+			np->tx_ring.ex[i].flaglen = 0;
 		if (nv_release_txskb(dev, i))
 			np->stats.tx_dropped++;
 	}
@@ -1387,9 +1405,9 @@
 	int i;
 	for (i = 0; i < np->rx_ring_size; i++) {
 		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
-			np->rx_ring.orig[i].FlagLen = 0;
+			np->rx_ring.orig[i].flaglen = 0;
 		else
-			np->rx_ring.ex[i].FlagLen = 0;
+			np->rx_ring.ex[i].flaglen = 0;
 		wmb();
 		if (np->rx_skbuff[i]) {
 			pci_unmap_single(np->pci_dev, np->rx_dma[i],
@@ -1450,17 +1468,17 @@
 		np->tx_dma_len[nr] = bcnt;
 
 		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-			np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
-			np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
+			np->tx_ring.orig[nr].buf = cpu_to_le32(np->tx_dma[nr]);
+			np->tx_ring.orig[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
 		} else {
-			np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
-			np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
-			np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
+			np->tx_ring.ex[nr].bufhigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
+			np->tx_ring.ex[nr].buflow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
+			np->tx_ring.ex[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
 		}
 		tx_flags = np->tx_flags;
 		offset += bcnt;
 		size -= bcnt;
-	} while(size);
+	} while (size);
 
 	/* setup the fragments */
 	for (i = 0; i < fragments; i++) {
@@ -1477,12 +1495,12 @@
 			np->tx_dma_len[nr] = bcnt;
 
 			if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-				np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
-				np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
+				np->tx_ring.orig[nr].buf = cpu_to_le32(np->tx_dma[nr]);
+				np->tx_ring.orig[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
 			} else {
-				np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
-				np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
-				np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
+				np->tx_ring.ex[nr].bufhigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
+				np->tx_ring.ex[nr].buflow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
+				np->tx_ring.ex[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
 			}
 			offset += bcnt;
 			size -= bcnt;
@@ -1491,9 +1509,9 @@
 
 	/* set last fragment flag  */
 	if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-		np->tx_ring.orig[nr].FlagLen |= cpu_to_le32(tx_flags_extra);
+		np->tx_ring.orig[nr].flaglen |= cpu_to_le32(tx_flags_extra);
 	} else {
-		np->tx_ring.ex[nr].FlagLen |= cpu_to_le32(tx_flags_extra);
+		np->tx_ring.ex[nr].flaglen |= cpu_to_le32(tx_flags_extra);
 	}
 
 	np->tx_skbuff[nr] = skb;
@@ -1512,10 +1530,10 @@
 
 	/* set tx flags */
 	if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-		np->tx_ring.orig[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra);
+		np->tx_ring.orig[start_nr].flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
 	} else {
-		np->tx_ring.ex[start_nr].TxVlan = cpu_to_le32(tx_flags_vlan);
-		np->tx_ring.ex[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra);
+		np->tx_ring.ex[start_nr].txvlan = cpu_to_le32(tx_flags_vlan);
+		np->tx_ring.ex[start_nr].flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
 	}
 
 	dprintk(KERN_DEBUG "%s: nv_start_xmit: packet %d (entries %d) queued for transmission. tx_flags_extra: %x\n",
@@ -1547,7 +1565,7 @@
 static void nv_tx_done(struct net_device *dev)
 {
 	struct fe_priv *np = netdev_priv(dev);
-	u32 Flags;
+	u32 flags;
 	unsigned int i;
 	struct sk_buff *skb;
 
@@ -1555,22 +1573,22 @@
 		i = np->nic_tx % np->tx_ring_size;
 
 		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
-			Flags = le32_to_cpu(np->tx_ring.orig[i].FlagLen);
+			flags = le32_to_cpu(np->tx_ring.orig[i].flaglen);
 		else
-			Flags = le32_to_cpu(np->tx_ring.ex[i].FlagLen);
+			flags = le32_to_cpu(np->tx_ring.ex[i].flaglen);
 
-		dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, Flags 0x%x.\n",
-					dev->name, np->nic_tx, Flags);
-		if (Flags & NV_TX_VALID)
+		dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, flags 0x%x.\n",
+					dev->name, np->nic_tx, flags);
+		if (flags & NV_TX_VALID)
 			break;
 		if (np->desc_ver == DESC_VER_1) {
-			if (Flags & NV_TX_LASTPACKET) {
+			if (flags & NV_TX_LASTPACKET) {
 				skb = np->tx_skbuff[i];
-				if (Flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
+				if (flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
 					     NV_TX_UNDERFLOW|NV_TX_ERROR)) {
-					if (Flags & NV_TX_UNDERFLOW)
+					if (flags & NV_TX_UNDERFLOW)
 						np->stats.tx_fifo_errors++;
-					if (Flags & NV_TX_CARRIERLOST)
+					if (flags & NV_TX_CARRIERLOST)
 						np->stats.tx_carrier_errors++;
 					np->stats.tx_errors++;
 				} else {
@@ -1579,13 +1597,13 @@
 				}
 			}
 		} else {
-			if (Flags & NV_TX2_LASTPACKET) {
+			if (flags & NV_TX2_LASTPACKET) {
 				skb = np->tx_skbuff[i];
-				if (Flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION|
+				if (flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION|
 					     NV_TX2_UNDERFLOW|NV_TX2_ERROR)) {
-					if (Flags & NV_TX2_UNDERFLOW)
+					if (flags & NV_TX2_UNDERFLOW)
 						np->stats.tx_fifo_errors++;
-					if (Flags & NV_TX2_CARRIERLOST)
+					if (flags & NV_TX2_CARRIERLOST)
 						np->stats.tx_carrier_errors++;
 					np->stats.tx_errors++;
 				} else {
@@ -1638,29 +1656,29 @@
 			if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
 				printk(KERN_INFO "%03x: %08x %08x // %08x %08x // %08x %08x // %08x %08x\n",
 				       i,
-				       le32_to_cpu(np->tx_ring.orig[i].PacketBuffer),
-				       le32_to_cpu(np->tx_ring.orig[i].FlagLen),
-				       le32_to_cpu(np->tx_ring.orig[i+1].PacketBuffer),
-				       le32_to_cpu(np->tx_ring.orig[i+1].FlagLen),
-				       le32_to_cpu(np->tx_ring.orig[i+2].PacketBuffer),
-				       le32_to_cpu(np->tx_ring.orig[i+2].FlagLen),
-				       le32_to_cpu(np->tx_ring.orig[i+3].PacketBuffer),
-				       le32_to_cpu(np->tx_ring.orig[i+3].FlagLen));
+				       le32_to_cpu(np->tx_ring.orig[i].buf),
+				       le32_to_cpu(np->tx_ring.orig[i].flaglen),
+				       le32_to_cpu(np->tx_ring.orig[i+1].buf),
+				       le32_to_cpu(np->tx_ring.orig[i+1].flaglen),
+				       le32_to_cpu(np->tx_ring.orig[i+2].buf),
+				       le32_to_cpu(np->tx_ring.orig[i+2].flaglen),
+				       le32_to_cpu(np->tx_ring.orig[i+3].buf),
+				       le32_to_cpu(np->tx_ring.orig[i+3].flaglen));
 			} else {
 				printk(KERN_INFO "%03x: %08x %08x %08x // %08x %08x %08x // %08x %08x %08x // %08x %08x %08x\n",
 				       i,
-				       le32_to_cpu(np->tx_ring.ex[i].PacketBufferHigh),
-				       le32_to_cpu(np->tx_ring.ex[i].PacketBufferLow),
-				       le32_to_cpu(np->tx_ring.ex[i].FlagLen),
-				       le32_to_cpu(np->tx_ring.ex[i+1].PacketBufferHigh),
-				       le32_to_cpu(np->tx_ring.ex[i+1].PacketBufferLow),
-				       le32_to_cpu(np->tx_ring.ex[i+1].FlagLen),
-				       le32_to_cpu(np->tx_ring.ex[i+2].PacketBufferHigh),
-				       le32_to_cpu(np->tx_ring.ex[i+2].PacketBufferLow),
-				       le32_to_cpu(np->tx_ring.ex[i+2].FlagLen),
-				       le32_to_cpu(np->tx_ring.ex[i+3].PacketBufferHigh),
-				       le32_to_cpu(np->tx_ring.ex[i+3].PacketBufferLow),
-				       le32_to_cpu(np->tx_ring.ex[i+3].FlagLen));
+				       le32_to_cpu(np->tx_ring.ex[i].bufhigh),
+				       le32_to_cpu(np->tx_ring.ex[i].buflow),
+				       le32_to_cpu(np->tx_ring.ex[i].flaglen),
+				       le32_to_cpu(np->tx_ring.ex[i+1].bufhigh),
+				       le32_to_cpu(np->tx_ring.ex[i+1].buflow),
+				       le32_to_cpu(np->tx_ring.ex[i+1].flaglen),
+				       le32_to_cpu(np->tx_ring.ex[i+2].bufhigh),
+				       le32_to_cpu(np->tx_ring.ex[i+2].buflow),
+				       le32_to_cpu(np->tx_ring.ex[i+2].flaglen),
+				       le32_to_cpu(np->tx_ring.ex[i+3].bufhigh),
+				       le32_to_cpu(np->tx_ring.ex[i+3].buflow),
+				       le32_to_cpu(np->tx_ring.ex[i+3].flaglen));
 			}
 		}
 	}
@@ -1697,7 +1715,7 @@
 	int protolen;	/* length as stored in the proto field */
 
 	/* 1) calculate len according to header */
-	if ( ((struct vlan_ethhdr *)packet)->h_vlan_proto == __constant_htons(ETH_P_8021Q)) {
+	if ( ((struct vlan_ethhdr *)packet)->h_vlan_proto == htons(ETH_P_8021Q)) {
 		protolen = ntohs( ((struct vlan_ethhdr *)packet)->h_vlan_encapsulated_proto );
 		hdrlen = VLAN_HLEN;
 	} else {
@@ -1740,13 +1758,14 @@
 	}
 }
 
-static void nv_rx_process(struct net_device *dev)
+static int nv_rx_process(struct net_device *dev, int limit)
 {
 	struct fe_priv *np = netdev_priv(dev);
-	u32 Flags;
+	u32 flags;
 	u32 vlanflags = 0;
+	int count;
 
-	for (;;) {
+ 	for (count = 0; count < limit; ++count) {
 		struct sk_buff *skb;
 		int len;
 		int i;
@@ -1755,18 +1774,18 @@
 
 		i = np->cur_rx % np->rx_ring_size;
 		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-			Flags = le32_to_cpu(np->rx_ring.orig[i].FlagLen);
+			flags = le32_to_cpu(np->rx_ring.orig[i].flaglen);
 			len = nv_descr_getlength(&np->rx_ring.orig[i], np->desc_ver);
 		} else {
-			Flags = le32_to_cpu(np->rx_ring.ex[i].FlagLen);
+			flags = le32_to_cpu(np->rx_ring.ex[i].flaglen);
 			len = nv_descr_getlength_ex(&np->rx_ring.ex[i], np->desc_ver);
-			vlanflags = le32_to_cpu(np->rx_ring.ex[i].PacketBufferLow);
+			vlanflags = le32_to_cpu(np->rx_ring.ex[i].buflow);
 		}
 
-		dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, Flags 0x%x.\n",
-					dev->name, np->cur_rx, Flags);
+		dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, flags 0x%x.\n",
+					dev->name, np->cur_rx, flags);
 
-		if (Flags & NV_RX_AVAIL)
+		if (flags & NV_RX_AVAIL)
 			break;	/* still owned by hardware, */
 
 		/*
@@ -1780,7 +1799,7 @@
 
 		{
 			int j;
-			dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",Flags);
+			dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",flags);
 			for (j=0; j<64; j++) {
 				if ((j%16) == 0)
 					dprintk("\n%03x:", j);
@@ -1790,30 +1809,30 @@
 		}
 		/* look at what we actually got: */
 		if (np->desc_ver == DESC_VER_1) {
-			if (!(Flags & NV_RX_DESCRIPTORVALID))
+			if (!(flags & NV_RX_DESCRIPTORVALID))
 				goto next_pkt;
 
-			if (Flags & NV_RX_ERROR) {
-				if (Flags & NV_RX_MISSEDFRAME) {
+			if (flags & NV_RX_ERROR) {
+				if (flags & NV_RX_MISSEDFRAME) {
 					np->stats.rx_missed_errors++;
 					np->stats.rx_errors++;
 					goto next_pkt;
 				}
-				if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) {
+				if (flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) {
 					np->stats.rx_errors++;
 					goto next_pkt;
 				}
-				if (Flags & NV_RX_CRCERR) {
+				if (flags & NV_RX_CRCERR) {
 					np->stats.rx_crc_errors++;
 					np->stats.rx_errors++;
 					goto next_pkt;
 				}
-				if (Flags & NV_RX_OVERFLOW) {
+				if (flags & NV_RX_OVERFLOW) {
 					np->stats.rx_over_errors++;
 					np->stats.rx_errors++;
 					goto next_pkt;
 				}
-				if (Flags & NV_RX_ERROR4) {
+				if (flags & NV_RX_ERROR4) {
 					len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
 					if (len < 0) {
 						np->stats.rx_errors++;
@@ -1821,32 +1840,32 @@
 					}
 				}
 				/* framing errors are soft errors. */
-				if (Flags & NV_RX_FRAMINGERR) {
-					if (Flags & NV_RX_SUBSTRACT1) {
+				if (flags & NV_RX_FRAMINGERR) {
+					if (flags & NV_RX_SUBSTRACT1) {
 						len--;
 					}
 				}
 			}
 		} else {
-			if (!(Flags & NV_RX2_DESCRIPTORVALID))
+			if (!(flags & NV_RX2_DESCRIPTORVALID))
 				goto next_pkt;
 
-			if (Flags & NV_RX2_ERROR) {
-				if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) {
+			if (flags & NV_RX2_ERROR) {
+				if (flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) {
 					np->stats.rx_errors++;
 					goto next_pkt;
 				}
-				if (Flags & NV_RX2_CRCERR) {
+				if (flags & NV_RX2_CRCERR) {
 					np->stats.rx_crc_errors++;
 					np->stats.rx_errors++;
 					goto next_pkt;
 				}
-				if (Flags & NV_RX2_OVERFLOW) {
+				if (flags & NV_RX2_OVERFLOW) {
 					np->stats.rx_over_errors++;
 					np->stats.rx_errors++;
 					goto next_pkt;
 				}
-				if (Flags & NV_RX2_ERROR4) {
+				if (flags & NV_RX2_ERROR4) {
 					len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
 					if (len < 0) {
 						np->stats.rx_errors++;
@@ -1854,17 +1873,17 @@
 					}
 				}
 				/* framing errors are soft errors */
-				if (Flags & NV_RX2_FRAMINGERR) {
-					if (Flags & NV_RX2_SUBSTRACT1) {
+				if (flags & NV_RX2_FRAMINGERR) {
+					if (flags & NV_RX2_SUBSTRACT1) {
 						len--;
 					}
 				}
 			}
 			if (np->txrxctl_bits & NVREG_TXRXCTL_RXCHECK) {
-				Flags &= NV_RX2_CHECKSUMMASK;
-				if (Flags == NV_RX2_CHECKSUMOK1 ||
-				    Flags == NV_RX2_CHECKSUMOK2 ||
-				    Flags == NV_RX2_CHECKSUMOK3) {
+				flags &= NV_RX2_CHECKSUMMASK;
+				if (flags == NV_RX2_CHECKSUMOK1 ||
+				    flags == NV_RX2_CHECKSUMOK2 ||
+				    flags == NV_RX2_CHECKSUMOK3) {
 					dprintk(KERN_DEBUG "%s: hw checksum hit!.\n", dev->name);
 					np->rx_skbuff[i]->ip_summed = CHECKSUM_UNNECESSARY;
 				} else {
@@ -1880,17 +1899,27 @@
 		skb->protocol = eth_type_trans(skb, dev);
 		dprintk(KERN_DEBUG "%s: nv_rx_process: packet %d with %d bytes, proto %d accepted.\n",
 					dev->name, np->cur_rx, len, skb->protocol);
-		if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT)) {
-			vlan_hwaccel_rx(skb, np->vlangrp, vlanflags & NV_RX3_VLAN_TAG_MASK);
-		} else {
+#ifdef CONFIG_FORCEDETH_NAPI
+		if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT))
+			vlan_hwaccel_receive_skb(skb, np->vlangrp,
+						 vlanflags & NV_RX3_VLAN_TAG_MASK);
+		else
+			netif_receive_skb(skb);
+#else
+		if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT))
+			vlan_hwaccel_rx(skb, np->vlangrp,
+					vlanflags & NV_RX3_VLAN_TAG_MASK);
+		else
 			netif_rx(skb);
-		}
+#endif
 		dev->last_rx = jiffies;
 		np->stats.rx_packets++;
 		np->stats.rx_bytes += len;
 next_pkt:
 		np->cur_rx++;
 	}
+
+	return count;
 }
 
 static void set_bufsize(struct net_device *dev)
@@ -1990,7 +2019,7 @@
 	struct fe_priv *np = netdev_priv(dev);
 	struct sockaddr *macaddr = (struct sockaddr*)addr;
 
-	if(!is_valid_ether_addr(macaddr->sa_data))
+	if (!is_valid_ether_addr(macaddr->sa_data))
 		return -EADDRNOTAVAIL;
 
 	/* synchronized against open : rtnl_lock() held by caller */
@@ -2283,20 +2312,20 @@
 			lpa_pause = lpa & (LPA_PAUSE_CAP| LPA_PAUSE_ASYM);
 
 			switch (adv_pause) {
-			case (ADVERTISE_PAUSE_CAP):
+			case ADVERTISE_PAUSE_CAP:
 				if (lpa_pause & LPA_PAUSE_CAP) {
 					pause_flags |= NV_PAUSEFRAME_RX_ENABLE;
 					if (np->pause_flags & NV_PAUSEFRAME_TX_REQ)
 						pause_flags |= NV_PAUSEFRAME_TX_ENABLE;
 				}
 				break;
-			case (ADVERTISE_PAUSE_ASYM):
+			case ADVERTISE_PAUSE_ASYM:
 				if (lpa_pause == (LPA_PAUSE_CAP| LPA_PAUSE_ASYM))
 				{
 					pause_flags |= NV_PAUSEFRAME_TX_ENABLE;
 				}
 				break;
-			case (ADVERTISE_PAUSE_CAP| ADVERTISE_PAUSE_ASYM):
+			case ADVERTISE_PAUSE_CAP| ADVERTISE_PAUSE_ASYM:
 				if (lpa_pause & LPA_PAUSE_CAP)
 				{
 					pause_flags |=  NV_PAUSEFRAME_RX_ENABLE;
@@ -2376,14 +2405,6 @@
 		nv_tx_done(dev);
 		spin_unlock(&np->lock);
 
-		nv_rx_process(dev);
-		if (nv_alloc_rx(dev)) {
-			spin_lock(&np->lock);
-			if (!np->in_shutdown)
-				mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
-			spin_unlock(&np->lock);
-		}
-
 		if (events & NVREG_IRQ_LINK) {
 			spin_lock(&np->lock);
 			nv_link_irq(dev);
@@ -2403,6 +2424,29 @@
 			printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",
 						dev->name, events);
 		}
+#ifdef CONFIG_FORCEDETH_NAPI
+		if (events & NVREG_IRQ_RX_ALL) {
+			netif_rx_schedule(dev);
+
+			/* Disable furthur receive irq's */
+			spin_lock(&np->lock);
+			np->irqmask &= ~NVREG_IRQ_RX_ALL;
+
+			if (np->msi_flags & NV_MSI_X_ENABLED)
+				writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
+			else
+				writel(np->irqmask, base + NvRegIrqMask);
+			spin_unlock(&np->lock);
+		}
+#else
+		nv_rx_process(dev, dev->weight);
+		if (nv_alloc_rx(dev)) {
+			spin_lock(&np->lock);
+			if (!np->in_shutdown)
+				mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+			spin_unlock(&np->lock);
+		}
+#endif
 		if (i > max_interrupt_work) {
 			spin_lock(&np->lock);
 			/* disable interrupts on the nic */
@@ -2474,6 +2518,63 @@
 	return IRQ_RETVAL(i);
 }
 
+#ifdef CONFIG_FORCEDETH_NAPI
+static int nv_napi_poll(struct net_device *dev, int *budget)
+{
+	int pkts, limit = min(*budget, dev->quota);
+	struct fe_priv *np = netdev_priv(dev);
+	u8 __iomem *base = get_hwbase(dev);
+
+	pkts = nv_rx_process(dev, limit);
+
+	if (nv_alloc_rx(dev)) {
+		spin_lock_irq(&np->lock);
+		if (!np->in_shutdown)
+			mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+		spin_unlock_irq(&np->lock);
+	}
+
+	if (pkts < limit) {
+		/* all done, no more packets present */
+		netif_rx_complete(dev);
+
+		/* re-enable receive interrupts */
+		spin_lock_irq(&np->lock);
+		np->irqmask |= NVREG_IRQ_RX_ALL;
+		if (np->msi_flags & NV_MSI_X_ENABLED)
+			writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
+		else
+			writel(np->irqmask, base + NvRegIrqMask);
+		spin_unlock_irq(&np->lock);
+		return 0;
+	} else {
+		/* used up our quantum, so reschedule */
+		dev->quota -= pkts;
+		*budget -= pkts;
+		return 1;
+	}
+}
+#endif
+
+#ifdef CONFIG_FORCEDETH_NAPI
+static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *) data;
+	u8 __iomem *base = get_hwbase(dev);
+	u32 events;
+
+	events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_RX_ALL;
+	writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus);
+
+	if (events) {
+		netif_rx_schedule(dev);
+		/* disable receive interrupts on the nic */
+		writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
+		pci_push(base);
+	}
+	return IRQ_HANDLED;
+}
+#else
 static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *) data;
@@ -2492,7 +2593,7 @@
 		if (!(events & np->irqmask))
 			break;
 
-		nv_rx_process(dev);
+		nv_rx_process(dev, dev->weight);
 		if (nv_alloc_rx(dev)) {
 			spin_lock_irq(&np->lock);
 			if (!np->in_shutdown)
@@ -2514,12 +2615,12 @@
 			spin_unlock_irq(&np->lock);
 			break;
 		}
-
 	}
 	dprintk(KERN_DEBUG "%s: nv_nic_irq_rx completed\n", dev->name);
 
 	return IRQ_RETVAL(i);
 }
+#endif
 
 static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs)
 {
@@ -3245,7 +3346,7 @@
 	if (!rxtx_ring || !rx_skbuff || !rx_dma || !tx_skbuff || !tx_dma || !tx_dma_len) {
 		/* fall back to old rings */
 		if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-			if(rxtx_ring)
+			if (rxtx_ring)
 				pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (ring->rx_pending + ring->tx_pending),
 						    rxtx_ring, ring_addr);
 		} else {
@@ -3481,7 +3582,7 @@
 	struct fe_priv *np = netdev_priv(dev);
 
 	if (np->driver_data & DEV_HAS_STATISTICS)
-		return (sizeof(struct nv_ethtool_stats)/sizeof(u64));
+		return sizeof(struct nv_ethtool_stats)/sizeof(u64);
 	else
 		return 0;
 }
@@ -3619,7 +3720,7 @@
 	struct sk_buff *tx_skb, *rx_skb;
 	dma_addr_t test_dma_addr;
 	u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET);
-	u32 Flags;
+	u32 flags;
 	int len, i, pkt_len;
 	u8 *pkt_data;
 	u32 filter_flags = 0;
@@ -3663,12 +3764,12 @@
 				       tx_skb->end-tx_skb->data, PCI_DMA_FROMDEVICE);
 
 	if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-		np->tx_ring.orig[0].PacketBuffer = cpu_to_le32(test_dma_addr);
-		np->tx_ring.orig[0].FlagLen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra);
+		np->tx_ring.orig[0].buf = cpu_to_le32(test_dma_addr);
+		np->tx_ring.orig[0].flaglen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra);
 	} else {
-		np->tx_ring.ex[0].PacketBufferHigh = cpu_to_le64(test_dma_addr) >> 32;
-		np->tx_ring.ex[0].PacketBufferLow = cpu_to_le64(test_dma_addr) & 0x0FFFFFFFF;
-		np->tx_ring.ex[0].FlagLen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra);
+		np->tx_ring.ex[0].bufhigh = cpu_to_le64(test_dma_addr) >> 32;
+		np->tx_ring.ex[0].buflow = cpu_to_le64(test_dma_addr) & 0x0FFFFFFFF;
+		np->tx_ring.ex[0].flaglen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra);
 	}
 	writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
 	pci_push(get_hwbase(dev));
@@ -3677,21 +3778,21 @@
 
 	/* check for rx of the packet */
 	if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-		Flags = le32_to_cpu(np->rx_ring.orig[0].FlagLen);
+		flags = le32_to_cpu(np->rx_ring.orig[0].flaglen);
 		len = nv_descr_getlength(&np->rx_ring.orig[0], np->desc_ver);
 
 	} else {
-		Flags = le32_to_cpu(np->rx_ring.ex[0].FlagLen);
+		flags = le32_to_cpu(np->rx_ring.ex[0].flaglen);
 		len = nv_descr_getlength_ex(&np->rx_ring.ex[0], np->desc_ver);
 	}
 
-	if (Flags & NV_RX_AVAIL) {
+	if (flags & NV_RX_AVAIL) {
 		ret = 0;
 	} else if (np->desc_ver == DESC_VER_1) {
-		if (Flags & NV_RX_ERROR)
+		if (flags & NV_RX_ERROR)
 			ret = 0;
 	} else {
-		if (Flags & NV_RX2_ERROR) {
+		if (flags & NV_RX2_ERROR) {
 			ret = 0;
 		}
 	}
@@ -3753,6 +3854,7 @@
 	if (test->flags & ETH_TEST_FL_OFFLINE) {
 		if (netif_running(dev)) {
 			netif_stop_queue(dev);
+			netif_poll_disable(dev);
 			netif_tx_lock_bh(dev);
 			spin_lock_irq(&np->lock);
 			nv_disable_hw_interrupts(dev, np->irqmask);
@@ -3811,6 +3913,7 @@
 			nv_start_rx(dev);
 			nv_start_tx(dev);
 			netif_start_queue(dev);
+			netif_poll_enable(dev);
 			nv_enable_hw_interrupts(dev, np->irqmask);
 		}
 	}
@@ -3895,10 +3998,9 @@
 
 	dprintk(KERN_DEBUG "nv_open: begin\n");
 
-	/* 1) erase previous misconfiguration */
+	/* erase previous misconfiguration */
 	if (np->driver_data & DEV_HAS_POWER_CNTRL)
 		nv_mac_reset(dev);
-	/* 4.1-1: stop adapter: ignored, 4.3 seems to be overkill */
 	writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA);
 	writel(0, base + NvRegMulticastAddrB);
 	writel(0, base + NvRegMulticastMaskA);
@@ -3913,26 +4015,22 @@
 	if (np->pause_flags & NV_PAUSEFRAME_TX_CAPABLE)
 		writel(NVREG_TX_PAUSEFRAME_DISABLE,  base + NvRegTxPauseFrame);
 
-	/* 2) initialize descriptor rings */
+	/* initialize descriptor rings */
 	set_bufsize(dev);
 	oom = nv_init_ring(dev);
 
 	writel(0, base + NvRegLinkSpeed);
-	writel(0, base + NvRegUnknownTransmitterReg);
+	writel(readl(base + NvRegTransmitPoll) & NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll);
 	nv_txrx_reset(dev);
 	writel(0, base + NvRegUnknownSetupReg6);
 
 	np->in_shutdown = 0;
 
-	/* 3) set mac address */
-	nv_copy_mac_to_hw(dev);
-
-	/* 4) give hw rings */
+	/* give hw rings */
 	setup_hw_rings(dev, NV_SETUP_RX_RING | NV_SETUP_TX_RING);
 	writel( ((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT),
 		base + NvRegRingSizes);
 
-	/* 5) continue setup */
 	writel(np->linkspeed, base + NvRegLinkSpeed);
 	if (np->desc_ver == DESC_VER_1)
 		writel(NVREG_TX_WM_DESC1_DEFAULT, base + NvRegTxWatermark);
@@ -3950,7 +4048,6 @@
 	writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
 	writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus);
 
-	/* 6) continue setup */
 	writel(NVREG_MISC1_FORCE | NVREG_MISC1_HD, base + NvRegMisc1);
 	writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus);
 	writel(NVREG_PFF_ALWAYS, base + NvRegPacketFilterFlags);
@@ -4020,6 +4117,8 @@
 	nv_start_rx(dev);
 	nv_start_tx(dev);
 	netif_start_queue(dev);
+	netif_poll_enable(dev);
+
 	if (ret) {
 		netif_carrier_on(dev);
 	} else {
@@ -4049,6 +4148,7 @@
 	spin_lock_irq(&np->lock);
 	np->in_shutdown = 1;
 	spin_unlock_irq(&np->lock);
+	netif_poll_disable(dev);
 	synchronize_irq(dev->irq);
 
 	del_timer_sync(&np->oom_kick);
@@ -4076,12 +4176,6 @@
 	if (np->wolenabled)
 		nv_start_rx(dev);
 
-	/* special op: write back the misordered MAC address - otherwise
-	 * the next nv_probe would see a wrong address.
-	 */
-	writel(np->orig_mac[0], base + NvRegMacAddrA);
-	writel(np->orig_mac[1], base + NvRegMacAddrB);
-
 	/* FIXME: power down nic */
 
 	return 0;
@@ -4094,7 +4188,7 @@
 	unsigned long addr;
 	u8 __iomem *base;
 	int err, i;
-	u32 powerstate;
+	u32 powerstate, txreg;
 
 	dev = alloc_etherdev(sizeof(struct fe_priv));
 	err = -ENOMEM;
@@ -4270,6 +4364,10 @@
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	dev->poll_controller = nv_poll_controller;
 #endif
+	dev->weight = 64;
+#ifdef CONFIG_FORCEDETH_NAPI
+	dev->poll = nv_napi_poll;
+#endif
 	SET_ETHTOOL_OPS(dev, &ops);
 	dev->tx_timeout = nv_tx_timeout;
 	dev->watchdog_timeo = NV_WATCHDOG_TIMEO;
@@ -4281,12 +4379,30 @@
 	np->orig_mac[0] = readl(base + NvRegMacAddrA);
 	np->orig_mac[1] = readl(base + NvRegMacAddrB);
 
-	dev->dev_addr[0] = (np->orig_mac[1] >>  8) & 0xff;
-	dev->dev_addr[1] = (np->orig_mac[1] >>  0) & 0xff;
-	dev->dev_addr[2] = (np->orig_mac[0] >> 24) & 0xff;
-	dev->dev_addr[3] = (np->orig_mac[0] >> 16) & 0xff;
-	dev->dev_addr[4] = (np->orig_mac[0] >>  8) & 0xff;
-	dev->dev_addr[5] = (np->orig_mac[0] >>  0) & 0xff;
+	/* check the workaround bit for correct mac address order */
+	txreg = readl(base + NvRegTransmitPoll);
+	if (txreg & NVREG_TRANSMITPOLL_MAC_ADDR_REV) {
+		/* mac address is already in correct order */
+		dev->dev_addr[0] = (np->orig_mac[0] >>  0) & 0xff;
+		dev->dev_addr[1] = (np->orig_mac[0] >>  8) & 0xff;
+		dev->dev_addr[2] = (np->orig_mac[0] >> 16) & 0xff;
+		dev->dev_addr[3] = (np->orig_mac[0] >> 24) & 0xff;
+		dev->dev_addr[4] = (np->orig_mac[1] >>  0) & 0xff;
+		dev->dev_addr[5] = (np->orig_mac[1] >>  8) & 0xff;
+	} else {
+		/* need to reverse mac address to correct order */
+		dev->dev_addr[0] = (np->orig_mac[1] >>  8) & 0xff;
+		dev->dev_addr[1] = (np->orig_mac[1] >>  0) & 0xff;
+		dev->dev_addr[2] = (np->orig_mac[0] >> 24) & 0xff;
+		dev->dev_addr[3] = (np->orig_mac[0] >> 16) & 0xff;
+		dev->dev_addr[4] = (np->orig_mac[0] >>  8) & 0xff;
+		dev->dev_addr[5] = (np->orig_mac[0] >>  0) & 0xff;
+		/* set permanent address to be correct aswell */
+		np->orig_mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) +
+			(dev->dev_addr[2] << 16) + (dev->dev_addr[3] << 24);
+		np->orig_mac[1] = (dev->dev_addr[4] << 0) + (dev->dev_addr[5] << 8);
+		writel(txreg|NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll);
+	}
 	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
 	if (!is_valid_ether_addr(dev->perm_addr)) {
@@ -4309,6 +4425,9 @@
 			dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
 			dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
 
+	/* set mac address */
+	nv_copy_mac_to_hw(dev);
+
 	/* disable WOL */
 	writel(0, base + NvRegWakeUpFlags);
 	np->wolenabled = 0;
@@ -4421,9 +4540,17 @@
 static void __devexit nv_remove(struct pci_dev *pci_dev)
 {
 	struct net_device *dev = pci_get_drvdata(pci_dev);
+	struct fe_priv *np = netdev_priv(dev);
+	u8 __iomem *base = get_hwbase(dev);
 
 	unregister_netdev(dev);
 
+	/* special op: write back the misordered MAC address - otherwise
+	 * the next nv_probe would see a wrong address.
+	 */
+	writel(np->orig_mac[0], base + NvRegMacAddrA);
+	writel(np->orig_mac[1], base + NvRegMacAddrB);
+
 	/* free all structures */
 	free_rings(dev);
 	iounmap(get_hwbase(dev));
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index e7d9bf3..ff5a67d 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -111,7 +111,6 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/types.h>
-#include <linux/config.h>	/* for CONFIG_PCI */
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/bitops.h>
diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c
index 47f6f64..415ba8d 100644
--- a/drivers/net/irda/mcs7780.c
+++ b/drivers/net/irda/mcs7780.c
@@ -45,7 +45,6 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/errno.h>
diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c
index 0ea65c4..b69776e 100644
--- a/drivers/net/irda/w83977af_ir.c
+++ b/drivers/net/irda/w83977af_ir.c
@@ -40,7 +40,6 @@
  ********************************************************************/
 
 #include <linux/module.h>
-#include <linux/config.h> 
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/skbuff.h>
diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c
index b1311ae..30ed9a5 100644
--- a/drivers/net/netx-eth.c
+++ b/drivers/net/netx-eth.c
@@ -17,7 +17,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index 0ecebfc..cc0dcc9 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -654,11 +654,8 @@
     SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 
     if (info->flags & (IS_DL10019|IS_DL10022)) {
-	u_char id = inb(dev->base_addr + 0x1a);
 	dev->do_ioctl = &ei_ioctl;
 	mii_phy_probe(dev);
-	if ((id == 0x30) && !info->pna_phy && (info->eth_phy == 4))
-	    info->eth_phy = 0;
     }
 
     link->dev_node = &info->node;
@@ -821,15 +818,6 @@
     }
 }
 
-static void mdio_reset(kio_addr_t addr, int phy_id)
-{
-    outb_p(0x08, addr);
-    outb_p(0x0c, addr);
-    outb_p(0x08, addr);
-    outb_p(0x0c, addr);
-    outb_p(0x00, addr);
-}
-
 /*======================================================================
 
     EEPROM access routines for DL10019 and DL10022 based cards
@@ -942,7 +930,8 @@
     }
     if (info->flags & IS_DL10022) {
 	if (info->flags & HAS_MII) {
-	    mdio_reset(nic_base + DLINK_GPIO, info->eth_phy);
+	    /* Advertise 100F, 100H, 10F, 10H */
+	    mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 4, 0x01e1);
 	    /* Restart MII autonegotiation */
 	    mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x0000);
 	    mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x1200);
diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c
index 25e31fb..b1d8ed4 100644
--- a/drivers/net/phy/smsc.c
+++ b/drivers/net/phy/smsc.c
@@ -14,7 +14,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mii.h>
diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c
index ffd215d..792716b 100644
--- a/drivers/net/phy/vitesse.c
+++ b/drivers/net/phy/vitesse.c
@@ -12,7 +12,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mii.h>
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
new file mode 100644
index 0000000..c729aee
--- /dev/null
+++ b/drivers/net/qla3xxx.c
@@ -0,0 +1,3537 @@
+/*
+ * QLogic QLA3xxx NIC HBA Driver
+ * Copyright (c)  2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla3xxx for copyright and licensing details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/dmapool.h>
+#include <linux/mempool.h>
+#include <linux/spinlock.h>
+#include <linux/kthread.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/ip.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <linux/if_vlan.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+
+#include "qla3xxx.h"
+
+#define DRV_NAME  	"qla3xxx"
+#define DRV_STRING 	"QLogic ISP3XXX Network Driver"
+#define DRV_VERSION	"v2.02.00-k36"
+#define PFX		DRV_NAME " "
+
+static const char ql3xxx_driver_name[] = DRV_NAME;
+static const char ql3xxx_driver_version[] = DRV_VERSION;
+
+MODULE_AUTHOR("QLogic Corporation");
+MODULE_DESCRIPTION("QLogic ISP3XXX Network Driver " DRV_VERSION " ");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+static const u32 default_msg
+    = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK
+    | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN;
+
+static int debug = -1;		/* defaults above */
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+
+static int msi;
+module_param(msi, int, 0);
+MODULE_PARM_DESC(msi, "Turn on Message Signaled Interrupts.");
+
+static struct pci_device_id ql3xxx_pci_tbl[] __devinitdata = {
+	{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QL3022_DEVICE_ID)},
+	/* required last entry */
+	{0,}
+};
+
+MODULE_DEVICE_TABLE(pci, ql3xxx_pci_tbl);
+
+/*
+ * Caller must take hw_lock.
+ */
+static int ql_sem_spinlock(struct ql3_adapter *qdev,
+			    u32 sem_mask, u32 sem_bits)
+{
+	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	u32 value;
+	unsigned int seconds = 3;
+
+	do {
+		writel((sem_mask | sem_bits),
+		       &port_regs->CommonRegs.semaphoreReg);
+		value = readl(&port_regs->CommonRegs.semaphoreReg);
+		if ((value & (sem_mask >> 16)) == sem_bits)
+			return 0;
+		ssleep(1);
+	} while(--seconds);
+	return -1;
+}
+
+static void ql_sem_unlock(struct ql3_adapter *qdev, u32 sem_mask)
+{
+	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	writel(sem_mask, &port_regs->CommonRegs.semaphoreReg);
+	readl(&port_regs->CommonRegs.semaphoreReg);
+}
+
+static int ql_sem_lock(struct ql3_adapter *qdev, u32 sem_mask, u32 sem_bits)
+{
+	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	u32 value;
+
+	writel((sem_mask | sem_bits), &port_regs->CommonRegs.semaphoreReg);
+	value = readl(&port_regs->CommonRegs.semaphoreReg);
+	return ((value & (sem_mask >> 16)) == sem_bits);
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static int ql_wait_for_drvr_lock(struct ql3_adapter *qdev)
+{
+	int i = 0;
+
+	while (1) {
+		if (!ql_sem_lock(qdev,
+				 QL_DRVR_SEM_MASK,
+				 (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index)
+				  * 2) << 1)) {
+			if (i < 10) {
+				ssleep(1);
+				i++;
+			} else {
+				printk(KERN_ERR PFX "%s: Timed out waiting for "
+				       "driver lock...\n",
+				       qdev->ndev->name);
+				return 0;
+			}
+		} else {
+			printk(KERN_DEBUG PFX
+			       "%s: driver lock acquired.\n",
+			       qdev->ndev->name);
+			return 1;
+		}
+	}
+}
+
+static void ql_set_register_page(struct ql3_adapter *qdev, u32 page)
+{
+	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+
+	writel(((ISP_CONTROL_NP_MASK << 16) | page),
+			&port_regs->CommonRegs.ispControlStatus);
+	readl(&port_regs->CommonRegs.ispControlStatus);
+	qdev->current_page = page;
+}
+
+static u32 ql_read_common_reg_l(struct ql3_adapter *qdev,
+			      u32 __iomem * reg)
+{
+	u32 value;
+	unsigned long hw_flags;
+
+	spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+	value = readl(reg);
+	spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+
+	return value;
+}
+
+static u32 ql_read_common_reg(struct ql3_adapter *qdev,
+			      u32 __iomem * reg)
+{
+	return readl(reg);
+}
+
+static u32 ql_read_page0_reg_l(struct ql3_adapter *qdev, u32 __iomem *reg)
+{
+	u32 value;
+	unsigned long hw_flags;
+
+	spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+
+	if (qdev->current_page != 0)
+		ql_set_register_page(qdev,0);
+	value = readl(reg);
+
+	spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+	return value;
+}
+
+static u32 ql_read_page0_reg(struct ql3_adapter *qdev, u32 __iomem *reg)
+{
+	if (qdev->current_page != 0)
+		ql_set_register_page(qdev,0);
+	return readl(reg);
+}
+
+static void ql_write_common_reg_l(struct ql3_adapter *qdev,
+				u32 * reg, u32 value)
+{
+	unsigned long hw_flags;
+
+	spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+	writel(value, (u32 *) reg);
+	readl(reg);
+	spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+	return;
+}
+
+static void ql_write_common_reg(struct ql3_adapter *qdev,
+				u32 * reg, u32 value)
+{
+	writel(value, (u32 *) reg);
+	readl(reg);
+	return;
+}
+
+static void ql_write_page0_reg(struct ql3_adapter *qdev,
+			       u32 * reg, u32 value)
+{
+	if (qdev->current_page != 0)
+		ql_set_register_page(qdev,0);
+	writel(value, (u32 *) reg);
+	readl(reg);
+	return;
+}
+
+/*
+ * Caller holds hw_lock. Only called during init.
+ */
+static void ql_write_page1_reg(struct ql3_adapter *qdev,
+			       u32 * reg, u32 value)
+{
+	if (qdev->current_page != 1)
+		ql_set_register_page(qdev,1);
+	writel(value, (u32 *) reg);
+	readl(reg);
+	return;
+}
+
+/*
+ * Caller holds hw_lock. Only called during init.
+ */
+static void ql_write_page2_reg(struct ql3_adapter *qdev,
+			       u32 * reg, u32 value)
+{
+	if (qdev->current_page != 2)
+		ql_set_register_page(qdev,2);
+	writel(value, (u32 *) reg);
+	readl(reg);
+	return;
+}
+
+static void ql_disable_interrupts(struct ql3_adapter *qdev)
+{
+	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+
+	ql_write_common_reg_l(qdev, &port_regs->CommonRegs.ispInterruptMaskReg,
+			    (ISP_IMR_ENABLE_INT << 16));
+
+}
+
+static void ql_enable_interrupts(struct ql3_adapter *qdev)
+{
+	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+
+	ql_write_common_reg_l(qdev, &port_regs->CommonRegs.ispInterruptMaskReg,
+			    ((0xff << 16) | ISP_IMR_ENABLE_INT));
+
+}
+
+static void ql_release_to_lrg_buf_free_list(struct ql3_adapter *qdev,
+					    struct ql_rcv_buf_cb *lrg_buf_cb)
+{
+	u64 map;
+	lrg_buf_cb->next = NULL;
+
+	if (qdev->lrg_buf_free_tail == NULL) {	/* The list is empty  */
+		qdev->lrg_buf_free_head = qdev->lrg_buf_free_tail = lrg_buf_cb;
+	} else {
+		qdev->lrg_buf_free_tail->next = lrg_buf_cb;
+		qdev->lrg_buf_free_tail = lrg_buf_cb;
+	}
+
+	if (!lrg_buf_cb->skb) {
+		lrg_buf_cb->skb = dev_alloc_skb(qdev->lrg_buffer_len);
+		if (unlikely(!lrg_buf_cb->skb)) {
+			printk(KERN_ERR PFX "%s: failed dev_alloc_skb().\n",
+			       qdev->ndev->name);
+			qdev->lrg_buf_skb_check++;
+		} else {
+			/*
+			 * We save some space to copy the ethhdr from first
+			 * buffer
+			 */
+			skb_reserve(lrg_buf_cb->skb, QL_HEADER_SPACE);
+			map = pci_map_single(qdev->pdev,
+					     lrg_buf_cb->skb->data,
+					     qdev->lrg_buffer_len -
+					     QL_HEADER_SPACE,
+					     PCI_DMA_FROMDEVICE);
+			lrg_buf_cb->buf_phy_addr_low =
+			    cpu_to_le32(LS_64BITS(map));
+			lrg_buf_cb->buf_phy_addr_high =
+			    cpu_to_le32(MS_64BITS(map));
+			pci_unmap_addr_set(lrg_buf_cb, mapaddr, map);
+			pci_unmap_len_set(lrg_buf_cb, maplen,
+					  qdev->lrg_buffer_len -
+					  QL_HEADER_SPACE);
+		}
+	}
+
+	qdev->lrg_buf_free_count++;
+}
+
+static struct ql_rcv_buf_cb *ql_get_from_lrg_buf_free_list(struct ql3_adapter
+							   *qdev)
+{
+	struct ql_rcv_buf_cb *lrg_buf_cb;
+
+	if ((lrg_buf_cb = qdev->lrg_buf_free_head) != NULL) {
+		if ((qdev->lrg_buf_free_head = lrg_buf_cb->next) == NULL)
+			qdev->lrg_buf_free_tail = NULL;
+		qdev->lrg_buf_free_count--;
+	}
+
+	return lrg_buf_cb;
+}
+
+static u32 addrBits = EEPROM_NO_ADDR_BITS;
+static u32 dataBits = EEPROM_NO_DATA_BITS;
+
+static void fm93c56a_deselect(struct ql3_adapter *qdev);
+static void eeprom_readword(struct ql3_adapter *qdev, u32 eepromAddr,
+			    unsigned short *value);
+
+/*
+ * Caller holds hw_lock.
+ */
+static void fm93c56a_select(struct ql3_adapter *qdev)
+{
+	struct ql3xxx_port_registers __iomem *port_regs =
+	    		qdev->mem_map_registers;
+
+	qdev->eeprom_cmd_data = AUBURN_EEPROM_CS_1;
+	ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+			    ISP_NVRAM_MASK | qdev->eeprom_cmd_data);
+	ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+			    ((ISP_NVRAM_MASK << 16) | qdev->eeprom_cmd_data));
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static void fm93c56a_cmd(struct ql3_adapter *qdev, u32 cmd, u32 eepromAddr)
+{
+	int i;
+	u32 mask;
+	u32 dataBit;
+	u32 previousBit;
+	struct ql3xxx_port_registers __iomem *port_regs =
+	    		qdev->mem_map_registers;
+
+	/* Clock in a zero, then do the start bit */
+	ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+			    ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
+			    AUBURN_EEPROM_DO_1);
+	ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+			    ISP_NVRAM_MASK | qdev->
+			    eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
+			    AUBURN_EEPROM_CLK_RISE);
+	ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+			    ISP_NVRAM_MASK | qdev->
+			    eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
+			    AUBURN_EEPROM_CLK_FALL);
+
+	mask = 1 << (FM93C56A_CMD_BITS - 1);
+	/* Force the previous data bit to be different */
+	previousBit = 0xffff;
+	for (i = 0; i < FM93C56A_CMD_BITS; i++) {
+		dataBit =
+		    (cmd & mask) ? AUBURN_EEPROM_DO_1 : AUBURN_EEPROM_DO_0;
+		if (previousBit != dataBit) {
+			/*
+			 * If the bit changed, then change the DO state to
+			 * match
+			 */
+			ql_write_common_reg(qdev,
+					    &port_regs->CommonRegs.
+					    serialPortInterfaceReg,
+					    ISP_NVRAM_MASK | qdev->
+					    eeprom_cmd_data | dataBit);
+			previousBit = dataBit;
+		}
+		ql_write_common_reg(qdev,
+				    &port_regs->CommonRegs.
+				    serialPortInterfaceReg,
+				    ISP_NVRAM_MASK | qdev->
+				    eeprom_cmd_data | dataBit |
+				    AUBURN_EEPROM_CLK_RISE);
+		ql_write_common_reg(qdev,
+				    &port_regs->CommonRegs.
+				    serialPortInterfaceReg,
+				    ISP_NVRAM_MASK | qdev->
+				    eeprom_cmd_data | dataBit |
+				    AUBURN_EEPROM_CLK_FALL);
+		cmd = cmd << 1;
+	}
+
+	mask = 1 << (addrBits - 1);
+	/* Force the previous data bit to be different */
+	previousBit = 0xffff;
+	for (i = 0; i < addrBits; i++) {
+		dataBit =
+		    (eepromAddr & mask) ? AUBURN_EEPROM_DO_1 :
+		    AUBURN_EEPROM_DO_0;
+		if (previousBit != dataBit) {
+			/*
+			 * If the bit changed, then change the DO state to
+			 * match
+			 */
+			ql_write_common_reg(qdev,
+					    &port_regs->CommonRegs.
+					    serialPortInterfaceReg,
+					    ISP_NVRAM_MASK | qdev->
+					    eeprom_cmd_data | dataBit);
+			previousBit = dataBit;
+		}
+		ql_write_common_reg(qdev,
+				    &port_regs->CommonRegs.
+				    serialPortInterfaceReg,
+				    ISP_NVRAM_MASK | qdev->
+				    eeprom_cmd_data | dataBit |
+				    AUBURN_EEPROM_CLK_RISE);
+		ql_write_common_reg(qdev,
+				    &port_regs->CommonRegs.
+				    serialPortInterfaceReg,
+				    ISP_NVRAM_MASK | qdev->
+				    eeprom_cmd_data | dataBit |
+				    AUBURN_EEPROM_CLK_FALL);
+		eepromAddr = eepromAddr << 1;
+	}
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static void fm93c56a_deselect(struct ql3_adapter *qdev)
+{
+	struct ql3xxx_port_registers __iomem *port_regs =
+	    		qdev->mem_map_registers;
+	qdev->eeprom_cmd_data = AUBURN_EEPROM_CS_0;
+	ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+			    ISP_NVRAM_MASK | qdev->eeprom_cmd_data);
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static void fm93c56a_datain(struct ql3_adapter *qdev, unsigned short *value)
+{
+	int i;
+	u32 data = 0;
+	u32 dataBit;
+	struct ql3xxx_port_registers __iomem *port_regs =
+	    		qdev->mem_map_registers;
+
+	/* Read the data bits */
+	/* The first bit is a dummy.  Clock right over it. */
+	for (i = 0; i < dataBits; i++) {
+		ql_write_common_reg(qdev,
+				    &port_regs->CommonRegs.
+				    serialPortInterfaceReg,
+				    ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
+				    AUBURN_EEPROM_CLK_RISE);
+		ql_write_common_reg(qdev,
+				    &port_regs->CommonRegs.
+				    serialPortInterfaceReg,
+				    ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
+				    AUBURN_EEPROM_CLK_FALL);
+		dataBit =
+		    (ql_read_common_reg
+		     (qdev,
+		      &port_regs->CommonRegs.
+		      serialPortInterfaceReg) & AUBURN_EEPROM_DI_1) ? 1 : 0;
+		data = (data << 1) | dataBit;
+	}
+	*value = (u16) data;
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static void eeprom_readword(struct ql3_adapter *qdev,
+			    u32 eepromAddr, unsigned short *value)
+{
+	fm93c56a_select(qdev);
+	fm93c56a_cmd(qdev, (int)FM93C56A_READ, eepromAddr);
+	fm93c56a_datain(qdev, value);
+	fm93c56a_deselect(qdev);
+}
+
+static void ql_swap_mac_addr(u8 * macAddress)
+{
+#ifdef __BIG_ENDIAN
+	u8 temp;
+	temp = macAddress[0];
+	macAddress[0] = macAddress[1];
+	macAddress[1] = temp;
+	temp = macAddress[2];
+	macAddress[2] = macAddress[3];
+	macAddress[3] = temp;
+	temp = macAddress[4];
+	macAddress[4] = macAddress[5];
+	macAddress[5] = temp;
+#endif
+}
+
+static int ql_get_nvram_params(struct ql3_adapter *qdev)
+{
+	u16 *pEEPROMData;
+	u16 checksum = 0;
+	u32 index;
+	unsigned long hw_flags;
+
+	spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+
+	pEEPROMData = (u16 *) & qdev->nvram_data;
+	qdev->eeprom_cmd_data = 0;
+	if(ql_sem_spinlock(qdev, QL_NVRAM_SEM_MASK,
+			(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
+			 2) << 10)) {
+		printk(KERN_ERR PFX"%s: Failed ql_sem_spinlock().\n",
+			__func__);
+		spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+		return -1;
+	}
+
+	for (index = 0; index < EEPROM_SIZE; index++) {
+		eeprom_readword(qdev, index, pEEPROMData);
+		checksum += *pEEPROMData;
+		pEEPROMData++;
+	}
+	ql_sem_unlock(qdev, QL_NVRAM_SEM_MASK);
+
+	if (checksum != 0) {
+		printk(KERN_ERR PFX "%s: checksum should be zero, is %x!!\n",
+		       qdev->ndev->name, checksum);
+		spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+		return -1;
+	}
+
+	/*
+	 * We have a problem with endianness for the MAC addresses
+	 * and the two 8-bit values version, and numPorts.  We
+	 * have to swap them on big endian systems.
+	 */
+	ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn0.macAddress);
+	ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn1.macAddress);
+	ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn2.macAddress);
+	ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn3.macAddress);
+	pEEPROMData = (u16 *) & qdev->nvram_data.version;
+	*pEEPROMData = le16_to_cpu(*pEEPROMData);
+
+	spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+	return checksum;
+}
+
+static const u32 PHYAddr[2] = {
+	PORT0_PHY_ADDRESS, PORT1_PHY_ADDRESS
+};
+
+static int ql_wait_for_mii_ready(struct ql3_adapter *qdev)
+{
+	struct ql3xxx_port_registers __iomem *port_regs =
+	    		qdev->mem_map_registers;
+	u32 temp;
+	int count = 1000;
+
+	while (count) {
+		temp = ql_read_page0_reg(qdev, &port_regs->macMIIStatusReg);
+		if (!(temp & MAC_MII_STATUS_BSY))
+			return 0;
+		udelay(10);
+		count--;
+	}
+	return -1;
+}
+
+static void ql_mii_enable_scan_mode(struct ql3_adapter *qdev)
+{
+	struct ql3xxx_port_registers __iomem *port_regs =
+	    		qdev->mem_map_registers;
+	u32 scanControl;
+
+	if (qdev->numPorts > 1) {
+		/* Auto scan will cycle through multiple ports */
+		scanControl = MAC_MII_CONTROL_AS | MAC_MII_CONTROL_SC;
+	} else {
+		scanControl = MAC_MII_CONTROL_SC;
+	}
+
+	/*
+	 * Scan register 1 of PHY/PETBI,
+	 * Set up to scan both devices
+	 * The autoscan starts from the first register, completes
+	 * the last one before rolling over to the first
+	 */
+	ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
+			   PHYAddr[0] | MII_SCAN_REGISTER);
+
+	ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
+			   (scanControl) |
+			   ((MAC_MII_CONTROL_SC | MAC_MII_CONTROL_AS) << 16));
+}
+
+static u8 ql_mii_disable_scan_mode(struct ql3_adapter *qdev)
+{
+	u8 ret;
+	struct ql3xxx_port_registers __iomem *port_regs =
+	    				qdev->mem_map_registers;
+
+	/* See if scan mode is enabled before we turn it off */
+	if (ql_read_page0_reg(qdev, &port_regs->macMIIMgmtControlReg) &
+	    (MAC_MII_CONTROL_AS | MAC_MII_CONTROL_SC)) {
+		/* Scan is enabled */
+		ret = 1;
+	} else {
+		/* Scan is disabled */
+		ret = 0;
+	}
+
+	/*
+	 * When disabling scan mode you must first change the MII register
+	 * address
+	 */
+	ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
+			   PHYAddr[0] | MII_SCAN_REGISTER);
+
+	ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
+			   ((MAC_MII_CONTROL_SC | MAC_MII_CONTROL_AS |
+			     MAC_MII_CONTROL_RC) << 16));
+
+	return ret;
+}
+
+static int ql_mii_write_reg_ex(struct ql3_adapter *qdev,
+			       u16 regAddr, u16 value, u32 mac_index)
+{
+	struct ql3xxx_port_registers __iomem *port_regs =
+	    		qdev->mem_map_registers;
+	u8 scanWasEnabled;
+
+	scanWasEnabled = ql_mii_disable_scan_mode(qdev);
+
+	if (ql_wait_for_mii_ready(qdev)) {
+		if (netif_msg_link(qdev))
+			printk(KERN_WARNING PFX
+			       "%s Timed out waiting for management port to "
+			       "get free before issuing command.\n",
+			       qdev->ndev->name);
+		return -1;
+	}
+
+	ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
+			   PHYAddr[mac_index] | regAddr);
+
+	ql_write_page0_reg(qdev, &port_regs->macMIIMgmtDataReg, value);
+
+	/* Wait for write to complete 9/10/04 SJP */
+	if (ql_wait_for_mii_ready(qdev)) {
+		if (netif_msg_link(qdev))
+			printk(KERN_WARNING PFX
+			       "%s: Timed out waiting for management port to"
+			       "get free before issuing command.\n",
+			       qdev->ndev->name);
+		return -1;
+	}
+
+	if (scanWasEnabled)
+		ql_mii_enable_scan_mode(qdev);
+
+	return 0;
+}
+
+static int ql_mii_read_reg_ex(struct ql3_adapter *qdev, u16 regAddr,
+			      u16 * value, u32 mac_index)
+{
+	struct ql3xxx_port_registers __iomem *port_regs =
+	    		qdev->mem_map_registers;
+	u8 scanWasEnabled;
+	u32 temp;
+
+	scanWasEnabled = ql_mii_disable_scan_mode(qdev);
+
+	if (ql_wait_for_mii_ready(qdev)) {
+		if (netif_msg_link(qdev))
+			printk(KERN_WARNING PFX
+			       "%s: Timed out waiting for management port to "
+			       "get free before issuing command.\n",
+			       qdev->ndev->name);
+		return -1;
+	}
+
+	ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
+			   PHYAddr[mac_index] | regAddr);
+
+	ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
+			   (MAC_MII_CONTROL_RC << 16));
+
+	ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
+			   (MAC_MII_CONTROL_RC << 16) | MAC_MII_CONTROL_RC);
+
+	/* Wait for the read to complete */
+	if (ql_wait_for_mii_ready(qdev)) {
+		if (netif_msg_link(qdev))
+			printk(KERN_WARNING PFX
+			       "%s: Timed out waiting for management port to "
+			       "get free after issuing command.\n",
+			       qdev->ndev->name);
+		return -1;
+	}
+
+	temp = ql_read_page0_reg(qdev, &port_regs->macMIIMgmtDataReg);
+	*value = (u16) temp;
+
+	if (scanWasEnabled)
+		ql_mii_enable_scan_mode(qdev);
+
+	return 0;
+}
+
+static int ql_mii_write_reg(struct ql3_adapter *qdev, u16 regAddr, u16 value)
+{
+	struct ql3xxx_port_registers __iomem *port_regs =
+	    		qdev->mem_map_registers;
+
+	ql_mii_disable_scan_mode(qdev);
+
+	if (ql_wait_for_mii_ready(qdev)) {
+		if (netif_msg_link(qdev))
+			printk(KERN_WARNING PFX
+			       "%s: Timed out waiting for management port to "
+			       "get free before issuing command.\n",
+			       qdev->ndev->name);
+		return -1;
+	}
+
+	ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
+			   qdev->PHYAddr | regAddr);
+
+	ql_write_page0_reg(qdev, &port_regs->macMIIMgmtDataReg, value);
+
+	/* Wait for write to complete. */
+	if (ql_wait_for_mii_ready(qdev)) {
+		if (netif_msg_link(qdev))
+			printk(KERN_WARNING PFX
+			       "%s: Timed out waiting for management port to "
+			       "get free before issuing command.\n",
+			       qdev->ndev->name);
+		return -1;
+	}
+
+	ql_mii_enable_scan_mode(qdev);
+
+	return 0;
+}
+
+static int ql_mii_read_reg(struct ql3_adapter *qdev, u16 regAddr, u16 *value)
+{
+	u32 temp;
+	struct ql3xxx_port_registers __iomem *port_regs =
+	    		qdev->mem_map_registers;
+
+	ql_mii_disable_scan_mode(qdev);
+
+	if (ql_wait_for_mii_ready(qdev)) {
+		if (netif_msg_link(qdev))
+			printk(KERN_WARNING PFX
+			       "%s: Timed out waiting for management port to "
+			       "get free before issuing command.\n",
+			       qdev->ndev->name);
+		return -1;
+	}
+
+	ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
+			   qdev->PHYAddr | regAddr);
+
+	ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
+			   (MAC_MII_CONTROL_RC << 16));
+
+	ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
+			   (MAC_MII_CONTROL_RC << 16) | MAC_MII_CONTROL_RC);
+
+	/* Wait for the read to complete */
+	if (ql_wait_for_mii_ready(qdev)) {
+		if (netif_msg_link(qdev))
+			printk(KERN_WARNING PFX
+			       "%s: Timed out waiting for management port to "
+			       "get free before issuing command.\n",
+			       qdev->ndev->name);
+		return -1;
+	}
+
+	temp = ql_read_page0_reg(qdev, &port_regs->macMIIMgmtDataReg);
+	*value = (u16) temp;
+
+	ql_mii_enable_scan_mode(qdev);
+
+	return 0;
+}
+
+static void ql_petbi_reset(struct ql3_adapter *qdev)
+{
+	ql_mii_write_reg(qdev, PETBI_CONTROL_REG, PETBI_CTRL_SOFT_RESET);
+}
+
+static void ql_petbi_start_neg(struct ql3_adapter *qdev)
+{
+	u16 reg;
+
+	/* Enable Auto-negotiation sense */
+	ql_mii_read_reg(qdev, PETBI_TBI_CTRL, &reg);
+	reg |= PETBI_TBI_AUTO_SENSE;
+	ql_mii_write_reg(qdev, PETBI_TBI_CTRL, reg);
+
+	ql_mii_write_reg(qdev, PETBI_NEG_ADVER,
+			 PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX);
+
+	ql_mii_write_reg(qdev, PETBI_CONTROL_REG,
+			 PETBI_CTRL_AUTO_NEG | PETBI_CTRL_RESTART_NEG |
+			 PETBI_CTRL_FULL_DUPLEX | PETBI_CTRL_SPEED_1000);
+
+}
+
+static void ql_petbi_reset_ex(struct ql3_adapter *qdev, u32 mac_index)
+{
+	ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG, PETBI_CTRL_SOFT_RESET,
+			    mac_index);
+}
+
+static void ql_petbi_start_neg_ex(struct ql3_adapter *qdev, u32 mac_index)
+{
+	u16 reg;
+
+	/* Enable Auto-negotiation sense */
+	ql_mii_read_reg_ex(qdev, PETBI_TBI_CTRL, &reg, mac_index);
+	reg |= PETBI_TBI_AUTO_SENSE;
+	ql_mii_write_reg_ex(qdev, PETBI_TBI_CTRL, reg, mac_index);
+
+	ql_mii_write_reg_ex(qdev, PETBI_NEG_ADVER,
+			    PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX, mac_index);
+
+	ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG,
+			    PETBI_CTRL_AUTO_NEG | PETBI_CTRL_RESTART_NEG |
+			    PETBI_CTRL_FULL_DUPLEX | PETBI_CTRL_SPEED_1000,
+			    mac_index);
+}
+
+static void ql_petbi_init(struct ql3_adapter *qdev)
+{
+	ql_petbi_reset(qdev);
+	ql_petbi_start_neg(qdev);
+}
+
+static void ql_petbi_init_ex(struct ql3_adapter *qdev, u32 mac_index)
+{
+	ql_petbi_reset_ex(qdev, mac_index);
+	ql_petbi_start_neg_ex(qdev, mac_index);
+}
+
+static int ql_is_petbi_neg_pause(struct ql3_adapter *qdev)
+{
+	u16 reg;
+
+	if (ql_mii_read_reg(qdev, PETBI_NEG_PARTNER, &reg) < 0)
+		return 0;
+
+	return (reg & PETBI_NEG_PAUSE_MASK) == PETBI_NEG_PAUSE;
+}
+
+static int ql_phy_get_speed(struct ql3_adapter *qdev)
+{
+	u16 reg;
+
+	if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, &reg) < 0)
+		return 0;
+
+	reg = (((reg & 0x18) >> 3) & 3);
+
+	if (reg == 2)
+		return SPEED_1000;
+	else if (reg == 1)
+		return SPEED_100;
+	else if (reg == 0)
+		return SPEED_10;
+	else
+		return -1;
+}
+
+static int ql_is_full_dup(struct ql3_adapter *qdev)
+{
+	u16 reg;
+
+	if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, &reg) < 0)
+		return 0;
+
+	return (reg & PHY_AUX_DUPLEX_STAT) != 0;
+}
+
+static int ql_is_phy_neg_pause(struct ql3_adapter *qdev)
+{
+	u16 reg;
+
+	if (ql_mii_read_reg(qdev, PHY_NEG_PARTNER, &reg) < 0)
+		return 0;
+
+	return (reg & PHY_NEG_PAUSE) != 0;
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static void ql_mac_enable(struct ql3_adapter *qdev, u32 enable)
+{
+	struct ql3xxx_port_registers __iomem *port_regs =
+	    		qdev->mem_map_registers;
+	u32 value;
+
+	if (enable)
+		value = (MAC_CONFIG_REG_PE | (MAC_CONFIG_REG_PE << 16));
+	else
+		value = (MAC_CONFIG_REG_PE << 16);
+
+	if (qdev->mac_index)
+		ql_write_page0_reg(qdev, &port_regs->mac1ConfigReg, value);
+	else
+		ql_write_page0_reg(qdev, &port_regs->mac0ConfigReg, value);
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static void ql_mac_cfg_soft_reset(struct ql3_adapter *qdev, u32 enable)
+{
+	struct ql3xxx_port_registers __iomem *port_regs =
+	    		qdev->mem_map_registers;
+	u32 value;
+
+	if (enable)
+		value = (MAC_CONFIG_REG_SR | (MAC_CONFIG_REG_SR << 16));
+	else
+		value = (MAC_CONFIG_REG_SR << 16);
+
+	if (qdev->mac_index)
+		ql_write_page0_reg(qdev, &port_regs->mac1ConfigReg, value);
+	else
+		ql_write_page0_reg(qdev, &port_regs->mac0ConfigReg, value);
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static void ql_mac_cfg_gig(struct ql3_adapter *qdev, u32 enable)
+{
+	struct ql3xxx_port_registers __iomem *port_regs =
+	    		qdev->mem_map_registers;
+	u32 value;
+
+	if (enable)
+		value = (MAC_CONFIG_REG_GM | (MAC_CONFIG_REG_GM << 16));
+	else
+		value = (MAC_CONFIG_REG_GM << 16);
+
+	if (qdev->mac_index)
+		ql_write_page0_reg(qdev, &port_regs->mac1ConfigReg, value);
+	else
+		ql_write_page0_reg(qdev, &port_regs->mac0ConfigReg, value);
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static void ql_mac_cfg_full_dup(struct ql3_adapter *qdev, u32 enable)
+{
+	struct ql3xxx_port_registers __iomem *port_regs =
+	    		qdev->mem_map_registers;
+	u32 value;
+
+	if (enable)
+		value = (MAC_CONFIG_REG_FD | (MAC_CONFIG_REG_FD << 16));
+	else
+		value = (MAC_CONFIG_REG_FD << 16);
+
+	if (qdev->mac_index)
+		ql_write_page0_reg(qdev, &port_regs->mac1ConfigReg, value);
+	else
+		ql_write_page0_reg(qdev, &port_regs->mac0ConfigReg, value);
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static void ql_mac_cfg_pause(struct ql3_adapter *qdev, u32 enable)
+{
+	struct ql3xxx_port_registers __iomem *port_regs =
+	    		qdev->mem_map_registers;
+	u32 value;
+
+	if (enable)
+		value =
+		    ((MAC_CONFIG_REG_TF | MAC_CONFIG_REG_RF) |
+		     ((MAC_CONFIG_REG_TF | MAC_CONFIG_REG_RF) << 16));
+	else
+		value = ((MAC_CONFIG_REG_TF | MAC_CONFIG_REG_RF) << 16);
+
+	if (qdev->mac_index)
+		ql_write_page0_reg(qdev, &port_regs->mac1ConfigReg, value);
+	else
+		ql_write_page0_reg(qdev, &port_regs->mac0ConfigReg, value);
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static int ql_is_fiber(struct ql3_adapter *qdev)
+{
+	struct ql3xxx_port_registers __iomem *port_regs =
+	    		qdev->mem_map_registers;
+	u32 bitToCheck = 0;
+	u32 temp;
+
+	switch (qdev->mac_index) {
+	case 0:
+		bitToCheck = PORT_STATUS_SM0;
+		break;
+	case 1:
+		bitToCheck = PORT_STATUS_SM1;
+		break;
+	}
+
+	temp = ql_read_page0_reg(qdev, &port_regs->portStatus);
+	return (temp & bitToCheck) != 0;
+}
+
+static int ql_is_auto_cfg(struct ql3_adapter *qdev)
+{
+	u16 reg;
+	ql_mii_read_reg(qdev, 0x00, &reg);
+	return (reg & 0x1000) != 0;
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static int ql_is_auto_neg_complete(struct ql3_adapter *qdev)
+{
+	struct ql3xxx_port_registers __iomem *port_regs =
+	    		qdev->mem_map_registers;
+	u32 bitToCheck = 0;
+	u32 temp;
+
+	switch (qdev->mac_index) {
+	case 0:
+		bitToCheck = PORT_STATUS_AC0;
+		break;
+	case 1:
+		bitToCheck = PORT_STATUS_AC1;
+		break;
+	}
+
+	temp = ql_read_page0_reg(qdev, &port_regs->portStatus);
+	if (temp & bitToCheck) {
+		if (netif_msg_link(qdev))
+			printk(KERN_INFO PFX
+			       "%s: Auto-Negotiate complete.\n",
+			       qdev->ndev->name);
+		return 1;
+	} else {
+		if (netif_msg_link(qdev))
+			printk(KERN_WARNING PFX
+			       "%s: Auto-Negotiate incomplete.\n",
+			       qdev->ndev->name);
+		return 0;
+	}
+}
+
+/*
+ *  ql_is_neg_pause() returns 1 if pause was negotiated to be on
+ */
+static int ql_is_neg_pause(struct ql3_adapter *qdev)
+{
+	if (ql_is_fiber(qdev))
+		return ql_is_petbi_neg_pause(qdev);
+	else
+		return ql_is_phy_neg_pause(qdev);
+}
+
+static int ql_auto_neg_error(struct ql3_adapter *qdev)
+{
+	struct ql3xxx_port_registers __iomem *port_regs =
+	    		qdev->mem_map_registers;
+	u32 bitToCheck = 0;
+	u32 temp;
+
+	switch (qdev->mac_index) {
+	case 0:
+		bitToCheck = PORT_STATUS_AE0;
+		break;
+	case 1:
+		bitToCheck = PORT_STATUS_AE1;
+		break;
+	}
+	temp = ql_read_page0_reg(qdev, &port_regs->portStatus);
+	return (temp & bitToCheck) != 0;
+}
+
+static u32 ql_get_link_speed(struct ql3_adapter *qdev)
+{
+	if (ql_is_fiber(qdev))
+		return SPEED_1000;
+	else
+		return ql_phy_get_speed(qdev);
+}
+
+static int ql_is_link_full_dup(struct ql3_adapter *qdev)
+{
+	if (ql_is_fiber(qdev))
+		return 1;
+	else
+		return ql_is_full_dup(qdev);
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static int ql_link_down_detect(struct ql3_adapter *qdev)
+{
+	struct ql3xxx_port_registers __iomem *port_regs =
+	    		qdev->mem_map_registers;
+	u32 bitToCheck = 0;
+	u32 temp;
+
+	switch (qdev->mac_index) {
+	case 0:
+		bitToCheck = ISP_CONTROL_LINK_DN_0;
+		break;
+	case 1:
+		bitToCheck = ISP_CONTROL_LINK_DN_1;
+		break;
+	}
+
+	temp =
+	    ql_read_common_reg(qdev, &port_regs->CommonRegs.ispControlStatus);
+	return (temp & bitToCheck) != 0;
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static int ql_link_down_detect_clear(struct ql3_adapter *qdev)
+{
+	struct ql3xxx_port_registers __iomem *port_regs =
+	    		qdev->mem_map_registers;
+
+	switch (qdev->mac_index) {
+	case 0:
+		ql_write_common_reg(qdev,
+				    &port_regs->CommonRegs.ispControlStatus,
+				    (ISP_CONTROL_LINK_DN_0) |
+				    (ISP_CONTROL_LINK_DN_0 << 16));
+		break;
+
+	case 1:
+		ql_write_common_reg(qdev,
+				    &port_regs->CommonRegs.ispControlStatus,
+				    (ISP_CONTROL_LINK_DN_1) |
+				    (ISP_CONTROL_LINK_DN_1 << 16));
+		break;
+
+	default:
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static int ql_this_adapter_controls_port(struct ql3_adapter *qdev,
+					 u32 mac_index)
+{
+	struct ql3xxx_port_registers __iomem *port_regs =
+	    		qdev->mem_map_registers;
+	u32 bitToCheck = 0;
+	u32 temp;
+
+	switch (mac_index) {
+	case 0:
+		bitToCheck = PORT_STATUS_F1_ENABLED;
+		break;
+	case 1:
+		bitToCheck = PORT_STATUS_F3_ENABLED;
+		break;
+	default:
+		break;
+	}
+
+	temp = ql_read_page0_reg(qdev, &port_regs->portStatus);
+	if (temp & bitToCheck) {
+		if (netif_msg_link(qdev))
+			printk(KERN_DEBUG PFX
+			       "%s: is not link master.\n", qdev->ndev->name);
+		return 0;
+	} else {
+		if (netif_msg_link(qdev))
+			printk(KERN_DEBUG PFX
+			       "%s: is link master.\n", qdev->ndev->name);
+		return 1;
+	}
+}
+
+static void ql_phy_reset_ex(struct ql3_adapter *qdev, u32 mac_index)
+{
+	ql_mii_write_reg_ex(qdev, CONTROL_REG, PHY_CTRL_SOFT_RESET, mac_index);
+}
+
+static void ql_phy_start_neg_ex(struct ql3_adapter *qdev, u32 mac_index)
+{
+	u16 reg;
+
+	ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER,
+			    PHY_NEG_PAUSE | PHY_NEG_ADV_SPEED | 1, mac_index);
+
+	ql_mii_read_reg_ex(qdev, CONTROL_REG, &reg, mac_index);
+	ql_mii_write_reg_ex(qdev, CONTROL_REG, reg | PHY_CTRL_RESTART_NEG,
+			    mac_index);
+}
+
+static void ql_phy_init_ex(struct ql3_adapter *qdev, u32 mac_index)
+{
+	ql_phy_reset_ex(qdev, mac_index);
+	ql_phy_start_neg_ex(qdev, mac_index);
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static u32 ql_get_link_state(struct ql3_adapter *qdev)
+{
+	struct ql3xxx_port_registers __iomem *port_regs =
+	    		qdev->mem_map_registers;
+	u32 bitToCheck = 0;
+	u32 temp, linkState;
+
+	switch (qdev->mac_index) {
+	case 0:
+		bitToCheck = PORT_STATUS_UP0;
+		break;
+	case 1:
+		bitToCheck = PORT_STATUS_UP1;
+		break;
+	}
+	temp = ql_read_page0_reg(qdev, &port_regs->portStatus);
+	if (temp & bitToCheck) {
+		linkState = LS_UP;
+	} else {
+		linkState = LS_DOWN;
+		if (netif_msg_link(qdev))
+			printk(KERN_WARNING PFX
+			       "%s: Link is down.\n", qdev->ndev->name);
+	}
+	return linkState;
+}
+
+static int ql_port_start(struct ql3_adapter *qdev)
+{
+	if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+		(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
+			 2) << 7))
+		return -1;
+
+	if (ql_is_fiber(qdev)) {
+		ql_petbi_init(qdev);
+	} else {
+		/* Copper port */
+		ql_phy_init_ex(qdev, qdev->mac_index);
+	}
+
+	ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
+	return 0;
+}
+
+static int ql_finish_auto_neg(struct ql3_adapter *qdev)
+{
+
+	if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+		(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
+			 2) << 7))
+		return -1;
+
+	if (!ql_auto_neg_error(qdev)) {
+		if (test_bit(QL_LINK_MASTER,&qdev->flags)) {
+			/* configure the MAC */
+			if (netif_msg_link(qdev))
+				printk(KERN_DEBUG PFX
+				       "%s: Configuring link.\n",
+				       qdev->ndev->
+				       name);
+			ql_mac_cfg_soft_reset(qdev, 1);
+			ql_mac_cfg_gig(qdev,
+				       (ql_get_link_speed
+					(qdev) ==
+					SPEED_1000));
+			ql_mac_cfg_full_dup(qdev,
+					    ql_is_link_full_dup
+					    (qdev));
+			ql_mac_cfg_pause(qdev,
+					 ql_is_neg_pause
+					 (qdev));
+			ql_mac_cfg_soft_reset(qdev, 0);
+
+			/* enable the MAC */
+			if (netif_msg_link(qdev))
+				printk(KERN_DEBUG PFX
+				       "%s: Enabling mac.\n",
+				       qdev->ndev->
+					       name);
+			ql_mac_enable(qdev, 1);
+		}
+
+		if (netif_msg_link(qdev))
+			printk(KERN_DEBUG PFX
+			       "%s: Change port_link_state LS_DOWN to LS_UP.\n",
+			       qdev->ndev->name);
+		qdev->port_link_state = LS_UP;
+		netif_start_queue(qdev->ndev);
+		netif_carrier_on(qdev->ndev);
+		if (netif_msg_link(qdev))
+			printk(KERN_INFO PFX
+			       "%s: Link is up at %d Mbps, %s duplex.\n",
+			       qdev->ndev->name,
+			       ql_get_link_speed(qdev),
+			       ql_is_link_full_dup(qdev)
+			       ? "full" : "half");
+
+	} else {	/* Remote error detected */
+
+		if (test_bit(QL_LINK_MASTER,&qdev->flags)) {
+			if (netif_msg_link(qdev))
+				printk(KERN_DEBUG PFX
+				       "%s: Remote error detected. "
+				       "Calling ql_port_start().\n",
+				       qdev->ndev->
+				       name);
+			/*
+			 * ql_port_start() is shared code and needs
+			 * to lock the PHY on it's own.
+			 */
+			ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
+			if(ql_port_start(qdev))	{/* Restart port */
+				return -1;
+			} else
+				return 0;
+		}
+	}
+	ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
+	return 0;
+}
+
+static void ql_link_state_machine(struct ql3_adapter *qdev)
+{
+	u32 curr_link_state;
+	unsigned long hw_flags;
+
+	spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+
+	curr_link_state = ql_get_link_state(qdev);
+
+	if (test_bit(QL_RESET_ACTIVE,&qdev->flags)) {
+		if (netif_msg_link(qdev))
+			printk(KERN_INFO PFX
+			       "%s: Reset in progress, skip processing link "
+			       "state.\n", qdev->ndev->name);
+		return;
+	}
+
+	switch (qdev->port_link_state) {
+	default:
+		if (test_bit(QL_LINK_MASTER,&qdev->flags)) {
+			ql_port_start(qdev);
+		}
+		qdev->port_link_state = LS_DOWN;
+		/* Fall Through */
+
+	case LS_DOWN:
+		if (netif_msg_link(qdev))
+			printk(KERN_DEBUG PFX
+			       "%s: port_link_state = LS_DOWN.\n",
+			       qdev->ndev->name);
+		if (curr_link_state == LS_UP) {
+			if (netif_msg_link(qdev))
+				printk(KERN_DEBUG PFX
+				       "%s: curr_link_state = LS_UP.\n",
+				       qdev->ndev->name);
+			if (ql_is_auto_neg_complete(qdev))
+				ql_finish_auto_neg(qdev);
+
+			if (qdev->port_link_state == LS_UP)
+				ql_link_down_detect_clear(qdev);
+
+		}
+		break;
+
+	case LS_UP:
+		/*
+		 * See if the link is currently down or went down and came
+		 * back up
+		 */
+		if ((curr_link_state == LS_DOWN) || ql_link_down_detect(qdev)) {
+			if (netif_msg_link(qdev))
+				printk(KERN_INFO PFX "%s: Link is down.\n",
+				       qdev->ndev->name);
+			qdev->port_link_state = LS_DOWN;
+		}
+		break;
+	}
+	spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+}
+
+/*
+ * Caller must take hw_lock and QL_PHY_GIO_SEM.
+ */
+static void ql_get_phy_owner(struct ql3_adapter *qdev)
+{
+	if (ql_this_adapter_controls_port(qdev, qdev->mac_index))
+		set_bit(QL_LINK_MASTER,&qdev->flags);
+	else
+		clear_bit(QL_LINK_MASTER,&qdev->flags);
+}
+
+/*
+ * Caller must take hw_lock and QL_PHY_GIO_SEM.
+ */
+static void ql_init_scan_mode(struct ql3_adapter *qdev)
+{
+	ql_mii_enable_scan_mode(qdev);
+
+	if (test_bit(QL_LINK_OPTICAL,&qdev->flags)) {
+		if (ql_this_adapter_controls_port(qdev, qdev->mac_index))
+			ql_petbi_init_ex(qdev, qdev->mac_index);
+	} else {
+		if (ql_this_adapter_controls_port(qdev, qdev->mac_index))
+			ql_phy_init_ex(qdev, qdev->mac_index);
+	}
+}
+
+/*
+ * MII_Setup needs to be called before taking the PHY out of reset so that the
+ * management interface clock speed can be set properly.  It would be better if
+ * we had a way to disable MDC until after the PHY is out of reset, but we
+ * don't have that capability.
+ */
+static int ql_mii_setup(struct ql3_adapter *qdev)
+{
+	u32 reg;
+	struct ql3xxx_port_registers __iomem *port_regs =
+	    		qdev->mem_map_registers;
+
+	if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+			(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
+			 2) << 7))
+		return -1;
+
+	/* Divide 125MHz clock by 28 to meet PHY timing requirements */
+	reg = MAC_MII_CONTROL_CLK_SEL_DIV28;
+
+	ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
+			   reg | ((MAC_MII_CONTROL_CLK_SEL_MASK) << 16));
+
+	ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
+	return 0;
+}
+
+static u32 ql_supported_modes(struct ql3_adapter *qdev)
+{
+	u32 supported;
+
+	if (test_bit(QL_LINK_OPTICAL,&qdev->flags)) {
+		supported = SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE
+		    | SUPPORTED_Autoneg;
+	} else {
+		supported = SUPPORTED_10baseT_Half
+		    | SUPPORTED_10baseT_Full
+		    | SUPPORTED_100baseT_Half
+		    | SUPPORTED_100baseT_Full
+		    | SUPPORTED_1000baseT_Half
+		    | SUPPORTED_1000baseT_Full
+		    | SUPPORTED_Autoneg | SUPPORTED_TP;
+	}
+
+	return supported;
+}
+
+static int ql_get_auto_cfg_status(struct ql3_adapter *qdev)
+{
+	int status;
+	unsigned long hw_flags;
+	spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+	if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+		(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
+			 2) << 7))
+		return 0;
+	status = ql_is_auto_cfg(qdev);
+	ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
+	spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+	return status;
+}
+
+static u32 ql_get_speed(struct ql3_adapter *qdev)
+{
+	u32 status;
+	unsigned long hw_flags;
+	spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+	if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+		(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
+			 2) << 7))
+		return 0;
+	status = ql_get_link_speed(qdev);
+	ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
+	spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+	return status;
+}
+
+static int ql_get_full_dup(struct ql3_adapter *qdev)
+{
+	int status;
+	unsigned long hw_flags;
+	spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+	if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+		(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
+			 2) << 7))
+		return 0;
+	status = ql_is_link_full_dup(qdev);
+	ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
+	spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+	return status;
+}
+
+
+static int ql_get_settings(struct net_device *ndev, struct ethtool_cmd *ecmd)
+{
+	struct ql3_adapter *qdev = netdev_priv(ndev);
+
+	ecmd->transceiver = XCVR_INTERNAL;
+	ecmd->supported = ql_supported_modes(qdev);
+
+	if (test_bit(QL_LINK_OPTICAL,&qdev->flags)) {
+		ecmd->port = PORT_FIBRE;
+	} else {
+		ecmd->port = PORT_TP;
+		ecmd->phy_address = qdev->PHYAddr;
+	}
+	ecmd->advertising = ql_supported_modes(qdev);
+	ecmd->autoneg = ql_get_auto_cfg_status(qdev);
+	ecmd->speed = ql_get_speed(qdev);
+	ecmd->duplex = ql_get_full_dup(qdev);
+	return 0;
+}
+
+static void ql_get_drvinfo(struct net_device *ndev,
+			   struct ethtool_drvinfo *drvinfo)
+{
+	struct ql3_adapter *qdev = netdev_priv(ndev);
+	strncpy(drvinfo->driver, ql3xxx_driver_name, 32);
+	strncpy(drvinfo->version, ql3xxx_driver_version, 32);
+	strncpy(drvinfo->fw_version, "N/A", 32);
+	strncpy(drvinfo->bus_info, pci_name(qdev->pdev), 32);
+	drvinfo->n_stats = 0;
+	drvinfo->testinfo_len = 0;
+	drvinfo->regdump_len = 0;
+	drvinfo->eedump_len = 0;
+}
+
+static u32 ql_get_msglevel(struct net_device *ndev)
+{
+	struct ql3_adapter *qdev = netdev_priv(ndev);
+	return qdev->msg_enable;
+}
+
+static void ql_set_msglevel(struct net_device *ndev, u32 value)
+{
+	struct ql3_adapter *qdev = netdev_priv(ndev);
+	qdev->msg_enable = value;
+}
+
+static struct ethtool_ops ql3xxx_ethtool_ops = {
+	.get_settings = ql_get_settings,
+	.get_drvinfo = ql_get_drvinfo,
+	.get_perm_addr = ethtool_op_get_perm_addr,
+	.get_link = ethtool_op_get_link,
+	.get_msglevel = ql_get_msglevel,
+	.set_msglevel = ql_set_msglevel,
+};
+
+static int ql_populate_free_queue(struct ql3_adapter *qdev)
+{
+	struct ql_rcv_buf_cb *lrg_buf_cb = qdev->lrg_buf_free_head;
+	u64 map;
+
+	while (lrg_buf_cb) {
+		if (!lrg_buf_cb->skb) {
+			lrg_buf_cb->skb = dev_alloc_skb(qdev->lrg_buffer_len);
+			if (unlikely(!lrg_buf_cb->skb)) {
+				printk(KERN_DEBUG PFX
+				       "%s: Failed dev_alloc_skb().\n",
+				       qdev->ndev->name);
+				break;
+			} else {
+				/*
+				 * We save some space to copy the ethhdr from
+				 * first buffer
+				 */
+				skb_reserve(lrg_buf_cb->skb, QL_HEADER_SPACE);
+				map = pci_map_single(qdev->pdev,
+						     lrg_buf_cb->skb->data,
+						     qdev->lrg_buffer_len -
+						     QL_HEADER_SPACE,
+						     PCI_DMA_FROMDEVICE);
+				lrg_buf_cb->buf_phy_addr_low =
+				    cpu_to_le32(LS_64BITS(map));
+				lrg_buf_cb->buf_phy_addr_high =
+				    cpu_to_le32(MS_64BITS(map));
+				pci_unmap_addr_set(lrg_buf_cb, mapaddr, map);
+				pci_unmap_len_set(lrg_buf_cb, maplen,
+						  qdev->lrg_buffer_len -
+						  QL_HEADER_SPACE);
+				--qdev->lrg_buf_skb_check;
+				if (!qdev->lrg_buf_skb_check)
+					return 1;
+			}
+		}
+		lrg_buf_cb = lrg_buf_cb->next;
+	}
+	return 0;
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static void ql_update_lrg_bufq_prod_index(struct ql3_adapter *qdev)
+{
+	struct bufq_addr_element *lrg_buf_q_ele;
+	int i;
+	struct ql_rcv_buf_cb *lrg_buf_cb;
+	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+
+	if ((qdev->lrg_buf_free_count >= 8)
+	    && (qdev->lrg_buf_release_cnt >= 16)) {
+
+		if (qdev->lrg_buf_skb_check)
+			if (!ql_populate_free_queue(qdev))
+				return;
+
+		lrg_buf_q_ele = qdev->lrg_buf_next_free;
+
+		while ((qdev->lrg_buf_release_cnt >= 16)
+		       && (qdev->lrg_buf_free_count >= 8)) {
+
+			for (i = 0; i < 8; i++) {
+				lrg_buf_cb =
+				    ql_get_from_lrg_buf_free_list(qdev);
+				lrg_buf_q_ele->addr_high =
+				    lrg_buf_cb->buf_phy_addr_high;
+				lrg_buf_q_ele->addr_low =
+				    lrg_buf_cb->buf_phy_addr_low;
+				lrg_buf_q_ele++;
+
+				qdev->lrg_buf_release_cnt--;
+			}
+
+			qdev->lrg_buf_q_producer_index++;
+
+			if (qdev->lrg_buf_q_producer_index == NUM_LBUFQ_ENTRIES)
+				qdev->lrg_buf_q_producer_index = 0;
+
+			if (qdev->lrg_buf_q_producer_index ==
+			    (NUM_LBUFQ_ENTRIES - 1)) {
+				lrg_buf_q_ele = qdev->lrg_buf_q_virt_addr;
+			}
+		}
+
+		qdev->lrg_buf_next_free = lrg_buf_q_ele;
+
+		ql_write_common_reg(qdev,
+				    (u32 *) & port_regs->CommonRegs.
+				    rxLargeQProducerIndex,
+				    qdev->lrg_buf_q_producer_index);
+	}
+}
+
+static void ql_process_mac_tx_intr(struct ql3_adapter *qdev,
+				   struct ob_mac_iocb_rsp *mac_rsp)
+{
+	struct ql_tx_buf_cb *tx_cb;
+
+	tx_cb = &qdev->tx_buf[mac_rsp->transaction_id];
+	pci_unmap_single(qdev->pdev,
+			 pci_unmap_addr(tx_cb, mapaddr),
+			 pci_unmap_len(tx_cb, maplen), PCI_DMA_TODEVICE);
+	dev_kfree_skb_irq(tx_cb->skb);
+	qdev->stats.tx_packets++;
+	qdev->stats.tx_bytes += tx_cb->skb->len;
+	tx_cb->skb = NULL;
+	atomic_inc(&qdev->tx_count);
+}
+
+static void ql_process_mac_rx_intr(struct ql3_adapter *qdev,
+				   struct ib_mac_iocb_rsp *ib_mac_rsp_ptr)
+{
+	long int offset;
+	u32 lrg_buf_phy_addr_low = 0;
+	struct ql_rcv_buf_cb *lrg_buf_cb1 = NULL;
+	struct ql_rcv_buf_cb *lrg_buf_cb2 = NULL;
+	u32 *curr_ial_ptr;
+	struct sk_buff *skb;
+	u16 length = le16_to_cpu(ib_mac_rsp_ptr->length);
+
+	/*
+	 * Get the inbound address list (small buffer).
+	 */
+	offset = qdev->small_buf_index * QL_SMALL_BUFFER_SIZE;
+	if (++qdev->small_buf_index == NUM_SMALL_BUFFERS)
+		qdev->small_buf_index = 0;
+
+	curr_ial_ptr = (u32 *) (qdev->small_buf_virt_addr + offset);
+	qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset;
+	qdev->small_buf_release_cnt++;
+
+	/* start of first buffer */
+	lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
+	lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
+	qdev->lrg_buf_release_cnt++;
+	if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
+		qdev->lrg_buf_index = 0;
+	curr_ial_ptr++;		/* 64-bit pointers require two incs. */
+	curr_ial_ptr++;
+
+	/* start of second buffer */
+	lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
+	lrg_buf_cb2 = &qdev->lrg_buf[qdev->lrg_buf_index];
+
+	/*
+	 * Second buffer gets sent up the stack.
+	 */
+	qdev->lrg_buf_release_cnt++;
+	if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
+		qdev->lrg_buf_index = 0;
+	skb = lrg_buf_cb2->skb;
+
+	qdev->stats.rx_packets++;
+	qdev->stats.rx_bytes += length;
+
+	skb_put(skb, length);
+	pci_unmap_single(qdev->pdev,
+			 pci_unmap_addr(lrg_buf_cb2, mapaddr),
+			 pci_unmap_len(lrg_buf_cb2, maplen),
+			 PCI_DMA_FROMDEVICE);
+	prefetch(skb->data);
+	skb->dev = qdev->ndev;
+	skb->ip_summed = CHECKSUM_NONE;
+	skb->protocol = eth_type_trans(skb, qdev->ndev);
+
+	netif_receive_skb(skb);
+	qdev->ndev->last_rx = jiffies;
+	lrg_buf_cb2->skb = NULL;
+
+	ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
+	ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb2);
+}
+
+static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
+				     struct ib_ip_iocb_rsp *ib_ip_rsp_ptr)
+{
+	long int offset;
+	u32 lrg_buf_phy_addr_low = 0;
+	struct ql_rcv_buf_cb *lrg_buf_cb1 = NULL;
+	struct ql_rcv_buf_cb *lrg_buf_cb2 = NULL;
+	u32 *curr_ial_ptr;
+	struct sk_buff *skb1, *skb2;
+	struct net_device *ndev = qdev->ndev;
+	u16 length = le16_to_cpu(ib_ip_rsp_ptr->length);
+	u16 size = 0;
+
+	/*
+	 * Get the inbound address list (small buffer).
+	 */
+
+	offset = qdev->small_buf_index * QL_SMALL_BUFFER_SIZE;
+	if (++qdev->small_buf_index == NUM_SMALL_BUFFERS)
+		qdev->small_buf_index = 0;
+	curr_ial_ptr = (u32 *) (qdev->small_buf_virt_addr + offset);
+	qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset;
+	qdev->small_buf_release_cnt++;
+
+	/* start of first buffer */
+	lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
+	lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
+
+	qdev->lrg_buf_release_cnt++;
+	if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
+		qdev->lrg_buf_index = 0;
+	skb1 = lrg_buf_cb1->skb;
+	curr_ial_ptr++;		/* 64-bit pointers require two incs. */
+	curr_ial_ptr++;
+
+	/* start of second buffer */
+	lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
+	lrg_buf_cb2 = &qdev->lrg_buf[qdev->lrg_buf_index];
+	skb2 = lrg_buf_cb2->skb;
+	qdev->lrg_buf_release_cnt++;
+	if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
+		qdev->lrg_buf_index = 0;
+
+	qdev->stats.rx_packets++;
+	qdev->stats.rx_bytes += length;
+
+	/*
+	 * Copy the ethhdr from first buffer to second. This
+	 * is necessary for IP completions.
+	 */
+	if (*((u16 *) skb1->data) != 0xFFFF)
+		size = VLAN_ETH_HLEN;
+	else
+		size = ETH_HLEN;
+
+	skb_put(skb2, length);	/* Just the second buffer length here. */
+	pci_unmap_single(qdev->pdev,
+			 pci_unmap_addr(lrg_buf_cb2, mapaddr),
+			 pci_unmap_len(lrg_buf_cb2, maplen),
+			 PCI_DMA_FROMDEVICE);
+	prefetch(skb2->data);
+
+	memcpy(skb_push(skb2, size), skb1->data + VLAN_ID_LEN, size);
+	skb2->dev = qdev->ndev;
+	skb2->ip_summed = CHECKSUM_NONE;
+	skb2->protocol = eth_type_trans(skb2, qdev->ndev);
+
+	netif_receive_skb(skb2);
+	ndev->last_rx = jiffies;
+	lrg_buf_cb2->skb = NULL;
+
+	ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
+	ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb2);
+}
+
+static int ql_tx_rx_clean(struct ql3_adapter *qdev,
+			  int *tx_cleaned, int *rx_cleaned, int work_to_do)
+{
+	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	struct net_rsp_iocb *net_rsp;
+	struct net_device *ndev = qdev->ndev;
+	unsigned long hw_flags;
+
+	/* While there are entries in the completion queue. */
+	while ((cpu_to_le32(*(qdev->prsp_producer_index)) !=
+		qdev->rsp_consumer_index) && (*rx_cleaned < work_to_do)) {
+
+		net_rsp = qdev->rsp_current;
+		switch (net_rsp->opcode) {
+
+		case OPCODE_OB_MAC_IOCB_FN0:
+		case OPCODE_OB_MAC_IOCB_FN2:
+			ql_process_mac_tx_intr(qdev, (struct ob_mac_iocb_rsp *)
+					       net_rsp);
+			(*tx_cleaned)++;
+			break;
+
+		case OPCODE_IB_MAC_IOCB:
+			ql_process_mac_rx_intr(qdev, (struct ib_mac_iocb_rsp *)
+					       net_rsp);
+			(*rx_cleaned)++;
+			break;
+
+		case OPCODE_IB_IP_IOCB:
+			ql_process_macip_rx_intr(qdev, (struct ib_ip_iocb_rsp *)
+						 net_rsp);
+			(*rx_cleaned)++;
+			break;
+		default:
+			{
+				u32 *tmp = (u32 *) net_rsp;
+				printk(KERN_ERR PFX
+				       "%s: Hit default case, not "
+				       "handled!\n"
+				       "	dropping the packet, opcode = "
+				       "%x.\n",
+				       ndev->name, net_rsp->opcode);
+				printk(KERN_ERR PFX
+				       "0x%08lx 0x%08lx 0x%08lx 0x%08lx \n",
+				       (unsigned long int)tmp[0],
+				       (unsigned long int)tmp[1],
+				       (unsigned long int)tmp[2],
+				       (unsigned long int)tmp[3]);
+			}
+		}
+
+		qdev->rsp_consumer_index++;
+
+		if (qdev->rsp_consumer_index == NUM_RSP_Q_ENTRIES) {
+			qdev->rsp_consumer_index = 0;
+			qdev->rsp_current = qdev->rsp_q_virt_addr;
+		} else {
+			qdev->rsp_current++;
+		}
+	}
+
+	spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+
+	ql_update_lrg_bufq_prod_index(qdev);
+
+	if (qdev->small_buf_release_cnt >= 16) {
+		while (qdev->small_buf_release_cnt >= 16) {
+			qdev->small_buf_q_producer_index++;
+
+			if (qdev->small_buf_q_producer_index ==
+			    NUM_SBUFQ_ENTRIES)
+				qdev->small_buf_q_producer_index = 0;
+			qdev->small_buf_release_cnt -= 8;
+		}
+
+		ql_write_common_reg(qdev,
+				    (u32 *) & port_regs->CommonRegs.
+				    rxSmallQProducerIndex,
+				    qdev->small_buf_q_producer_index);
+	}
+
+	ql_write_common_reg(qdev,
+			    (u32 *) & port_regs->CommonRegs.rspQConsumerIndex,
+			    qdev->rsp_consumer_index);
+	spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+
+	if (unlikely(netif_queue_stopped(qdev->ndev))) {
+		if (netif_queue_stopped(qdev->ndev) &&
+		    (atomic_read(&qdev->tx_count) > (NUM_REQ_Q_ENTRIES / 4)))
+			netif_wake_queue(qdev->ndev);
+	}
+
+	return *tx_cleaned + *rx_cleaned;
+}
+
+static int ql_poll(struct net_device *ndev, int *budget)
+{
+	struct ql3_adapter *qdev = netdev_priv(ndev);
+	int work_to_do = min(*budget, ndev->quota);
+	int rx_cleaned = 0, tx_cleaned = 0;
+
+	if (!netif_carrier_ok(ndev))
+		goto quit_polling;
+
+	ql_tx_rx_clean(qdev, &tx_cleaned, &rx_cleaned, work_to_do);
+	*budget -= rx_cleaned;
+	ndev->quota -= rx_cleaned;
+
+	if ((!tx_cleaned && !rx_cleaned) || !netif_running(ndev)) {
+quit_polling:
+		netif_rx_complete(ndev);
+		ql_enable_interrupts(qdev);
+		return 0;
+	}
+	return 1;
+}
+
+static irqreturn_t ql3xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+
+	struct net_device *ndev = dev_id;
+	struct ql3_adapter *qdev = netdev_priv(ndev);
+	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	u32 value;
+	int handled = 1;
+	u32 var;
+
+	port_regs = qdev->mem_map_registers;
+
+	value =
+	    ql_read_common_reg_l(qdev, &port_regs->CommonRegs.ispControlStatus);
+
+	if (value & (ISP_CONTROL_FE | ISP_CONTROL_RI)) {
+		spin_lock(&qdev->adapter_lock);
+		netif_stop_queue(qdev->ndev);
+		netif_carrier_off(qdev->ndev);
+		ql_disable_interrupts(qdev);
+		qdev->port_link_state = LS_DOWN;
+		set_bit(QL_RESET_ACTIVE,&qdev->flags) ;
+
+		if (value & ISP_CONTROL_FE) {
+			/*
+			 * Chip Fatal Error.
+			 */
+			var =
+			    ql_read_page0_reg_l(qdev,
+					      &port_regs->PortFatalErrStatus);
+			printk(KERN_WARNING PFX
+			       "%s: Resetting chip. PortFatalErrStatus "
+			       "register = 0x%x\n", ndev->name, var);
+			set_bit(QL_RESET_START,&qdev->flags) ;
+		} else {
+			/*
+			 * Soft Reset Requested.
+			 */
+			set_bit(QL_RESET_PER_SCSI,&qdev->flags) ;
+			printk(KERN_ERR PFX
+			       "%s: Another function issued a reset to the "
+			       "chip. ISR value = %x.\n", ndev->name, value);
+		}
+		queue_work(qdev->workqueue, &qdev->reset_work);
+		spin_unlock(&qdev->adapter_lock);
+	} else if (value & ISP_IMR_DISABLE_CMPL_INT) {
+		ql_disable_interrupts(qdev);
+		if (likely(netif_rx_schedule_prep(ndev)))
+			__netif_rx_schedule(ndev);
+		else
+			ql_enable_interrupts(qdev);
+	} else {
+		return IRQ_NONE;
+	}
+
+	return IRQ_RETVAL(handled);
+}
+
+static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
+{
+	struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
+	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	struct ql_tx_buf_cb *tx_cb;
+	struct ob_mac_iocb_req *mac_iocb_ptr;
+	u64 map;
+
+	if (unlikely(atomic_read(&qdev->tx_count) < 2)) {
+		if (!netif_queue_stopped(ndev))
+			netif_stop_queue(ndev);
+		return NETDEV_TX_BUSY;
+	}
+	tx_cb = &qdev->tx_buf[qdev->req_producer_index] ;
+	mac_iocb_ptr = tx_cb->queue_entry;
+	memset((void *)mac_iocb_ptr, 0, sizeof(struct ob_mac_iocb_req));
+	mac_iocb_ptr->opcode = qdev->mac_ob_opcode;
+	mac_iocb_ptr->flags |= qdev->mb_bit_mask;
+	mac_iocb_ptr->transaction_id = qdev->req_producer_index;
+	mac_iocb_ptr->data_len = cpu_to_le16((u16) skb->len);
+	tx_cb->skb = skb;
+	map = pci_map_single(qdev->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+	mac_iocb_ptr->buf_addr0_low = cpu_to_le32(LS_64BITS(map));
+	mac_iocb_ptr->buf_addr0_high = cpu_to_le32(MS_64BITS(map));
+	mac_iocb_ptr->buf_0_len = cpu_to_le32(skb->len | OB_MAC_IOCB_REQ_E);
+	pci_unmap_addr_set(tx_cb, mapaddr, map);
+	pci_unmap_len_set(tx_cb, maplen, skb->len);
+	atomic_dec(&qdev->tx_count);
+
+	qdev->req_producer_index++;
+	if (qdev->req_producer_index == NUM_REQ_Q_ENTRIES)
+		qdev->req_producer_index = 0;
+	wmb();
+	ql_write_common_reg_l(qdev,
+			    (u32 *) & port_regs->CommonRegs.reqQProducerIndex,
+			    qdev->req_producer_index);
+
+	ndev->trans_start = jiffies;
+	if (netif_msg_tx_queued(qdev))
+		printk(KERN_DEBUG PFX "%s: tx queued, slot %d, len %d\n",
+		       ndev->name, qdev->req_producer_index, skb->len);
+
+	return NETDEV_TX_OK;
+}
+static int ql_alloc_net_req_rsp_queues(struct ql3_adapter *qdev)
+{
+	qdev->req_q_size =
+	    (u32) (NUM_REQ_Q_ENTRIES * sizeof(struct ob_mac_iocb_req));
+
+	qdev->req_q_virt_addr =
+	    pci_alloc_consistent(qdev->pdev,
+				 (size_t) qdev->req_q_size,
+				 &qdev->req_q_phy_addr);
+
+	if ((qdev->req_q_virt_addr == NULL) ||
+	    LS_64BITS(qdev->req_q_phy_addr) & (qdev->req_q_size - 1)) {
+		printk(KERN_ERR PFX "%s: reqQ failed.\n",
+		       qdev->ndev->name);
+		return -ENOMEM;
+	}
+
+	qdev->rsp_q_size = NUM_RSP_Q_ENTRIES * sizeof(struct net_rsp_iocb);
+
+	qdev->rsp_q_virt_addr =
+	    pci_alloc_consistent(qdev->pdev,
+				 (size_t) qdev->rsp_q_size,
+				 &qdev->rsp_q_phy_addr);
+
+	if ((qdev->rsp_q_virt_addr == NULL) ||
+	    LS_64BITS(qdev->rsp_q_phy_addr) & (qdev->rsp_q_size - 1)) {
+		printk(KERN_ERR PFX
+		       "%s: rspQ allocation failed\n",
+		       qdev->ndev->name);
+		pci_free_consistent(qdev->pdev, (size_t) qdev->req_q_size,
+				    qdev->req_q_virt_addr,
+				    qdev->req_q_phy_addr);
+		return -ENOMEM;
+	}
+
+	set_bit(QL_ALLOC_REQ_RSP_Q_DONE,&qdev->flags);
+
+	return 0;
+}
+
+static void ql_free_net_req_rsp_queues(struct ql3_adapter *qdev)
+{
+	if (!test_bit(QL_ALLOC_REQ_RSP_Q_DONE,&qdev->flags)) {
+		printk(KERN_INFO PFX
+		       "%s: Already done.\n", qdev->ndev->name);
+		return;
+	}
+
+	pci_free_consistent(qdev->pdev,
+			    qdev->req_q_size,
+			    qdev->req_q_virt_addr, qdev->req_q_phy_addr);
+
+	qdev->req_q_virt_addr = NULL;
+
+	pci_free_consistent(qdev->pdev,
+			    qdev->rsp_q_size,
+			    qdev->rsp_q_virt_addr, qdev->rsp_q_phy_addr);
+
+	qdev->rsp_q_virt_addr = NULL;
+
+	clear_bit(QL_ALLOC_REQ_RSP_Q_DONE,&qdev->flags);
+}
+
+static int ql_alloc_buffer_queues(struct ql3_adapter *qdev)
+{
+	/* Create Large Buffer Queue */
+	qdev->lrg_buf_q_size =
+	    NUM_LBUFQ_ENTRIES * sizeof(struct lrg_buf_q_entry);
+	if (qdev->lrg_buf_q_size < PAGE_SIZE)
+		qdev->lrg_buf_q_alloc_size = PAGE_SIZE;
+	else
+		qdev->lrg_buf_q_alloc_size = qdev->lrg_buf_q_size * 2;
+
+	qdev->lrg_buf_q_alloc_virt_addr =
+	    pci_alloc_consistent(qdev->pdev,
+				 qdev->lrg_buf_q_alloc_size,
+				 &qdev->lrg_buf_q_alloc_phy_addr);
+
+	if (qdev->lrg_buf_q_alloc_virt_addr == NULL) {
+		printk(KERN_ERR PFX
+		       "%s: lBufQ failed\n", qdev->ndev->name);
+		return -ENOMEM;
+	}
+	qdev->lrg_buf_q_virt_addr = qdev->lrg_buf_q_alloc_virt_addr;
+	qdev->lrg_buf_q_phy_addr = qdev->lrg_buf_q_alloc_phy_addr;
+
+	/* Create Small Buffer Queue */
+	qdev->small_buf_q_size =
+	    NUM_SBUFQ_ENTRIES * sizeof(struct lrg_buf_q_entry);
+	if (qdev->small_buf_q_size < PAGE_SIZE)
+		qdev->small_buf_q_alloc_size = PAGE_SIZE;
+	else
+		qdev->small_buf_q_alloc_size = qdev->small_buf_q_size * 2;
+
+	qdev->small_buf_q_alloc_virt_addr =
+	    pci_alloc_consistent(qdev->pdev,
+				 qdev->small_buf_q_alloc_size,
+				 &qdev->small_buf_q_alloc_phy_addr);
+
+	if (qdev->small_buf_q_alloc_virt_addr == NULL) {
+		printk(KERN_ERR PFX
+		       "%s: Small Buffer Queue allocation failed.\n",
+		       qdev->ndev->name);
+		pci_free_consistent(qdev->pdev, qdev->lrg_buf_q_alloc_size,
+				    qdev->lrg_buf_q_alloc_virt_addr,
+				    qdev->lrg_buf_q_alloc_phy_addr);
+		return -ENOMEM;
+	}
+
+	qdev->small_buf_q_virt_addr = qdev->small_buf_q_alloc_virt_addr;
+	qdev->small_buf_q_phy_addr = qdev->small_buf_q_alloc_phy_addr;
+	set_bit(QL_ALLOC_BUFQS_DONE,&qdev->flags);
+	return 0;
+}
+
+static void ql_free_buffer_queues(struct ql3_adapter *qdev)
+{
+	if (!test_bit(QL_ALLOC_BUFQS_DONE,&qdev->flags)) {
+		printk(KERN_INFO PFX
+		       "%s: Already done.\n", qdev->ndev->name);
+		return;
+	}
+
+	pci_free_consistent(qdev->pdev,
+			    qdev->lrg_buf_q_alloc_size,
+			    qdev->lrg_buf_q_alloc_virt_addr,
+			    qdev->lrg_buf_q_alloc_phy_addr);
+
+	qdev->lrg_buf_q_virt_addr = NULL;
+
+	pci_free_consistent(qdev->pdev,
+			    qdev->small_buf_q_alloc_size,
+			    qdev->small_buf_q_alloc_virt_addr,
+			    qdev->small_buf_q_alloc_phy_addr);
+
+	qdev->small_buf_q_virt_addr = NULL;
+
+	clear_bit(QL_ALLOC_BUFQS_DONE,&qdev->flags);
+}
+
+static int ql_alloc_small_buffers(struct ql3_adapter *qdev)
+{
+	int i;
+	struct bufq_addr_element *small_buf_q_entry;
+
+	/* Currently we allocate on one of memory and use it for smallbuffers */
+	qdev->small_buf_total_size =
+	    (QL_ADDR_ELE_PER_BUFQ_ENTRY * NUM_SBUFQ_ENTRIES *
+	     QL_SMALL_BUFFER_SIZE);
+
+	qdev->small_buf_virt_addr =
+	    pci_alloc_consistent(qdev->pdev,
+				 qdev->small_buf_total_size,
+				 &qdev->small_buf_phy_addr);
+
+	if (qdev->small_buf_virt_addr == NULL) {
+		printk(KERN_ERR PFX
+		       "%s: Failed to get small buffer memory.\n",
+		       qdev->ndev->name);
+		return -ENOMEM;
+	}
+
+	qdev->small_buf_phy_addr_low = LS_64BITS(qdev->small_buf_phy_addr);
+	qdev->small_buf_phy_addr_high = MS_64BITS(qdev->small_buf_phy_addr);
+
+	small_buf_q_entry = qdev->small_buf_q_virt_addr;
+
+	qdev->last_rsp_offset = qdev->small_buf_phy_addr_low;
+
+	/* Initialize the small buffer queue. */
+	for (i = 0; i < (QL_ADDR_ELE_PER_BUFQ_ENTRY * NUM_SBUFQ_ENTRIES); i++) {
+		small_buf_q_entry->addr_high =
+		    cpu_to_le32(qdev->small_buf_phy_addr_high);
+		small_buf_q_entry->addr_low =
+		    cpu_to_le32(qdev->small_buf_phy_addr_low +
+				(i * QL_SMALL_BUFFER_SIZE));
+		small_buf_q_entry++;
+	}
+	qdev->small_buf_index = 0;
+	set_bit(QL_ALLOC_SMALL_BUF_DONE,&qdev->flags);
+	return 0;
+}
+
+static void ql_free_small_buffers(struct ql3_adapter *qdev)
+{
+	if (!test_bit(QL_ALLOC_SMALL_BUF_DONE,&qdev->flags)) {
+		printk(KERN_INFO PFX
+		       "%s: Already done.\n", qdev->ndev->name);
+		return;
+	}
+	if (qdev->small_buf_virt_addr != NULL) {
+		pci_free_consistent(qdev->pdev,
+				    qdev->small_buf_total_size,
+				    qdev->small_buf_virt_addr,
+				    qdev->small_buf_phy_addr);
+
+		qdev->small_buf_virt_addr = NULL;
+	}
+}
+
+static void ql_free_large_buffers(struct ql3_adapter *qdev)
+{
+	int i = 0;
+	struct ql_rcv_buf_cb *lrg_buf_cb;
+
+	for (i = 0; i < NUM_LARGE_BUFFERS; i++) {
+		lrg_buf_cb = &qdev->lrg_buf[i];
+		if (lrg_buf_cb->skb) {
+			dev_kfree_skb(lrg_buf_cb->skb);
+			pci_unmap_single(qdev->pdev,
+					 pci_unmap_addr(lrg_buf_cb, mapaddr),
+					 pci_unmap_len(lrg_buf_cb, maplen),
+					 PCI_DMA_FROMDEVICE);
+			memset(lrg_buf_cb, 0, sizeof(struct ql_rcv_buf_cb));
+		} else {
+			break;
+		}
+	}
+}
+
+static void ql_init_large_buffers(struct ql3_adapter *qdev)
+{
+	int i;
+	struct ql_rcv_buf_cb *lrg_buf_cb;
+	struct bufq_addr_element *buf_addr_ele = qdev->lrg_buf_q_virt_addr;
+
+	for (i = 0; i < NUM_LARGE_BUFFERS; i++) {
+		lrg_buf_cb = &qdev->lrg_buf[i];
+		buf_addr_ele->addr_high = lrg_buf_cb->buf_phy_addr_high;
+		buf_addr_ele->addr_low = lrg_buf_cb->buf_phy_addr_low;
+		buf_addr_ele++;
+	}
+	qdev->lrg_buf_index = 0;
+	qdev->lrg_buf_skb_check = 0;
+}
+
+static int ql_alloc_large_buffers(struct ql3_adapter *qdev)
+{
+	int i;
+	struct ql_rcv_buf_cb *lrg_buf_cb;
+	struct sk_buff *skb;
+	u64 map;
+
+	for (i = 0; i < NUM_LARGE_BUFFERS; i++) {
+		skb = dev_alloc_skb(qdev->lrg_buffer_len);
+		if (unlikely(!skb)) {
+			/* Better luck next round */
+			printk(KERN_ERR PFX
+			       "%s: large buff alloc failed, "
+			       "for %d bytes at index %d.\n",
+			       qdev->ndev->name,
+			       qdev->lrg_buffer_len * 2, i);
+			ql_free_large_buffers(qdev);
+			return -ENOMEM;
+		} else {
+
+			lrg_buf_cb = &qdev->lrg_buf[i];
+			memset(lrg_buf_cb, 0, sizeof(struct ql_rcv_buf_cb));
+			lrg_buf_cb->index = i;
+			lrg_buf_cb->skb = skb;
+			/*
+			 * We save some space to copy the ethhdr from first
+			 * buffer
+			 */
+			skb_reserve(skb, QL_HEADER_SPACE);
+			map = pci_map_single(qdev->pdev,
+					     skb->data,
+					     qdev->lrg_buffer_len -
+					     QL_HEADER_SPACE,
+					     PCI_DMA_FROMDEVICE);
+			pci_unmap_addr_set(lrg_buf_cb, mapaddr, map);
+			pci_unmap_len_set(lrg_buf_cb, maplen,
+					  qdev->lrg_buffer_len -
+					  QL_HEADER_SPACE);
+			lrg_buf_cb->buf_phy_addr_low =
+			    cpu_to_le32(LS_64BITS(map));
+			lrg_buf_cb->buf_phy_addr_high =
+			    cpu_to_le32(MS_64BITS(map));
+		}
+	}
+	return 0;
+}
+
+static void ql_create_send_free_list(struct ql3_adapter *qdev)
+{
+	struct ql_tx_buf_cb *tx_cb;
+	int i;
+	struct ob_mac_iocb_req *req_q_curr =
+					qdev->req_q_virt_addr;
+
+	/* Create free list of transmit buffers */
+	for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) {
+		tx_cb = &qdev->tx_buf[i];
+		tx_cb->skb = NULL;
+		tx_cb->queue_entry = req_q_curr;
+		req_q_curr++;
+	}
+}
+
+static int ql_alloc_mem_resources(struct ql3_adapter *qdev)
+{
+	if (qdev->ndev->mtu == NORMAL_MTU_SIZE)
+		qdev->lrg_buffer_len = NORMAL_MTU_SIZE;
+	else if (qdev->ndev->mtu == JUMBO_MTU_SIZE) {
+		qdev->lrg_buffer_len = JUMBO_MTU_SIZE;
+	} else {
+		printk(KERN_ERR PFX
+		       "%s: Invalid mtu size.  Only 1500 and 9000 are accepted.\n",
+		       qdev->ndev->name);
+		return -ENOMEM;
+	}
+	qdev->lrg_buffer_len += VLAN_ETH_HLEN + VLAN_ID_LEN + QL_HEADER_SPACE;
+	qdev->max_frame_size =
+	    (qdev->lrg_buffer_len - QL_HEADER_SPACE) + ETHERNET_CRC_SIZE;
+
+	/*
+	 * First allocate a page of shared memory and use it for shadow
+	 * locations of Network Request Queue Consumer Address Register and
+	 * Network Completion Queue Producer Index Register
+	 */
+	qdev->shadow_reg_virt_addr =
+	    pci_alloc_consistent(qdev->pdev,
+				 PAGE_SIZE, &qdev->shadow_reg_phy_addr);
+
+	if (qdev->shadow_reg_virt_addr != NULL) {
+		qdev->preq_consumer_index = (u16 *) qdev->shadow_reg_virt_addr;
+		qdev->req_consumer_index_phy_addr_high =
+		    MS_64BITS(qdev->shadow_reg_phy_addr);
+		qdev->req_consumer_index_phy_addr_low =
+		    LS_64BITS(qdev->shadow_reg_phy_addr);
+
+		qdev->prsp_producer_index =
+		    (u32 *) (((u8 *) qdev->preq_consumer_index) + 8);
+		qdev->rsp_producer_index_phy_addr_high =
+		    qdev->req_consumer_index_phy_addr_high;
+		qdev->rsp_producer_index_phy_addr_low =
+		    qdev->req_consumer_index_phy_addr_low + 8;
+	} else {
+		printk(KERN_ERR PFX
+		       "%s: shadowReg Alloc failed.\n", qdev->ndev->name);
+		return -ENOMEM;
+	}
+
+	if (ql_alloc_net_req_rsp_queues(qdev) != 0) {
+		printk(KERN_ERR PFX
+		       "%s: ql_alloc_net_req_rsp_queues failed.\n",
+		       qdev->ndev->name);
+		goto err_req_rsp;
+	}
+
+	if (ql_alloc_buffer_queues(qdev) != 0) {
+		printk(KERN_ERR PFX
+		       "%s: ql_alloc_buffer_queues failed.\n",
+		       qdev->ndev->name);
+		goto err_buffer_queues;
+	}
+
+	if (ql_alloc_small_buffers(qdev) != 0) {
+		printk(KERN_ERR PFX
+		       "%s: ql_alloc_small_buffers failed\n", qdev->ndev->name);
+		goto err_small_buffers;
+	}
+
+	if (ql_alloc_large_buffers(qdev) != 0) {
+		printk(KERN_ERR PFX
+		       "%s: ql_alloc_large_buffers failed\n", qdev->ndev->name);
+		goto err_small_buffers;
+	}
+
+	/* Initialize the large buffer queue. */
+	ql_init_large_buffers(qdev);
+	ql_create_send_free_list(qdev);
+
+	qdev->rsp_current = qdev->rsp_q_virt_addr;
+
+	return 0;
+
+err_small_buffers:
+	ql_free_buffer_queues(qdev);
+err_buffer_queues:
+	ql_free_net_req_rsp_queues(qdev);
+err_req_rsp:
+	pci_free_consistent(qdev->pdev,
+			    PAGE_SIZE,
+			    qdev->shadow_reg_virt_addr,
+			    qdev->shadow_reg_phy_addr);
+
+	return -ENOMEM;
+}
+
+static void ql_free_mem_resources(struct ql3_adapter *qdev)
+{
+	ql_free_large_buffers(qdev);
+	ql_free_small_buffers(qdev);
+	ql_free_buffer_queues(qdev);
+	ql_free_net_req_rsp_queues(qdev);
+	if (qdev->shadow_reg_virt_addr != NULL) {
+		pci_free_consistent(qdev->pdev,
+				    PAGE_SIZE,
+				    qdev->shadow_reg_virt_addr,
+				    qdev->shadow_reg_phy_addr);
+		qdev->shadow_reg_virt_addr = NULL;
+	}
+}
+
+static int ql_init_misc_registers(struct ql3_adapter *qdev)
+{
+	struct ql3xxx_local_ram_registers *local_ram =
+	    (struct ql3xxx_local_ram_registers *)qdev->mem_map_registers;
+
+	if(ql_sem_spinlock(qdev, QL_DDR_RAM_SEM_MASK,
+			(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
+			 2) << 4))
+		return -1;
+
+	ql_write_page2_reg(qdev,
+			   &local_ram->bufletSize, qdev->nvram_data.bufletSize);
+
+	ql_write_page2_reg(qdev,
+			   &local_ram->maxBufletCount,
+			   qdev->nvram_data.bufletCount);
+
+	ql_write_page2_reg(qdev,
+			   &local_ram->freeBufletThresholdLow,
+			   (qdev->nvram_data.tcpWindowThreshold25 << 16) |
+			   (qdev->nvram_data.tcpWindowThreshold0));
+
+	ql_write_page2_reg(qdev,
+			   &local_ram->freeBufletThresholdHigh,
+			   qdev->nvram_data.tcpWindowThreshold50);
+
+	ql_write_page2_reg(qdev,
+			   &local_ram->ipHashTableBase,
+			   (qdev->nvram_data.ipHashTableBaseHi << 16) |
+			   qdev->nvram_data.ipHashTableBaseLo);
+	ql_write_page2_reg(qdev,
+			   &local_ram->ipHashTableCount,
+			   qdev->nvram_data.ipHashTableSize);
+	ql_write_page2_reg(qdev,
+			   &local_ram->tcpHashTableBase,
+			   (qdev->nvram_data.tcpHashTableBaseHi << 16) |
+			   qdev->nvram_data.tcpHashTableBaseLo);
+	ql_write_page2_reg(qdev,
+			   &local_ram->tcpHashTableCount,
+			   qdev->nvram_data.tcpHashTableSize);
+	ql_write_page2_reg(qdev,
+			   &local_ram->ncbBase,
+			   (qdev->nvram_data.ncbTableBaseHi << 16) |
+			   qdev->nvram_data.ncbTableBaseLo);
+	ql_write_page2_reg(qdev,
+			   &local_ram->maxNcbCount,
+			   qdev->nvram_data.ncbTableSize);
+	ql_write_page2_reg(qdev,
+			   &local_ram->drbBase,
+			   (qdev->nvram_data.drbTableBaseHi << 16) |
+			   qdev->nvram_data.drbTableBaseLo);
+	ql_write_page2_reg(qdev,
+			   &local_ram->maxDrbCount,
+			   qdev->nvram_data.drbTableSize);
+	ql_sem_unlock(qdev, QL_DDR_RAM_SEM_MASK);
+	return 0;
+}
+
+static int ql_adapter_initialize(struct ql3_adapter *qdev)
+{
+	u32 value;
+	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	struct ql3xxx_host_memory_registers __iomem *hmem_regs =
+	    (struct ql3xxx_host_memory_registers *)port_regs;
+	u32 delay = 10;
+	int status = 0;
+
+	if(ql_mii_setup(qdev))
+		return -1;
+
+	/* Bring out PHY out of reset */
+	ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+			    (ISP_SERIAL_PORT_IF_WE |
+			     (ISP_SERIAL_PORT_IF_WE << 16)));
+
+	qdev->port_link_state = LS_DOWN;
+	netif_carrier_off(qdev->ndev);
+
+	/* V2 chip fix for ARS-39168. */
+	ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+			    (ISP_SERIAL_PORT_IF_SDE |
+			     (ISP_SERIAL_PORT_IF_SDE << 16)));
+
+	/* Request Queue Registers */
+	*((u32 *) (qdev->preq_consumer_index)) = 0;
+	atomic_set(&qdev->tx_count,NUM_REQ_Q_ENTRIES);
+	qdev->req_producer_index = 0;
+
+	ql_write_page1_reg(qdev,
+			   &hmem_regs->reqConsumerIndexAddrHigh,
+			   qdev->req_consumer_index_phy_addr_high);
+	ql_write_page1_reg(qdev,
+			   &hmem_regs->reqConsumerIndexAddrLow,
+			   qdev->req_consumer_index_phy_addr_low);
+
+	ql_write_page1_reg(qdev,
+			   &hmem_regs->reqBaseAddrHigh,
+			   MS_64BITS(qdev->req_q_phy_addr));
+	ql_write_page1_reg(qdev,
+			   &hmem_regs->reqBaseAddrLow,
+			   LS_64BITS(qdev->req_q_phy_addr));
+	ql_write_page1_reg(qdev, &hmem_regs->reqLength, NUM_REQ_Q_ENTRIES);
+
+	/* Response Queue Registers */
+	*((u16 *) (qdev->prsp_producer_index)) = 0;
+	qdev->rsp_consumer_index = 0;
+	qdev->rsp_current = qdev->rsp_q_virt_addr;
+
+	ql_write_page1_reg(qdev,
+			   &hmem_regs->rspProducerIndexAddrHigh,
+			   qdev->rsp_producer_index_phy_addr_high);
+
+	ql_write_page1_reg(qdev,
+			   &hmem_regs->rspProducerIndexAddrLow,
+			   qdev->rsp_producer_index_phy_addr_low);
+
+	ql_write_page1_reg(qdev,
+			   &hmem_regs->rspBaseAddrHigh,
+			   MS_64BITS(qdev->rsp_q_phy_addr));
+
+	ql_write_page1_reg(qdev,
+			   &hmem_regs->rspBaseAddrLow,
+			   LS_64BITS(qdev->rsp_q_phy_addr));
+
+	ql_write_page1_reg(qdev, &hmem_regs->rspLength, NUM_RSP_Q_ENTRIES);
+
+	/* Large Buffer Queue */
+	ql_write_page1_reg(qdev,
+			   &hmem_regs->rxLargeQBaseAddrHigh,
+			   MS_64BITS(qdev->lrg_buf_q_phy_addr));
+
+	ql_write_page1_reg(qdev,
+			   &hmem_regs->rxLargeQBaseAddrLow,
+			   LS_64BITS(qdev->lrg_buf_q_phy_addr));
+
+	ql_write_page1_reg(qdev, &hmem_regs->rxLargeQLength, NUM_LBUFQ_ENTRIES);
+
+	ql_write_page1_reg(qdev,
+			   &hmem_regs->rxLargeBufferLength,
+			   qdev->lrg_buffer_len);
+
+	/* Small Buffer Queue */
+	ql_write_page1_reg(qdev,
+			   &hmem_regs->rxSmallQBaseAddrHigh,
+			   MS_64BITS(qdev->small_buf_q_phy_addr));
+
+	ql_write_page1_reg(qdev,
+			   &hmem_regs->rxSmallQBaseAddrLow,
+			   LS_64BITS(qdev->small_buf_q_phy_addr));
+
+	ql_write_page1_reg(qdev, &hmem_regs->rxSmallQLength, NUM_SBUFQ_ENTRIES);
+	ql_write_page1_reg(qdev,
+			   &hmem_regs->rxSmallBufferLength,
+			   QL_SMALL_BUFFER_SIZE);
+
+	qdev->small_buf_q_producer_index = NUM_SBUFQ_ENTRIES - 1;
+	qdev->small_buf_release_cnt = 8;
+	qdev->lrg_buf_q_producer_index = NUM_LBUFQ_ENTRIES - 1;
+	qdev->lrg_buf_release_cnt = 8;
+	qdev->lrg_buf_next_free =
+	    (struct bufq_addr_element *)qdev->lrg_buf_q_virt_addr;
+	qdev->small_buf_index = 0;
+	qdev->lrg_buf_index = 0;
+	qdev->lrg_buf_free_count = 0;
+	qdev->lrg_buf_free_head = NULL;
+	qdev->lrg_buf_free_tail = NULL;
+
+	ql_write_common_reg(qdev,
+			    (u32 *) & port_regs->CommonRegs.
+			    rxSmallQProducerIndex,
+			    qdev->small_buf_q_producer_index);
+	ql_write_common_reg(qdev,
+			    (u32 *) & port_regs->CommonRegs.
+			    rxLargeQProducerIndex,
+			    qdev->lrg_buf_q_producer_index);
+
+	/*
+	 * Find out if the chip has already been initialized.  If it has, then
+	 * we skip some of the initialization.
+	 */
+	clear_bit(QL_LINK_MASTER, &qdev->flags);
+	value = ql_read_page0_reg(qdev, &port_regs->portStatus);
+	if ((value & PORT_STATUS_IC) == 0) {
+
+		/* Chip has not been configured yet, so let it rip. */
+		if(ql_init_misc_registers(qdev)) {
+			status = -1;
+			goto out;
+		}
+
+		if (qdev->mac_index)
+			ql_write_page0_reg(qdev,
+					   &port_regs->mac1MaxFrameLengthReg,
+					   qdev->max_frame_size);
+		else
+			ql_write_page0_reg(qdev,
+					   &port_regs->mac0MaxFrameLengthReg,
+					   qdev->max_frame_size);
+
+		value = qdev->nvram_data.tcpMaxWindowSize;
+		ql_write_page0_reg(qdev, &port_regs->tcpMaxWindow, value);
+
+		value = (0xFFFF << 16) | qdev->nvram_data.extHwConfig;
+
+		if(ql_sem_spinlock(qdev, QL_FLASH_SEM_MASK,
+				(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index)
+				 * 2) << 13)) {
+			status = -1;
+			goto out;
+		}
+		ql_write_page0_reg(qdev, &port_regs->ExternalHWConfig, value);
+		ql_write_page0_reg(qdev, &port_regs->InternalChipConfig,
+				   (((INTERNAL_CHIP_SD | INTERNAL_CHIP_WE) <<
+				     16) | (INTERNAL_CHIP_SD |
+					    INTERNAL_CHIP_WE)));
+		ql_sem_unlock(qdev, QL_FLASH_SEM_MASK);
+	}
+
+
+	if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+			(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
+			 2) << 7)) {
+		status = -1;
+		goto out;
+	}
+
+	ql_init_scan_mode(qdev);
+	ql_get_phy_owner(qdev);
+
+	/* Load the MAC Configuration */
+
+	/* Program lower 32 bits of the MAC address */
+	ql_write_page0_reg(qdev, &port_regs->macAddrIndirectPtrReg,
+			   (MAC_ADDR_INDIRECT_PTR_REG_RP_MASK << 16));
+	ql_write_page0_reg(qdev, &port_regs->macAddrDataReg,
+			   ((qdev->ndev->dev_addr[2] << 24)
+			    | (qdev->ndev->dev_addr[3] << 16)
+			    | (qdev->ndev->dev_addr[4] << 8)
+			    | qdev->ndev->dev_addr[5]));
+
+	/* Program top 16 bits of the MAC address */
+	ql_write_page0_reg(qdev, &port_regs->macAddrIndirectPtrReg,
+			   ((MAC_ADDR_INDIRECT_PTR_REG_RP_MASK << 16) | 1));
+	ql_write_page0_reg(qdev, &port_regs->macAddrDataReg,
+			   ((qdev->ndev->dev_addr[0] << 8)
+			    | qdev->ndev->dev_addr[1]));
+
+	/* Enable Primary MAC */
+	ql_write_page0_reg(qdev, &port_regs->macAddrIndirectPtrReg,
+			   ((MAC_ADDR_INDIRECT_PTR_REG_PE << 16) |
+			    MAC_ADDR_INDIRECT_PTR_REG_PE));
+
+	/* Clear Primary and Secondary IP addresses */
+	ql_write_page0_reg(qdev, &port_regs->ipAddrIndexReg,
+			   ((IP_ADDR_INDEX_REG_MASK << 16) |
+			    (qdev->mac_index << 2)));
+	ql_write_page0_reg(qdev, &port_regs->ipAddrDataReg, 0);
+
+	ql_write_page0_reg(qdev, &port_regs->ipAddrIndexReg,
+			   ((IP_ADDR_INDEX_REG_MASK << 16) |
+			    ((qdev->mac_index << 2) + 1)));
+	ql_write_page0_reg(qdev, &port_regs->ipAddrDataReg, 0);
+
+	ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
+
+	/* Indicate Configuration Complete */
+	ql_write_page0_reg(qdev,
+			   &port_regs->portControl,
+			   ((PORT_CONTROL_CC << 16) | PORT_CONTROL_CC));
+
+	do {
+		value = ql_read_page0_reg(qdev, &port_regs->portStatus);
+		if (value & PORT_STATUS_IC)
+			break;
+		msleep(500);
+	} while (--delay);
+
+	if (delay == 0) {
+		printk(KERN_ERR PFX
+		       "%s: Hw Initialization timeout.\n", qdev->ndev->name);
+		status = -1;
+		goto out;
+	}
+
+	/* Enable Ethernet Function */
+	value =
+	    (PORT_CONTROL_EF | PORT_CONTROL_ET | PORT_CONTROL_EI |
+	     PORT_CONTROL_HH);
+	ql_write_page0_reg(qdev, &port_regs->portControl,
+			   ((value << 16) | value));
+
+out:
+	return status;
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static int ql_adapter_reset(struct ql3_adapter *qdev)
+{
+	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	int status = 0;
+	u16 value;
+	int max_wait_time;
+
+	set_bit(QL_RESET_ACTIVE, &qdev->flags);
+	clear_bit(QL_RESET_DONE, &qdev->flags);
+
+	/*
+	 * Issue soft reset to chip.
+	 */
+	printk(KERN_DEBUG PFX
+	       "%s: Issue soft reset to chip.\n",
+	       qdev->ndev->name);
+	ql_write_common_reg(qdev,
+			    (u32 *) & port_regs->CommonRegs.ispControlStatus,
+			    ((ISP_CONTROL_SR << 16) | ISP_CONTROL_SR));
+
+	/* Wait 3 seconds for reset to complete. */
+	printk(KERN_DEBUG PFX
+	       "%s: Wait 10 milliseconds for reset to complete.\n",
+	       qdev->ndev->name);
+
+	/* Wait until the firmware tells us the Soft Reset is done */
+	max_wait_time = 5;
+	do {
+		value =
+		    ql_read_common_reg(qdev,
+				       &port_regs->CommonRegs.ispControlStatus);
+		if ((value & ISP_CONTROL_SR) == 0)
+			break;
+
+		ssleep(1);
+	} while ((--max_wait_time));
+
+	/*
+	 * Also, make sure that the Network Reset Interrupt bit has been
+	 * cleared after the soft reset has taken place.
+	 */
+	value =
+	    ql_read_common_reg(qdev, &port_regs->CommonRegs.ispControlStatus);
+	if (value & ISP_CONTROL_RI) {
+		printk(KERN_DEBUG PFX
+		       "ql_adapter_reset: clearing RI after reset.\n");
+		ql_write_common_reg(qdev,
+				    (u32 *) & port_regs->CommonRegs.
+				    ispControlStatus,
+				    ((ISP_CONTROL_RI << 16) | ISP_CONTROL_RI));
+	}
+
+	if (max_wait_time == 0) {
+		/* Issue Force Soft Reset */
+		ql_write_common_reg(qdev,
+				    (u32 *) & port_regs->CommonRegs.
+				    ispControlStatus,
+				    ((ISP_CONTROL_FSR << 16) |
+				     ISP_CONTROL_FSR));
+		/*
+		 * Wait until the firmware tells us the Force Soft Reset is
+		 * done
+		 */
+		max_wait_time = 5;
+		do {
+			value =
+			    ql_read_common_reg(qdev,
+					       &port_regs->CommonRegs.
+					       ispControlStatus);
+			if ((value & ISP_CONTROL_FSR) == 0) {
+				break;
+			}
+			ssleep(1);
+		} while ((--max_wait_time));
+	}
+	if (max_wait_time == 0)
+		status = 1;
+
+	clear_bit(QL_RESET_ACTIVE, &qdev->flags);
+	set_bit(QL_RESET_DONE, &qdev->flags);
+	return status;
+}
+
+static void ql_set_mac_info(struct ql3_adapter *qdev)
+{
+	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	u32 value, port_status;
+	u8 func_number;
+
+	/* Get the function number */
+	value =
+	    ql_read_common_reg_l(qdev, &port_regs->CommonRegs.ispControlStatus);
+	func_number = (u8) ((value >> 4) & OPCODE_FUNC_ID_MASK);
+	port_status = ql_read_page0_reg(qdev, &port_regs->portStatus);
+	switch (value & ISP_CONTROL_FN_MASK) {
+	case ISP_CONTROL_FN0_NET:
+		qdev->mac_index = 0;
+		qdev->mac_ob_opcode = OUTBOUND_MAC_IOCB | func_number;
+		qdev->tcp_ob_opcode = OUTBOUND_TCP_IOCB | func_number;
+		qdev->update_ob_opcode = UPDATE_NCB_IOCB | func_number;
+		qdev->mb_bit_mask = FN0_MA_BITS_MASK;
+		qdev->PHYAddr = PORT0_PHY_ADDRESS;
+		if (port_status & PORT_STATUS_SM0)
+			set_bit(QL_LINK_OPTICAL,&qdev->flags);
+		else
+			clear_bit(QL_LINK_OPTICAL,&qdev->flags);
+		break;
+
+	case ISP_CONTROL_FN1_NET:
+		qdev->mac_index = 1;
+		qdev->mac_ob_opcode = OUTBOUND_MAC_IOCB | func_number;
+		qdev->tcp_ob_opcode = OUTBOUND_TCP_IOCB | func_number;
+		qdev->update_ob_opcode = UPDATE_NCB_IOCB | func_number;
+		qdev->mb_bit_mask = FN1_MA_BITS_MASK;
+		qdev->PHYAddr = PORT1_PHY_ADDRESS;
+		if (port_status & PORT_STATUS_SM1)
+			set_bit(QL_LINK_OPTICAL,&qdev->flags);
+		else
+			clear_bit(QL_LINK_OPTICAL,&qdev->flags);
+		break;
+
+	case ISP_CONTROL_FN0_SCSI:
+	case ISP_CONTROL_FN1_SCSI:
+	default:
+		printk(KERN_DEBUG PFX
+		       "%s: Invalid function number, ispControlStatus = 0x%x\n",
+		       qdev->ndev->name,value);
+		break;
+	}
+	qdev->numPorts = qdev->nvram_data.numPorts;
+}
+
+static void ql_display_dev_info(struct net_device *ndev)
+{
+	struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
+	struct pci_dev *pdev = qdev->pdev;
+
+	printk(KERN_INFO PFX
+	       "\n%s Adapter %d RevisionID %d found on PCI slot %d.\n",
+	       DRV_NAME, qdev->index, qdev->chip_rev_id, qdev->pci_slot);
+	printk(KERN_INFO PFX
+	       "%s Interface.\n",
+	       test_bit(QL_LINK_OPTICAL,&qdev->flags) ? "OPTICAL" : "COPPER");
+
+	/*
+	 * Print PCI bus width/type.
+	 */
+	printk(KERN_INFO PFX
+	       "Bus interface is %s %s.\n",
+	       ((qdev->pci_width == 64) ? "64-bit" : "32-bit"),
+	       ((qdev->pci_x) ? "PCI-X" : "PCI"));
+
+	printk(KERN_INFO PFX
+	       "mem  IO base address adjusted = 0x%p\n",
+	       qdev->mem_map_registers);
+	printk(KERN_INFO PFX "Interrupt number = %d\n", pdev->irq);
+
+	if (netif_msg_probe(qdev))
+		printk(KERN_INFO PFX
+		       "%s: MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
+		       ndev->name, ndev->dev_addr[0], ndev->dev_addr[1],
+		       ndev->dev_addr[2], ndev->dev_addr[3], ndev->dev_addr[4],
+		       ndev->dev_addr[5]);
+}
+
+static int ql_adapter_down(struct ql3_adapter *qdev, int do_reset)
+{
+	struct net_device *ndev = qdev->ndev;
+	int retval = 0;
+
+	netif_stop_queue(ndev);
+	netif_carrier_off(ndev);
+
+	clear_bit(QL_ADAPTER_UP,&qdev->flags);
+	clear_bit(QL_LINK_MASTER,&qdev->flags);
+
+	ql_disable_interrupts(qdev);
+
+	free_irq(qdev->pdev->irq, ndev);
+
+	if (qdev->msi && test_bit(QL_MSI_ENABLED,&qdev->flags)) {
+		printk(KERN_INFO PFX
+		       "%s: calling pci_disable_msi().\n", qdev->ndev->name);
+		clear_bit(QL_MSI_ENABLED,&qdev->flags);
+		pci_disable_msi(qdev->pdev);
+	}
+
+	del_timer_sync(&qdev->adapter_timer);
+
+	netif_poll_disable(ndev);
+
+	if (do_reset) {
+		int soft_reset;
+		unsigned long hw_flags;
+
+		spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+		if (ql_wait_for_drvr_lock(qdev)) {
+			if ((soft_reset = ql_adapter_reset(qdev))) {
+				printk(KERN_ERR PFX
+				       "%s: ql_adapter_reset(%d) FAILED!\n",
+				       ndev->name, qdev->index);
+			}
+			printk(KERN_ERR PFX
+				"%s: Releaseing driver lock via chip reset.\n",ndev->name);
+		} else {
+			printk(KERN_ERR PFX
+			       "%s: Could not acquire driver lock to do "
+			       "reset!\n", ndev->name);
+			retval = -1;
+		}
+		spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+	}
+	ql_free_mem_resources(qdev);
+	return retval;
+}
+
+static int ql_adapter_up(struct ql3_adapter *qdev)
+{
+	struct net_device *ndev = qdev->ndev;
+	int err;
+	unsigned long irq_flags = SA_SAMPLE_RANDOM | SA_SHIRQ;
+	unsigned long hw_flags;
+
+	if (ql_alloc_mem_resources(qdev)) {
+		printk(KERN_ERR PFX
+		       "%s Unable to  allocate buffers.\n", ndev->name);
+		return -ENOMEM;
+	}
+
+	if (qdev->msi) {
+		if (pci_enable_msi(qdev->pdev)) {
+			printk(KERN_ERR PFX
+			       "%s: User requested MSI, but MSI failed to "
+			       "initialize.  Continuing without MSI.\n",
+			       qdev->ndev->name);
+			qdev->msi = 0;
+		} else {
+			printk(KERN_INFO PFX "%s: MSI Enabled...\n", qdev->ndev->name);
+			set_bit(QL_MSI_ENABLED,&qdev->flags);
+			irq_flags &= ~SA_SHIRQ;
+		}
+	}
+
+	if ((err = request_irq(qdev->pdev->irq,
+			       ql3xxx_isr,
+			       irq_flags, ndev->name, ndev))) {
+		printk(KERN_ERR PFX
+		       "%s: Failed to reserve interrupt %d already in use.\n",
+		       ndev->name, qdev->pdev->irq);
+		goto err_irq;
+	}
+
+	spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+
+	if ((err = ql_wait_for_drvr_lock(qdev))) {
+		if ((err = ql_adapter_initialize(qdev))) {
+			printk(KERN_ERR PFX
+			       "%s: Unable to initialize adapter.\n",
+			       ndev->name);
+			goto err_init;
+		}
+		printk(KERN_ERR PFX
+				"%s: Releaseing driver lock.\n",ndev->name);
+		ql_sem_unlock(qdev, QL_DRVR_SEM_MASK);
+	} else {
+		printk(KERN_ERR PFX
+		       "%s: Could not aquire driver lock.\n",
+		       ndev->name);
+		goto err_lock;
+	}
+
+	spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+
+	set_bit(QL_ADAPTER_UP,&qdev->flags);
+
+	mod_timer(&qdev->adapter_timer, jiffies + HZ * 1);
+
+	netif_poll_enable(ndev);
+	ql_enable_interrupts(qdev);
+	return 0;
+
+err_init:
+	ql_sem_unlock(qdev, QL_DRVR_SEM_MASK);
+err_lock:
+	free_irq(qdev->pdev->irq, ndev);
+err_irq:
+	if (qdev->msi && test_bit(QL_MSI_ENABLED,&qdev->flags)) {
+		printk(KERN_INFO PFX
+		       "%s: calling pci_disable_msi().\n",
+		       qdev->ndev->name);
+		clear_bit(QL_MSI_ENABLED,&qdev->flags);
+		pci_disable_msi(qdev->pdev);
+	}
+	return err;
+}
+
+static int ql_cycle_adapter(struct ql3_adapter *qdev, int reset)
+{
+	if( ql_adapter_down(qdev,reset) || ql_adapter_up(qdev)) {
+		printk(KERN_ERR PFX
+				"%s: Driver up/down cycle failed, "
+				"closing device\n",qdev->ndev->name);
+		dev_close(qdev->ndev);
+		return -1;
+	}
+	return 0;
+}
+
+static int ql3xxx_close(struct net_device *ndev)
+{
+	struct ql3_adapter *qdev = netdev_priv(ndev);
+
+	/*
+	 * Wait for device to recover from a reset.
+	 * (Rarely happens, but possible.)
+	 */
+	while (!test_bit(QL_ADAPTER_UP,&qdev->flags))
+		msleep(50);
+
+	ql_adapter_down(qdev,QL_DO_RESET);
+	return 0;
+}
+
+static int ql3xxx_open(struct net_device *ndev)
+{
+	struct ql3_adapter *qdev = netdev_priv(ndev);
+	return (ql_adapter_up(qdev));
+}
+
+static struct net_device_stats *ql3xxx_get_stats(struct net_device *dev)
+{
+	struct ql3_adapter *qdev = (struct ql3_adapter *)dev->priv;
+	return &qdev->stats;
+}
+
+static int ql3xxx_change_mtu(struct net_device *ndev, int new_mtu)
+{
+	struct ql3_adapter *qdev = netdev_priv(ndev);
+	printk(KERN_ERR PFX "%s:  new mtu size = %d.\n", ndev->name, new_mtu);
+	if (new_mtu != NORMAL_MTU_SIZE && new_mtu != JUMBO_MTU_SIZE) {
+		printk(KERN_ERR PFX
+		       "%s: mtu size of %d is not valid.  Use exactly %d or "
+		       "%d.\n", ndev->name, new_mtu, NORMAL_MTU_SIZE,
+		       JUMBO_MTU_SIZE);
+		return -EINVAL;
+	}
+
+	if (!netif_running(ndev)) {
+		ndev->mtu = new_mtu;
+		return 0;
+	}
+
+	ndev->mtu = new_mtu;
+	return ql_cycle_adapter(qdev,QL_DO_RESET);
+}
+
+static void ql3xxx_set_multicast_list(struct net_device *ndev)
+{
+	/*
+	 * We are manually parsing the list in the net_device structure.
+	 */
+	return;
+}
+
+static int ql3xxx_set_mac_address(struct net_device *ndev, void *p)
+{
+	struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
+	struct ql3xxx_port_registers __iomem *port_regs =
+	    		qdev->mem_map_registers;
+	struct sockaddr *addr = p;
+	unsigned long hw_flags;
+
+	if (netif_running(ndev))
+		return -EBUSY;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EADDRNOTAVAIL;
+
+	memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len);
+
+	spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+	/* Program lower 32 bits of the MAC address */
+	ql_write_page0_reg(qdev, &port_regs->macAddrIndirectPtrReg,
+			   (MAC_ADDR_INDIRECT_PTR_REG_RP_MASK << 16));
+	ql_write_page0_reg(qdev, &port_regs->macAddrDataReg,
+			   ((ndev->dev_addr[2] << 24) | (ndev->
+							 dev_addr[3] << 16) |
+			    (ndev->dev_addr[4] << 8) | ndev->dev_addr[5]));
+
+	/* Program top 16 bits of the MAC address */
+	ql_write_page0_reg(qdev, &port_regs->macAddrIndirectPtrReg,
+			   ((MAC_ADDR_INDIRECT_PTR_REG_RP_MASK << 16) | 1));
+	ql_write_page0_reg(qdev, &port_regs->macAddrDataReg,
+			   ((ndev->dev_addr[0] << 8) | ndev->dev_addr[1]));
+	spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+
+	return 0;
+}
+
+static void ql3xxx_tx_timeout(struct net_device *ndev)
+{
+	struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
+
+	printk(KERN_ERR PFX "%s: Resetting...\n", ndev->name);
+	/*
+	 * Stop the queues, we've got a problem.
+	 */
+	netif_stop_queue(ndev);
+
+	/*
+	 * Wake up the worker to process this event.
+	 */
+	queue_work(qdev->workqueue, &qdev->tx_timeout_work);
+}
+
+static void ql_reset_work(struct ql3_adapter *qdev)
+{
+	struct net_device *ndev = qdev->ndev;
+	u32 value;
+	struct ql_tx_buf_cb *tx_cb;
+	int max_wait_time, i;
+	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	unsigned long hw_flags;
+
+	if (test_bit((QL_RESET_PER_SCSI | QL_RESET_START),&qdev->flags)) {
+		clear_bit(QL_LINK_MASTER,&qdev->flags);
+
+		/*
+		 * Loop through the active list and return the skb.
+		 */
+		for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) {
+			tx_cb = &qdev->tx_buf[i];
+			if (tx_cb->skb) {
+
+				printk(KERN_DEBUG PFX
+				       "%s: Freeing lost SKB.\n",
+				       qdev->ndev->name);
+				pci_unmap_single(qdev->pdev,
+					pci_unmap_addr(tx_cb, mapaddr),
+					pci_unmap_len(tx_cb, maplen), PCI_DMA_TODEVICE);
+				dev_kfree_skb(tx_cb->skb);
+				tx_cb->skb = NULL;
+			}
+		}
+
+		printk(KERN_ERR PFX
+		       "%s: Clearing NRI after reset.\n", qdev->ndev->name);
+		spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+		ql_write_common_reg(qdev,
+				    &port_regs->CommonRegs.
+				    ispControlStatus,
+				    ((ISP_CONTROL_RI << 16) | ISP_CONTROL_RI));
+		/*
+		 * Wait the for Soft Reset to Complete.
+		 */
+		max_wait_time = 10;
+		do {
+			value = ql_read_common_reg(qdev,
+						   &port_regs->CommonRegs.
+
+						   ispControlStatus);
+			if ((value & ISP_CONTROL_SR) == 0) {
+				printk(KERN_DEBUG PFX
+				       "%s: reset completed.\n",
+				       qdev->ndev->name);
+				break;
+			}
+
+			if (value & ISP_CONTROL_RI) {
+				printk(KERN_DEBUG PFX
+				       "%s: clearing NRI after reset.\n",
+				       qdev->ndev->name);
+				ql_write_common_reg(qdev,
+						    (u32 *) &
+						    port_regs->
+						    CommonRegs.
+						    ispControlStatus,
+						    ((ISP_CONTROL_RI <<
+						      16) | ISP_CONTROL_RI));
+			}
+
+			ssleep(1);
+		} while (--max_wait_time);
+		spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+
+		if (value & ISP_CONTROL_SR) {
+
+			/*
+			 * Set the reset flags and clear the board again.
+			 * Nothing else to do...
+			 */
+			printk(KERN_ERR PFX
+			       "%s: Timed out waiting for reset to "
+			       "complete.\n", ndev->name);
+			printk(KERN_ERR PFX
+			       "%s: Do a reset.\n", ndev->name);
+			clear_bit(QL_RESET_PER_SCSI,&qdev->flags);
+			clear_bit(QL_RESET_START,&qdev->flags);
+			ql_cycle_adapter(qdev,QL_DO_RESET);
+			return;
+		}
+
+		clear_bit(QL_RESET_ACTIVE,&qdev->flags);
+		clear_bit(QL_RESET_PER_SCSI,&qdev->flags);
+		clear_bit(QL_RESET_START,&qdev->flags);
+		ql_cycle_adapter(qdev,QL_NO_RESET);
+	}
+}
+
+static void ql_tx_timeout_work(struct ql3_adapter *qdev)
+{
+	ql_cycle_adapter(qdev,QL_DO_RESET);
+}
+
+static void ql_get_board_info(struct ql3_adapter *qdev)
+{
+	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+	u32 value;
+
+	value = ql_read_page0_reg_l(qdev, &port_regs->portStatus);
+
+	qdev->chip_rev_id = ((value & PORT_STATUS_REV_ID_MASK) >> 12);
+	if (value & PORT_STATUS_64)
+		qdev->pci_width = 64;
+	else
+		qdev->pci_width = 32;
+	if (value & PORT_STATUS_X)
+		qdev->pci_x = 1;
+	else
+		qdev->pci_x = 0;
+	qdev->pci_slot = (u8) PCI_SLOT(qdev->pdev->devfn);
+}
+
+static void ql3xxx_timer(unsigned long ptr)
+{
+	struct ql3_adapter *qdev = (struct ql3_adapter *)ptr;
+
+	if (test_bit(QL_RESET_ACTIVE,&qdev->flags)) {
+		printk(KERN_DEBUG PFX
+		       "%s: Reset in progress.\n",
+		       qdev->ndev->name);
+		goto end;
+	}
+
+	ql_link_state_machine(qdev);
+
+	/* Restart timer on 2 second interval. */
+end:
+	mod_timer(&qdev->adapter_timer, jiffies + HZ * 1);
+}
+
+static int __devinit ql3xxx_probe(struct pci_dev *pdev,
+				  const struct pci_device_id *pci_entry)
+{
+	struct net_device *ndev = NULL;
+	struct ql3_adapter *qdev = NULL;
+	static int cards_found = 0;
+	int pci_using_dac, err;
+
+	err = pci_enable_device(pdev);
+	if (err) {
+		printk(KERN_ERR PFX "%s cannot enable PCI device\n",
+		       pci_name(pdev));
+		goto err_out;
+	}
+
+	err = pci_request_regions(pdev, DRV_NAME);
+	if (err) {
+		printk(KERN_ERR PFX "%s cannot obtain PCI resources\n",
+		       pci_name(pdev));
+		goto err_out_disable_pdev;
+	}
+
+	pci_set_master(pdev);
+
+	if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+		pci_using_dac = 1;
+		err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+	} else if (!(err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) {
+		pci_using_dac = 0;
+		err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+	}
+
+	if (err) {
+		printk(KERN_ERR PFX "%s no usable DMA configuration\n",
+		       pci_name(pdev));
+		goto err_out_free_regions;
+	}
+
+	ndev = alloc_etherdev(sizeof(struct ql3_adapter));
+	if (!ndev)
+		goto err_out_free_regions;
+
+	SET_MODULE_OWNER(ndev);
+	SET_NETDEV_DEV(ndev, &pdev->dev);
+
+	ndev->features = NETIF_F_LLTX;
+	if (pci_using_dac)
+		ndev->features |= NETIF_F_HIGHDMA;
+
+	pci_set_drvdata(pdev, ndev);
+
+	qdev = netdev_priv(ndev);
+	qdev->index = cards_found;
+	qdev->ndev = ndev;
+	qdev->pdev = pdev;
+	qdev->port_link_state = LS_DOWN;
+	if (msi)
+		qdev->msi = 1;
+
+	qdev->msg_enable = netif_msg_init(debug, default_msg);
+
+	qdev->mem_map_registers =
+	    ioremap_nocache(pci_resource_start(pdev, 1),
+			    pci_resource_len(qdev->pdev, 1));
+	if (!qdev->mem_map_registers) {
+		printk(KERN_ERR PFX "%s: cannot map device registers\n",
+		       pci_name(pdev));
+		goto err_out_free_ndev;
+	}
+
+	spin_lock_init(&qdev->adapter_lock);
+	spin_lock_init(&qdev->hw_lock);
+
+	/* Set driver entry points */
+	ndev->open = ql3xxx_open;
+	ndev->hard_start_xmit = ql3xxx_send;
+	ndev->stop = ql3xxx_close;
+	ndev->get_stats = ql3xxx_get_stats;
+	ndev->change_mtu = ql3xxx_change_mtu;
+	ndev->set_multicast_list = ql3xxx_set_multicast_list;
+	SET_ETHTOOL_OPS(ndev, &ql3xxx_ethtool_ops);
+	ndev->set_mac_address = ql3xxx_set_mac_address;
+	ndev->tx_timeout = ql3xxx_tx_timeout;
+	ndev->watchdog_timeo = 5 * HZ;
+
+	ndev->poll = &ql_poll;
+	ndev->weight = 64;
+
+	ndev->irq = pdev->irq;
+
+	/* make sure the EEPROM is good */
+	if (ql_get_nvram_params(qdev)) {
+		printk(KERN_ALERT PFX
+		       "ql3xxx_probe: Adapter #%d, Invalid NVRAM parameters.\n",
+		       qdev->index);
+		goto err_out_iounmap;
+	}
+
+	ql_set_mac_info(qdev);
+
+	/* Validate and set parameters */
+	if (qdev->mac_index) {
+		memcpy(ndev->dev_addr, &qdev->nvram_data.funcCfg_fn2.macAddress,
+		       ETH_ALEN);
+	} else {
+		memcpy(ndev->dev_addr, &qdev->nvram_data.funcCfg_fn0.macAddress,
+		       ETH_ALEN);
+	}
+	memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len);
+
+	ndev->tx_queue_len = NUM_REQ_Q_ENTRIES;
+
+	/* Turn off support for multicasting */
+	ndev->flags &= ~IFF_MULTICAST;
+
+	/* Record PCI bus information. */
+	ql_get_board_info(qdev);
+
+	/*
+	 * Set the Maximum Memory Read Byte Count value. We do this to handle
+	 * jumbo frames.
+	 */
+	if (qdev->pci_x) {
+		pci_write_config_word(pdev, (int)0x4e, (u16) 0x0036);
+	}
+
+	err = register_netdev(ndev);
+	if (err) {
+		printk(KERN_ERR PFX "%s: cannot register net device\n",
+		       pci_name(pdev));
+		goto err_out_iounmap;
+	}
+
+	/* we're going to reset, so assume we have no link for now */
+
+	netif_carrier_off(ndev);
+	netif_stop_queue(ndev);
+
+	qdev->workqueue = create_singlethread_workqueue(ndev->name);
+	INIT_WORK(&qdev->reset_work, (void (*)(void *))ql_reset_work, qdev);
+	INIT_WORK(&qdev->tx_timeout_work,
+		  (void (*)(void *))ql_tx_timeout_work, qdev);
+
+	init_timer(&qdev->adapter_timer);
+	qdev->adapter_timer.function = ql3xxx_timer;
+	qdev->adapter_timer.expires = jiffies + HZ * 2;	/* two second delay */
+	qdev->adapter_timer.data = (unsigned long)qdev;
+
+	if(!cards_found) {
+		printk(KERN_ALERT PFX "%s\n", DRV_STRING);
+		printk(KERN_ALERT PFX "Driver name: %s, Version: %s.\n",
+	    	   DRV_NAME, DRV_VERSION);
+	}
+	ql_display_dev_info(ndev);
+
+	cards_found++;
+	return 0;
+
+err_out_iounmap:
+	iounmap(qdev->mem_map_registers);
+err_out_free_ndev:
+	free_netdev(ndev);
+err_out_free_regions:
+	pci_release_regions(pdev);
+err_out_disable_pdev:
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+err_out:
+	return err;
+}
+
+static void __devexit ql3xxx_remove(struct pci_dev *pdev)
+{
+	struct net_device *ndev = pci_get_drvdata(pdev);
+	struct ql3_adapter *qdev = netdev_priv(ndev);
+
+	unregister_netdev(ndev);
+	qdev = netdev_priv(ndev);
+
+	ql_disable_interrupts(qdev);
+
+	if (qdev->workqueue) {
+		cancel_delayed_work(&qdev->reset_work);
+		cancel_delayed_work(&qdev->tx_timeout_work);
+		destroy_workqueue(qdev->workqueue);
+		qdev->workqueue = NULL;
+	}
+
+	iounmap((void *)qdev->mmap_virt_base);
+	pci_release_regions(pdev);
+	pci_set_drvdata(pdev, NULL);
+	free_netdev(ndev);
+}
+
+static struct pci_driver ql3xxx_driver = {
+
+	.name = DRV_NAME,
+	.id_table = ql3xxx_pci_tbl,
+	.probe = ql3xxx_probe,
+	.remove = __devexit_p(ql3xxx_remove),
+};
+
+static int __init ql3xxx_init_module(void)
+{
+	return pci_register_driver(&ql3xxx_driver);
+}
+
+static void __exit ql3xxx_exit(void)
+{
+	pci_unregister_driver(&ql3xxx_driver);
+}
+
+module_init(ql3xxx_init_module);
+module_exit(ql3xxx_exit);
diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h
new file mode 100644
index 0000000..9492cee
--- /dev/null
+++ b/drivers/net/qla3xxx.h
@@ -0,0 +1,1194 @@
+/*
+ * QLogic QLA3xxx NIC HBA Driver
+ * Copyright (c)  2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla3xxx for copyright and licensing details.
+ */
+#ifndef _QLA3XXX_H_
+#define _QLA3XXX_H_
+
+/*
+ * IOCB Definitions...
+ */
+#pragma pack(1)
+
+#define OPCODE_OB_MAC_IOCB_FN0          0x01
+#define OPCODE_OB_MAC_IOCB_FN2          0x21
+#define OPCODE_OB_TCP_IOCB_FN0          0x03
+#define OPCODE_OB_TCP_IOCB_FN2          0x23
+#define OPCODE_UPDATE_NCB_IOCB_FN0      0x00
+#define OPCODE_UPDATE_NCB_IOCB_FN2      0x20
+
+#define OPCODE_UPDATE_NCB_IOCB      0xF0
+#define OPCODE_IB_MAC_IOCB          0xF9
+#define OPCODE_IB_IP_IOCB           0xFA
+#define OPCODE_IB_TCP_IOCB          0xFB
+#define OPCODE_DUMP_PROTO_IOCB      0xFE
+#define OPCODE_BUFFER_ALERT_IOCB    0xFB
+
+#define OPCODE_FUNC_ID_MASK                 0x30
+#define OUTBOUND_MAC_IOCB                   0x01	/* plus function bits */
+#define OUTBOUND_TCP_IOCB                   0x03	/* plus function bits */
+#define UPDATE_NCB_IOCB                     0x00	/* plus function bits */
+
+#define FN0_MA_BITS_MASK    0x00
+#define FN1_MA_BITS_MASK    0x80
+
+struct ob_mac_iocb_req {
+	u8 opcode;
+	u8 flags;
+#define OB_MAC_IOCB_REQ_MA  0xC0
+#define OB_MAC_IOCB_REQ_F   0x20
+#define OB_MAC_IOCB_REQ_X   0x10
+#define OB_MAC_IOCB_REQ_D   0x02
+#define OB_MAC_IOCB_REQ_I   0x01
+	__le16 reserved0;
+
+	__le32 transaction_id;
+	__le16 data_len;
+	__le16 reserved1;
+	__le32 reserved2;
+	__le32 reserved3;
+	__le32 buf_addr0_low;
+	__le32 buf_addr0_high;
+	__le32 buf_0_len;
+	__le32 buf_addr1_low;
+	__le32 buf_addr1_high;
+	__le32 buf_1_len;
+	__le32 buf_addr2_low;
+	__le32 buf_addr2_high;
+	__le32 buf_2_len;
+	__le32 reserved4;
+	__le32 reserved5;
+};
+/*
+ * The following constants define control bits for buffer
+ * length fields for all IOCB's.
+ */
+#define OB_MAC_IOCB_REQ_E   0x80000000	/* Last valid buffer in list. */
+#define OB_MAC_IOCB_REQ_C   0x40000000	/* points to an OAL. (continuation) */
+#define OB_MAC_IOCB_REQ_L   0x20000000	/* Auburn local address pointer. */
+#define OB_MAC_IOCB_REQ_R   0x10000000	/* 32-bit address pointer. */
+
+struct ob_mac_iocb_rsp {
+	u8 opcode;
+	u8 flags;
+#define OB_MAC_IOCB_RSP_P   0x08
+#define OB_MAC_IOCB_RSP_S   0x02
+#define OB_MAC_IOCB_RSP_I   0x01
+
+	__le16 reserved0;
+	__le32 transaction_id;
+	__le32 reserved1;
+	__le32 reserved2;
+};
+
+struct ib_mac_iocb_rsp {
+	u8 opcode;
+	u8 flags;
+#define IB_MAC_IOCB_RSP_S   0x80
+#define IB_MAC_IOCB_RSP_H1  0x40
+#define IB_MAC_IOCB_RSP_H0  0x20
+#define IB_MAC_IOCB_RSP_B   0x10
+#define IB_MAC_IOCB_RSP_M   0x08
+#define IB_MAC_IOCB_RSP_MA  0x07
+
+	__le16 length;
+	__le32 reserved;
+	__le32 ial_low;
+	__le32 ial_high;
+
+};
+
+struct ob_ip_iocb_req {
+	u8 opcode;
+	__le16 flags;
+#define OB_IP_IOCB_REQ_O        0x100
+#define OB_IP_IOCB_REQ_H        0x008
+#define OB_IP_IOCB_REQ_U        0x004
+#define OB_IP_IOCB_REQ_D        0x002
+#define OB_IP_IOCB_REQ_I        0x001
+
+	u8 reserved0;
+
+	__le32 transaction_id;
+	__le16 data_len;
+	__le16 reserved1;
+	__le32 hncb_ptr_low;
+	__le32 hncb_ptr_high;
+	__le32 buf_addr0_low;
+	__le32 buf_addr0_high;
+	__le32 buf_0_len;
+	__le32 buf_addr1_low;
+	__le32 buf_addr1_high;
+	__le32 buf_1_len;
+	__le32 buf_addr2_low;
+	__le32 buf_addr2_high;
+	__le32 buf_2_len;
+	__le32 reserved2;
+	__le32 reserved3;
+};
+
+/* defines for BufferLength fields above */
+#define OB_IP_IOCB_REQ_E    0x80000000
+#define OB_IP_IOCB_REQ_C    0x40000000
+#define OB_IP_IOCB_REQ_L    0x20000000
+#define OB_IP_IOCB_REQ_R    0x10000000
+
+struct ob_ip_iocb_rsp {
+	u8 opcode;
+	u8 flags;
+#define OB_MAC_IOCB_RSP_E       0x08
+#define OB_MAC_IOCB_RSP_L       0x04
+#define OB_MAC_IOCB_RSP_S       0x02
+#define OB_MAC_IOCB_RSP_I       0x01
+
+	__le16 reserved0;
+	__le32 transaction_id;
+	__le32 reserved1;
+	__le32 reserved2;
+};
+
+struct ob_tcp_iocb_req {
+	u8 opcode;
+
+	u8 flags0;
+#define OB_TCP_IOCB_REQ_P       0x80
+#define OB_TCP_IOCB_REQ_CI      0x20
+#define OB_TCP_IOCB_REQ_H       0x10
+#define OB_TCP_IOCB_REQ_LN      0x08
+#define OB_TCP_IOCB_REQ_K       0x04
+#define OB_TCP_IOCB_REQ_D       0x02
+#define OB_TCP_IOCB_REQ_I       0x01
+
+	u8 flags1;
+#define OB_TCP_IOCB_REQ_OSM     0x40
+#define OB_TCP_IOCB_REQ_URG     0x20
+#define OB_TCP_IOCB_REQ_ACK     0x10
+#define OB_TCP_IOCB_REQ_PSH     0x08
+#define OB_TCP_IOCB_REQ_RST     0x04
+#define OB_TCP_IOCB_REQ_SYN     0x02
+#define OB_TCP_IOCB_REQ_FIN     0x01
+
+	u8 options_len;
+#define OB_TCP_IOCB_REQ_OMASK   0xF0
+#define OB_TCP_IOCB_REQ_SHIFT   4
+
+	__le32 transaction_id;
+	__le32 data_len;
+	__le32 hncb_ptr_low;
+	__le32 hncb_ptr_high;
+	__le32 buf_addr0_low;
+	__le32 buf_addr0_high;
+	__le32 buf_0_len;
+	__le32 buf_addr1_low;
+	__le32 buf_addr1_high;
+	__le32 buf_1_len;
+	__le32 buf_addr2_low;
+	__le32 buf_addr2_high;
+	__le32 buf_2_len;
+	__le32 time_stamp;
+	__le32 reserved1;
+};
+
+struct ob_tcp_iocb_rsp {
+	u8 opcode;
+
+	u8 flags0;
+#define OB_TCP_IOCB_RSP_C       0x20
+#define OB_TCP_IOCB_RSP_H       0x10
+#define OB_TCP_IOCB_RSP_LN      0x08
+#define OB_TCP_IOCB_RSP_K       0x04
+#define OB_TCP_IOCB_RSP_D       0x02
+#define OB_TCP_IOCB_RSP_I       0x01
+
+	u8 flags1;
+#define OB_TCP_IOCB_RSP_E       0x10
+#define OB_TCP_IOCB_RSP_W       0x08
+#define OB_TCP_IOCB_RSP_P       0x04
+#define OB_TCP_IOCB_RSP_T       0x02
+#define OB_TCP_IOCB_RSP_F       0x01
+
+	u8 state;
+#define OB_TCP_IOCB_RSP_SMASK   0xF0
+#define OB_TCP_IOCB_RSP_SHIFT   4
+
+	__le32 transaction_id;
+	__le32 local_ncb_ptr;
+	__le32 reserved0;
+};
+
+struct ib_ip_iocb_rsp {
+	u8 opcode;
+	u8 flags;
+#define IB_IP_IOCB_RSP_S        0x80
+#define IB_IP_IOCB_RSP_H1       0x40
+#define IB_IP_IOCB_RSP_H0       0x20
+#define IB_IP_IOCB_RSP_B        0x10
+#define IB_IP_IOCB_RSP_M        0x08
+#define IB_IP_IOCB_RSP_MA       0x07
+
+	__le16 length;
+	__le16 checksum;
+	__le16 reserved;
+#define IB_IP_IOCB_RSP_R        0x01
+	__le32 ial_low;
+	__le32 ial_high;
+};
+
+struct ib_tcp_iocb_rsp {
+	u8 opcode;
+	u8 flags;
+#define IB_TCP_IOCB_RSP_P       0x80
+#define IB_TCP_IOCB_RSP_T       0x40
+#define IB_TCP_IOCB_RSP_D       0x20
+#define IB_TCP_IOCB_RSP_N       0x10
+#define IB_TCP_IOCB_RSP_IP      0x03
+#define IB_TCP_FLAG_MASK        0xf0
+#define IB_TCP_FLAG_IOCB_SYN    0x00
+
+#define TCP_IB_RSP_FLAGS(x) (x->flags & ~IB_TCP_FLAG_MASK)
+
+	__le16 length;
+	__le32 hncb_ref_num;
+	__le32 ial_low;
+	__le32 ial_high;
+};
+
+struct net_rsp_iocb {
+	u8 opcode;
+	u8 flags;
+	__le16 reserved0;
+	__le32 reserved[3];
+};
+#pragma pack()
+
+/*
+ * Register Definitions...
+ */
+#define PORT0_PHY_ADDRESS   0x1e00
+#define PORT1_PHY_ADDRESS   0x1f00
+
+#define ETHERNET_CRC_SIZE   4
+
+#define MII_SCAN_REGISTER 0x00000001
+
+/* 32-bit ispControlStatus */
+enum {
+	ISP_CONTROL_NP_MASK = 0x0003,
+	ISP_CONTROL_NP_PCSR = 0x0000,
+	ISP_CONTROL_NP_HMCR = 0x0001,
+	ISP_CONTROL_NP_LRAMCR = 0x0002,
+	ISP_CONTROL_NP_PSR = 0x0003,
+	ISP_CONTROL_RI = 0x0008,
+	ISP_CONTROL_CI = 0x0010,
+	ISP_CONTROL_PI = 0x0020,
+	ISP_CONTROL_IN = 0x0040,
+	ISP_CONTROL_BE = 0x0080,
+	ISP_CONTROL_FN_MASK = 0x0700,
+	ISP_CONTROL_FN0_NET = 0x0400,
+	ISP_CONTROL_FN0_SCSI = 0x0500,
+	ISP_CONTROL_FN1_NET = 0x0600,
+	ISP_CONTROL_FN1_SCSI = 0x0700,
+	ISP_CONTROL_LINK_DN_0 = 0x0800,
+	ISP_CONTROL_LINK_DN_1 = 0x1000,
+	ISP_CONTROL_FSR = 0x2000,
+	ISP_CONTROL_FE = 0x4000,
+	ISP_CONTROL_SR = 0x8000,
+};
+
+/* 32-bit ispInterruptMaskReg */
+enum {
+	ISP_IMR_ENABLE_INT = 0x0004,
+	ISP_IMR_DISABLE_RESET_INT = 0x0008,
+	ISP_IMR_DISABLE_CMPL_INT = 0x0010,
+	ISP_IMR_DISABLE_PROC_INT = 0x0020,
+};
+
+/* 32-bit serialPortInterfaceReg */
+enum {
+	ISP_SERIAL_PORT_IF_CLK = 0x0001,
+	ISP_SERIAL_PORT_IF_CS = 0x0002,
+	ISP_SERIAL_PORT_IF_D0 = 0x0004,
+	ISP_SERIAL_PORT_IF_DI = 0x0008,
+	ISP_NVRAM_MASK = (0x000F << 16),
+	ISP_SERIAL_PORT_IF_WE = 0x0010,
+	ISP_SERIAL_PORT_IF_NVR_MASK = 0x001F,
+	ISP_SERIAL_PORT_IF_SCI = 0x0400,
+	ISP_SERIAL_PORT_IF_SC0 = 0x0800,
+	ISP_SERIAL_PORT_IF_SCE = 0x1000,
+	ISP_SERIAL_PORT_IF_SDI = 0x2000,
+	ISP_SERIAL_PORT_IF_SDO = 0x4000,
+	ISP_SERIAL_PORT_IF_SDE = 0x8000,
+	ISP_SERIAL_PORT_IF_I2C_MASK = 0xFC00,
+};
+
+/* semaphoreReg */
+enum {
+	QL_RESOURCE_MASK_BASE_CODE = 0x7,
+	QL_RESOURCE_BITS_BASE_CODE = 0x4,
+	QL_DRVR_SEM_BITS = (QL_RESOURCE_BITS_BASE_CODE << 1),
+	QL_DDR_RAM_SEM_BITS = (QL_RESOURCE_BITS_BASE_CODE << 4),
+	QL_PHY_GIO_SEM_BITS = (QL_RESOURCE_BITS_BASE_CODE << 7),
+	QL_NVRAM_SEM_BITS = (QL_RESOURCE_BITS_BASE_CODE << 10),
+	QL_FLASH_SEM_BITS = (QL_RESOURCE_BITS_BASE_CODE << 13),
+	QL_DRVR_SEM_MASK = (QL_RESOURCE_MASK_BASE_CODE << (1 + 16)),
+	QL_DDR_RAM_SEM_MASK = (QL_RESOURCE_MASK_BASE_CODE << (4 + 16)),
+	QL_PHY_GIO_SEM_MASK = (QL_RESOURCE_MASK_BASE_CODE << (7 + 16)),
+	QL_NVRAM_SEM_MASK = (QL_RESOURCE_MASK_BASE_CODE << (10 + 16)),
+	QL_FLASH_SEM_MASK = (QL_RESOURCE_MASK_BASE_CODE << (13 + 16)),
+};
+
+ /*
+  * QL3XXX memory-mapped registers
+  * QL3XXX has 4 "pages" of registers, each page occupying
+  * 256 bytes.  Each page has a "common" area at the start and then
+  * page-specific registers after that.
+  */
+struct ql3xxx_common_registers {
+	u32 MB0;		/* Offset 0x00 */
+	u32 MB1;		/* Offset 0x04 */
+	u32 MB2;		/* Offset 0x08 */
+	u32 MB3;		/* Offset 0x0c */
+	u32 MB4;		/* Offset 0x10 */
+	u32 MB5;		/* Offset 0x14 */
+	u32 MB6;		/* Offset 0x18 */
+	u32 MB7;		/* Offset 0x1c */
+	u32 flashBiosAddr;
+	u32 flashBiosData;
+	u32 ispControlStatus;
+	u32 ispInterruptMaskReg;
+	u32 serialPortInterfaceReg;
+	u32 semaphoreReg;
+	u32 reqQProducerIndex;
+	u32 rspQConsumerIndex;
+
+	u32 rxLargeQProducerIndex;
+	u32 rxSmallQProducerIndex;
+	u32 arcMadiCommand;
+	u32 arcMadiData;
+};
+
+enum {
+	EXT_HW_CONFIG_SP_MASK = 0x0006,
+	EXT_HW_CONFIG_SP_NONE = 0x0000,
+	EXT_HW_CONFIG_SP_BYTE_PARITY = 0x0002,
+	EXT_HW_CONFIG_SP_ECC = 0x0004,
+	EXT_HW_CONFIG_SP_ECCx = 0x0006,
+	EXT_HW_CONFIG_SIZE_MASK = 0x0060,
+	EXT_HW_CONFIG_SIZE_128M = 0x0000,
+	EXT_HW_CONFIG_SIZE_256M = 0x0020,
+	EXT_HW_CONFIG_SIZE_512M = 0x0040,
+	EXT_HW_CONFIG_SIZE_INVALID = 0x0060,
+	EXT_HW_CONFIG_PD = 0x0080,
+	EXT_HW_CONFIG_FW = 0x0200,
+	EXT_HW_CONFIG_US = 0x0400,
+	EXT_HW_CONFIG_DCS_MASK = 0x1800,
+	EXT_HW_CONFIG_DCS_9MA = 0x0000,
+	EXT_HW_CONFIG_DCS_15MA = 0x0800,
+	EXT_HW_CONFIG_DCS_18MA = 0x1000,
+	EXT_HW_CONFIG_DCS_24MA = 0x1800,
+	EXT_HW_CONFIG_DDS_MASK = 0x6000,
+	EXT_HW_CONFIG_DDS_9MA = 0x0000,
+	EXT_HW_CONFIG_DDS_15MA = 0x2000,
+	EXT_HW_CONFIG_DDS_18MA = 0x4000,
+	EXT_HW_CONFIG_DDS_24MA = 0x6000,
+};
+
+/* InternalChipConfig */
+enum {
+	INTERNAL_CHIP_DM = 0x0001,
+	INTERNAL_CHIP_SD = 0x0002,
+	INTERNAL_CHIP_RAP_MASK = 0x000C,
+	INTERNAL_CHIP_RAP_RR = 0x0000,
+	INTERNAL_CHIP_RAP_NRM = 0x0004,
+	INTERNAL_CHIP_RAP_ERM = 0x0008,
+	INTERNAL_CHIP_RAP_ERMx = 0x000C,
+	INTERNAL_CHIP_WE = 0x0010,
+	INTERNAL_CHIP_EF = 0x0020,
+	INTERNAL_CHIP_FR = 0x0040,
+	INTERNAL_CHIP_FW = 0x0080,
+	INTERNAL_CHIP_FI = 0x0100,
+	INTERNAL_CHIP_FT = 0x0200,
+};
+
+/* portControl */
+enum {
+	PORT_CONTROL_DS = 0x0001,
+	PORT_CONTROL_HH = 0x0002,
+	PORT_CONTROL_EI = 0x0004,
+	PORT_CONTROL_ET = 0x0008,
+	PORT_CONTROL_EF = 0x0010,
+	PORT_CONTROL_DRM = 0x0020,
+	PORT_CONTROL_RLB = 0x0040,
+	PORT_CONTROL_RCB = 0x0080,
+	PORT_CONTROL_MAC = 0x0100,
+	PORT_CONTROL_IPV = 0x0200,
+	PORT_CONTROL_IFP = 0x0400,
+	PORT_CONTROL_ITP = 0x0800,
+	PORT_CONTROL_FI = 0x1000,
+	PORT_CONTROL_DFP = 0x2000,
+	PORT_CONTROL_OI = 0x4000,
+	PORT_CONTROL_CC = 0x8000,
+};
+
+/* portStatus */
+enum {
+	PORT_STATUS_SM0 = 0x0001,
+	PORT_STATUS_SM1 = 0x0002,
+	PORT_STATUS_X = 0x0008,
+	PORT_STATUS_DL = 0x0080,
+	PORT_STATUS_IC = 0x0200,
+	PORT_STATUS_MRC = 0x0400,
+	PORT_STATUS_NL = 0x0800,
+	PORT_STATUS_REV_ID_MASK = 0x7000,
+	PORT_STATUS_REV_ID_1 = 0x1000,
+	PORT_STATUS_REV_ID_2 = 0x2000,
+	PORT_STATUS_REV_ID_3 = 0x3000,
+	PORT_STATUS_64 = 0x8000,
+	PORT_STATUS_UP0 = 0x10000,
+	PORT_STATUS_AC0 = 0x20000,
+	PORT_STATUS_AE0 = 0x40000,
+	PORT_STATUS_UP1 = 0x100000,
+	PORT_STATUS_AC1 = 0x200000,
+	PORT_STATUS_AE1 = 0x400000,
+	PORT_STATUS_F0_ENABLED = 0x1000000,
+	PORT_STATUS_F1_ENABLED = 0x2000000,
+	PORT_STATUS_F2_ENABLED = 0x4000000,
+	PORT_STATUS_F3_ENABLED = 0x8000000,
+};
+
+/* macMIIMgmtControlReg */
+enum {
+	MAC_ADDR_INDIRECT_PTR_REG_RP_MASK = 0x0003,
+	MAC_ADDR_INDIRECT_PTR_REG_RP_PRI_LWR = 0x0000,
+	MAC_ADDR_INDIRECT_PTR_REG_RP_PRI_UPR = 0x0001,
+	MAC_ADDR_INDIRECT_PTR_REG_RP_SEC_LWR = 0x0002,
+	MAC_ADDR_INDIRECT_PTR_REG_RP_SEC_UPR = 0x0003,
+	MAC_ADDR_INDIRECT_PTR_REG_PR = 0x0008,
+	MAC_ADDR_INDIRECT_PTR_REG_SS = 0x0010,
+	MAC_ADDR_INDIRECT_PTR_REG_SE = 0x0020,
+	MAC_ADDR_INDIRECT_PTR_REG_SP = 0x0040,
+	MAC_ADDR_INDIRECT_PTR_REG_PE = 0x0080,
+};
+
+/* macMIIMgmtControlReg */
+enum {
+	MAC_MII_CONTROL_RC = 0x0001,
+	MAC_MII_CONTROL_SC = 0x0002,
+	MAC_MII_CONTROL_AS = 0x0004,
+	MAC_MII_CONTROL_NP = 0x0008,
+	MAC_MII_CONTROL_CLK_SEL_MASK = 0x0070,
+	MAC_MII_CONTROL_CLK_SEL_DIV2 = 0x0000,
+	MAC_MII_CONTROL_CLK_SEL_DIV4 = 0x0010,
+	MAC_MII_CONTROL_CLK_SEL_DIV6 = 0x0020,
+	MAC_MII_CONTROL_CLK_SEL_DIV8 = 0x0030,
+	MAC_MII_CONTROL_CLK_SEL_DIV10 = 0x0040,
+	MAC_MII_CONTROL_CLK_SEL_DIV14 = 0x0050,
+	MAC_MII_CONTROL_CLK_SEL_DIV20 = 0x0060,
+	MAC_MII_CONTROL_CLK_SEL_DIV28 = 0x0070,
+	MAC_MII_CONTROL_RM = 0x8000,
+};
+
+/* macMIIStatusReg */
+enum {
+	MAC_MII_STATUS_BSY = 0x0001,
+	MAC_MII_STATUS_SC = 0x0002,
+	MAC_MII_STATUS_NV = 0x0004,
+};
+
+enum {
+	MAC_CONFIG_REG_PE = 0x0001,
+	MAC_CONFIG_REG_TF = 0x0002,
+	MAC_CONFIG_REG_RF = 0x0004,
+	MAC_CONFIG_REG_FD = 0x0008,
+	MAC_CONFIG_REG_GM = 0x0010,
+	MAC_CONFIG_REG_LB = 0x0020,
+	MAC_CONFIG_REG_SR = 0x8000,
+};
+
+enum {
+	MAC_HALF_DUPLEX_REG_ED = 0x10000,
+	MAC_HALF_DUPLEX_REG_NB = 0x20000,
+	MAC_HALF_DUPLEX_REG_BNB = 0x40000,
+	MAC_HALF_DUPLEX_REG_ALT = 0x80000,
+};
+
+enum {
+	IP_ADDR_INDEX_REG_MASK = 0x000f,
+	IP_ADDR_INDEX_REG_FUNC_0_PRI = 0x0000,
+	IP_ADDR_INDEX_REG_FUNC_0_SEC = 0x0001,
+	IP_ADDR_INDEX_REG_FUNC_1_PRI = 0x0002,
+	IP_ADDR_INDEX_REG_FUNC_1_SEC = 0x0003,
+	IP_ADDR_INDEX_REG_FUNC_2_PRI = 0x0004,
+	IP_ADDR_INDEX_REG_FUNC_2_SEC = 0x0005,
+	IP_ADDR_INDEX_REG_FUNC_3_PRI = 0x0006,
+	IP_ADDR_INDEX_REG_FUNC_3_SEC = 0x0007,
+};
+
+enum {
+	PROBE_MUX_ADDR_REG_MUX_SEL_MASK = 0x003f,
+	PROBE_MUX_ADDR_REG_SYSCLK = 0x0000,
+	PROBE_MUX_ADDR_REG_PCICLK = 0x0040,
+	PROBE_MUX_ADDR_REG_NRXCLK = 0x0080,
+	PROBE_MUX_ADDR_REG_CPUCLK = 0x00C0,
+	PROBE_MUX_ADDR_REG_MODULE_SEL_MASK = 0x3f00,
+	PROBE_MUX_ADDR_REG_UP = 0x4000,
+	PROBE_MUX_ADDR_REG_RE = 0x8000,
+};
+
+enum {
+	STATISTICS_INDEX_REG_MASK = 0x01ff,
+	STATISTICS_INDEX_REG_MAC0_TX_FRAME = 0x0000,
+	STATISTICS_INDEX_REG_MAC0_TX_BYTES = 0x0001,
+	STATISTICS_INDEX_REG_MAC0_TX_STAT1 = 0x0002,
+	STATISTICS_INDEX_REG_MAC0_TX_STAT2 = 0x0003,
+	STATISTICS_INDEX_REG_MAC0_TX_STAT3 = 0x0004,
+	STATISTICS_INDEX_REG_MAC0_TX_STAT4 = 0x0005,
+	STATISTICS_INDEX_REG_MAC0_TX_STAT5 = 0x0006,
+	STATISTICS_INDEX_REG_MAC0_RX_FRAME = 0x0007,
+	STATISTICS_INDEX_REG_MAC0_RX_BYTES = 0x0008,
+	STATISTICS_INDEX_REG_MAC0_RX_STAT1 = 0x0009,
+	STATISTICS_INDEX_REG_MAC0_RX_STAT2 = 0x000a,
+	STATISTICS_INDEX_REG_MAC0_RX_STAT3 = 0x000b,
+	STATISTICS_INDEX_REG_MAC0_RX_ERR_CRC = 0x000c,
+	STATISTICS_INDEX_REG_MAC0_RX_ERR_ENC = 0x000d,
+	STATISTICS_INDEX_REG_MAC0_RX_ERR_LEN = 0x000e,
+	STATISTICS_INDEX_REG_MAC0_RX_STAT4 = 0x000f,
+	STATISTICS_INDEX_REG_MAC1_TX_FRAME = 0x0010,
+	STATISTICS_INDEX_REG_MAC1_TX_BYTES = 0x0011,
+	STATISTICS_INDEX_REG_MAC1_TX_STAT1 = 0x0012,
+	STATISTICS_INDEX_REG_MAC1_TX_STAT2 = 0x0013,
+	STATISTICS_INDEX_REG_MAC1_TX_STAT3 = 0x0014,
+	STATISTICS_INDEX_REG_MAC1_TX_STAT4 = 0x0015,
+	STATISTICS_INDEX_REG_MAC1_TX_STAT5 = 0x0016,
+	STATISTICS_INDEX_REG_MAC1_RX_FRAME = 0x0017,
+	STATISTICS_INDEX_REG_MAC1_RX_BYTES = 0x0018,
+	STATISTICS_INDEX_REG_MAC1_RX_STAT1 = 0x0019,
+	STATISTICS_INDEX_REG_MAC1_RX_STAT2 = 0x001a,
+	STATISTICS_INDEX_REG_MAC1_RX_STAT3 = 0x001b,
+	STATISTICS_INDEX_REG_MAC1_RX_ERR_CRC = 0x001c,
+	STATISTICS_INDEX_REG_MAC1_RX_ERR_ENC = 0x001d,
+	STATISTICS_INDEX_REG_MAC1_RX_ERR_LEN = 0x001e,
+	STATISTICS_INDEX_REG_MAC1_RX_STAT4 = 0x001f,
+	STATISTICS_INDEX_REG_IP_TX_PKTS = 0x0020,
+	STATISTICS_INDEX_REG_IP_TX_BYTES = 0x0021,
+	STATISTICS_INDEX_REG_IP_TX_FRAG = 0x0022,
+	STATISTICS_INDEX_REG_IP_RX_PKTS = 0x0023,
+	STATISTICS_INDEX_REG_IP_RX_BYTES = 0x0024,
+	STATISTICS_INDEX_REG_IP_RX_FRAG = 0x0025,
+	STATISTICS_INDEX_REG_IP_DGRM_REASSEMBLY = 0x0026,
+	STATISTICS_INDEX_REG_IP_V6_RX_PKTS = 0x0027,
+	STATISTICS_INDEX_REG_IP_RX_PKTERR = 0x0028,
+	STATISTICS_INDEX_REG_IP_REASSEMBLY_ERR = 0x0029,
+	STATISTICS_INDEX_REG_TCP_TX_SEG = 0x0030,
+	STATISTICS_INDEX_REG_TCP_TX_BYTES = 0x0031,
+	STATISTICS_INDEX_REG_TCP_RX_SEG = 0x0032,
+	STATISTICS_INDEX_REG_TCP_RX_BYTES = 0x0033,
+	STATISTICS_INDEX_REG_TCP_TIMER_EXP = 0x0034,
+	STATISTICS_INDEX_REG_TCP_RX_ACK = 0x0035,
+	STATISTICS_INDEX_REG_TCP_TX_ACK = 0x0036,
+	STATISTICS_INDEX_REG_TCP_RX_ERR = 0x0037,
+	STATISTICS_INDEX_REG_TCP_RX_WIN_PROBE = 0x0038,
+	STATISTICS_INDEX_REG_TCP_ECC_ERR_CORR = 0x003f,
+};
+
+enum {
+	PORT_FATAL_ERROR_STATUS_OFB_RE_MAC0 = 0x00000001,
+	PORT_FATAL_ERROR_STATUS_OFB_RE_MAC1 = 0x00000002,
+	PORT_FATAL_ERROR_STATUS_OFB_WE = 0x00000004,
+	PORT_FATAL_ERROR_STATUS_IFB_RE = 0x00000008,
+	PORT_FATAL_ERROR_STATUS_IFB_WE_MAC0 = 0x00000010,
+	PORT_FATAL_ERROR_STATUS_IFB_WE_MAC1 = 0x00000020,
+	PORT_FATAL_ERROR_STATUS_ODE_RE = 0x00000040,
+	PORT_FATAL_ERROR_STATUS_ODE_WE = 0x00000080,
+	PORT_FATAL_ERROR_STATUS_IDE_RE = 0x00000100,
+	PORT_FATAL_ERROR_STATUS_IDE_WE = 0x00000200,
+	PORT_FATAL_ERROR_STATUS_SDE_RE = 0x00000400,
+	PORT_FATAL_ERROR_STATUS_SDE_WE = 0x00000800,
+	PORT_FATAL_ERROR_STATUS_BLE = 0x00001000,
+	PORT_FATAL_ERROR_STATUS_SPE = 0x00002000,
+	PORT_FATAL_ERROR_STATUS_EP0 = 0x00004000,
+	PORT_FATAL_ERROR_STATUS_EP1 = 0x00008000,
+	PORT_FATAL_ERROR_STATUS_ICE = 0x00010000,
+	PORT_FATAL_ERROR_STATUS_ILE = 0x00020000,
+	PORT_FATAL_ERROR_STATUS_OPE = 0x00040000,
+	PORT_FATAL_ERROR_STATUS_TA = 0x00080000,
+	PORT_FATAL_ERROR_STATUS_MA = 0x00100000,
+	PORT_FATAL_ERROR_STATUS_SCE = 0x00200000,
+	PORT_FATAL_ERROR_STATUS_RPE = 0x00400000,
+	PORT_FATAL_ERROR_STATUS_MPE = 0x00800000,
+	PORT_FATAL_ERROR_STATUS_OCE = 0x01000000,
+};
+
+/*
+ *  port control and status page - page 0
+ */
+
+struct ql3xxx_port_registers {
+	struct ql3xxx_common_registers CommonRegs;
+
+	u32 ExternalHWConfig;
+	u32 InternalChipConfig;
+	u32 portControl;
+	u32 portStatus;
+	u32 macAddrIndirectPtrReg;
+	u32 macAddrDataReg;
+	u32 macMIIMgmtControlReg;
+	u32 macMIIMgmtAddrReg;
+	u32 macMIIMgmtDataReg;
+	u32 macMIIStatusReg;
+	u32 mac0ConfigReg;
+	u32 mac0IpgIfgReg;
+	u32 mac0HalfDuplexReg;
+	u32 mac0MaxFrameLengthReg;
+	u32 mac0PauseThresholdReg;
+	u32 mac1ConfigReg;
+	u32 mac1IpgIfgReg;
+	u32 mac1HalfDuplexReg;
+	u32 mac1MaxFrameLengthReg;
+	u32 mac1PauseThresholdReg;
+	u32 ipAddrIndexReg;
+	u32 ipAddrDataReg;
+	u32 ipReassemblyTimeout;
+	u32 tcpMaxWindow;
+	u32 currentTcpTimestamp[2];
+	u32 internalRamRWAddrReg;
+	u32 internalRamWDataReg;
+	u32 reclaimedBufferAddrRegLow;
+	u32 reclaimedBufferAddrRegHigh;
+	u32 reserved[2];
+	u32 fpgaRevID;
+	u32 localRamAddr;
+	u32 localRamDataAutoIncr;
+	u32 localRamDataNonIncr;
+	u32 gpOutput;
+	u32 gpInput;
+	u32 probeMuxAddr;
+	u32 probeMuxData;
+	u32 statisticsIndexReg;
+	u32 statisticsReadDataRegAutoIncr;
+	u32 statisticsReadDataRegNoIncr;
+	u32 PortFatalErrStatus;
+};
+
+/*
+ * port host memory config page - page 1
+ */
+struct ql3xxx_host_memory_registers {
+	struct ql3xxx_common_registers CommonRegs;
+
+	u32 reserved[12];
+
+	/* Network Request Queue */
+	u32 reqConsumerIndex;
+	u32 reqConsumerIndexAddrLow;
+	u32 reqConsumerIndexAddrHigh;
+	u32 reqBaseAddrLow;
+	u32 reqBaseAddrHigh;
+	u32 reqLength;
+
+	/* Network Completion Queue */
+	u32 rspProducerIndex;
+	u32 rspProducerIndexAddrLow;
+	u32 rspProducerIndexAddrHigh;
+	u32 rspBaseAddrLow;
+	u32 rspBaseAddrHigh;
+	u32 rspLength;
+
+	/* RX Large Buffer Queue */
+	u32 rxLargeQConsumerIndex;
+	u32 rxLargeQBaseAddrLow;
+	u32 rxLargeQBaseAddrHigh;
+	u32 rxLargeQLength;
+	u32 rxLargeBufferLength;
+
+	/* RX Small Buffer Queue */
+	u32 rxSmallQConsumerIndex;
+	u32 rxSmallQBaseAddrLow;
+	u32 rxSmallQBaseAddrHigh;
+	u32 rxSmallQLength;
+	u32 rxSmallBufferLength;
+
+};
+
+/*
+ *  port local RAM page - page 2
+ */
+struct ql3xxx_local_ram_registers {
+	struct ql3xxx_common_registers CommonRegs;
+	u32 bufletSize;
+	u32 maxBufletCount;
+	u32 currentBufletCount;
+	u32 reserved;
+	u32 freeBufletThresholdLow;
+	u32 freeBufletThresholdHigh;
+	u32 ipHashTableBase;
+	u32 ipHashTableCount;
+	u32 tcpHashTableBase;
+	u32 tcpHashTableCount;
+	u32 ncbBase;
+	u32 maxNcbCount;
+	u32 currentNcbCount;
+	u32 drbBase;
+	u32 maxDrbCount;
+	u32 currentDrbCount;
+};
+
+/*
+ * definitions for Semaphore bits in Semaphore/Serial NVRAM interface register
+ */
+
+#define LS_64BITS(x)    (u32)(0xffffffff & ((u64)x))
+#define MS_64BITS(x)    (u32)(0xffffffff & (((u64)x)>>16>>16) )
+
+/*
+ * I/O register
+ */
+
+enum {
+	CONTROL_REG = 0,
+	STATUS_REG = 1,
+	PHY_STAT_LINK_UP = 0x0004,
+	PHY_CTRL_LOOPBACK = 0x4000,
+
+	PETBI_CONTROL_REG = 0x00,
+	PETBI_CTRL_SOFT_RESET = 0x8000,
+	PETBI_CTRL_AUTO_NEG = 0x1000,
+	PETBI_CTRL_RESTART_NEG = 0x0200,
+	PETBI_CTRL_FULL_DUPLEX = 0x0100,
+	PETBI_CTRL_SPEED_1000 = 0x0040,
+
+	PETBI_STATUS_REG = 0x01,
+	PETBI_STAT_NEG_DONE = 0x0020,
+	PETBI_STAT_LINK_UP = 0x0004,
+
+	PETBI_NEG_ADVER = 0x04,
+	PETBI_NEG_PAUSE = 0x0080,
+	PETBI_NEG_PAUSE_MASK = 0x0180,
+	PETBI_NEG_DUPLEX = 0x0020,
+	PETBI_NEG_DUPLEX_MASK = 0x0060,
+
+	PETBI_NEG_PARTNER = 0x05,
+	PETBI_NEG_ERROR_MASK = 0x3000,
+
+	PETBI_EXPANSION_REG = 0x06,
+	PETBI_EXP_PAGE_RX = 0x0002,
+
+	PETBI_TBI_CTRL = 0x11,
+	PETBI_TBI_RESET = 0x8000,
+	PETBI_TBI_AUTO_SENSE = 0x0100,
+	PETBI_TBI_SERDES_MODE = 0x0010,
+	PETBI_TBI_SERDES_WRAP = 0x0002,
+
+	AUX_CONTROL_STATUS = 0x1c,
+	PHY_AUX_NEG_DONE = 0x8000,
+	PHY_NEG_PARTNER = 5,
+	PHY_AUX_DUPLEX_STAT = 0x0020,
+	PHY_AUX_SPEED_STAT = 0x0018,
+	PHY_AUX_NO_HW_STRAP = 0x0004,
+	PHY_AUX_RESET_STICK = 0x0002,
+	PHY_NEG_PAUSE = 0x0400,
+	PHY_CTRL_SOFT_RESET = 0x8000,
+	PHY_NEG_ADVER = 4,
+	PHY_NEG_ADV_SPEED = 0x01e0,
+	PHY_CTRL_RESTART_NEG = 0x0200,
+};
+enum {
+/* AM29LV Flash definitions	*/
+	FM93C56A_START = 0x1,
+/* Commands */
+	FM93C56A_READ = 0x2,
+	FM93C56A_WEN = 0x0,
+	FM93C56A_WRITE = 0x1,
+	FM93C56A_WRITE_ALL = 0x0,
+	FM93C56A_WDS = 0x0,
+	FM93C56A_ERASE = 0x3,
+	FM93C56A_ERASE_ALL = 0x0,
+/* Command Extentions */
+	FM93C56A_WEN_EXT = 0x3,
+	FM93C56A_WRITE_ALL_EXT = 0x1,
+	FM93C56A_WDS_EXT = 0x0,
+	FM93C56A_ERASE_ALL_EXT = 0x2,
+/* Special Bits */
+	FM93C56A_READ_DUMMY_BITS = 1,
+	FM93C56A_READY = 0,
+	FM93C56A_BUSY = 1,
+	FM93C56A_CMD_BITS = 2,
+/* AM29LV Flash definitions	*/
+	FM93C56A_SIZE_8 = 0x100,
+	FM93C56A_SIZE_16 = 0x80,
+	FM93C66A_SIZE_8 = 0x200,
+	FM93C66A_SIZE_16 = 0x100,
+	FM93C86A_SIZE_16 = 0x400,
+/* Address Bits */
+	FM93C56A_NO_ADDR_BITS_16 = 8,
+	FM93C56A_NO_ADDR_BITS_8 = 9,
+	FM93C86A_NO_ADDR_BITS_16 = 10,
+/* Data Bits */
+	FM93C56A_DATA_BITS_16 = 16,
+	FM93C56A_DATA_BITS_8 = 8,
+};
+enum {
+/* Auburn Bits */
+	    AUBURN_EEPROM_DI = 0x8,
+	AUBURN_EEPROM_DI_0 = 0x0,
+	AUBURN_EEPROM_DI_1 = 0x8,
+	AUBURN_EEPROM_DO = 0x4,
+	AUBURN_EEPROM_DO_0 = 0x0,
+	AUBURN_EEPROM_DO_1 = 0x4,
+	AUBURN_EEPROM_CS = 0x2,
+	AUBURN_EEPROM_CS_0 = 0x0,
+	AUBURN_EEPROM_CS_1 = 0x2,
+	AUBURN_EEPROM_CLK_RISE = 0x1,
+	AUBURN_EEPROM_CLK_FALL = 0x0,
+};
+enum {EEPROM_SIZE = FM93C86A_SIZE_16,
+	EEPROM_NO_ADDR_BITS = FM93C86A_NO_ADDR_BITS_16,
+	EEPROM_NO_DATA_BITS = FM93C56A_DATA_BITS_16,
+};
+
+/*
+ *  MAC Config data structure
+ */
+    struct eeprom_port_cfg {
+	u16 etherMtu_mac;
+	u16 pauseThreshold_mac;
+	u16 resumeThreshold_mac;
+	u16 portConfiguration;
+#define PORT_CONFIG_AUTO_NEG_ENABLED        0x8000
+#define PORT_CONFIG_SYM_PAUSE_ENABLED       0x4000
+#define PORT_CONFIG_FULL_DUPLEX_ENABLED     0x2000
+#define PORT_CONFIG_HALF_DUPLEX_ENABLED     0x1000
+#define PORT_CONFIG_1000MB_SPEED            0x0400
+#define PORT_CONFIG_100MB_SPEED             0x0200
+#define PORT_CONFIG_10MB_SPEED              0x0100
+#define PORT_CONFIG_LINK_SPEED_MASK         0x0F00
+	u16 reserved[12];
+
+};
+
+/*
+ * BIOS data structure
+ */
+struct eeprom_bios_cfg {
+	u16 SpinDlyEn:1, disBios:1, EnMemMap:1, EnSelectBoot:1, Reserved:12;
+
+	u8 bootID0:7, boodID0Valid:1;
+	u8 bootLun0[8];
+
+	u8 bootID1:7, boodID1Valid:1;
+	u8 bootLun1[8];
+
+	u16 MaxLunsTrgt;
+	u8 reserved[10];
+};
+
+/*
+ *  Function Specific Data structure
+ */
+struct eeprom_function_cfg {
+	u8 reserved[30];
+	u8 macAddress[6];
+	u8 macAddressSecondary[6];
+
+	u16 subsysVendorId;
+	u16 subsysDeviceId;
+};
+
+/*
+ *  EEPROM format
+ */
+struct eeprom_data {
+	u8 asicId[4];
+	u8 version;
+	u8 numPorts;
+	u16 boardId;
+
+#define EEPROM_BOARDID_STR_SIZE   16
+#define EEPROM_SERIAL_NUM_SIZE    16
+
+	u8 boardIdStr[16];
+	u8 serialNumber[16];
+	u16 extHwConfig;
+	struct eeprom_port_cfg macCfg_port0;
+	struct eeprom_port_cfg macCfg_port1;
+	u16 bufletSize;
+	u16 bufletCount;
+	u16 tcpWindowThreshold50;
+	u16 tcpWindowThreshold25;
+	u16 tcpWindowThreshold0;
+	u16 ipHashTableBaseHi;
+	u16 ipHashTableBaseLo;
+	u16 ipHashTableSize;
+	u16 tcpHashTableBaseHi;
+	u16 tcpHashTableBaseLo;
+	u16 tcpHashTableSize;
+	u16 ncbTableBaseHi;
+	u16 ncbTableBaseLo;
+	u16 ncbTableSize;
+	u16 drbTableBaseHi;
+	u16 drbTableBaseLo;
+	u16 drbTableSize;
+	u16 reserved_142[4];
+	u16 ipReassemblyTimeout;
+	u16 tcpMaxWindowSize;
+	u16 ipSecurity;
+#define IPSEC_CONFIG_PRESENT 0x0001
+	u8 reserved_156[294];
+	u16 qDebug[8];
+	struct eeprom_function_cfg funcCfg_fn0;
+	u16 reserved_510;
+	u8 oemSpace[432];
+	struct eeprom_bios_cfg biosCfg_fn1;
+	struct eeprom_function_cfg funcCfg_fn1;
+	u16 reserved_1022;
+	u8 reserved_1024[464];
+	struct eeprom_function_cfg funcCfg_fn2;
+	u16 reserved_1534;
+	u8 reserved_1536[432];
+	struct eeprom_bios_cfg biosCfg_fn3;
+	struct eeprom_function_cfg funcCfg_fn3;
+	u16 checksum;
+};
+
+/*
+ * General definitions...
+ */
+
+/*
+ * Below are a number compiler switches for controlling driver behavior.
+ * Some are not supported under certain conditions and are notated as such.
+ */
+
+#define QL3XXX_VENDOR_ID    0x1077
+#define QL3022_DEVICE_ID    0x3022
+
+/* MTU & Frame Size stuff */
+#define NORMAL_MTU_SIZE 		ETH_DATA_LEN
+#define JUMBO_MTU_SIZE 			9000
+#define VLAN_ID_LEN			    2
+
+/* Request Queue Related Definitions */
+#define NUM_REQ_Q_ENTRIES   256	/* so that 64 * 64  = 4096 (1 page) */
+
+/* Response Queue Related Definitions */
+#define NUM_RSP_Q_ENTRIES   256	/* so that 256 * 16  = 4096 (1 page) */
+
+/* Transmit and Receive Buffers */
+#define NUM_LBUFQ_ENTRIES   	128
+#define NUM_SBUFQ_ENTRIES   	64
+#define QL_SMALL_BUFFER_SIZE    32
+#define QL_ADDR_ELE_PER_BUFQ_ENTRY \
+(sizeof(struct lrg_buf_q_entry) / sizeof(struct bufq_addr_element))
+    /* Each send has at least control block.  This is how many we keep. */
+#define NUM_SMALL_BUFFERS     	NUM_SBUFQ_ENTRIES * QL_ADDR_ELE_PER_BUFQ_ENTRY
+#define NUM_LARGE_BUFFERS     	NUM_LBUFQ_ENTRIES * QL_ADDR_ELE_PER_BUFQ_ENTRY
+#define QL_HEADER_SPACE 32	/* make header space at top of skb. */
+/*
+ * Large & Small Buffers for Receives
+ */
+struct lrg_buf_q_entry {
+
+	u32 addr0_lower;
+#define IAL_LAST_ENTRY 0x00000001
+#define IAL_CONT_ENTRY 0x00000002
+#define IAL_FLAG_MASK  0x00000003
+	u32 addr0_upper;
+	u32 addr1_lower;
+	u32 addr1_upper;
+	u32 addr2_lower;
+	u32 addr2_upper;
+	u32 addr3_lower;
+	u32 addr3_upper;
+	u32 addr4_lower;
+	u32 addr4_upper;
+	u32 addr5_lower;
+	u32 addr5_upper;
+	u32 addr6_lower;
+	u32 addr6_upper;
+	u32 addr7_lower;
+	u32 addr7_upper;
+
+};
+
+struct bufq_addr_element {
+	u32 addr_low;
+	u32 addr_high;
+};
+
+#define QL_NO_RESET			0
+#define QL_DO_RESET			1
+
+enum link_state_t {
+	LS_UNKNOWN = 0,
+	LS_DOWN,
+	LS_DEGRADE,
+	LS_RECOVER,
+	LS_UP,
+};
+
+struct ql_rcv_buf_cb {
+	struct ql_rcv_buf_cb *next;
+	struct sk_buff *skb;
+	 DECLARE_PCI_UNMAP_ADDR(mapaddr);
+	 DECLARE_PCI_UNMAP_LEN(maplen);
+	__le32 buf_phy_addr_low;
+	__le32 buf_phy_addr_high;
+	int index;
+};
+
+struct ql_tx_buf_cb {
+	struct sk_buff *skb;
+	struct ob_mac_iocb_req *queue_entry ;
+	 DECLARE_PCI_UNMAP_ADDR(mapaddr);
+	 DECLARE_PCI_UNMAP_LEN(maplen);
+};
+
+/* definitions for type field */
+#define QL_BUF_TYPE_MACIOCB 0x01
+#define QL_BUF_TYPE_IPIOCB  0x02
+#define QL_BUF_TYPE_TCPIOCB 0x03
+
+/* qdev->flags definitions. */
+enum { QL_RESET_DONE = 1,	/* Reset finished. */
+	QL_RESET_ACTIVE = 2,	/* Waiting for reset to finish. */
+	QL_RESET_START = 3,	/* Please reset the chip. */
+	QL_RESET_PER_SCSI = 4,	/* SCSI driver requests reset. */
+	QL_TX_TIMEOUT = 5,	/* Timeout in progress. */
+	QL_LINK_MASTER = 6,	/* This driver controls the link. */
+	QL_ADAPTER_UP = 7,	/* Adapter has been brought up. */
+	QL_THREAD_UP = 8,	/* This flag is available. */
+	QL_LINK_UP = 9,	/* Link Status. */
+	QL_ALLOC_REQ_RSP_Q_DONE = 10,
+	QL_ALLOC_BUFQS_DONE = 11,
+	QL_ALLOC_SMALL_BUF_DONE = 12,
+	QL_LINK_OPTICAL = 13,
+	QL_MSI_ENABLED = 14,
+};
+
+/*
+ * ql3_adapter - The main Adapter structure definition.
+ * This structure has all fields relevant to the hardware.
+ */
+
+struct ql3_adapter {
+	u32 reserved_00;
+	unsigned long flags;
+
+	/* PCI Configuration information for this device */
+	struct pci_dev *pdev;
+	struct net_device *ndev;	/* Parent NET device */
+
+	/* Hardware information */
+	u8 chip_rev_id;
+	u8 pci_slot;
+	u8 pci_width;
+	u8 pci_x;
+	u32 msi;
+	int index;
+	struct timer_list adapter_timer;	/* timer used for various functions */
+
+	spinlock_t adapter_lock;
+	spinlock_t hw_lock;
+
+	/* PCI Bus Relative Register Addresses */
+	u8 *mmap_virt_base;	/* stores return value from ioremap() */
+	struct ql3xxx_port_registers __iomem *mem_map_registers;
+	u32 current_page;	/* tracks current register page */
+
+	u32 msg_enable;
+	u8 reserved_01[2];
+	u8 reserved_02[2];
+
+	/* Page for Shadow Registers */
+	void *shadow_reg_virt_addr;
+	dma_addr_t shadow_reg_phy_addr;
+
+	/* Net Request Queue */
+	u32 req_q_size;
+	u32 reserved_03;
+	struct ob_mac_iocb_req *req_q_virt_addr;
+	dma_addr_t req_q_phy_addr;
+	u16 req_producer_index;
+	u16 reserved_04;
+	u16 *preq_consumer_index;
+	u32 req_consumer_index_phy_addr_high;
+	u32 req_consumer_index_phy_addr_low;
+	atomic_t tx_count;
+	struct ql_tx_buf_cb tx_buf[NUM_REQ_Q_ENTRIES];
+
+	/* Net Response Queue */
+	u32 rsp_q_size;
+	u32 eeprom_cmd_data;
+	struct net_rsp_iocb *rsp_q_virt_addr;
+	dma_addr_t rsp_q_phy_addr;
+	struct net_rsp_iocb *rsp_current;
+	u16 rsp_consumer_index;
+	u16 reserved_06;
+	u32 *prsp_producer_index;
+	u32 rsp_producer_index_phy_addr_high;
+	u32 rsp_producer_index_phy_addr_low;
+
+	/* Large Buffer Queue */
+	u32 lrg_buf_q_alloc_size;
+	u32 lrg_buf_q_size;
+	void *lrg_buf_q_alloc_virt_addr;
+	void *lrg_buf_q_virt_addr;
+	dma_addr_t lrg_buf_q_alloc_phy_addr;
+	dma_addr_t lrg_buf_q_phy_addr;
+	u32 lrg_buf_q_producer_index;
+	u32 lrg_buf_release_cnt;
+	struct bufq_addr_element *lrg_buf_next_free;
+
+	/* Large (Receive) Buffers */
+	struct ql_rcv_buf_cb lrg_buf[NUM_LARGE_BUFFERS];
+	struct ql_rcv_buf_cb *lrg_buf_free_head;
+	struct ql_rcv_buf_cb *lrg_buf_free_tail;
+	u32 lrg_buf_free_count;
+	u32 lrg_buffer_len;
+	u32 lrg_buf_index;
+	u32 lrg_buf_skb_check;
+
+	/* Small Buffer Queue */
+	u32 small_buf_q_alloc_size;
+	u32 small_buf_q_size;
+	u32 small_buf_q_producer_index;
+	void *small_buf_q_alloc_virt_addr;
+	void *small_buf_q_virt_addr;
+	dma_addr_t small_buf_q_alloc_phy_addr;
+	dma_addr_t small_buf_q_phy_addr;
+	u32 small_buf_index;
+
+	/* Small (Receive) Buffers */
+	void *small_buf_virt_addr;
+	dma_addr_t small_buf_phy_addr;
+	u32 small_buf_phy_addr_low;
+	u32 small_buf_phy_addr_high;
+	u32 small_buf_release_cnt;
+	u32 small_buf_total_size;
+
+	/* ISR related, saves status for DPC. */
+	u32 control_status;
+
+	struct eeprom_data nvram_data;
+	struct timer_list ioctl_timer;
+	u32 port_link_state;
+	u32 last_rsp_offset;
+
+	/* 4022 specific */
+	u32 mac_index;		/* Driver's MAC number can be 0 or 1 for first and second networking functions respectively */
+	u32 PHYAddr;		/* Address of PHY 0x1e00 Port 0 and 0x1f00 Port 1 */
+	u32 mac_ob_opcode;	/* Opcode to use on mac transmission */
+	u32 tcp_ob_opcode;	/* Opcode to use on tcp transmission */
+	u32 update_ob_opcode;	/* Opcode to use for updating NCB */
+	u32 mb_bit_mask;	/* MA Bits mask to use on transmission */
+	u32 numPorts;
+	struct net_device_stats stats;
+	struct workqueue_struct *workqueue;
+	struct work_struct reset_work;
+	struct work_struct tx_timeout_work;
+	u32 max_frame_size;
+};
+
+#endif				/* _QLA3XXX_H_ */
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index 29ee7ff..b19f3ab 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -134,6 +134,7 @@
 	{ "AMD 79C901 10BASE-T PHY",  		0x0000, 0x6B70, LAN },
 	{ "AMD 79C901 HomePNA PHY",		0x0000, 0x6B90, HOME},
 	{ "ICS LAN PHY",			0x0015, 0xF440, LAN },
+	{ "ICS LAN PHY",			0x0143, 0xBC70, LAN },
 	{ "NS 83851 PHY",			0x2000, 0x5C20, MIX },
 	{ "NS 83847 PHY",                       0x2000, 0x5C30, MIX },
 	{ "Realtek RTL8201 PHY",		0x0000, 0x8200, LAN },
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 933e87f..805a7dc 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -50,7 +50,7 @@
 #include "sky2.h"
 
 #define DRV_NAME		"sky2"
-#define DRV_VERSION		"1.5"
+#define DRV_VERSION		"1.6"
 #define PFX			DRV_NAME " "
 
 /*
@@ -121,6 +121,11 @@
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4361) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4362) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4363) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4364) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4365) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4366) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4367) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4368) },
 	{ 0 }
 };
 
@@ -1926,12 +1931,6 @@
 	}
 }
 
-/* Is status ring empty or is there more to do? */
-static inline int sky2_more_work(const struct sky2_hw *hw)
-{
-	return (hw->st_idx != sky2_read16(hw, STAT_PUT_IDX));
-}
-
 /* Process status response ring */
 static int sky2_status_intr(struct sky2_hw *hw, int to_do)
 {
@@ -2022,6 +2021,9 @@
 		}
 	}
 
+	/* Fully processed status ring so clear irq */
+	sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
+
 exit_loop:
 	if (buf_write[0]) {
 		sky2 = netdev_priv(hw->dev[0]);
@@ -2231,19 +2233,16 @@
 		sky2_descriptor_error(hw, 1, "transmit", Y2_IS_CHK_TXA2);
 
 	work_done = sky2_status_intr(hw, work_limit);
-	*budget -= work_done;
-	dev0->quota -= work_done;
+	if (work_done < work_limit) {
+		netif_rx_complete(dev0);
 
-	if (status & Y2_IS_STAT_BMU)
-		sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
-
-	if (sky2_more_work(hw))
+		sky2_read32(hw, B0_Y2_SP_LISR);
+		return 0;
+	} else {
+		*budget -= work_done;
+		dev0->quota -= work_done;
 		return 1;
-
-	netif_rx_complete(dev0);
-
-	sky2_read32(hw, B0_Y2_SP_LISR);
-	return 0;
+	}
 }
 
 static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs)
diff --git a/drivers/net/slhc.c b/drivers/net/slhc.c
index 3a1b713..9a540e2 100644
--- a/drivers/net/slhc.c
+++ b/drivers/net/slhc.c
@@ -94,27 +94,23 @@
 	register struct cstate *ts;
 	struct slcompress *comp;
 
-	comp = (struct slcompress *)kmalloc(sizeof(struct slcompress),
-					    GFP_KERNEL);
+	comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL);
 	if (! comp)
 		goto out_fail;
-	memset(comp, 0, sizeof(struct slcompress));
 
 	if ( rslots > 0  &&  rslots < 256 ) {
 		size_t rsize = rslots * sizeof(struct cstate);
-		comp->rstate = (struct cstate *) kmalloc(rsize, GFP_KERNEL);
+		comp->rstate = kzalloc(rsize, GFP_KERNEL);
 		if (! comp->rstate)
 			goto out_free;
-		memset(comp->rstate, 0, rsize);
 		comp->rslot_limit = rslots - 1;
 	}
 
 	if ( tslots > 0  &&  tslots < 256 ) {
 		size_t tsize = tslots * sizeof(struct cstate);
-		comp->tstate = (struct cstate *) kmalloc(tsize, GFP_KERNEL);
+		comp->tstate = kzalloc(tsize, GFP_KERNEL);
 		if (! comp->tstate)
 			goto out_free2;
-		memset(comp->tstate, 0, tsize);
 		comp->tslot_limit = tslots - 1;
 	}
 
@@ -141,9 +137,9 @@
 	return comp;
 
 out_free2:
-	kfree((unsigned char *)comp->rstate);
+	kfree(comp->rstate);
 out_free:
-	kfree((unsigned char *)comp);
+	kfree(comp);
 out_fail:
 	return NULL;
 }
@@ -700,20 +696,6 @@
 EXPORT_SYMBOL(slhc_uncompress);
 EXPORT_SYMBOL(slhc_toss);
 
-#ifdef MODULE
-
-int init_module(void)
-{
-	printk(KERN_INFO "CSLIP: code copyright 1989 Regents of the University of California\n");
-	return 0;
-}
-
-void cleanup_module(void)
-{
-	return;
-}
-
-#endif /* MODULE */
 #else /* CONFIG_INET */
 
 
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index 0b15290..4438fe8 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -55,8 +55,6 @@
 			 )
 #endif
 
-
-#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index 698568e..90ac216d 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -17,6 +17,8 @@
 	Support and updates available at
 	http://www.scyld.com/network/sundance.html
 	[link no longer provides useful info -jgarzik]
+	Archives of the mailing list are still available at
+	http://www.beowulf.org/pipermail/netdrivers/
 
 */
 
@@ -646,7 +648,7 @@
 	/* Reset the chip to erase previous misconfiguration. */
 	if (netif_msg_hw(np))
 		printk("ASIC Control is %x.\n", ioread32(ioaddr + ASICCtrl));
-	iowrite16(0x00ff, ioaddr + ASICCtrl + 2);
+	sundance_reset(dev, 0x00ff << 16);
 	if (netif_msg_hw(np))
 		printk("ASIC Control is now %x.\n", ioread32(ioaddr + ASICCtrl));
 
@@ -1075,13 +1077,8 @@
 	
 	/* Reset tx logic, TxListPtr will be cleaned */
 	iowrite16 (TxDisable, ioaddr + MACCtrl1);
-	iowrite16 (TxReset | DMAReset | FIFOReset | NetworkReset,
-			ioaddr + ASICCtrl + 2);
-	for (i=50; i > 0; i--) {
-		if ((ioread16(ioaddr + ASICCtrl + 2) & ResetBusy) == 0)
-			break;
-		mdelay(1);
-	}
+	sundance_reset(dev, (NetworkReset|FIFOReset|DMAReset|TxReset) << 16);
+
 	/* free all tx skbuff */
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		skb = np->tx_skbuff[i];
diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c
index fd64b2b..c4c720e 100644
--- a/drivers/net/tulip/uli526x.c
+++ b/drivers/net/tulip/uli526x.c
@@ -1702,7 +1702,6 @@
 
 static int __init uli526x_init_module(void)
 {
-	int rc;
 
 	printk(version);
 	printed_version = 1;
@@ -1714,22 +1713,19 @@
 	if (cr6set)
 		uli526x_cr6_user_set = cr6set;
 
- 	switch(mode) {
+ 	switch (mode) {
    	case ULI526X_10MHF:
 	case ULI526X_100MHF:
 	case ULI526X_10MFD:
 	case ULI526X_100MFD:
 		uli526x_media_mode = mode;
 		break;
-	default:uli526x_media_mode = ULI526X_AUTO;
+	default:
+		uli526x_media_mode = ULI526X_AUTO;
 		break;
 	}
 
-	rc = pci_module_init(&uli526x_driver);
-	if (rc < 0)
-		return rc;
-
-	return 0;
+	return pci_register_driver(&uli526x_driver);
 }
 
 
diff --git a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c
index 430b1f6..a5e7ce1 100644
--- a/drivers/net/wan/cycx_main.c
+++ b/drivers/net/wan/cycx_main.c
@@ -40,7 +40,6 @@
 * 1998/08/08	acme		Initial version.
 */
 
-#include <linux/config.h>	/* OS configuration options */
 #include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
 #include <linux/string.h>	/* inline memset(), etc. */
diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c
index 6e1ec5b..7369875 100644
--- a/drivers/net/wan/dlci.c
+++ b/drivers/net/wan/dlci.c
@@ -28,7 +28,6 @@
  *		2 of the License, or (at your option) any later version.
  */
 
-#include <linux/config.h> /* for CONFIG_DLCI_COUNT */
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c
index 7628c2d..0ba018f 100644
--- a/drivers/net/wan/sdla.c
+++ b/drivers/net/wan/sdla.c
@@ -32,7 +32,6 @@
  *		2 of the License, or (at your option) any later version.
  */
 
-#include <linux/config.h> /* for CONFIG_DLCI_MAX */
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index a4dd139..16befbce 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -3950,13 +3950,11 @@
 	pRsp->rsp0 = IN4500(ai, RESP0);
 	pRsp->rsp1 = IN4500(ai, RESP1);
 	pRsp->rsp2 = IN4500(ai, RESP2);
-	if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET) {
-		airo_print_err(ai->dev->name, "cmd= %x\n", pCmd->cmd);
-		airo_print_err(ai->dev->name, "status= %x\n", pRsp->status);
-		airo_print_err(ai->dev->name, "Rsp0= %x\n", pRsp->rsp0);
-		airo_print_err(ai->dev->name, "Rsp1= %x\n", pRsp->rsp1);
-		airo_print_err(ai->dev->name, "Rsp2= %x\n", pRsp->rsp2);
-	}
+	if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET)
+		airo_print_err(ai->dev->name,
+			"cmd:%x status:%x rsp0:%x rsp1:%x rsp2:%x",
+			pCmd->cmd, pRsp->status, pRsp->rsp0, pRsp->rsp1,
+			pRsp->rsp2);
 
 	// clear stuck command busy if necessary
 	if (IN4500(ai, COMMAND) & COMMAND_BUSY) {
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 17a5682..c6ee1e9 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -504,6 +504,12 @@
 	 * This lock is only used by bcm43xx_phy_{un}lock()
 	 */
 	spinlock_t lock;
+
+	/* Firmware. */
+	const struct firmware *ucode;
+	const struct firmware *pcm;
+	const struct firmware *initvals0;
+	const struct firmware *initvals1;
 };
 
 
@@ -593,12 +599,14 @@
 	u8 available:1,
 	   enabled:1,
 	   initialized:1;
-	/** core_id ID number */
-	u16 id;
 	/** core_rev revision number */
 	u8 rev;
 	/** Index number for _switch_core() */
 	u8 index;
+	/** core_id ID number */
+	u16 id;
+	/** Core-specific data. */
+	void *priv;
 };
 
 /* Additional information for each 80211 core. */
@@ -647,7 +655,23 @@
 	BCM43xx_STAT_RESTARTING,	/* controller_restart() called. */
 };
 #define bcm43xx_status(bcm)		atomic_read(&(bcm)->init_status)
-#define bcm43xx_set_status(bcm, stat)	atomic_set(&(bcm)->init_status, (stat))
+#define bcm43xx_set_status(bcm, stat)	do {			\
+		atomic_set(&(bcm)->init_status, (stat));	\
+		smp_wmb();					\
+					} while (0)
+
+/*    *** THEORY OF LOCKING ***
+ *
+ * We have two different locks in the bcm43xx driver.
+ * => bcm->mutex:    General sleeping mutex. Protects struct bcm43xx_private
+ *                   and the device registers. This mutex does _not_ protect
+ *                   against concurrency from the IRQ handler.
+ * => bcm->irq_lock: IRQ spinlock. Protects against IRQ handler concurrency.
+ *
+ * Please note that, if you only take the irq_lock, you are not protected
+ * against concurrency from the periodic work handlers.
+ * Most times you want to take _both_ locks.
+ */
 
 struct bcm43xx_private {
 	struct ieee80211_device *ieee;
@@ -659,7 +683,6 @@
 
 	void __iomem *mmio_addr;
 
-	/* Locking, see "theory of locking" text below. */
 	spinlock_t irq_lock;
 	struct mutex mutex;
 
@@ -691,6 +714,7 @@
 	struct bcm43xx_sprominfo sprom;
 #define BCM43xx_NR_LEDS		4
 	struct bcm43xx_led leds[BCM43xx_NR_LEDS];
+	spinlock_t leds_lock;
 
 	/* The currently active core. */
 	struct bcm43xx_coreinfo *current_core;
@@ -708,10 +732,6 @@
 	struct bcm43xx_coreinfo core_80211[ BCM43xx_MAX_80211_CORES ];
 	/* Additional information, specific to the 80211 cores. */
 	struct bcm43xx_coreinfo_80211 core_80211_ext[ BCM43xx_MAX_80211_CORES ];
-	/* Index of the current 80211 core. If current_core is not
-	 * an 80211 core, this is -1.
-	 */
-	int current_80211_core_idx;
 	/* Number of available 80211 cores. */
 	int nr_80211_available;
 
@@ -724,6 +744,8 @@
 	u32 irq_savedstate;
 	/* Link Quality calculation context. */
 	struct bcm43xx_noise_calculation noisecalc;
+	/* if > 0 MAC is suspended. if == 0 MAC is enabled. */
+	int mac_suspended;
 
 	/* Threshold values. */
 	//TODO: The RTS thr has to be _used_. Currently, it is only set via WX.
@@ -746,12 +768,6 @@
 	struct bcm43xx_key key[54];
 	u8 default_key_idx;
 
-	/* Firmware. */
-	const struct firmware *ucode;
-	const struct firmware *pcm;
-	const struct firmware *initvals0;
-	const struct firmware *initvals1;
-
 	/* Random Number Generator. */
 	struct hwrng rng;
 	char rng_name[20 + 1];
@@ -763,55 +779,6 @@
 };
 
 
-/*    *** THEORY OF LOCKING ***
- *
- * We have two different locks in the bcm43xx driver.
- * => bcm->mutex:    General sleeping mutex. Protects struct bcm43xx_private
- *                   and the device registers.
- * => bcm->irq_lock: IRQ spinlock. Protects against IRQ handler concurrency.
- *
- * We have three types of helper function pairs to utilize these locks.
- *     (Always use the helper functions.)
- * 1) bcm43xx_{un}lock_noirq():
- *     Takes bcm->mutex. Does _not_ protect against IRQ concurrency,
- *     so it is almost always unsafe, if device IRQs are enabled.
- *     So only use this, if device IRQs are masked.
- *     Locking may sleep.
- *     You can sleep within the critical section.
- * 2) bcm43xx_{un}lock_irqonly():
- *     Takes bcm->irq_lock. Does _not_ protect against
- *     bcm43xx_lock_noirq() critical sections.
- *     Does only protect against the IRQ handler path and other
- *     irqonly() critical sections.
- *     Locking does not sleep.
- *     You must not sleep within the critical section.
- * 3) bcm43xx_{un}lock_irqsafe():
- *     This is the cummulative lock and takes both, mutex and irq_lock.
- *     Protects against noirq() and irqonly() critical sections (and
- *     the IRQ handler path).
- *     Locking may sleep.
- *     You must not sleep within the critical section.
- */
-
-/* Lock type 1 */
-#define bcm43xx_lock_noirq(bcm)		mutex_lock(&(bcm)->mutex)
-#define bcm43xx_unlock_noirq(bcm)	mutex_unlock(&(bcm)->mutex)
-/* Lock type 2 */
-#define bcm43xx_lock_irqonly(bcm, flags)	\
-	spin_lock_irqsave(&(bcm)->irq_lock, flags)
-#define bcm43xx_unlock_irqonly(bcm, flags)	\
-	spin_unlock_irqrestore(&(bcm)->irq_lock, flags)
-/* Lock type 3 */
-#define bcm43xx_lock_irqsafe(bcm, flags) do {	\
-	bcm43xx_lock_noirq(bcm);		\
-	bcm43xx_lock_irqonly(bcm, flags);	\
-		} while (0)
-#define bcm43xx_unlock_irqsafe(bcm, flags) do {	\
-	bcm43xx_unlock_irqonly(bcm, flags);	\
-	bcm43xx_unlock_noirq(bcm);		\
-		} while (0)
-
-
 static inline
 struct bcm43xx_private * bcm43xx_priv(struct net_device *dev)
 {
@@ -863,34 +830,33 @@
  * any of these functions.
  */
 static inline
+struct bcm43xx_coreinfo_80211 *
+bcm43xx_current_80211_priv(struct bcm43xx_private *bcm)
+{
+	assert(bcm->current_core->id == BCM43xx_COREID_80211);
+	return bcm->current_core->priv;
+}
+static inline
 struct bcm43xx_pio * bcm43xx_current_pio(struct bcm43xx_private *bcm)
 {
 	assert(bcm43xx_using_pio(bcm));
-	assert(bcm->current_80211_core_idx >= 0);
-	assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
-	return &(bcm->core_80211_ext[bcm->current_80211_core_idx].pio);
+	return &(bcm43xx_current_80211_priv(bcm)->pio);
 }
 static inline
 struct bcm43xx_dma * bcm43xx_current_dma(struct bcm43xx_private *bcm)
 {
 	assert(!bcm43xx_using_pio(bcm));
-	assert(bcm->current_80211_core_idx >= 0);
-	assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
-	return &(bcm->core_80211_ext[bcm->current_80211_core_idx].dma);
+	return &(bcm43xx_current_80211_priv(bcm)->dma);
 }
 static inline
 struct bcm43xx_phyinfo * bcm43xx_current_phy(struct bcm43xx_private *bcm)
 {
-	assert(bcm->current_80211_core_idx >= 0);
-	assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
-	return &(bcm->core_80211_ext[bcm->current_80211_core_idx].phy);
+	return &(bcm43xx_current_80211_priv(bcm)->phy);
 }
 static inline
 struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm)
 {
-	assert(bcm->current_80211_core_idx >= 0);
-	assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
-	return &(bcm->core_80211_ext[bcm->current_80211_core_idx].radio);
+	return &(bcm43xx_current_80211_priv(bcm)->radio);
 }
 
 
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
index ce2e40b..923275e 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
@@ -77,7 +77,8 @@
 
 	down(&big_buffer_sem);
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
 		fappend("Board not initialized.\n");
 		goto out;
@@ -121,7 +122,8 @@
 	fappend("\n");
 
 out:
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
 	up(&big_buffer_sem);
 	return res;
@@ -159,7 +161,8 @@
 	unsigned long flags;
 
 	down(&big_buffer_sem);
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
 		fappend("Board not initialized.\n");
 		goto out;
@@ -169,7 +172,8 @@
 	fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags);
 
 out:
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
 	up(&big_buffer_sem);
 	return res;
@@ -188,7 +192,8 @@
 	u64 tsf;
 
 	down(&big_buffer_sem);
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
 		fappend("Board not initialized.\n");
 		goto out;
@@ -199,7 +204,8 @@
 		(unsigned int)(tsf & 0xFFFFFFFFULL));
 
 out:
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
 	up(&big_buffer_sem);
 	return res;
@@ -221,7 +227,8 @@
 	        res = -EFAULT;
 		goto out_up;
 	}
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
 		printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
 		res = -EFAULT;
@@ -237,7 +244,8 @@
 	res = buf_size;
 	
 out_unlock:
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 out_up:
 	up(&big_buffer_sem);
 	return res;
@@ -258,7 +266,8 @@
 	int i, cnt, j = 0;
 
 	down(&big_buffer_sem);
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 
 	fappend("Last %d logged xmitstatus blobs (Latest first):\n\n",
 		BCM43xx_NR_LOGGED_XMITSTATUS);
@@ -294,14 +303,51 @@
 			i = BCM43xx_NR_LOGGED_XMITSTATUS - 1;
 	}
 
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
 	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
-	bcm43xx_lock_irqsafe(bcm, flags);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	if (*ppos == pos) {
 		/* Done. Drop the copied data. */
 		e->xmitstatus_printing = 0;
 	}
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
+	up(&big_buffer_sem);
+	return res;
+}
+
+static ssize_t restart_write_file(struct file *file, const char __user *user_buf,
+				  size_t count, loff_t *ppos)
+{
+	struct bcm43xx_private *bcm = file->private_data;
+	char *buf = really_big_buffer;
+	ssize_t buf_size;
+	ssize_t res;
+	unsigned long flags;
+
+	buf_size = min(count, sizeof (really_big_buffer) - 1);
+	down(&big_buffer_sem);
+	if (copy_from_user(buf, user_buf, buf_size)) {
+	        res = -EFAULT;
+		goto out_up;
+	}
+	mutex_lock(&(bcm)->mutex);
+	spin_lock_irqsave(&(bcm)->irq_lock, flags);
+	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
+		printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	if (count > 0 && buf[0] == '1') {
+		bcm43xx_controller_restart(bcm, "manually restarted");
+		res = count;
+	} else
+		res = -EINVAL;
+
+out_unlock:
+	spin_unlock_irqrestore(&(bcm)->irq_lock, flags);
+	mutex_unlock(&(bcm)->mutex);
+out_up:
 	up(&big_buffer_sem);
 	return res;
 }
@@ -339,6 +385,11 @@
 	.open = open_file_generic,
 };
 
+static struct file_operations restart_fops = {
+	.write = restart_write_file,
+	.open = open_file_generic,
+};
+
 
 void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm)
 {
@@ -390,6 +441,10 @@
 						bcm, &txstat_fops);
 	if (!e->dentry_txstat)
 		printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir);
+	e->dentry_restart = debugfs_create_file("restart", 0222, e->subdir,
+						bcm, &restart_fops);
+	if (!e->dentry_restart)
+		printk(KERN_ERR PFX "debugfs: creating \"restart\" for \"%s\" failed!\n", devdir);
 }
 
 void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm)
@@ -405,6 +460,7 @@
 	debugfs_remove(e->dentry_devinfo);
 	debugfs_remove(e->dentry_tsf);
 	debugfs_remove(e->dentry_txstat);
+	debugfs_remove(e->dentry_restart);
 	debugfs_remove(e->subdir);
 	kfree(e->xmitstatus_buffer);
 	kfree(e->xmitstatus_print_buffer);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h
index 50ce267..a40d1af 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h
@@ -20,6 +20,7 @@
 	struct dentry *dentry_spromdump;
 	struct dentry *dentry_tsf;
 	struct dentry *dentry_txstat;
+	struct dentry *dentry_restart;
 
 	struct bcm43xx_private *bcm;
 
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
index ec80692..c3f90c8 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
@@ -51,12 +51,12 @@
 	struct bcm43xx_private *bcm = led->bcm;
 	unsigned long flags;
 
-	bcm43xx_lock_irqonly(bcm, flags);
+	spin_lock_irqsave(&bcm->leds_lock, flags);
 	if (led->blink_interval) {
 		bcm43xx_led_changestate(led);
 		mod_timer(&led->blink_timer, jiffies + led->blink_interval);
 	}
-	bcm43xx_unlock_irqonly(bcm, flags);
+	spin_unlock_irqrestore(&bcm->leds_lock, flags);
 }
 
 static void bcm43xx_led_blink_start(struct bcm43xx_led *led,
@@ -177,7 +177,9 @@
 	int i, turn_on;
 	unsigned long interval = 0;
 	u16 ledctl;
+	unsigned long flags;
 
+	spin_lock_irqsave(&bcm->leds_lock, flags);
 	ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
 	for (i = 0; i < BCM43xx_NR_LEDS; i++) {
 		led = &(bcm->leds[i]);
@@ -266,6 +268,7 @@
 			ledctl &= ~(1 << i);
 	}
 	bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
+	spin_unlock_irqrestore(&bcm->leds_lock, flags);
 }
 
 void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on)
@@ -274,7 +277,9 @@
 	u16 ledctl;
 	int i;
 	int bit_on;
+	unsigned long flags;
 
+	spin_lock_irqsave(&bcm->leds_lock, flags);
 	ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
 	for (i = 0; i < BCM43xx_NR_LEDS; i++) {
 		led = &(bcm->leds[i]);
@@ -290,4 +295,5 @@
 			ledctl &= ~(1 << i);
 	}
 	bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
+	spin_unlock_irqrestore(&bcm->leds_lock, flags);
 }
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index df317c1..b095f3c 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -509,23 +509,19 @@
 }
 
 /* Make sure we don't receive more data from the device. */
-static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate)
+static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm)
 {
 	unsigned long flags;
-	u32 old;
 
-	bcm43xx_lock_irqonly(bcm, flags);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)) {
-		bcm43xx_unlock_irqonly(bcm, flags);
+		spin_unlock_irqrestore(&bcm->irq_lock, flags);
 		return -EBUSY;
 	}
-	old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
-	bcm43xx_unlock_irqonly(bcm, flags);
+	bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
 	bcm43xx_synchronize_irq(bcm);
 
-	if (oldstate)
-		*oldstate = old;
-
 	return 0;
 }
 
@@ -537,7 +533,6 @@
 	u16 manufact;
 	u16 version;
 	u8 revision;
-	s8 i;
 
 	if (bcm->chip_id == 0x4317) {
 		if (bcm->chip_rev == 0x00)
@@ -580,20 +575,11 @@
 	radio->version = version;
 	radio->revision = revision;
 
-	/* Set default attenuation values. */
-	radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm);
-	radio->radio_atten = bcm43xx_default_radio_attenuation(bcm);
-	radio->txctl1 = bcm43xx_default_txctl1(bcm);
-	radio->txctl2 = 0xFFFF;
 	if (phy->type == BCM43xx_PHYTYPE_A)
 		radio->txpower_desired = bcm->sprom.maxpower_aphy;
 	else
 		radio->txpower_desired = bcm->sprom.maxpower_bgphy;
 
-	/* Initialize the in-memory nrssi Lookup Table. */
-	for (i = 0; i < 64; i++)
-		radio->nrssi_lt[i] = i;
-
 	return 0;
 
 err_unsupported_radio:
@@ -1250,10 +1236,6 @@
 		goto out;
 
 	bcm->current_core = new_core;
-	bcm->current_80211_core_idx = -1;
-	if (new_core->id == BCM43xx_COREID_80211)
-		bcm->current_80211_core_idx = (int)(new_core - &(bcm->core_80211[0]));
-
 out:
 	return err;
 }
@@ -1423,43 +1405,23 @@
 	bcm43xx_core_disable(bcm, 0);
 }
 
-/* Mark the current 80211 core inactive.
- * "active_80211_core" is the other 80211 core, which is used.
- */
-static int bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm,
-					       struct bcm43xx_coreinfo *active_80211_core)
+/* Mark the current 80211 core inactive. */
+static void bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm)
 {
 	u32 sbtmstatelow;
-	struct bcm43xx_coreinfo *old_core;
-	int err = 0;
 
 	bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
 	bcm43xx_radio_turn_off(bcm);
 	sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
-	sbtmstatelow &= ~0x200a0000;
-	sbtmstatelow |= 0xa0000;
+	sbtmstatelow &= 0xDFF5FFFF;
+	sbtmstatelow |= 0x000A0000;
 	bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
 	udelay(1);
 	sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
-	sbtmstatelow &= ~0xa0000;
-	sbtmstatelow |= 0x80000;
+	sbtmstatelow &= 0xFFF5FFFF;
+	sbtmstatelow |= 0x00080000;
 	bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
 	udelay(1);
-
-	if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G) {
-		old_core = bcm->current_core;
-		err = bcm43xx_switch_core(bcm, active_80211_core);
-		if (err)
-			goto out;
-		sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
-		sbtmstatelow &= ~0x20000000;
-		sbtmstatelow |= 0x20000000;
-		bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
-		err = bcm43xx_switch_core(bcm, old_core);
-	}
-
-out:
-	return err;
 }
 
 static void handle_irq_transmit_status(struct bcm43xx_private *bcm)
@@ -1720,7 +1682,7 @@
 # define bcmirq_handled(irq)	do { /* nothing */ } while (0)
 #endif /* CONFIG_BCM43XX_DEBUG*/
 
-	bcm43xx_lock_irqonly(bcm, flags);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	reason = bcm->irq_reason;
 	dma_reason[0] = bcm->dma_reason[0];
 	dma_reason[1] = bcm->dma_reason[1];
@@ -1746,7 +1708,7 @@
 			dma_reason[2], dma_reason[3]);
 		bcm43xx_controller_restart(bcm, "DMA error");
 		mmiowb();
-		bcm43xx_unlock_irqonly(bcm, flags);
+		spin_unlock_irqrestore(&bcm->irq_lock, flags);
 		return;
 	}
 	if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) |
@@ -1834,7 +1796,7 @@
 		bcm43xx_leds_update(bcm, activity);
 	bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
 	mmiowb();
-	bcm43xx_unlock_irqonly(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
 }
 
 static void pio_irq_workaround(struct bcm43xx_private *bcm,
@@ -1885,14 +1847,8 @@
 
 	spin_lock(&bcm->irq_lock);
 
-	/* Only accept IRQs, if we are initialized properly.
-	 * This avoids an RX race while initializing.
-	 * We should probably not enable IRQs before we are initialized
-	 * completely, but some careful work is needed to fix this. I think it
-	 * is best to stay with this cheap workaround for now... .
-	 */
-	if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED))
-		goto out;
+	assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
+	assert(bcm->current_core->id == BCM43xx_COREID_80211);
 
 	reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
 	if (reason == 0xffffffff) {
@@ -1930,16 +1886,18 @@
 
 static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force)
 {
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+
 	if (bcm->firmware_norelease && !force)
 		return; /* Suspending or controller reset. */
-	release_firmware(bcm->ucode);
-	bcm->ucode = NULL;
-	release_firmware(bcm->pcm);
-	bcm->pcm = NULL;
-	release_firmware(bcm->initvals0);
-	bcm->initvals0 = NULL;
-	release_firmware(bcm->initvals1);
-	bcm->initvals1 = NULL;
+	release_firmware(phy->ucode);
+	phy->ucode = NULL;
+	release_firmware(phy->pcm);
+	phy->pcm = NULL;
+	release_firmware(phy->initvals0);
+	phy->initvals0 = NULL;
+	release_firmware(phy->initvals1);
+	phy->initvals1 = NULL;
 }
 
 static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
@@ -1950,11 +1908,11 @@
 	int nr;
 	char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 };
 
-	if (!bcm->ucode) {
+	if (!phy->ucode) {
 		snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw",
 			 (rev >= 5 ? 5 : rev),
 			 modparam_fwpostfix);
-		err = request_firmware(&bcm->ucode, buf, &bcm->pci_dev->dev);
+		err = request_firmware(&phy->ucode, buf, &bcm->pci_dev->dev);
 		if (err) {
 			printk(KERN_ERR PFX 
 			       "Error: Microcode \"%s\" not available or load failed.\n",
@@ -1963,12 +1921,12 @@
 		}
 	}
 
-	if (!bcm->pcm) {
+	if (!phy->pcm) {
 		snprintf(buf, ARRAY_SIZE(buf),
 			 "bcm43xx_pcm%d%s.fw",
 			 (rev < 5 ? 4 : 5),
 			 modparam_fwpostfix);
-		err = request_firmware(&bcm->pcm, buf, &bcm->pci_dev->dev);
+		err = request_firmware(&phy->pcm, buf, &bcm->pci_dev->dev);
 		if (err) {
 			printk(KERN_ERR PFX
 			       "Error: PCM \"%s\" not available or load failed.\n",
@@ -1977,7 +1935,7 @@
 		}
 	}
 
-	if (!bcm->initvals0) {
+	if (!phy->initvals0) {
 		if (rev == 2 || rev == 4) {
 			switch (phy->type) {
 			case BCM43xx_PHYTYPE_A:
@@ -2008,20 +1966,20 @@
 		snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
 			 nr, modparam_fwpostfix);
 
-		err = request_firmware(&bcm->initvals0, buf, &bcm->pci_dev->dev);
+		err = request_firmware(&phy->initvals0, buf, &bcm->pci_dev->dev);
 		if (err) {
 			printk(KERN_ERR PFX 
 			       "Error: InitVals \"%s\" not available or load failed.\n",
 			        buf);
 			goto error;
 		}
-		if (bcm->initvals0->size % sizeof(struct bcm43xx_initval)) {
+		if (phy->initvals0->size % sizeof(struct bcm43xx_initval)) {
 			printk(KERN_ERR PFX "InitVals fileformat error.\n");
 			goto error;
 		}
 	}
 
-	if (!bcm->initvals1) {
+	if (!phy->initvals1) {
 		if (rev >= 5) {
 			u32 sbtmstatehigh;
 
@@ -2043,14 +2001,14 @@
 			snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
 				 nr, modparam_fwpostfix);
 
-			err = request_firmware(&bcm->initvals1, buf, &bcm->pci_dev->dev);
+			err = request_firmware(&phy->initvals1, buf, &bcm->pci_dev->dev);
 			if (err) {
 				printk(KERN_ERR PFX 
 				       "Error: InitVals \"%s\" not available or load failed.\n",
 			        	buf);
 				goto error;
 			}
-			if (bcm->initvals1->size % sizeof(struct bcm43xx_initval)) {
+			if (phy->initvals1->size % sizeof(struct bcm43xx_initval)) {
 				printk(KERN_ERR PFX "InitVals fileformat error.\n");
 				goto error;
 			}
@@ -2070,12 +2028,13 @@
 
 static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm)
 {
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
 	const u32 *data;
 	unsigned int i, len;
 
 	/* Upload Microcode. */
-	data = (u32 *)(bcm->ucode->data);
-	len = bcm->ucode->size / sizeof(u32);
+	data = (u32 *)(phy->ucode->data);
+	len = phy->ucode->size / sizeof(u32);
 	bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000);
 	for (i = 0; i < len; i++) {
 		bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
@@ -2084,8 +2043,8 @@
 	}
 
 	/* Upload PCM data. */
-	data = (u32 *)(bcm->pcm->data);
-	len = bcm->pcm->size / sizeof(u32);
+	data = (u32 *)(phy->pcm->data);
+	len = phy->pcm->size / sizeof(u32);
 	bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea);
 	bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000);
 	bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb);
@@ -2131,15 +2090,16 @@
 
 static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm)
 {
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
 	int err;
 
-	err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data,
-				     bcm->initvals0->size / sizeof(struct bcm43xx_initval));
+	err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals0->data,
+				     phy->initvals0->size / sizeof(struct bcm43xx_initval));
 	if (err)
 		goto out;
-	if (bcm->initvals1) {
-		err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data,
-					     bcm->initvals1->size / sizeof(struct bcm43xx_initval));
+	if (phy->initvals1) {
+		err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals1->data,
+					     phy->initvals1->size / sizeof(struct bcm43xx_initval));
 		if (err)
 			goto out;
 	}
@@ -2156,9 +2116,7 @@
 
 static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
 {
-	int res;
-	unsigned int i;
-	u32 data;
+	int err;
 
 	bcm->irq = bcm->pci_dev->irq;
 #ifdef CONFIG_BCM947XX
@@ -2175,32 +2133,12 @@
 		}
 	}
 #endif
-	res = request_irq(bcm->irq, bcm43xx_interrupt_handler,
+	err = request_irq(bcm->irq, bcm43xx_interrupt_handler,
 			  IRQF_SHARED, KBUILD_MODNAME, bcm);
-	if (res) {
+	if (err)
 		printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq);
-		return -ENODEV;
-	}
-	bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff);
-	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);
-	i = 0;
-	while (1) {
-		data = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
-		if (data == BCM43xx_IRQ_READY)
-			break;
-		i++;
-		if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {
-			printk(KERN_ERR PFX "Card IRQ register not responding. "
-					    "Giving up.\n");
-			free_irq(bcm->irq, bcm);
-			return -ENODEV;
-		}
-		udelay(10);
-	}
-	// dummy read
-	bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
 
-	return 0;
+	return err;
 }
 
 /* Switch to the core used to write the GPIO register.
@@ -2298,13 +2236,17 @@
 /* http://bcm-specs.sipsolutions.net/EnableMac */
 void bcm43xx_mac_enable(struct bcm43xx_private *bcm)
 {
-	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
-	                bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
-			| BCM43xx_SBF_MAC_ENABLED);
-	bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY);
-	bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
-	bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
-	bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
+	bcm->mac_suspended--;
+	assert(bcm->mac_suspended >= 0);
+	if (bcm->mac_suspended == 0) {
+		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+		                bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
+				| BCM43xx_SBF_MAC_ENABLED);
+		bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY);
+		bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
+		bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
+		bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
+	}
 }
 
 /* http://bcm-specs.sipsolutions.net/SuspendMAC */
@@ -2313,18 +2255,23 @@
 	int i;
 	u32 tmp;
 
-	bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
-	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
-	                bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
-			& ~BCM43xx_SBF_MAC_ENABLED);
-	bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
-	for (i = 100000; i; i--) {
-		tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
-		if (tmp & BCM43xx_IRQ_READY)
-			return;
-		udelay(10);
+	assert(bcm->mac_suspended >= 0);
+	if (bcm->mac_suspended == 0) {
+		bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
+		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+		                bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
+				& ~BCM43xx_SBF_MAC_ENABLED);
+		bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
+		for (i = 10000; i; i--) {
+			tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
+			if (tmp & BCM43xx_IRQ_READY)
+				goto out;
+			udelay(1);
+		}
+		printkl(KERN_ERR PFX "MAC suspend failed\n");
 	}
-	printkl(KERN_ERR PFX "MAC suspend failed\n");
+out:
+	bcm->mac_suspended++;
 }
 
 void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,
@@ -2394,7 +2341,6 @@
 	if (!modparam_noleds)
 		bcm43xx_leds_exit(bcm);
 	bcm43xx_gpio_cleanup(bcm);
-	free_irq(bcm->irq, bcm);
 	bcm43xx_release_firmware(bcm, 0);
 }
 
@@ -2406,7 +2352,7 @@
 	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
 	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
 	int err;
-	int tmp;
+	int i, tmp;
 	u32 value32;
 	u16 value16;
 
@@ -2419,13 +2365,26 @@
 		goto out;
 	bcm43xx_upload_microcode(bcm);
 
-	err = bcm43xx_initialize_irq(bcm);
-	if (err)
-		goto err_release_fw;
+	bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xFFFFFFFF);
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);
+	i = 0;
+	while (1) {
+		value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
+		if (value32 == BCM43xx_IRQ_READY)
+			break;
+		i++;
+		if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {
+			printk(KERN_ERR PFX "IRQ_READY timeout\n");
+			err = -ENODEV;
+			goto err_release_fw;
+		}
+		udelay(10);
+	}
+	bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
 
 	err = bcm43xx_gpio_init(bcm);
 	if (err)
-		goto err_free_irq;
+		goto err_release_fw;
 
 	err = bcm43xx_upload_initvals(bcm);
 	if (err)
@@ -2509,8 +2468,6 @@
 	bcm43xx_radio_turn_off(bcm);
 err_gpio_cleanup:
 	bcm43xx_gpio_cleanup(bcm);
-err_free_irq:
-	free_irq(bcm->irq, bcm);
 err_release_fw:
 	bcm43xx_release_firmware(bcm, 1);
 	goto out;
@@ -2550,11 +2507,9 @@
 {
 	/* Initialize a "phyinfo" structure. The structure is already
 	 * zeroed out.
+	 * This is called on insmod time to initialize members.
 	 */
-	phy->antenna_diversity = 0xFFFF;
 	phy->savedpctlreg = 0xFFFF;
-	phy->minlowsig[0] = 0xFFFF;
-	phy->minlowsig[1] = 0xFFFF;
 	spin_lock_init(&phy->lock);
 }
 
@@ -2562,14 +2517,11 @@
 {
 	/* Initialize a "radioinfo" structure. The structure is already
 	 * zeroed out.
+	 * This is called on insmod time to initialize members.
 	 */
 	radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
 	radio->channel = 0xFF;
 	radio->initial_channel = 0xFF;
-	radio->lofcal = 0xFFFF;
-	radio->initval = 0xFFFF;
-	radio->nrssi[0] = -1000;
-	radio->nrssi[1] = -1000;
 }
 
 static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
@@ -2587,7 +2539,6 @@
 				    * BCM43xx_MAX_80211_CORES);
 	memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211)
 					* BCM43xx_MAX_80211_CORES);
-	bcm->current_80211_core_idx = -1;
 	bcm->nr_80211_available = 0;
 	bcm->current_core = NULL;
 	bcm->active_80211_core = NULL;
@@ -2757,6 +2708,7 @@
 				goto out;
 			}
 			bcm->nr_80211_available++;
+			core->priv = ext_80211;
 			bcm43xx_init_struct_phyinfo(&ext_80211->phy);
 			bcm43xx_init_struct_radioinfo(&ext_80211->radio);
 			break;
@@ -2857,7 +2809,8 @@
 }
 
 /* http://bcm-specs.sipsolutions.net/80211Init */
-static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm)
+static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm,
+				      int active_wlcore)
 {
 	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
 	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
@@ -2939,19 +2892,26 @@
 	if (bcm->current_core->rev >= 5)
 		bcm43xx_write16(bcm, 0x043C, 0x000C);
 
-	if (bcm43xx_using_pio(bcm))
-		err = bcm43xx_pio_init(bcm);
-	else
-		err = bcm43xx_dma_init(bcm);
-	if (err)
-		goto err_chip_cleanup;
+	if (active_wlcore) {
+		if (bcm43xx_using_pio(bcm))
+			err = bcm43xx_pio_init(bcm);
+		else
+			err = bcm43xx_dma_init(bcm);
+		if (err)
+			goto err_chip_cleanup;
+	}
 	bcm43xx_write16(bcm, 0x0612, 0x0050);
 	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050);
 	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4);
 
-	bcm43xx_mac_enable(bcm);
-	bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
+	if (active_wlcore) {
+		if (radio->initial_channel != 0xFF)
+			bcm43xx_radio_selectchannel(bcm, radio->initial_channel, 0);
+	}
 
+	/* Don't enable MAC/IRQ here, as it will race with the IRQ handler.
+	 * We enable it later.
+	 */
 	bcm->current_core->initialized = 1;
 out:
 	return err;
@@ -3066,11 +3026,6 @@
 	return err;
 }
 
-static void bcm43xx_softmac_init(struct bcm43xx_private *bcm)
-{
-	ieee80211softmac_start(bcm->net_dev);
-}
-
 static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm)
 {
 	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
@@ -3182,39 +3137,40 @@
 		/* Periodic work will take a long time, so we want it to
 		 * be preemtible.
 		 */
-		bcm43xx_lock_irqonly(bcm, flags);
 		netif_stop_queue(bcm->net_dev);
+		synchronize_net();
+		spin_lock_irqsave(&bcm->irq_lock, flags);
+		bcm43xx_mac_suspend(bcm);
 		if (bcm43xx_using_pio(bcm))
 			bcm43xx_pio_freeze_txqueues(bcm);
 		savedirqs = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
-		bcm43xx_unlock_irqonly(bcm, flags);
-		bcm43xx_lock_noirq(bcm);
+		spin_unlock_irqrestore(&bcm->irq_lock, flags);
+		mutex_lock(&bcm->mutex);
 		bcm43xx_synchronize_irq(bcm);
 	} else {
 		/* Periodic work should take short time, so we want low
 		 * locking overhead.
 		 */
-		bcm43xx_lock_irqsafe(bcm, flags);
+		mutex_lock(&bcm->mutex);
+		spin_lock_irqsave(&bcm->irq_lock, flags);
 	}
 
 	do_periodic_work(bcm);
 
 	if (badness > BADNESS_LIMIT) {
-		bcm43xx_lock_irqonly(bcm, flags);
+		spin_lock_irqsave(&bcm->irq_lock, flags);
 		if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) {
 			tasklet_enable(&bcm->isr_tasklet);
 			bcm43xx_interrupt_enable(bcm, savedirqs);
 			if (bcm43xx_using_pio(bcm))
 				bcm43xx_pio_thaw_txqueues(bcm);
+			bcm43xx_mac_enable(bcm);
 		}
 		netif_wake_queue(bcm->net_dev);
-		mmiowb();
-		bcm43xx_unlock_irqonly(bcm, flags);
-		bcm43xx_unlock_noirq(bcm);
-	} else {
-		mmiowb();
-		bcm43xx_unlock_irqsafe(bcm, flags);
 	}
+	mmiowb();
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 }
 
 static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
@@ -3243,9 +3199,9 @@
 	struct bcm43xx_private *bcm = (struct bcm43xx_private *)rng->priv;
 	unsigned long flags;
 
-	bcm43xx_lock_irqonly(bcm, flags);
+	spin_lock_irqsave(&(bcm)->irq_lock, flags);
 	*data = bcm43xx_read16(bcm, BCM43xx_MMIO_RNG);
-	bcm43xx_unlock_irqonly(bcm, flags);
+	spin_unlock_irqrestore(&(bcm)->irq_lock, flags);
 
 	return (sizeof(u16));
 }
@@ -3271,139 +3227,322 @@
 	return err;
 }
 
+static int bcm43xx_shutdown_all_wireless_cores(struct bcm43xx_private *bcm)
+{
+	int ret = 0;
+	int i, err;
+	struct bcm43xx_coreinfo *core;
+
+	bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN);
+	for (i = 0; i < bcm->nr_80211_available; i++) {
+		core = &(bcm->core_80211[i]);
+		assert(core->available);
+		if (!core->initialized)
+			continue;
+		err = bcm43xx_switch_core(bcm, core);
+		if (err) {
+			dprintk(KERN_ERR PFX "shutdown_all_wireless_cores "
+					     "switch_core failed (%d)\n", err);
+			ret = err;
+			continue;
+		}
+		bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+		bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
+		bcm43xx_wireless_core_cleanup(bcm);
+		if (core == bcm->active_80211_core)
+			bcm->active_80211_core = NULL;
+	}
+	free_irq(bcm->irq, bcm);
+	bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
+
+	return ret;
+}
+
 /* This is the opposite of bcm43xx_init_board() */
 static void bcm43xx_free_board(struct bcm43xx_private *bcm)
 {
-	int i, err;
-
-	bcm43xx_lock_noirq(bcm);
 	bcm43xx_sysfs_unregister(bcm);
 	bcm43xx_periodic_tasks_delete(bcm);
 
-	bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN);
+	mutex_lock(&(bcm)->mutex);
+	bcm43xx_shutdown_all_wireless_cores(bcm);
+	bcm43xx_pctl_set_crystal(bcm, 0);
+	mutex_unlock(&(bcm)->mutex);
+}
 
-	bcm43xx_rng_exit(bcm);
+static void prepare_phydata_for_init(struct bcm43xx_phyinfo *phy)
+{
+	phy->antenna_diversity = 0xFFFF;
+	memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
+	memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
+
+	/* Flags */
+	phy->calibrated = 0;
+	phy->is_locked = 0;
+
+	if (phy->_lo_pairs) {
+		memset(phy->_lo_pairs, 0,
+		       sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT);
+	}
+	memset(phy->loopback_gain, 0, sizeof(phy->loopback_gain));
+}
+
+static void prepare_radiodata_for_init(struct bcm43xx_private *bcm,
+				       struct bcm43xx_radioinfo *radio)
+{
+	int i;
+
+	/* Set default attenuation values. */
+	radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm);
+	radio->radio_atten = bcm43xx_default_radio_attenuation(bcm);
+	radio->txctl1 = bcm43xx_default_txctl1(bcm);
+	radio->txctl2 = 0xFFFF;
+	radio->txpwr_offset = 0;
+
+	/* NRSSI */
+	radio->nrssislope = 0;
+	for (i = 0; i < ARRAY_SIZE(radio->nrssi); i++)
+		radio->nrssi[i] = -1000;
+	for (i = 0; i < ARRAY_SIZE(radio->nrssi_lt); i++)
+		radio->nrssi_lt[i] = i;
+
+	radio->lofcal = 0xFFFF;
+	radio->initval = 0xFFFF;
+
+	radio->aci_enable = 0;
+	radio->aci_wlan_automatic = 0;
+	radio->aci_hw_rssi = 0;
+}
+
+static void prepare_priv_for_init(struct bcm43xx_private *bcm)
+{
+	int i;
+	struct bcm43xx_coreinfo *core;
+	struct bcm43xx_coreinfo_80211 *wlext;
+
+	assert(!bcm->active_80211_core);
+
+	bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
+
+	/* Flags */
+	bcm->was_initialized = 0;
+	bcm->reg124_set_0x4 = 0;
+
+	/* Stats */
+	memset(&bcm->stats, 0, sizeof(bcm->stats));
+
+	/* Wireless core data */
 	for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
-		if (!bcm->core_80211[i].available)
-			continue;
-		if (!bcm->core_80211[i].initialized)
-			continue;
+		core = &(bcm->core_80211[i]);
+		wlext = core->priv;
 
-		err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
-		assert(err == 0);
-		bcm43xx_wireless_core_cleanup(bcm);
+		if (!core->available)
+			continue;
+		assert(wlext == &(bcm->core_80211_ext[i]));
+
+		prepare_phydata_for_init(&wlext->phy);
+		prepare_radiodata_for_init(bcm, &wlext->radio);
 	}
 
-	bcm43xx_pctl_set_crystal(bcm, 0);
+	/* IRQ related flags */
+	bcm->irq_reason = 0;
+	memset(bcm->dma_reason, 0, sizeof(bcm->dma_reason));
+	bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
 
+	/* Noise calculation context */
+	memset(&bcm->noisecalc, 0, sizeof(bcm->noisecalc));
+
+	/* Periodic work context */
+	bcm->periodic_state = 0;
+}
+
+static int wireless_core_up(struct bcm43xx_private *bcm,
+			    int active_wlcore)
+{
+	int err;
+
+	if (!bcm43xx_core_enabled(bcm))
+		bcm43xx_wireless_core_reset(bcm, 1);
+	if (!active_wlcore)
+		bcm43xx_wireless_core_mark_inactive(bcm);
+	err = bcm43xx_wireless_core_init(bcm, active_wlcore);
+	if (err)
+		goto out;
+	if (!active_wlcore)
+		bcm43xx_radio_turn_off(bcm);
+out:
+	return err;
+}
+
+/* Select and enable the "to be used" wireless core.
+ * Locking: bcm->mutex must be aquired before calling this.
+ *          bcm->irq_lock must not be aquired.
+ */
+int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm,
+				 int phytype)
+{
+	int i, err;
+	struct bcm43xx_coreinfo *active_core = NULL;
+	struct bcm43xx_coreinfo_80211 *active_wlext = NULL;
+	struct bcm43xx_coreinfo *core;
+	struct bcm43xx_coreinfo_80211 *wlext;
+	int adjust_active_sbtmstatelow = 0;
+
+	might_sleep();
+
+	if (phytype < 0) {
+		/* If no phytype is requested, select the first core. */
+		assert(bcm->core_80211[0].available);
+		wlext = bcm->core_80211[0].priv;
+		phytype = wlext->phy.type;
+	}
+	/* Find the requested core. */
+	for (i = 0; i < bcm->nr_80211_available; i++) {
+		core = &(bcm->core_80211[i]);
+		wlext = core->priv;
+		if (wlext->phy.type == phytype) {
+			active_core = core;
+			active_wlext = wlext;
+			break;
+		}
+	}
+	if (!active_core)
+		return -ESRCH; /* No such PHYTYPE on this board. */
+
+	if (bcm->active_80211_core) {
+		/* We already selected a wl core in the past.
+		 * So first clean up everything.
+		 */
+		dprintk(KERN_INFO PFX "select_wireless_core: cleanup\n");
+		ieee80211softmac_stop(bcm->net_dev);
+		bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
+		err = bcm43xx_disable_interrupts_sync(bcm);
+		assert(!err);
+		tasklet_enable(&bcm->isr_tasklet);
+		err = bcm43xx_shutdown_all_wireless_cores(bcm);
+		if (err)
+			goto error;
+		/* Ok, everything down, continue to re-initialize. */
+		bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
+	}
+
+	/* Reset all data structures. */
+	prepare_priv_for_init(bcm);
+
+	err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST);
+	if (err)
+		goto error;
+
+	/* Mark all unused cores "inactive". */
+	for (i = 0; i < bcm->nr_80211_available; i++) {
+		core = &(bcm->core_80211[i]);
+		wlext = core->priv;
+
+		if (core == active_core)
+			continue;
+		err = bcm43xx_switch_core(bcm, core);
+		if (err) {
+			dprintk(KERN_ERR PFX "Could not switch to inactive "
+					     "802.11 core (%d)\n", err);
+			goto error;
+		}
+		err = wireless_core_up(bcm, 0);
+		if (err) {
+			dprintk(KERN_ERR PFX "core_up for inactive 802.11 core "
+					     "failed (%d)\n", err);
+			goto error;
+		}
+		adjust_active_sbtmstatelow = 1;
+	}
+
+	/* Now initialize the active 802.11 core. */
+	err = bcm43xx_switch_core(bcm, active_core);
+	if (err) {
+		dprintk(KERN_ERR PFX "Could not switch to active "
+				     "802.11 core (%d)\n", err);
+		goto error;
+	}
+	if (adjust_active_sbtmstatelow &&
+	    active_wlext->phy.type == BCM43xx_PHYTYPE_G) {
+		u32 sbtmstatelow;
+
+		sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+		sbtmstatelow |= 0x20000000;
+		bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
+	}
+	err = wireless_core_up(bcm, 1);
+	if (err) {
+		dprintk(KERN_ERR PFX "core_up for active 802.11 core "
+				     "failed (%d)\n", err);
+		goto error;
+	}
+	err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC);
+	if (err)
+		goto error;
+	bcm->active_80211_core = active_core;
+
+	bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
+	bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr));
+	bcm43xx_security_init(bcm);
+	ieee80211softmac_start(bcm->net_dev);
+
+	/* Let's go! Be careful after enabling the IRQs.
+	 * Don't switch cores, for example.
+	 */
+	bcm43xx_mac_enable(bcm);
+	bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
+	err = bcm43xx_initialize_irq(bcm);
+	if (err)
+		goto error;
+	bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
+
+	dprintk(KERN_INFO PFX "Selected 802.11 core (phytype %d)\n",
+		active_wlext->phy.type);
+
+	return 0;
+
+error:
 	bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
-	bcm43xx_unlock_noirq(bcm);
+	bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
+	return err;
 }
 
 static int bcm43xx_init_board(struct bcm43xx_private *bcm)
 {
-	int i, err;
-	int connect_phy;
+	int err;
 
-	might_sleep();
+	mutex_lock(&(bcm)->mutex);
 
-	bcm43xx_lock_noirq(bcm);
-	bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
-
+	tasklet_enable(&bcm->isr_tasklet);
 	err = bcm43xx_pctl_set_crystal(bcm, 1);
 	if (err)
-		goto out;
+		goto err_tasklet;
 	err = bcm43xx_pctl_init(bcm);
 	if (err)
 		goto err_crystal_off;
-	err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST);
+	err = bcm43xx_select_wireless_core(bcm, -1);
 	if (err)
 		goto err_crystal_off;
 
-	tasklet_enable(&bcm->isr_tasklet);
-	for (i = 0; i < bcm->nr_80211_available; i++) {
-		err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
-		assert(err != -ENODEV);
-		if (err)
-			goto err_80211_unwind;
-
-		/* Enable the selected wireless core.
-		 * Connect PHY only on the first core.
-		 */
-		if (!bcm43xx_core_enabled(bcm)) {
-			if (bcm->nr_80211_available == 1) {
-				connect_phy = bcm43xx_current_phy(bcm)->connected;
-			} else {
-				if (i == 0)
-					connect_phy = 1;
-				else
-					connect_phy = 0;
-			}
-			bcm43xx_wireless_core_reset(bcm, connect_phy);
-		}
-
-		if (i != 0)
-			bcm43xx_wireless_core_mark_inactive(bcm, &bcm->core_80211[0]);
-
-		err = bcm43xx_wireless_core_init(bcm);
-		if (err)
-			goto err_80211_unwind;
-
-		if (i != 0) {
-			bcm43xx_mac_suspend(bcm);
-			bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
-			bcm43xx_radio_turn_off(bcm);
-		}
-	}
-	bcm->active_80211_core = &bcm->core_80211[0];
-	if (bcm->nr_80211_available >= 2) {
-		bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
-		bcm43xx_mac_enable(bcm);
-	}
-	err = bcm43xx_rng_init(bcm);
-	if (err)
-		goto err_80211_unwind;
-	bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
-	bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr));
-	dprintk(KERN_INFO PFX "80211 cores initialized\n");
-	bcm43xx_security_init(bcm);
-	bcm43xx_softmac_init(bcm);
-
-	bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC);
-
-	if (bcm43xx_current_radio(bcm)->initial_channel != 0xFF) {
-		bcm43xx_mac_suspend(bcm);
-		bcm43xx_radio_selectchannel(bcm, bcm43xx_current_radio(bcm)->initial_channel, 0);
-		bcm43xx_mac_enable(bcm);
-	}
-
-	/* Initialization of the board is done. Flag it as such. */
-	bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
-
 	bcm43xx_periodic_tasks_setup(bcm);
-	bcm43xx_sysfs_register(bcm);
-	//FIXME: check for bcm43xx_sysfs_register failure. This function is a bit messy regarding unwinding, though...
+	err = bcm43xx_sysfs_register(bcm);
+	if (err)
+		goto err_wlshutdown;
 
 	/*FIXME: This should be handled by softmac instead. */
 	schedule_work(&bcm->softmac->associnfo.work);
 
-	assert(err == 0);
 out:
-	bcm43xx_unlock_noirq(bcm);
+	mutex_unlock(&(bcm)->mutex);
 
 	return err;
 
-err_80211_unwind:
-	tasklet_disable(&bcm->isr_tasklet);
-	/* unwind all 80211 initialization */
-	for (i = 0; i < bcm->nr_80211_available; i++) {
-		if (!bcm->core_80211[i].initialized)
-			continue;
-		bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
-		bcm43xx_wireless_core_cleanup(bcm);
-	}
+err_wlshutdown:
+	bcm43xx_shutdown_all_wireless_cores(bcm);
 err_crystal_off:
 	bcm43xx_pctl_set_crystal(bcm, 0);
+err_tasklet:
+	tasklet_disable(&bcm->isr_tasklet);
 	goto out;
 }
 
@@ -3647,7 +3786,8 @@
 	struct bcm43xx_radioinfo *radio;
 	unsigned long flags;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
 		bcm43xx_mac_suspend(bcm);
 		bcm43xx_radio_selectchannel(bcm, channel, 0);
@@ -3656,7 +3796,8 @@
 		radio = bcm43xx_current_radio(bcm);
 		radio->initial_channel = channel;
 	}
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 }
 
 /* set_security() callback in struct ieee80211_device */
@@ -3670,7 +3811,8 @@
 	
 	dprintk(KERN_INFO PFX "set security called");
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 
 	for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
 		if (sec->flags & (1<<keyidx)) {
@@ -3739,7 +3881,8 @@
 		} else
 				bcm43xx_clear_keys(bcm);
 	}
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 }
 
 /* hard_start_xmit() callback in struct ieee80211_device */
@@ -3751,10 +3894,10 @@
 	int err = -ENODEV;
 	unsigned long flags;
 
-	bcm43xx_lock_irqonly(bcm, flags);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED))
 		err = bcm43xx_tx(bcm, txb);
-	bcm43xx_unlock_irqonly(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
 
 	return err;
 }
@@ -3769,9 +3912,9 @@
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 	unsigned long flags;
 
-	bcm43xx_lock_irqonly(bcm, flags);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	bcm43xx_controller_restart(bcm, "TX timeout");
-	bcm43xx_unlock_irqonly(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -3781,7 +3924,8 @@
 	unsigned long flags;
 
 	local_irq_save(flags);
-	bcm43xx_interrupt_handler(bcm->irq, bcm, NULL);
+	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
+		bcm43xx_interrupt_handler(bcm->irq, bcm, NULL);
 	local_irq_restore(flags);
 }
 #endif /* CONFIG_NET_POLL_CONTROLLER */
@@ -3799,7 +3943,7 @@
 	int err;
 
 	ieee80211softmac_stop(net_dev);
-	err = bcm43xx_disable_interrupts_sync(bcm, NULL);
+	err = bcm43xx_disable_interrupts_sync(bcm);
 	assert(!err);
 	bcm43xx_free_board(bcm);
 
@@ -3818,10 +3962,12 @@
 	bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan;
 
 	bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
+	bcm->mac_suspended = 1;
 	bcm->pci_dev = pci_dev;
 	bcm->net_dev = net_dev;
 	bcm->bad_frames_preempt = modparam_bad_frames_preempt;
 	spin_lock_init(&bcm->irq_lock);
+	spin_lock_init(&bcm->leds_lock);
 	mutex_init(&bcm->mutex);
 	tasklet_init(&bcm->isr_tasklet,
 		     (void (*)(unsigned long))bcm43xx_interrupt_tasklet,
@@ -3940,7 +4086,6 @@
 	bcm43xx_debugfs_remove_device(bcm);
 	unregister_netdev(net_dev);
 	bcm43xx_detach_board(bcm);
-	assert(bcm->ucode == NULL);
 	free_ieee80211softmac(net_dev);
 }
 
@@ -3950,47 +4095,25 @@
 static void bcm43xx_chip_reset(void *_bcm)
 {
 	struct bcm43xx_private *bcm = _bcm;
-	struct net_device *net_dev = bcm->net_dev;
-	struct pci_dev *pci_dev = bcm->pci_dev;
+	struct bcm43xx_phyinfo *phy;
 	int err;
-	int was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
 
-	netif_stop_queue(bcm->net_dev);
-	tasklet_disable(&bcm->isr_tasklet);
+	mutex_lock(&(bcm)->mutex);
+	phy = bcm43xx_current_phy(bcm);
+	err = bcm43xx_select_wireless_core(bcm, phy->type);
+	mutex_unlock(&(bcm)->mutex);
 
-	bcm->firmware_norelease = 1;
-	if (was_initialized)
-		bcm43xx_free_board(bcm);
-	bcm->firmware_norelease = 0;
-	bcm43xx_detach_board(bcm);
-	err = bcm43xx_init_private(bcm, net_dev, pci_dev);
-	if (err)
-		goto failure;
-	err = bcm43xx_attach_board(bcm);
-	if (err)
-		goto failure;
-	if (was_initialized) {
-		err = bcm43xx_init_board(bcm);
-		if (err)
-			goto failure;
-	}
-	netif_wake_queue(bcm->net_dev);
-	printk(KERN_INFO PFX "Controller restarted\n");
-
-	return;
-failure:
-	printk(KERN_ERR PFX "Controller restart failed\n");
+	printk(KERN_ERR PFX "Controller restart%s\n",
+	       (err == 0) ? "ed" : " failed");
 }
 
 /* Hard-reset the chip.
  * This can be called from interrupt or process context.
- * Make sure to _not_ re-enable device interrupts after this has been called.
-*/
+ */
 void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason)
 {
+	assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
 	bcm43xx_set_status(bcm, BCM43xx_STAT_RESTARTING);
-	bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
-	bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
 	printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason);
 	INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm);
 	schedule_work(&bcm->restart_work);
@@ -4002,21 +4125,16 @@
 {
 	struct net_device *net_dev = pci_get_drvdata(pdev);
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-	unsigned long flags;
-	int try_to_shutdown = 0, err;
+	int err;
 
 	dprintk(KERN_INFO PFX "Suspending...\n");
 
-	bcm43xx_lock_irqsafe(bcm, flags);
-	bcm->was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
-	if (bcm->was_initialized)
-		try_to_shutdown = 1;
-	bcm43xx_unlock_irqsafe(bcm, flags);
-
 	netif_device_detach(net_dev);
-	if (try_to_shutdown) {
+	bcm->was_initialized = 0;
+	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
+		bcm->was_initialized = 1;
 		ieee80211softmac_stop(net_dev);
-		err = bcm43xx_disable_interrupts_sync(bcm, &bcm->irq_savedstate);
+		err = bcm43xx_disable_interrupts_sync(bcm);
 		if (unlikely(err)) {
 			dprintk(KERN_ERR PFX "Suspend failed.\n");
 			return -EAGAIN;
@@ -4049,17 +4167,14 @@
 	pci_restore_state(pdev);
 
 	bcm43xx_chipset_attach(bcm);
-	if (bcm->was_initialized) {
-		bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
+	if (bcm->was_initialized)
 		err = bcm43xx_init_board(bcm);
-	}
 	if (err) {
 		printk(KERN_ERR PFX "Resume failed!\n");
 		return err;
 	}
-
 	netif_device_attach(net_dev);
-	
+
 	dprintk(KERN_INFO PFX "Device resumed.\n");
 
 	return 0;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
index 1164936..505c86e 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
@@ -133,6 +133,9 @@
 
 int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core);
 
+int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm,
+				 int phytype);
+
 void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy);
 
 void bcm43xx_mac_suspend(struct bcm43xx_private *bcm);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
index f8200de..eafd0f6 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
@@ -81,6 +81,16 @@
 static void bcm43xx_phy_initg(struct bcm43xx_private *bcm);
 
 
+static inline
+void bcm43xx_voluntary_preempt(void)
+{
+	assert(!in_atomic() && !in_irq() &&
+	       !in_interrupt() && !irqs_disabled());
+#ifndef CONFIG_PREEMPT
+	cond_resched();
+#endif /* CONFIG_PREEMPT */
+}
+
 void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm)
 {
 	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
@@ -133,22 +143,14 @@
 void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm)
 {
 	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
-	unsigned long flags;
 
 	bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* Dummy read. */
 	if (phy->calibrated)
 		return;
 	if (phy->type == BCM43xx_PHYTYPE_G && phy->rev == 1) {
-		/* We do not want to be preempted while calibrating
-		 * the hardware.
-		 */
-		local_irq_save(flags);
-
 		bcm43xx_wireless_core_reset(bcm, 0);
 		bcm43xx_phy_initg(bcm);
 		bcm43xx_wireless_core_reset(bcm, 1);
-
-		local_irq_restore(flags);
 	}
 	phy->calibrated = 1;
 }
@@ -1299,7 +1301,9 @@
 {
 	int i;
 	u16 ret = 0;
+	unsigned long flags;
 
+	local_irq_save(flags);
 	for (i = 0; i < 10; i++){
 		bcm43xx_phy_write(bcm, 0x0015, 0xAFA0);
 		udelay(1);
@@ -1309,6 +1313,8 @@
 		udelay(40);
 		ret += bcm43xx_phy_read(bcm, 0x002C);
 	}
+	local_irq_restore(flags);
+	bcm43xx_voluntary_preempt();
 
 	return ret;
 }
@@ -1435,6 +1441,7 @@
 	}
 	ret = bcm43xx_phy_read(bcm, 0x002D);
 	local_irq_restore(flags);
+	bcm43xx_voluntary_preempt();
 
 	return ret;
 }
@@ -1760,6 +1767,7 @@
 			bcm43xx_radio_write16(bcm, 0x43, i);
 			bcm43xx_radio_write16(bcm, 0x52, radio->txctl2);
 			udelay(10);
+			bcm43xx_voluntary_preempt();
 
 			bcm43xx_phy_set_baseband_attenuation(bcm, j * 2);
 
@@ -1803,6 +1811,7 @@
 					      radio->txctl2
 					      | (3/*txctl1*/ << 4));//FIXME: shouldn't txctl1 be zero here and 3 in the loop above?
 			udelay(10);
+			bcm43xx_voluntary_preempt();
 
 			bcm43xx_phy_set_baseband_attenuation(bcm, j * 2);
 
@@ -1824,6 +1833,7 @@
 		bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA2);
 		udelay(2);
 		bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA3);
+		bcm43xx_voluntary_preempt();
 	} else
 		bcm43xx_phy_write(bcm, 0x0015, r27 | 0xEFA0);
 	bcm43xx_phy_lo_adjust(bcm, is_initializing);
@@ -2188,12 +2198,6 @@
 {
 	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
 	int err = -ENODEV;
-	unsigned long flags;
-
-	/* We do not want to be preempted while calibrating
-	 * the hardware.
-	 */
-	local_irq_save(flags);
 
 	switch (phy->type) {
 	case BCM43xx_PHYTYPE_A:
@@ -2227,7 +2231,6 @@
 		err = 0;
 		break;
 	}
-	local_irq_restore(flags);
 	if (err)
 		printk(KERN_WARNING PFX "Unknown PHYTYPE found!\n");
 
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
index 574085c..c60c174 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
@@ -262,7 +262,7 @@
 	int err;
 	u16 txctl;
 
-	bcm43xx_lock_irqonly(bcm, flags);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 
 	if (queue->tx_frozen)
 		goto out_unlock;
@@ -300,7 +300,7 @@
 		continue;
 	}
 out_unlock:
-	bcm43xx_unlock_irqonly(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
 }
 
 static void setup_txqueues(struct bcm43xx_pioqueue *queue)
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
index 6a23bdc..ece3351 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
@@ -120,12 +120,14 @@
 			GFP_KERNEL);
 	if (!sprom)
 		return -ENOMEM;
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	err = bcm43xx_sprom_read(bcm, sprom);
 	if (!err)
 		err = sprom2hex(sprom, buf, PAGE_SIZE);
 	mmiowb();
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 	kfree(sprom);
 
 	return err;
@@ -150,10 +152,14 @@
 	err = hex2sprom(sprom, buf, count);
 	if (err)
 		goto out_kfree;
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
+	spin_lock(&bcm->leds_lock);
 	err = bcm43xx_sprom_write(bcm, sprom);
 	mmiowb();
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock(&bcm->leds_lock);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 out_kfree:
 	kfree(sprom);
 
@@ -176,7 +182,7 @@
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
 
-	bcm43xx_lock_noirq(bcm);
+	mutex_lock(&bcm->mutex);
 
 	switch (bcm43xx_current_radio(bcm)->interfmode) {
 	case BCM43xx_RADIO_INTERFMODE_NONE:
@@ -193,7 +199,7 @@
 	}
 	err = 0;
 
-	bcm43xx_unlock_noirq(bcm);
+	mutex_unlock(&bcm->mutex);
 
 	return err ? err : count;
 
@@ -229,7 +235,8 @@
 		return -EINVAL;
 	}
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 
 	err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
 	if (err) {
@@ -237,7 +244,8 @@
 				    "supported by device\n");
 	}
 	mmiowb();
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return err ? err : count;
 }
@@ -257,7 +265,7 @@
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
 
-	bcm43xx_lock_noirq(bcm);
+	mutex_lock(&bcm->mutex);
 
 	if (bcm->short_preamble)
 		count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n");
@@ -265,7 +273,7 @@
 		count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
 
 	err = 0;
-	bcm43xx_unlock_noirq(bcm);
+	mutex_unlock(&bcm->mutex);
 
 	return err ? err : count;
 }
@@ -285,12 +293,14 @@
 	value = get_boolean(buf, count);
 	if (value < 0)
 		return value;
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 
 	bcm->short_preamble = !!value;
 
 	err = 0;
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return err ? err : count;
 }
@@ -299,6 +309,70 @@
 		   bcm43xx_attr_preamble_show,
 		   bcm43xx_attr_preamble_store);
 
+static ssize_t bcm43xx_attr_phymode_store(struct device *dev,
+					  struct device_attribute *attr,
+					  const char *buf, size_t count)
+{
+	struct bcm43xx_private *bcm = dev_to_bcm(dev);
+	int phytype;
+	int err = -EINVAL;
+
+	if (count < 1)
+		goto out;
+	switch (buf[0]) {
+	case 'a':  case 'A':
+		phytype = BCM43xx_PHYTYPE_A;
+		break;
+	case 'b':  case 'B':
+		phytype = BCM43xx_PHYTYPE_B;
+		break;
+	case 'g':  case 'G':
+		phytype = BCM43xx_PHYTYPE_G;
+		break;
+	default:
+		goto out;
+	}
+
+	mutex_lock(&(bcm)->mutex);
+	err = bcm43xx_select_wireless_core(bcm, phytype);
+	mutex_unlock(&(bcm)->mutex);
+	if (err == -ESRCH)
+		err = -ENODEV;
+
+out:
+	return err ? err : count;
+}
+
+static ssize_t bcm43xx_attr_phymode_show(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf)
+{
+	struct bcm43xx_private *bcm = dev_to_bcm(dev);
+	ssize_t count = 0;
+
+	mutex_lock(&(bcm)->mutex);
+	switch (bcm43xx_current_phy(bcm)->type) {
+	case BCM43xx_PHYTYPE_A:
+		snprintf(buf, PAGE_SIZE, "A");
+		break;
+	case BCM43xx_PHYTYPE_B:
+		snprintf(buf, PAGE_SIZE, "B");
+		break;
+	case BCM43xx_PHYTYPE_G:
+		snprintf(buf, PAGE_SIZE, "G");
+		break;
+	default:
+		assert(0);
+	}
+	mutex_unlock(&(bcm)->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(phymode, 0644,
+		   bcm43xx_attr_phymode_show,
+		   bcm43xx_attr_phymode_store);
+
 int bcm43xx_sysfs_register(struct bcm43xx_private *bcm)
 {
 	struct device *dev = &bcm->pci_dev->dev;
@@ -315,9 +389,14 @@
 	err = device_create_file(dev, &dev_attr_shortpreamble);
 	if (err)
 		goto err_remove_interfmode;
+	err = device_create_file(dev, &dev_attr_phymode);
+	if (err)
+		goto err_remove_shortpreamble;
 
 out:
 	return err;
+err_remove_shortpreamble:
+	device_remove_file(dev, &dev_attr_shortpreamble);
 err_remove_interfmode:
 	device_remove_file(dev, &dev_attr_interference);
 err_remove_sprom:
@@ -329,6 +408,7 @@
 {
 	struct device *dev = &bcm->pci_dev->dev;
 
+	device_remove_file(dev, &dev_attr_phymode);
 	device_remove_file(dev, &dev_attr_shortpreamble);
 	device_remove_file(dev, &dev_attr_interference);
 	device_remove_file(dev, &dev_attr_sprom);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
index 5c36e29..1d3a3aa 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -47,6 +47,8 @@
 #define BCM43xx_WX_VERSION	18
 
 #define MAX_WX_STRING		80
+/* FIXME: the next line is a guess as to what the maximum RSSI value might be */
+#define RX_RSSI_MAX		60
 
 
 static int bcm43xx_wx_get_name(struct net_device *net_dev,
@@ -56,12 +58,11 @@
 {
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 	int i;
-	unsigned long flags;
 	struct bcm43xx_phyinfo *phy;
 	char suffix[7] = { 0 };
 	int have_a = 0, have_b = 0, have_g = 0;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
 	for (i = 0; i < bcm->nr_80211_available; i++) {
 		phy = &(bcm->core_80211_ext[i].phy);
 		switch (phy->type) {
@@ -77,7 +78,7 @@
 			assert(0);
 		}
 	}
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	mutex_unlock(&bcm->mutex);
 
 	i = 0;
 	if (have_a) {
@@ -111,7 +112,9 @@
 	int freq;
 	int err = -EINVAL;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
+
 	if ((data->freq.m >= 0) && (data->freq.m <= 1000)) {
 		channel = data->freq.m;
 		freq = bcm43xx_channel_to_freq(bcm, channel);
@@ -131,7 +134,8 @@
 		err = 0;
 	}
 out_unlock:
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return err;
 }
@@ -143,11 +147,10 @@
 {
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 	struct bcm43xx_radioinfo *radio;
-	unsigned long flags;
 	int err = -ENODEV;
 	u16 channel;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
 	radio = bcm43xx_current_radio(bcm);
 	channel = radio->channel;
 	if (channel == 0xFF) {
@@ -162,7 +165,7 @@
 
 	err = 0;
 out_unlock:
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return err;
 }
@@ -180,13 +183,15 @@
 	if (mode == IW_MODE_AUTO)
 		mode = BCM43xx_INITIAL_IWMODE;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
 		if (bcm->ieee->iw_mode != mode)
 			bcm43xx_set_iwmode(bcm, mode);
 	} else
 		bcm->ieee->iw_mode = mode;
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return 0;
 }
@@ -197,11 +202,10 @@
 			       char *extra)
 {
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-	unsigned long flags;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
 	data->mode = bcm->ieee->iw_mode;
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return 0;
 }
@@ -214,7 +218,6 @@
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 	struct iw_range *range = (struct iw_range *)extra;
 	const struct ieee80211_geo *geo;
-	unsigned long flags;
 	int i, j;
 	struct bcm43xx_phyinfo *phy;
 
@@ -226,15 +229,14 @@
 	range->throughput = 27 * 1000 * 1000;
 
 	range->max_qual.qual = 100;
-	/* TODO: Real max RSSI */
-	range->max_qual.level = 3;
-	range->max_qual.noise = 100;
-	range->max_qual.updated = 7;
+	range->max_qual.level = 152; /* set floor at -104 dBm (152 - 256) */
+	range->max_qual.noise = 152;
+	range->max_qual.updated = IW_QUAL_ALL_UPDATED;
 
-	range->avg_qual.qual = 70;
-	range->avg_qual.level = 2;
-	range->avg_qual.noise = 40;
-	range->avg_qual.updated = 7;
+	range->avg_qual.qual = 50;
+	range->avg_qual.level = 0;
+	range->avg_qual.noise = 0;
+	range->avg_qual.updated = IW_QUAL_ALL_UPDATED;
 
 	range->min_rts = BCM43xx_MIN_RTS_THRESHOLD;
 	range->max_rts = BCM43xx_MAX_RTS_THRESHOLD;
@@ -254,7 +256,7 @@
 			  IW_ENC_CAPA_CIPHER_TKIP |
 			  IW_ENC_CAPA_CIPHER_CCMP;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
 	phy = bcm43xx_current_phy(bcm);
 
 	range->num_bitrates = 0;
@@ -301,7 +303,7 @@
 	}
 	range->num_frequency = j;
 
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return 0;
 }
@@ -314,11 +316,11 @@
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 	size_t len;
 
-	bcm43xx_lock_noirq(bcm);
+	mutex_lock(&bcm->mutex);
 	len =  min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE);
 	memcpy(bcm->nick, extra, len);
 	bcm->nick[len] = '\0';
-	bcm43xx_unlock_noirq(bcm);
+	mutex_unlock(&bcm->mutex);
 
 	return 0;
 }
@@ -331,12 +333,12 @@
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 	size_t len;
 
-	bcm43xx_lock_noirq(bcm);
+	mutex_lock(&bcm->mutex);
 	len = strlen(bcm->nick) + 1;
 	memcpy(extra, bcm->nick, len);
 	data->data.length = (__u16)len;
 	data->data.flags = 1;
-	bcm43xx_unlock_noirq(bcm);
+	mutex_unlock(&bcm->mutex);
 
 	return 0;
 }
@@ -350,7 +352,8 @@
 	unsigned long flags;
 	int err = -EINVAL;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	if (data->rts.disabled) {
 		bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD;
 		err = 0;
@@ -361,7 +364,8 @@
 			err = 0;
 		}
 	}
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return err;
 }
@@ -372,13 +376,12 @@
 			      char *extra)
 {
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-	unsigned long flags;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
 	data->rts.value = bcm->rts_threshold;
 	data->rts.fixed = 0;
 	data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD);
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return 0;
 }
@@ -392,7 +395,8 @@
 	unsigned long flags;
 	int err = -EINVAL;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	if (data->frag.disabled) {
 		bcm->ieee->fts = MAX_FRAG_THRESHOLD;
 		err = 0;
@@ -403,7 +407,8 @@
 			err = 0;
 		}
 	}
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return err;
 }
@@ -414,13 +419,12 @@
 			       char *extra)
 {
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-	unsigned long flags;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
 	data->frag.value = bcm->ieee->fts;
 	data->frag.fixed = 0;
 	data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD);
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return 0;
 }
@@ -442,7 +446,8 @@
 		return -EOPNOTSUPP;
 	}
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
 		goto out_unlock;
 	radio = bcm43xx_current_radio(bcm);
@@ -466,7 +471,8 @@
 	err = 0;
 
 out_unlock:
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return err;
 }
@@ -478,10 +484,9 @@
 {
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 	struct bcm43xx_radioinfo *radio;
-	unsigned long flags;
 	int err = -ENODEV;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
 	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
 		goto out_unlock;
 	radio = bcm43xx_current_radio(bcm);
@@ -493,7 +498,7 @@
 
 	err = 0;
 out_unlock:
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return err;
 }
@@ -580,7 +585,8 @@
 		return -EINVAL;
 	}
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
 		err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
 		if (err) {
@@ -595,7 +601,8 @@
 		} else
 			bcm43xx_current_radio(bcm)->interfmode = mode;
 	}
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return err;
 }
@@ -606,12 +613,11 @@
 				     char *extra)
 {
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-	unsigned long flags;
 	int mode;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
 	mode = bcm43xx_current_radio(bcm)->interfmode;
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	mutex_unlock(&bcm->mutex);
 
 	switch (mode) {
 	case BCM43xx_RADIO_INTERFMODE_NONE:
@@ -641,9 +647,11 @@
 	int on;
 
 	on = *((int *)extra);
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	bcm->short_preamble = !!on;
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return 0;
 }
@@ -654,12 +662,11 @@
 					char *extra)
 {
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-	unsigned long flags;
 	int on;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
 	on = bcm->short_preamble;
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	mutex_unlock(&bcm->mutex);
 
 	if (on)
 		strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING);
@@ -681,11 +688,13 @@
 	
 	on = *((int *)extra);
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	bcm->ieee->host_encrypt = !!on;
 	bcm->ieee->host_decrypt = !!on;
 	bcm->ieee->host_build_iv = !on;
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return 0;
 }
@@ -696,12 +705,11 @@
 				       char *extra)
 {
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-	unsigned long flags;
 	int on;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
 	on = bcm->ieee->host_encrypt;
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	mutex_unlock(&bcm->mutex);
 
 	if (on)
 		strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING);
@@ -764,11 +772,13 @@
 	if (!sprom)
 		goto out;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	err = -ENODEV;
 	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
 		err = bcm43xx_sprom_read(bcm, sprom);
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 	if (!err)
 		data->data.length = sprom2hex(sprom, extra);
 	kfree(sprom);
@@ -809,11 +819,15 @@
 	if (err)
 		goto out_kfree;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
+	spin_lock(&bcm->leds_lock);
 	err = -ENODEV;
 	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
 		err = bcm43xx_sprom_write(bcm, sprom);
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock(&bcm->leds_lock);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 out_kfree:
 	kfree(sprom);
 out:
@@ -827,6 +841,10 @@
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 	struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
 	struct iw_statistics *wstats;
+	struct ieee80211_network *network = NULL;
+	static int tmp_level = 0;
+	static int tmp_qual = 0;
+	unsigned long flags;
 
 	wstats = &bcm->stats.wstats;
 	if (!mac->associated) {
@@ -844,16 +862,28 @@
 		wstats->qual.level = 0;
 		wstats->qual.noise = 0;
 		wstats->qual.updated = 7;
-		wstats->qual.updated |= IW_QUAL_NOISE_INVALID |
-			IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
+		wstats->qual.updated |= IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
 		return wstats;
 	}
 	/* fill in the real statistics when iface associated */
-	wstats->qual.qual = 100;     // TODO: get the real signal quality
-	wstats->qual.level = 3 - bcm->stats.link_quality;
+	spin_lock_irqsave(&mac->ieee->lock, flags);
+	list_for_each_entry(network, &mac->ieee->network_list, list) {
+		if (!memcmp(mac->associnfo.bssid, network->bssid, ETH_ALEN)) {
+			if (!tmp_level)	{	/* get initial values */
+				tmp_level = network->stats.signal;
+				tmp_qual = network->stats.rssi;
+			} else {		/* smooth results */
+				tmp_level = (15 * tmp_level + network->stats.signal)/16;
+				tmp_qual = (15 * tmp_qual + network->stats.rssi)/16;
+			}
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&mac->ieee->lock, flags);
+	wstats->qual.level = tmp_level;
+	wstats->qual.qual = 100 * tmp_qual / RX_RSSI_MAX;
 	wstats->qual.noise = bcm->stats.noise;
-	wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
-			IW_QUAL_NOISE_UPDATED;
+	wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
 	wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable;
 	wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded;
 	wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
index 6dbd855..c0efbfe 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
@@ -492,16 +492,15 @@
 
 	memset(&stats, 0, sizeof(stats));
 	stats.mac_time = le16_to_cpu(rxhdr->mactime);
-	stats.rssi = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm,
+	stats.rssi = rxhdr->rssi;
+	stats.signal = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm,
 					      !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ),
 					      !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ));
-	stats.signal = rxhdr->signal_quality;	//FIXME
 //TODO	stats.noise = 
 	if (is_ofdm)
 		stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp);
 	else
 		stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp);
-//printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate);
 	stats.received_channel = radio->channel;
 //TODO	stats.control = 
 	stats.mask = IEEE80211_STATMASK_SIGNAL |
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index b3300ff..758459e 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -2667,7 +2667,7 @@
 
 	IPW_DEBUG_FW(">> :\n");
 
-	//set the Stop and Abort bit
+	/* set the Stop and Abort bit */
 	control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_STOP_AND_ABORT;
 	ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control);
 	priv->sram_desc.last_cb_index = 0;
@@ -3002,8 +3002,6 @@
 	if (rc < 0)
 		return rc;
 
-//      spin_lock_irqsave(&priv->lock, flags);
-
 	for (addr = IPW_SHARED_LOWER_BOUND;
 	     addr < IPW_REGISTER_DOMAIN1_END; addr += 4) {
 		ipw_write32(priv, addr, 0);
@@ -3097,8 +3095,6 @@
 	   firmware have problem getting alive resp. */
 	ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0);
 
-//      spin_unlock_irqrestore(&priv->lock, flags);
-
 	return rc;
 }
 
@@ -6387,13 +6383,6 @@
 	    (wrqu->data.length && extra == NULL))
 		return -EINVAL;
 
-	//mutex_lock(&priv->mutex);
-
-	//if (!ieee->wpa_enabled) {
-	//      err = -EOPNOTSUPP;
-	//      goto out;
-	//}
-
 	if (wrqu->data.length) {
 		buf = kmalloc(wrqu->data.length, GFP_KERNEL);
 		if (buf == NULL) {
@@ -6413,7 +6402,6 @@
 
 	ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len);
       out:
-	//mutex_unlock(&priv->mutex);
 	return err;
 }
 
@@ -6426,13 +6414,6 @@
 	struct ieee80211_device *ieee = priv->ieee;
 	int err = 0;
 
-	//mutex_lock(&priv->mutex);
-
-	//if (!ieee->wpa_enabled) {
-	//      err = -EOPNOTSUPP;
-	//      goto out;
-	//}
-
 	if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) {
 		wrqu->data.length = 0;
 		goto out;
@@ -6447,7 +6428,6 @@
 	memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len);
 
       out:
-	//mutex_unlock(&priv->mutex);
 	return err;
 }
 
@@ -6558,7 +6538,6 @@
 		ieee->ieee802_1x = param->value;
 		break;
 
-		//case IW_AUTH_ROAMING_CONTROL:
 	case IW_AUTH_PRIVACY_INVOKED:
 		ieee->privacy_invoked = param->value;
 		break;
@@ -6680,7 +6659,7 @@
 
 	switch (mlme->cmd) {
 	case IW_MLME_DEAUTH:
-		// silently ignore
+		/* silently ignore */
 		break;
 
 	case IW_MLME_DISASSOC:
@@ -9766,7 +9745,7 @@
 	return 0;
 }
 
-#endif				// CONFIG_IPW2200_MONITOR
+#endif				/* CONFIG_IPW2200_MONITOR */
 
 static int ipw_wx_reset(struct net_device *dev,
 			struct iw_request_info *info,
@@ -10009,7 +9988,7 @@
 	sys_config->dot11g_auto_detection = 0;
 	sys_config->enable_cts_to_self = 0;
 	sys_config->bt_coexist_collision_thr = 0;
-	sys_config->pass_noise_stats_to_host = 1;	//1 -- fix for 256
+	sys_config->pass_noise_stats_to_host = 1;	/* 1 -- fix for 256 */
 	sys_config->silence_threshold = 0x1e;
 }
 
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 989599a..0c30fe7 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -35,10 +35,14 @@
 
 #include <net/iw_handler.h>	/* New driver API */
 
+#define KEY_SIZE_WEP104 13	/* 104/128-bit WEP keys */
+#define KEY_SIZE_WEP40  5	/* 40/64-bit WEP keys */
+/* KEY_SIZE_TKIP should match isl_oid.h, struct obj_key.key[] size */
+#define KEY_SIZE_TKIP   32	/* TKIP keys */
 
-static void prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
+static void prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid,
 				u8 *wpa_ie, size_t wpa_ie_len);
-static size_t prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie);
+static size_t prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie);
 static int prism54_set_wpa(struct net_device *, struct iw_request_info *,
 				__u32 *, char *);
 
@@ -468,6 +472,9 @@
 	range->event_capa[1] = IW_EVENT_CAPA_K_1;
 	range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVCUSTOM);
 
+	range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
+		IW_ENC_CAPA_CIPHER_TKIP;
+
 	if (islpci_get_state(priv) < PRV_STATE_INIT)
 		return 0;
 
@@ -567,6 +574,8 @@
 	struct iw_event iwe;	/* Temporary buffer */
 	short cap;
 	islpci_private *priv = netdev_priv(ndev);
+	u8 wpa_ie[MAX_WPA_IE_LEN];
+	size_t wpa_ie_len;
 
 	/* The first entry must be the MAC address */
 	memcpy(iwe.u.ap_addr.sa_data, bss->address, 6);
@@ -627,27 +636,13 @@
 	current_ev =
 	    iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
 
-	if (priv->wpa) {
-		u8 wpa_ie[MAX_WPA_IE_LEN];
-		char *buf, *p;
-		size_t wpa_ie_len;
-		int i;
-
-		wpa_ie_len = prism54_wpa_ie_get(priv, bss->address, wpa_ie);
-		if (wpa_ie_len > 0 &&
-		    (buf = kmalloc(wpa_ie_len * 2 + 10, GFP_ATOMIC))) {
-			p = buf;
-			p += sprintf(p, "wpa_ie=");
-			for (i = 0; i < wpa_ie_len; i++) {
-				p += sprintf(p, "%02x", wpa_ie[i]);
-			}
-			memset(&iwe, 0, sizeof (iwe));
-			iwe.cmd = IWEVCUSTOM;
-			iwe.u.data.length = strlen(buf);
-			current_ev = iwe_stream_add_point(current_ev, end_buf,
-							  &iwe, buf);
-			kfree(buf);
-		}
+	/* Add WPA/RSN Information Element, if any */
+	wpa_ie_len = prism54_wpa_bss_ie_get(priv, bss->address, wpa_ie);
+	if (wpa_ie_len > 0) {
+		iwe.cmd = IWEVGENIE;
+		iwe.u.data.length = min(wpa_ie_len, (size_t)MAX_WPA_IE_LEN);
+		current_ev = iwe_stream_add_point(current_ev, end_buf,
+				&iwe, wpa_ie);
 	}
 	return current_ev;
 }
@@ -1051,12 +1046,24 @@
 		current_index = r.u;
 		/* Verify that the key is not marked as invalid */
 		if (!(dwrq->flags & IW_ENCODE_NOKEY)) {
-			key.length = dwrq->length > sizeof (key.key) ?
-			    sizeof (key.key) : dwrq->length;
-			memcpy(key.key, extra, key.length);
-			if (key.length == 32)
-				/* we want WPA-PSK */
+			if (dwrq->length > KEY_SIZE_TKIP) {
+				/* User-provided key data too big */
+				return -EINVAL;
+			}
+			if (dwrq->length > KEY_SIZE_WEP104) {
+				/* WPA-PSK TKIP */
 				key.type = DOT11_PRIV_TKIP;
+				key.length = KEY_SIZE_TKIP;
+			} else if (dwrq->length > KEY_SIZE_WEP40) {
+				/* WEP 104/128 */
+				key.length = KEY_SIZE_WEP104;
+			} else {
+				/* WEP 40/64 */
+				key.length = KEY_SIZE_WEP40;
+			}
+			memset(key.key, 0, sizeof (key.key));
+			memcpy(key.key, extra, dwrq->length);
+
 			if ((index < 0) || (index > 3))
 				/* no index provided use the current one */
 				index = current_index;
@@ -1210,6 +1217,489 @@
 	}
 }
 
+static int prism54_set_genie(struct net_device *ndev,
+			     struct iw_request_info *info,
+			     struct iw_point *data, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	int alen, ret = 0;
+	struct obj_attachment *attach;
+
+	if (data->length > MAX_WPA_IE_LEN ||
+	    (data->length && extra == NULL))
+		return -EINVAL;
+
+	memcpy(priv->wpa_ie, extra, data->length);
+	priv->wpa_ie_len = data->length;
+
+	alen = sizeof(*attach) + priv->wpa_ie_len;
+	attach = kzalloc(alen, GFP_KERNEL);
+	if (attach == NULL)
+		return -ENOMEM;
+
+#define WLAN_FC_TYPE_MGMT 0
+#define WLAN_FC_STYPE_ASSOC_REQ 0
+#define WLAN_FC_STYPE_REASSOC_REQ 2
+
+	/* Note: endianness is covered by mgt_set_varlen */
+	attach->type = (WLAN_FC_TYPE_MGMT << 2) |
+               (WLAN_FC_STYPE_ASSOC_REQ << 4);
+	attach->id = -1;
+	attach->size = priv->wpa_ie_len;
+	memcpy(attach->data, extra, priv->wpa_ie_len);
+
+	ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach,
+		priv->wpa_ie_len);
+	if (ret == 0) {
+		attach->type = (WLAN_FC_TYPE_MGMT << 2) |
+			(WLAN_FC_STYPE_REASSOC_REQ << 4);
+
+		ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach,
+			priv->wpa_ie_len);
+		if (ret == 0)
+			printk(KERN_DEBUG "%s: WPA IE Attachment was set\n",
+				ndev->name);
+	}
+
+	kfree(attach);
+	return ret;
+}
+
+
+static int prism54_get_genie(struct net_device *ndev,
+			     struct iw_request_info *info,
+			     struct iw_point *data, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	int len = priv->wpa_ie_len;
+
+	if (len <= 0) {
+		data->length = 0;
+		return 0;
+	}
+
+	if (data->length < len)
+		return -E2BIG;
+
+	data->length = len;
+	memcpy(extra, priv->wpa_ie, len);
+
+	return 0;
+}
+
+static int prism54_set_auth(struct net_device *ndev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	struct iw_param *param = &wrqu->param;
+	u32 mlmelevel = 0, authen = 0, dot1x = 0;
+	u32 exunencrypt = 0, privinvoked = 0, wpa = 0;
+	u32 old_wpa;
+	int ret = 0;
+	union oid_res_t r;
+
+	if (islpci_get_state(priv) < PRV_STATE_INIT)
+		return 0;
+
+	/* first get the flags */
+	down_write(&priv->mib_sem);
+	wpa = old_wpa = priv->wpa;
+	up_write(&priv->mib_sem);
+	ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
+	authen = r.u;
+	ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
+	privinvoked = r.u;
+	ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
+	exunencrypt = r.u;
+	ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r);
+	dot1x = r.u;
+	ret = mgt_get_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, NULL, &r);
+	mlmelevel = r.u;
+
+	if (ret < 0)
+		goto out;
+
+	switch (param->flags & IW_AUTH_INDEX) {
+	case IW_AUTH_CIPHER_PAIRWISE:
+	case IW_AUTH_CIPHER_GROUP:
+	case IW_AUTH_KEY_MGMT:
+		break;
+
+	case IW_AUTH_WPA_ENABLED:
+		/* Do the same thing as IW_AUTH_WPA_VERSION */
+		if (param->value) {
+			wpa = 1;
+			privinvoked = 1; /* For privacy invoked */
+			exunencrypt = 1; /* Filter out all unencrypted frames */
+			dot1x = 0x01; /* To enable eap filter */
+			mlmelevel = DOT11_MLME_EXTENDED;
+			authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */
+		} else {
+			wpa = 0;
+			privinvoked = 0;
+			exunencrypt = 0; /* Do not filter un-encrypted data */
+			dot1x = 0;
+			mlmelevel = DOT11_MLME_AUTO;
+		}
+		break;
+
+	case IW_AUTH_WPA_VERSION:
+		if (param->value & IW_AUTH_WPA_VERSION_DISABLED) {
+			wpa = 0;
+			privinvoked = 0;
+			exunencrypt = 0; /* Do not filter un-encrypted data */
+			dot1x = 0;
+			mlmelevel = DOT11_MLME_AUTO;
+		} else {
+			if (param->value & IW_AUTH_WPA_VERSION_WPA)
+				wpa = 1;
+			else if (param->value & IW_AUTH_WPA_VERSION_WPA2)
+				wpa = 2;
+			privinvoked = 1; /* For privacy invoked */
+			exunencrypt = 1; /* Filter out all unencrypted frames */
+			dot1x = 0x01; /* To enable eap filter */
+			mlmelevel = DOT11_MLME_EXTENDED;
+			authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */
+		}
+		break;
+
+	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+		dot1x = param->value ? 1 : 0;
+		break;
+
+	case IW_AUTH_PRIVACY_INVOKED:
+		privinvoked = param->value ? 1 : 0;
+
+	case IW_AUTH_DROP_UNENCRYPTED:
+		exunencrypt = param->value ? 1 : 0;
+		break;
+
+	case IW_AUTH_80211_AUTH_ALG:
+		if (param->value & IW_AUTH_ALG_SHARED_KEY) {
+			/* Only WEP uses _SK and _BOTH */
+			if (wpa > 0) {
+				ret = -EINVAL;
+				goto out;
+			}
+			authen = DOT11_AUTH_SK;
+		} else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
+			authen = DOT11_AUTH_OS;
+		} else {
+			ret = -EINVAL;
+			goto out;
+		}
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	/* Set all the values */
+	down_write(&priv->mib_sem);
+	priv->wpa = wpa;
+	up_write(&priv->mib_sem);
+	mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
+	mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &privinvoked);
+	mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &exunencrypt);
+	mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x);
+	mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlmelevel);
+
+out:
+	return ret;
+}
+
+static int prism54_get_auth(struct net_device *ndev,
+			    struct iw_request_info *info,
+			    union iwreq_data *wrqu, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	struct iw_param *param = &wrqu->param;
+	u32 wpa = 0;
+	int ret = 0;
+	union oid_res_t r;
+
+	if (islpci_get_state(priv) < PRV_STATE_INIT)
+		return 0;
+
+	/* first get the flags */
+	down_write(&priv->mib_sem);
+	wpa = priv->wpa;
+	up_write(&priv->mib_sem);
+
+	switch (param->flags & IW_AUTH_INDEX) {
+	case IW_AUTH_CIPHER_PAIRWISE:
+	case IW_AUTH_CIPHER_GROUP:
+	case IW_AUTH_KEY_MGMT:
+		/*
+		 * wpa_supplicant will control these internally
+		 */
+		ret = -EOPNOTSUPP;
+		break;
+
+	case IW_AUTH_WPA_VERSION:
+		switch (wpa) {
+		case 1:
+			param->value = IW_AUTH_WPA_VERSION_WPA;
+			break;
+		case 2:
+			param->value = IW_AUTH_WPA_VERSION_WPA2;
+			break;
+		case 0:
+		default:
+			param->value = IW_AUTH_WPA_VERSION_DISABLED;
+			break;
+		}
+		break;
+
+	case IW_AUTH_DROP_UNENCRYPTED:
+		ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
+		if (ret >= 0)
+			param->value = r.u > 0 ? 1 : 0;
+		break;
+
+	case IW_AUTH_80211_AUTH_ALG:
+		ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
+		if (ret >= 0) {
+			switch (r.u) {
+			case DOT11_AUTH_OS:
+				param->value = IW_AUTH_ALG_OPEN_SYSTEM;
+				break;
+			case DOT11_AUTH_BOTH:
+			case DOT11_AUTH_SK:
+				param->value = IW_AUTH_ALG_SHARED_KEY;
+			case DOT11_AUTH_NONE:
+			default:
+				param->value = 0;
+				break;
+			}
+		}
+		break;
+
+	case IW_AUTH_WPA_ENABLED:
+		param->value = wpa > 0 ? 1 : 0;
+		break;
+
+	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+		ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r);
+		if (ret >= 0)
+			param->value = r.u > 0 ? 1 : 0;
+		break;
+
+	case IW_AUTH_PRIVACY_INVOKED:
+		ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
+		if (ret >= 0)
+			param->value = r.u > 0 ? 1 : 0;
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+	return ret;
+}
+
+static int prism54_set_encodeext(struct net_device *ndev,
+				 struct iw_request_info *info,
+				 union iwreq_data *wrqu,
+				 char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	struct iw_point *encoding = &wrqu->encoding;
+	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+	int idx, alg = ext->alg, set_key = 1;
+	union oid_res_t r;
+	int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0;
+	int ret = 0;
+
+	if (islpci_get_state(priv) < PRV_STATE_INIT)
+		return 0;
+
+	/* Determine and validate the key index */
+	idx = (encoding->flags & IW_ENCODE_INDEX) - 1;
+	if (idx) {
+		if (idx < 0 || idx > 3)
+			return -EINVAL;
+	} else {
+		ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
+		if (ret < 0)
+			goto out;
+		idx = r.u;
+	}
+
+	if (encoding->flags & IW_ENCODE_DISABLED)
+		alg = IW_ENCODE_ALG_NONE;
+
+	if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
+		/* Only set transmit key index here, actual
+		 * key is set below if needed.
+		 */
+		ret = mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, &idx);
+		set_key = ext->key_len > 0 ? 1 : 0;
+	}
+
+	if (set_key) {
+		struct obj_key key = { DOT11_PRIV_WEP, 0, "" };
+		switch (alg) {
+		case IW_ENCODE_ALG_NONE:
+			break;
+		case IW_ENCODE_ALG_WEP:
+			if (ext->key_len > KEY_SIZE_WEP104) {
+				ret = -EINVAL;
+				goto out;
+			}
+			if (ext->key_len > KEY_SIZE_WEP40)
+				key.length = KEY_SIZE_WEP104;
+			else
+				key.length = KEY_SIZE_WEP40;
+			break;
+		case IW_ENCODE_ALG_TKIP:
+			if (ext->key_len > KEY_SIZE_TKIP) {
+				ret = -EINVAL;
+				goto out;
+			}
+			key.type = DOT11_PRIV_TKIP;
+			key.length = KEY_SIZE_TKIP;
+		default:
+			return -EINVAL;
+		}
+
+		if (key.length) {
+			memset(key.key, 0, sizeof(key.key));
+			memcpy(key.key, ext->key, ext->key_len);
+			ret = mgt_set_request(priv, DOT11_OID_DEFKEYX, idx,
+					    &key);
+			if (ret < 0)
+				goto out;
+		}
+	}
+
+	/* Read the flags */
+	if (encoding->flags & IW_ENCODE_DISABLED) {
+		/* Encoding disabled,
+		 * authen = DOT11_AUTH_OS;
+		 * invoke = 0;
+		 * exunencrypt = 0; */
+	}
+	if (encoding->flags & IW_ENCODE_OPEN) {
+		/* Encode but accept non-encoded packets. No auth */
+		invoke = 1;
+	}
+	if (encoding->flags & IW_ENCODE_RESTRICTED) {
+		/* Refuse non-encoded packets. Auth */
+		authen = DOT11_AUTH_BOTH;
+		invoke = 1;
+		exunencrypt = 1;
+	}
+
+	/* do the change if requested  */
+	if (encoding->flags & IW_ENCODE_MODE) {
+		ret = mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0,
+				      &authen);
+		ret = mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0,
+				      &invoke);
+		ret = mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0,
+				      &exunencrypt);
+	}
+
+out:
+	return ret;
+}
+
+
+static int prism54_get_encodeext(struct net_device *ndev,
+				 struct iw_request_info *info,
+				 union iwreq_data *wrqu,
+				 char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	struct iw_point *encoding = &wrqu->encoding;
+	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+	int idx, max_key_len;
+	union oid_res_t r;
+	int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0, wpa = 0;
+	int ret = 0;
+
+	if (islpci_get_state(priv) < PRV_STATE_INIT)
+		return 0;
+
+	/* first get the flags */
+	ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
+	authen = r.u;
+	ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
+	invoke = r.u;
+	ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
+	exunencrypt = r.u;
+	if (ret < 0)
+		goto out;
+
+	max_key_len = encoding->length - sizeof(*ext);
+	if (max_key_len < 0)
+		return -EINVAL;
+
+	idx = (encoding->flags & IW_ENCODE_INDEX) - 1;
+	if (idx) {
+		if (idx < 0 || idx > 3)
+			return -EINVAL;
+	} else {
+		ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
+		if (ret < 0)
+			goto out;
+		idx = r.u;
+	}
+
+	encoding->flags = idx + 1;
+	memset(ext, 0, sizeof(*ext));
+
+	switch (authen) {
+	case DOT11_AUTH_BOTH:
+	case DOT11_AUTH_SK:
+		wrqu->encoding.flags |= IW_ENCODE_RESTRICTED;
+	case DOT11_AUTH_OS:
+	default:
+		wrqu->encoding.flags |= IW_ENCODE_OPEN;
+		break;
+	}
+
+	down_write(&priv->mib_sem);
+	wpa = priv->wpa;
+	up_write(&priv->mib_sem);
+
+	if (authen == DOT11_AUTH_OS && !exunencrypt && !invoke && !wpa) {
+		/* No encryption */
+		ext->alg = IW_ENCODE_ALG_NONE;
+		ext->key_len = 0;
+		wrqu->encoding.flags |= IW_ENCODE_DISABLED;
+	} else {
+		struct obj_key *key;
+
+		ret = mgt_get_request(priv, DOT11_OID_DEFKEYX, idx, NULL, &r);
+		if (ret < 0)
+			goto out;
+		key = r.ptr;
+		if (max_key_len < key->length) {
+			ret = -E2BIG;
+			goto out;
+		}
+		memcpy(ext->key, key->key, key->length);
+		ext->key_len = key->length;
+
+		switch (key->type) {
+		case DOT11_PRIV_TKIP:
+			ext->alg = IW_ENCODE_ALG_TKIP;
+			break;
+		default:
+		case DOT11_PRIV_WEP:
+			ext->alg = IW_ENCODE_ALG_WEP;
+			break;
+		}
+		wrqu->encoding.flags |= IW_ENCODE_ENABLED;
+	}
+
+out:
+	return ret;
+}
+
+
 static int
 prism54_reset(struct net_device *ndev, struct iw_request_info *info,
 	      __u32 * uwrq, char *extra)
@@ -1591,8 +2081,8 @@
 #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
 
 static void
-prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
-		   u8 *wpa_ie, size_t wpa_ie_len)
+prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid,
+		       u8 *wpa_ie, size_t wpa_ie_len)
 {
 	struct list_head *ptr;
 	struct islpci_bss_wpa_ie *bss = NULL;
@@ -1658,7 +2148,7 @@
 }
 
 static size_t
-prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie)
+prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie)
 {
 	struct list_head *ptr;
 	struct islpci_bss_wpa_ie *bss = NULL;
@@ -1683,14 +2173,14 @@
 }
 
 void
-prism54_wpa_ie_init(islpci_private *priv)
+prism54_wpa_bss_ie_init(islpci_private *priv)
 {
 	INIT_LIST_HEAD(&priv->bss_wpa_list);
 	sema_init(&priv->wpa_sem, 1);
 }
 
 void
-prism54_wpa_ie_clean(islpci_private *priv)
+prism54_wpa_bss_ie_clean(islpci_private *priv)
 {
 	struct list_head *ptr, *n;
 
@@ -1722,7 +2212,7 @@
 		}
 		if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 &&
 		    memcmp(pos + 2, wpa_oid, 4) == 0) {
-			prism54_wpa_ie_add(priv, addr, pos, pos[1] + 2);
+			prism54_wpa_bss_ie_add(priv, addr, pos, pos[1] + 2);
 			return;
 		}
 		pos += 2 + pos[1];
@@ -1879,7 +2369,7 @@
 		send_formatted_event(priv, "Associate request (ex)", mlme, 1);
 
 		if (priv->iw_mode != IW_MODE_MASTER 
-				&& mlmeex->state != DOT11_STATE_AUTHING)
+				&& mlmeex->state != DOT11_STATE_ASSOCING)
 			break;
 		
 		confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC);
@@ -1893,7 +2383,7 @@
 		confirm->state = 0; /* not used */
 		confirm->code = 0;
 
-		wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie);
+		wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
 
 		if (!wpa_ie_len) {
 			printk(KERN_DEBUG "No WPA IE found from "
@@ -1937,7 +2427,7 @@
 		confirm->state = 0; /* not used */
 		confirm->code = 0;
 
-		wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie);
+		wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
 
 		if (!wpa_ie_len) {
 			printk(KERN_DEBUG "No WPA IE found from "
@@ -2553,6 +3043,15 @@
 	(iw_handler) prism54_get_encode,	/* SIOCGIWENCODE */
 	(iw_handler) NULL,	/* SIOCSIWPOWER */
 	(iw_handler) NULL,	/* SIOCGIWPOWER */
+	NULL,			/* -- hole -- */
+	NULL,			/* -- hole -- */
+	(iw_handler) prism54_set_genie,	/* SIOCSIWGENIE */
+	(iw_handler) prism54_get_genie,	/* SIOCGIWGENIE */
+	(iw_handler) prism54_set_auth,	/* SIOCSIWAUTH */
+	(iw_handler) prism54_get_auth,	/* SIOCGIWAUTH */
+	(iw_handler) prism54_set_encodeext, /* SIOCSIWENCODEEXT */
+	(iw_handler) prism54_get_encodeext, /* SIOCGIWENCODEEXT */
+	NULL,			/* SIOCSIWPMKSA */
 };
 
 /* The low order bit identify a SET (0) or a GET (1) ioctl.  */
diff --git a/drivers/net/wireless/prism54/isl_ioctl.h b/drivers/net/wireless/prism54/isl_ioctl.h
index 46d5cde..65f33ac 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.h
+++ b/drivers/net/wireless/prism54/isl_ioctl.h
@@ -27,7 +27,7 @@
 
 #include <net/iw_handler.h>	/* New driver API */
 
-#define SUPPORTED_WIRELESS_EXT                  16
+#define SUPPORTED_WIRELESS_EXT                  19
 
 void prism54_mib_init(islpci_private *);
 
@@ -39,8 +39,8 @@
 
 void prism54_process_trap(void *);
 
-void prism54_wpa_ie_init(islpci_private *priv);
-void prism54_wpa_ie_clean(islpci_private *priv);
+void prism54_wpa_bss_ie_init(islpci_private *priv);
+void prism54_wpa_bss_ie_clean(islpci_private *priv);
 
 int prism54_set_mac_address(struct net_device *, void *);
 
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index 5ddf295..ab3c5a2 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -715,7 +715,7 @@
 	}
 
 	prism54_acl_init(&priv->acl);
-	prism54_wpa_ie_init(priv);
+	prism54_wpa_bss_ie_init(priv);
 	if (mgt_init(priv)) 
 		goto out_free;
 
@@ -774,7 +774,7 @@
 
 	/* Free the acces control list and the WPA list */
 	prism54_acl_clean(&priv->acl);
-	prism54_wpa_ie_clean(priv);
+	prism54_wpa_bss_ie_clean(priv);
 	mgt_clean(priv);
 
 	return 0;
diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h
index 0705316..5049f37 100644
--- a/drivers/net/wireless/prism54/islpci_dev.h
+++ b/drivers/net/wireless/prism54/islpci_dev.h
@@ -179,6 +179,8 @@
 	struct list_head bss_wpa_list;
 	int num_bss_wpa;
 	struct semaphore wpa_sem;
+	u8 wpa_ie[MAX_WPA_IE_LEN];
+	size_t wpa_ie_len;
 
 	struct work_struct reset_task;
 	int reset_task_pending;
diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.c b/drivers/net/wireless/zd1211rw/zd_netdev.c
index 9df232c..440ef24 100644
--- a/drivers/net/wireless/zd1211rw/zd_netdev.c
+++ b/drivers/net/wireless/zd1211rw/zd_netdev.c
@@ -72,10 +72,18 @@
 	               struct iw_request_info *info,
 		       union iwreq_data *req, char *extra)
 {
-	/* FIXME: check whether 802.11a will also supported, add also
-	 *        zd1211B, if we support it.
-	 */
-	strlcpy(req->name, "802.11g zd1211", IFNAMSIZ);
+	/* FIXME: check whether 802.11a will also supported */
+	strlcpy(req->name, "IEEE 802.11b/g", IFNAMSIZ);
+	return 0;
+}
+
+static int iw_get_nick(struct net_device *netdev,
+	               struct iw_request_info *info,
+		       union iwreq_data *req, char *extra)
+{
+	strcpy(extra, "zd1211");
+	req->data.length = strlen(extra) + 1;
+	req->data.flags = 1;
 	return 0;
 }
 
@@ -181,6 +189,7 @@
 
 static const iw_handler zd_standard_iw_handlers[] = {
 	WX(SIOCGIWNAME)		= iw_get_name,
+	WX(SIOCGIWNICKN)	= iw_get_nick,
 	WX(SIOCSIWFREQ)		= iw_set_freq,
 	WX(SIOCGIWFREQ)		= iw_get_freq,
 	WX(SIOCSIWMODE)		= iw_set_mode,
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 6320984..96551da 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -39,9 +39,11 @@
 	{ USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
+	{ USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 },
 	/* ZD1211B */
 	{ USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B },
 	{}
 };
 
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index ecc4286..b174ebb 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -240,6 +240,11 @@
 #define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10)
 #define WLAN_CAPABILITY_DSSS_OFDM (1<<13)
 
+/* 802.11g ERP information element */
+#define WLAN_ERP_NON_ERP_PRESENT (1<<0)
+#define WLAN_ERP_USE_PROTECTION (1<<1)
+#define WLAN_ERP_BARKER_PREAMBLE (1<<2)
+
 /* Status codes */
 enum ieee80211_statuscode {
 	WLAN_STATUS_SUCCESS = 0,
@@ -747,6 +752,8 @@
 #define NETWORK_HAS_IBSS_DFS            (1<<8)
 #define NETWORK_HAS_TPC_REPORT          (1<<9)
 
+#define NETWORK_HAS_ERP_VALUE           (1<<10)
+
 #define QOS_QUEUE_NUM                   4
 #define QOS_OUI_LEN                     3
 #define QOS_OUI_TYPE                    2
@@ -1252,6 +1259,8 @@
 			      int total_len, int encrypt_mpdu);
 
 /* ieee80211_rx.c */
+extern void ieee80211_rx_any(struct ieee80211_device *ieee,
+		     struct sk_buff *skb, struct ieee80211_rx_stats *stats);
 extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
 			struct ieee80211_rx_stats *rx_stats);
 /* make sure to set stats->len */
diff --git a/include/net/ieee80211softmac.h b/include/net/ieee80211softmac.h
index 00ad810..425b3a5 100644
--- a/include/net/ieee80211softmac.h
+++ b/include/net/ieee80211softmac.h
@@ -86,9 +86,6 @@
 	
 	/* BSSID we're trying to associate to */
 	char bssid[ETH_ALEN];
-
-	/* Rates supported by the network */
-	struct ieee80211softmac_ratesinfo supported_rates;
 	
 	/* some flags.
 	 * static_essid is valid if the essid is constant,
@@ -103,6 +100,7 @@
 	 * bssfixed is used for SIOCSIWAP.
 	 */
 	u8 static_essid:1,
+	   short_preamble_available:1,
 	   associating:1,
 	   assoc_wait:1,
 	   bssvalid:1,
@@ -115,6 +113,19 @@
 	struct work_struct timeout;
 };
 
+struct ieee80211softmac_bss_info {
+	/* Rates supported by the network */
+	struct ieee80211softmac_ratesinfo supported_rates;
+
+	/* This indicates whether frames can currently be transmitted with
+	 * short preamble (only use this variable during TX at CCK rates) */
+	u8 short_preamble:1;
+
+	/* This indicates whether protection (e.g. self-CTS) should be used
+	 * when transmitting with OFDM modulation */
+	u8 use_protection:1;
+};
+
 enum {
 	IEEE80211SOFTMAC_AUTH_OPEN_REQUEST	= 1,
 	IEEE80211SOFTMAC_AUTH_OPEN_RESPONSE	= 2,
@@ -157,6 +168,10 @@
 #define IEEE80211SOFTMAC_TXRATECHG_MCAST		(1 << 2) /* mcast_rate */
 #define IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST		(1 << 3) /* mgt_mcast_rate */
 
+#define IEEE80211SOFTMAC_BSSINFOCHG_RATES		(1 << 0) /* supported_rates */
+#define IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE	(1 << 1) /* short_preamble */
+#define IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION		(1 << 2) /* use_protection */
+
 struct ieee80211softmac_device {
 	/* 802.11 structure for data stuff */
 	struct ieee80211_device *ieee;
@@ -200,10 +215,16 @@
 	 * The driver just needs to read them.
 	 */
 	struct ieee80211softmac_txrates txrates;
-	/* If the driver needs to do stuff on TX rate changes, assign this callback. */
+
+	/* If the driver needs to do stuff on TX rate changes, assign this
+	 * callback. See IEEE80211SOFTMAC_TXRATECHG for change flags. */
 	void (*txrates_change)(struct net_device *dev,
-			       u32 changes, /* see IEEE80211SOFTMAC_TXRATECHG flags */
-			       const struct ieee80211softmac_txrates *rates_before_change);
+			       u32 changes);
+
+	/* If the driver needs to do stuff when BSS properties change, assign
+	 * this callback. see IEEE80211SOFTMAC_BSSINFOCHG for change flags. */
+	void (*bssinfo_change)(struct net_device *dev,
+			       u32 changes);
 
 	/* private stuff follows */
 	/* this lock protects this structure */
@@ -216,6 +237,7 @@
 	
 	struct ieee80211softmac_scaninfo *scaninfo;
 	struct ieee80211softmac_assoc_info associnfo;
+	struct ieee80211softmac_bss_info bssinfo;
 
 	struct list_head auth_queue;
 	struct list_head events;
@@ -257,6 +279,14 @@
  * Note that the rates need to be sorted. */
 extern void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates);
 
+/* Finds the highest rate which is:
+ *  1. Present in ri (optionally a basic rate)
+ *  2. Supported by the device
+ *  3. Less than or equal to the user-defined rate
+ */
+extern u8 ieee80211softmac_highest_supported_rate(struct ieee80211softmac_device *mac,
+	struct ieee80211softmac_ratesinfo *ri, int basic_only);
+
 /* Helper function which advises you the rate at which a frame should be
  * transmitted at. */
 static inline u8 ieee80211softmac_suggest_txrate(struct ieee80211softmac_device *mac,
@@ -279,6 +309,24 @@
 		return txrates->mcast_rate;
 }
 
+/* Helper function which advises you when it is safe to transmit with short
+ * preamble.
+ * You should only call this function when transmitting at CCK rates. */
+static inline int ieee80211softmac_short_preamble_ok(struct ieee80211softmac_device *mac,
+						    int is_multicast,
+						    int is_mgt)
+{
+	return (is_multicast && is_mgt) ? 0 : mac->bssinfo.short_preamble;
+}
+
+/* Helper function which advises you whether protection (e.g. self-CTS) is
+ * needed. 1 = protection needed, 0 = no protection needed
+ * Only use this function when transmitting with OFDM modulation. */
+static inline int ieee80211softmac_protection_needed(struct ieee80211softmac_device *mac)
+{
+	return mac->bssinfo.use_protection;
+}
+
 /* Start the SoftMAC. Call this after you initialized the device
  * and it is ready to run.
  */
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
index 72d4d4e..d60358d 100644
--- a/net/ieee80211/ieee80211_rx.c
+++ b/net/ieee80211/ieee80211_rx.c
@@ -779,33 +779,44 @@
 	return 0;
 }
 
-/* Filter out unrelated packets, call ieee80211_rx[_mgt] */
-int ieee80211_rx_any(struct ieee80211_device *ieee,
+/* Filter out unrelated packets, call ieee80211_rx[_mgt]
+ * This function takes over the skb, it should not be used again after calling
+ * this function. */
+void ieee80211_rx_any(struct ieee80211_device *ieee,
 		     struct sk_buff *skb, struct ieee80211_rx_stats *stats)
 {
 	struct ieee80211_hdr_4addr *hdr;
 	int is_packet_for_us;
 	u16 fc;
 
-	if (ieee->iw_mode == IW_MODE_MONITOR)
-		return ieee80211_rx(ieee, skb, stats) ? 0 : -EINVAL;
+	if (ieee->iw_mode == IW_MODE_MONITOR) {
+		if (!ieee80211_rx(ieee, skb, stats))
+			dev_kfree_skb_irq(skb);
+		return;
+	}
+
+	if (skb->len < sizeof(struct ieee80211_hdr))
+		goto drop_free;
 
 	hdr = (struct ieee80211_hdr_4addr *)skb->data;
 	fc = le16_to_cpu(hdr->frame_ctl);
 
 	if ((fc & IEEE80211_FCTL_VERS) != 0)
-		return -EINVAL;
+		goto drop_free;
 		
 	switch (fc & IEEE80211_FCTL_FTYPE) {
 	case IEEE80211_FTYPE_MGMT:
+		if (skb->len < sizeof(struct ieee80211_hdr_3addr))
+			goto drop_free;
 		ieee80211_rx_mgt(ieee, hdr, stats);
-		return 0;
+		dev_kfree_skb_irq(skb);
+		return;
 	case IEEE80211_FTYPE_DATA:
 		break;
 	case IEEE80211_FTYPE_CTL:
-		return 0;
+		return;
 	default:
-		return -EINVAL;
+		return;
 	}
 
 	is_packet_for_us = 0;
@@ -849,8 +860,14 @@
 	}
 
 	if (is_packet_for_us)
-		return (ieee80211_rx(ieee, skb, stats) ? 0 : -EINVAL);
-	return 0;
+		if (!ieee80211_rx(ieee, skb, stats))
+			dev_kfree_skb_irq(skb);
+	return;
+
+drop_free:
+	dev_kfree_skb_irq(skb);
+	ieee->stats.rx_dropped++;
+	return;
 }
 
 #define MGMT_FRAME_FIXED_PART_LENGTH		0x24
@@ -1166,6 +1183,7 @@
 
 		case MFIE_TYPE_ERP_INFO:
 			network->erp_value = info_element->data[0];
+			network->flags |= NETWORK_HAS_ERP_VALUE;
 			IEEE80211_DEBUG_MGMT("MFIE_TYPE_ERP_SET: %d\n",
 					     network->erp_value);
 			break;
@@ -1729,5 +1747,6 @@
 	}
 }
 
+EXPORT_SYMBOL_GPL(ieee80211_rx_any);
 EXPORT_SYMBOL(ieee80211_rx_mgt);
 EXPORT_SYMBOL(ieee80211_rx);
diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c
index 44215ce..589f6d2 100644
--- a/net/ieee80211/softmac/ieee80211softmac_assoc.c
+++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c
@@ -96,7 +96,7 @@
 	mac->associated = 0;
 	mac->associnfo.bssvalid = 0;
 	mac->associnfo.associating = 0;
-	ieee80211softmac_init_txrates(mac);
+	ieee80211softmac_init_bss(mac);
 	ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL);
 	spin_unlock_irqrestore(&mac->lock, flags);
 }
@@ -334,11 +334,19 @@
 	struct ieee80211_assoc_response * resp,
 	struct ieee80211softmac_network *net)
 {
+	u16 cap = le16_to_cpu(resp->capability);
+	u8 erp_value = net->erp_value;
+
 	mac->associnfo.associating = 0;
-	mac->associnfo.supported_rates = net->supported_rates;
+	mac->bssinfo.supported_rates = net->supported_rates;
 	ieee80211softmac_recalc_txrates(mac);
 
 	mac->associated = 1;
+
+	mac->associnfo.short_preamble_available =
+		(cap & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0;
+	ieee80211softmac_process_erp(mac, erp_value);
+
 	if (mac->set_bssid_filter)
 		mac->set_bssid_filter(mac->dev, net->bssid);
 	memcpy(mac->ieee->bssid, net->bssid, ETH_ALEN);
@@ -351,9 +359,9 @@
 int
 ieee80211softmac_handle_assoc_response(struct net_device * dev,
 				       struct ieee80211_assoc_response * resp,
-				       struct ieee80211_network * _ieee80211_network_do_not_use)
+				       struct ieee80211_network * _ieee80211_network)
 {
-	/* NOTE: the network parameter has to be ignored by
+	/* NOTE: the network parameter has to be mostly ignored by
 	 *       this code because it is the ieee80211's pointer
 	 *       to the struct, not ours (we made a copy)
 	 */
@@ -385,6 +393,11 @@
 	/* now that we know it was for us, we can cancel the timeout */
 	cancel_delayed_work(&mac->associnfo.timeout);
 
+	/* if the association response included an ERP IE, update our saved
+	 * copy */
+	if (_ieee80211_network->flags & NETWORK_HAS_ERP_VALUE)
+		network->erp_value = _ieee80211_network->erp_value;
+
 	switch (status) {
 		case 0:
 			dprintk(KERN_INFO PFX "associated!\n");
diff --git a/net/ieee80211/softmac/ieee80211softmac_io.c b/net/ieee80211/softmac/ieee80211softmac_io.c
index 6ae5a1d..82bfddb 100644
--- a/net/ieee80211/softmac/ieee80211softmac_io.c
+++ b/net/ieee80211/softmac/ieee80211softmac_io.c
@@ -467,3 +467,17 @@
 	kfree(pkt);
 	return 0;
 }
+
+/* Beacon handling */
+int ieee80211softmac_handle_beacon(struct net_device *dev,
+	struct ieee80211_beacon *beacon,
+	struct ieee80211_network *network)
+{
+	struct ieee80211softmac_device *mac = ieee80211_priv(dev);
+
+	if (mac->associated && memcmp(network->bssid, mac->associnfo.bssid, ETH_ALEN) == 0)
+		ieee80211softmac_process_erp(mac, network->erp_value);
+
+	return 0;
+}
+
diff --git a/net/ieee80211/softmac/ieee80211softmac_module.c b/net/ieee80211/softmac/ieee80211softmac_module.c
index 4b2e57d..addea1c 100644
--- a/net/ieee80211/softmac/ieee80211softmac_module.c
+++ b/net/ieee80211/softmac/ieee80211softmac_module.c
@@ -44,6 +44,7 @@
 	softmac->ieee->handle_assoc_response = ieee80211softmac_handle_assoc_response;
 	softmac->ieee->handle_reassoc_request = ieee80211softmac_handle_reassoc_req;
 	softmac->ieee->handle_disassoc = ieee80211softmac_handle_disassoc;
+ 	softmac->ieee->handle_beacon = ieee80211softmac_handle_beacon;
 	softmac->scaninfo = NULL;
 
 	softmac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
@@ -178,21 +179,14 @@
 	return 0;
 }
 
-/* Finds the highest rate which is:
- *  1. Present in ri (optionally a basic rate)
- *  2. Supported by the device
- *  3. Less than or equal to the user-defined rate
- */
-static u8 highest_supported_rate(struct ieee80211softmac_device *mac,
+u8 ieee80211softmac_highest_supported_rate(struct ieee80211softmac_device *mac,
 	struct ieee80211softmac_ratesinfo *ri, int basic_only)
 {
 	u8 user_rate = mac->txrates.user_rate;
 	int i;
 
-	if (ri->count == 0) {
-		dprintk(KERN_ERR PFX "empty ratesinfo?\n");
+	if (ri->count == 0)
 		return IEEE80211_CCK_RATE_1MB;
-	}
 
 	for (i = ri->count - 1; i >= 0; i--) {
 		u8 rate = ri->rates[i];
@@ -208,36 +202,61 @@
 	/* If we haven't found a suitable rate by now, just trust the user */
 	return user_rate;
 }
+EXPORT_SYMBOL_GPL(ieee80211softmac_highest_supported_rate);
+
+void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac,
+	u8 erp_value)
+{
+ 	int use_protection;
+	int short_preamble;
+ 	u32 changes = 0;
+
+	/* Barker preamble mode */
+	short_preamble = ((erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0
+			  && mac->associnfo.short_preamble_available) ? 1 : 0;
+
+	/* Protection needed? */
+	use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
+
+	if (mac->bssinfo.short_preamble != short_preamble) {
+		changes |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
+		mac->bssinfo.short_preamble = short_preamble;
+	}
+
+	if (mac->bssinfo.use_protection != use_protection) {
+		changes |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
+		mac->bssinfo.use_protection = use_protection;
+	}
+
+	if (mac->bssinfo_change && changes)
+		mac->bssinfo_change(mac->dev, changes);
+}
 
 void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac)
 {
 	struct ieee80211softmac_txrates *txrates = &mac->txrates;
-	struct ieee80211softmac_txrates oldrates;
 	u32 change = 0;
 
-	if (mac->txrates_change)
-		oldrates = mac->txrates;
-
 	change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
-	txrates->default_rate = highest_supported_rate(mac, &mac->associnfo.supported_rates, 0);
+	txrates->default_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 0);
 
 	change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
 	txrates->default_fallback = lower_rate(mac, txrates->default_rate);
 
 	change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
-	txrates->mcast_rate = highest_supported_rate(mac, &mac->associnfo.supported_rates, 1);
+	txrates->mcast_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 1);
 
 	if (mac->txrates_change)
-		mac->txrates_change(mac->dev, change, &oldrates);
+		mac->txrates_change(mac->dev, change);
 
 }
 
-void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac)
+void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac)
 {
 	struct ieee80211_device *ieee = mac->ieee;
 	u32 change = 0;
 	struct ieee80211softmac_txrates *txrates = &mac->txrates;
-	struct ieee80211softmac_txrates oldrates;
+	struct ieee80211softmac_bss_info *bssinfo = &mac->bssinfo;
 
 	/* TODO: We need some kind of state machine to lower the default rates
 	 *       if we loose too many packets.
@@ -245,8 +264,6 @@
 	/* Change the default txrate to the highest possible value.
 	 * The txrate machine will lower it, if it is too high.
 	 */
-	if (mac->txrates_change)
-		oldrates = mac->txrates;
 	/* FIXME: We don't correctly handle backing down to lower
 	   rates, so 801.11g devices start off at 11M for now. People
 	   can manually change it if they really need to, but 11M is
@@ -272,7 +289,23 @@
 	change |= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST;
 
 	if (mac->txrates_change)
-		mac->txrates_change(mac->dev, change, &oldrates);
+		mac->txrates_change(mac->dev, change);
+
+	change = 0;
+
+	bssinfo->supported_rates.count = 0;
+	memset(bssinfo->supported_rates.rates, 0,
+		sizeof(bssinfo->supported_rates.rates));
+	change |= IEEE80211SOFTMAC_BSSINFOCHG_RATES;
+
+	bssinfo->short_preamble = 0;
+	change |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
+
+	bssinfo->use_protection = 0;
+	change |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
+
+	if (mac->bssinfo_change)
+		mac->bssinfo_change(mac->dev, change);
 
 	mac->running = 1;
 }
@@ -282,7 +315,7 @@
 	struct ieee80211softmac_device *mac = ieee80211_priv(dev);
 
 	ieee80211softmac_start_check_rates(mac);
-	ieee80211softmac_init_txrates(mac);
+	ieee80211softmac_init_bss(mac);
 }
 EXPORT_SYMBOL_GPL(ieee80211softmac_start);
 
@@ -335,7 +368,6 @@
 static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac,
 						 int amount)
 {
-	struct ieee80211softmac_txrates oldrates;
 	u8 default_rate = mac->txrates.default_rate;
 	u8 default_fallback = mac->txrates.default_fallback;
 	u32 changes = 0;
@@ -348,8 +380,6 @@
 	mac->txrate_badness += amount;
 	if (mac->txrate_badness <= -1000) {
 		/* Very small badness. Try a faster bitrate. */
-		if (mac->txrates_change)
-			memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
 		default_rate = raise_rate(mac, default_rate);
 		changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
 		default_fallback = get_fallback_rate(mac, default_rate);
@@ -358,8 +388,6 @@
 printk("Bitrate raised to %u\n", default_rate);
 	} else if (mac->txrate_badness >= 10000) {
 		/* Very high badness. Try a slower bitrate. */
-		if (mac->txrates_change)
-			memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
 		default_rate = lower_rate(mac, default_rate);
 		changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
 		default_fallback = get_fallback_rate(mac, default_rate);
@@ -372,7 +400,7 @@
 	mac->txrates.default_fallback = default_fallback;
 
 	if (changes && mac->txrates_change)
-		mac->txrates_change(mac->dev, changes, &oldrates);
+		mac->txrates_change(mac->dev, changes);
 }
 
 void ieee80211softmac_fragment_lost(struct net_device *dev,
@@ -416,7 +444,11 @@
 	memcpy(&softnet->supported_rates.rates[softnet->supported_rates.count], net->rates_ex, net->rates_ex_len);
 	softnet->supported_rates.count += net->rates_ex_len;
 	sort(softnet->supported_rates.rates, softnet->supported_rates.count, sizeof(softnet->supported_rates.rates[0]), rate_cmp, NULL);
-	
+
+	/* we save the ERP value because it is needed at association time, and
+	 * many AP's do not include an ERP IE in the association response. */
+	softnet->erp_value = net->erp_value;
+
 	softnet->capabilities = net->capability;
 	return softnet;
 }
diff --git a/net/ieee80211/softmac/ieee80211softmac_priv.h b/net/ieee80211/softmac/ieee80211softmac_priv.h
index fa1f8e3..0642e09 100644
--- a/net/ieee80211/softmac/ieee80211softmac_priv.h
+++ b/net/ieee80211/softmac/ieee80211softmac_priv.h
@@ -116,9 +116,11 @@
 	struct ieee80211softmac_essid *essid);
 
 /* Rates related */
+void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac,
+	u8 erp_value);
 int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate);
 u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta);
-void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac);
+void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac);
 void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac);
 static inline u8 lower_rate(struct ieee80211softmac_device *mac, u8 rate) {
 	return ieee80211softmac_lower_rate_delta(mac, rate, 1);
@@ -133,6 +135,9 @@
 /*** prototypes from _io.c */
 int ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
 	void* ptrarg, u32 type, u32 arg);
+int ieee80211softmac_handle_beacon(struct net_device *dev,
+	struct ieee80211_beacon *beacon,
+	struct ieee80211_network *network);
 
 /*** prototypes from _auth.c */
 /* do these have to go into the public header? */
@@ -189,6 +194,7 @@
 	    authenticated:1,
 	    auth_desynced_once:1;
 
+	u8 erp_value;				/* Saved ERP value */
 	u16 capabilities;			/* Capabilities bitfield */
 	u8 challenge_len;			/* Auth Challenge length */
 	char *challenge;			/* Challenge Text */