]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/bnx2.c
Merge branch 'for-linus' of git://git.o-hand.com/linux-mfd
[linux-2.6-omap-h63xx.git] / drivers / net / bnx2.c
index 3872e51b3c851b5d0949e8db0c98560484bf7b6c..5ebde67d4297451aa9019f97105f31c76f268f7f 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/prefetch.h>
 #include <linux/cache.h>
 #include <linux/zlib.h>
+#include <linux/log2.h>
 
 #include "bnx2.h"
 #include "bnx2_fw.h"
@@ -56,8 +57,8 @@
 
 #define DRV_MODULE_NAME                "bnx2"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "1.7.6"
-#define DRV_MODULE_RELDATE     "May 16, 2008"
+#define DRV_MODULE_VERSION     "1.7.9"
+#define DRV_MODULE_RELDATE     "July 18, 2008"
 
 #define RUN_AT(x) (jiffies + (x))
 
@@ -68,7 +69,7 @@ static char version[] __devinitdata =
        "Broadcom NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
 
 MODULE_AUTHOR("Michael Chan <mchan@broadcom.com>");
-MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708 Driver");
+MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709 Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_MODULE_VERSION);
 
@@ -87,6 +88,7 @@ typedef enum {
        BCM5708S,
        BCM5709,
        BCM5709S,
+       BCM5716,
 } board_t;
 
 /* indexed by board_t, above */
@@ -102,9 +104,10 @@ static struct {
        { "Broadcom NetXtreme II BCM5708 1000Base-SX" },
        { "Broadcom NetXtreme II BCM5709 1000Base-T" },
        { "Broadcom NetXtreme II BCM5709 1000Base-SX" },
+       { "Broadcom NetXtreme II BCM5716 1000Base-T" },
        };
 
-static struct pci_device_id bnx2_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(bnx2_pci_tbl) = {
        { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
          PCI_VENDOR_ID_HP, 0x3101, 0, 0, NC370T },
        { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
@@ -123,6 +126,8 @@ static struct pci_device_id bnx2_pci_tbl[] = {
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709 },
        { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709S,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709S },
+       { PCI_VENDOR_ID_BROADCOM, 0x163b,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716 },
        { 0, }
 };
 
@@ -289,7 +294,6 @@ bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
                REG_WR(bp, BNX2_CTX_CTX_CTRL,
                       offset | BNX2_CTX_CTX_CTRL_WRITE_REQ);
                for (i = 0; i < 5; i++) {
-                       u32 val;
                        val = REG_RD(bp, BNX2_CTX_CTX_CTRL);
                        if ((val & BNX2_CTX_CTX_CTRL_WRITE_REQ) == 0)
                                break;
@@ -488,7 +492,7 @@ bnx2_netif_start(struct bnx2 *bp)
 {
        if (atomic_dec_and_test(&bp->intr_sem)) {
                if (netif_running(bp->dev)) {
-                       netif_wake_queue(bp->dev);
+                       netif_tx_wake_all_queues(bp->dev);
                        bnx2_napi_enable(bp);
                        bnx2_enable_int(bp);
                }
@@ -1487,7 +1491,7 @@ bnx2_phy_get_pause_adv(struct bnx2 *bp)
        return adv;
 }
 
-static int bnx2_fw_sync(struct bnx2 *, u32, int);
+static int bnx2_fw_sync(struct bnx2 *, u32, int, int);
 
 static int
 bnx2_setup_remote_phy(struct bnx2 *bp, u8 port)
@@ -1540,7 +1544,7 @@ bnx2_setup_remote_phy(struct bnx2 *bp, u8 port)
        bnx2_shmem_wr(bp, BNX2_DRV_MB_ARG0, speed_arg);
 
        spin_unlock_bh(&bp->phy_lock);
-       bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 0);
+       bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 1, 0);
        spin_lock_bh(&bp->phy_lock);
 
        return 0;
@@ -2258,7 +2262,7 @@ bnx2_set_phy_loopback(struct bnx2 *bp)
 }
 
 static int
-bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int silent)
+bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int ack, int silent)
 {
        int i;
        u32 val;
@@ -2268,6 +2272,9 @@ bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int silent)
 
        bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
 
+       if (!ack)
+               return 0;
+
        /* wait for an acknowledgement. */
        for (i = 0; i < (FW_ACK_TIME_OUT_MS / 10); i++) {
                msleep(10);
@@ -2444,19 +2451,18 @@ bnx2_alloc_bad_rbuf(struct bnx2 *bp)
 }
 
 static void
-bnx2_set_mac_addr(struct bnx2 *bp)
+bnx2_set_mac_addr(struct bnx2 *bp, u8 *mac_addr, u32 pos)
 {
        u32 val;
-       u8 *mac_addr = bp->dev->dev_addr;
 
        val = (mac_addr[0] << 8) | mac_addr[1];
 
-       REG_WR(bp, BNX2_EMAC_MAC_MATCH0, val);
+       REG_WR(bp, BNX2_EMAC_MAC_MATCH0 + (pos * 8), val);
 
        val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
                (mac_addr[4] << 8) | mac_addr[5];
 
-       REG_WR(bp, BNX2_EMAC_MAC_MATCH1, val);
+       REG_WR(bp, BNX2_EMAC_MAC_MATCH1 + (pos * 8), val);
 }
 
 static inline int
@@ -2578,7 +2584,11 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
 {
        struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
        u16 hw_cons, sw_cons, sw_ring_cons;
-       int tx_pkt = 0;
+       int tx_pkt = 0, index;
+       struct netdev_queue *txq;
+
+       index = (bnapi - bp->bnx2_napi);
+       txq = netdev_get_tx_queue(bp->dev, index);
 
        hw_cons = bnx2_get_hw_tx_cons(bnapi);
        sw_cons = txr->tx_cons;
@@ -2638,21 +2648,23 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
 
        txr->hw_tx_cons = hw_cons;
        txr->tx_cons = sw_cons;
+
        /* Need to make the tx_cons update visible to bnx2_start_xmit()
-        * before checking for netif_queue_stopped().  Without the
+        * before checking for netif_tx_queue_stopped().  Without the
         * memory barrier, there is a small possibility that bnx2_start_xmit()
         * will miss it and cause the queue to be stopped forever.
         */
        smp_mb();
 
-       if (unlikely(netif_queue_stopped(bp->dev)) &&
+       if (unlikely(netif_tx_queue_stopped(txq)) &&
                     (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)) {
-               netif_tx_lock(bp->dev);
-               if ((netif_queue_stopped(bp->dev)) &&
+               __netif_tx_lock(txq, smp_processor_id());
+               if ((netif_tx_queue_stopped(txq)) &&
                    (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh))
-                       netif_wake_queue(bp->dev);
-               netif_tx_unlock(bp->dev);
+                       netif_tx_wake_queue(txq);
+               __netif_tx_unlock(txq);
        }
+
        return tx_pkt;
 }
 
@@ -2996,9 +3008,9 @@ next_rx:
 static irqreturn_t
 bnx2_msi(int irq, void *dev_instance)
 {
-       struct net_device *dev = dev_instance;
-       struct bnx2 *bp = netdev_priv(dev);
-       struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
+       struct bnx2_napi *bnapi = dev_instance;
+       struct bnx2 *bp = bnapi->bp;
+       struct net_device *dev = bp->dev;
 
        prefetch(bnapi->status_blk.msi);
        REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
@@ -3017,9 +3029,9 @@ bnx2_msi(int irq, void *dev_instance)
 static irqreturn_t
 bnx2_msi_1shot(int irq, void *dev_instance)
 {
-       struct net_device *dev = dev_instance;
-       struct bnx2 *bp = netdev_priv(dev);
-       struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
+       struct bnx2_napi *bnapi = dev_instance;
+       struct bnx2 *bp = bnapi->bp;
+       struct net_device *dev = bp->dev;
 
        prefetch(bnapi->status_blk.msi);
 
@@ -3035,9 +3047,9 @@ bnx2_msi_1shot(int irq, void *dev_instance)
 static irqreturn_t
 bnx2_interrupt(int irq, void *dev_instance)
 {
-       struct net_device *dev = dev_instance;
-       struct bnx2 *bp = netdev_priv(dev);
-       struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
+       struct bnx2_napi *bnapi = dev_instance;
+       struct bnx2 *bp = bnapi->bp;
+       struct net_device *dev = bp->dev;
        struct status_block *sblk = bnapi->status_blk.msi;
 
        /* When using INTx, it is possible for the interrupt to arrive
@@ -3072,23 +3084,6 @@ bnx2_interrupt(int irq, void *dev_instance)
        return IRQ_HANDLED;
 }
 
-static irqreturn_t
-bnx2_tx_msix(int irq, void *dev_instance)
-{
-       struct net_device *dev = dev_instance;
-       struct bnx2 *bp = netdev_priv(dev);
-       struct bnx2_napi *bnapi = &bp->bnx2_napi[BNX2_TX_VEC];
-
-       prefetch(bnapi->status_blk.msix);
-
-       /* Return here if interrupt is disabled. */
-       if (unlikely(atomic_read(&bp->intr_sem) != 0))
-               return IRQ_HANDLED;
-
-       netif_rx_schedule(dev, &bnapi->napi);
-       return IRQ_HANDLED;
-}
-
 static inline int
 bnx2_has_fast_work(struct bnx2_napi *bnapi)
 {
@@ -3119,30 +3114,6 @@ bnx2_has_work(struct bnx2_napi *bnapi)
        return 0;
 }
 
-static int bnx2_tx_poll(struct napi_struct *napi, int budget)
-{
-       struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
-       struct bnx2 *bp = bnapi->bp;
-       struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
-       int work_done = 0;
-       struct status_block_msix *sblk = bnapi->status_blk.msix;
-
-       do {
-               work_done += bnx2_tx_int(bp, bnapi, budget - work_done);
-               if (unlikely(work_done >= budget))
-                       return work_done;
-
-               bnapi->last_status_idx = sblk->status_idx;
-               rmb();
-       } while (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons);
-
-       netif_rx_complete(bp->dev, napi);
-       REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
-              BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
-              bnapi->last_status_idx);
-       return work_done;
-}
-
 static void bnx2_poll_link(struct bnx2 *bp, struct bnx2_napi *bnapi)
 {
        struct status_block *sblk = bnapi->status_blk.msi;
@@ -3178,6 +3149,33 @@ static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi,
        return work_done;
 }
 
+static int bnx2_poll_msix(struct napi_struct *napi, int budget)
+{
+       struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
+       struct bnx2 *bp = bnapi->bp;
+       int work_done = 0;
+       struct status_block_msix *sblk = bnapi->status_blk.msix;
+
+       while (1) {
+               work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
+               if (unlikely(work_done >= budget))
+                       break;
+
+               bnapi->last_status_idx = sblk->status_idx;
+               /* status idx must be read before checking for more work. */
+               rmb();
+               if (likely(!bnx2_has_fast_work(bnapi))) {
+
+                       netif_rx_complete(bp->dev, napi);
+                       REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
+                              BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
+                              bnapi->last_status_idx);
+                       break;
+               }
+       }
+       return work_done;
+}
+
 static int bnx2_poll(struct napi_struct *napi, int budget)
 {
        struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
@@ -3230,6 +3228,7 @@ bnx2_set_rx_mode(struct net_device *dev)
 {
        struct bnx2 *bp = netdev_priv(dev);
        u32 rx_mode, sort_mode;
+       struct dev_addr_list *uc_ptr;
        int i;
 
        spin_lock_bh(&bp->phy_lock);
@@ -3285,6 +3284,25 @@ bnx2_set_rx_mode(struct net_device *dev)
                sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN;
        }
 
+       uc_ptr = NULL;
+       if (dev->uc_count > BNX2_MAX_UNICAST_ADDRESSES) {
+               rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
+               sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
+                            BNX2_RPM_SORT_USER0_PROM_VLAN;
+       } else if (!(dev->flags & IFF_PROMISC)) {
+               uc_ptr = dev->uc_list;
+
+               /* Add all entries into to the match filter list */
+               for (i = 0; i < dev->uc_count; i++) {
+                       bnx2_set_mac_addr(bp, uc_ptr->da_addr,
+                                         i + BNX2_START_UNICAST_ADDRESS_INDEX);
+                       sort_mode |= (1 <<
+                                     (i + BNX2_START_UNICAST_ADDRESS_INDEX));
+                       uc_ptr = uc_ptr->next;
+               }
+
+       }
+
        if (rx_mode != bp->rx_mode) {
                bp->rx_mode = rx_mode;
                REG_WR(bp, BNX2_EMAC_RX_MODE, rx_mode);
@@ -3569,7 +3587,7 @@ bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
                        bp->autoneg = autoneg;
                        bp->advertising = advertising;
 
-                       bnx2_set_mac_addr(bp);
+                       bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
 
                        val = REG_RD(bp, BNX2_EMAC_MODE);
 
@@ -3620,7 +3638,8 @@ bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
                }
 
                if (!(bp->flags & BNX2_FLAG_NO_WOL))
-                       bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg, 0);
+                       bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg,
+                                    1, 0);
 
                pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
                if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
@@ -4261,35 +4280,43 @@ nvram_write_end:
 }
 
 static void
-bnx2_init_remote_phy(struct bnx2 *bp)
+bnx2_init_fw_cap(struct bnx2 *bp)
 {
-       u32 val;
+       u32 val, sig = 0;
 
        bp->phy_flags &= ~BNX2_PHY_FLAG_REMOTE_PHY_CAP;
-       if (!(bp->phy_flags & BNX2_PHY_FLAG_SERDES))
-               return;
+       bp->flags &= ~BNX2_FLAG_CAN_KEEP_VLAN;
+
+       if (!(bp->flags & BNX2_FLAG_ASF_ENABLE))
+               bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
 
        val = bnx2_shmem_rd(bp, BNX2_FW_CAP_MB);
        if ((val & BNX2_FW_CAP_SIGNATURE_MASK) != BNX2_FW_CAP_SIGNATURE)
                return;
 
-       if (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE) {
+       if ((val & BNX2_FW_CAP_CAN_KEEP_VLAN) == BNX2_FW_CAP_CAN_KEEP_VLAN) {
+               bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN;
+               sig |= BNX2_DRV_ACK_CAP_SIGNATURE | BNX2_FW_CAP_CAN_KEEP_VLAN;
+       }
+
+       if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
+           (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE)) {
+               u32 link;
+
                bp->phy_flags |= BNX2_PHY_FLAG_REMOTE_PHY_CAP;
 
-               val = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
-               if (val & BNX2_LINK_STATUS_SERDES_LINK)
+               link = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
+               if (link & BNX2_LINK_STATUS_SERDES_LINK)
                        bp->phy_port = PORT_FIBRE;
                else
                        bp->phy_port = PORT_TP;
 
-               if (netif_running(bp->dev)) {
-                       u32 sig;
-
-                       sig = BNX2_DRV_ACK_CAP_SIGNATURE |
-                             BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
-                       bnx2_shmem_wr(bp, BNX2_DRV_ACK_CAP_MB, sig);
-               }
+               sig |= BNX2_DRV_ACK_CAP_SIGNATURE |
+                      BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
        }
+
+       if (netif_running(bp->dev) && sig)
+               bnx2_shmem_wr(bp, BNX2_DRV_ACK_CAP_MB, sig);
 }
 
 static void
@@ -4319,7 +4346,7 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
        udelay(5);
 
        /* Wait for the firmware to tell us it is ok to issue a reset. */
-       bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code, 1);
+       bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code, 1, 1);
 
        /* Deposit a driver reset signature so the firmware knows that
         * this is a soft reset. */
@@ -4380,13 +4407,13 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
        }
 
        /* Wait for the firmware to finish its initialization. */
-       rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT1 | reset_code, 0);
+       rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT1 | reset_code, 1, 0);
        if (rc)
                return rc;
 
        spin_lock_bh(&bp->phy_lock);
        old_port = bp->phy_port;
-       bnx2_init_remote_phy(bp);
+       bnx2_init_fw_cap(bp);
        if ((bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) &&
            old_port != bp->phy_port)
                bnx2_set_default_remote_link(bp);
@@ -4470,7 +4497,7 @@ bnx2_init_chip(struct bnx2 *bp)
 
        bnx2_init_nvram(bp);
 
-       bnx2_set_mac_addr(bp);
+       bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
 
        val = REG_RD(bp, BNX2_MQ_CONFIG);
        val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
@@ -4556,15 +4583,25 @@ bnx2_init_chip(struct bnx2 *bp)
                      BNX2_HC_CONFIG_COLLECT_STATS;
        }
 
-       if (bp->flags & BNX2_FLAG_USING_MSIX) {
-               u32 base = ((BNX2_TX_VEC - 1) * BNX2_HC_SB_CONFIG_SIZE) +
-                          BNX2_HC_SB_CONFIG_1;
-
+       if (bp->irq_nvecs > 1) {
                REG_WR(bp, BNX2_HC_MSIX_BIT_VECTOR,
                       BNX2_HC_MSIX_BIT_VECTOR_VAL);
 
+               val |= BNX2_HC_CONFIG_SB_ADDR_INC_128B;
+       }
+
+       if (bp->flags & BNX2_FLAG_ONE_SHOT_MSI)
+               val |= BNX2_HC_CONFIG_ONE_SHOT;
+
+       REG_WR(bp, BNX2_HC_CONFIG, val);
+
+       for (i = 1; i < bp->irq_nvecs; i++) {
+               u32 base = ((i - 1) * BNX2_HC_SB_CONFIG_SIZE) +
+                          BNX2_HC_SB_CONFIG_1;
+
                REG_WR(bp, base,
                        BNX2_HC_SB_CONFIG_1_TX_TMR_MODE |
+                       BNX2_HC_SB_CONFIG_1_RX_TMR_MODE |
                        BNX2_HC_SB_CONFIG_1_ONE_SHOT);
 
                REG_WR(bp, base + BNX2_HC_TX_QUICK_CONS_TRIP_OFF,
@@ -4574,13 +4611,13 @@ bnx2_init_chip(struct bnx2 *bp)
                REG_WR(bp, base + BNX2_HC_TX_TICKS_OFF,
                        (bp->tx_ticks_int << 16) | bp->tx_ticks);
 
-               val |= BNX2_HC_CONFIG_SB_ADDR_INC_128B;
-       }
+               REG_WR(bp, base + BNX2_HC_RX_QUICK_CONS_TRIP_OFF,
+                      (bp->rx_quick_cons_trip_int << 16) |
+                       bp->rx_quick_cons_trip);
 
-       if (bp->flags & BNX2_FLAG_ONE_SHOT_MSI)
-               val |= BNX2_HC_CONFIG_ONE_SHOT;
-
-       REG_WR(bp, BNX2_HC_CONFIG, val);
+               REG_WR(bp, base + BNX2_HC_RX_TICKS_OFF,
+                       (bp->rx_ticks_int << 16) | bp->rx_ticks);
+       }
 
        /* Clear internal stats counters. */
        REG_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW);
@@ -4596,7 +4633,7 @@ bnx2_init_chip(struct bnx2 *bp)
                REG_WR(bp, BNX2_MISC_NEW_CORE_CTL, val);
        }
        rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT2 | BNX2_DRV_MSG_CODE_RESET,
-                         0);
+                         1, 0);
 
        REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS, BNX2_MISC_ENABLE_DEFAULT);
        REG_RD(bp, BNX2_MISC_ENABLE_SET_BITS);
@@ -4751,7 +4788,7 @@ bnx2_init_rx_ring(struct bnx2 *bp, int ring_num)
                val = (bp->rx_buf_use_size << 16) | PAGE_SIZE;
                bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, val);
                bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_RBDC_KEY,
-                      BNX2_L2CTX_RBDC_JUMBO_KEY);
+                      BNX2_L2CTX_RBDC_JUMBO_KEY - ring_num);
 
                val = (u64) rxr->rx_pg_desc_mapping[0] >> 32;
                bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_HI, val);
@@ -4801,6 +4838,7 @@ static void
 bnx2_init_all_rings(struct bnx2 *bp)
 {
        int i;
+       u32 val;
 
        bnx2_clear_ring_states(bp);
 
@@ -4812,8 +4850,33 @@ bnx2_init_all_rings(struct bnx2 *bp)
                REG_WR(bp, BNX2_TSCH_TSS_CFG, ((bp->num_tx_rings - 1) << 24) |
                       (TX_TSS_CID << 7));
 
+       REG_WR(bp, BNX2_RLUP_RSS_CONFIG, 0);
+       bnx2_reg_wr_ind(bp, BNX2_RXP_SCRATCH_RSS_TBL_SZ, 0);
+
        for (i = 0; i < bp->num_rx_rings; i++)
                bnx2_init_rx_ring(bp, i);
+
+       if (bp->num_rx_rings > 1) {
+               u32 tbl_32;
+               u8 *tbl = (u8 *) &tbl_32;
+
+               bnx2_reg_wr_ind(bp, BNX2_RXP_SCRATCH_RSS_TBL_SZ,
+                               BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES);
+
+               for (i = 0; i < BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES; i++) {
+                       tbl[i % 4] = i % (bp->num_rx_rings - 1);
+                       if ((i % 4) == 3)
+                               bnx2_reg_wr_ind(bp,
+                                               BNX2_RXP_SCRATCH_RSS_TBL + i,
+                                               cpu_to_be32(tbl_32));
+               }
+
+               val = BNX2_RLUP_RSS_CONFIG_IPV4_RSS_TYPE_ALL_XI |
+                     BNX2_RLUP_RSS_CONFIG_IPV6_RSS_TYPE_ALL_XI;
+
+               REG_WR(bp, BNX2_RLUP_RSS_CONFIG, val);
+
+       }
 }
 
 static u32 bnx2_find_max_ring(u32 ring_size, u32 max_size)
@@ -5636,7 +5699,6 @@ bnx2_restart_timer:
 static int
 bnx2_request_irq(struct bnx2 *bp)
 {
-       struct net_device *dev = bp->dev;
        unsigned long flags;
        struct bnx2_irq *irq;
        int rc = 0, i;
@@ -5649,7 +5711,7 @@ bnx2_request_irq(struct bnx2 *bp)
        for (i = 0; i < bp->irq_nvecs; i++) {
                irq = &bp->irq_tbl[i];
                rc = request_irq(irq->vector, irq->handler, flags, irq->name,
-                                dev);
+                                &bp->bnx2_napi[i]);
                if (rc)
                        break;
                irq->requested = 1;
@@ -5660,14 +5722,13 @@ bnx2_request_irq(struct bnx2 *bp)
 static void
 bnx2_free_irq(struct bnx2 *bp)
 {
-       struct net_device *dev = bp->dev;
        struct bnx2_irq *irq;
        int i;
 
        for (i = 0; i < bp->irq_nvecs; i++) {
                irq = &bp->irq_tbl[i];
                if (irq->requested)
-                       free_irq(irq->vector, dev);
+                       free_irq(irq->vector, &bp->bnx2_napi[i]);
                irq->requested = 0;
        }
        if (bp->flags & BNX2_FLAG_USING_MSI)
@@ -5679,7 +5740,7 @@ bnx2_free_irq(struct bnx2 *bp)
 }
 
 static void
-bnx2_enable_msix(struct bnx2 *bp)
+bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)
 {
        int i, rc;
        struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC];
@@ -5694,17 +5755,14 @@ bnx2_enable_msix(struct bnx2 *bp)
                msix_ent[i].vector = 0;
 
                strcpy(bp->irq_tbl[i].name, bp->dev->name);
-               if (i == 0)
-                       bp->irq_tbl[i].handler = bnx2_msi_1shot;
-               else
-                       bp->irq_tbl[i].handler = bnx2_tx_msix;
+               bp->irq_tbl[i].handler = bnx2_msi_1shot;
        }
 
        rc = pci_enable_msix(bp->pdev, msix_ent, BNX2_MAX_MSIX_VEC);
        if (rc != 0)
                return;
 
-       bp->irq_nvecs = BNX2_MAX_MSIX_VEC;
+       bp->irq_nvecs = msix_vecs;
        bp->flags |= BNX2_FLAG_USING_MSIX | BNX2_FLAG_ONE_SHOT_MSI;
        for (i = 0; i < BNX2_MAX_MSIX_VEC; i++)
                bp->irq_tbl[i].vector = msix_ent[i].vector;
@@ -5713,13 +5771,16 @@ bnx2_enable_msix(struct bnx2 *bp)
 static void
 bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi)
 {
+       int cpus = num_online_cpus();
+       int msix_vecs = min(cpus + 1, RX_MAX_RINGS);
+
        bp->irq_tbl[0].handler = bnx2_interrupt;
        strcpy(bp->irq_tbl[0].name, bp->dev->name);
        bp->irq_nvecs = 1;
        bp->irq_tbl[0].vector = bp->pdev->irq;
 
-       if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi)
-               bnx2_enable_msix(bp);
+       if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi && cpus > 1)
+               bnx2_enable_msix(bp, msix_vecs);
 
        if ((bp->flags & BNX2_FLAG_MSI_CAP) && !dis_msi &&
            !(bp->flags & BNX2_FLAG_USING_MSIX)) {
@@ -5734,8 +5795,11 @@ bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi)
                        bp->irq_tbl[0].vector = bp->pdev->irq;
                }
        }
-       bp->num_tx_rings = 1;
-       bp->num_rx_rings = 1;
+
+       bp->num_tx_rings = rounddown_pow_of_two(bp->irq_nvecs);
+       bp->dev->real_num_tx_queues = bp->num_tx_rings;
+
+       bp->num_rx_rings = bp->irq_nvecs;
 }
 
 /* Called with rtnl_lock */
@@ -5753,29 +5817,16 @@ bnx2_open(struct net_device *dev)
        bnx2_setup_int_mode(bp, disable_msi);
        bnx2_napi_enable(bp);
        rc = bnx2_alloc_mem(bp);
-       if (rc) {
-               bnx2_napi_disable(bp);
-               bnx2_free_mem(bp);
-               return rc;
-       }
+       if (rc)
+               goto open_err;
 
        rc = bnx2_request_irq(bp);
-
-       if (rc) {
-               bnx2_napi_disable(bp);
-               bnx2_free_mem(bp);
-               return rc;
-       }
+       if (rc)
+               goto open_err;
 
        rc = bnx2_init_nic(bp, 1);
-
-       if (rc) {
-               bnx2_napi_disable(bp);
-               bnx2_free_irq(bp);
-               bnx2_free_skbs(bp);
-               bnx2_free_mem(bp);
-               return rc;
-       }
+       if (rc)
+               goto open_err;
 
        mod_timer(&bp->timer, jiffies + bp->current_interval);
 
@@ -5805,11 +5856,8 @@ bnx2_open(struct net_device *dev)
                                rc = bnx2_request_irq(bp);
 
                        if (rc) {
-                               bnx2_napi_disable(bp);
-                               bnx2_free_skbs(bp);
-                               bnx2_free_mem(bp);
                                del_timer_sync(&bp->timer);
-                               return rc;
+                               goto open_err;
                        }
                        bnx2_enable_int(bp);
                }
@@ -5819,9 +5867,16 @@ bnx2_open(struct net_device *dev)
        else if (bp->flags & BNX2_FLAG_USING_MSIX)
                printk(KERN_INFO PFX "%s: using MSIX\n", dev->name);
 
-       netif_start_queue(dev);
+       netif_tx_start_all_queues(dev);
 
        return 0;
+
+open_err:
+       bnx2_napi_disable(bp);
+       bnx2_free_skbs(bp);
+       bnx2_free_irq(bp);
+       bnx2_free_mem(bp);
+       return rc;
 }
 
 static void
@@ -5860,6 +5915,8 @@ bnx2_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp)
 
        bp->vlgrp = vlgrp;
        bnx2_set_rx_mode(dev);
+       if (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN)
+               bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_KEEP_VLAN_UPDATE, 0, 1);
 
        bnx2_netif_start(bp);
 }
@@ -5879,12 +5936,19 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
        u32 len, vlan_tag_flags, last_frag, mss;
        u16 prod, ring_prod;
        int i;
-       struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
-       struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
+       struct bnx2_napi *bnapi;
+       struct bnx2_tx_ring_info *txr;
+       struct netdev_queue *txq;
+
+       /*  Determine which tx ring we will be placed on */
+       i = skb_get_queue_mapping(skb);
+       bnapi = &bp->bnx2_napi[i];
+       txr = &bnapi->tx_ring;
+       txq = netdev_get_tx_queue(dev, i);
 
        if (unlikely(bnx2_tx_avail(bp, txr) <
            (skb_shinfo(skb)->nr_frags + 1))) {
-               netif_stop_queue(dev);
+               netif_tx_stop_queue(txq);
                printk(KERN_ERR PFX "%s: BUG! Tx ring full when queue awake!\n",
                        dev->name);
 
@@ -5999,9 +6063,9 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
        dev->trans_start = jiffies;
 
        if (unlikely(bnx2_tx_avail(bp, txr) <= MAX_SKB_FRAGS)) {
-               netif_stop_queue(dev);
+               netif_tx_stop_queue(txq);
                if (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)
-                       netif_wake_queue(dev);
+                       netif_tx_wake_queue(txq);
        }
 
        return NETDEV_TX_OK;
@@ -6204,6 +6268,12 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
            !(bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP))
                goto err_out_unlock;
 
+       /* If device is down, we can store the settings only if the user
+        * is setting the currently active port.
+        */
+       if (!netif_running(dev) && cmd->port != bp->phy_port)
+               goto err_out_unlock;
+
        if (cmd->autoneg == AUTONEG_ENABLE) {
                autoneg |= AUTONEG_SPEED;
 
@@ -6261,7 +6331,12 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        bp->req_line_speed = req_line_speed;
        bp->req_duplex = req_duplex;
 
-       err = bnx2_setup_phy(bp, cmd->port);
+       err = 0;
+       /* If device is down, the new settings will be picked up when it is
+        * brought up.
+        */
+       if (netif_running(dev))
+               err = bnx2_setup_phy(bp, cmd->port);
 
 err_out_unlock:
        spin_unlock_bh(&bp->phy_lock);
@@ -7060,7 +7135,7 @@ bnx2_change_mac_addr(struct net_device *dev, void *p)
 
        memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
        if (netif_running(dev))
-               bnx2_set_mac_addr(bp);
+               bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0);
 
        return 0;
 }
@@ -7235,7 +7310,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
        INIT_WORK(&bp->reset_task, bnx2_reset_task);
 
        dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0);
-       mem_len = MB_GET_CID_ADDR(TX_TSS_CID + 1);
+       mem_len = MB_GET_CID_ADDR(TX_TSS_CID + TX_MAX_TSS_RINGS);
        dev->mem_end = dev->mem_start + mem_len;
        dev->irq = pdev->irq;
 
@@ -7382,7 +7457,6 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
        reg &= BNX2_CONDITION_MFW_RUN_MASK;
        if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN &&
            reg != BNX2_CONDITION_MFW_RUN_NONE) {
-               int i;
                u32 addr = bnx2_shmem_rd(bp, BNX2_MFW_VER_PTR);
 
                bp->fw_version[j++] = ' ';
@@ -7453,8 +7527,6 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
                        if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
                                bp->phy_flags |= BNX2_PHY_FLAG_2_5G_CAPABLE;
                }
-               bnx2_init_remote_phy(bp);
-
        } else if (CHIP_NUM(bp) == CHIP_NUM_5706 ||
                   CHIP_NUM(bp) == CHIP_NUM_5708)
                bp->phy_flags |= BNX2_PHY_FLAG_CRC_FIX;
@@ -7463,6 +7535,8 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
                  CHIP_REV(bp) == CHIP_REV_Bx))
                bp->phy_flags |= BNX2_PHY_FLAG_DIS_EARLY_DAC;
 
+       bnx2_init_fw_cap(bp);
+
        if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
            (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
            (CHIP_ID(bp) == CHIP_ID_5708_B1)) {
@@ -7567,7 +7641,7 @@ bnx2_init_napi(struct bnx2 *bp)
                if (i == 0)
                        poll = bnx2_poll;
                else
-                       poll = bnx2_tx_poll;
+                       poll = bnx2_poll_msix;
 
                netif_napi_add(bp->dev, &bp->bnx2_napi[i].napi, poll, 64);
                bnapi->bp = bp;
@@ -7588,7 +7662,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                printk(KERN_INFO "%s", version);
 
        /* dev zeroed in init_etherdev */
-       dev = alloc_etherdev(sizeof(*bp));
+       dev = alloc_etherdev_mq(sizeof(*bp), TX_MAX_RINGS);
 
        if (!dev)
                return -ENOMEM;
@@ -7603,7 +7677,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        dev->hard_start_xmit = bnx2_start_xmit;
        dev->stop = bnx2_close;
        dev->get_stats = bnx2_get_stats;
-       dev->set_multicast_list = bnx2_set_rx_mode;
+       dev->set_rx_mode = bnx2_set_rx_mode;
        dev->do_ioctl = bnx2_ioctl;
        dev->set_mac_address = bnx2_change_mac_addr;
        dev->change_mtu = bnx2_change_mtu;