bnx2x: Introduce 2013 and advance version to 1.78.02
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / net / ethernet / broadcom / bnx2x / bnx2x_main.c
index 940ef859dc6054338b884abce2c519e0ba4a89ea..af7af0894d70e86a60673196fda78e1da3b8da94 100644 (file)
@@ -1,6 +1,6 @@
 /* bnx2x_main.c: Broadcom Everest network driver.
  *
- * Copyright (c) 2007-2012 Broadcom Corporation
+ * Copyright (c) 2007-2013 Broadcom Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -59,6 +59,7 @@
 #include "bnx2x_init.h"
 #include "bnx2x_init_ops.h"
 #include "bnx2x_cmn.h"
+#include "bnx2x_vfpf.h"
 #include "bnx2x_dcb.h"
 #include "bnx2x_sp.h"
 
@@ -127,45 +128,66 @@ MODULE_PARM_DESC(debug, " Default debug msglevel");
 
 struct workqueue_struct *bnx2x_wq;
 
+struct bnx2x_mac_vals {
+       u32 xmac_addr;
+       u32 xmac_val;
+       u32 emac_addr;
+       u32 emac_val;
+       u32 umac_addr;
+       u32 umac_val;
+       u32 bmac_addr;
+       u32 bmac_val[2];
+};
+
 enum bnx2x_board_type {
        BCM57710 = 0,
        BCM57711,
        BCM57711E,
        BCM57712,
        BCM57712_MF,
+       BCM57712_VF,
        BCM57800,
        BCM57800_MF,
+       BCM57800_VF,
        BCM57810,
        BCM57810_MF,
-       BCM57840_O,
+       BCM57810_VF,
        BCM57840_4_10,
        BCM57840_2_20,
-       BCM57840_MFO,
        BCM57840_MF,
+       BCM57840_VF,
        BCM57811,
-       BCM57811_MF
+       BCM57811_MF,
+       BCM57840_O,
+       BCM57840_MFO,
+       BCM57811_VF
 };
 
 /* indexed by board_type, above */
 static struct {
        char *name;
 } board_info[] = {
-       { "Broadcom NetXtreme II BCM57710 10 Gigabit PCIe [Everest]" },
-       { "Broadcom NetXtreme II BCM57711 10 Gigabit PCIe" },
-       { "Broadcom NetXtreme II BCM57711E 10 Gigabit PCIe" },
-       { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet" },
-       { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet Multi Function" },
-       { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet" },
-       { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet Multi Function" },
-       { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet" },
-       { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet Multi Function" },
-       { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet" },
-       { "Broadcom NetXtreme II BCM57840 10 Gigabit Ethernet" },
-       { "Broadcom NetXtreme II BCM57840 20 Gigabit Ethernet" },
-       { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function"},
-       { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function"},
-       { "Broadcom NetXtreme II BCM57811 10 Gigabit Ethernet"},
-       { "Broadcom NetXtreme II BCM57811 10 Gigabit Ethernet Multi Function"},
+       [BCM57710]      = { "Broadcom NetXtreme II BCM57710 10 Gigabit PCIe [Everest]" },
+       [BCM57711]      = { "Broadcom NetXtreme II BCM57711 10 Gigabit PCIe" },
+       [BCM57711E]     = { "Broadcom NetXtreme II BCM57711E 10 Gigabit PCIe" },
+       [BCM57712]      = { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet" },
+       [BCM57712_MF]   = { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet Multi Function" },
+       [BCM57712_VF]   = { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet Virtual Function" },
+       [BCM57800]      = { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet" },
+       [BCM57800_MF]   = { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet Multi Function" },
+       [BCM57800_VF]   = { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet Virtual Function" },
+       [BCM57810]      = { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet" },
+       [BCM57810_MF]   = { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet Multi Function" },
+       [BCM57810_VF]   = { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet Virtual Function" },
+       [BCM57840_4_10] = { "Broadcom NetXtreme II BCM57840 10 Gigabit Ethernet" },
+       [BCM57840_2_20] = { "Broadcom NetXtreme II BCM57840 20 Gigabit Ethernet" },
+       [BCM57840_MF]   = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function" },
+       [BCM57840_VF]   = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Virtual Function" },
+       [BCM57811]      = { "Broadcom NetXtreme II BCM57811 10 Gigabit Ethernet" },
+       [BCM57811_MF]   = { "Broadcom NetXtreme II BCM57811 10 Gigabit Ethernet Multi Function" },
+       [BCM57840_O]    = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet" },
+       [BCM57840_MFO]  = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function" },
+       [BCM57811_VF]   = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Virtual Function" }
 };
 
 #ifndef PCI_DEVICE_ID_NX2_57710
@@ -183,12 +205,18 @@ static struct {
 #ifndef PCI_DEVICE_ID_NX2_57712_MF
 #define PCI_DEVICE_ID_NX2_57712_MF     CHIP_NUM_57712_MF
 #endif
+#ifndef PCI_DEVICE_ID_NX2_57712_VF
+#define PCI_DEVICE_ID_NX2_57712_VF     CHIP_NUM_57712_VF
+#endif
 #ifndef PCI_DEVICE_ID_NX2_57800
 #define PCI_DEVICE_ID_NX2_57800                CHIP_NUM_57800
 #endif
 #ifndef PCI_DEVICE_ID_NX2_57800_MF
 #define PCI_DEVICE_ID_NX2_57800_MF     CHIP_NUM_57800_MF
 #endif
+#ifndef PCI_DEVICE_ID_NX2_57800_VF
+#define PCI_DEVICE_ID_NX2_57800_VF     CHIP_NUM_57800_VF
+#endif
 #ifndef PCI_DEVICE_ID_NX2_57810
 #define PCI_DEVICE_ID_NX2_57810                CHIP_NUM_57810
 #endif
@@ -198,6 +226,9 @@ static struct {
 #ifndef PCI_DEVICE_ID_NX2_57840_O
 #define PCI_DEVICE_ID_NX2_57840_O      CHIP_NUM_57840_OBSOLETE
 #endif
+#ifndef PCI_DEVICE_ID_NX2_57810_VF
+#define PCI_DEVICE_ID_NX2_57810_VF     CHIP_NUM_57810_VF
+#endif
 #ifndef PCI_DEVICE_ID_NX2_57840_4_10
 #define PCI_DEVICE_ID_NX2_57840_4_10   CHIP_NUM_57840_4_10
 #endif
@@ -210,29 +241,41 @@ static struct {
 #ifndef PCI_DEVICE_ID_NX2_57840_MF
 #define PCI_DEVICE_ID_NX2_57840_MF     CHIP_NUM_57840_MF
 #endif
+#ifndef PCI_DEVICE_ID_NX2_57840_VF
+#define PCI_DEVICE_ID_NX2_57840_VF     CHIP_NUM_57840_VF
+#endif
 #ifndef PCI_DEVICE_ID_NX2_57811
 #define PCI_DEVICE_ID_NX2_57811                CHIP_NUM_57811
 #endif
 #ifndef PCI_DEVICE_ID_NX2_57811_MF
 #define PCI_DEVICE_ID_NX2_57811_MF     CHIP_NUM_57811_MF
 #endif
+#ifndef PCI_DEVICE_ID_NX2_57811_VF
+#define PCI_DEVICE_ID_NX2_57811_VF     CHIP_NUM_57811_VF
+#endif
+
 static DEFINE_PCI_DEVICE_TABLE(bnx2x_pci_tbl) = {
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57710), BCM57710 },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711), BCM57711 },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711E), BCM57711E },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57712), BCM57712 },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57712_MF), BCM57712_MF },
+       { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57712_VF), BCM57712_VF },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57800), BCM57800 },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57800_MF), BCM57800_MF },
+       { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57800_VF), BCM57800_VF },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57810), BCM57810 },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57810_MF), BCM57810_MF },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_O), BCM57840_O },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_4_10), BCM57840_4_10 },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_2_20), BCM57840_2_20 },
+       { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57810_VF), BCM57810_VF },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_MFO), BCM57840_MFO },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_MF), BCM57840_MF },
+       { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_VF), BCM57840_VF },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57811), BCM57811 },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57811_MF), BCM57811_MF },
+       { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57811_VF), BCM57811_VF },
        { 0 }
 };
 
@@ -335,6 +378,65 @@ static u32 bnx2x_reg_rd_ind(struct bnx2x *bp, u32 addr)
 #define DMAE_DP_DST_PCI                "pci dst_addr [%x:%08x]"
 #define DMAE_DP_DST_NONE       "dst_addr [none]"
 
+void bnx2x_dp_dmae(struct bnx2x *bp, struct dmae_command *dmae, int msglvl)
+{
+       u32 src_type = dmae->opcode & DMAE_COMMAND_SRC;
+
+       switch (dmae->opcode & DMAE_COMMAND_DST) {
+       case DMAE_CMD_DST_PCI:
+               if (src_type == DMAE_CMD_SRC_PCI)
+                       DP(msglvl, "DMAE: opcode 0x%08x\n"
+                          "src [%x:%08x], len [%d*4], dst [%x:%08x]\n"
+                          "comp_addr [%x:%08x], comp_val 0x%08x\n",
+                          dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo,
+                          dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo,
+                          dmae->comp_addr_hi, dmae->comp_addr_lo,
+                          dmae->comp_val);
+               else
+                       DP(msglvl, "DMAE: opcode 0x%08x\n"
+                          "src [%08x], len [%d*4], dst [%x:%08x]\n"
+                          "comp_addr [%x:%08x], comp_val 0x%08x\n",
+                          dmae->opcode, dmae->src_addr_lo >> 2,
+                          dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo,
+                          dmae->comp_addr_hi, dmae->comp_addr_lo,
+                          dmae->comp_val);
+               break;
+       case DMAE_CMD_DST_GRC:
+               if (src_type == DMAE_CMD_SRC_PCI)
+                       DP(msglvl, "DMAE: opcode 0x%08x\n"
+                          "src [%x:%08x], len [%d*4], dst_addr [%08x]\n"
+                          "comp_addr [%x:%08x], comp_val 0x%08x\n",
+                          dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo,
+                          dmae->len, dmae->dst_addr_lo >> 2,
+                          dmae->comp_addr_hi, dmae->comp_addr_lo,
+                          dmae->comp_val);
+               else
+                       DP(msglvl, "DMAE: opcode 0x%08x\n"
+                          "src [%08x], len [%d*4], dst [%08x]\n"
+                          "comp_addr [%x:%08x], comp_val 0x%08x\n",
+                          dmae->opcode, dmae->src_addr_lo >> 2,
+                          dmae->len, dmae->dst_addr_lo >> 2,
+                          dmae->comp_addr_hi, dmae->comp_addr_lo,
+                          dmae->comp_val);
+               break;
+       default:
+               if (src_type == DMAE_CMD_SRC_PCI)
+                       DP(msglvl, "DMAE: opcode 0x%08x\n"
+                          "src_addr [%x:%08x]  len [%d * 4]  dst_addr [none]\n"
+                          "comp_addr [%x:%08x]  comp_val 0x%08x\n",
+                          dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo,
+                          dmae->len, dmae->comp_addr_hi, dmae->comp_addr_lo,
+                          dmae->comp_val);
+               else
+                       DP(msglvl, "DMAE: opcode 0x%08x\n"
+                          "src_addr [%08x]  len [%d * 4]  dst_addr [none]\n"
+                          "comp_addr [%x:%08x]  comp_val 0x%08x\n",
+                          dmae->opcode, dmae->src_addr_lo >> 2,
+                          dmae->len, dmae->comp_addr_hi, dmae->comp_addr_lo,
+                          dmae->comp_val);
+               break;
+       }
+}
 
 /* copy command into DMAE command memory and set DMAE command go */
 void bnx2x_post_dmae(struct bnx2x *bp, struct dmae_command *dmae, int idx)
@@ -385,7 +487,7 @@ u32 bnx2x_dmae_opcode(struct bnx2x *bp, u8 src_type, u8 dst_type,
        return opcode;
 }
 
-static void bnx2x_prep_dmae_with_comp(struct bnx2x *bp,
+void bnx2x_prep_dmae_with_comp(struct bnx2x *bp,
                                      struct dmae_command *dmae,
                                      u8 src_type, u8 dst_type)
 {
@@ -401,9 +503,8 @@ static void bnx2x_prep_dmae_with_comp(struct bnx2x *bp,
        dmae->comp_val = DMAE_COMP_VAL;
 }
 
-/* issue a dmae command over the init-channel and wailt for completion */
-static int bnx2x_issue_dmae_with_comp(struct bnx2x *bp,
-                                     struct dmae_command *dmae)
+/* issue a dmae command over the init-channel and wait for completion */
+int bnx2x_issue_dmae_with_comp(struct bnx2x *bp, struct dmae_command *dmae)
 {
        u32 *wb_comp = bnx2x_sp(bp, wb_comp);
        int cnt = CHIP_REV_IS_SLOW(bp) ? (400000) : 4000;
@@ -701,7 +802,71 @@ static void bnx2x_fw_dump(struct bnx2x *bp)
        bnx2x_fw_dump_lvl(bp, KERN_ERR);
 }
 
-void bnx2x_panic_dump(struct bnx2x *bp)
+static void bnx2x_hc_int_disable(struct bnx2x *bp)
+{
+       int port = BP_PORT(bp);
+       u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
+       u32 val = REG_RD(bp, addr);
+
+       /* in E1 we must use only PCI configuration space to disable
+        * MSI/MSIX capablility
+        * It's forbitten to disable IGU_PF_CONF_MSI_MSIX_EN in HC block
+        */
+       if (CHIP_IS_E1(bp)) {
+               /* Since IGU_PF_CONF_MSI_MSIX_EN still always on
+                * Use mask register to prevent from HC sending interrupts
+                * after we exit the function
+                */
+               REG_WR(bp, HC_REG_INT_MASK + port*4, 0);
+
+               val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
+                        HC_CONFIG_0_REG_INT_LINE_EN_0 |
+                        HC_CONFIG_0_REG_ATTN_BIT_EN_0);
+       } else
+               val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
+                        HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
+                        HC_CONFIG_0_REG_INT_LINE_EN_0 |
+                        HC_CONFIG_0_REG_ATTN_BIT_EN_0);
+
+       DP(NETIF_MSG_IFDOWN,
+          "write %x to HC %d (addr 0x%x)\n",
+          val, port, addr);
+
+       /* flush all outstanding writes */
+       mmiowb();
+
+       REG_WR(bp, addr, val);
+       if (REG_RD(bp, addr) != val)
+               BNX2X_ERR("BUG! proper val not read from IGU!\n");
+}
+
+static void bnx2x_igu_int_disable(struct bnx2x *bp)
+{
+       u32 val = REG_RD(bp, IGU_REG_PF_CONFIGURATION);
+
+       val &= ~(IGU_PF_CONF_MSI_MSIX_EN |
+                IGU_PF_CONF_INT_LINE_EN |
+                IGU_PF_CONF_ATTN_BIT_EN);
+
+       DP(NETIF_MSG_IFDOWN, "write %x to IGU\n", val);
+
+       /* flush all outstanding writes */
+       mmiowb();
+
+       REG_WR(bp, IGU_REG_PF_CONFIGURATION, val);
+       if (REG_RD(bp, IGU_REG_PF_CONFIGURATION) != val)
+               BNX2X_ERR("BUG! proper val not read from IGU!\n");
+}
+
+static void bnx2x_int_disable(struct bnx2x *bp)
+{
+       if (bp->common.int_block == INT_BLOCK_HC)
+               bnx2x_hc_int_disable(bp);
+       else
+               bnx2x_igu_int_disable(bp);
+}
+
+void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
 {
        int i;
        u16 j;
@@ -711,6 +876,8 @@ void bnx2x_panic_dump(struct bnx2x *bp)
        u16 start = 0, end = 0;
        u8 cos;
 #endif
+       if (disable_int)
+               bnx2x_int_disable(bp);
 
        bp->stats_state = STATS_STATE_DISABLED;
        bp->eth_stats.unrecoverable_error++;
@@ -1027,8 +1194,8 @@ static u32 bnx2x_flr_clnup_reg_poll(struct bnx2x *bp, u32 reg,
        return val;
 }
 
-static int bnx2x_flr_clnup_poll_hw_counter(struct bnx2x *bp, u32 reg,
-                                          char *msg, u32 poll_cnt)
+int bnx2x_flr_clnup_poll_hw_counter(struct bnx2x *bp, u32 reg,
+                                   char *msg, u32 poll_cnt)
 {
        u32 val = bnx2x_flr_clnup_reg_poll(bp, reg, 0, poll_cnt);
        if (val != 0) {
@@ -1038,7 +1205,8 @@ static int bnx2x_flr_clnup_poll_hw_counter(struct bnx2x *bp, u32 reg,
        return 0;
 }
 
-static u32 bnx2x_flr_clnup_poll_count(struct bnx2x *bp)
+/* Common routines with VF FLR cleanup */
+u32 bnx2x_flr_clnup_poll_count(struct bnx2x *bp)
 {
        /* adjust polling timeout */
        if (CHIP_REV_IS_EMUL(bp))
@@ -1050,7 +1218,7 @@ static u32 bnx2x_flr_clnup_poll_count(struct bnx2x *bp)
        return FLR_POLL_CNT;
 }
 
-static void bnx2x_tx_hw_flushed(struct bnx2x *bp, u32 poll_count)
+void bnx2x_tx_hw_flushed(struct bnx2x *bp, u32 poll_count)
 {
        struct pbf_pN_cmd_regs cmd_regs[] = {
                {0, (CHIP_IS_E3B0(bp)) ?
@@ -1125,8 +1293,7 @@ static void bnx2x_tx_hw_flushed(struct bnx2x *bp, u32 poll_count)
        (((index) << SDM_OP_GEN_AGG_VECT_IDX_SHIFT) & SDM_OP_GEN_AGG_VECT_IDX)
 
 
-static int bnx2x_send_final_clnup(struct bnx2x *bp, u8 clnup_func,
-                                        u32 poll_cnt)
+int bnx2x_send_final_clnup(struct bnx2x *bp, u8 clnup_func, u32 poll_cnt)
 {
        struct sdm_op_gen op_gen = {0};
 
@@ -1151,7 +1318,8 @@ static int bnx2x_send_final_clnup(struct bnx2x *bp, u8 clnup_func,
                BNX2X_ERR("FW final cleanup did not succeed\n");
                DP(BNX2X_MSG_SP, "At timeout completion address contained %x\n",
                   (REG_RD(bp, comp_addr)));
-               ret = 1;
+               bnx2x_panic();
+               return 1;
        }
        /* Zero completion for nxt FLR */
        REG_WR(bp, comp_addr, 0);
@@ -1159,7 +1327,7 @@ static int bnx2x_send_final_clnup(struct bnx2x *bp, u8 clnup_func,
        return ret;
 }
 
-static u8 bnx2x_is_pcie_pending(struct pci_dev *dev)
+u8 bnx2x_is_pcie_pending(struct pci_dev *dev)
 {
        u16 status;
 
@@ -1371,26 +1539,31 @@ static void bnx2x_igu_int_enable(struct bnx2x *bp)
        if (msix) {
                val &= ~(IGU_PF_CONF_INT_LINE_EN |
                         IGU_PF_CONF_SINGLE_ISR_EN);
-               val |= (IGU_PF_CONF_FUNC_EN |
-                       IGU_PF_CONF_MSI_MSIX_EN |
+               val |= (IGU_PF_CONF_MSI_MSIX_EN |
                        IGU_PF_CONF_ATTN_BIT_EN);
 
                if (single_msix)
                        val |= IGU_PF_CONF_SINGLE_ISR_EN;
        } else if (msi) {
                val &= ~IGU_PF_CONF_INT_LINE_EN;
-               val |= (IGU_PF_CONF_FUNC_EN |
-                       IGU_PF_CONF_MSI_MSIX_EN |
+               val |= (IGU_PF_CONF_MSI_MSIX_EN |
                        IGU_PF_CONF_ATTN_BIT_EN |
                        IGU_PF_CONF_SINGLE_ISR_EN);
        } else {
                val &= ~IGU_PF_CONF_MSI_MSIX_EN;
-               val |= (IGU_PF_CONF_FUNC_EN |
-                       IGU_PF_CONF_INT_LINE_EN |
+               val |= (IGU_PF_CONF_INT_LINE_EN |
                        IGU_PF_CONF_ATTN_BIT_EN |
                        IGU_PF_CONF_SINGLE_ISR_EN);
        }
 
+       /* Clean previous status - need to configure igu prior to ack*/
+       if ((!msix) || single_msix) {
+               REG_WR(bp, IGU_REG_PF_CONFIGURATION, val);
+               bnx2x_ack_int(bp);
+       }
+
+       val |= IGU_PF_CONF_FUNC_EN;
+
        DP(NETIF_MSG_IFUP, "write 0x%x to IGU  mode %s\n",
           val, (msix ? "MSI-X" : (msi ? "MSI" : "INTx")));
 
@@ -1425,71 +1598,6 @@ void bnx2x_int_enable(struct bnx2x *bp)
                bnx2x_igu_int_enable(bp);
 }
 
-static void bnx2x_hc_int_disable(struct bnx2x *bp)
-{
-       int port = BP_PORT(bp);
-       u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
-       u32 val = REG_RD(bp, addr);
-
-       /*
-        * in E1 we must use only PCI configuration space to disable
-        * MSI/MSIX capablility
-        * It's forbitten to disable IGU_PF_CONF_MSI_MSIX_EN in HC block
-        */
-       if (CHIP_IS_E1(bp)) {
-               /*  Since IGU_PF_CONF_MSI_MSIX_EN still always on
-                *  Use mask register to prevent from HC sending interrupts
-                *  after we exit the function
-                */
-               REG_WR(bp, HC_REG_INT_MASK + port*4, 0);
-
-               val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
-                        HC_CONFIG_0_REG_INT_LINE_EN_0 |
-                        HC_CONFIG_0_REG_ATTN_BIT_EN_0);
-       } else
-               val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
-                        HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
-                        HC_CONFIG_0_REG_INT_LINE_EN_0 |
-                        HC_CONFIG_0_REG_ATTN_BIT_EN_0);
-
-       DP(NETIF_MSG_IFDOWN,
-          "write %x to HC %d (addr 0x%x)\n",
-          val, port, addr);
-
-       /* flush all outstanding writes */
-       mmiowb();
-
-       REG_WR(bp, addr, val);
-       if (REG_RD(bp, addr) != val)
-               BNX2X_ERR("BUG! proper val not read from IGU!\n");
-}
-
-static void bnx2x_igu_int_disable(struct bnx2x *bp)
-{
-       u32 val = REG_RD(bp, IGU_REG_PF_CONFIGURATION);
-
-       val &= ~(IGU_PF_CONF_MSI_MSIX_EN |
-                IGU_PF_CONF_INT_LINE_EN |
-                IGU_PF_CONF_ATTN_BIT_EN);
-
-       DP(NETIF_MSG_IFDOWN, "write %x to IGU\n", val);
-
-       /* flush all outstanding writes */
-       mmiowb();
-
-       REG_WR(bp, IGU_REG_PF_CONFIGURATION, val);
-       if (REG_RD(bp, IGU_REG_PF_CONFIGURATION) != val)
-               BNX2X_ERR("BUG! proper val not read from IGU!\n");
-}
-
-static void bnx2x_int_disable(struct bnx2x *bp)
-{
-       if (bp->common.int_block == INT_BLOCK_HC)
-               bnx2x_hc_int_disable(bp);
-       else
-               bnx2x_igu_int_disable(bp);
-}
-
 void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw)
 {
        int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0;
@@ -1588,6 +1696,24 @@ static bool bnx2x_trylock_leader_lock(struct bnx2x *bp)
 
 static void bnx2x_cnic_cfc_comp(struct bnx2x *bp, int cid, u8 err);
 
+/* schedule the sp task and mark that interrupt occurred (runs from ISR) */
+static int bnx2x_schedule_sp_task(struct bnx2x *bp)
+{
+       /* Set the interrupt occurred bit for the sp-task to recognize it
+        * must ack the interrupt and transition according to the IGU
+        * state machine.
+        */
+       atomic_set(&bp->interrupt_occurred, 1);
+
+       /* The sp_task must execute only after this bit
+        * is set, otherwise we will get out of sync and miss all
+        * further interrupts. Hence, the barrier.
+        */
+       smp_wmb();
+
+       /* schedule sp_task to workqueue */
+       return queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
+}
 
 void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe)
 {
@@ -1602,6 +1728,13 @@ void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe)
           fp->index, cid, command, bp->state,
           rr_cqe->ramrod_cqe.ramrod_type);
 
+       /* If cid is within VF range, replace the slowpath object with the
+        * one corresponding to this VF
+        */
+       if (cid >= BNX2X_FIRST_VF_CID  &&
+           cid < BNX2X_FIRST_VF_CID + BNX2X_VF_CIDS)
+               bnx2x_iov_set_queue_sp_obj(bp, cid, &q_obj);
+
        switch (command) {
        case (RAMROD_CMD_ID_ETH_CLIENT_UPDATE):
                DP(BNX2X_MSG_SP, "got UPDATE ramrod. CID %d\n", cid);
@@ -1653,6 +1786,8 @@ void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe)
 #else
                return;
 #endif
+       /* SRIOV: reschedule any 'in_progress' operations */
+       bnx2x_iov_sp_event(bp, cid, true);
 
        smp_mb__before_atomic_inc();
        atomic_inc(&bp->cq_spq_left);
@@ -1678,22 +1813,13 @@ void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe)
                clear_bit(BNX2X_AFEX_FCOE_Q_UPDATE_PENDING, &bp->sp_state);
                smp_mb__after_clear_bit();
 
-               /* schedule workqueue to send ack to MCP */
-               queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
+               /* schedule the sp task as mcp ack is required */
+               bnx2x_schedule_sp_task(bp);
        }
 
        return;
 }
 
-void bnx2x_update_rx_prod(struct bnx2x *bp, struct bnx2x_fastpath *fp,
-                       u16 bd_prod, u16 rx_comp_prod, u16 rx_sge_prod)
-{
-       u32 start = BAR_USTRORM_INTMEM + fp->ustorm_rx_prods_offset;
-
-       bnx2x_update_rx_prod_gen(bp, fp, bd_prod, rx_comp_prod, rx_sge_prod,
-                                start);
-}
-
 irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
 {
        struct bnx2x *bp = netdev_priv(dev_instance);
@@ -1748,7 +1874,11 @@ irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
        }
 
        if (unlikely(status & 0x1)) {
-               queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
+
+               /* schedule sp task to perform default status block work, ack
+                * attentions and enable interrupts.
+                */
+               bnx2x_schedule_sp_task(bp);
 
                status &= ~0x1;
                if (!status)
@@ -2448,17 +2578,49 @@ void bnx2x__link_status_update(struct bnx2x *bp)
                return;
 
        /* read updated dcb configuration */
-       bnx2x_dcbx_pmf_update(bp);
-
-       bnx2x_link_status_update(&bp->link_params, &bp->link_vars);
+       if (IS_PF(bp)) {
+               bnx2x_dcbx_pmf_update(bp);
+               bnx2x_link_status_update(&bp->link_params, &bp->link_vars);
+               if (bp->link_vars.link_up)
+                       bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
+               else
+                       bnx2x_stats_handle(bp, STATS_EVENT_STOP);
+                       /* indicate link status */
+               bnx2x_link_report(bp);
 
-       if (bp->link_vars.link_up)
+       } else { /* VF */
+               bp->port.supported[0] |= (SUPPORTED_10baseT_Half |
+                                         SUPPORTED_10baseT_Full |
+                                         SUPPORTED_100baseT_Half |
+                                         SUPPORTED_100baseT_Full |
+                                         SUPPORTED_1000baseT_Full |
+                                         SUPPORTED_2500baseX_Full |
+                                         SUPPORTED_10000baseT_Full |
+                                         SUPPORTED_TP |
+                                         SUPPORTED_FIBRE |
+                                         SUPPORTED_Autoneg |
+                                         SUPPORTED_Pause |
+                                         SUPPORTED_Asym_Pause);
+               bp->port.advertising[0] = bp->port.supported[0];
+
+               bp->link_params.bp = bp;
+               bp->link_params.port = BP_PORT(bp);
+               bp->link_params.req_duplex[0] = DUPLEX_FULL;
+               bp->link_params.req_flow_ctrl[0] = BNX2X_FLOW_CTRL_NONE;
+               bp->link_params.req_line_speed[0] = SPEED_10000;
+               bp->link_params.speed_cap_mask[0] = 0x7f0000;
+               bp->link_params.switch_cfg = SWITCH_CFG_10G;
+               bp->link_vars.mac_type = MAC_TYPE_BMAC;
+               bp->link_vars.line_speed = SPEED_10000;
+               bp->link_vars.link_status =
+                       (LINK_STATUS_LINK_UP |
+                        LINK_STATUS_SPEED_AND_DUPLEX_10GTFD);
+               bp->link_vars.link_up = 1;
+               bp->link_vars.duplex = DUPLEX_FULL;
+               bp->link_vars.flow_ctrl = BNX2X_FLOW_CTRL_NONE;
+               __bnx2x_link_report(bp);
                bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
-       else
-               bnx2x_stats_handle(bp, STATS_EVENT_STOP);
-
-       /* indicate link status */
-       bnx2x_link_report(bp);
+       }
 }
 
 static int bnx2x_afex_func_update(struct bnx2x *bp, u16 vifid,
@@ -2789,6 +2951,10 @@ static unsigned long bnx2x_get_common_flags(struct bnx2x *bp,
                __set_bit(BNX2X_Q_FLG_ZERO_STATS, &flags);
 
 
+#ifdef BNX2X_STOP_ON_ERROR
+       __set_bit(BNX2X_Q_FLG_TX_SEC, &flags);
+#endif
+
        return flags;
 }
 
@@ -3780,6 +3946,10 @@ static void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
 
                        if (val & DRV_STATUS_DRV_INFO_REQ)
                                bnx2x_handle_drv_info_req(bp);
+
+                       if (val & DRV_STATUS_VF_DISABLED)
+                               bnx2x_vf_handle_flr_event(bp);
+
                        if ((bp->port.pmf == 0) && (val & DRV_STATUS_PMF))
                                bnx2x_pmf_update(bp);
 
@@ -4576,8 +4746,8 @@ static void bnx2x_attn_int(struct bnx2x *bp)
 void bnx2x_igu_ack_sb(struct bnx2x *bp, u8 igu_sb_id, u8 segment,
                      u16 index, u8 op, u8 update)
 {
-       u32 igu_addr = BAR_IGU_INTMEM + (IGU_CMD_INT_ACK_BASE + igu_sb_id)*8;
-
+       u32 igu_addr = bp->igu_base_addr;
+       igu_addr += (IGU_CMD_INT_ACK_BASE + igu_sb_id)*8;
        bnx2x_igu_ack_sb_gen(bp, igu_sb_id, segment, index, op, update,
                             igu_addr);
 }
@@ -4605,7 +4775,7 @@ static int  bnx2x_cnic_handle_cfc_del(struct bnx2x *bp, u32 cid,
 
                BNX2X_ERR("got delete ramrod for CNIC CID %d with error!\n",
                          cid);
-               bnx2x_panic_dump(bp);
+               bnx2x_panic_dump(bp, false);
        }
        bnx2x_cnic_cfc_comp(bp, cid, err);
        return 0;
@@ -4798,7 +4968,7 @@ static void bnx2x_eq_int(struct bnx2x *bp)
        u8 echo;
        u32 cid;
        u8 opcode;
-       int spqe_cnt = 0;
+       int rc, spqe_cnt = 0;
        struct bnx2x_queue_sp_obj *q_obj;
        struct bnx2x_func_sp_obj *f_obj = &bp->func_obj;
        struct bnx2x_raw_obj *rss_raw = &bp->rss_conf_obj.raw;
@@ -4829,12 +4999,23 @@ static void bnx2x_eq_int(struct bnx2x *bp)
 
                elem = &bp->eq_ring[EQ_DESC(sw_cons)];
 
+               rc = bnx2x_iov_eq_sp_event(bp, elem);
+               if (!rc) {
+                       DP(BNX2X_MSG_IOV, "bnx2x_iov_eq_sp_event returned %d\n",
+                          rc);
+                       goto next_spqe;
+               }
                cid = SW_CID(elem->message.data.cfc_del_event.cid);
                opcode = elem->message.opcode;
 
 
                /* handle eq element */
                switch (opcode) {
+               case EVENT_RING_OPCODE_VF_PF_CHANNEL:
+                       DP(BNX2X_MSG_IOV, "vf pf channel element on eq\n");
+                       bnx2x_vf_mbx(bp, &elem->message.data.vf_pf_event);
+                       continue;
+
                case EVENT_RING_OPCODE_STAT_QUERY:
                        DP(BNX2X_MSG_SP | BNX2X_MSG_STATS,
                           "got statistics comp event %d\n",
@@ -5000,50 +5181,65 @@ next_spqe:
 static void bnx2x_sp_task(struct work_struct *work)
 {
        struct bnx2x *bp = container_of(work, struct bnx2x, sp_task.work);
-       u16 status;
 
-       status = bnx2x_update_dsb_idx(bp);
-/*     if (status == 0)                                     */
-/*             BNX2X_ERR("spurious slowpath interrupt!\n"); */
+       DP(BNX2X_MSG_SP, "sp task invoked\n");
 
-       DP(BNX2X_MSG_SP, "got a slowpath interrupt (status 0x%x)\n", status);
+       /* make sure the atomic interupt_occurred has been written */
+       smp_rmb();
+       if (atomic_read(&bp->interrupt_occurred)) {
 
-       /* HW attentions */
-       if (status & BNX2X_DEF_SB_ATT_IDX) {
-               bnx2x_attn_int(bp);
-               status &= ~BNX2X_DEF_SB_ATT_IDX;
-       }
+               /* what work needs to be performed? */
+               u16 status = bnx2x_update_dsb_idx(bp);
+
+               DP(BNX2X_MSG_SP, "status %x\n", status);
+               DP(BNX2X_MSG_SP, "setting interrupt_occurred to 0\n");
+               atomic_set(&bp->interrupt_occurred, 0);
+
+               /* HW attentions */
+               if (status & BNX2X_DEF_SB_ATT_IDX) {
+                       bnx2x_attn_int(bp);
+                       status &= ~BNX2X_DEF_SB_ATT_IDX;
+               }
 
-       /* SP events: STAT_QUERY and others */
-       if (status & BNX2X_DEF_SB_IDX) {
-               struct bnx2x_fastpath *fp = bnx2x_fcoe_fp(bp);
+               /* SP events: STAT_QUERY and others */
+               if (status & BNX2X_DEF_SB_IDX) {
+                       struct bnx2x_fastpath *fp = bnx2x_fcoe_fp(bp);
 
                if (FCOE_INIT(bp) &&
-                   (bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
-                       /*
-                        * Prevent local bottom-halves from running as
-                        * we are going to change the local NAPI list.
-                        */
-                       local_bh_disable();
-                       napi_schedule(&bnx2x_fcoe(bp, napi));
-                       local_bh_enable();
+                           (bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
+                               /* Prevent local bottom-halves from running as
+                                * we are going to change the local NAPI list.
+                                */
+                               local_bh_disable();
+                               napi_schedule(&bnx2x_fcoe(bp, napi));
+                               local_bh_enable();
+                       }
+
+                       /* Handle EQ completions */
+                       bnx2x_eq_int(bp);
+                       bnx2x_ack_sb(bp, bp->igu_dsb_id, USTORM_ID,
+                                    le16_to_cpu(bp->def_idx), IGU_INT_NOP, 1);
+
+                       status &= ~BNX2X_DEF_SB_IDX;
                }
 
-               /* Handle EQ completions */
-               bnx2x_eq_int(bp);
+               /* if status is non zero then perhaps something went wrong */
+               if (unlikely(status))
+                       DP(BNX2X_MSG_SP,
+                          "got an unknown interrupt! (status 0x%x)\n", status);
 
-               bnx2x_ack_sb(bp, bp->igu_dsb_id, USTORM_ID,
-                       le16_to_cpu(bp->def_idx), IGU_INT_NOP, 1);
+               /* ack status block only if something was actually handled */
+               bnx2x_ack_sb(bp, bp->igu_dsb_id, ATTENTION_ID,
+                            le16_to_cpu(bp->def_att_idx), IGU_INT_ENABLE, 1);
 
-               status &= ~BNX2X_DEF_SB_IDX;
        }
 
-       if (unlikely(status))
-               DP(BNX2X_MSG_SP, "got an unknown interrupt! (status 0x%x)\n",
-                  status);
-
-       bnx2x_ack_sb(bp, bp->igu_dsb_id, ATTENTION_ID,
-            le16_to_cpu(bp->def_att_idx), IGU_INT_ENABLE, 1);
+       /* must be called after the EQ processing (since eq leads to sriov
+        * ramrod completion flows).
+        * This flow may have been scheduled by the arrival of a ramrod
+        * completion, or by the sriov code rescheduling itself.
+        */
+       bnx2x_iov_sp_task(bp);
 
        /* afex - poll to check if VIFSET_ACK should be sent to MFW */
        if (test_and_clear_bit(BNX2X_AFEX_PENDING_VIFSET_MCP_ACK,
@@ -5076,7 +5272,10 @@ irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)
                rcu_read_unlock();
        }
 
-       queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
+       /* schedule sp task to perform default status block work, ack
+        * attentions and enable interrupts.
+        */
+       bnx2x_schedule_sp_task(bp);
 
        return IRQ_HANDLED;
 }
@@ -5090,7 +5289,6 @@ void bnx2x_drv_pulse(struct bnx2x *bp)
                 bp->fw_drv_pulse_wr_seq);
 }
 
-
 static void bnx2x_timer(unsigned long data)
 {
        struct bnx2x *bp = (struct bnx2x *) data;
@@ -5098,7 +5296,8 @@ static void bnx2x_timer(unsigned long data)
        if (!netif_running(bp->dev))
                return;
 
-       if (!BP_NOMCP(bp)) {
+       if (IS_PF(bp) &&
+           !BP_NOMCP(bp)) {
                int mb_idx = BP_FW_MB_IDX(bp);
                u32 drv_pulse;
                u32 mcp_pulse;
@@ -5125,6 +5324,10 @@ static void bnx2x_timer(unsigned long data)
        if (bp->state == BNX2X_STATE_OPEN)
                bnx2x_stats_handle(bp, STATS_EVENT_UPDATE);
 
+       /* sample pf vf bulletin board for new posts from pf */
+       if (IS_VF(bp))
+               bnx2x_sample_bulletin(bp);
+
        mod_timer(&bp->timer, jiffies + bp->current_interval);
 }
 
@@ -5267,7 +5470,7 @@ static void bnx2x_map_sb_state_machines(struct hc_index_data *index_data)
                SM_TX_ID << HC_INDEX_DATA_SM_ID_SHIFT;
 }
 
-static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid,
+void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid,
                          u8 vf_valid, int fw_sb_id, int igu_sb_id)
 {
        int igu_seg_id;
@@ -5688,6 +5891,13 @@ static void bnx2x_init_eth_fp(struct bnx2x *bp, int fp_idx)
                cids[cos] = fp->txdata_ptr[cos]->cid;
        }
 
+       /* nothing more for vf to do here */
+       if (IS_VF(bp))
+               return;
+
+       bnx2x_init_sb(bp, fp->status_blk_mapping, BNX2X_VF_ID_INVALID, false,
+                     fp->fw_sb_id, fp->igu_sb_id);
+       bnx2x_update_fpsb_idx(fp);
        bnx2x_init_queue_obj(bp, &bnx2x_sp_obj(bp, fp).q_obj, fp->cl_id, cids,
                             fp->max_cos, BP_FUNC(bp), bnx2x_sp(bp, q_rdata),
                             bnx2x_sp_mapping(bp, q_rdata), q_type);
@@ -5697,13 +5907,10 @@ static void bnx2x_init_eth_fp(struct bnx2x *bp, int fp_idx)
         */
        bnx2x_init_vlan_mac_fp_objs(fp, BNX2X_OBJ_TYPE_RX_TX);
 
-       DP(NETIF_MSG_IFUP, "queue[%d]:  bnx2x_init_sb(%p,%p)  cl_id %d  fw_sb %d  igu_sb %d\n",
-                  fp_idx, bp, fp->status_blk.e2_sb, fp->cl_id, fp->fw_sb_id,
-                  fp->igu_sb_id);
-       bnx2x_init_sb(bp, fp->status_blk_mapping, BNX2X_VF_ID_INVALID, false,
-                     fp->fw_sb_id, fp->igu_sb_id);
-
-       bnx2x_update_fpsb_idx(fp);
+       DP(NETIF_MSG_IFUP,
+          "queue[%d]:  bnx2x_init_sb(%p,%p)  cl_id %d  fw_sb %d  igu_sb %d\n",
+          fp_idx, bp, fp->status_blk.e2_sb, fp->cl_id, fp->fw_sb_id,
+          fp->igu_sb_id);
 }
 
 static void bnx2x_init_tx_ring_one(struct bnx2x_fp_txdata *txdata)
@@ -5775,17 +5982,22 @@ void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
 
        for_each_eth_queue(bp, i)
                bnx2x_init_eth_fp(bp, i);
+
+       /* ensure status block indices were read */
+       rmb();
+       bnx2x_init_rx_rings(bp);
+       bnx2x_init_tx_rings(bp);
+
+       if (IS_VF(bp))
+               return;
+
        /* Initialize MOD_ABS interrupts */
        bnx2x_init_mod_abs_int(bp, &bp->link_vars, bp->common.chip_id,
                               bp->common.shmem_base, bp->common.shmem2_base,
                               BP_PORT(bp));
-       /* ensure status block indices were read */
-       rmb();
 
        bnx2x_init_def_sb(bp);
        bnx2x_update_dsb_idx(bp);
-       bnx2x_init_rx_rings(bp);
-       bnx2x_init_tx_rings(bp);
        bnx2x_init_sp_ring(bp);
        bnx2x_init_eq_ring(bp);
        bnx2x_init_internal(bp, load_code);
@@ -6225,49 +6437,6 @@ static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp)
        REG_WR(bp, MISC_REG_SPIO_EVENT_EN, val);
 }
 
-static void bnx2x_pretend_func(struct bnx2x *bp, u8 pretend_func_num)
-{
-       u32 offset = 0;
-
-       if (CHIP_IS_E1(bp))
-               return;
-       if (CHIP_IS_E1H(bp) && (pretend_func_num >= E1H_FUNC_MAX))
-               return;
-
-       switch (BP_ABS_FUNC(bp)) {
-       case 0:
-               offset = PXP2_REG_PGL_PRETEND_FUNC_F0;
-               break;
-       case 1:
-               offset = PXP2_REG_PGL_PRETEND_FUNC_F1;
-               break;
-       case 2:
-               offset = PXP2_REG_PGL_PRETEND_FUNC_F2;
-               break;
-       case 3:
-               offset = PXP2_REG_PGL_PRETEND_FUNC_F3;
-               break;
-       case 4:
-               offset = PXP2_REG_PGL_PRETEND_FUNC_F4;
-               break;
-       case 5:
-               offset = PXP2_REG_PGL_PRETEND_FUNC_F5;
-               break;
-       case 6:
-               offset = PXP2_REG_PGL_PRETEND_FUNC_F6;
-               break;
-       case 7:
-               offset = PXP2_REG_PGL_PRETEND_FUNC_F7;
-               break;
-       default:
-               return;
-       }
-
-       REG_WR(bp, offset, pretend_func_num);
-       REG_RD(bp, offset);
-       DP(NETIF_MSG_HW, "Pretending to func %d\n", pretend_func_num);
-}
-
 void bnx2x_pf_disable(struct bnx2x *bp)
 {
        u32 val = REG_RD(bp, IGU_REG_PF_CONFIGURATION);
@@ -6524,6 +6693,8 @@ static int bnx2x_init_hw_common(struct bnx2x *bp)
 
        bnx2x_init_block(bp, BLOCK_DMAE, PHASE_COMMON);
 
+       bnx2x_iov_init_dmae(bp);
+
        /* clean the DMAE memory */
        bp->dmae_ready = 1;
        bnx2x_init_fill(bp, TSEM_REG_PRAM, 0, 8, 1);
@@ -7009,15 +7180,14 @@ static void bnx2x_ilt_wr(struct bnx2x *bp, u32 index, dma_addr_t addr)
        REG_WR_DMAE(bp, reg, wb_write, 2);
 }
 
-static void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func,
-                                  u8 idu_sb_id, bool is_Pf)
+void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func, u8 idu_sb_id, bool is_pf)
 {
        u32 data, ctl, cnt = 100;
        u32 igu_addr_data = IGU_REG_COMMAND_REG_32LSB_DATA;
        u32 igu_addr_ctl = IGU_REG_COMMAND_REG_CTRL;
        u32 igu_addr_ack = IGU_REG_CSTORM_TYPE_0_SB_CLEANUP + (idu_sb_id/32)*4;
        u32 sb_bit =  1 << (idu_sb_id%32);
-       u32 func_encode = func | (is_Pf ? 1 : 0) << IGU_FID_ENCODE_IS_PF_SHIFT;
+       u32 func_encode = func | (is_pf ? 1 : 0) << IGU_FID_ENCODE_IS_PF_SHIFT;
        u32 addr_encode = IGU_CMD_E2_PROD_UPD_BASE + idu_sb_id;
 
        /* Not supported in BC mode */
@@ -7226,12 +7396,21 @@ static int bnx2x_init_hw_func(struct bnx2x *bp)
        ilt = BP_ILT(bp);
        cdu_ilt_start = ilt->clients[ILT_CLIENT_CDU].start;
 
+       if (IS_SRIOV(bp))
+               cdu_ilt_start += BNX2X_FIRST_VF_CID/ILT_PAGE_CIDS;
+       cdu_ilt_start = bnx2x_iov_init_ilt(bp, cdu_ilt_start);
+
+       /* since BNX2X_FIRST_VF_CID > 0 the PF L2 cids precedes
+        * those of the VFs, so start line should be reset
+        */
+       cdu_ilt_start = ilt->clients[ILT_CLIENT_CDU].start;
        for (i = 0; i < L2_ILT_LINES(bp); i++) {
                ilt->lines[cdu_ilt_start + i].page = bp->context[i].vcxt;
                ilt->lines[cdu_ilt_start + i].page_mapping =
                        bp->context[i].cxt_mapping;
                ilt->lines[cdu_ilt_start + i].size = bp->context[i].size;
        }
+
        bnx2x_ilt_init_op(bp, INITOP_SET);
 
        if (!CONFIGURE_NIC_MODE(bp)) {
@@ -7304,6 +7483,9 @@ static int bnx2x_init_hw_func(struct bnx2x *bp)
 
        bnx2x_init_block(bp, BLOCK_TM, init_phase);
        bnx2x_init_block(bp, BLOCK_DORQ, init_phase);
+
+       bnx2x_iov_init_dq(bp);
+
        bnx2x_init_block(bp, BLOCK_BRB1, init_phase);
        bnx2x_init_block(bp, BLOCK_PRS, init_phase);
        bnx2x_init_block(bp, BLOCK_TSDM, init_phase);
@@ -7538,66 +7720,6 @@ void bnx2x_free_mem(struct bnx2x *bp)
                       BCM_PAGE_SIZE * NUM_EQ_PAGES);
 }
 
-static int bnx2x_alloc_fw_stats_mem(struct bnx2x *bp)
-{
-       int num_groups;
-       int is_fcoe_stats = NO_FCOE(bp) ? 0 : 1;
-
-       /* number of queues for statistics is number of eth queues + FCoE */
-       u8 num_queue_stats = BNX2X_NUM_ETH_QUEUES(bp) + is_fcoe_stats;
-
-       /* Total number of FW statistics requests =
-        * 1 for port stats + 1 for PF stats + potential 1 for FCoE stats +
-        * num of queues
-        */
-       bp->fw_stats_num = 2 + is_fcoe_stats + num_queue_stats;
-
-
-       /* Request is built from stats_query_header and an array of
-        * stats_query_cmd_group each of which contains
-        * STATS_QUERY_CMD_COUNT rules. The real number or requests is
-        * configured in the stats_query_header.
-        */
-       num_groups = ((bp->fw_stats_num) / STATS_QUERY_CMD_COUNT) +
-                    (((bp->fw_stats_num) % STATS_QUERY_CMD_COUNT) ? 1 : 0);
-
-       bp->fw_stats_req_sz = sizeof(struct stats_query_header) +
-                       num_groups * sizeof(struct stats_query_cmd_group);
-
-       /* Data for statistics requests + stats_conter
-        *
-        * stats_counter holds per-STORM counters that are incremented
-        * when STORM has finished with the current request.
-        *
-        * memory for FCoE offloaded statistics are counted anyway,
-        * even if they will not be sent.
-        */
-       bp->fw_stats_data_sz = sizeof(struct per_port_stats) +
-               sizeof(struct per_pf_stats) +
-               sizeof(struct fcoe_statistics_params) +
-               sizeof(struct per_queue_stats) * num_queue_stats +
-               sizeof(struct stats_counter);
-
-       BNX2X_PCI_ALLOC(bp->fw_stats, &bp->fw_stats_mapping,
-                       bp->fw_stats_data_sz + bp->fw_stats_req_sz);
-
-       /* Set shortcuts */
-       bp->fw_stats_req = (struct bnx2x_fw_stats_req *)bp->fw_stats;
-       bp->fw_stats_req_mapping = bp->fw_stats_mapping;
-
-       bp->fw_stats_data = (struct bnx2x_fw_stats_data *)
-               ((u8 *)bp->fw_stats + bp->fw_stats_req_sz);
-
-       bp->fw_stats_data_mapping = bp->fw_stats_mapping +
-                                  bp->fw_stats_req_sz;
-       return 0;
-
-alloc_mem_err:
-       BNX2X_PCI_FREE(bp->fw_stats, bp->fw_stats_mapping,
-                      bp->fw_stats_data_sz + bp->fw_stats_req_sz);
-       BNX2X_ERR("Can't allocate memory\n");
-       return -ENOMEM;
-}
 
 int bnx2x_alloc_mem_cnic(struct bnx2x *bp)
 {
@@ -7644,10 +7766,6 @@ int bnx2x_alloc_mem(struct bnx2x *bp)
        BNX2X_PCI_ALLOC(bp->slowpath, &bp->slowpath_mapping,
                        sizeof(struct bnx2x_slowpath));
 
-       /* Allocated memory for FW statistics  */
-       if (bnx2x_alloc_fw_stats_mem(bp))
-               goto alloc_mem_err;
-
        /* Allocate memory for CDU context:
         * This memory is allocated separately and not in the generic ILT
         * functions because CDU differs in few aspects:
@@ -7676,6 +7794,9 @@ int bnx2x_alloc_mem(struct bnx2x *bp)
        if (bnx2x_ilt_mem_op(bp, ILT_MEMOP_ALLOC))
                goto alloc_mem_err;
 
+       if (bnx2x_iov_alloc_mem(bp))
+               goto alloc_mem_err;
+
        /* Slow path ring */
        BNX2X_PCI_ALLOC(bp->spq, &bp->spq_mapping, BCM_PAGE_SIZE);
 
@@ -7683,13 +7804,6 @@ int bnx2x_alloc_mem(struct bnx2x *bp)
        BNX2X_PCI_ALLOC(bp->eq_ring, &bp->eq_mapping,
                        BCM_PAGE_SIZE * NUM_EQ_PAGES);
 
-
-       /* fastpath */
-       /* need to be done at the end, since it's self adjusting to amount
-        * of memory available for RSS queues
-        */
-       if (bnx2x_alloc_fp_mem(bp))
-               goto alloc_mem_err;
        return 0;
 
 alloc_mem_err:
@@ -7792,43 +7906,53 @@ int bnx2x_setup_leading(struct bnx2x *bp)
  *
  * In case of MSI-X it will also try to enable MSI-X.
  */
-void bnx2x_set_int_mode(struct bnx2x *bp)
+int bnx2x_set_int_mode(struct bnx2x *bp)
 {
+       int rc = 0;
+
+       if (IS_VF(bp) && int_mode != BNX2X_INT_MODE_MSIX)
+               return -EINVAL;
+
        switch (int_mode) {
-       case INT_MODE_MSI:
+       case BNX2X_INT_MODE_MSIX:
+               /* attempt to enable msix */
+               rc = bnx2x_enable_msix(bp);
+
+               /* msix attained */
+               if (!rc)
+                       return 0;
+
+               /* vfs use only msix */
+               if (rc && IS_VF(bp))
+                       return rc;
+
+               /* failed to enable multiple MSI-X */
+               BNX2X_DEV_INFO("Failed to enable multiple MSI-X (%d), set number of queues to %d\n",
+                              bp->num_queues,
+                              1 + bp->num_cnic_queues);
+
+               /* falling through... */
+       case BNX2X_INT_MODE_MSI:
                bnx2x_enable_msi(bp);
+
                /* falling through... */
-       case INT_MODE_INTx:
+       case BNX2X_INT_MODE_INTX:
                bp->num_ethernet_queues = 1;
                bp->num_queues = bp->num_ethernet_queues + bp->num_cnic_queues;
                BNX2X_DEV_INFO("set number of queues to 1\n");
                break;
        default:
-               /* if we can't use MSI-X we only need one fp,
-                * so try to enable MSI-X with the requested number of fp's
-                * and fallback to MSI or legacy INTx with one fp
-                */
-               if (bnx2x_enable_msix(bp) ||
-                   bp->flags & USING_SINGLE_MSIX_FLAG) {
-                       /* failed to enable multiple MSI-X */
-                       BNX2X_DEV_INFO("Failed to enable multiple MSI-X (%d), set number of queues to %d\n",
-                                      bp->num_queues,
-                                      1 + bp->num_cnic_queues);
-
-                       bp->num_queues = 1 + bp->num_cnic_queues;
-
-                       /* Try to enable MSI */
-                       if (!(bp->flags & USING_SINGLE_MSIX_FLAG) &&
-                           !(bp->flags & DISABLE_MSI_FLAG))
-                               bnx2x_enable_msi(bp);
-               }
-               break;
+               BNX2X_DEV_INFO("unknown value in int_mode module parameter\n");
+               return -EINVAL;
        }
+       return 0;
 }
 
-/* must be called prioir to any HW initializations */
+/* must be called prior to any HW initializations */
 static inline u16 bnx2x_cid_ilt_lines(struct bnx2x *bp)
 {
+       if (IS_SRIOV(bp))
+               return (BNX2X_FIRST_VF_CID + BNX2X_VF_CIDS)/ILT_PAGE_CIDS;
        return L2_ILT_LINES(bp);
 }
 
@@ -8551,6 +8675,7 @@ void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode, bool keep_link)
 
        netif_addr_unlock_bh(bp->dev);
 
+       bnx2x_iov_chip_cleanup(bp);
 
 
        /*
@@ -9288,8 +9413,10 @@ static void bnx2x_sp_rtnl_task(struct work_struct *work)
 
        rtnl_lock();
 
-       if (!netif_running(bp->dev))
-               goto sp_rtnl_exit;
+       if (!netif_running(bp->dev)) {
+               rtnl_unlock();
+               return;
+       }
 
        /* if stop on error is defined no recovery flows should be executed */
 #ifdef BNX2X_STOP_ON_ERROR
@@ -9308,7 +9435,8 @@ static void bnx2x_sp_rtnl_task(struct work_struct *work)
 
                bnx2x_parity_recover(bp);
 
-               goto sp_rtnl_exit;
+               rtnl_unlock();
+               return;
        }
 
        if (test_and_clear_bit(BNX2X_SP_RTNL_TX_TIMEOUT, &bp->sp_rtnl_state)) {
@@ -9322,7 +9450,8 @@ static void bnx2x_sp_rtnl_task(struct work_struct *work)
                bnx2x_nic_unload(bp, UNLOAD_NORMAL, true);
                bnx2x_nic_load(bp, LOAD_NORMAL);
 
-               goto sp_rtnl_exit;
+               rtnl_unlock();
+               return;
        }
 #ifdef BNX2X_STOP_ON_ERROR
 sp_rtnl_not_reset:
@@ -9340,13 +9469,33 @@ sp_rtnl_not_reset:
                DP(NETIF_MSG_HW, "fan failure detected. Unloading driver\n");
                netif_device_detach(bp->dev);
                bnx2x_close(bp->dev);
+               rtnl_unlock();
+               return;
+       }
+
+       if (test_and_clear_bit(BNX2X_SP_RTNL_VFPF_MCAST, &bp->sp_rtnl_state)) {
+               DP(BNX2X_MSG_SP,
+                  "sending set mcast vf pf channel message from rtnl sp-task\n");
+               bnx2x_vfpf_set_mcast(bp->dev);
        }
 
-sp_rtnl_exit:
+       if (test_and_clear_bit(BNX2X_SP_RTNL_VFPF_STORM_RX_MODE,
+                              &bp->sp_rtnl_state)) {
+               DP(BNX2X_MSG_SP,
+                  "sending set storm rx mode vf pf channel message from rtnl sp-task\n");
+               bnx2x_vfpf_storm_rx_mode(bp);
+       }
+
+       /* work which needs rtnl lock not-taken (as it takes the lock itself and
+        * can be called from other contexts as well)
+        */
        rtnl_unlock();
-}
 
-/* end of nic load/unload */
+       /* enable SR-IOV if applicable */
+       if (IS_SRIOV(bp) && test_and_clear_bit(BNX2X_SP_RTNL_ENABLE_SRIOV,
+                                              &bp->sp_rtnl_state))
+               bnx2x_enable_sriov(bp);
+}
 
 static void bnx2x_period_task(struct work_struct *work)
 {
@@ -9383,7 +9532,7 @@ period_task_exit:
  * Init service functions
  */
 
-static u32 bnx2x_get_pretend_reg(struct bnx2x *bp)
+u32 bnx2x_get_pretend_reg(struct bnx2x *bp)
 {
        u32 base = PXP2_REG_PGL_PRETEND_FUNC_F0;
        u32 stride = PXP2_REG_PGL_PRETEND_FUNC_F1 - base;
@@ -9420,12 +9569,19 @@ static inline void bnx2x_undi_int_disable(struct bnx2x *bp)
                bnx2x_undi_int_disable_e1h(bp);
 }
 
-static void bnx2x_prev_unload_close_mac(struct bnx2x *bp)
+static void bnx2x_prev_unload_close_mac(struct bnx2x *bp,
+                                       struct bnx2x_mac_vals *vals)
 {
        u32 val, base_addr, offset, mask, reset_reg;
        bool mac_stopped = false;
        u8 port = BP_PORT(bp);
 
+       /* reset addresses as they also mark which values were changed */
+       vals->bmac_addr = 0;
+       vals->umac_addr = 0;
+       vals->xmac_addr = 0;
+       vals->emac_addr = 0;
+
        reset_reg = REG_RD(bp, MISC_REG_RESET_REG_2);
 
        if (!CHIP_IS_E3(bp)) {
@@ -9447,14 +9603,18 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp)
                         */
                        wb_data[0] = REG_RD(bp, base_addr + offset);
                        wb_data[1] = REG_RD(bp, base_addr + offset + 0x4);
+                       vals->bmac_addr = base_addr + offset;
+                       vals->bmac_val[0] = wb_data[0];
+                       vals->bmac_val[1] = wb_data[1];
                        wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
-                       REG_WR(bp, base_addr + offset, wb_data[0]);
-                       REG_WR(bp, base_addr + offset + 0x4, wb_data[1]);
+                       REG_WR(bp, vals->bmac_addr, wb_data[0]);
+                       REG_WR(bp, vals->bmac_addr + 0x4, wb_data[1]);
 
                }
                BNX2X_DEV_INFO("Disable emac Rx\n");
-               REG_WR(bp, NIG_REG_NIG_EMAC0_EN + BP_PORT(bp)*4, 0);
-
+               vals->emac_addr = NIG_REG_NIG_EMAC0_EN + BP_PORT(bp)*4;
+               vals->emac_val = REG_RD(bp, vals->emac_addr);
+               REG_WR(bp, vals->emac_addr, 0);
                mac_stopped = true;
        } else {
                if (reset_reg & MISC_REGISTERS_RESET_REG_2_XMAC) {
@@ -9465,14 +9625,18 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp)
                               val & ~(1 << 1));
                        REG_WR(bp, base_addr + XMAC_REG_PFC_CTRL_HI,
                               val | (1 << 1));
-                       REG_WR(bp, base_addr + XMAC_REG_CTRL, 0);
+                       vals->xmac_addr = base_addr + XMAC_REG_CTRL;
+                       vals->xmac_val = REG_RD(bp, vals->xmac_addr);
+                       REG_WR(bp, vals->xmac_addr, 0);
                        mac_stopped = true;
                }
                mask = MISC_REGISTERS_RESET_REG_2_UMAC0 << port;
                if (mask & reset_reg) {
                        BNX2X_DEV_INFO("Disable umac Rx\n");
                        base_addr = BP_PORT(bp) ? GRCBASE_UMAC1 : GRCBASE_UMAC0;
-                       REG_WR(bp, base_addr + UMAC_REG_COMMAND_CONFIG, 0);
+                       vals->umac_addr = base_addr + UMAC_REG_COMMAND_CONFIG;
+                       vals->umac_val = REG_RD(bp, vals->umac_addr);
+                       REG_WR(bp, vals->umac_addr, 0);
                        mac_stopped = true;
                }
        }
@@ -9636,7 +9800,7 @@ static int bnx2x_prev_unload_uncommon(struct bnx2x *bp)
         * the one required, then FLR will be sufficient to clean any residue
         * left by previous driver
         */
-       rc = bnx2x_test_firmware_version(bp, false);
+       rc = bnx2x_nic_load_analyze_req(bp, FW_MSG_CODE_DRV_LOAD_FUNCTION);
 
        if (!rc) {
                /* fw version is good */
@@ -9664,12 +9828,16 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
 {
        u32 reset_reg, tmp_reg = 0, rc;
        bool prev_undi = false;
+       struct bnx2x_mac_vals mac_vals;
+
        /* It is possible a previous function received 'common' answer,
         * but hasn't loaded yet, therefore creating a scenario of
         * multiple functions receiving 'common' on the same path.
         */
        BNX2X_DEV_INFO("Common unload Flow\n");
 
+       memset(&mac_vals, 0, sizeof(mac_vals));
+
        if (bnx2x_prev_is_path_marked(bp))
                return bnx2x_prev_mcp_done(bp);
 
@@ -9680,7 +9848,10 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
                u32 timer_count = 1000;
 
                /* Close the MAC Rx to prevent BRB from filling up */
-               bnx2x_prev_unload_close_mac(bp);
+               bnx2x_prev_unload_close_mac(bp, &mac_vals);
+
+               /* close LLH filters towards the BRB */
+               bnx2x_set_rx_filter(&bp->link_params, 0);
 
                /* Check if the UNDI driver was previously loaded
                 * UNDI driver initializes CID offset for normal bell to 0x7
@@ -9693,6 +9864,8 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
                                prev_undi = true;
                                /* clear the UNDI indication */
                                REG_WR(bp, DORQ_REG_NORM_CID_OFST, 0);
+                               /* clear possible idle check errors */
+                               REG_RD(bp, NIG_REG_NIG_INT_STS_CLR_0);
                        }
                }
                /* wait until BRB is empty */
@@ -9727,6 +9900,17 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
        /* No packets are in the pipeline, path is ready for reset */
        bnx2x_reset_common(bp);
 
+       if (mac_vals.xmac_addr)
+               REG_WR(bp, mac_vals.xmac_addr, mac_vals.xmac_val);
+       if (mac_vals.umac_addr)
+               REG_WR(bp, mac_vals.umac_addr, mac_vals.umac_val);
+       if (mac_vals.emac_addr)
+               REG_WR(bp, mac_vals.emac_addr, mac_vals.emac_val);
+       if (mac_vals.bmac_addr) {
+               REG_WR(bp, mac_vals.bmac_addr, mac_vals.bmac_val[0]);
+               REG_WR(bp, mac_vals.bmac_addr + 4, mac_vals.bmac_val[1]);
+       }
+
        rc = bnx2x_prev_mark_path(bp, prev_undi);
        if (rc) {
                bnx2x_prev_mcp_done(bp);
@@ -10396,6 +10580,13 @@ static void bnx2x_get_port_hwinfo(struct bnx2x *bp)
        bp->wol = (!(bp->flags & NO_WOL_FLAG) &&
                   (config & PORT_FEATURE_WOL_ENABLED));
 
+       if ((config & PORT_FEAT_CFG_STORAGE_PERSONALITY_MASK) ==
+           PORT_FEAT_CFG_STORAGE_PERSONALITY_FCOE && !IS_MF(bp))
+               bp->flags |= NO_ISCSI_FLAG;
+       if ((config & PORT_FEAT_CFG_STORAGE_PERSONALITY_MASK) ==
+           PORT_FEAT_CFG_STORAGE_PERSONALITY_ISCSI && !(IS_MF(bp)))
+               bp->flags |= NO_FCOE_FLAG;
+
        BNX2X_DEV_INFO("lane_config 0x%08x  speed_cap_mask0 0x%08x  link_config0 0x%08x\n",
                       bp->link_params.lane_config,
                       bp->link_params.speed_cap_mask[0],
@@ -10615,7 +10806,7 @@ static void bnx2x_get_cnic_mac_hwinfo(struct bnx2x *bp)
                        /* Zero primary MAC configuration */
                        memset(bp->dev->dev_addr, 0, ETH_ALEN);
 
-               if (IS_MF_FCOE_AFEX(bp))
+               if (IS_MF_FCOE_AFEX(bp) || IS_MF_FCOE_SD(bp))
                        /* use FIP MAC as primary MAC */
                        memcpy(bp->dev->dev_addr, fip_mac, ETH_ALEN);
 
@@ -10678,7 +10869,6 @@ static void bnx2x_get_mac_hwinfo(struct bnx2x *bp)
        }
 
        memcpy(bp->link_params.mac_addr, bp->dev->dev_addr, ETH_ALEN);
-       memcpy(bp->dev->perm_addr, bp->dev->dev_addr, ETH_ALEN);
 
        if (!bnx2x_is_valid_ether_addr(bp, bp->dev->dev_addr))
                dev_err(&bp->pdev->dev,
@@ -11081,9 +11271,13 @@ static int bnx2x_init_bp(struct bnx2x *bp)
        INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task);
        INIT_DELAYED_WORK(&bp->sp_rtnl_task, bnx2x_sp_rtnl_task);
        INIT_DELAYED_WORK(&bp->period_task, bnx2x_period_task);
-       rc = bnx2x_get_hwinfo(bp);
-       if (rc)
-               return rc;
+       if (IS_PF(bp)) {
+               rc = bnx2x_get_hwinfo(bp);
+               if (rc)
+                       return rc;
+       } else {
+               random_ether_addr(bp->dev->dev_addr);
+       }
 
        bnx2x_set_modes_bitmap(bp);
 
@@ -11096,7 +11290,7 @@ static int bnx2x_init_bp(struct bnx2x *bp)
        func = BP_FUNC(bp);
 
        /* need to reset chip if undi was active */
-       if (!BP_NOMCP(bp)) {
+       if (IS_PF(bp) && !BP_NOMCP(bp)) {
                /* init fw_seq */
                bp->fw_seq =
                        SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
@@ -11133,6 +11327,8 @@ static int bnx2x_init_bp(struct bnx2x *bp)
        bp->mrrs = mrrs;
 
        bp->tx_ring_size = IS_MF_FCOE_AFEX(bp) ? 0 : MAX_TX_AVAIL;
+       if (IS_VF(bp))
+               bp->rx_ring_size = MAX_RX_AVAIL;
 
        /* make sure that the numbers are in the right granularity */
        bp->tx_ticks = (50 / BNX2X_BTR) * BNX2X_BTR;
@@ -11161,12 +11357,18 @@ static int bnx2x_init_bp(struct bnx2x *bp)
                bp->cnic_base_cl_id = FP_SB_MAX_E2;
 
        /* multiple tx priority */
-       if (CHIP_IS_E1x(bp))
+       if (IS_VF(bp))
+               bp->max_cos = 1;
+       else if (CHIP_IS_E1x(bp))
                bp->max_cos = BNX2X_MULTI_TX_COS_E1X;
-       if (CHIP_IS_E2(bp) || CHIP_IS_E3A0(bp))
+       else if (CHIP_IS_E2(bp) || CHIP_IS_E3A0(bp))
                bp->max_cos = BNX2X_MULTI_TX_COS_E2_E3A0;
-       if (CHIP_IS_E3B0(bp))
+       else if (CHIP_IS_E3B0(bp))
                bp->max_cos = BNX2X_MULTI_TX_COS_E3B0;
+       else
+               BNX2X_ERR("unknown chip %x revision %x\n",
+                         CHIP_NUM(bp), CHIP_REV(bp));
+       BNX2X_DEV_INFO("set bp->max_cos to %d\n", bp->max_cos);
 
        /* We need at least one default status block for slow-path events,
         * second status block for the L2 queue, and a third status block for
@@ -11190,6 +11392,26 @@ static int bnx2x_init_bp(struct bnx2x *bp)
  * net_device service functions
  */
 
+static int bnx2x_open_epilog(struct bnx2x *bp)
+{
+       /* Enable sriov via delayed work. This must be done via delayed work
+        * because it causes the probe of the vf devices to be run, which invoke
+        * register_netdevice which must have rtnl lock taken. As we are holding
+        * the lock right now, that could only work if the probe would not take
+        * the lock. However, as the probe of the vf may be called from other
+        * contexts as well (such as passthrough to vm failes) it can't assume
+        * the lock is being held for it. Using delayed work here allows the
+        * probe code to simply take the lock (i.e. wait for it to be released
+        * if it is being held).
+        */
+       smp_mb__before_clear_bit();
+       set_bit(BNX2X_SP_RTNL_ENABLE_SRIOV, &bp->sp_rtnl_state);
+       smp_mb__after_clear_bit();
+       schedule_delayed_work(&bp->sp_rtnl_task, 0);
+
+       return 0;
+}
+
 /* called with rtnl_lock */
 static int bnx2x_open(struct net_device *dev)
 {
@@ -11197,6 +11419,7 @@ static int bnx2x_open(struct net_device *dev)
        bool global = false;
        int other_engine = BP_PATH(bp) ? 0 : 1;
        bool other_load_status, load_status;
+       int rc;
 
        bp->stats_init = true;
 
@@ -11204,53 +11427,57 @@ static int bnx2x_open(struct net_device *dev)
 
        bnx2x_set_power_state(bp, PCI_D0);
 
-       other_load_status = bnx2x_get_load_status(bp, other_engine);
-       load_status = bnx2x_get_load_status(bp, BP_PATH(bp));
-
-       /*
-        * If parity had happen during the unload, then attentions
+       /* If parity had happen during the unload, then attentions
         * and/or RECOVERY_IN_PROGRES may still be set. In this case we
         * want the first function loaded on the current engine to
         * complete the recovery.
+        * Parity recovery is only relevant for PF driver.
         */
-       if (!bnx2x_reset_is_done(bp, BP_PATH(bp)) ||
-           bnx2x_chk_parity_attn(bp, &global, true))
-               do {
-                       /*
-                        * If there are attentions and they are in a global
-                        * blocks, set the GLOBAL_RESET bit regardless whether
-                        * it will be this function that will complete the
-                        * recovery or not.
-                        */
-                       if (global)
-                               bnx2x_set_reset_global(bp);
+       if (IS_PF(bp)) {
+               other_load_status = bnx2x_get_load_status(bp, other_engine);
+               load_status = bnx2x_get_load_status(bp, BP_PATH(bp));
+               if (!bnx2x_reset_is_done(bp, BP_PATH(bp)) ||
+                   bnx2x_chk_parity_attn(bp, &global, true)) {
+                       do {
+                               /* If there are attentions and they are in a
+                                * global blocks, set the GLOBAL_RESET bit
+                                * regardless whether it will be this function
+                                * that will complete the recovery or not.
+                                */
+                               if (global)
+                                       bnx2x_set_reset_global(bp);
 
-                       /*
-                        * Only the first function on the current engine should
-                        * try to recover in open. In case of attentions in
-                        * global blocks only the first in the chip should try
-                        * to recover.
-                        */
-                       if ((!load_status &&
-                            (!global || !other_load_status)) &&
-                           bnx2x_trylock_leader_lock(bp) &&
-                           !bnx2x_leader_reset(bp)) {
-                               netdev_info(bp->dev, "Recovered in open\n");
-                               break;
-                       }
+                               /* Only the first function on the current
+                                * engine should try to recover in open. In case
+                                * of attentions in global blocks only the first
+                                * in the chip should try to recover.
+                                */
+                               if ((!load_status &&
+                                    (!global || !other_load_status)) &&
+                                     bnx2x_trylock_leader_lock(bp) &&
+                                     !bnx2x_leader_reset(bp)) {
+                                       netdev_info(bp->dev,
+                                                   "Recovered in open\n");
+                                       break;
+                               }
 
-                       /* recovery has failed... */
-                       bnx2x_set_power_state(bp, PCI_D3hot);
-                       bp->recovery_state = BNX2X_RECOVERY_FAILED;
+                               /* recovery has failed... */
+                               bnx2x_set_power_state(bp, PCI_D3hot);
+                               bp->recovery_state = BNX2X_RECOVERY_FAILED;
 
-                       BNX2X_ERR("Recovery flow hasn't been properly completed yet. Try again later.\n"
-                                 "If you still see this message after a few retries then power cycle is required.\n");
+                               BNX2X_ERR("Recovery flow hasn't been properly completed yet. Try again later.\n"
+                                         "If you still see this message after a few retries then power cycle is required.\n");
 
-                       return -EAGAIN;
-               } while (0);
+                               return -EAGAIN;
+                       } while (0);
+               }
+       }
 
        bp->recovery_state = BNX2X_RECOVERY_DONE;
-       return bnx2x_nic_load(bp, LOAD_OPEN);
+       rc = bnx2x_nic_load(bp, LOAD_OPEN);
+       if (rc)
+               return rc;
+       return bnx2x_open_epilog(bp);
 }
 
 /* called with rtnl_lock */
@@ -11405,12 +11632,25 @@ void bnx2x_set_rx_mode(struct net_device *dev)
                  CHIP_IS_E1(bp)))
                rx_mode = BNX2X_RX_MODE_ALLMULTI;
        else {
-               /* some multicasts */
-               if (bnx2x_set_mc_list(bp) < 0)
-                       rx_mode = BNX2X_RX_MODE_ALLMULTI;
+               if (IS_PF(bp)) {
+                       /* some multicasts */
+                       if (bnx2x_set_mc_list(bp) < 0)
+                               rx_mode = BNX2X_RX_MODE_ALLMULTI;
 
-               if (bnx2x_set_uc_list(bp) < 0)
-                       rx_mode = BNX2X_RX_MODE_PROMISC;
+                       if (bnx2x_set_uc_list(bp) < 0)
+                               rx_mode = BNX2X_RX_MODE_PROMISC;
+               } else {
+                       /* configuring mcast to a vf involves sleeping (when we
+                        * wait for the pf's response). Since this function is
+                        * called from non sleepable context we must schedule
+                        * a work item for this purpose
+                        */
+                       smp_mb__before_clear_bit();
+                       set_bit(BNX2X_SP_RTNL_VFPF_MCAST,
+                               &bp->sp_rtnl_state);
+                       smp_mb__after_clear_bit();
+                       schedule_delayed_work(&bp->sp_rtnl_task, 0);
+               }
        }
 
        bp->rx_mode = rx_mode;
@@ -11424,7 +11664,20 @@ void bnx2x_set_rx_mode(struct net_device *dev)
                return;
        }
 
-       bnx2x_set_storm_rx_mode(bp);
+       if (IS_PF(bp)) {
+               bnx2x_set_storm_rx_mode(bp);
+       } else {
+               /* configuring rx mode to storms in a vf involves sleeping (when
+                * we wait for the pf's response). Since this function is
+                * called from non sleepable context we must schedule
+                * a work item for this purpose
+                */
+               smp_mb__before_clear_bit();
+               set_bit(BNX2X_SP_RTNL_VFPF_STORM_RX_MODE,
+                       &bp->sp_rtnl_state);
+               smp_mb__after_clear_bit();
+               schedule_delayed_work(&bp->sp_rtnl_task, 0);
+       }
 }
 
 /* called with rtnl_lock */
@@ -11527,7 +11780,9 @@ static const struct net_device_ops bnx2x_netdev_ops = {
        .ndo_poll_controller    = poll_bnx2x,
 #endif
        .ndo_setup_tc           = bnx2x_setup_tc,
-
+#ifdef CONFIG_BNX2X_SRIOV
+       .ndo_set_vf_mac         = bnx2x_set_vf_mac,
+#endif
 #ifdef NETDEV_FCOE_WWNN
        .ndo_fcoe_get_wwn       = bnx2x_fcoe_get_wwn,
 #endif
@@ -11551,10 +11806,9 @@ static int bnx2x_set_coherency_mask(struct bnx2x *bp)
        return 0;
 }
 
-static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev,
-                         unsigned long board_type)
+static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev,
+                         struct net_device *dev, unsigned long board_type)
 {
-       struct bnx2x *bp;
        int rc;
        u32 pci_cfg_dword;
        bool chip_is_e1x = (board_type == BCM57710 ||
@@ -11562,11 +11816,9 @@ static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev,
                            board_type == BCM57711E);
 
        SET_NETDEV_DEV(dev, &pdev->dev);
-       bp = netdev_priv(dev);
 
        bp->dev = dev;
        bp->pdev = pdev;
-       bp->flags = 0;
 
        rc = pci_enable_device(pdev);
        if (rc) {
@@ -11582,9 +11834,8 @@ static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev,
                goto err_out_disable;
        }
 
-       if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
-               dev_err(&bp->pdev->dev, "Cannot find second PCI device"
-                      " base address, aborting\n");
+       if (IS_PF(bp) && !(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
+               dev_err(&bp->pdev->dev, "Cannot find second PCI device base address, aborting\n");
                rc = -ENODEV;
                goto err_out_disable;
        }
@@ -11609,12 +11860,14 @@ static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev,
                pci_save_state(pdev);
        }
 
-       bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
-       if (bp->pm_cap == 0) {
-               dev_err(&bp->pdev->dev,
-                       "Cannot find power management capability, aborting\n");
-               rc = -EIO;
-               goto err_out_release;
+       if (IS_PF(bp)) {
+               bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
+               if (bp->pm_cap == 0) {
+                       dev_err(&bp->pdev->dev,
+                               "Cannot find power management capability, aborting\n");
+                       rc = -EIO;
+                       goto err_out_release;
+               }
        }
 
        if (!pci_is_pcie(pdev)) {
@@ -11665,25 +11918,28 @@ static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev,
         * Clean the following indirect addresses for all functions since it
         * is not used by the driver.
         */
-       REG_WR(bp, PXP2_REG_PGL_ADDR_88_F0, 0);
-       REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F0, 0);
-       REG_WR(bp, PXP2_REG_PGL_ADDR_90_F0, 0);
-       REG_WR(bp, PXP2_REG_PGL_ADDR_94_F0, 0);
+       if (IS_PF(bp)) {
+               REG_WR(bp, PXP2_REG_PGL_ADDR_88_F0, 0);
+               REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F0, 0);
+               REG_WR(bp, PXP2_REG_PGL_ADDR_90_F0, 0);
+               REG_WR(bp, PXP2_REG_PGL_ADDR_94_F0, 0);
+
+               if (chip_is_e1x) {
+                       REG_WR(bp, PXP2_REG_PGL_ADDR_88_F1, 0);
+                       REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F1, 0);
+                       REG_WR(bp, PXP2_REG_PGL_ADDR_90_F1, 0);
+                       REG_WR(bp, PXP2_REG_PGL_ADDR_94_F1, 0);
+               }
 
-       if (chip_is_e1x) {
-               REG_WR(bp, PXP2_REG_PGL_ADDR_88_F1, 0);
-               REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F1, 0);
-               REG_WR(bp, PXP2_REG_PGL_ADDR_90_F1, 0);
-               REG_WR(bp, PXP2_REG_PGL_ADDR_94_F1, 0);
+               /* Enable internal target-read (in case we are probed after PF
+                * FLR). Must be done prior to any BAR read access. Only for
+                * 57712 and up
+                */
+               if (!chip_is_e1x)
+                       REG_WR(bp,
+                              PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_READ, 1);
        }
 
-       /*
-        * Enable internal target-read (in case we are probed after PF FLR).
-        * Must be done prior to any BAR read access. Only for 57712 and up
-        */
-       if (!chip_is_e1x)
-               REG_WR(bp, PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_READ, 1);
-
        dev->watchdog_timeo = TX_TIMEOUT;
 
        dev->netdev_ops = &bnx2x_netdev_ops;
@@ -11734,8 +11990,9 @@ err_out:
 
 static void bnx2x_get_pcie_width_speed(struct bnx2x *bp, int *width, int *speed)
 {
-       u32 val = REG_RD(bp, PCICFG_OFFSET + PCICFG_LINK_CONTROL);
+       u32 val = 0;
 
+       pci_read_config_dword(bp->pdev, PCICFG_LINK_CONTROL, &val);
        *width = (val & PCICFG_LINK_WIDTH) >> PCICFG_LINK_WIDTH_SHIFT;
 
        /* return value of 1=2.5GHz 2=5GHz */
@@ -12000,8 +12257,12 @@ static int bnx2x_set_qm_cid_count(struct bnx2x *bp)
 {
        int cid_count = BNX2X_L2_MAX_CID(bp);
 
+       if (IS_SRIOV(bp))
+               cid_count += BNX2X_VF_CIDS;
+
        if (CNIC_SUPPORT(bp))
                cid_count += CNIC_CID_MAX;
+
        return roundup(cid_count, QM_CID_ROUND);
 }
 
@@ -12012,10 +12273,10 @@ static int bnx2x_set_qm_cid_count(struct bnx2x *bp)
  *
  */
 static int bnx2x_get_num_non_def_sbs(struct pci_dev *pdev,
-                                    int cnic_cnt)
+                                    int cnic_cnt, bool is_vf)
 {
-       int pos;
-       u16 control;
+       int pos, index;
+       u16 control = 0;
 
        pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
 
@@ -12023,85 +12284,114 @@ static int bnx2x_get_num_non_def_sbs(struct pci_dev *pdev,
         * If MSI-X is not supported - return number of SBs needed to support
         * one fast path queue: one FP queue + SB for CNIC
         */
-       if (!pos)
+       if (!pos) {
+               dev_info(&pdev->dev, "no msix capability found\n");
                return 1 + cnic_cnt;
+       }
+       dev_info(&pdev->dev, "msix capability found\n");
 
        /*
         * The value in the PCI configuration space is the index of the last
         * entry, namely one less than the actual size of the table, which is
         * exactly what we want to return from this function: number of all SBs
         * without the default SB.
+        * For VFs there is no default SB, then we return (index+1).
         */
        pci_read_config_word(pdev, pos  + PCI_MSI_FLAGS, &control);
-       return control & PCI_MSIX_FLAGS_QSIZE;
-}
 
-struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *);
+       index = control & PCI_MSIX_FLAGS_QSIZE;
 
-static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
-       struct net_device *dev = NULL;
-       struct bnx2x *bp;
-       int pcie_width, pcie_speed;
-       int rc, max_non_def_sbs;
-       int rx_count, tx_count, rss_count, doorbell_size;
-       int cnic_cnt;
-       /*
-        * An estimated maximum supported CoS number according to the chip
-        * version.
-        * We will try to roughly estimate the maximum number of CoSes this chip
-        * may support in order to minimize the memory allocated for Tx
-        * netdev_queue's. This number will be accurately calculated during the
-        * initialization of bp->max_cos based on the chip versions AND chip
-        * revision in the bnx2x_init_bp().
-        */
-       u8 max_cos_est = 0;
+       return is_vf ? index + 1 : index;
+}
 
-       switch (ent->driver_data) {
+static int set_max_cos_est(int chip_id)
+{
+       switch (chip_id) {
        case BCM57710:
        case BCM57711:
        case BCM57711E:
-               max_cos_est = BNX2X_MULTI_TX_COS_E1X;
-               break;
-
+               return BNX2X_MULTI_TX_COS_E1X;
        case BCM57712:
        case BCM57712_MF:
-               max_cos_est = BNX2X_MULTI_TX_COS_E2_E3A0;
-               break;
-
+       case BCM57712_VF:
+               return BNX2X_MULTI_TX_COS_E2_E3A0;
        case BCM57800:
        case BCM57800_MF:
+       case BCM57800_VF:
        case BCM57810:
        case BCM57810_MF:
-       case BCM57840_O:
        case BCM57840_4_10:
        case BCM57840_2_20:
+       case BCM57840_O:
        case BCM57840_MFO:
+       case BCM57810_VF:
        case BCM57840_MF:
+       case BCM57840_VF:
        case BCM57811:
        case BCM57811_MF:
-               max_cos_est = BNX2X_MULTI_TX_COS_E3B0;
-               break;
-
+       case BCM57811_VF:
+               return BNX2X_MULTI_TX_COS_E3B0;
+               return 1;
        default:
-               pr_err("Unknown board_type (%ld), aborting\n",
-                          ent->driver_data);
+               pr_err("Unknown board_type (%d), aborting\n", chip_id);
                return -ENODEV;
        }
+}
+
+static int set_is_vf(int chip_id)
+{
+       switch (chip_id) {
+       case BCM57712_VF:
+       case BCM57800_VF:
+       case BCM57810_VF:
+       case BCM57840_VF:
+       case BCM57811_VF:
+               return true;
+       default:
+               return false;
+       }
+}
+
+struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev);
 
-       cnic_cnt = 1;
-       max_non_def_sbs = bnx2x_get_num_non_def_sbs(pdev, cnic_cnt);
+static int bnx2x_init_one(struct pci_dev *pdev,
+                                   const struct pci_device_id *ent)
+{
+       struct net_device *dev = NULL;
+       struct bnx2x *bp;
+       int pcie_width, pcie_speed;
+       int rc, max_non_def_sbs;
+       int rx_count, tx_count, rss_count, doorbell_size;
+       int max_cos_est;
+       bool is_vf;
+       int cnic_cnt;
+
+       /* An estimated maximum supported CoS number according to the chip
+        * version.
+        * We will try to roughly estimate the maximum number of CoSes this chip
+        * may support in order to minimize the memory allocated for Tx
+        * netdev_queue's. This number will be accurately calculated during the
+        * initialization of bp->max_cos based on the chip versions AND chip
+        * revision in the bnx2x_init_bp().
+        */
+       max_cos_est = set_max_cos_est(ent->driver_data);
+       if (max_cos_est < 0)
+               return max_cos_est;
+       is_vf = set_is_vf(ent->driver_data);
+       cnic_cnt = is_vf ? 0 : 1;
 
-       WARN_ON(!max_non_def_sbs);
+       max_non_def_sbs = bnx2x_get_num_non_def_sbs(pdev, cnic_cnt, is_vf);
 
        /* Maximum number of RSS queues: one IGU SB goes to CNIC */
-       rss_count = max_non_def_sbs - cnic_cnt;
+       rss_count = is_vf ? 1 : max_non_def_sbs - cnic_cnt;
+
+       if (rss_count < 1)
+               return -EINVAL;
 
        /* Maximum number of netdev Rx queues: RSS + FCoE L2 */
        rx_count = rss_count + cnic_cnt;
 
-       /*
-        * Maximum number of netdev Tx queues:
+       /* Maximum number of netdev Tx queues:
         * Maximum TSS queues * Maximum supported number of CoS  + FCoE L2
         */
        tx_count = rss_count * max_cos_est + cnic_cnt;
@@ -12113,22 +12403,28 @@ static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        bp = netdev_priv(dev);
 
+       bp->flags = 0;
+       if (is_vf)
+               bp->flags |= IS_VF_FLAG;
+
        bp->igu_sb_cnt = max_non_def_sbs;
+       bp->igu_base_addr = IS_VF(bp) ? PXP_VF_ADDR_IGU_START : BAR_IGU_INTMEM;
        bp->msg_enable = debug;
        bp->cnic_support = cnic_cnt;
        bp->cnic_probe = bnx2x_cnic_probe;
 
        pci_set_drvdata(pdev, dev);
 
-       rc = bnx2x_init_dev(pdev, dev, ent->driver_data);
+       rc = bnx2x_init_dev(bp, pdev, dev, ent->driver_data);
        if (rc < 0) {
                free_netdev(dev);
                return rc;
        }
 
+       BNX2X_DEV_INFO("This is a %s function\n",
+                      IS_PF(bp) ? "physical" : "virtual");
        BNX2X_DEV_INFO("Cnic support is %s\n", CNIC_SUPPORT(bp) ? "on" : "off");
-       BNX2X_DEV_INFO("max_non_def_sbs %d\n", max_non_def_sbs);
-
+       BNX2X_DEV_INFO("Max num of status blocks %d\n", max_non_def_sbs);
        BNX2X_DEV_INFO("Allocated netdev with %d tx and %d rx queues\n",
                          tx_count, rx_count);
 
@@ -12136,19 +12432,26 @@ static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc)
                goto init_one_exit;
 
-       /*
-        * Map doorbels here as we need the real value of bp->max_cos which
-        * is initialized in bnx2x_init_bp().
+       /* Map doorbells here as we need the real value of bp->max_cos which
+        * is initialized in bnx2x_init_bp() to determine the number of
+        * l2 connections.
         */
-       doorbell_size = BNX2X_L2_MAX_CID(bp) * (1 << BNX2X_DB_SHIFT);
-       if (doorbell_size > pci_resource_len(pdev, 2)) {
-               dev_err(&bp->pdev->dev,
-                       "Cannot map doorbells, bar size too small, aborting\n");
-               rc = -ENOMEM;
-               goto init_one_exit;
+       if (IS_VF(bp)) {
+               bnx2x_vf_map_doorbells(bp);
+               rc = bnx2x_vf_pci_alloc(bp);
+               if (rc)
+                       goto init_one_exit;
+       } else {
+               doorbell_size = BNX2X_L2_MAX_CID(bp) * (1 << BNX2X_DB_SHIFT);
+               if (doorbell_size > pci_resource_len(pdev, 2)) {
+                       dev_err(&bp->pdev->dev,
+                               "Cannot map doorbells, bar size too small, aborting\n");
+                       rc = -ENOMEM;
+                       goto init_one_exit;
+               }
+               bp->doorbells = ioremap_nocache(pci_resource_start(pdev, 2),
+                                               doorbell_size);
        }
-       bp->doorbells = ioremap_nocache(pci_resource_start(pdev, 2),
-                                       doorbell_size);
        if (!bp->doorbells) {
                dev_err(&bp->pdev->dev,
                        "Cannot map doorbell space, aborting\n");
@@ -12156,8 +12459,25 @@ static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto init_one_exit;
        }
 
+       if (IS_VF(bp)) {
+               rc = bnx2x_vfpf_acquire(bp, tx_count, rx_count);
+               if (rc)
+                       goto init_one_exit;
+       }
+
+       /* Enable SRIOV if capability found in configuration space.
+        * Once the generic SR-IOV framework makes it in from the
+        * pci tree this will be revised, to allow dynamic control
+        * over the number of VFs. Right now, change the num of vfs
+        * param below to enable SR-IOV.
+        */
+       rc = bnx2x_iov_init_one(bp, int_mode, 0/*num vfs*/);
+       if (rc)
+               goto init_one_exit;
+
        /* calc qm_cid_count */
        bp->qm_cid_count = bnx2x_set_qm_cid_count(bp);
+       BNX2X_DEV_INFO("qm_cid_count %d\n", bp->qm_cid_count);
 
        /* disable FCOE L2 queue for E1x*/
        if (CHIP_IS_E1x(bp))
@@ -12179,13 +12499,19 @@ static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        /* Configure interrupt mode: try to enable MSI-X/MSI if
         * needed.
         */
-       bnx2x_set_int_mode(bp);
+       rc = bnx2x_set_int_mode(bp);
+       if (rc) {
+               dev_err(&pdev->dev, "Cannot set interrupts\n");
+               goto init_one_exit;
+       }
 
+       /* register the net device */
        rc = register_netdev(dev);
        if (rc) {
                dev_err(&pdev->dev, "Cannot register net device\n");
                goto init_one_exit;
        }
+       BNX2X_DEV_INFO("device name after netdev register %s\n", dev->name);
 
 
        if (!NO_FCOE(bp)) {
@@ -12196,6 +12522,8 @@ static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
        bnx2x_get_pcie_width_speed(bp, &pcie_width, &pcie_speed);
+       BNX2X_DEV_INFO("got pcie width %d and speed %d\n",
+                      pcie_width, pcie_speed);
 
        BNX2X_DEV_INFO(
                "%s (%c%d) PCI-E x%d %s found at mem %lx, IRQ %d, node addr %pM\n",
@@ -12213,7 +12541,7 @@ init_one_exit:
        if (bp->regview)
                iounmap(bp->regview);
 
-       if (bp->doorbells)
+       if (IS_PF(bp) && bp->doorbells)
                iounmap(bp->doorbells);
 
        free_netdev(dev);
@@ -12253,25 +12581,37 @@ static void bnx2x_remove_one(struct pci_dev *pdev)
        unregister_netdev(dev);
 
        /* Power on: we can't let PCI layer write to us while we are in D3 */
-       bnx2x_set_power_state(bp, PCI_D0);
+       if (IS_PF(bp))
+               bnx2x_set_power_state(bp, PCI_D0);
 
        /* Disable MSI/MSI-X */
        bnx2x_disable_msi(bp);
 
        /* Power off */
-       bnx2x_set_power_state(bp, PCI_D3hot);
+       if (IS_PF(bp))
+               bnx2x_set_power_state(bp, PCI_D3hot);
 
        /* Make sure RESET task is not scheduled before continuing */
        cancel_delayed_work_sync(&bp->sp_rtnl_task);
 
+       bnx2x_iov_remove_one(bp);
+
+       /* send message via vfpf channel to release the resources of this vf */
+       if (IS_VF(bp))
+               bnx2x_vfpf_release(bp);
+
        if (bp->regview)
                iounmap(bp->regview);
 
-       if (bp->doorbells)
-               iounmap(bp->doorbells);
-
-       bnx2x_release_firmware(bp);
+       /* for vf doorbells are part of the regview and were unmapped along with
+        * it. FW is only loaded by PF.
+        */
+       if (IS_PF(bp)) {
+               if (bp->doorbells)
+                       iounmap(bp->doorbells);
 
+               bnx2x_release_firmware(bp);
+       }
        bnx2x_free_mem_bp(bp);
 
        free_netdev(dev);
@@ -13059,4 +13399,36 @@ struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev)
        return cp;
 }
 
+u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp)
+{
+       struct bnx2x *bp = fp->bp;
+       u32 offset = BAR_USTRORM_INTMEM;
+
+       if (IS_VF(bp))
+               return bnx2x_vf_ustorm_prods_offset(bp, fp);
+       else if (!CHIP_IS_E1x(bp))
+               offset += USTORM_RX_PRODS_E2_OFFSET(fp->cl_qzone_id);
+       else
+               offset += USTORM_RX_PRODS_E1X_OFFSET(BP_PORT(bp), fp->cl_id);
+
+       return offset;
+}
 
+/* called only on E1H or E2.
+ * When pretending to be PF, the pretend value is the function number 0...7
+ * When pretending to be VF, the pretend val is the PF-num:VF-valid:ABS-VFID
+ * combination
+ */
+int bnx2x_pretend_func(struct bnx2x *bp, u16 pretend_func_val)
+{
+       u32 pretend_reg;
+
+       if (CHIP_IS_E1H(bp) && pretend_func_val >= E1H_FUNC_MAX)
+               return -1;
+
+       /* get my own pretend register */
+       pretend_reg = bnx2x_get_pretend_reg(bp);
+       REG_WR(bp, pretend_reg, pretend_func_val);
+       REG_RD(bp, pretend_reg);
+       return 0;
+}