qlge: Optimize rx buffer refill process.
[safe/jmp/linux-2.6] / drivers / net / qlge / qlge_main.c
index c6ab6a4..1719845 100644 (file)
@@ -76,7 +76,6 @@ MODULE_PARM_DESC(irq_type, "0 = MSI-X, 1 = MSI, 2 = Legacy.");
 
 static struct pci_device_id qlge_pci_tbl[] __devinitdata = {
        {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID)},
-       {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID1)},
        /* required last entry */
        {0,}
 };
@@ -127,12 +126,12 @@ static int ql_sem_trylock(struct ql_adapter *qdev, u32 sem_mask)
 
 int ql_sem_spinlock(struct ql_adapter *qdev, u32 sem_mask)
 {
-       unsigned int seconds = 3;
+       unsigned int wait_count = 30;
        do {
                if (!ql_sem_trylock(qdev, sem_mask))
                        return 0;
-               ssleep(1);
-       } while (--seconds);
+               udelay(100);
+       } while (--wait_count);
        return -ETIMEDOUT;
 }
 
@@ -248,16 +247,13 @@ int ql_get_mac_addr_reg(struct ql_adapter *qdev, u32 type, u16 index,
        u32 offset = 0;
        int status;
 
-       status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
-       if (status)
-               return status;
        switch (type) {
        case MAC_ADDR_TYPE_MULTI_MAC:
        case MAC_ADDR_TYPE_CAM_MAC:
                {
                        status =
                            ql_wait_reg_rdy(qdev,
-                               MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E);
+                               MAC_ADDR_IDX, MAC_ADDR_MW, 0);
                        if (status)
                                goto exit;
                        ql_write32(qdev, MAC_ADDR_IDX, (offset++) | /* offset */
@@ -265,13 +261,13 @@ int ql_get_mac_addr_reg(struct ql_adapter *qdev, u32 type, u16 index,
                                   MAC_ADDR_ADR | MAC_ADDR_RS | type); /* type */
                        status =
                            ql_wait_reg_rdy(qdev,
-                               MAC_ADDR_IDX, MAC_ADDR_MR, MAC_ADDR_E);
+                               MAC_ADDR_IDX, MAC_ADDR_MR, 0);
                        if (status)
                                goto exit;
                        *value++ = ql_read32(qdev, MAC_ADDR_DATA);
                        status =
                            ql_wait_reg_rdy(qdev,
-                               MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E);
+                               MAC_ADDR_IDX, MAC_ADDR_MW, 0);
                        if (status)
                                goto exit;
                        ql_write32(qdev, MAC_ADDR_IDX, (offset++) | /* offset */
@@ -279,14 +275,14 @@ int ql_get_mac_addr_reg(struct ql_adapter *qdev, u32 type, u16 index,
                                   MAC_ADDR_ADR | MAC_ADDR_RS | type); /* type */
                        status =
                            ql_wait_reg_rdy(qdev,
-                               MAC_ADDR_IDX, MAC_ADDR_MR, MAC_ADDR_E);
+                               MAC_ADDR_IDX, MAC_ADDR_MR, 0);
                        if (status)
                                goto exit;
                        *value++ = ql_read32(qdev, MAC_ADDR_DATA);
                        if (type == MAC_ADDR_TYPE_CAM_MAC) {
                                status =
                                    ql_wait_reg_rdy(qdev,
-                                       MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E);
+                                       MAC_ADDR_IDX, MAC_ADDR_MW, 0);
                                if (status)
                                        goto exit;
                                ql_write32(qdev, MAC_ADDR_IDX, (offset++) | /* offset */
@@ -294,7 +290,7 @@ int ql_get_mac_addr_reg(struct ql_adapter *qdev, u32 type, u16 index,
                                           MAC_ADDR_ADR | MAC_ADDR_RS | type); /* type */
                                status =
                                    ql_wait_reg_rdy(qdev, MAC_ADDR_IDX,
-                                                   MAC_ADDR_MR, MAC_ADDR_E);
+                                                   MAC_ADDR_MR, 0);
                                if (status)
                                        goto exit;
                                *value++ = ql_read32(qdev, MAC_ADDR_DATA);
@@ -309,7 +305,6 @@ int ql_get_mac_addr_reg(struct ql_adapter *qdev, u32 type, u16 index,
                status = -EPERM;
        }
 exit:
-       ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
        return status;
 }
 
@@ -322,9 +317,6 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type,
        u32 offset = 0;
        int status = 0;
 
-       status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
-       if (status)
-               return status;
        switch (type) {
        case MAC_ADDR_TYPE_MULTI_MAC:
        case MAC_ADDR_TYPE_CAM_MAC:
@@ -344,7 +336,7 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type,
 
                        status =
                            ql_wait_reg_rdy(qdev,
-                               MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E);
+                               MAC_ADDR_IDX, MAC_ADDR_MW, 0);
                        if (status)
                                goto exit;
                        ql_write32(qdev, MAC_ADDR_IDX, (offset++) | /* offset */
@@ -353,7 +345,7 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type,
                        ql_write32(qdev, MAC_ADDR_DATA, lower);
                        status =
                            ql_wait_reg_rdy(qdev,
-                               MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E);
+                               MAC_ADDR_IDX, MAC_ADDR_MW, 0);
                        if (status)
                                goto exit;
                        ql_write32(qdev, MAC_ADDR_IDX, (offset++) | /* offset */
@@ -362,7 +354,7 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type,
                        ql_write32(qdev, MAC_ADDR_DATA, upper);
                        status =
                            ql_wait_reg_rdy(qdev,
-                               MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E);
+                               MAC_ADDR_IDX, MAC_ADDR_MW, 0);
                        if (status)
                                goto exit;
                        ql_write32(qdev, MAC_ADDR_IDX, (offset) |       /* offset */
@@ -400,7 +392,7 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type,
 
                        status =
                            ql_wait_reg_rdy(qdev,
-                               MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E);
+                               MAC_ADDR_IDX, MAC_ADDR_MW, 0);
                        if (status)
                                goto exit;
                        ql_write32(qdev, MAC_ADDR_IDX, offset | /* offset */
@@ -416,7 +408,6 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type,
                status = -EPERM;
        }
 exit:
-       ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
        return status;
 }
 
@@ -427,22 +418,17 @@ int ql_get_routing_reg(struct ql_adapter *qdev, u32 index, u32 *value)
 {
        int status = 0;
 
-       status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK);
-       if (status)
-               goto exit;
-
-       status = ql_wait_reg_rdy(qdev, RT_IDX, RT_IDX_MW, RT_IDX_E);
+       status = ql_wait_reg_rdy(qdev, RT_IDX, RT_IDX_MW, 0);
        if (status)
                goto exit;
 
        ql_write32(qdev, RT_IDX,
                   RT_IDX_TYPE_NICQ | RT_IDX_RS | (index << RT_IDX_IDX_SHIFT));
-       status = ql_wait_reg_rdy(qdev, RT_IDX, RT_IDX_MR, RT_IDX_E);
+       status = ql_wait_reg_rdy(qdev, RT_IDX, RT_IDX_MR, 0);
        if (status)
                goto exit;
        *value = ql_read32(qdev, RT_DATA);
 exit:
-       ql_sem_unlock(qdev, SEM_RT_IDX_MASK);
        return status;
 }
 
@@ -454,13 +440,9 @@ exit:
 static int ql_set_routing_reg(struct ql_adapter *qdev, u32 index, u32 mask,
                              int enable)
 {
-       int status;
+       int status = -EINVAL; /* Return error if no mask match. */
        u32 value = 0;
 
-       status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK);
-       if (status)
-               return status;
-
        QPRINTK(qdev, IFUP, DEBUG,
                "%s %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s mask %s the routing reg.\n",
                (enable ? "Adding" : "Removing"),
@@ -556,7 +538,6 @@ static int ql_set_routing_reg(struct ql_adapter *qdev, u32 index, u32 mask,
                ql_write32(qdev, RT_DATA, enable ? mask : 0);
        }
 exit:
-       ql_sem_unlock(qdev, SEM_RT_IDX_MASK);
        return status;
 }
 
@@ -642,7 +623,7 @@ static void ql_enable_all_completion_interrupts(struct ql_adapter *qdev)
 
 }
 
-static int ql_read_flash_word(struct ql_adapter *qdev, int offset, u32 *data)
+static int ql_read_flash_word(struct ql_adapter *qdev, int offset, __le32 *data)
 {
        int status = 0;
        /* wait for reg to come ready */
@@ -657,8 +638,11 @@ static int ql_read_flash_word(struct ql_adapter *qdev, int offset, u32 *data)
                        FLASH_ADDR, FLASH_ADDR_RDY, FLASH_ADDR_ERR);
        if (status)
                goto exit;
-       /* get the data */
-       *data = ql_read32(qdev, FLASH_DATA);
+        /* This data is stored on flash as an array of
+        * __le32.  Since ql_read32() returns cpu endian
+        * we need to swap it back.
+        */
+       *data = cpu_to_le32(ql_read32(qdev, FLASH_DATA));
 exit:
        return status;
 }
@@ -667,13 +651,20 @@ static int ql_get_flash_params(struct ql_adapter *qdev)
 {
        int i;
        int status;
-       u32 *p = (u32 *)&qdev->flash;
+       __le32 *p = (__le32 *)&qdev->flash;
+       u32 offset = 0;
+
+       /* Second function's parameters follow the first
+        * function's.
+        */
+       if (qdev->func)
+               offset = sizeof(qdev->flash) / sizeof(u32);
 
        if (ql_sem_spinlock(qdev, SEM_FLASH_MASK))
                return -ETIMEDOUT;
 
        for (i = 0; i < sizeof(qdev->flash) / sizeof(u32); i++, p++) {
-               status = ql_read_flash_word(qdev, i, p);
+               status = ql_read_flash_word(qdev, i+offset, p);
                if (status) {
                        QPRINTK(qdev, IFUP, ERR, "Error reading flash.\n");
                        goto exit;
@@ -872,9 +863,9 @@ static void ql_write_cq_idx(struct rx_ring *rx_ring)
 /* Process (refill) a large buffer queue. */
 static void ql_update_lbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
 {
-       int clean_idx = rx_ring->lbq_clean_idx;
+       u32 clean_idx = rx_ring->lbq_clean_idx;
+       u32 start_idx = clean_idx;
        struct bq_desc *lbq_desc;
-       struct bq_element *bq;
        u64 map;
        int i;
 
@@ -884,13 +875,13 @@ static void ql_update_lbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
                                "lbq: try cleaning clean_idx = %d.\n",
                                clean_idx);
                        lbq_desc = &rx_ring->lbq[clean_idx];
-                       bq = lbq_desc->bq;
                        if (lbq_desc->p.lbq_page == NULL) {
                                QPRINTK(qdev, RX_STATUS, DEBUG,
                                        "lbq: getting new page for index %d.\n",
                                        lbq_desc->index);
                                lbq_desc->p.lbq_page = alloc_page(GFP_ATOMIC);
                                if (lbq_desc->p.lbq_page == NULL) {
+                                       rx_ring->lbq_clean_idx = clean_idx;
                                        QPRINTK(qdev, RX_STATUS, ERR,
                                                "Couldn't get a page.\n");
                                        return;
@@ -900,16 +891,16 @@ static void ql_update_lbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
                                                   0, PAGE_SIZE,
                                                   PCI_DMA_FROMDEVICE);
                                if (pci_dma_mapping_error(qdev->pdev, map)) {
+                                       rx_ring->lbq_clean_idx = clean_idx;
+                                       put_page(lbq_desc->p.lbq_page);
+                                       lbq_desc->p.lbq_page = NULL;
                                        QPRINTK(qdev, RX_STATUS, ERR,
                                                "PCI mapping failed.\n");
                                        return;
                                }
                                pci_unmap_addr_set(lbq_desc, mapaddr, map);
                                pci_unmap_len_set(lbq_desc, maplen, PAGE_SIZE);
-                               bq->addr_lo =   /*lbq_desc->addr_lo = */
-                                   cpu_to_le32(map);
-                               bq->addr_hi =   /*lbq_desc->addr_hi = */
-                                   cpu_to_le32(map >> 32);
+                               *lbq_desc->addr = cpu_to_le64(map);
                        }
                        clean_idx++;
                        if (clean_idx == rx_ring->lbq_len)
@@ -920,21 +911,24 @@ static void ql_update_lbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
                rx_ring->lbq_prod_idx += 16;
                if (rx_ring->lbq_prod_idx == rx_ring->lbq_len)
                        rx_ring->lbq_prod_idx = 0;
+               rx_ring->lbq_free_cnt -= 16;
+       }
+
+       if (start_idx != clean_idx) {
                QPRINTK(qdev, RX_STATUS, DEBUG,
                        "lbq: updating prod idx = %d.\n",
                        rx_ring->lbq_prod_idx);
                ql_write_db_reg(rx_ring->lbq_prod_idx,
                                rx_ring->lbq_prod_idx_db_reg);
-               rx_ring->lbq_free_cnt -= 16;
        }
 }
 
 /* Process (refill) a small buffer queue. */
 static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
 {
-       int clean_idx = rx_ring->sbq_clean_idx;
+       u32 clean_idx = rx_ring->sbq_clean_idx;
+       u32 start_idx = clean_idx;
        struct bq_desc *sbq_desc;
-       struct bq_element *bq;
        u64 map;
        int i;
 
@@ -944,7 +938,6 @@ static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
                        QPRINTK(qdev, RX_STATUS, DEBUG,
                                "sbq: try cleaning clean_idx = %d.\n",
                                clean_idx);
-                       bq = sbq_desc->bq;
                        if (sbq_desc->p.skb == NULL) {
                                QPRINTK(qdev, RX_STATUS, DEBUG,
                                        "sbq: getting new skb for index %d.\n",
@@ -966,13 +959,14 @@ static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
                                if (pci_dma_mapping_error(qdev->pdev, map)) {
                                        QPRINTK(qdev, IFUP, ERR, "PCI mapping failed.\n");
                                        rx_ring->sbq_clean_idx = clean_idx;
+                                       dev_kfree_skb_any(sbq_desc->p.skb);
+                                       sbq_desc->p.skb = NULL;
                                        return;
                                }
                                pci_unmap_addr_set(sbq_desc, mapaddr, map);
                                pci_unmap_len_set(sbq_desc, maplen,
                                                  rx_ring->sbq_buf_size / 2);
-                               bq->addr_lo = cpu_to_le32(map);
-                               bq->addr_hi = cpu_to_le32(map >> 32);
+                               *sbq_desc->addr = cpu_to_le64(map);
                        }
 
                        clean_idx++;
@@ -983,13 +977,15 @@ static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
                rx_ring->sbq_prod_idx += 16;
                if (rx_ring->sbq_prod_idx == rx_ring->sbq_len)
                        rx_ring->sbq_prod_idx = 0;
+               rx_ring->sbq_free_cnt -= 16;
+       }
+
+       if (start_idx != clean_idx) {
                QPRINTK(qdev, RX_STATUS, DEBUG,
                        "sbq: updating prod idx = %d.\n",
                        rx_ring->sbq_prod_idx);
                ql_write_db_reg(rx_ring->sbq_prod_idx,
                                rx_ring->sbq_prod_idx_db_reg);
-
-               rx_ring->sbq_free_cnt -= 16;
        }
 }
 
@@ -1308,6 +1304,11 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
                                        "No skb available, drop the packet.\n");
                                return NULL;
                        }
+                       pci_unmap_page(qdev->pdev,
+                                      pci_unmap_addr(lbq_desc,
+                                                     mapaddr),
+                                      pci_unmap_len(lbq_desc, maplen),
+                                      PCI_DMA_FROMDEVICE);
                        skb_reserve(skb, NET_IP_ALIGN);
                        QPRINTK(qdev, RX_STATUS, DEBUG,
                                "%d bytes of headers and data in large. Chain page to new skb and pull tail.\n", length);
@@ -1335,7 +1336,7 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
                 *          eventually be in trouble.
                 */
                int size, offset, i = 0;
-               struct bq_element *bq, bq_array[8];
+               __le64 *bq, bq_array[8];
                sbq_desc = ql_get_curr_sbuf(rx_ring);
                pci_unmap_single(qdev->pdev,
                                 pci_unmap_addr(sbq_desc, mapaddr),
@@ -1361,16 +1362,10 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
                } else {
                        QPRINTK(qdev, RX_STATUS, DEBUG,
                                "Headers in small, %d bytes of data in chain of large.\n", length);
-                       bq = (struct bq_element *)sbq_desc->p.skb->data;
+                       bq = (__le64 *)sbq_desc->p.skb->data;
                }
                while (length > 0) {
                        lbq_desc = ql_get_curr_lbuf(rx_ring);
-                       if ((bq->addr_lo & ~BQ_MASK) != lbq_desc->bq->addr_lo) {
-                               QPRINTK(qdev, RX_STATUS, ERR,
-                                       "Panic!!! bad large buffer address, expected 0x%.08x, got 0x%.08x.\n",
-                                       lbq_desc->bq->addr_lo, bq->addr_lo);
-                               return NULL;
-                       }
                        pci_unmap_page(qdev->pdev,
                                       pci_unmap_addr(lbq_desc,
                                                      mapaddr),
@@ -1446,15 +1441,16 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev,
        qdev->stats.rx_packets++;
        qdev->stats.rx_bytes += skb->len;
        skb->protocol = eth_type_trans(skb, ndev);
+       skb_record_rx_queue(skb, rx_ring - &qdev->rx_ring[0]);
        if (qdev->vlgrp && (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V)) {
                QPRINTK(qdev, RX_STATUS, DEBUG,
                        "Passing a VLAN packet upstream.\n");
-               vlan_hwaccel_rx(skb, qdev->vlgrp,
+               vlan_hwaccel_receive_skb(skb, qdev->vlgrp,
                                le16_to_cpu(ib_mac_rsp->vlan_id));
        } else {
                QPRINTK(qdev, RX_STATUS, DEBUG,
                        "Passing a normal packet upstream.\n");
-               netif_rx(skb);
+               netif_receive_skb(skb);
        }
 }
 
@@ -1511,6 +1507,11 @@ void ql_queue_asic_error(struct ql_adapter *qdev)
        netif_stop_queue(qdev->ndev);
        netif_carrier_off(qdev->ndev);
        ql_disable_interrupts(qdev);
+       /* Clear adapter up bit to signal the recovery
+        * process that it shouldn't kill the reset worker
+        * thread
+        */
+       clear_bit(QL_ADAPTER_UP, &qdev->flags);
        queue_delayed_work(qdev->workqueue, &qdev->asic_reset_work, 0);
 }
 
@@ -1652,7 +1653,7 @@ static int ql_napi_poll_msix(struct napi_struct *napi, int budget)
                rx_ring->cq_id);
 
        if (work_done < budget) {
-               __netif_rx_complete(napi);
+               __napi_complete(napi);
                ql_enable_completion_interrupt(qdev, rx_ring->irq);
        }
        return work_done;
@@ -1678,19 +1679,29 @@ static void ql_vlan_rx_add_vid(struct net_device *ndev, u16 vid)
 {
        struct ql_adapter *qdev = netdev_priv(ndev);
        u32 enable_bit = MAC_ADDR_E;
+       int status;
 
+       status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
+       if (status)
+               return;
        spin_lock(&qdev->hw_lock);
        if (ql_set_mac_addr_reg
            (qdev, (u8 *) &enable_bit, MAC_ADDR_TYPE_VLAN, vid)) {
                QPRINTK(qdev, IFUP, ERR, "Failed to init vlan address.\n");
        }
        spin_unlock(&qdev->hw_lock);
+       ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
 }
 
 static void ql_vlan_rx_kill_vid(struct net_device *ndev, u16 vid)
 {
        struct ql_adapter *qdev = netdev_priv(ndev);
        u32 enable_bit = 0;
+       int status;
+
+       status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
+       if (status)
+               return;
 
        spin_lock(&qdev->hw_lock);
        if (ql_set_mac_addr_reg
@@ -1698,6 +1709,7 @@ static void ql_vlan_rx_kill_vid(struct net_device *ndev, u16 vid)
                QPRINTK(qdev, IFUP, ERR, "Failed to clear vlan address.\n");
        }
        spin_unlock(&qdev->hw_lock);
+       ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
 
 }
 
@@ -1737,7 +1749,7 @@ static irqreturn_t qlge_msix_tx_isr(int irq, void *dev_id)
 static irqreturn_t qlge_msix_rx_isr(int irq, void *dev_id)
 {
        struct rx_ring *rx_ring = dev_id;
-       netif_rx_schedule(&rx_ring->napi);
+       napi_schedule(&rx_ring->napi);
        return IRQ_HANDLED;
 }
 
@@ -1823,7 +1835,7 @@ static irqreturn_t qlge_isr(int irq, void *dev_id)
                                                              &rx_ring->rx_work,
                                                              0);
                                else
-                                       netif_rx_schedule(&rx_ring->napi);
+                                       napi_schedule(&rx_ring->napi);
                                work_done++;
                        }
                }
@@ -1879,7 +1891,7 @@ static void ql_hw_csum_setup(struct sk_buff *skb,
 {
        int len;
        struct iphdr *iph = ip_hdr(skb);
-       u16 *check;
+       __sum16 *check;
        mac_iocb_ptr->opcode = OPCODE_OB_MAC_TSO_IOCB;
        mac_iocb_ptr->frame_len = cpu_to_le32((u32) skb->len);
        mac_iocb_ptr->net_trans_offset =
@@ -1927,10 +1939,6 @@ static int qlge_send(struct sk_buff *skb, struct net_device *ndev)
        tx_ring_desc = &tx_ring->q[tx_ring->prod_idx];
        mac_iocb_ptr = tx_ring_desc->queue_entry;
        memset((void *)mac_iocb_ptr, 0, sizeof(mac_iocb_ptr));
-       if (ql_map_send(qdev, mac_iocb_ptr, skb, tx_ring_desc) != NETDEV_TX_OK) {
-               QPRINTK(qdev, TX_QUEUED, ERR, "Could not map the segments.\n");
-               return NETDEV_TX_BUSY;
-       }
 
        mac_iocb_ptr->opcode = OPCODE_OB_MAC_IOCB;
        mac_iocb_ptr->tid = tx_ring_desc->index;
@@ -1956,6 +1964,12 @@ static int qlge_send(struct sk_buff *skb, struct net_device *ndev)
                ql_hw_csum_setup(skb,
                                 (struct ob_mac_tso_iocb_req *)mac_iocb_ptr);
        }
+       if (ql_map_send(qdev, mac_iocb_ptr, skb, tx_ring_desc) !=
+                       NETDEV_TX_OK) {
+               QPRINTK(qdev, TX_QUEUED, ERR,
+                               "Could not map the segments.\n");
+               return NETDEV_TX_BUSY;
+       }
        QL_DUMP_OB_MAC_IOCB(mac_iocb_ptr);
        tx_ring->prod_idx++;
        if (tx_ring->prod_idx == tx_ring->wq_len)
@@ -2088,8 +2102,6 @@ static void ql_free_lbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring
                        put_page(lbq_desc->p.lbq_page);
                        lbq_desc->p.lbq_page = NULL;
                }
-               lbq_desc->bq->addr_lo = 0;
-               lbq_desc->bq->addr_hi = 0;
        }
 }
 
@@ -2102,12 +2114,12 @@ static int ql_alloc_lbq_buffers(struct ql_adapter *qdev,
        int i;
        struct bq_desc *lbq_desc;
        u64 map;
-       struct bq_element *bq = rx_ring->lbq_base;
+       __le64 *bq = rx_ring->lbq_base;
 
        for (i = 0; i < rx_ring->lbq_len; i++) {
                lbq_desc = &rx_ring->lbq[i];
                memset(lbq_desc, 0, sizeof(lbq_desc));
-               lbq_desc->bq = bq;
+               lbq_desc->addr = bq;
                lbq_desc->index = i;
                lbq_desc->p.lbq_page = alloc_page(GFP_ATOMIC);
                if (unlikely(!lbq_desc->p.lbq_page)) {
@@ -2124,8 +2136,7 @@ static int ql_alloc_lbq_buffers(struct ql_adapter *qdev,
                        }
                        pci_unmap_addr_set(lbq_desc, mapaddr, map);
                        pci_unmap_len_set(lbq_desc, maplen, PAGE_SIZE);
-                       bq->addr_lo = cpu_to_le32(map);
-                       bq->addr_hi = cpu_to_le32(map >> 32);
+                       *lbq_desc->addr = cpu_to_le64(map);
                }
                bq++;
        }
@@ -2154,13 +2165,6 @@ static void ql_free_sbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring
                        dev_kfree_skb(sbq_desc->p.skb);
                        sbq_desc->p.skb = NULL;
                }
-               if (sbq_desc->bq == NULL) {
-                       QPRINTK(qdev, IFUP, ERR, "sbq_desc->bq %d is NULL.\n",
-                               i);
-                       return;
-               }
-               sbq_desc->bq->addr_lo = 0;
-               sbq_desc->bq->addr_hi = 0;
        }
 }
 
@@ -2172,13 +2176,13 @@ static int ql_alloc_sbq_buffers(struct ql_adapter *qdev,
        struct bq_desc *sbq_desc;
        struct sk_buff *skb;
        u64 map;
-       struct bq_element *bq = rx_ring->sbq_base;
+       __le64 *bq = rx_ring->sbq_base;
 
        for (i = 0; i < rx_ring->sbq_len; i++) {
                sbq_desc = &rx_ring->sbq[i];
                memset(sbq_desc, 0, sizeof(sbq_desc));
                sbq_desc->index = i;
-               sbq_desc->bq = bq;
+               sbq_desc->addr = bq;
                skb = netdev_alloc_skb(qdev->ndev, rx_ring->sbq_buf_size);
                if (unlikely(!skb)) {
                        /* Better luck next round */
@@ -2204,10 +2208,7 @@ static int ql_alloc_sbq_buffers(struct ql_adapter *qdev,
                }
                pci_unmap_addr_set(sbq_desc, mapaddr, map);
                pci_unmap_len_set(sbq_desc, maplen, rx_ring->sbq_buf_size / 2);
-               bq->addr_lo =   /*sbq_desc->addr_lo = */
-                   cpu_to_le32(map);
-               bq->addr_hi =   /*sbq_desc->addr_hi = */
-                   cpu_to_le32(map >> 32);
+               *sbq_desc->addr = cpu_to_le64(map);
                bq++;
        }
        return 0;
@@ -2378,28 +2379,6 @@ static void ql_tx_ring_clean(struct ql_adapter *qdev)
        }
 }
 
-static void ql_free_ring_cb(struct ql_adapter *qdev)
-{
-       kfree(qdev->ring_mem);
-}
-
-static int ql_alloc_ring_cb(struct ql_adapter *qdev)
-{
-       /* Allocate space for tx/rx ring control blocks. */
-       qdev->ring_mem_size =
-           (qdev->tx_ring_count * sizeof(struct tx_ring)) +
-           (qdev->rx_ring_count * sizeof(struct rx_ring));
-       qdev->ring_mem = kmalloc(qdev->ring_mem_size, GFP_KERNEL);
-       if (qdev->ring_mem == NULL) {
-               return -ENOMEM;
-       } else {
-               qdev->rx_ring = qdev->ring_mem;
-               qdev->tx_ring = qdev->ring_mem +
-                   (qdev->rx_ring_count * sizeof(struct rx_ring));
-       }
-       return 0;
-}
-
 static void ql_free_mem_resources(struct ql_adapter *qdev)
 {
        int i;
@@ -2486,14 +2465,12 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring)
        memset((void *)cqicb, 0, sizeof(struct cqicb));
        cqicb->msix_vect = rx_ring->irq;
 
-       cqicb->len = cpu_to_le16(rx_ring->cq_len | LEN_V | LEN_CPP_CONT);
+       bq_len = (rx_ring->cq_len == 65536) ? 0 : (u16) rx_ring->cq_len;
+       cqicb->len = cpu_to_le16(bq_len | LEN_V | LEN_CPP_CONT);
 
-       cqicb->addr_lo = cpu_to_le32(rx_ring->cq_base_dma);
-       cqicb->addr_hi = cpu_to_le32((u64) rx_ring->cq_base_dma >> 32);
+       cqicb->addr = cpu_to_le64(rx_ring->cq_base_dma);
 
-       cqicb->prod_idx_addr_lo = cpu_to_le32(rx_ring->prod_idx_sh_reg_dma);
-       cqicb->prod_idx_addr_hi =
-           cpu_to_le32((u64) rx_ring->prod_idx_sh_reg_dma >> 32);
+       cqicb->prod_idx_addr = cpu_to_le64(rx_ring->prod_idx_sh_reg_dma);
 
        /*
         * Set up the control block load flags.
@@ -2504,12 +2481,13 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring)
        if (rx_ring->lbq_len) {
                cqicb->flags |= FLAGS_LL;       /* Load lbq values */
                *((u64 *) rx_ring->lbq_base_indirect) = rx_ring->lbq_base_dma;
-               cqicb->lbq_addr_lo =
-                   cpu_to_le32(rx_ring->lbq_base_indirect_dma);
-               cqicb->lbq_addr_hi =
-                   cpu_to_le32((u64) rx_ring->lbq_base_indirect_dma >> 32);
-               cqicb->lbq_buf_size = cpu_to_le32(rx_ring->lbq_buf_size);
-               bq_len = (u16) rx_ring->lbq_len;
+               cqicb->lbq_addr =
+                   cpu_to_le64(rx_ring->lbq_base_indirect_dma);
+               bq_len = (rx_ring->lbq_buf_size == 65536) ? 0 :
+                       (u16) rx_ring->lbq_buf_size;
+               cqicb->lbq_buf_size = cpu_to_le16(bq_len);
+               bq_len = (rx_ring->lbq_len == 65536) ? 0 :
+                       (u16) rx_ring->lbq_len;
                cqicb->lbq_len = cpu_to_le16(bq_len);
                rx_ring->lbq_prod_idx = rx_ring->lbq_len - 16;
                rx_ring->lbq_curr_idx = 0;
@@ -2519,13 +2497,12 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring)
        if (rx_ring->sbq_len) {
                cqicb->flags |= FLAGS_LS;       /* Load sbq values */
                *((u64 *) rx_ring->sbq_base_indirect) = rx_ring->sbq_base_dma;
-               cqicb->sbq_addr_lo =
-                   cpu_to_le32(rx_ring->sbq_base_indirect_dma);
-               cqicb->sbq_addr_hi =
-                   cpu_to_le32((u64) rx_ring->sbq_base_indirect_dma >> 32);
+               cqicb->sbq_addr =
+                   cpu_to_le64(rx_ring->sbq_base_indirect_dma);
                cqicb->sbq_buf_size =
                    cpu_to_le16(((rx_ring->sbq_buf_size / 2) + 8) & 0xfffffff8);
-               bq_len = (u16) rx_ring->sbq_len;
+               bq_len = (rx_ring->sbq_len == 65536) ? 0 :
+                       (u16) rx_ring->sbq_len;
                cqicb->sbq_len = cpu_to_le16(bq_len);
                rx_ring->sbq_prod_idx = rx_ring->sbq_len - 16;
                rx_ring->sbq_curr_idx = 0;
@@ -2628,12 +2605,9 @@ static int ql_start_tx_ring(struct ql_adapter *qdev, struct tx_ring *tx_ring)
                                   Q_FLAGS_LB | Q_FLAGS_LI | Q_FLAGS_LO);
        wqicb->cq_id_rss = cpu_to_le16(tx_ring->cq_id);
        wqicb->rid = 0;
-       wqicb->addr_lo = cpu_to_le32(tx_ring->wq_base_dma);
-       wqicb->addr_hi = cpu_to_le32((u64) tx_ring->wq_base_dma >> 32);
+       wqicb->addr = cpu_to_le64(tx_ring->wq_base_dma);
 
-       wqicb->cnsmr_idx_addr_lo = cpu_to_le32(tx_ring->cnsmr_idx_sh_reg_dma);
-       wqicb->cnsmr_idx_addr_hi =
-           cpu_to_le32((u64) tx_ring->cnsmr_idx_sh_reg_dma >> 32);
+       wqicb->cnsmr_idx_addr = cpu_to_le64(tx_ring->cnsmr_idx_sh_reg_dma);
 
        ql_init_tx_ring(qdev, tx_ring);
 
@@ -2763,14 +2737,14 @@ static void ql_resolve_queues_to_irqs(struct ql_adapter *qdev)
                                 * Outbound queue is for outbound completions only.
                                 */
                                intr_context->handler = qlge_msix_tx_isr;
-                               sprintf(intr_context->name, "%s-txq-%d",
+                               sprintf(intr_context->name, "%s-tx-%d",
                                        qdev->ndev->name, i);
                        } else {
                                /*
                                 * Inbound queues handle unicast frames only.
                                 */
                                intr_context->handler = qlge_msix_rx_isr;
-                               sprintf(intr_context->name, "%s-rxq-%d",
+                               sprintf(intr_context->name, "%s-rx-%d",
                                        qdev->ndev->name, i);
                        }
                }
@@ -2913,8 +2887,8 @@ static int ql_start_rss(struct ql_adapter *qdev)
        /*
         * Fill out the Indirection Table.
         */
-       for (i = 0; i < 32; i++)
-               hash_id[i] = i & 1;
+       for (i = 0; i < 256; i++)
+               hash_id[i] = i & (qdev->rss_ring_count - 1);
 
        /*
         * Random values for the IPv6 and IPv4 Hash Keys.
@@ -2939,13 +2913,17 @@ static int ql_route_initialize(struct ql_adapter *qdev)
        int status = 0;
        int i;
 
+       status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK);
+       if (status)
+               return status;
+
        /* Clear all the entries in the routing table. */
        for (i = 0; i < 16; i++) {
                status = ql_set_routing_reg(qdev, i, 0, 0);
                if (status) {
                        QPRINTK(qdev, IFUP, ERR,
                                "Failed to init routing register for CAM packets.\n");
-                       return status;
+                       goto exit;
                }
        }
 
@@ -2953,13 +2931,13 @@ static int ql_route_initialize(struct ql_adapter *qdev)
        if (status) {
                QPRINTK(qdev, IFUP, ERR,
                        "Failed to init routing register for error packets.\n");
-               return status;
+               goto exit;
        }
        status = ql_set_routing_reg(qdev, RT_IDX_BCAST_SLOT, RT_IDX_BCAST, 1);
        if (status) {
                QPRINTK(qdev, IFUP, ERR,
                        "Failed to init routing register for broadcast packets.\n");
-               return status;
+               goto exit;
        }
        /* If we have more than one inbound queue, then turn on RSS in the
         * routing block.
@@ -2970,17 +2948,39 @@ static int ql_route_initialize(struct ql_adapter *qdev)
                if (status) {
                        QPRINTK(qdev, IFUP, ERR,
                                "Failed to init routing register for MATCH RSS packets.\n");
-                       return status;
+                       goto exit;
                }
        }
 
        status = ql_set_routing_reg(qdev, RT_IDX_CAM_HIT_SLOT,
                                    RT_IDX_CAM_HIT, 1);
-       if (status) {
+       if (status)
                QPRINTK(qdev, IFUP, ERR,
                        "Failed to init routing register for CAM packets.\n");
+exit:
+       ql_sem_unlock(qdev, SEM_RT_IDX_MASK);
+       return status;
+}
+
+static int ql_cam_route_initialize(struct ql_adapter *qdev)
+{
+       int status;
+
+       status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
+       if (status)
+               return status;
+       status = ql_set_mac_addr_reg(qdev, (u8 *) qdev->ndev->perm_addr,
+                            MAC_ADDR_TYPE_CAM_MAC, qdev->func * MAX_CQ);
+       ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
+       if (status) {
+               QPRINTK(qdev, IFUP, ERR, "Failed to init mac address.\n");
                return status;
        }
+
+       status = ql_route_initialize(qdev);
+       if (status)
+               QPRINTK(qdev, IFUP, ERR, "Failed to init routing table.\n");
+
        return status;
 }
 
@@ -3054,16 +3054,11 @@ static int ql_adapter_initialize(struct ql_adapter *qdev)
                return status;
        }
 
-       status = ql_set_mac_addr_reg(qdev, (u8 *) qdev->ndev->perm_addr,
-                                    MAC_ADDR_TYPE_CAM_MAC, qdev->func);
+       /* Set up the MAC address and frame routing filter. */
+       status = ql_cam_route_initialize(qdev);
        if (status) {
-               QPRINTK(qdev, IFUP, ERR, "Failed to init mac address.\n");
-               return status;
-       }
-
-       status = ql_route_initialize(qdev);
-       if (status) {
-               QPRINTK(qdev, IFUP, ERR, "Failed to init routing table.\n");
+               QPRINTK(qdev, IFUP, ERR,
+                               "Failed to init CAM/Routing tables.\n");
                return status;
        }
 
@@ -3140,7 +3135,11 @@ static int ql_adapter_down(struct ql_adapter *qdev)
        netif_stop_queue(ndev);
        netif_carrier_off(ndev);
 
-       cancel_delayed_work_sync(&qdev->asic_reset_work);
+       /* Don't kill the reset worker thread if we
+        * are in the process of recovery.
+        */
+       if (test_bit(QL_ADAPTER_UP, &qdev->flags))
+               cancel_delayed_work_sync(&qdev->asic_reset_work);
        cancel_delayed_work_sync(&qdev->mpi_reset_work);
        cancel_delayed_work_sync(&qdev->mpi_work);
 
@@ -3264,7 +3263,6 @@ static int qlge_close(struct net_device *ndev)
                msleep(1);
        ql_adapter_down(qdev);
        ql_release_adapter_resources(qdev);
-       ql_free_ring_cb(qdev);
        return 0;
 }
 
@@ -3290,8 +3288,8 @@ static int ql_configure_rings(struct ql_adapter *qdev)
         * This limitation can be removed when requested.
         */
 
-       if (cpu_cnt > 8)
-               cpu_cnt = 8;
+       if (cpu_cnt > MAX_CPUS)
+               cpu_cnt = MAX_CPUS;
 
        /*
         * rx_ring[0] is always the default queue.
@@ -3311,9 +3309,6 @@ static int ql_configure_rings(struct ql_adapter *qdev)
         */
        qdev->rx_ring_count = qdev->tx_ring_count + qdev->rss_ring_count + 1;
 
-       if (ql_alloc_ring_cb(qdev))
-               return -ENOMEM;
-
        for (i = 0; i < qdev->tx_ring_count; i++) {
                tx_ring = &qdev->tx_ring[i];
                memset((void *)tx_ring, 0, sizeof(tx_ring));
@@ -3346,11 +3341,11 @@ static int ql_configure_rings(struct ql_adapter *qdev)
                            rx_ring->cq_len * sizeof(struct ql_net_rsp_iocb);
                        rx_ring->lbq_len = NUM_LARGE_BUFFERS;
                        rx_ring->lbq_size =
-                           rx_ring->lbq_len * sizeof(struct bq_element);
+                           rx_ring->lbq_len * sizeof(__le64);
                        rx_ring->lbq_buf_size = LARGE_BUFFER_SIZE;
                        rx_ring->sbq_len = NUM_SMALL_BUFFERS;
                        rx_ring->sbq_size =
-                           rx_ring->sbq_len * sizeof(struct bq_element);
+                           rx_ring->sbq_len * sizeof(__le64);
                        rx_ring->sbq_buf_size = SMALL_BUFFER_SIZE * 2;
                        rx_ring->type = DEFAULT_Q;
                } else if (i < qdev->rss_ring_first_cq_id) {
@@ -3377,11 +3372,11 @@ static int ql_configure_rings(struct ql_adapter *qdev)
                            rx_ring->cq_len * sizeof(struct ql_net_rsp_iocb);
                        rx_ring->lbq_len = NUM_LARGE_BUFFERS;
                        rx_ring->lbq_size =
-                           rx_ring->lbq_len * sizeof(struct bq_element);
+                           rx_ring->lbq_len * sizeof(__le64);
                        rx_ring->lbq_buf_size = LARGE_BUFFER_SIZE;
                        rx_ring->sbq_len = NUM_SMALL_BUFFERS;
                        rx_ring->sbq_size =
-                           rx_ring->sbq_len * sizeof(struct bq_element);
+                           rx_ring->sbq_len * sizeof(__le64);
                        rx_ring->sbq_buf_size = SMALL_BUFFER_SIZE * 2;
                        rx_ring->type = RX_Q;
                }
@@ -3410,7 +3405,6 @@ static int qlge_open(struct net_device *ndev)
 
 error_up:
        ql_release_adapter_resources(qdev);
-       ql_free_ring_cb(qdev);
        return err;
 }
 
@@ -3442,8 +3436,11 @@ static void qlge_set_multicast_list(struct net_device *ndev)
 {
        struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev);
        struct dev_mc_list *mc_ptr;
-       int i;
+       int i, status;
 
+       status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK);
+       if (status)
+               return;
        spin_lock(&qdev->hw_lock);
        /*
         * Set or clear promiscuous mode if a
@@ -3499,14 +3496,19 @@ static void qlge_set_multicast_list(struct net_device *ndev)
        }
 
        if (ndev->mc_count) {
+               status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
+               if (status)
+                       goto exit;
                for (i = 0, mc_ptr = ndev->mc_list; mc_ptr;
                     i++, mc_ptr = mc_ptr->next)
                        if (ql_set_mac_addr_reg(qdev, (u8 *) mc_ptr->dmi_addr,
                                                MAC_ADDR_TYPE_MULTI_MAC, i)) {
                                QPRINTK(qdev, HW, ERR,
                                        "Failed to loadmulticast address.\n");
+                               ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
                                goto exit;
                        }
+               ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
                if (ql_set_routing_reg
                    (qdev, RT_IDX_MCAST_MATCH_SLOT, RT_IDX_MCAST_MATCH, 1)) {
                        QPRINTK(qdev, HW, ERR,
@@ -3517,13 +3519,14 @@ static void qlge_set_multicast_list(struct net_device *ndev)
        }
 exit:
        spin_unlock(&qdev->hw_lock);
+       ql_sem_unlock(qdev, SEM_RT_IDX_MASK);
 }
 
 static int qlge_set_mac_address(struct net_device *ndev, void *p)
 {
        struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev);
        struct sockaddr *addr = p;
-       int ret = 0;
+       int status;
 
        if (netif_running(ndev))
                return -EBUSY;
@@ -3532,21 +3535,23 @@ static int qlge_set_mac_address(struct net_device *ndev, void *p)
                return -EADDRNOTAVAIL;
        memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len);
 
+       status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
+       if (status)
+               return status;
        spin_lock(&qdev->hw_lock);
-       if (ql_set_mac_addr_reg(qdev, (u8 *) ndev->dev_addr,
-                       MAC_ADDR_TYPE_CAM_MAC, qdev->func)) {/* Unicast */
-               QPRINTK(qdev, HW, ERR, "Failed to load MAC address.\n");
-               ret = -1;
-       }
+       status = ql_set_mac_addr_reg(qdev, (u8 *) ndev->dev_addr,
+                       MAC_ADDR_TYPE_CAM_MAC, qdev->func * MAX_CQ);
        spin_unlock(&qdev->hw_lock);
-
-       return ret;
+       if (status)
+               QPRINTK(qdev, HW, ERR, "Failed to load MAC address.\n");
+       ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
+       return status;
 }
 
 static void qlge_tx_timeout(struct net_device *ndev)
 {
        struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev);
-       queue_delayed_work(qdev->workqueue, &qdev->asic_reset_work, 0);
+       ql_queue_asic_error(qdev);
 }
 
 static void ql_asic_reset_work(struct work_struct *work)
@@ -3881,7 +3886,7 @@ static int qlge_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct net_device *ndev = pci_get_drvdata(pdev);
        struct ql_adapter *qdev = netdev_priv(ndev);
-       int err;
+       int err, i;
 
        netif_device_detach(ndev);
 
@@ -3891,6 +3896,9 @@ static int qlge_suspend(struct pci_dev *pdev, pm_message_t state)
                        return err;
        }
 
+       for (i = qdev->rss_ring_first_cq_id; i < qdev->rx_ring_count; i++)
+               netif_napi_del(&qdev->rx_ring[i].napi);
+
        err = pci_save_state(pdev);
        if (err)
                return err;