Merge branch 'master' into upstream
Jeff Garzik [Mon, 7 Aug 2006 10:38:41 +0000 (06:38 -0400)]
38 files changed:
Documentation/networking/LICENSE.qla3xxx [new file with mode: 0644]
MAINTAINERS
drivers/isdn/i4l/Kconfig
drivers/net/8390.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/forcedeth.c
drivers/net/qla3xxx.c [new file with mode: 0644]
drivers/net/qla3xxx.h [new file with mode: 0644]
drivers/net/sky2.c
drivers/net/slhc.c
drivers/net/tulip/uli526x.c
drivers/net/wireless/airo.c
drivers/net/wireless/bcm43xx/bcm43xx.h
drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h
drivers/net/wireless/bcm43xx/bcm43xx_leds.c
drivers/net/wireless/bcm43xx/bcm43xx_main.c
drivers/net/wireless/bcm43xx/bcm43xx_main.h
drivers/net/wireless/bcm43xx/bcm43xx_phy.c
drivers/net/wireless/bcm43xx/bcm43xx_pio.c
drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
drivers/net/wireless/bcm43xx/bcm43xx_wx.c
drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
drivers/net/wireless/ipw2200.c
drivers/net/wireless/prism54/isl_ioctl.c
drivers/net/wireless/prism54/isl_ioctl.h
drivers/net/wireless/prism54/islpci_dev.c
drivers/net/wireless/prism54/islpci_dev.h
drivers/net/wireless/zd1211rw/zd_netdev.c
drivers/net/wireless/zd1211rw/zd_usb.c
include/net/ieee80211.h
include/net/ieee80211softmac.h
net/ieee80211/ieee80211_rx.c
net/ieee80211/softmac/ieee80211softmac_assoc.c
net/ieee80211/softmac/ieee80211softmac_io.c
net/ieee80211/softmac/ieee80211softmac_module.c
net/ieee80211/softmac/ieee80211softmac_priv.h

diff --git a/Documentation/networking/LICENSE.qla3xxx b/Documentation/networking/LICENSE.qla3xxx
new file mode 100644 (file)
index 0000000..2f2077e
--- /dev/null
@@ -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.
+
index e3e1515..13f345c 100644 (file)
@@ -2360,6 +2360,12 @@ M:       linux-driver@qlogic.com
 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 @@ P:       Nicolas Pitre
 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
@@ -3326,6 +3344,15 @@ W:       http://www.qsl.net/dl1bke/
 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
index a4f7288..3ef567b 100644 (file)
@@ -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
index d2935ae..3eb7048 100644 (file)
@@ -299,7 +299,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
         *      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 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
                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 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
        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 @@ irqreturn_t ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 #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
 
index 3918990..3a0d80b 100644 (file)
@@ -2249,6 +2249,15 @@ config MV643XX_ETH_2
          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
 
 #
@@ -2509,6 +2518,7 @@ config PLIP
 
 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
@@ -2689,6 +2699,7 @@ config SLIP
 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
@@ -2701,6 +2712,12 @@ config SLIP_COMPRESSED
          <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
index c91e951..5e91c35 100644 (file)
@@ -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/
@@ -110,8 +106,9 @@ obj-$(CONFIG_FORCEDETH) += forcedeth.o
 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
@@ -120,9 +117,7 @@ obj-$(CONFIG_PPP_MPPE) += ppp_mppe.o
 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
index 11b8f1b..6fc6d1b 100644 (file)
@@ -381,21 +381,21 @@ enum {
 
 /* 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 +653,8 @@ static const struct nv_ethtool_str nv_etests_str[] = {
 };
 
 struct register_test {
-       u32 reg;
-       u32 mask;
+       __le32 reg;
+       __le32 mask;
 };
 
 static const struct register_test nv_registers_test[] = {
@@ -713,7 +713,7 @@ struct fe_priv {
        /* 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 +733,7 @@ struct fe_priv {
        /*
         * 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 +826,13 @@ static inline void pci_push(u8 __iomem *base)
 
 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 +885,7 @@ static void free_rings(struct net_device *dev)
        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 {
@@ -1258,14 +1258,14 @@ static int nv_alloc_rx(struct net_device *dev)
                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);
@@ -1315,9 +1315,9 @@ static void nv_init_rx(struct net_device *dev)
        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 +1328,9 @@ static void nv_init_tx(struct net_device *dev)
        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 +1373,9 @@ static void nv_drain_tx(struct net_device *dev)
 
        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 +1387,9 @@ static void nv_drain_rx(struct net_device *dev)
        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 +1450,17 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
                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 +1477,12 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        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 +1491,9 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* 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 +1512,10 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* 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 +1547,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
 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 +1555,22 @@ static void nv_tx_done(struct net_device *dev)
                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 +1579,13 @@ static void nv_tx_done(struct net_device *dev)
                                }
                        }
                } 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 +1638,29 @@ static void nv_tx_timeout(struct net_device *dev)
                        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 +1697,7 @@ static int nv_getlen(struct net_device *dev, void *packet, int datalen)
        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 {
@@ -1743,7 +1743,7 @@ static int nv_getlen(struct net_device *dev, void *packet, int datalen)
 static void nv_rx_process(struct net_device *dev)
 {
        struct fe_priv *np = netdev_priv(dev);
-       u32 Flags;
+       u32 flags;
        u32 vlanflags = 0;
 
        for (;;) {
@@ -1755,18 +1755,18 @@ static void nv_rx_process(struct net_device *dev)
 
                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 +1780,7 @@ static void nv_rx_process(struct net_device *dev)
 
                {
                        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 +1790,30 @@ static void nv_rx_process(struct net_device *dev)
                }
                /* 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 +1821,32 @@ static void nv_rx_process(struct net_device *dev)
                                        }
                                }
                                /* 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 +1854,17 @@ static void nv_rx_process(struct net_device *dev)
                                        }
                                }
                                /* 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 {
@@ -1990,7 +1990,7 @@ static int nv_set_mac_address(struct net_device *dev, void *addr)
        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 +2283,20 @@ set_speed:
                        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;
@@ -3245,7 +3245,7 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
        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 +3481,7 @@ static int nv_get_stats_count(struct net_device *dev)
        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 +3619,7 @@ static int nv_loopback_test(struct net_device *dev)
        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 +3663,12 @@ static int nv_loopback_test(struct net_device *dev)
                                       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 +3677,21 @@ static int nv_loopback_test(struct net_device *dev)
 
        /* 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;
                }
        }
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
new file mode 100644 (file)
index 0000000..c729aee
--- /dev/null
@@ -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 (file)
index 0000000..9492cee
--- /dev/null
@@ -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_ */
index de91609..13431f6 100644 (file)
@@ -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 @@ static const struct pci_device_id sky2_id_table[] = {
        { 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 }
 };
 
@@ -1927,12 +1932,6 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last)
        }
 }
 
-/* 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)
 {
@@ -2023,6 +2022,9 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
                }
        }
 
+       /* 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]);
@@ -2232,19 +2234,16 @@ static int sky2_poll(struct net_device *dev0, int *budget)
                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 (status & Y2_IS_STAT_BMU)
-               sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
+       if (work_done < work_limit) {
+               netif_rx_complete(dev0);
 
-       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)
index 3a1b713..9a540e2 100644 (file)
@@ -94,27 +94,23 @@ slhc_init(int rslots, int tslots)
        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 @@ slhc_init(int rslots, int tslots)
        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_compress);
 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 */
 
 
index fd64b2b..c4c720e 100644 (file)
@@ -1702,7 +1702,6 @@ MODULE_PARM_DESC(mode, "ULi M5261/M5263: Bit 0: 10/100Mbps, bit 2: duplex, bit 8
 
 static int __init uli526x_init_module(void)
 {
-       int rc;
 
        printk(version);
        printed_version = 1;
@@ -1714,22 +1713,19 @@ static int __init uli526x_init_module(void)
        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);
 }
 
 
index a4dd139..16befbc 100644 (file)
@@ -3950,13 +3950,11 @@ static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
        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) {
index 17a5682..c6ee1e9 100644 (file)
@@ -504,6 +504,12 @@ struct bcm43xx_phyinfo {
         * 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 @@ struct bcm43xx_coreinfo {
        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 @@ enum {
        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 @@ struct bcm43xx_private {
 
        void __iomem *mmio_addr;
 
-       /* Locking, see "theory of locking" text below. */
        spinlock_t irq_lock;
        struct mutex mutex;
 
@@ -691,6 +714,7 @@ struct bcm43xx_private {
        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_private {
        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 @@ struct bcm43xx_private {
        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_private {
        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 @@ struct bcm43xx_private {
 };
 
 
-/*    *** 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 @@ int bcm43xx_using_pio(struct bcm43xx_private *bcm)
  * 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);
 }
 
 
index ce2e40b..923275e 100644 (file)
@@ -77,7 +77,8 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf,
 
        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 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf,
        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 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf,
        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 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf,
        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 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf,
        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 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf,
                (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 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf,
                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 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf,
        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 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf,
        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 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf,
                        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 @@ static struct file_operations txstat_fops = {
        .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 @@ void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm)
                                                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 @@ void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm)
        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);
index 50ce267..a40d1af 100644 (file)
@@ -20,6 +20,7 @@ struct bcm43xx_dfsentry {
        struct dentry *dentry_spromdump;
        struct dentry *dentry_tsf;
        struct dentry *dentry_txstat;
+       struct dentry *dentry_restart;
 
        struct bcm43xx_private *bcm;
 
index ec80692..c3f90c8 100644 (file)
@@ -51,12 +51,12 @@ static void bcm43xx_led_blink(unsigned long d)
        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 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
        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 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
                        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 @@ void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on)
        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 @@ void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on)
                        ledctl &= ~(1 << i);
        }
        bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
+       spin_unlock_irqrestore(&bcm->leds_lock, flags);
 }
index df317c1..b095f3c 100644 (file)
@@ -509,23 +509,19 @@ static void bcm43xx_synchronize_irq(struct bcm43xx_private *bcm)
 }
 
 /* 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 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm)
        u16 manufact;
        u16 version;
        u8 revision;
-       s8 i;
 
        if (bcm->chip_id == 0x4317) {
                if (bcm->chip_rev == 0x00)
@@ -580,20 +575,11 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm)
        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 @@ int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *ne
                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 @@ static void bcm43xx_wireless_core_disable(struct bcm43xx_private *bcm)
        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 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
 # 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 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
                        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 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
                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 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re
 
        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 @@ out:
 
 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 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
        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 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
                }
        }
 
-       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 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
                }
        }
 
-       if (!bcm->initvals0) {
+       if (!phy->initvals0) {
                if (rev == 2 || rev == 4) {
                        switch (phy->type) {
                        case BCM43xx_PHYTYPE_A:
@@ -2008,20 +1966,20 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
                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 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
                        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 @@ err_noinitval:
 
 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 @@ static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm)
        }
 
        /* 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 @@ err_format:
 
 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 struct pci_device_id bcm43xx_47xx_ids[] = {
 
 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 @@ static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
                }
        }
 #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 @@ static int bcm43xx_gpio_cleanup(struct bcm43xx_private *bcm)
 /* 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 @@ void bcm43xx_mac_suspend(struct bcm43xx_private *bcm)
        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 @@ static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm)
        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 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
        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 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
                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 @@ err_radio_off:
        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 @@ static void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy)
 {
        /* 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 @@ static void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio)
 {
        /* 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 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
                                    * 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 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
                                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 @@ static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm)
 }
 
 /* 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 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm)
        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 @@ out:
        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 @@ static void bcm43xx_periodic_work_handler(void *d)
                /* 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 @@ static int bcm43xx_rng_read(struct hwrng *rng, u32 *data)
        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 @@ static int bcm43xx_rng_init(struct bcm43xx_private *bcm)
        return err;
 }
 
-/* This is the opposite of bcm43xx_init_board() */
-static void bcm43xx_free_board(struct bcm43xx_private *bcm)
+static int bcm43xx_shutdown_all_wireless_cores(struct bcm43xx_private *bcm)
 {
+       int ret = 0;
        int i, err;
+       struct bcm43xx_coreinfo *core;
 
-       bcm43xx_lock_noirq(bcm);
+       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)
+{
        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);
+}
+
+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;
 
-       bcm43xx_rng_exit(bcm);
+       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)
+               core = &(bcm->core_80211[i]);
+               wlext = core->priv;
+
+               if (!core->available)
                        continue;
+               assert(wlext == &(bcm->core_80211_ext[i]));
 
-               err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
-               assert(err == 0);
-               bcm43xx_wireless_core_cleanup(bcm);
+               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;
 
-       bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
-       bcm43xx_unlock_noirq(bcm);
+       /* Noise calculation context */
+       memset(&bcm->noisecalc, 0, sizeof(bcm->noisecalc));
+
+       /* Periodic work context */
+       bcm->periodic_state = 0;
 }
 
-static int bcm43xx_init_board(struct bcm43xx_private *bcm)
+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;
-       int connect_phy;
+       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();
 
-       bcm43xx_lock_noirq(bcm);
-       bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
+       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_crystal(bcm, 1);
-       if (err)
-               goto out;
-       err = bcm43xx_pctl_init(bcm);
-       if (err)
-               goto err_crystal_off;
        err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST);
        if (err)
-               goto err_crystal_off;
+               goto error;
 
-       tasklet_enable(&bcm->isr_tasklet);
+       /* Mark all unused cores "inactive". */
        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;
+               core = &(bcm->core_80211[i]);
+               wlext = core->priv;
 
-               /* 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 (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;
+       }
 
-               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;
+       /* 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;
 
-               if (i != 0) {
-                       bcm43xx_mac_suspend(bcm);
-                       bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
-                       bcm43xx_radio_turn_off(bcm);
-               }
+               sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+               sbtmstatelow |= 0x20000000;
+               bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
        }
-       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 = 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_rng_init(bcm);
+       err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC);
        if (err)
-               goto err_80211_unwind;
+               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));
-       dprintk(KERN_INFO PFX "80211 cores initialized\n");
        bcm43xx_security_init(bcm);
-       bcm43xx_softmac_init(bcm);
+       ieee80211softmac_start(bcm->net_dev);
 
-       bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC);
+       /* 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);
 
-       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);
-       }
+       dprintk(KERN_INFO PFX "Selected 802.11 core (phytype %d)\n",
+               active_wlext->phy.type);
 
-       /* Initialization of the board is done. Flag it as such. */
-       bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
+       return 0;
+
+error:
+       bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
+       bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
+       return err;
+}
+
+static int bcm43xx_init_board(struct bcm43xx_private *bcm)
+{
+       int err;
+
+       mutex_lock(&(bcm)->mutex);
+
+       tasklet_enable(&bcm->isr_tasklet);
+       err = bcm43xx_pctl_set_crystal(bcm, 1);
+       if (err)
+               goto err_tasklet;
+       err = bcm43xx_pctl_init(bcm);
+       if (err)
+               goto err_crystal_off;
+       err = bcm43xx_select_wireless_core(bcm, -1);
+       if (err)
+               goto err_crystal_off;
 
        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 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev,
        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 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev,
                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 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
        
        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 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
                } 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 @@ static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb,
        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 @@ static void bcm43xx_net_tx_timeout(struct net_device *net_dev)
        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 @@ static void bcm43xx_net_poll_controller(struct net_device *net_dev)
        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 @@ static int bcm43xx_net_stop(struct net_device *net_dev)
        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 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm,
        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 @@ static void __devexit bcm43xx_remove_one(struct pci_dev *pdev)
        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 __devexit bcm43xx_remove_one(struct pci_dev *pdev)
 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 @@ static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        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 @@ static int bcm43xx_resume(struct pci_dev *pdev)
        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;
index 1164936..505c86e 100644 (file)
@@ -133,6 +133,9 @@ void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm);
 
 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);
index f8200de..eafd0f6 100644 (file)
@@ -81,6 +81,16 @@ static const s8 bcm43xx_tssi2dbm_g_table[] = {
 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_write(struct bcm43xx_private *bcm, u16 offset, u16 val)
 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 @@ static u16 bcm43xx_phy_lo_b_r15_loop(struct bcm43xx_private *bcm)
 {
        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 @@ static u16 bcm43xx_phy_lo_b_r15_loop(struct bcm43xx_private *bcm)
                udelay(40);
                ret += bcm43xx_phy_read(bcm, 0x002C);
        }
+       local_irq_restore(flags);
+       bcm43xx_voluntary_preempt();
 
        return ret;
 }
@@