]> Pileus Git - ~andy/linux/blobdiff - drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[~andy/linux] / drivers / net / ethernet / broadcom / bnx2x / bnx2x_main.c
index 0067b975873f1592f0fbc2f7dc4a67de91d8c900..e118a3ec62bc263fcf380aa9832c7b251bf59460 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
+#include <linux/aer.h>
 #include <linux/init.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -93,8 +94,8 @@ MODULE_FIRMWARE(FW_FILE_NAME_E1);
 MODULE_FIRMWARE(FW_FILE_NAME_E1H);
 MODULE_FIRMWARE(FW_FILE_NAME_E2);
 
-int num_queues;
-module_param(num_queues, int, 0);
+int bnx2x_num_queues;
+module_param_named(num_queues, bnx2x_num_queues, int, 0);
 MODULE_PARM_DESC(num_queues,
                 " Set number of queues (default is as a number of CPUs)");
 
@@ -102,7 +103,7 @@ static int disable_tpa;
 module_param(disable_tpa, int, 0);
 MODULE_PARM_DESC(disable_tpa, " Disable the TPA (LRO) feature");
 
-int int_mode;
+static int int_mode;
 module_param(int_mode, int, 0);
 MODULE_PARM_DESC(int_mode, " Force interrupt mode other than MSI-X "
                                "(1 INT#x; 2 MSI)");
@@ -278,6 +279,12 @@ MODULE_DEVICE_TABLE(pci, bnx2x_pci_tbl);
 #define BNX2X_PREV_WAIT_NEEDED 1
 static DEFINE_SEMAPHORE(bnx2x_prev_sem);
 static LIST_HEAD(bnx2x_prev_list);
+
+/* Forward declaration */
+static struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev);
+static u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp);
+static int bnx2x_set_storm_rx_mode(struct bnx2x *bp);
+
 /****************************************************************************
 * General service functions
 ****************************************************************************/
@@ -3000,6 +3007,9 @@ static unsigned long bnx2x_get_common_flags(struct bnx2x *bp,
        if (zero_stats)
                __set_bit(BNX2X_Q_FLG_ZERO_STATS, &flags);
 
+       if (bp->flags & TX_SWITCHING)
+               __set_bit(BNX2X_Q_FLG_TX_SWITCH, &flags);
+
        __set_bit(BNX2X_Q_FLG_PCSUM_ON_PKT, &flags);
        __set_bit(BNX2X_Q_FLG_TUN_INC_INNER_IP_ID, &flags);
 
@@ -3297,6 +3307,10 @@ static void bnx2x_drv_info_ether_stat(struct bnx2x *bp)
 
        ether_stat->txq_size = bp->tx_ring_size;
        ether_stat->rxq_size = bp->rx_ring_size;
+
+#ifdef CONFIG_BNX2X_SRIOV
+       ether_stat->vf_cnt = IS_SRIOV(bp) ? bp->vfdb->sriov.nr_virtfn : 0;
+#endif
 }
 
 static void bnx2x_drv_info_fcoe_stat(struct bnx2x *bp)
@@ -5852,11 +5866,11 @@ static void bnx2x_init_eq_ring(struct bnx2x *bp)
 }
 
 /* called with netif_addr_lock_bh() */
-int bnx2x_set_q_rx_mode(struct bnx2x *bp, u8 cl_id,
-                       unsigned long rx_mode_flags,
-                       unsigned long rx_accept_flags,
-                       unsigned long tx_accept_flags,
-                       unsigned long ramrod_flags)
+static int bnx2x_set_q_rx_mode(struct bnx2x *bp, u8 cl_id,
+                              unsigned long rx_mode_flags,
+                              unsigned long rx_accept_flags,
+                              unsigned long tx_accept_flags,
+                              unsigned long ramrod_flags)
 {
        struct bnx2x_rx_mode_ramrod_params ramrod_param;
        int rc;
@@ -5964,7 +5978,7 @@ static int bnx2x_fill_accept_flags(struct bnx2x *bp, u32 rx_mode,
 }
 
 /* called with netif_addr_lock_bh() */
-int bnx2x_set_storm_rx_mode(struct bnx2x *bp)
+static int bnx2x_set_storm_rx_mode(struct bnx2x *bp)
 {
        unsigned long rx_mode_flags = 0, ramrod_flags = 0;
        unsigned long rx_accept_flags = 0, tx_accept_flags = 0;
@@ -6160,6 +6174,47 @@ static void bnx2x_init_tx_rings(struct bnx2x *bp)
                        bnx2x_init_tx_ring_one(bp->fp[i].txdata_ptr[cos]);
 }
 
+static void bnx2x_init_fcoe_fp(struct bnx2x *bp)
+{
+       struct bnx2x_fastpath *fp = bnx2x_fcoe_fp(bp);
+       unsigned long q_type = 0;
+
+       bnx2x_fcoe(bp, rx_queue) = BNX2X_NUM_ETH_QUEUES(bp);
+       bnx2x_fcoe(bp, cl_id) = bnx2x_cnic_eth_cl_id(bp,
+                                                    BNX2X_FCOE_ETH_CL_ID_IDX);
+       bnx2x_fcoe(bp, cid) = BNX2X_FCOE_ETH_CID(bp);
+       bnx2x_fcoe(bp, fw_sb_id) = DEF_SB_ID;
+       bnx2x_fcoe(bp, igu_sb_id) = bp->igu_dsb_id;
+       bnx2x_fcoe(bp, rx_cons_sb) = BNX2X_FCOE_L2_RX_INDEX;
+       bnx2x_init_txdata(bp, bnx2x_fcoe(bp, txdata_ptr[0]),
+                         fp->cid, FCOE_TXQ_IDX(bp), BNX2X_FCOE_L2_TX_INDEX,
+                         fp);
+
+       DP(NETIF_MSG_IFUP, "created fcoe tx data (fp index %d)\n", fp->index);
+
+       /* qZone id equals to FW (per path) client id */
+       bnx2x_fcoe(bp, cl_qzone_id) = bnx2x_fp_qzone_id(fp);
+       /* init shortcut */
+       bnx2x_fcoe(bp, ustorm_rx_prods_offset) =
+               bnx2x_rx_ustorm_prods_offset(fp);
+
+       /* Configure Queue State object */
+       __set_bit(BNX2X_Q_TYPE_HAS_RX, &q_type);
+       __set_bit(BNX2X_Q_TYPE_HAS_TX, &q_type);
+
+       /* No multi-CoS for FCoE L2 client */
+       BUG_ON(fp->max_cos != 1);
+
+       bnx2x_init_queue_obj(bp, &bnx2x_sp_obj(bp, fp).q_obj, fp->cl_id,
+                            &fp->cid, 1, BP_FUNC(bp), bnx2x_sp(bp, q_rdata),
+                            bnx2x_sp_mapping(bp, q_rdata), q_type);
+
+       DP(NETIF_MSG_IFUP,
+          "queue[%d]: bnx2x_init_sb(%p,%p) cl_id %d fw_sb %d igu_sb %d\n",
+          fp->index, bp, fp->status_blk.e2_sb, fp->cl_id, fp->fw_sb_id,
+          fp->igu_sb_id);
+}
+
 void bnx2x_nic_init_cnic(struct bnx2x *bp)
 {
        if (!NO_FCOE(bp))
@@ -8732,16 +8787,16 @@ u32 bnx2x_send_unload_req(struct bnx2x *bp, int unload_mode)
                int path = BP_PATH(bp);
 
                DP(NETIF_MSG_IFDOWN, "NO MCP - load counts[%d]      %d, %d, %d\n",
-                  path, load_count[path][0], load_count[path][1],
-                  load_count[path][2]);
-               load_count[path][0]--;
-               load_count[path][1 + port]--;
+                  path, bnx2x_load_count[path][0], bnx2x_load_count[path][1],
+                  bnx2x_load_count[path][2]);
+               bnx2x_load_count[path][0]--;
+               bnx2x_load_count[path][1 + port]--;
                DP(NETIF_MSG_IFDOWN, "NO MCP - new load counts[%d]  %d, %d, %d\n",
-                  path, load_count[path][0], load_count[path][1],
-                  load_count[path][2]);
-               if (load_count[path][0] == 0)
+                  path, bnx2x_load_count[path][0], bnx2x_load_count[path][1],
+                  bnx2x_load_count[path][2]);
+               if (bnx2x_load_count[path][0] == 0)
                        reset_code = FW_MSG_CODE_DRV_UNLOAD_COMMON;
-               else if (load_count[path][1 + port] == 0)
+               else if (bnx2x_load_count[path][1 + port] == 0)
                        reset_code = FW_MSG_CODE_DRV_UNLOAD_PORT;
                else
                        reset_code = FW_MSG_CODE_DRV_UNLOAD_FUNCTION;
@@ -9767,7 +9822,7 @@ period_task_exit:
  * Init service functions
  */
 
-u32 bnx2x_get_pretend_reg(struct bnx2x *bp)
+static 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;
@@ -9854,6 +9909,64 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp,
 #define BNX2X_PREV_UNDI_BD(val)                ((val) >> 16 & 0xffff)
 #define BNX2X_PREV_UNDI_PROD(rcq, bd)  ((bd) << 16 | (rcq))
 
+#define BCM_5710_UNDI_FW_MF_MAJOR      (0x07)
+#define BCM_5710_UNDI_FW_MF_MINOR      (0x08)
+#define BCM_5710_UNDI_FW_MF_VERS       (0x05)
+#define BNX2X_PREV_UNDI_MF_PORT(p)     (0x1a150c + ((p) << 4))
+#define BNX2X_PREV_UNDI_MF_FUNC(f)     (0x1a184c + ((f) << 4))
+static bool bnx2x_prev_unload_undi_fw_supports_mf(struct bnx2x *bp)
+{
+       u8 major, minor, version;
+       u32 fw;
+
+       /* Must check that FW is loaded */
+       if (!(REG_RD(bp, MISC_REG_RESET_REG_1) &
+            MISC_REGISTERS_RESET_REG_1_RST_XSEM)) {
+               BNX2X_DEV_INFO("XSEM is reset - UNDI MF FW is not loaded\n");
+               return false;
+       }
+
+       /* Read Currently loaded FW version */
+       fw = REG_RD(bp, XSEM_REG_PRAM);
+       major = fw & 0xff;
+       minor = (fw >> 0x8) & 0xff;
+       version = (fw >> 0x10) & 0xff;
+       BNX2X_DEV_INFO("Loaded FW: 0x%08x: Major 0x%02x Minor 0x%02x Version 0x%02x\n",
+                      fw, major, minor, version);
+
+       if (major > BCM_5710_UNDI_FW_MF_MAJOR)
+               return true;
+
+       if ((major == BCM_5710_UNDI_FW_MF_MAJOR) &&
+           (minor > BCM_5710_UNDI_FW_MF_MINOR))
+               return true;
+
+       if ((major == BCM_5710_UNDI_FW_MF_MAJOR) &&
+           (minor == BCM_5710_UNDI_FW_MF_MINOR) &&
+           (version >= BCM_5710_UNDI_FW_MF_VERS))
+               return true;
+
+       return false;
+}
+
+static void bnx2x_prev_unload_undi_mf(struct bnx2x *bp)
+{
+       int i;
+
+       /* Due to legacy (FW) code, the first function on each engine has a
+        * different offset macro from the rest of the functions.
+        * Setting this for all 8 functions is harmless regardless of whether
+        * this is actually a multi-function device.
+        */
+       for (i = 0; i < 2; i++)
+               REG_WR(bp, BNX2X_PREV_UNDI_MF_PORT(i), 1);
+
+       for (i = 2; i < 8; i++)
+               REG_WR(bp, BNX2X_PREV_UNDI_MF_FUNC(i - 2), 1);
+
+       BNX2X_DEV_INFO("UNDI FW (MF) set to discard\n");
+}
+
 static void bnx2x_prev_unload_undi_inc(struct bnx2x *bp, u8 port, u8 inc)
 {
        u16 rcq, bd;
@@ -10054,7 +10167,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_nic_load_analyze_req(bp, FW_MSG_CODE_DRV_LOAD_FUNCTION);
+       rc = bnx2x_compare_fw_ver(bp, FW_MSG_CODE_DRV_LOAD_FUNCTION, false);
 
        if (!rc) {
                /* fw version is good */
@@ -10142,10 +10255,17 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
                        else
                                timer_count--;
 
-                       /* If UNDI resides in memory, manually increment it */
-                       if (prev_undi)
+                       /* New UNDI FW supports MF and contains better
+                        * cleaning methods - might be redundant but harmless.
+                        */
+                       if (bnx2x_prev_unload_undi_fw_supports_mf(bp)) {
+                               bnx2x_prev_unload_undi_mf(bp);
+                       } else if (prev_undi) {
+                               /* If UNDI resides in memory,
+                                * manually increment it
+                                */
                                bnx2x_prev_unload_undi_inc(bp, BP_PORT(bp), 1);
-
+                       }
                        udelay(10);
                }
 
@@ -10265,8 +10385,8 @@ static int bnx2x_prev_unload(struct bnx2x *bp)
        } while (--time_counter);
 
        if (!time_counter || rc) {
-               BNX2X_ERR("Failed unloading previous driver, aborting\n");
-               rc = -EBUSY;
+               BNX2X_DEV_INFO("Unloading previous driver did not occur, Possibly due to MF UNDI\n");
+               rc = -EPROBE_DEFER;
        }
 
        /* Mark function if its port was used to boot from SAN */
@@ -11636,7 +11756,11 @@ static int bnx2x_init_bp(struct bnx2x *bp)
                                                        DRV_MSG_SEQ_NUMBER_MASK;
                BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq);
 
-               bnx2x_prev_unload(bp);
+               rc = bnx2x_prev_unload(bp);
+               if (rc) {
+                       bnx2x_free_mem_bp(bp);
+                       return rc;
+               }
        }
 
        if (CHIP_REV_IS_FPGA(bp))
@@ -11931,7 +12055,7 @@ static int bnx2x_set_mc_list(struct bnx2x *bp)
 }
 
 /* If bp->state is OPEN, should be called with netif_addr_lock_bh() */
-void bnx2x_set_rx_mode(struct net_device *dev)
+static void bnx2x_set_rx_mode(struct net_device *dev)
 {
        struct bnx2x *bp = netdev_priv(dev);
 
@@ -12156,6 +12280,14 @@ static int bnx2x_set_coherency_mask(struct bnx2x *bp)
        return 0;
 }
 
+static void bnx2x_disable_pcie_error_reporting(struct bnx2x *bp)
+{
+       if (bp->flags & AER_ENABLED) {
+               pci_disable_pcie_error_reporting(bp->pdev);
+               bp->flags &= ~AER_ENABLED;
+       }
+}
+
 static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev,
                          struct net_device *dev, unsigned long board_type)
 {
@@ -12262,6 +12394,14 @@ static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev,
        /* clean indirect addresses */
        pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS,
                               PCICFG_VENDOR_ID_OFFSET);
+
+       /* AER (Advanced Error reporting) configuration */
+       rc = pci_enable_pcie_error_reporting(pdev);
+       if (!rc)
+               bp->flags |= AER_ENABLED;
+       else
+               BNX2X_DEV_INFO("Failed To configure PCIe AER [%d]\n", rc);
+
        /*
         * Clean the following indirect addresses for all functions since it
         * is not used by the driver.
@@ -12693,8 +12833,6 @@ static int set_is_vf(int chip_id)
        }
 }
 
-struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev);
-
 static int bnx2x_init_one(struct pci_dev *pdev,
                                    const struct pci_device_id *ent)
 {
@@ -12869,6 +13007,8 @@ static int bnx2x_init_one(struct pci_dev *pdev,
        return 0;
 
 init_one_exit:
+       bnx2x_disable_pcie_error_reporting(bp);
+
        if (bp->regview)
                iounmap(bp->regview);
 
@@ -12942,6 +13082,7 @@ static void __bnx2x_remove(struct pci_dev *pdev,
                pci_set_power_state(pdev, PCI_D3hot);
        }
 
+       bnx2x_disable_pcie_error_reporting(bp);
        if (remove_netdev) {
                if (bp->regview)
                        iounmap(bp->regview);
@@ -13120,6 +13261,14 @@ static pci_ers_result_t bnx2x_io_slot_reset(struct pci_dev *pdev)
 
        rtnl_unlock();
 
+       /* If AER, perform cleanup of the PCIe registers */
+       if (bp->flags & AER_ENABLED) {
+               if (pci_cleanup_aer_uncorrect_error_status(pdev))
+                       BNX2X_ERR("pci_cleanup_aer_uncorrect_error_status failed\n");
+               else
+                       DP(NETIF_MSG_HW, "pci_cleanup_aer_uncorrect_error_status succeeded\n");
+       }
+
        return PCI_ERS_RESULT_RECOVERED;
 }
 
@@ -13758,7 +13907,7 @@ static int bnx2x_unregister_cnic(struct net_device *dev)
        return 0;
 }
 
-struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev)
+static struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev)
 {
        struct bnx2x *bp = netdev_priv(dev);
        struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
@@ -13808,7 +13957,7 @@ struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev)
        return cp;
 }
 
-u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp)
+static u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp)
 {
        struct bnx2x *bp = fp->bp;
        u32 offset = BAR_USTRORM_INTMEM;