|
@@ -1064,7 +1064,7 @@ void __bnx2x_link_report(struct bnx2x *bp)
|
|
|
struct bnx2x_link_report_data cur_data;
|
|
|
|
|
|
/* reread mf_cfg */
|
|
|
- if (!CHIP_IS_E1(bp))
|
|
|
+ if (IS_PF(bp) && !CHIP_IS_E1(bp))
|
|
|
bnx2x_read_mf_cfg(bp);
|
|
|
|
|
|
/* Read the current link report info */
|
|
@@ -1406,10 +1406,14 @@ static void bnx2x_free_msix_irqs(struct bnx2x *bp, int nvecs)
|
|
|
|
|
|
if (nvecs == offset)
|
|
|
return;
|
|
|
- free_irq(bp->msix_table[offset].vector, bp->dev);
|
|
|
- DP(NETIF_MSG_IFDOWN, "released sp irq (%d)\n",
|
|
|
- bp->msix_table[offset].vector);
|
|
|
- offset++;
|
|
|
+
|
|
|
+ /* VFs don't have a default SB */
|
|
|
+ if (IS_PF(bp)) {
|
|
|
+ free_irq(bp->msix_table[offset].vector, bp->dev);
|
|
|
+ DP(NETIF_MSG_IFDOWN, "released sp irq (%d)\n",
|
|
|
+ bp->msix_table[offset].vector);
|
|
|
+ offset++;
|
|
|
+ }
|
|
|
|
|
|
if (CNIC_SUPPORT(bp)) {
|
|
|
if (nvecs == offset)
|
|
@@ -1430,11 +1434,17 @@ static void bnx2x_free_msix_irqs(struct bnx2x *bp, int nvecs)
|
|
|
void bnx2x_free_irq(struct bnx2x *bp)
|
|
|
{
|
|
|
if (bp->flags & USING_MSIX_FLAG &&
|
|
|
- !(bp->flags & USING_SINGLE_MSIX_FLAG))
|
|
|
- bnx2x_free_msix_irqs(bp, BNX2X_NUM_ETH_QUEUES(bp) +
|
|
|
- CNIC_SUPPORT(bp) + 1);
|
|
|
- else
|
|
|
+ !(bp->flags & USING_SINGLE_MSIX_FLAG)) {
|
|
|
+ int nvecs = BNX2X_NUM_ETH_QUEUES(bp) + CNIC_SUPPORT(bp);
|
|
|
+
|
|
|
+ /* vfs don't have a default status block */
|
|
|
+ if (IS_PF(bp))
|
|
|
+ nvecs++;
|
|
|
+
|
|
|
+ bnx2x_free_msix_irqs(bp, nvecs);
|
|
|
+ } else {
|
|
|
free_irq(bp->dev->irq, bp->dev);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
int bnx2x_enable_msix(struct bnx2x *bp)
|
|
@@ -1530,12 +1540,15 @@ static int bnx2x_req_msix_irqs(struct bnx2x *bp)
|
|
|
{
|
|
|
int i, rc, offset = 0;
|
|
|
|
|
|
- rc = request_irq(bp->msix_table[offset++].vector,
|
|
|
- bnx2x_msix_sp_int, 0,
|
|
|
- bp->dev->name, bp->dev);
|
|
|
- if (rc) {
|
|
|
- BNX2X_ERR("request sp irq failed\n");
|
|
|
- return -EBUSY;
|
|
|
+ /* no default status block for vf */
|
|
|
+ if (IS_PF(bp)) {
|
|
|
+ rc = request_irq(bp->msix_table[offset++].vector,
|
|
|
+ bnx2x_msix_sp_int, 0,
|
|
|
+ bp->dev->name, bp->dev);
|
|
|
+ if (rc) {
|
|
|
+ BNX2X_ERR("request sp irq failed\n");
|
|
|
+ return -EBUSY;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if (CNIC_SUPPORT(bp))
|
|
@@ -1559,12 +1572,20 @@ static int bnx2x_req_msix_irqs(struct bnx2x *bp)
|
|
|
}
|
|
|
|
|
|
i = BNX2X_NUM_ETH_QUEUES(bp);
|
|
|
- offset = 1 + CNIC_SUPPORT(bp);
|
|
|
- netdev_info(bp->dev, "using MSI-X IRQs: sp %d fp[%d] %d ... fp[%d] %d\n",
|
|
|
- bp->msix_table[0].vector,
|
|
|
- 0, bp->msix_table[offset].vector,
|
|
|
- i - 1, bp->msix_table[offset + i - 1].vector);
|
|
|
-
|
|
|
+ if (IS_PF(bp)) {
|
|
|
+ offset = 1 + CNIC_SUPPORT(bp);
|
|
|
+ netdev_info(bp->dev,
|
|
|
+ "using MSI-X IRQs: sp %d fp[%d] %d ... fp[%d] %d\n",
|
|
|
+ bp->msix_table[0].vector,
|
|
|
+ 0, bp->msix_table[offset].vector,
|
|
|
+ i - 1, bp->msix_table[offset + i - 1].vector);
|
|
|
+ } else {
|
|
|
+ offset = CNIC_SUPPORT(bp);
|
|
|
+ netdev_info(bp->dev,
|
|
|
+ "using MSI-X IRQs: fp[%d] %d ... fp[%d] %d\n",
|
|
|
+ 0, bp->msix_table[offset].vector,
|
|
|
+ i - 1, bp->msix_table[offset + i - 1].vector);
|
|
|
+ }
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -1972,27 +1993,204 @@ static void bnx2x_squeeze_objects(struct bnx2x *bp)
|
|
|
} while (0)
|
|
|
#endif /*BNX2X_STOP_ON_ERROR*/
|
|
|
|
|
|
-bool bnx2x_test_firmware_version(struct bnx2x *bp, bool is_err)
|
|
|
+static void bnx2x_free_fw_stats_mem(struct bnx2x *bp)
|
|
|
+{
|
|
|
+ BNX2X_PCI_FREE(bp->fw_stats, bp->fw_stats_mapping,
|
|
|
+ bp->fw_stats_data_sz + bp->fw_stats_req_sz);
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+static int bnx2x_alloc_fw_stats_mem(struct bnx2x *bp)
|
|
|
{
|
|
|
- /* build FW version dword */
|
|
|
- u32 my_fw = (BCM_5710_FW_MAJOR_VERSION) +
|
|
|
- (BCM_5710_FW_MINOR_VERSION << 8) +
|
|
|
- (BCM_5710_FW_REVISION_VERSION << 16) +
|
|
|
- (BCM_5710_FW_ENGINEERING_VERSION << 24);
|
|
|
+ int num_groups;
|
|
|
+ int is_fcoe_stats = NO_FCOE(bp) ? 0 : 1;
|
|
|
|
|
|
- /* read loaded FW from chip */
|
|
|
- u32 loaded_fw = REG_RD(bp, XSEM_REG_PRAM);
|
|
|
+ /* number of queues for statistics is number of eth queues + FCoE */
|
|
|
+ u8 num_queue_stats = BNX2X_NUM_ETH_QUEUES(bp) + is_fcoe_stats;
|
|
|
|
|
|
- DP(NETIF_MSG_IFUP, "loaded fw %x, my fw %x\n", loaded_fw, my_fw);
|
|
|
+ /* Total number of FW statistics requests =
|
|
|
+ * 1 for port stats + 1 for PF stats + potential 2 for FCoE (fcoe proper
|
|
|
+ * and fcoe l2 queue) stats + num of queues (which includes another 1
|
|
|
+ * for fcoe l2 queue if applicable)
|
|
|
+ */
|
|
|
+ bp->fw_stats_num = 2 + is_fcoe_stats + num_queue_stats;
|
|
|
|
|
|
- if (loaded_fw != my_fw) {
|
|
|
- if (is_err)
|
|
|
- BNX2X_ERR("bnx2x with FW %x was already loaded, which mismatches my %x FW. aborting\n",
|
|
|
+ /* 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));
|
|
|
+
|
|
|
+ DP(BNX2X_MSG_SP, "stats fw_stats_num %d, num_groups %d\n",
|
|
|
+ bp->fw_stats_num, num_groups);
|
|
|
+ bp->fw_stats_req_sz = sizeof(struct stats_query_header) +
|
|
|
+ num_groups * sizeof(struct stats_query_cmd_group);
|
|
|
+
|
|
|
+ /* Data for statistics requests + stats_counter
|
|
|
+ * 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.
|
|
|
+ * VF stats are not accounted for here as the data of VF stats is stored
|
|
|
+ * in memory allocated by the VF, not here.
|
|
|
+ */
|
|
|
+ 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;
|
|
|
+
|
|
|
+ DP(BNX2X_MSG_SP, "statistics request base address set to %x %x",
|
|
|
+ U64_HI(bp->fw_stats_req_mapping),
|
|
|
+ U64_LO(bp->fw_stats_req_mapping));
|
|
|
+ DP(BNX2X_MSG_SP, "statistics data base address set to %x %x",
|
|
|
+ U64_HI(bp->fw_stats_data_mapping),
|
|
|
+ U64_LO(bp->fw_stats_data_mapping));
|
|
|
+ return 0;
|
|
|
+
|
|
|
+alloc_mem_err:
|
|
|
+ bnx2x_free_fw_stats_mem(bp);
|
|
|
+ BNX2X_ERR("Can't allocate FW stats memory\n");
|
|
|
+ return -ENOMEM;
|
|
|
+}
|
|
|
+
|
|
|
+/* send load request to mcp and analyze response */
|
|
|
+static int bnx2x_nic_load_request(struct bnx2x *bp, u32 *load_code)
|
|
|
+{
|
|
|
+ /* init fw_seq */
|
|
|
+ bp->fw_seq =
|
|
|
+ (SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
|
|
|
+ DRV_MSG_SEQ_NUMBER_MASK);
|
|
|
+ BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq);
|
|
|
+
|
|
|
+ /* Get current FW pulse sequence */
|
|
|
+ bp->fw_drv_pulse_wr_seq =
|
|
|
+ (SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_pulse_mb) &
|
|
|
+ DRV_PULSE_SEQ_MASK);
|
|
|
+ BNX2X_DEV_INFO("drv_pulse 0x%x\n", bp->fw_drv_pulse_wr_seq);
|
|
|
+
|
|
|
+ /* load request */
|
|
|
+ (*load_code) = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ,
|
|
|
+ DRV_MSG_CODE_LOAD_REQ_WITH_LFA);
|
|
|
+
|
|
|
+ /* if mcp fails to respond we must abort */
|
|
|
+ if (!(*load_code)) {
|
|
|
+ BNX2X_ERR("MCP response failure, aborting\n");
|
|
|
+ return -EBUSY;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* If mcp refused (e.g. other port is in diagnostic mode) we
|
|
|
+ * must abort
|
|
|
+ */
|
|
|
+ if ((*load_code) == FW_MSG_CODE_DRV_LOAD_REFUSED) {
|
|
|
+ BNX2X_ERR("MCP refused load request, aborting\n");
|
|
|
+ return -EBUSY;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* check whether another PF has already loaded FW to chip. In
|
|
|
+ * virtualized environments a pf from another VM may have already
|
|
|
+ * initialized the device including loading FW
|
|
|
+ */
|
|
|
+int bnx2x_nic_load_analyze_req(struct bnx2x *bp, u32 load_code)
|
|
|
+{
|
|
|
+ /* is another pf loaded on this engine? */
|
|
|
+ if (load_code != FW_MSG_CODE_DRV_LOAD_COMMON_CHIP &&
|
|
|
+ load_code != FW_MSG_CODE_DRV_LOAD_COMMON) {
|
|
|
+ /* build my FW version dword */
|
|
|
+ u32 my_fw = (BCM_5710_FW_MAJOR_VERSION) +
|
|
|
+ (BCM_5710_FW_MINOR_VERSION << 8) +
|
|
|
+ (BCM_5710_FW_REVISION_VERSION << 16) +
|
|
|
+ (BCM_5710_FW_ENGINEERING_VERSION << 24);
|
|
|
+
|
|
|
+ /* read loaded FW from chip */
|
|
|
+ u32 loaded_fw = REG_RD(bp, XSEM_REG_PRAM);
|
|
|
+
|
|
|
+ DP(BNX2X_MSG_SP, "loaded fw %x, my fw %x\n",
|
|
|
+ loaded_fw, my_fw);
|
|
|
+
|
|
|
+ /* abort nic load if version mismatch */
|
|
|
+ if (my_fw != loaded_fw) {
|
|
|
+ BNX2X_ERR("bnx2x with FW %x was already loaded which mismatches my %x FW. aborting\n",
|
|
|
loaded_fw, my_fw);
|
|
|
- return false;
|
|
|
+ return -EBUSY;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* returns the "mcp load_code" according to global load_count array */
|
|
|
+static int bnx2x_nic_load_no_mcp(struct bnx2x *bp, int port)
|
|
|
+{
|
|
|
+ int path = BP_PATH(bp);
|
|
|
+
|
|
|
+ DP(NETIF_MSG_IFUP, "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]++;
|
|
|
+ DP(NETIF_MSG_IFUP, "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] == 1)
|
|
|
+ return FW_MSG_CODE_DRV_LOAD_COMMON;
|
|
|
+ else if (load_count[path][1 + port] == 1)
|
|
|
+ return FW_MSG_CODE_DRV_LOAD_PORT;
|
|
|
+ else
|
|
|
+ return FW_MSG_CODE_DRV_LOAD_FUNCTION;
|
|
|
+}
|
|
|
+
|
|
|
+/* mark PMF if applicable */
|
|
|
+static void bnx2x_nic_load_pmf(struct bnx2x *bp, u32 load_code)
|
|
|
+{
|
|
|
+ if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
|
|
|
+ (load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP) ||
|
|
|
+ (load_code == FW_MSG_CODE_DRV_LOAD_PORT)) {
|
|
|
+ bp->port.pmf = 1;
|
|
|
+ /* We need the barrier to ensure the ordering between the
|
|
|
+ * writing to bp->port.pmf here and reading it from the
|
|
|
+ * bnx2x_periodic_task().
|
|
|
+ */
|
|
|
+ smp_mb();
|
|
|
+ } else {
|
|
|
+ bp->port.pmf = 0;
|
|
|
}
|
|
|
|
|
|
- return true;
|
|
|
+ DP(NETIF_MSG_LINK, "pmf %d\n", bp->port.pmf);
|
|
|
+}
|
|
|
+
|
|
|
+static void bnx2x_nic_load_afex_dcc(struct bnx2x *bp, int load_code)
|
|
|
+{
|
|
|
+ if (((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
|
|
|
+ (load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP)) &&
|
|
|
+ (bp->common.shmem2_base)) {
|
|
|
+ if (SHMEM2_HAS(bp, dcc_support))
|
|
|
+ SHMEM2_WR(bp, dcc_support,
|
|
|
+ (SHMEM_DCC_SUPPORT_DISABLE_ENABLE_PF_TLV |
|
|
|
+ SHMEM_DCC_SUPPORT_BANDWIDTH_ALLOCATION_TLV));
|
|
|
+ if (SHMEM2_HAS(bp, afex_driver_support))
|
|
|
+ SHMEM2_WR(bp, afex_driver_support,
|
|
|
+ SHMEM_AFEX_SUPPORTED_VERSION_ONE);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Set AFEX default VLAN tag to an invalid value */
|
|
|
+ bp->afex_def_vlan_tag = -1;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -2095,10 +2293,12 @@ int bnx2x_load_cnic(struct bnx2x *bp)
|
|
|
|
|
|
mutex_init(&bp->cnic_mutex);
|
|
|
|
|
|
- rc = bnx2x_alloc_mem_cnic(bp);
|
|
|
- if (rc) {
|
|
|
- BNX2X_ERR("Unable to allocate bp memory for cnic\n");
|
|
|
- LOAD_ERROR_EXIT_CNIC(bp, load_error_cnic0);
|
|
|
+ if (IS_PF(bp)) {
|
|
|
+ rc = bnx2x_alloc_mem_cnic(bp);
|
|
|
+ if (rc) {
|
|
|
+ BNX2X_ERR("Unable to allocate bp memory for cnic\n");
|
|
|
+ LOAD_ERROR_EXIT_CNIC(bp, load_error_cnic0);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
rc = bnx2x_alloc_fp_mem_cnic(bp);
|
|
@@ -2125,14 +2325,17 @@ int bnx2x_load_cnic(struct bnx2x *bp)
|
|
|
|
|
|
bnx2x_nic_init_cnic(bp);
|
|
|
|
|
|
- /* Enable Timer scan */
|
|
|
- REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + port*4, 1);
|
|
|
-
|
|
|
- for_each_cnic_queue(bp, i) {
|
|
|
- rc = bnx2x_setup_queue(bp, &bp->fp[i], 0);
|
|
|
- if (rc) {
|
|
|
- BNX2X_ERR("Queue setup failed\n");
|
|
|
- LOAD_ERROR_EXIT(bp, load_error_cnic2);
|
|
|
+ if (IS_PF(bp)) {
|
|
|
+ /* Enable Timer scan */
|
|
|
+ REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + port*4, 1);
|
|
|
+
|
|
|
+ /* setup cnic queues */
|
|
|
+ for_each_cnic_queue(bp, i) {
|
|
|
+ rc = bnx2x_setup_queue(bp, &bp->fp[i], 0);
|
|
|
+ if (rc) {
|
|
|
+ BNX2X_ERR("Queue setup failed\n");
|
|
|
+ LOAD_ERROR_EXIT(bp, load_error_cnic2);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -2178,8 +2381,7 @@ load_error_cnic0:
|
|
|
int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
|
|
|
{
|
|
|
int port = BP_PORT(bp);
|
|
|
- u32 load_code;
|
|
|
- int i, rc;
|
|
|
+ int i, rc = 0, load_code = 0;
|
|
|
|
|
|
DP(NETIF_MSG_IFUP, "Starting NIC load\n");
|
|
|
DP(NETIF_MSG_IFUP,
|
|
@@ -2201,8 +2403,9 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
|
|
|
&bp->last_reported_link.link_report_flags);
|
|
|
bnx2x_release_phy_lock(bp);
|
|
|
|
|
|
- /* must be called before memory allocation and HW init */
|
|
|
- bnx2x_ilt_set_info(bp);
|
|
|
+ if (IS_PF(bp))
|
|
|
+ /* must be called before memory allocation and HW init */
|
|
|
+ bnx2x_ilt_set_info(bp);
|
|
|
|
|
|
/*
|
|
|
* Zero fastpath structures preserving invariants like napi, which are
|
|
@@ -2221,8 +2424,26 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
|
|
|
/* Set the receive queues buffer size */
|
|
|
bnx2x_set_rx_buf_size(bp);
|
|
|
|
|
|
- if (bnx2x_alloc_mem(bp))
|
|
|
- return -ENOMEM;
|
|
|
+ if (IS_PF(bp)) {
|
|
|
+ rc = bnx2x_alloc_mem(bp);
|
|
|
+ if (rc) {
|
|
|
+ BNX2X_ERR("Unable to allocate bp memory\n");
|
|
|
+ return rc;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Allocated memory for FW statistics */
|
|
|
+ if (bnx2x_alloc_fw_stats_mem(bp))
|
|
|
+ LOAD_ERROR_EXIT(bp, load_error0);
|
|
|
+
|
|
|
+ /* need to be done after alloc mem, since it's self adjusting to amount
|
|
|
+ * of memory available for RSS queues
|
|
|
+ */
|
|
|
+ rc = bnx2x_alloc_fp_mem(bp);
|
|
|
+ if (rc) {
|
|
|
+ BNX2X_ERR("Unable to allocate memory for fps\n");
|
|
|
+ LOAD_ERROR_EXIT(bp, load_error0);
|
|
|
+ }
|
|
|
|
|
|
/* As long as bnx2x_alloc_mem() may possibly update
|
|
|
* bp->num_queues, bnx2x_set_real_num_queues() should always
|
|
@@ -2245,98 +2466,48 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
|
|
|
DP(NETIF_MSG_IFUP, "napi added\n");
|
|
|
bnx2x_napi_enable(bp);
|
|
|
|
|
|
- /* set pf load just before approaching the MCP */
|
|
|
- bnx2x_set_pf_load(bp);
|
|
|
-
|
|
|
- /* Send LOAD_REQUEST command to MCP
|
|
|
- * Returns the type of LOAD command:
|
|
|
- * if it is the first port to be initialized
|
|
|
- * common blocks should be initialized, otherwise - not
|
|
|
- */
|
|
|
- if (!BP_NOMCP(bp)) {
|
|
|
- /* init fw_seq */
|
|
|
- bp->fw_seq =
|
|
|
- (SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
|
|
|
- DRV_MSG_SEQ_NUMBER_MASK);
|
|
|
- BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq);
|
|
|
-
|
|
|
- /* Get current FW pulse sequence */
|
|
|
- bp->fw_drv_pulse_wr_seq =
|
|
|
- (SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_pulse_mb) &
|
|
|
- DRV_PULSE_SEQ_MASK);
|
|
|
- BNX2X_DEV_INFO("drv_pulse 0x%x\n", bp->fw_drv_pulse_wr_seq);
|
|
|
-
|
|
|
- load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ,
|
|
|
- DRV_MSG_CODE_LOAD_REQ_WITH_LFA);
|
|
|
- if (!load_code) {
|
|
|
- BNX2X_ERR("MCP response failure, aborting\n");
|
|
|
- rc = -EBUSY;
|
|
|
- LOAD_ERROR_EXIT(bp, load_error1);
|
|
|
- }
|
|
|
- if (load_code == FW_MSG_CODE_DRV_LOAD_REFUSED) {
|
|
|
- BNX2X_ERR("Driver load refused\n");
|
|
|
- rc = -EBUSY; /* other port in diagnostic mode */
|
|
|
- LOAD_ERROR_EXIT(bp, load_error1);
|
|
|
- }
|
|
|
- if (load_code != FW_MSG_CODE_DRV_LOAD_COMMON_CHIP &&
|
|
|
- load_code != FW_MSG_CODE_DRV_LOAD_COMMON) {
|
|
|
- /* abort nic load if version mismatch */
|
|
|
- if (!bnx2x_test_firmware_version(bp, true)) {
|
|
|
- rc = -EBUSY;
|
|
|
+ if (IS_PF(bp)) {
|
|
|
+ /* set pf load just before approaching the MCP */
|
|
|
+ bnx2x_set_pf_load(bp);
|
|
|
+
|
|
|
+ /* if mcp exists send load request and analyze response */
|
|
|
+ if (!BP_NOMCP(bp)) {
|
|
|
+ /* attempt to load pf */
|
|
|
+ rc = bnx2x_nic_load_request(bp, &load_code);
|
|
|
+ if (rc)
|
|
|
+ LOAD_ERROR_EXIT(bp, load_error1);
|
|
|
+
|
|
|
+ /* what did mcp say? */
|
|
|
+ rc = bnx2x_nic_load_analyze_req(bp, load_code);
|
|
|
+ if (rc) {
|
|
|
+ bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
|
|
|
LOAD_ERROR_EXIT(bp, load_error2);
|
|
|
}
|
|
|
+ } else {
|
|
|
+ load_code = bnx2x_nic_load_no_mcp(bp, port);
|
|
|
}
|
|
|
|
|
|
- } else {
|
|
|
- int path = BP_PATH(bp);
|
|
|
-
|
|
|
- DP(NETIF_MSG_IFUP, "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]++;
|
|
|
- DP(NETIF_MSG_IFUP, "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] == 1)
|
|
|
- load_code = FW_MSG_CODE_DRV_LOAD_COMMON;
|
|
|
- else if (load_count[path][1 + port] == 1)
|
|
|
- load_code = FW_MSG_CODE_DRV_LOAD_PORT;
|
|
|
- else
|
|
|
- load_code = FW_MSG_CODE_DRV_LOAD_FUNCTION;
|
|
|
- }
|
|
|
+ /* mark pmf if applicable */
|
|
|
+ bnx2x_nic_load_pmf(bp, load_code);
|
|
|
|
|
|
- if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
|
|
|
- (load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP) ||
|
|
|
- (load_code == FW_MSG_CODE_DRV_LOAD_PORT)) {
|
|
|
- bp->port.pmf = 1;
|
|
|
- /*
|
|
|
- * We need the barrier to ensure the ordering between the
|
|
|
- * writing to bp->port.pmf here and reading it from the
|
|
|
- * bnx2x_periodic_task().
|
|
|
- */
|
|
|
- smp_mb();
|
|
|
- } else
|
|
|
- bp->port.pmf = 0;
|
|
|
-
|
|
|
- DP(NETIF_MSG_IFUP, "pmf %d\n", bp->port.pmf);
|
|
|
+ /* Init Function state controlling object */
|
|
|
+ bnx2x__init_func_obj(bp);
|
|
|
|
|
|
- /* Init Function state controlling object */
|
|
|
- bnx2x__init_func_obj(bp);
|
|
|
-
|
|
|
- /* Initialize HW */
|
|
|
- rc = bnx2x_init_hw(bp, load_code);
|
|
|
- if (rc) {
|
|
|
- BNX2X_ERR("HW init failed, aborting\n");
|
|
|
- bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
|
|
|
- LOAD_ERROR_EXIT(bp, load_error2);
|
|
|
+ /* Initialize HW */
|
|
|
+ rc = bnx2x_init_hw(bp, load_code);
|
|
|
+ if (rc) {
|
|
|
+ BNX2X_ERR("HW init failed, aborting\n");
|
|
|
+ bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
|
|
|
+ LOAD_ERROR_EXIT(bp, load_error2);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* Connect to IRQs */
|
|
|
rc = bnx2x_setup_irqs(bp);
|
|
|
if (rc) {
|
|
|
- BNX2X_ERR("IRQs setup failed\n");
|
|
|
- bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
|
|
|
+ BNX2X_ERR("setup irqs failed\n");
|
|
|
+ if (IS_PF(bp))
|
|
|
+ bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
|
|
|
LOAD_ERROR_EXIT(bp, load_error2);
|
|
|
}
|
|
|
|
|
@@ -2344,78 +2515,78 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
|
|
|
bnx2x_nic_init(bp, load_code);
|
|
|
|
|
|
/* Init per-function objects */
|
|
|
- bnx2x_init_bp_objs(bp);
|
|
|
-
|
|
|
- if (((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) ||
|
|
|
- (load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP)) &&
|
|
|
- (bp->common.shmem2_base)) {
|
|
|
- if (SHMEM2_HAS(bp, dcc_support))
|
|
|
- SHMEM2_WR(bp, dcc_support,
|
|
|
- (SHMEM_DCC_SUPPORT_DISABLE_ENABLE_PF_TLV |
|
|
|
- SHMEM_DCC_SUPPORT_BANDWIDTH_ALLOCATION_TLV));
|
|
|
- if (SHMEM2_HAS(bp, afex_driver_support))
|
|
|
- SHMEM2_WR(bp, afex_driver_support,
|
|
|
- SHMEM_AFEX_SUPPORTED_VERSION_ONE);
|
|
|
- }
|
|
|
+ if (IS_PF(bp)) {
|
|
|
+ bnx2x_init_bp_objs(bp);
|
|
|
|
|
|
- /* Set AFEX default VLAN tag to an invalid value */
|
|
|
- bp->afex_def_vlan_tag = -1;
|
|
|
|
|
|
- bp->state = BNX2X_STATE_OPENING_WAIT4_PORT;
|
|
|
- rc = bnx2x_func_start(bp);
|
|
|
- if (rc) {
|
|
|
- BNX2X_ERR("Function start failed!\n");
|
|
|
- bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
|
|
|
- LOAD_ERROR_EXIT(bp, load_error3);
|
|
|
- }
|
|
|
+ /* Set AFEX default VLAN tag to an invalid value */
|
|
|
+ bp->afex_def_vlan_tag = -1;
|
|
|
+ bnx2x_nic_load_afex_dcc(bp, load_code);
|
|
|
+ bp->state = BNX2X_STATE_OPENING_WAIT4_PORT;
|
|
|
+ rc = bnx2x_func_start(bp);
|
|
|
+ if (rc) {
|
|
|
+ BNX2X_ERR("Function start failed!\n");
|
|
|
+ bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
|
|
|
|
|
|
- /* Send LOAD_DONE command to MCP */
|
|
|
- if (!BP_NOMCP(bp)) {
|
|
|
- load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
|
|
|
- if (!load_code) {
|
|
|
- BNX2X_ERR("MCP response failure, aborting\n");
|
|
|
- rc = -EBUSY;
|
|
|
LOAD_ERROR_EXIT(bp, load_error3);
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- rc = bnx2x_setup_leading(bp);
|
|
|
- if (rc) {
|
|
|
- BNX2X_ERR("Setup leading failed!\n");
|
|
|
- LOAD_ERROR_EXIT(bp, load_error3);
|
|
|
- }
|
|
|
+ /* Send LOAD_DONE command to MCP */
|
|
|
+ if (!BP_NOMCP(bp)) {
|
|
|
+ load_code = bnx2x_fw_command(bp,
|
|
|
+ DRV_MSG_CODE_LOAD_DONE, 0);
|
|
|
+ if (!load_code) {
|
|
|
+ BNX2X_ERR("MCP response failure, aborting\n");
|
|
|
+ rc = -EBUSY;
|
|
|
+ LOAD_ERROR_EXIT(bp, load_error3);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- for_each_nondefault_eth_queue(bp, i) {
|
|
|
- rc = bnx2x_setup_queue(bp, &bp->fp[i], 0);
|
|
|
+ /* setup the leading queue */
|
|
|
+ rc = bnx2x_setup_leading(bp);
|
|
|
if (rc) {
|
|
|
- BNX2X_ERR("Queue setup failed\n");
|
|
|
+ BNX2X_ERR("Setup leading failed!\n");
|
|
|
LOAD_ERROR_EXIT(bp, load_error3);
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- rc = bnx2x_init_rss_pf(bp);
|
|
|
- if (rc) {
|
|
|
- BNX2X_ERR("PF RSS init failed\n");
|
|
|
- LOAD_ERROR_EXIT(bp, load_error3);
|
|
|
+ /* set up the rest of the queues */
|
|
|
+ for_each_nondefault_eth_queue(bp, i) {
|
|
|
+ rc = bnx2x_setup_queue(bp, &bp->fp[i], 0);
|
|
|
+ if (rc) {
|
|
|
+ BNX2X_ERR("Queue setup failed\n");
|
|
|
+ LOAD_ERROR_EXIT(bp, load_error3);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* setup rss */
|
|
|
+ rc = bnx2x_init_rss_pf(bp);
|
|
|
+ if (rc) {
|
|
|
+ BNX2X_ERR("PF RSS init failed\n");
|
|
|
+ LOAD_ERROR_EXIT(bp, load_error3);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* Now when Clients are configured we are ready to work */
|
|
|
bp->state = BNX2X_STATE_OPEN;
|
|
|
|
|
|
/* Configure a ucast MAC */
|
|
|
- rc = bnx2x_set_eth_mac(bp, true);
|
|
|
+ if (IS_PF(bp))
|
|
|
+ rc = bnx2x_set_eth_mac(bp, true);
|
|
|
if (rc) {
|
|
|
BNX2X_ERR("Setting Ethernet MAC failed\n");
|
|
|
LOAD_ERROR_EXIT(bp, load_error3);
|
|
|
}
|
|
|
|
|
|
- if (bp->pending_max) {
|
|
|
+ if (IS_PF(bp) && bp->pending_max) {
|
|
|
bnx2x_update_max_mf_config(bp, bp->pending_max);
|
|
|
bp->pending_max = 0;
|
|
|
}
|
|
|
|
|
|
- if (bp->port.pmf)
|
|
|
- bnx2x_initial_phy_init(bp, load_mode);
|
|
|
+ if (bp->port.pmf) {
|
|
|
+ rc = bnx2x_initial_phy_init(bp, load_mode);
|
|
|
+ if (rc)
|
|
|
+ LOAD_ERROR_EXIT(bp, load_error3);
|
|
|
+ }
|
|
|
bp->link_params.feature_config_flags &= ~FEATURE_CONFIG_BOOT_FROM_SAN;
|
|
|
|
|
|
/* Start fast path */
|
|
@@ -2457,8 +2628,8 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
|
|
|
if (CNIC_ENABLED(bp))
|
|
|
bnx2x_load_cnic(bp);
|
|
|
|
|
|
- /* mark driver is loaded in shmem2 */
|
|
|
- if (SHMEM2_HAS(bp, drv_capabilities_flag)) {
|
|
|
+ if (IS_PF(bp) && SHMEM2_HAS(bp, drv_capabilities_flag)) {
|
|
|
+ /* mark driver is loaded in shmem2 */
|
|
|
u32 val;
|
|
|
val = SHMEM2_RD(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)]);
|
|
|
SHMEM2_WR(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)],
|
|
@@ -2467,7 +2638,7 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
|
|
|
}
|
|
|
|
|
|
/* Wait for all pending SP commands to complete */
|
|
|
- if (!bnx2x_wait_sp_comp(bp, ~0x0UL)) {
|
|
|
+ if (IS_PF(bp) && !bnx2x_wait_sp_comp(bp, ~0x0UL)) {
|
|
|
BNX2X_ERR("Timeout waiting for SP elements to complete\n");
|
|
|
bnx2x_nic_unload(bp, UNLOAD_CLOSE, false);
|
|
|
return -EBUSY;
|
|
@@ -2483,10 +2654,12 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
|
|
|
|
|
|
#ifndef BNX2X_STOP_ON_ERROR
|
|
|
load_error3:
|
|
|
- bnx2x_int_disable_sync(bp, 1);
|
|
|
+ if (IS_PF(bp)) {
|
|
|
+ bnx2x_int_disable_sync(bp, 1);
|
|
|
|
|
|
- /* Clean queueable objects */
|
|
|
- bnx2x_squeeze_objects(bp);
|
|
|
+ /* Clean queueable objects */
|
|
|
+ bnx2x_squeeze_objects(bp);
|
|
|
+ }
|
|
|
|
|
|
/* Free SKBs, SGEs, TPA pool and driver internals */
|
|
|
bnx2x_free_skbs(bp);
|
|
@@ -2496,7 +2669,7 @@ load_error3:
|
|
|
/* Release IRQs */
|
|
|
bnx2x_free_irq(bp);
|
|
|
load_error2:
|
|
|
- if (!BP_NOMCP(bp)) {
|
|
|
+ if (IS_PF(bp) && !BP_NOMCP(bp)) {
|
|
|
bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP, 0);
|
|
|
bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE, 0);
|
|
|
}
|
|
@@ -2504,15 +2677,35 @@ load_error2:
|
|
|
bp->port.pmf = 0;
|
|
|
load_error1:
|
|
|
bnx2x_napi_disable(bp);
|
|
|
+
|
|
|
/* clear pf_load status, as it was already set */
|
|
|
- bnx2x_clear_pf_load(bp);
|
|
|
+ if (IS_PF(bp))
|
|
|
+ bnx2x_clear_pf_load(bp);
|
|
|
load_error0:
|
|
|
+ bnx2x_free_fp_mem(bp);
|
|
|
+ bnx2x_free_fw_stats_mem(bp);
|
|
|
bnx2x_free_mem(bp);
|
|
|
|
|
|
return rc;
|
|
|
#endif /* ! BNX2X_STOP_ON_ERROR */
|
|
|
}
|
|
|
|
|
|
+static int bnx2x_drain_tx_queues(struct bnx2x *bp)
|
|
|
+{
|
|
|
+ u8 rc = 0, cos, i;
|
|
|
+
|
|
|
+ /* Wait until tx fastpath tasks complete */
|
|
|
+ for_each_tx_queue(bp, i) {
|
|
|
+ struct bnx2x_fastpath *fp = &bp->fp[i];
|
|
|
+
|
|
|
+ for_each_cos_in_tx_queue(fp, cos)
|
|
|
+ rc = bnx2x_clean_tx_queue(bp, fp->txdata_ptr[cos]);
|
|
|
+ if (rc)
|
|
|
+ return rc;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/* must be called with rtnl_lock */
|
|
|
int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
|
|
|
{
|
|
@@ -2522,15 +2715,16 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
|
|
|
DP(NETIF_MSG_IFUP, "Starting NIC unload\n");
|
|
|
|
|
|
/* mark driver is unloaded in shmem2 */
|
|
|
- if (SHMEM2_HAS(bp, drv_capabilities_flag)) {
|
|
|
+ if (IS_PF(bp) && SHMEM2_HAS(bp, drv_capabilities_flag)) {
|
|
|
u32 val;
|
|
|
val = SHMEM2_RD(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)]);
|
|
|
SHMEM2_WR(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)],
|
|
|
val & ~DRV_FLAGS_CAPABILITIES_LOADED_L2);
|
|
|
}
|
|
|
|
|
|
- if ((bp->state == BNX2X_STATE_CLOSED) ||
|
|
|
- (bp->state == BNX2X_STATE_ERROR)) {
|
|
|
+ if (IS_PF(bp) &&
|
|
|
+ (bp->state == BNX2X_STATE_CLOSED ||
|
|
|
+ bp->state == BNX2X_STATE_ERROR)) {
|
|
|
/* We can get here if the driver has been unloaded
|
|
|
* during parity error recovery and is either waiting for a
|
|
|
* leader to complete or for other functions to unload and
|
|
@@ -2567,13 +2761,16 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
|
|
|
|
|
|
del_timer_sync(&bp->timer);
|
|
|
|
|
|
- /* Set ALWAYS_ALIVE bit in shmem */
|
|
|
- bp->fw_drv_pulse_wr_seq |= DRV_PULSE_ALWAYS_ALIVE;
|
|
|
-
|
|
|
- bnx2x_drv_pulse(bp);
|
|
|
+ if (IS_PF(bp)) {
|
|
|
+ /* Set ALWAYS_ALIVE bit in shmem */
|
|
|
+ bp->fw_drv_pulse_wr_seq |= DRV_PULSE_ALWAYS_ALIVE;
|
|
|
+ bnx2x_drv_pulse(bp);
|
|
|
+ bnx2x_stats_handle(bp, STATS_EVENT_STOP);
|
|
|
+ bnx2x_save_statistics(bp);
|
|
|
+ }
|
|
|
|
|
|
- bnx2x_stats_handle(bp, STATS_EVENT_STOP);
|
|
|
- bnx2x_save_statistics(bp);
|
|
|
+ /* wait till consumers catch up with producers in all queues */
|
|
|
+ bnx2x_drain_tx_queues(bp);
|
|
|
|
|
|
/* Cleanup the chip if needed */
|
|
|
if (unload_mode != UNLOAD_RECOVERY)
|
|
@@ -2609,7 +2806,8 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
|
|
|
* At this stage no more interrupts will arrive so we may safly clean
|
|
|
* the queueable objects here in case they failed to get cleaned so far.
|
|
|
*/
|
|
|
- bnx2x_squeeze_objects(bp);
|
|
|
+ if (IS_PF(bp))
|
|
|
+ bnx2x_squeeze_objects(bp);
|
|
|
|
|
|
/* There should be no more pending SP commands at this stage */
|
|
|
bp->sp_state = 0;
|
|
@@ -2623,19 +2821,22 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
|
|
|
for_each_rx_queue(bp, i)
|
|
|
bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
|
|
|
|
|
|
- if (CNIC_LOADED(bp)) {
|
|
|
+ bnx2x_free_fp_mem(bp);
|
|
|
+ if (CNIC_LOADED(bp))
|
|
|
bnx2x_free_fp_mem_cnic(bp);
|
|
|
- bnx2x_free_mem_cnic(bp);
|
|
|
- }
|
|
|
- bnx2x_free_mem(bp);
|
|
|
|
|
|
+ if (IS_PF(bp)) {
|
|
|
+ bnx2x_free_mem(bp);
|
|
|
+ if (CNIC_LOADED(bp))
|
|
|
+ bnx2x_free_mem_cnic(bp);
|
|
|
+ }
|
|
|
bp->state = BNX2X_STATE_CLOSED;
|
|
|
bp->cnic_loaded = false;
|
|
|
|
|
|
/* Check if there are pending parity attentions. If there are - set
|
|
|
* RECOVERY_IN_PROGRESS.
|
|
|
*/
|
|
|
- if (bnx2x_chk_parity_attn(bp, &global, false)) {
|
|
|
+ if (IS_PF(bp) && bnx2x_chk_parity_attn(bp, &global, false)) {
|
|
|
bnx2x_set_reset_in_progress(bp);
|
|
|
|
|
|
/* Set RESET_IS_GLOBAL if needed */
|
|
@@ -2647,7 +2848,9 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
|
|
|
/* The last driver must disable a "close the gate" if there is no
|
|
|
* parity attention or "process kill" pending.
|
|
|
*/
|
|
|
- if (!bnx2x_clear_pf_load(bp) && bnx2x_reset_is_done(bp, BP_PATH(bp)))
|
|
|
+ if (IS_PF(bp) &&
|
|
|
+ !bnx2x_clear_pf_load(bp) &&
|
|
|
+ bnx2x_reset_is_done(bp, BP_PATH(bp)))
|
|
|
bnx2x_disable_close_the_gate(bp);
|
|
|
|
|
|
DP(NETIF_MSG_IFUP, "Ending NIC unload\n");
|