Merge branch 'master' of github.com:davem330/net
David S. Miller [Fri, 7 Oct 2011 17:38:43 +0000 (13:38 -0400)]
Conflicts:
net/batman-adv/soft-interface.c

21 files changed:
1  2 
Documentation/networking/ip-sysctl.txt
MAINTAINERS
drivers/net/bonding/bond_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
drivers/net/ethernet/chelsio/cxgb3/l2t.c
drivers/net/ethernet/chelsio/cxgb3/l2t.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/ibm/ibmveth.c
drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
drivers/net/macvlan.c
drivers/net/phy/dp83640.c
include/linux/pci.h
net/batman-adv/soft-interface.c
net/bridge/br_device.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv6/tcp_ipv6.c
net/packet/af_packet.c

@@@ -1042,14 -1042,9 +1042,14 @@@ conf/interface/*
        The functional behaviour for certain settings is different
        depending on whether local forwarding is enabled or not.
  
- accept_ra - BOOLEAN
+ accept_ra - INTEGER
        Accept Router Advertisements; autoconfigure using them.
  
 +      It also determines whether or not to transmit Router
 +      Solicitations. If and only if the functional setting is to
 +      accept Router Advertisements, Router Solicitations will be
 +      transmitted.
 +
        Possible values are:
                0 Do not accept Router Advertisements.
                1 Accept Router Advertisements if forwarding is disabled.
diff --cc MAINTAINERS
Simple merge
Simple merge
index 0b9bd55,0000000..51bd748
mode 100644,000000..100644
--- /dev/null
@@@ -1,2510 -1,0 +1,2511 @@@
 +/* bnx2x_dcb.c: Broadcom Everest network driver.
 + *
 + * Copyright 2009-2011 Broadcom Corporation
 + *
 + * Unless you and Broadcom execute a separate written software license
 + * agreement governing use of this software, this software is licensed to you
 + * under the terms of the GNU General Public License version 2, available
 + * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
 + *
 + * Notwithstanding the above, under no circumstances may you combine this
 + * software in any way with any other Broadcom software provided under a
 + * license other than the GPL, without Broadcom's express prior written
 + * consent.
 + *
 + * Maintained by: Eilon Greenstein <eilong@broadcom.com>
 + * Written by: Dmitry Kravkov
 + *
 + */
 +
 +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 +
 +#include <linux/netdevice.h>
 +#include <linux/types.h>
 +#include <linux/errno.h>
 +#include <linux/rtnetlink.h>
 +#include <net/dcbnl.h>
 +
 +#include "bnx2x.h"
 +#include "bnx2x_cmn.h"
 +#include "bnx2x_dcb.h"
 +
 +/* forward declarations of dcbx related functions */
 +static int bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp);
 +static void bnx2x_pfc_set_pfc(struct bnx2x *bp);
 +static void bnx2x_dcbx_update_ets_params(struct bnx2x *bp);
 +static int bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp);
 +static void bnx2x_dcbx_get_ets_pri_pg_tbl(struct bnx2x *bp,
 +                                        u32 *set_configuration_ets_pg,
 +                                        u32 *pri_pg_tbl);
 +static void bnx2x_dcbx_get_num_pg_traf_type(struct bnx2x *bp,
 +                                          u32 *pg_pri_orginal_spread,
 +                                          struct pg_help_data *help_data);
 +static void bnx2x_dcbx_fill_cos_params(struct bnx2x *bp,
 +                                     struct pg_help_data *help_data,
 +                                     struct dcbx_ets_feature *ets,
 +                                     u32 *pg_pri_orginal_spread);
 +static void bnx2x_dcbx_separate_pauseable_from_non(struct bnx2x *bp,
 +                              struct cos_help_data *cos_data,
 +                              u32 *pg_pri_orginal_spread,
 +                              struct dcbx_ets_feature *ets);
 +static void bnx2x_dcbx_fw_struct(struct bnx2x *bp,
 +                               struct bnx2x_func_tx_start_params*);
 +
 +/* helpers: read/write len bytes from addr into buff by REG_RD/REG_WR */
 +static void bnx2x_read_data(struct bnx2x *bp, u32 *buff,
 +                                 u32 addr, u32 len)
 +{
 +      int i;
 +      for (i = 0; i < len; i += 4, buff++)
 +              *buff = REG_RD(bp, addr + i);
 +}
 +
 +static void bnx2x_write_data(struct bnx2x *bp, u32 *buff,
 +                                  u32 addr, u32 len)
 +{
 +      int i;
 +      for (i = 0; i < len; i += 4, buff++)
 +              REG_WR(bp, addr + i, *buff);
 +}
 +
 +static void bnx2x_pfc_set(struct bnx2x *bp)
 +{
 +      struct bnx2x_nig_brb_pfc_port_params pfc_params = {0};
 +      u32 pri_bit, val = 0;
 +      int i;
 +
 +      pfc_params.num_of_rx_cos_priority_mask =
 +                                      bp->dcbx_port_params.ets.num_of_cos;
 +
 +      /* Tx COS configuration */
 +      for (i = 0; i < bp->dcbx_port_params.ets.num_of_cos; i++)
 +              /*
 +               * We configure only the pauseable bits (non pauseable aren't
 +               * configured at all) it's done to avoid false pauses from
 +               * network
 +               */
 +              pfc_params.rx_cos_priority_mask[i] =
 +                      bp->dcbx_port_params.ets.cos_params[i].pri_bitmask
 +                              & DCBX_PFC_PRI_PAUSE_MASK(bp);
 +
 +      /*
 +       * Rx COS configuration
 +       * Changing PFC RX configuration .
 +       * In RX COS0 will always be configured to lossy and COS1 to lossless
 +       */
 +      for (i = 0 ; i < MAX_PFC_PRIORITIES ; i++) {
 +              pri_bit = 1 << i;
 +
 +              if (pri_bit & DCBX_PFC_PRI_PAUSE_MASK(bp))
 +                      val |= 1 << (i * 4);
 +      }
 +
 +      pfc_params.pkt_priority_to_cos = val;
 +
 +      /* RX COS0 */
 +      pfc_params.llfc_low_priority_classes = 0;
 +      /* RX COS1 */
 +      pfc_params.llfc_high_priority_classes = DCBX_PFC_PRI_PAUSE_MASK(bp);
 +
 +      /* BRB configuration */
 +      pfc_params.cos0_pauseable = false;
 +      pfc_params.cos1_pauseable = true;
 +
 +      bnx2x_acquire_phy_lock(bp);
 +      bp->link_params.feature_config_flags |= FEATURE_CONFIG_PFC_ENABLED;
 +      bnx2x_update_pfc(&bp->link_params, &bp->link_vars, &pfc_params);
 +      bnx2x_release_phy_lock(bp);
 +}
 +
 +static void bnx2x_pfc_clear(struct bnx2x *bp)
 +{
 +      struct bnx2x_nig_brb_pfc_port_params nig_params = {0};
 +      nig_params.pause_enable = 1;
 +#ifdef BNX2X_SAFC
 +      if (bp->flags & SAFC_TX_FLAG) {
 +              u32 high = 0, low = 0;
 +              int i;
 +
 +              for (i = 0; i < BNX2X_MAX_PRIORITY; i++) {
 +                      if (bp->pri_map[i] == 1)
 +                              high |= (1 << i);
 +                      if (bp->pri_map[i] == 0)
 +                              low |= (1 << i);
 +              }
 +
 +              nig_params.llfc_low_priority_classes = high;
 +              nig_params.llfc_low_priority_classes = low;
 +
 +              nig_params.pause_enable = 0;
 +              nig_params.llfc_enable = 1;
 +              nig_params.llfc_out_en = 1;
 +      }
 +#endif /* BNX2X_SAFC */
 +      bnx2x_acquire_phy_lock(bp);
 +      bp->link_params.feature_config_flags &= ~FEATURE_CONFIG_PFC_ENABLED;
 +      bnx2x_update_pfc(&bp->link_params, &bp->link_vars, &nig_params);
 +      bnx2x_release_phy_lock(bp);
 +}
 +
 +static void  bnx2x_dump_dcbx_drv_param(struct bnx2x *bp,
 +                                     struct dcbx_features *features,
 +                                     u32 error)
 +{
 +      u8 i = 0;
 +      DP(NETIF_MSG_LINK, "local_mib.error %x\n", error);
 +
 +      /* PG */
 +      DP(NETIF_MSG_LINK,
 +         "local_mib.features.ets.enabled %x\n", features->ets.enabled);
 +      for (i = 0; i < DCBX_MAX_NUM_PG_BW_ENTRIES; i++)
 +              DP(NETIF_MSG_LINK,
 +                 "local_mib.features.ets.pg_bw_tbl[%d] %d\n", i,
 +                 DCBX_PG_BW_GET(features->ets.pg_bw_tbl, i));
 +      for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES; i++)
 +              DP(NETIF_MSG_LINK,
 +                 "local_mib.features.ets.pri_pg_tbl[%d] %d\n", i,
 +                 DCBX_PRI_PG_GET(features->ets.pri_pg_tbl, i));
 +
 +      /* pfc */
 +      DP(NETIF_MSG_LINK, "dcbx_features.pfc.pri_en_bitmap %x\n",
 +                                      features->pfc.pri_en_bitmap);
 +      DP(NETIF_MSG_LINK, "dcbx_features.pfc.pfc_caps %x\n",
 +                                      features->pfc.pfc_caps);
 +      DP(NETIF_MSG_LINK, "dcbx_features.pfc.enabled %x\n",
 +                                      features->pfc.enabled);
 +
 +      DP(NETIF_MSG_LINK, "dcbx_features.app.default_pri %x\n",
 +                                      features->app.default_pri);
 +      DP(NETIF_MSG_LINK, "dcbx_features.app.tc_supported %x\n",
 +                                      features->app.tc_supported);
 +      DP(NETIF_MSG_LINK, "dcbx_features.app.enabled %x\n",
 +                                      features->app.enabled);
 +      for (i = 0; i < DCBX_MAX_APP_PROTOCOL; i++) {
 +              DP(NETIF_MSG_LINK,
 +                 "dcbx_features.app.app_pri_tbl[%x].app_id %x\n",
 +                 i, features->app.app_pri_tbl[i].app_id);
 +              DP(NETIF_MSG_LINK,
 +                 "dcbx_features.app.app_pri_tbl[%x].pri_bitmap %x\n",
 +                 i, features->app.app_pri_tbl[i].pri_bitmap);
 +              DP(NETIF_MSG_LINK,
 +                 "dcbx_features.app.app_pri_tbl[%x].appBitfield %x\n",
 +                 i, features->app.app_pri_tbl[i].appBitfield);
 +      }
 +}
 +
 +static void bnx2x_dcbx_get_ap_priority(struct bnx2x *bp,
 +                                     u8 pri_bitmap,
 +                                     u8 llfc_traf_type)
 +{
 +      u32 pri = MAX_PFC_PRIORITIES;
 +      u32 index = MAX_PFC_PRIORITIES - 1;
 +      u32 pri_mask;
 +      u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority;
 +
 +      /* Choose the highest priority */
 +      while ((MAX_PFC_PRIORITIES == pri) && (0 != index)) {
 +              pri_mask = 1 << index;
 +              if (GET_FLAGS(pri_bitmap, pri_mask))
 +                      pri = index ;
 +              index--;
 +      }
 +
 +      if (pri < MAX_PFC_PRIORITIES)
 +              ttp[llfc_traf_type] = max_t(u32, ttp[llfc_traf_type], pri);
 +}
 +
 +static void bnx2x_dcbx_get_ap_feature(struct bnx2x *bp,
 +                                 struct dcbx_app_priority_feature *app,
 +                                 u32 error) {
 +      u8 index;
 +      u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority;
 +
 +      if (GET_FLAGS(error, DCBX_LOCAL_APP_ERROR))
 +              DP(NETIF_MSG_LINK, "DCBX_LOCAL_APP_ERROR\n");
 +
 +      if (GET_FLAGS(error, DCBX_LOCAL_APP_MISMATCH))
 +              DP(NETIF_MSG_LINK, "DCBX_LOCAL_APP_MISMATCH\n");
 +
 +      if (app->enabled &&
 +          !GET_FLAGS(error, DCBX_LOCAL_APP_ERROR | DCBX_LOCAL_APP_MISMATCH)) {
 +
 +              bp->dcbx_port_params.app.enabled = true;
 +
 +              for (index = 0 ; index < LLFC_DRIVER_TRAFFIC_TYPE_MAX; index++)
 +                      ttp[index] = 0;
 +
 +              if (app->default_pri < MAX_PFC_PRIORITIES)
 +                      ttp[LLFC_TRAFFIC_TYPE_NW] = app->default_pri;
 +
 +              for (index = 0 ; index < DCBX_MAX_APP_PROTOCOL; index++) {
 +                      struct dcbx_app_priority_entry *entry =
 +                                                      app->app_pri_tbl;
 +
 +                      if (GET_FLAGS(entry[index].appBitfield,
 +                                   DCBX_APP_SF_ETH_TYPE) &&
 +                         ETH_TYPE_FCOE == entry[index].app_id)
 +                              bnx2x_dcbx_get_ap_priority(bp,
 +                                              entry[index].pri_bitmap,
 +                                              LLFC_TRAFFIC_TYPE_FCOE);
 +
 +                      if (GET_FLAGS(entry[index].appBitfield,
 +                                   DCBX_APP_SF_PORT) &&
 +                         TCP_PORT_ISCSI == entry[index].app_id)
 +                              bnx2x_dcbx_get_ap_priority(bp,
 +                                              entry[index].pri_bitmap,
 +                                              LLFC_TRAFFIC_TYPE_ISCSI);
 +              }
 +      } else {
 +              DP(NETIF_MSG_LINK, "DCBX_LOCAL_APP_DISABLED\n");
 +              bp->dcbx_port_params.app.enabled = false;
 +              for (index = 0 ; index < LLFC_DRIVER_TRAFFIC_TYPE_MAX; index++)
 +                      ttp[index] = INVALID_TRAFFIC_TYPE_PRIORITY;
 +      }
 +}
 +
 +static void bnx2x_dcbx_get_ets_feature(struct bnx2x *bp,
 +                                     struct dcbx_ets_feature *ets,
 +                                     u32 error) {
 +      int i = 0;
 +      u32 pg_pri_orginal_spread[DCBX_MAX_NUM_PG_BW_ENTRIES] = {0};
 +      struct pg_help_data pg_help_data;
 +      struct bnx2x_dcbx_cos_params *cos_params =
 +                      bp->dcbx_port_params.ets.cos_params;
 +
 +      memset(&pg_help_data, 0, sizeof(struct pg_help_data));
 +
 +
 +      if (GET_FLAGS(error, DCBX_LOCAL_ETS_ERROR))
 +              DP(NETIF_MSG_LINK, "DCBX_LOCAL_ETS_ERROR\n");
 +
 +
 +      /* Clean up old settings of ets on COS */
 +      for (i = 0; i < ARRAY_SIZE(bp->dcbx_port_params.ets.cos_params) ; i++) {
 +              cos_params[i].pauseable = false;
 +              cos_params[i].strict = BNX2X_DCBX_STRICT_INVALID;
 +              cos_params[i].bw_tbl = DCBX_INVALID_COS_BW;
 +              cos_params[i].pri_bitmask = 0;
 +      }
 +
 +      if (bp->dcbx_port_params.app.enabled &&
 +         !GET_FLAGS(error, DCBX_LOCAL_ETS_ERROR) &&
 +         ets->enabled) {
 +              DP(NETIF_MSG_LINK, "DCBX_LOCAL_ETS_ENABLE\n");
 +              bp->dcbx_port_params.ets.enabled = true;
 +
 +              bnx2x_dcbx_get_ets_pri_pg_tbl(bp,
 +                                            pg_pri_orginal_spread,
 +                                            ets->pri_pg_tbl);
 +
 +              bnx2x_dcbx_get_num_pg_traf_type(bp,
 +                                              pg_pri_orginal_spread,
 +                                              &pg_help_data);
 +
 +              bnx2x_dcbx_fill_cos_params(bp, &pg_help_data,
 +                                         ets, pg_pri_orginal_spread);
 +
 +      } else {
 +              DP(NETIF_MSG_LINK, "DCBX_LOCAL_ETS_DISABLED\n");
 +              bp->dcbx_port_params.ets.enabled = false;
 +              ets->pri_pg_tbl[0] = 0;
 +
 +              for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES ; i++)
 +                      DCBX_PG_BW_SET(ets->pg_bw_tbl, i, 1);
 +      }
 +}
 +
 +static void  bnx2x_dcbx_get_pfc_feature(struct bnx2x *bp,
 +                                      struct dcbx_pfc_feature *pfc, u32 error)
 +{
 +
 +      if (GET_FLAGS(error, DCBX_LOCAL_PFC_ERROR))
 +              DP(NETIF_MSG_LINK, "DCBX_LOCAL_PFC_ERROR\n");
 +
 +      if (bp->dcbx_port_params.app.enabled &&
 +         !GET_FLAGS(error, DCBX_LOCAL_PFC_ERROR | DCBX_LOCAL_PFC_MISMATCH) &&
 +         pfc->enabled) {
 +              bp->dcbx_port_params.pfc.enabled = true;
 +              bp->dcbx_port_params.pfc.priority_non_pauseable_mask =
 +                      ~(pfc->pri_en_bitmap);
 +      } else {
 +              DP(NETIF_MSG_LINK, "DCBX_LOCAL_PFC_DISABLED\n");
 +              bp->dcbx_port_params.pfc.enabled = false;
 +              bp->dcbx_port_params.pfc.priority_non_pauseable_mask = 0;
 +      }
 +}
 +
 +/* maps unmapped priorities to to the same COS as L2 */
 +static void bnx2x_dcbx_map_nw(struct bnx2x *bp)
 +{
 +      int i;
 +      u32 unmapped = (1 << MAX_PFC_PRIORITIES) - 1; /* all ones */
 +      u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority;
 +      u32 nw_prio = 1 << ttp[LLFC_TRAFFIC_TYPE_NW];
 +      struct bnx2x_dcbx_cos_params *cos_params =
 +                      bp->dcbx_port_params.ets.cos_params;
 +
 +      /* get unmapped priorities by clearing mapped bits */
 +      for (i = 0; i < LLFC_DRIVER_TRAFFIC_TYPE_MAX; i++)
 +              unmapped &= ~(1 << ttp[i]);
 +
 +      /* find cos for nw prio and extend it with unmapped */
 +      for (i = 0; i < ARRAY_SIZE(bp->dcbx_port_params.ets.cos_params); i++) {
 +              if (cos_params[i].pri_bitmask & nw_prio) {
 +                      /* extend the bitmask with unmapped */
 +                      DP(NETIF_MSG_LINK,
 +                         "cos %d extended with 0x%08x\n", i, unmapped);
 +                      cos_params[i].pri_bitmask |= unmapped;
 +                      break;
 +              }
 +      }
 +}
 +
 +static void bnx2x_get_dcbx_drv_param(struct bnx2x *bp,
 +                                   struct dcbx_features *features,
 +                                   u32 error)
 +{
 +      bnx2x_dcbx_get_ap_feature(bp, &features->app, error);
 +
 +      bnx2x_dcbx_get_pfc_feature(bp, &features->pfc, error);
 +
 +      bnx2x_dcbx_get_ets_feature(bp, &features->ets, error);
 +
 +      bnx2x_dcbx_map_nw(bp);
 +}
 +
 +#define DCBX_LOCAL_MIB_MAX_TRY_READ           (100)
 +static int bnx2x_dcbx_read_mib(struct bnx2x *bp,
 +                             u32 *base_mib_addr,
 +                             u32 offset,
 +                             int read_mib_type)
 +{
 +      int max_try_read = 0;
 +      u32 mib_size, prefix_seq_num, suffix_seq_num;
 +      struct lldp_remote_mib *remote_mib ;
 +      struct lldp_local_mib  *local_mib;
 +
 +
 +      switch (read_mib_type) {
 +      case DCBX_READ_LOCAL_MIB:
 +              mib_size = sizeof(struct lldp_local_mib);
 +              break;
 +      case DCBX_READ_REMOTE_MIB:
 +              mib_size = sizeof(struct lldp_remote_mib);
 +              break;
 +      default:
 +              return 1; /*error*/
 +      }
 +
 +      offset += BP_PORT(bp) * mib_size;
 +
 +      do {
 +              bnx2x_read_data(bp, base_mib_addr, offset, mib_size);
 +
 +              max_try_read++;
 +
 +              switch (read_mib_type) {
 +              case DCBX_READ_LOCAL_MIB:
 +                      local_mib = (struct lldp_local_mib *) base_mib_addr;
 +                      prefix_seq_num = local_mib->prefix_seq_num;
 +                      suffix_seq_num = local_mib->suffix_seq_num;
 +                      break;
 +              case DCBX_READ_REMOTE_MIB:
 +                      remote_mib = (struct lldp_remote_mib *) base_mib_addr;
 +                      prefix_seq_num = remote_mib->prefix_seq_num;
 +                      suffix_seq_num = remote_mib->suffix_seq_num;
 +                      break;
 +              default:
 +                      return 1; /*error*/
 +              }
 +      } while ((prefix_seq_num != suffix_seq_num) &&
 +             (max_try_read < DCBX_LOCAL_MIB_MAX_TRY_READ));
 +
 +      if (max_try_read >= DCBX_LOCAL_MIB_MAX_TRY_READ) {
 +              BNX2X_ERR("MIB could not be read\n");
 +              return 1;
 +      }
 +
 +      return 0;
 +}
 +
 +static void bnx2x_pfc_set_pfc(struct bnx2x *bp)
 +{
 +      if (bp->dcbx_port_params.pfc.enabled &&
 +          !(bp->dcbx_error & DCBX_REMOTE_MIB_ERROR))
 +              /*
 +               * 1. Fills up common PFC structures if required
 +               * 2. Configure NIG, MAC and BRB via the elink
 +               */
 +              bnx2x_pfc_set(bp);
 +      else
 +              bnx2x_pfc_clear(bp);
 +}
 +
 +static int bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp)
 +{
 +      struct bnx2x_func_state_params func_params = {0};
 +
 +      func_params.f_obj = &bp->func_obj;
 +      func_params.cmd = BNX2X_F_CMD_TX_STOP;
 +
 +      DP(NETIF_MSG_LINK, "STOP TRAFFIC\n");
 +      return bnx2x_func_state_change(bp, &func_params);
 +}
 +
 +static int bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp)
 +{
 +      struct bnx2x_func_state_params func_params = {0};
 +      struct bnx2x_func_tx_start_params *tx_params =
 +              &func_params.params.tx_start;
 +
 +      func_params.f_obj = &bp->func_obj;
 +      func_params.cmd = BNX2X_F_CMD_TX_START;
 +
 +      bnx2x_dcbx_fw_struct(bp, tx_params);
 +
 +      DP(NETIF_MSG_LINK, "START TRAFFIC\n");
 +      return bnx2x_func_state_change(bp, &func_params);
 +}
 +
 +static void bnx2x_dcbx_2cos_limit_update_ets_config(struct bnx2x *bp)
 +{
 +      struct bnx2x_dcbx_pg_params *ets = &(bp->dcbx_port_params.ets);
 +      int rc = 0;
 +
 +      if (ets->num_of_cos == 0 || ets->num_of_cos > DCBX_COS_MAX_NUM_E2) {
 +              BNX2X_ERR("Illegal number of COSes %d\n", ets->num_of_cos);
 +              return;
 +      }
 +
 +      /* valid COS entries */
 +      if (ets->num_of_cos == 1)   /* no ETS */
 +              return;
 +
 +      /* sanity */
 +      if (((BNX2X_DCBX_STRICT_INVALID == ets->cos_params[0].strict) &&
 +           (DCBX_INVALID_COS_BW == ets->cos_params[0].bw_tbl)) ||
 +          ((BNX2X_DCBX_STRICT_INVALID == ets->cos_params[1].strict) &&
 +           (DCBX_INVALID_COS_BW == ets->cos_params[1].bw_tbl))) {
 +              BNX2X_ERR("all COS should have at least bw_limit or strict"
 +                          "ets->cos_params[0].strict= %x"
 +                          "ets->cos_params[0].bw_tbl= %x"
 +                          "ets->cos_params[1].strict= %x"
 +                          "ets->cos_params[1].bw_tbl= %x",
 +                        ets->cos_params[0].strict,
 +                        ets->cos_params[0].bw_tbl,
 +                        ets->cos_params[1].strict,
 +                        ets->cos_params[1].bw_tbl);
 +              return;
 +      }
 +      /* If we join a group and there is bw_tbl and strict then bw rules */
 +      if ((DCBX_INVALID_COS_BW != ets->cos_params[0].bw_tbl) &&
 +          (DCBX_INVALID_COS_BW != ets->cos_params[1].bw_tbl)) {
 +              u32 bw_tbl_0 = ets->cos_params[0].bw_tbl;
 +              u32 bw_tbl_1 = ets->cos_params[1].bw_tbl;
 +              /* Do not allow 0-100 configuration
 +               * since PBF does not support it
 +               * force 1-99 instead
 +               */
 +              if (bw_tbl_0 == 0) {
 +                      bw_tbl_0 = 1;
 +                      bw_tbl_1 = 99;
 +              } else if (bw_tbl_1 == 0) {
 +                      bw_tbl_1 = 1;
 +                      bw_tbl_0 = 99;
 +              }
 +
 +              bnx2x_ets_bw_limit(&bp->link_params, bw_tbl_0, bw_tbl_1);
 +      } else {
 +              if (ets->cos_params[0].strict == BNX2X_DCBX_STRICT_COS_HIGHEST)
 +                      rc = bnx2x_ets_strict(&bp->link_params, 0);
 +              else if (ets->cos_params[1].strict
 +                                      == BNX2X_DCBX_STRICT_COS_HIGHEST)
 +                      rc = bnx2x_ets_strict(&bp->link_params, 1);
 +              if (rc)
 +                      BNX2X_ERR("update_ets_params failed\n");
 +      }
 +}
 +
 +/*
 + * In E3B0 the configuration may have more than 2 COS.
 + */
 +void bnx2x_dcbx_update_ets_config(struct bnx2x *bp)
 +{
 +      struct bnx2x_dcbx_pg_params *ets = &(bp->dcbx_port_params.ets);
 +      struct bnx2x_ets_params ets_params = { 0 };
 +      u8 i;
 +
 +      ets_params.num_of_cos = ets->num_of_cos;
 +
 +      for (i = 0; i < ets->num_of_cos; i++) {
 +              /* COS is SP */
 +              if (ets->cos_params[i].strict != BNX2X_DCBX_STRICT_INVALID) {
 +                      if (ets->cos_params[i].bw_tbl != DCBX_INVALID_COS_BW) {
 +                              BNX2X_ERR("COS can't be not BW and not SP\n");
 +                              return;
 +                      }
 +
 +                      ets_params.cos[i].state = bnx2x_cos_state_strict;
 +                      ets_params.cos[i].params.sp_params.pri =
 +                                              ets->cos_params[i].strict;
 +              } else { /* COS is BW */
 +                      if (ets->cos_params[i].bw_tbl == DCBX_INVALID_COS_BW) {
 +                              BNX2X_ERR("COS can't be not BW and not SP\n");
 +                              return;
 +                      }
 +                      ets_params.cos[i].state = bnx2x_cos_state_bw;
 +                      ets_params.cos[i].params.bw_params.bw =
 +                                              (u8)ets->cos_params[i].bw_tbl;
 +              }
 +      }
 +
 +      /* Configure the ETS in HW */
 +      if (bnx2x_ets_e3b0_config(&bp->link_params, &bp->link_vars,
 +                                &ets_params)) {
 +              BNX2X_ERR("bnx2x_ets_e3b0_config failed\n");
 +              bnx2x_ets_disabled(&bp->link_params, &bp->link_vars);
 +      }
 +}
 +
 +static void bnx2x_dcbx_update_ets_params(struct bnx2x *bp)
 +{
 +      bnx2x_ets_disabled(&bp->link_params, &bp->link_vars);
 +
 +      if (!bp->dcbx_port_params.ets.enabled ||
 +          (bp->dcbx_error & DCBX_REMOTE_MIB_ERROR))
 +              return;
 +
 +      if (CHIP_IS_E3B0(bp))
 +              bnx2x_dcbx_update_ets_config(bp);
 +      else
 +              bnx2x_dcbx_2cos_limit_update_ets_config(bp);
 +}
 +
 +#ifdef BCM_DCBNL
 +static int bnx2x_dcbx_read_shmem_remote_mib(struct bnx2x *bp)
 +{
 +      struct lldp_remote_mib remote_mib = {0};
 +      u32 dcbx_remote_mib_offset = SHMEM2_RD(bp, dcbx_remote_mib_offset);
 +      int rc;
 +
 +      DP(NETIF_MSG_LINK, "dcbx_remote_mib_offset 0x%x\n",
 +         dcbx_remote_mib_offset);
 +
 +      if (SHMEM_DCBX_REMOTE_MIB_NONE == dcbx_remote_mib_offset) {
 +              BNX2X_ERR("FW doesn't support dcbx_remote_mib_offset\n");
 +              return -EINVAL;
 +      }
 +
 +      rc = bnx2x_dcbx_read_mib(bp, (u32 *)&remote_mib, dcbx_remote_mib_offset,
 +                               DCBX_READ_REMOTE_MIB);
 +
 +      if (rc) {
 +              BNX2X_ERR("Faild to read remote mib from FW\n");
 +              return rc;
 +      }
 +
 +      /* save features and flags */
 +      bp->dcbx_remote_feat = remote_mib.features;
 +      bp->dcbx_remote_flags = remote_mib.flags;
 +      return 0;
 +}
 +#endif
 +
 +static int bnx2x_dcbx_read_shmem_neg_results(struct bnx2x *bp)
 +{
 +      struct lldp_local_mib local_mib = {0};
 +      u32 dcbx_neg_res_offset = SHMEM2_RD(bp, dcbx_neg_res_offset);
 +      int rc;
 +
 +      DP(NETIF_MSG_LINK, "dcbx_neg_res_offset 0x%x\n", dcbx_neg_res_offset);
 +
 +      if (SHMEM_DCBX_NEG_RES_NONE == dcbx_neg_res_offset) {
 +              BNX2X_ERR("FW doesn't support dcbx_neg_res_offset\n");
 +              return -EINVAL;
 +      }
 +
 +      rc = bnx2x_dcbx_read_mib(bp, (u32 *)&local_mib, dcbx_neg_res_offset,
 +                               DCBX_READ_LOCAL_MIB);
 +
 +      if (rc) {
 +              BNX2X_ERR("Faild to read local mib from FW\n");
 +              return rc;
 +      }
 +
 +      /* save features and error */
 +      bp->dcbx_local_feat = local_mib.features;
 +      bp->dcbx_error = local_mib.error;
 +      return 0;
 +}
 +
 +
 +#ifdef BCM_DCBNL
 +static inline
 +u8 bnx2x_dcbx_dcbnl_app_up(struct dcbx_app_priority_entry *ent)
 +{
 +      u8 pri;
 +
 +      /* Choose the highest priority */
 +      for (pri = MAX_PFC_PRIORITIES - 1; pri > 0; pri--)
 +              if (ent->pri_bitmap & (1 << pri))
 +                      break;
 +      return pri;
 +}
 +
 +static inline
 +u8 bnx2x_dcbx_dcbnl_app_idtype(struct dcbx_app_priority_entry *ent)
 +{
 +      return ((ent->appBitfield & DCBX_APP_ENTRY_SF_MASK) ==
 +              DCBX_APP_SF_PORT) ? DCB_APP_IDTYPE_PORTNUM :
 +              DCB_APP_IDTYPE_ETHTYPE;
 +}
 +
 +int bnx2x_dcbnl_update_applist(struct bnx2x *bp, bool delall)
 +{
 +      int i, err = 0;
 +
 +      for (i = 0; i < DCBX_MAX_APP_PROTOCOL && err == 0; i++) {
 +              struct dcbx_app_priority_entry *ent =
 +                      &bp->dcbx_local_feat.app.app_pri_tbl[i];
 +
 +              if (ent->appBitfield & DCBX_APP_ENTRY_VALID) {
 +                      u8 up = bnx2x_dcbx_dcbnl_app_up(ent);
 +
 +                      /* avoid invalid user-priority */
 +                      if (up) {
 +                              struct dcb_app app;
 +                              app.selector = bnx2x_dcbx_dcbnl_app_idtype(ent);
 +                              app.protocol = ent->app_id;
 +                              app.priority = delall ? 0 : up;
 +                              err = dcb_setapp(bp->dev, &app);
 +                      }
 +              }
 +      }
 +      return err;
 +}
 +#endif
 +
 +static inline void bnx2x_update_drv_flags(struct bnx2x *bp, u32 flags, u32 set)
 +{
 +      if (SHMEM2_HAS(bp, drv_flags)) {
 +              u32 drv_flags;
 +              bnx2x_acquire_hw_lock(bp, HW_LOCK_DRV_FLAGS);
 +              drv_flags = SHMEM2_RD(bp, drv_flags);
 +
 +              if (set)
 +                      SET_FLAGS(drv_flags, flags);
 +              else
 +                      RESET_FLAGS(drv_flags, flags);
 +
 +              SHMEM2_WR(bp, drv_flags, drv_flags);
 +              DP(NETIF_MSG_HW, "drv_flags 0x%08x\n", drv_flags);
 +              bnx2x_release_hw_lock(bp, HW_LOCK_DRV_FLAGS);
 +      }
 +}
 +
 +static inline void bnx2x_dcbx_update_tc_mapping(struct bnx2x *bp)
 +{
 +      u8 prio, cos;
 +      for (cos = 0; cos < bp->dcbx_port_params.ets.num_of_cos; cos++) {
 +              for (prio = 0; prio < BNX2X_MAX_PRIORITY; prio++) {
 +                      if (bp->dcbx_port_params.ets.cos_params[cos].pri_bitmask
 +                          & (1 << prio)) {
 +                              bp->prio_to_cos[prio] = cos;
 +                              DP(NETIF_MSG_LINK,
 +                                 "tx_mapping %d --> %d\n", prio, cos);
 +                      }
 +              }
 +      }
 +
 +      /* setup tc must be called under rtnl lock, but we can't take it here
 +       * as we are handling an attetntion on a work queue which must be
 +       * flushed at some rtnl-locked contexts (e.g. if down)
 +       */
 +      if (!test_and_set_bit(BNX2X_SP_RTNL_SETUP_TC, &bp->sp_rtnl_state))
 +              schedule_delayed_work(&bp->sp_rtnl_task, 0);
 +}
 +
 +void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state)
 +{
 +      switch (state) {
 +      case BNX2X_DCBX_STATE_NEG_RECEIVED:
 +              {
 +                      DP(NETIF_MSG_LINK, "BNX2X_DCBX_STATE_NEG_RECEIVED\n");
 +#ifdef BCM_DCBNL
 +                      /**
 +                       * Delete app tlvs from dcbnl before reading new
 +                       * negotiation results
 +                       */
 +                      bnx2x_dcbnl_update_applist(bp, true);
 +
 +                      /* Read rmeote mib if dcbx is in the FW */
 +                      if (bnx2x_dcbx_read_shmem_remote_mib(bp))
 +                              return;
 +#endif
 +                      /* Read neg results if dcbx is in the FW */
 +                      if (bnx2x_dcbx_read_shmem_neg_results(bp))
 +                              return;
 +
 +                      bnx2x_dump_dcbx_drv_param(bp, &bp->dcbx_local_feat,
 +                                                bp->dcbx_error);
 +
 +                      bnx2x_get_dcbx_drv_param(bp, &bp->dcbx_local_feat,
 +                                               bp->dcbx_error);
 +
 +                      /* mark DCBX result for PMF migration */
 +                      bnx2x_update_drv_flags(bp, DRV_FLAGS_DCB_CONFIGURED, 1);
 +#ifdef BCM_DCBNL
 +                      /**
 +                       * Add new app tlvs to dcbnl
 +                       */
 +                      bnx2x_dcbnl_update_applist(bp, false);
 +#endif
 +                      bnx2x_dcbx_stop_hw_tx(bp);
 +
 +                      /* reconfigure the netdevice with the results of the new
 +                       * dcbx negotiation.
 +                       */
 +                      bnx2x_dcbx_update_tc_mapping(bp);
 +
 +                      return;
 +              }
 +      case BNX2X_DCBX_STATE_TX_PAUSED:
 +              DP(NETIF_MSG_LINK, "BNX2X_DCBX_STATE_TX_PAUSED\n");
 +              bnx2x_pfc_set_pfc(bp);
 +
 +              bnx2x_dcbx_update_ets_params(bp);
 +              bnx2x_dcbx_resume_hw_tx(bp);
 +              return;
 +      case BNX2X_DCBX_STATE_TX_RELEASED:
 +              DP(NETIF_MSG_LINK, "BNX2X_DCBX_STATE_TX_RELEASED\n");
 +              bnx2x_fw_command(bp, DRV_MSG_CODE_DCBX_PMF_DRV_OK, 0);
 +#ifdef BCM_DCBNL
 +              /*
 +               * Send a notification for the new negotiated parameters
 +               */
 +              dcbnl_cee_notify(bp->dev, RTM_GETDCB, DCB_CMD_CEE_GET, 0, 0);
 +#endif
 +              return;
 +      default:
 +              BNX2X_ERR("Unknown DCBX_STATE\n");
 +      }
 +}
 +
 +#define LLDP_ADMIN_MIB_OFFSET(bp)     (PORT_MAX*sizeof(struct lldp_params) + \
 +                                    BP_PORT(bp)*sizeof(struct lldp_admin_mib))
 +
 +static void bnx2x_dcbx_admin_mib_updated_params(struct bnx2x *bp,
 +                              u32 dcbx_lldp_params_offset)
 +{
 +      struct lldp_admin_mib admin_mib;
 +      u32 i, other_traf_type = PREDEFINED_APP_IDX_MAX, traf_type = 0;
 +      u32 offset = dcbx_lldp_params_offset + LLDP_ADMIN_MIB_OFFSET(bp);
 +
 +      /*shortcuts*/
 +      struct dcbx_features *af = &admin_mib.features;
 +      struct bnx2x_config_dcbx_params *dp = &bp->dcbx_config_params;
 +
 +      memset(&admin_mib, 0, sizeof(struct lldp_admin_mib));
 +
 +      /* Read the data first */
 +      bnx2x_read_data(bp, (u32 *)&admin_mib, offset,
 +                      sizeof(struct lldp_admin_mib));
 +
 +      if (bp->dcbx_enabled == BNX2X_DCBX_ENABLED_ON_NEG_ON)
 +              SET_FLAGS(admin_mib.ver_cfg_flags, DCBX_DCBX_ENABLED);
 +      else
 +              RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_DCBX_ENABLED);
 +
 +      if (dp->overwrite_settings == BNX2X_DCBX_OVERWRITE_SETTINGS_ENABLE) {
 +
 +              RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_CEE_VERSION_MASK);
 +              admin_mib.ver_cfg_flags |=
 +                      (dp->admin_dcbx_version << DCBX_CEE_VERSION_SHIFT) &
 +                       DCBX_CEE_VERSION_MASK;
 +
 +              af->ets.enabled = (u8)dp->admin_ets_enable;
 +
 +              af->pfc.enabled = (u8)dp->admin_pfc_enable;
 +
 +              /* FOR IEEE dp->admin_tc_supported_tx_enable */
 +              if (dp->admin_ets_configuration_tx_enable)
 +                      SET_FLAGS(admin_mib.ver_cfg_flags,
 +                                DCBX_ETS_CONFIG_TX_ENABLED);
 +              else
 +                      RESET_FLAGS(admin_mib.ver_cfg_flags,
 +                                  DCBX_ETS_CONFIG_TX_ENABLED);
 +              /* For IEEE admin_ets_recommendation_tx_enable */
 +              if (dp->admin_pfc_tx_enable)
 +                      SET_FLAGS(admin_mib.ver_cfg_flags,
 +                                DCBX_PFC_CONFIG_TX_ENABLED);
 +              else
 +                      RESET_FLAGS(admin_mib.ver_cfg_flags,
 +                                DCBX_PFC_CONFIG_TX_ENABLED);
 +
 +              if (dp->admin_application_priority_tx_enable)
 +                      SET_FLAGS(admin_mib.ver_cfg_flags,
 +                                DCBX_APP_CONFIG_TX_ENABLED);
 +              else
 +                      RESET_FLAGS(admin_mib.ver_cfg_flags,
 +                                DCBX_APP_CONFIG_TX_ENABLED);
 +
 +              if (dp->admin_ets_willing)
 +                      SET_FLAGS(admin_mib.ver_cfg_flags, DCBX_ETS_WILLING);
 +              else
 +                      RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_ETS_WILLING);
 +              /* For IEEE admin_ets_reco_valid */
 +              if (dp->admin_pfc_willing)
 +                      SET_FLAGS(admin_mib.ver_cfg_flags, DCBX_PFC_WILLING);
 +              else
 +                      RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_PFC_WILLING);
 +
 +              if (dp->admin_app_priority_willing)
 +                      SET_FLAGS(admin_mib.ver_cfg_flags, DCBX_APP_WILLING);
 +              else
 +                      RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_APP_WILLING);
 +
 +              for (i = 0 ; i < DCBX_MAX_NUM_PG_BW_ENTRIES; i++) {
 +                      DCBX_PG_BW_SET(af->ets.pg_bw_tbl, i,
 +                              (u8)dp->admin_configuration_bw_precentage[i]);
 +
 +                      DP(NETIF_MSG_LINK, "pg_bw_tbl[%d] = %02x\n",
 +                         i, DCBX_PG_BW_GET(af->ets.pg_bw_tbl, i));
 +              }
 +
 +              for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES; i++) {
 +                      DCBX_PRI_PG_SET(af->ets.pri_pg_tbl, i,
 +                                      (u8)dp->admin_configuration_ets_pg[i]);
 +
 +                      DP(NETIF_MSG_LINK, "pri_pg_tbl[%d] = %02x\n",
 +                         i, DCBX_PRI_PG_GET(af->ets.pri_pg_tbl, i));
 +              }
 +
 +              /*For IEEE admin_recommendation_bw_precentage
 +               *For IEEE admin_recommendation_ets_pg */
 +              af->pfc.pri_en_bitmap = (u8)dp->admin_pfc_bitmap;
 +              for (i = 0; i < 4; i++) {
 +                      if (dp->admin_priority_app_table[i].valid) {
 +                              struct bnx2x_admin_priority_app_table *table =
 +                                      dp->admin_priority_app_table;
 +                              if ((ETH_TYPE_FCOE == table[i].app_id) &&
 +                                 (TRAFFIC_TYPE_ETH == table[i].traffic_type))
 +                                      traf_type = FCOE_APP_IDX;
 +                              else if ((TCP_PORT_ISCSI == table[i].app_id) &&
 +                                 (TRAFFIC_TYPE_PORT == table[i].traffic_type))
 +                                      traf_type = ISCSI_APP_IDX;
 +                              else
 +                                      traf_type = other_traf_type++;
 +
 +                              af->app.app_pri_tbl[traf_type].app_id =
 +                                      table[i].app_id;
 +
 +                              af->app.app_pri_tbl[traf_type].pri_bitmap =
 +                                      (u8)(1 << table[i].priority);
 +
 +                              af->app.app_pri_tbl[traf_type].appBitfield =
 +                                  (DCBX_APP_ENTRY_VALID);
 +
 +                              af->app.app_pri_tbl[traf_type].appBitfield |=
 +                                 (TRAFFIC_TYPE_ETH == table[i].traffic_type) ?
 +                                      DCBX_APP_SF_ETH_TYPE : DCBX_APP_SF_PORT;
 +                      }
 +              }
 +
 +              af->app.default_pri = (u8)dp->admin_default_priority;
 +
 +      }
 +
 +      /* Write the data. */
 +      bnx2x_write_data(bp, (u32 *)&admin_mib, offset,
 +                       sizeof(struct lldp_admin_mib));
 +
 +}
 +
 +void bnx2x_dcbx_set_state(struct bnx2x *bp, bool dcb_on, u32 dcbx_enabled)
 +{
 +      if (!CHIP_IS_E1x(bp) && !CHIP_IS_E3(bp)) {
 +              bp->dcb_state = dcb_on;
 +              bp->dcbx_enabled = dcbx_enabled;
 +      } else {
 +              bp->dcb_state = false;
 +              bp->dcbx_enabled = BNX2X_DCBX_ENABLED_INVALID;
 +      }
 +      DP(NETIF_MSG_LINK, "DCB state [%s:%s]\n",
 +         dcb_on ? "ON" : "OFF",
 +         dcbx_enabled == BNX2X_DCBX_ENABLED_OFF ? "user-mode" :
 +         dcbx_enabled == BNX2X_DCBX_ENABLED_ON_NEG_OFF ? "on-chip static" :
 +         dcbx_enabled == BNX2X_DCBX_ENABLED_ON_NEG_ON ?
 +         "on-chip with negotiation" : "invalid");
 +}
 +
 +void bnx2x_dcbx_init_params(struct bnx2x *bp)
 +{
 +      bp->dcbx_config_params.admin_dcbx_version = 0x0; /* 0 - CEE; 1 - IEEE */
 +      bp->dcbx_config_params.admin_ets_willing = 1;
 +      bp->dcbx_config_params.admin_pfc_willing = 1;
 +      bp->dcbx_config_params.overwrite_settings = 1;
 +      bp->dcbx_config_params.admin_ets_enable = 1;
 +      bp->dcbx_config_params.admin_pfc_enable = 1;
 +      bp->dcbx_config_params.admin_tc_supported_tx_enable = 1;
 +      bp->dcbx_config_params.admin_ets_configuration_tx_enable = 1;
 +      bp->dcbx_config_params.admin_pfc_tx_enable = 1;
 +      bp->dcbx_config_params.admin_application_priority_tx_enable = 1;
 +      bp->dcbx_config_params.admin_ets_reco_valid = 1;
 +      bp->dcbx_config_params.admin_app_priority_willing = 1;
 +      bp->dcbx_config_params.admin_configuration_bw_precentage[0] = 00;
 +      bp->dcbx_config_params.admin_configuration_bw_precentage[1] = 50;
 +      bp->dcbx_config_params.admin_configuration_bw_precentage[2] = 50;
 +      bp->dcbx_config_params.admin_configuration_bw_precentage[3] = 0;
 +      bp->dcbx_config_params.admin_configuration_bw_precentage[4] = 0;
 +      bp->dcbx_config_params.admin_configuration_bw_precentage[5] = 0;
 +      bp->dcbx_config_params.admin_configuration_bw_precentage[6] = 0;
 +      bp->dcbx_config_params.admin_configuration_bw_precentage[7] = 0;
 +      bp->dcbx_config_params.admin_configuration_ets_pg[0] = 1;
 +      bp->dcbx_config_params.admin_configuration_ets_pg[1] = 0;
 +      bp->dcbx_config_params.admin_configuration_ets_pg[2] = 0;
 +      bp->dcbx_config_params.admin_configuration_ets_pg[3] = 2;
 +      bp->dcbx_config_params.admin_configuration_ets_pg[4] = 0;
 +      bp->dcbx_config_params.admin_configuration_ets_pg[5] = 0;
 +      bp->dcbx_config_params.admin_configuration_ets_pg[6] = 0;
 +      bp->dcbx_config_params.admin_configuration_ets_pg[7] = 0;
 +      bp->dcbx_config_params.admin_recommendation_bw_precentage[0] = 0;
 +      bp->dcbx_config_params.admin_recommendation_bw_precentage[1] = 1;
 +      bp->dcbx_config_params.admin_recommendation_bw_precentage[2] = 2;
 +      bp->dcbx_config_params.admin_recommendation_bw_precentage[3] = 0;
 +      bp->dcbx_config_params.admin_recommendation_bw_precentage[4] = 7;
 +      bp->dcbx_config_params.admin_recommendation_bw_precentage[5] = 5;
 +      bp->dcbx_config_params.admin_recommendation_bw_precentage[6] = 6;
 +      bp->dcbx_config_params.admin_recommendation_bw_precentage[7] = 7;
 +      bp->dcbx_config_params.admin_recommendation_ets_pg[0] = 0;
 +      bp->dcbx_config_params.admin_recommendation_ets_pg[1] = 1;
 +      bp->dcbx_config_params.admin_recommendation_ets_pg[2] = 2;
 +      bp->dcbx_config_params.admin_recommendation_ets_pg[3] = 3;
 +      bp->dcbx_config_params.admin_recommendation_ets_pg[4] = 4;
 +      bp->dcbx_config_params.admin_recommendation_ets_pg[5] = 5;
 +      bp->dcbx_config_params.admin_recommendation_ets_pg[6] = 6;
 +      bp->dcbx_config_params.admin_recommendation_ets_pg[7] = 7;
 +      bp->dcbx_config_params.admin_pfc_bitmap = 0x8; /* FCoE(3) enable */
 +      bp->dcbx_config_params.admin_priority_app_table[0].valid = 1;
 +      bp->dcbx_config_params.admin_priority_app_table[1].valid = 1;
 +      bp->dcbx_config_params.admin_priority_app_table[2].valid = 0;
 +      bp->dcbx_config_params.admin_priority_app_table[3].valid = 0;
 +      bp->dcbx_config_params.admin_priority_app_table[0].priority = 3;
 +      bp->dcbx_config_params.admin_priority_app_table[1].priority = 0;
 +      bp->dcbx_config_params.admin_priority_app_table[2].priority = 0;
 +      bp->dcbx_config_params.admin_priority_app_table[3].priority = 0;
 +      bp->dcbx_config_params.admin_priority_app_table[0].traffic_type = 0;
 +      bp->dcbx_config_params.admin_priority_app_table[1].traffic_type = 1;
 +      bp->dcbx_config_params.admin_priority_app_table[2].traffic_type = 0;
 +      bp->dcbx_config_params.admin_priority_app_table[3].traffic_type = 0;
 +      bp->dcbx_config_params.admin_priority_app_table[0].app_id = 0x8906;
 +      bp->dcbx_config_params.admin_priority_app_table[1].app_id = 3260;
 +      bp->dcbx_config_params.admin_priority_app_table[2].app_id = 0;
 +      bp->dcbx_config_params.admin_priority_app_table[3].app_id = 0;
 +      bp->dcbx_config_params.admin_default_priority =
 +              bp->dcbx_config_params.admin_priority_app_table[1].priority;
 +}
 +
 +void bnx2x_dcbx_init(struct bnx2x *bp)
 +{
 +      u32 dcbx_lldp_params_offset = SHMEM_LLDP_DCBX_PARAMS_NONE;
 +
 +      if (bp->dcbx_enabled <= 0)
 +              return;
 +
 +      /* validate:
 +       * chip of good for dcbx version,
 +       * dcb is wanted
 +       * the function is pmf
 +       * shmem2 contains DCBX support fields
 +       */
 +      DP(NETIF_MSG_LINK, "dcb_state %d bp->port.pmf %d\n",
 +         bp->dcb_state, bp->port.pmf);
 +
 +      if (bp->dcb_state == BNX2X_DCB_STATE_ON && bp->port.pmf &&
 +          SHMEM2_HAS(bp, dcbx_lldp_params_offset)) {
 +              dcbx_lldp_params_offset =
 +                      SHMEM2_RD(bp, dcbx_lldp_params_offset);
 +
 +              DP(NETIF_MSG_LINK, "dcbx_lldp_params_offset 0x%x\n",
 +                 dcbx_lldp_params_offset);
 +
 +              bnx2x_update_drv_flags(bp, DRV_FLAGS_DCB_CONFIGURED, 0);
 +
 +              if (SHMEM_LLDP_DCBX_PARAMS_NONE != dcbx_lldp_params_offset) {
 +                      bnx2x_dcbx_admin_mib_updated_params(bp,
 +                              dcbx_lldp_params_offset);
 +
 +                      /* Let HW start negotiation */
 +                      bnx2x_fw_command(bp,
 +                                       DRV_MSG_CODE_DCBX_ADMIN_PMF_MSG, 0);
 +              }
 +      }
 +}
 +static void
 +bnx2x_dcbx_print_cos_params(struct bnx2x *bp,
 +                          struct bnx2x_func_tx_start_params *pfc_fw_cfg)
 +{
 +      u8 pri = 0;
 +      u8 cos = 0;
 +
 +      DP(NETIF_MSG_LINK,
 +         "pfc_fw_cfg->dcb_version %x\n", pfc_fw_cfg->dcb_version);
 +      DP(NETIF_MSG_LINK,
 +         "pdev->params.dcbx_port_params.pfc."
 +         "priority_non_pauseable_mask %x\n",
 +         bp->dcbx_port_params.pfc.priority_non_pauseable_mask);
 +
 +      for (cos = 0 ; cos < bp->dcbx_port_params.ets.num_of_cos ; cos++) {
 +              DP(NETIF_MSG_LINK, "pdev->params.dcbx_port_params.ets."
 +                 "cos_params[%d].pri_bitmask %x\n", cos,
 +                 bp->dcbx_port_params.ets.cos_params[cos].pri_bitmask);
 +
 +              DP(NETIF_MSG_LINK, "pdev->params.dcbx_port_params.ets."
 +                 "cos_params[%d].bw_tbl %x\n", cos,
 +                 bp->dcbx_port_params.ets.cos_params[cos].bw_tbl);
 +
 +              DP(NETIF_MSG_LINK, "pdev->params.dcbx_port_params.ets."
 +                 "cos_params[%d].strict %x\n", cos,
 +                 bp->dcbx_port_params.ets.cos_params[cos].strict);
 +
 +              DP(NETIF_MSG_LINK, "pdev->params.dcbx_port_params.ets."
 +                 "cos_params[%d].pauseable %x\n", cos,
 +                 bp->dcbx_port_params.ets.cos_params[cos].pauseable);
 +      }
 +
 +      for (pri = 0; pri < LLFC_DRIVER_TRAFFIC_TYPE_MAX; pri++) {
 +              DP(NETIF_MSG_LINK,
 +                 "pfc_fw_cfg->traffic_type_to_priority_cos[%d]."
 +                 "priority %x\n", pri,
 +                 pfc_fw_cfg->traffic_type_to_priority_cos[pri].priority);
 +
 +              DP(NETIF_MSG_LINK,
 +                 "pfc_fw_cfg->traffic_type_to_priority_cos[%d].cos %x\n",
 +                 pri, pfc_fw_cfg->traffic_type_to_priority_cos[pri].cos);
 +      }
 +}
 +
 +/* fills help_data according to pg_info */
 +static void bnx2x_dcbx_get_num_pg_traf_type(struct bnx2x *bp,
 +                                          u32 *pg_pri_orginal_spread,
 +                                          struct pg_help_data *help_data)
 +{
 +      bool pg_found  = false;
 +      u32 i, traf_type, add_traf_type, add_pg;
 +      u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority;
 +      struct pg_entry_help_data *data = help_data->data; /*shotcut*/
 +
 +      /* Set to invalid */
 +      for (i = 0; i < LLFC_DRIVER_TRAFFIC_TYPE_MAX; i++)
 +              data[i].pg = DCBX_ILLEGAL_PG;
 +
 +      for (add_traf_type = 0;
 +           add_traf_type < LLFC_DRIVER_TRAFFIC_TYPE_MAX; add_traf_type++) {
 +              pg_found = false;
 +              if (ttp[add_traf_type] < MAX_PFC_PRIORITIES) {
 +                      add_pg = (u8)pg_pri_orginal_spread[ttp[add_traf_type]];
 +                      for (traf_type = 0;
 +                           traf_type < LLFC_DRIVER_TRAFFIC_TYPE_MAX;
 +                           traf_type++) {
 +                              if (data[traf_type].pg == add_pg) {
 +                                      if (!(data[traf_type].pg_priority &
 +                                           (1 << ttp[add_traf_type])))
 +                                              data[traf_type].
 +                                                      num_of_dif_pri++;
 +                                      data[traf_type].pg_priority |=
 +                                              (1 << ttp[add_traf_type]);
 +                                      pg_found = true;
 +                                      break;
 +                              }
 +                      }
 +                      if (false == pg_found) {
 +                              data[help_data->num_of_pg].pg = add_pg;
 +                              data[help_data->num_of_pg].pg_priority =
 +                                              (1 << ttp[add_traf_type]);
 +                              data[help_data->num_of_pg].num_of_dif_pri = 1;
 +                              help_data->num_of_pg++;
 +                      }
 +              }
 +              DP(NETIF_MSG_LINK,
 +                 "add_traf_type %d pg_found %s num_of_pg %d\n",
 +                 add_traf_type, (false == pg_found) ? "NO" : "YES",
 +                 help_data->num_of_pg);
 +      }
 +}
 +
 +static void bnx2x_dcbx_ets_disabled_entry_data(struct bnx2x *bp,
 +                                             struct cos_help_data *cos_data,
 +                                             u32 pri_join_mask)
 +{
 +      /* Only one priority than only one COS */
 +      cos_data->data[0].pausable =
 +              IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask);
 +      cos_data->data[0].pri_join_mask = pri_join_mask;
 +      cos_data->data[0].cos_bw = 100;
 +      cos_data->num_of_cos = 1;
 +}
 +
 +static inline void bnx2x_dcbx_add_to_cos_bw(struct bnx2x *bp,
 +                                          struct cos_entry_help_data *data,
 +                                          u8 pg_bw)
 +{
 +      if (data->cos_bw == DCBX_INVALID_COS_BW)
 +              data->cos_bw = pg_bw;
 +      else
 +              data->cos_bw += pg_bw;
 +}
 +
 +static void bnx2x_dcbx_separate_pauseable_from_non(struct bnx2x *bp,
 +                      struct cos_help_data *cos_data,
 +                      u32 *pg_pri_orginal_spread,
 +                      struct dcbx_ets_feature *ets)
 +{
 +      u32     pri_tested      = 0;
 +      u8      i               = 0;
 +      u8      entry           = 0;
 +      u8      pg_entry        = 0;
 +      u8      num_of_pri      = LLFC_DRIVER_TRAFFIC_TYPE_MAX;
 +
 +      cos_data->data[0].pausable = true;
 +      cos_data->data[1].pausable = false;
 +      cos_data->data[0].pri_join_mask = cos_data->data[1].pri_join_mask = 0;
 +
 +      for (i = 0 ; i < num_of_pri ; i++) {
 +              pri_tested = 1 << bp->dcbx_port_params.
 +                                      app.traffic_type_priority[i];
 +
 +              if (pri_tested & DCBX_PFC_PRI_NON_PAUSE_MASK(bp)) {
 +                      cos_data->data[1].pri_join_mask |= pri_tested;
 +                      entry = 1;
 +              } else {
 +                      cos_data->data[0].pri_join_mask |= pri_tested;
 +                      entry = 0;
 +              }
 +              pg_entry = (u8)pg_pri_orginal_spread[bp->dcbx_port_params.
 +                                              app.traffic_type_priority[i]];
 +              /* There can be only one strict pg */
 +              if (pg_entry < DCBX_MAX_NUM_PG_BW_ENTRIES)
 +                      bnx2x_dcbx_add_to_cos_bw(bp, &cos_data->data[entry],
 +                              DCBX_PG_BW_GET(ets->pg_bw_tbl, pg_entry));
 +              else
 +                      /* If we join a group and one is strict
 +                       * than the bw rulls */
 +                      cos_data->data[entry].strict =
 +                                              BNX2X_DCBX_STRICT_COS_HIGHEST;
 +      }
 +      if ((0 == cos_data->data[0].pri_join_mask) &&
 +          (0 == cos_data->data[1].pri_join_mask))
 +              BNX2X_ERR("dcbx error: Both groups must have priorities\n");
 +}
 +
 +
 +#ifndef POWER_OF_2
 +#define POWER_OF_2(x) ((0 != x) && (0 == (x & (x-1))))
 +#endif
 +
 +static void bnx2x_dcbx_2cos_limit_cee_single_pg_to_cos_params(struct bnx2x *bp,
 +                                            struct pg_help_data *pg_help_data,
 +                                            struct cos_help_data *cos_data,
 +                                            u32 pri_join_mask,
 +                                            u8 num_of_dif_pri)
 +{
 +      u8 i = 0;
 +      u32 pri_tested = 0;
 +      u32 pri_mask_without_pri = 0;
 +      u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority;
 +      /*debug*/
 +      if (num_of_dif_pri == 1) {
 +              bnx2x_dcbx_ets_disabled_entry_data(bp, cos_data, pri_join_mask);
 +              return;
 +      }
 +      /* single priority group */
 +      if (pg_help_data->data[0].pg < DCBX_MAX_NUM_PG_BW_ENTRIES) {
 +              /* If there are both pauseable and non-pauseable priorities,
 +               * the pauseable priorities go to the first queue and
 +               * the non-pauseable priorities go to the second queue.
 +               */
 +              if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask)) {
 +                      /* Pauseable */
 +                      cos_data->data[0].pausable = true;
 +                      /* Non pauseable.*/
 +                      cos_data->data[1].pausable = false;
 +
 +                      if (2 == num_of_dif_pri) {
 +                              cos_data->data[0].cos_bw = 50;
 +                              cos_data->data[1].cos_bw = 50;
 +                      }
 +
 +                      if (3 == num_of_dif_pri) {
 +                              if (POWER_OF_2(DCBX_PFC_PRI_GET_PAUSE(bp,
 +                                                      pri_join_mask))) {
 +                                      cos_data->data[0].cos_bw = 33;
 +                                      cos_data->data[1].cos_bw = 67;
 +                              } else {
 +                                      cos_data->data[0].cos_bw = 67;
 +                                      cos_data->data[1].cos_bw = 33;
 +                              }
 +                      }
 +
 +              } else if (IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask)) {
 +                      /* If there are only pauseable priorities,
 +                       * then one/two priorities go to the first queue
 +                       * and one priority goes to the second queue.
 +                       */
 +                      if (2 == num_of_dif_pri) {
 +                              cos_data->data[0].cos_bw = 50;
 +                              cos_data->data[1].cos_bw = 50;
 +                      } else {
 +                              cos_data->data[0].cos_bw = 67;
 +                              cos_data->data[1].cos_bw = 33;
 +                      }
 +                      cos_data->data[1].pausable = true;
 +                      cos_data->data[0].pausable = true;
 +                      /* All priorities except FCOE */
 +                      cos_data->data[0].pri_join_mask = (pri_join_mask &
 +                              ((u8)~(1 << ttp[LLFC_TRAFFIC_TYPE_FCOE])));
 +                      /* Only FCOE priority.*/
 +                      cos_data->data[1].pri_join_mask =
 +                              (1 << ttp[LLFC_TRAFFIC_TYPE_FCOE]);
 +              } else
 +                      /* If there are only non-pauseable priorities,
 +                       * they will all go to the same queue.
 +                       */
 +                      bnx2x_dcbx_ets_disabled_entry_data(bp,
 +                                              cos_data, pri_join_mask);
 +      } else {
 +              /* priority group which is not BW limited (PG#15):*/
 +              if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask)) {
 +                      /* If there are both pauseable and non-pauseable
 +                       * priorities, the pauseable priorities go to the first
 +                       * queue and the non-pauseable priorities
 +                       * go to the second queue.
 +                       */
 +                      if (DCBX_PFC_PRI_GET_PAUSE(bp, pri_join_mask) >
 +                          DCBX_PFC_PRI_GET_NON_PAUSE(bp, pri_join_mask)) {
 +                              cos_data->data[0].strict =
 +                                      BNX2X_DCBX_STRICT_COS_HIGHEST;
 +                              cos_data->data[1].strict =
 +                                      BNX2X_DCBX_STRICT_COS_NEXT_LOWER_PRI(
 +                                              BNX2X_DCBX_STRICT_COS_HIGHEST);
 +                      } else {
 +                              cos_data->data[0].strict =
 +                                      BNX2X_DCBX_STRICT_COS_NEXT_LOWER_PRI(
 +                                              BNX2X_DCBX_STRICT_COS_HIGHEST);
 +                              cos_data->data[1].strict =
 +                                      BNX2X_DCBX_STRICT_COS_HIGHEST;
 +                      }
 +                      /* Pauseable */
 +                      cos_data->data[0].pausable = true;
 +                      /* Non pause-able.*/
 +                      cos_data->data[1].pausable = false;
 +              } else {
 +                      /* If there are only pauseable priorities or
 +                       * only non-pauseable,* the lower priorities go
 +                       * to the first queue and the higherpriorities go
 +                       * to the second queue.
 +                       */
 +                      cos_data->data[0].pausable =
 +                              cos_data->data[1].pausable =
 +                              IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask);
 +
 +                      for (i = 0 ; i < LLFC_DRIVER_TRAFFIC_TYPE_MAX; i++) {
 +                              pri_tested = 1 << bp->dcbx_port_params.
 +                                      app.traffic_type_priority[i];
 +                              /* Remove priority tested */
 +                              pri_mask_without_pri =
 +                                      (pri_join_mask & ((u8)(~pri_tested)));
 +                              if (pri_mask_without_pri < pri_tested)
 +                                      break;
 +                      }
 +
 +                      if (i == LLFC_DRIVER_TRAFFIC_TYPE_MAX)
 +                              BNX2X_ERR("Invalid value for pri_join_mask -"
 +                                        " could not find a priority\n");
 +
 +                      cos_data->data[0].pri_join_mask = pri_mask_without_pri;
 +                      cos_data->data[1].pri_join_mask = pri_tested;
 +                      /* Both queues are strict priority,
 +                       * and that with the highest priority
 +                       * gets the highest strict priority in the arbiter.
 +                       */
 +                      cos_data->data[0].strict =
 +                                      BNX2X_DCBX_STRICT_COS_NEXT_LOWER_PRI(
 +                                              BNX2X_DCBX_STRICT_COS_HIGHEST);
 +                      cos_data->data[1].strict =
 +                                      BNX2X_DCBX_STRICT_COS_HIGHEST;
 +              }
 +      }
 +}
 +
 +static void bnx2x_dcbx_2cos_limit_cee_two_pg_to_cos_params(
 +                          struct bnx2x                *bp,
 +                          struct  pg_help_data        *pg_help_data,
 +                          struct dcbx_ets_feature     *ets,
 +                          struct cos_help_data        *cos_data,
 +                          u32                 *pg_pri_orginal_spread,
 +                          u32                         pri_join_mask,
 +                          u8                          num_of_dif_pri)
 +{
 +      u8 i = 0;
 +      u8 pg[DCBX_COS_MAX_NUM_E2] = { 0 };
 +
 +      /* If there are both pauseable and non-pauseable priorities,
 +       * the pauseable priorities go to the first queue and
 +       * the non-pauseable priorities go to the second queue.
 +       */
 +      if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask)) {
 +              if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp,
 +                                       pg_help_data->data[0].pg_priority) ||
 +                  IS_DCBX_PFC_PRI_MIX_PAUSE(bp,
 +                                       pg_help_data->data[1].pg_priority)) {
 +                      /* If one PG contains both pauseable and
 +                       * non-pauseable priorities then ETS is disabled.
 +                       */
 +                      bnx2x_dcbx_separate_pauseable_from_non(bp, cos_data,
 +                                      pg_pri_orginal_spread, ets);
 +                      bp->dcbx_port_params.ets.enabled = false;
 +                      return;
 +              }
 +
 +              /* Pauseable */
 +              cos_data->data[0].pausable = true;
 +              /* Non pauseable. */
 +              cos_data->data[1].pausable = false;
 +              if (IS_DCBX_PFC_PRI_ONLY_PAUSE(bp,
 +                              pg_help_data->data[0].pg_priority)) {
 +                      /* 0 is pauseable */
 +                      cos_data->data[0].pri_join_mask =
 +                              pg_help_data->data[0].pg_priority;
 +                      pg[0] = pg_help_data->data[0].pg;
 +                      cos_data->data[1].pri_join_mask =
 +                              pg_help_data->data[1].pg_priority;
 +                      pg[1] = pg_help_data->data[1].pg;
 +              } else {/* 1 is pauseable */
 +                      cos_data->data[0].pri_join_mask =
 +                              pg_help_data->data[1].pg_priority;
 +                      pg[0] = pg_help_data->data[1].pg;
 +                      cos_data->data[1].pri_join_mask =
 +                              pg_help_data->data[0].pg_priority;
 +                      pg[1] = pg_help_data->data[0].pg;
 +              }
 +      } else {
 +              /* If there are only pauseable priorities or
 +               * only non-pauseable, each PG goes to a queue.
 +               */
 +              cos_data->data[0].pausable = cos_data->data[1].pausable =
 +                      IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask);
 +              cos_data->data[0].pri_join_mask =
 +                      pg_help_data->data[0].pg_priority;
 +              pg[0] = pg_help_data->data[0].pg;
 +              cos_data->data[1].pri_join_mask =
 +                      pg_help_data->data[1].pg_priority;
 +              pg[1] = pg_help_data->data[1].pg;
 +      }
 +
 +      /* There can be only one strict pg */
 +      for (i = 0 ; i < ARRAY_SIZE(pg); i++) {
 +              if (pg[i] < DCBX_MAX_NUM_PG_BW_ENTRIES)
 +                      cos_data->data[i].cos_bw =
 +                              DCBX_PG_BW_GET(ets->pg_bw_tbl, pg[i]);
 +              else
 +                      cos_data->data[i].strict =
 +                                              BNX2X_DCBX_STRICT_COS_HIGHEST;
 +      }
 +}
 +
 +static int bnx2x_dcbx_join_pgs(
 +                            struct bnx2x            *bp,
 +                            struct dcbx_ets_feature *ets,
 +                            struct pg_help_data     *pg_help_data,
 +                            u8                      required_num_of_pg)
 +{
 +      u8 entry_joined    = pg_help_data->num_of_pg - 1;
 +      u8 entry_removed   = entry_joined + 1;
 +      u8 pg_joined       = 0;
 +
 +      if (required_num_of_pg == 0 || ARRAY_SIZE(pg_help_data->data)
 +                                              <= pg_help_data->num_of_pg) {
 +
 +              BNX2X_ERR("required_num_of_pg can't be zero\n");
 +              return -EINVAL;
 +      }
 +
 +      while (required_num_of_pg < pg_help_data->num_of_pg) {
 +              entry_joined = pg_help_data->num_of_pg - 2;
 +              entry_removed = entry_joined + 1;
 +              /* protect index */
 +              entry_removed %= ARRAY_SIZE(pg_help_data->data);
 +
 +              pg_help_data->data[entry_joined].pg_priority |=
 +                      pg_help_data->data[entry_removed].pg_priority;
 +
 +              pg_help_data->data[entry_joined].num_of_dif_pri +=
 +                      pg_help_data->data[entry_removed].num_of_dif_pri;
 +
 +              if (pg_help_data->data[entry_joined].pg == DCBX_STRICT_PRI_PG ||
 +                  pg_help_data->data[entry_removed].pg == DCBX_STRICT_PRI_PG)
 +                      /* Entries joined strict priority rules */
 +                      pg_help_data->data[entry_joined].pg =
 +                                                      DCBX_STRICT_PRI_PG;
 +              else {
 +                      /* Entries can be joined join BW */
 +                      pg_joined = DCBX_PG_BW_GET(ets->pg_bw_tbl,
 +                                      pg_help_data->data[entry_joined].pg) +
 +                                  DCBX_PG_BW_GET(ets->pg_bw_tbl,
 +                                      pg_help_data->data[entry_removed].pg);
 +
 +                      DCBX_PG_BW_SET(ets->pg_bw_tbl,
 +                              pg_help_data->data[entry_joined].pg, pg_joined);
 +              }
 +              /* Joined the entries */
 +              pg_help_data->num_of_pg--;
 +      }
 +
 +      return 0;
 +}
 +
 +static void bnx2x_dcbx_2cos_limit_cee_three_pg_to_cos_params(
 +                            struct bnx2x              *bp,
 +                            struct pg_help_data       *pg_help_data,
 +                            struct dcbx_ets_feature   *ets,
 +                            struct cos_help_data      *cos_data,
 +                            u32                       *pg_pri_orginal_spread,
 +                            u32                       pri_join_mask,
 +                            u8                        num_of_dif_pri)
 +{
 +      u8 i = 0;
 +      u32 pri_tested = 0;
 +      u8 entry = 0;
 +      u8 pg_entry = 0;
 +      bool b_found_strict = false;
 +      u8 num_of_pri = LLFC_DRIVER_TRAFFIC_TYPE_MAX;
 +
 +      cos_data->data[0].pri_join_mask = cos_data->data[1].pri_join_mask = 0;
 +      /* If there are both pauseable and non-pauseable priorities,
 +       * the pauseable priorities go to the first queue and the
 +       * non-pauseable priorities go to the second queue.
 +       */
 +      if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask))
 +              bnx2x_dcbx_separate_pauseable_from_non(bp,
 +                              cos_data, pg_pri_orginal_spread, ets);
 +      else {
 +              /* If two BW-limited PG-s were combined to one queue,
 +               * the BW is their sum.
 +               *
 +               * If there are only pauseable priorities or only non-pauseable,
 +               * and there are both BW-limited and non-BW-limited PG-s,
 +               * the BW-limited PG/s go to one queue and the non-BW-limited
 +               * PG/s go to the second queue.
 +               *
 +               * If there are only pauseable priorities or only non-pauseable
 +               * and all are BW limited, then two priorities go to the first
 +               * queue and one priority goes to the second queue.
 +               *
 +               * We will join this two cases:
 +               * if one is BW limited it will go to the secoend queue
 +               * otherwise the last priority will get it
 +               */
 +
 +              cos_data->data[0].pausable = cos_data->data[1].pausable =
 +                      IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask);
 +
 +              for (i = 0 ; i < num_of_pri; i++) {
 +                      pri_tested = 1 << bp->dcbx_port_params.
 +                              app.traffic_type_priority[i];
 +                      pg_entry = (u8)pg_pri_orginal_spread[bp->
 +                              dcbx_port_params.app.traffic_type_priority[i]];
 +
 +                      if (pg_entry < DCBX_MAX_NUM_PG_BW_ENTRIES) {
 +                              entry = 0;
 +
 +                              if (i == (num_of_pri-1) &&
 +                                  false == b_found_strict)
 +                                      /* last entry will be handled separately
 +                                       * If no priority is strict than last
 +                                       * enty goes to last queue.*/
 +                                      entry = 1;
 +                              cos_data->data[entry].pri_join_mask |=
 +                                                              pri_tested;
 +                              bnx2x_dcbx_add_to_cos_bw(bp,
 +                                      &cos_data->data[entry],
 +                                      DCBX_PG_BW_GET(ets->pg_bw_tbl,
 +                                                     pg_entry));
 +                      } else {
 +                              b_found_strict = true;
 +                              cos_data->data[1].pri_join_mask |= pri_tested;
 +                              /* If we join a group and one is strict
 +                               * than the bw rulls */
 +                              cos_data->data[1].strict =
 +                                      BNX2X_DCBX_STRICT_COS_HIGHEST;
 +                      }
 +              }
 +      }
 +}
 +
 +
 +static void bnx2x_dcbx_2cos_limit_cee_fill_cos_params(struct bnx2x *bp,
 +                                     struct pg_help_data *help_data,
 +                                     struct dcbx_ets_feature *ets,
 +                                     struct cos_help_data *cos_data,
 +                                     u32 *pg_pri_orginal_spread,
 +                                     u32 pri_join_mask,
 +                                     u8 num_of_dif_pri)
 +{
 +
 +      /* default E2 settings */
 +      cos_data->num_of_cos = DCBX_COS_MAX_NUM_E2;
 +
 +      switch (help_data->num_of_pg) {
 +      case 1:
 +              bnx2x_dcbx_2cos_limit_cee_single_pg_to_cos_params(
 +                                             bp,
 +                                             help_data,
 +                                             cos_data,
 +                                             pri_join_mask,
 +                                             num_of_dif_pri);
 +              break;
 +      case 2:
 +              bnx2x_dcbx_2cos_limit_cee_two_pg_to_cos_params(
 +                                          bp,
 +                                          help_data,
 +                                          ets,
 +                                          cos_data,
 +                                          pg_pri_orginal_spread,
 +                                          pri_join_mask,
 +                                          num_of_dif_pri);
 +              break;
 +
 +      case 3:
 +              bnx2x_dcbx_2cos_limit_cee_three_pg_to_cos_params(
 +                                            bp,
 +                                            help_data,
 +                                            ets,
 +                                            cos_data,
 +                                            pg_pri_orginal_spread,
 +                                            pri_join_mask,
 +                                            num_of_dif_pri);
 +              break;
 +      default:
 +              BNX2X_ERR("Wrong pg_help_data.num_of_pg\n");
 +              bnx2x_dcbx_ets_disabled_entry_data(bp,
 +                                                 cos_data, pri_join_mask);
 +      }
 +}
 +
 +static int bnx2x_dcbx_spread_strict_pri(struct bnx2x *bp,
 +                                      struct cos_help_data *cos_data,
 +                                      u8 entry,
 +                                      u8 num_spread_of_entries,
 +                                      u8 strict_app_pris)
 +{
 +      u8 strict_pri = BNX2X_DCBX_STRICT_COS_HIGHEST;
 +      u8 num_of_app_pri = MAX_PFC_PRIORITIES;
 +      u8 app_pri_bit = 0;
 +
 +      while (num_spread_of_entries && num_of_app_pri > 0) {
 +              app_pri_bit = 1 << (num_of_app_pri - 1);
 +              if (app_pri_bit & strict_app_pris) {
 +                      struct cos_entry_help_data *data = &cos_data->
 +                                                              data[entry];
 +                      num_spread_of_entries--;
 +                      if (num_spread_of_entries == 0) {
 +                              /* last entry needed put all the entries left */
 +                              data->cos_bw = DCBX_INVALID_COS_BW;
 +                              data->strict = strict_pri;
 +                              data->pri_join_mask = strict_app_pris;
 +                              data->pausable = DCBX_IS_PFC_PRI_SOME_PAUSE(bp,
 +                                                      data->pri_join_mask);
 +                      } else {
 +                              strict_app_pris &= ~app_pri_bit;
 +
 +                              data->cos_bw = DCBX_INVALID_COS_BW;
 +                              data->strict = strict_pri;
 +                              data->pri_join_mask = app_pri_bit;
 +                              data->pausable = DCBX_IS_PFC_PRI_SOME_PAUSE(bp,
 +                                                      data->pri_join_mask);
 +                      }
 +
 +                      strict_pri =
 +                          BNX2X_DCBX_STRICT_COS_NEXT_LOWER_PRI(strict_pri);
 +                      entry++;
 +              }
 +
 +              num_of_app_pri--;
 +      }
 +
 +      if (num_spread_of_entries)
 +              return -EINVAL;
 +
 +      return 0;
 +}
 +
 +static u8 bnx2x_dcbx_cee_fill_strict_pri(struct bnx2x *bp,
 +                                       struct cos_help_data *cos_data,
 +                                       u8 entry,
 +                                       u8 num_spread_of_entries,
 +                                       u8 strict_app_pris)
 +{
 +
 +      if (bnx2x_dcbx_spread_strict_pri(bp, cos_data, entry,
 +                                       num_spread_of_entries,
 +                                       strict_app_pris)) {
 +              struct cos_entry_help_data *data = &cos_data->
 +                                                  data[entry];
 +              /* Fill BW entry */
 +              data->cos_bw = DCBX_INVALID_COS_BW;
 +              data->strict = BNX2X_DCBX_STRICT_COS_HIGHEST;
 +              data->pri_join_mask = strict_app_pris;
 +              data->pausable = DCBX_IS_PFC_PRI_SOME_PAUSE(bp,
 +                               data->pri_join_mask);
 +              return 1;
 +      }
 +
 +      return num_spread_of_entries;
 +}
 +
 +static void bnx2x_dcbx_cee_fill_cos_params(struct bnx2x *bp,
 +                                         struct pg_help_data *help_data,
 +                                         struct dcbx_ets_feature *ets,
 +                                         struct cos_help_data *cos_data,
 +                                         u32 pri_join_mask)
 +
 +{
 +      u8 need_num_of_entries = 0;
 +      u8 i = 0;
 +      u8 entry = 0;
 +
 +      /*
 +       * if the number of requested PG-s in CEE is greater than 3
 +       * then the results are not determined since this is a violation
 +       * of the standard.
 +       */
 +      if (help_data->num_of_pg > DCBX_COS_MAX_NUM_E3B0) {
 +              if (bnx2x_dcbx_join_pgs(bp, ets, help_data,
 +                                      DCBX_COS_MAX_NUM_E3B0)) {
 +                      BNX2X_ERR("Unable to reduce the number of PGs -"
 +                                "we will disables ETS\n");
 +                      bnx2x_dcbx_ets_disabled_entry_data(bp, cos_data,
 +                                                         pri_join_mask);
 +                      return;
 +              }
 +      }
 +
 +      for (i = 0 ; i < help_data->num_of_pg; i++) {
 +              struct pg_entry_help_data *pg =  &help_data->data[i];
 +              if (pg->pg < DCBX_MAX_NUM_PG_BW_ENTRIES) {
 +                      struct cos_entry_help_data *data = &cos_data->
 +                                                          data[entry];
 +                      /* Fill BW entry */
 +                      data->cos_bw = DCBX_PG_BW_GET(ets->pg_bw_tbl, pg->pg);
 +                      data->strict = BNX2X_DCBX_STRICT_INVALID;
 +                      data->pri_join_mask = pg->pg_priority;
 +                      data->pausable = DCBX_IS_PFC_PRI_SOME_PAUSE(bp,
 +                                              data->pri_join_mask);
 +
 +                      entry++;
 +              } else {
 +                      need_num_of_entries =  min_t(u8,
 +                              (u8)pg->num_of_dif_pri,
 +                              (u8)DCBX_COS_MAX_NUM_E3B0 -
 +                                               help_data->num_of_pg + 1);
 +                      /*
 +                       * If there are still VOQ-s which have no associated PG,
 +                       * then associate these VOQ-s to PG15. These PG-s will
 +                       * be used for SP between priorities on PG15.
 +                       */
 +                      entry += bnx2x_dcbx_cee_fill_strict_pri(bp, cos_data,
 +                              entry, need_num_of_entries, pg->pg_priority);
 +              }
 +      }
 +
 +      /* the entry will represent the number of COSes used */
 +      cos_data->num_of_cos = entry;
 +}
 +static void bnx2x_dcbx_fill_cos_params(struct bnx2x *bp,
 +                                     struct pg_help_data *help_data,
 +                                     struct dcbx_ets_feature *ets,
 +                                     u32 *pg_pri_orginal_spread)
 +{
 +      struct cos_help_data         cos_data;
 +      u8                    i                           = 0;
 +      u32                   pri_join_mask               = 0;
 +      u8                    num_of_dif_pri              = 0;
 +
 +      memset(&cos_data, 0, sizeof(cos_data));
 +
 +      /* Validate the pg value */
 +      for (i = 0; i < help_data->num_of_pg ; i++) {
 +              if (DCBX_STRICT_PRIORITY != help_data->data[i].pg &&
 +                  DCBX_MAX_NUM_PG_BW_ENTRIES <= help_data->data[i].pg)
 +                      BNX2X_ERR("Invalid pg[%d] data %x\n", i,
 +                                help_data->data[i].pg);
 +              pri_join_mask   |=  help_data->data[i].pg_priority;
 +              num_of_dif_pri  += help_data->data[i].num_of_dif_pri;
 +      }
 +
 +      /* defaults */
 +      cos_data.num_of_cos = 1;
 +      for (i = 0; i < ARRAY_SIZE(cos_data.data); i++) {
 +              cos_data.data[i].pri_join_mask = 0;
 +              cos_data.data[i].pausable = false;
 +              cos_data.data[i].strict = BNX2X_DCBX_STRICT_INVALID;
 +              cos_data.data[i].cos_bw = DCBX_INVALID_COS_BW;
 +      }
 +
 +      if (CHIP_IS_E3B0(bp))
 +              bnx2x_dcbx_cee_fill_cos_params(bp, help_data, ets,
 +                                             &cos_data, pri_join_mask);
 +      else /* E2 + E3A0 */
 +              bnx2x_dcbx_2cos_limit_cee_fill_cos_params(bp,
 +                                                        help_data, ets,
 +                                                        &cos_data,
 +                                                        pg_pri_orginal_spread,
 +                                                        pri_join_mask,
 +                                                        num_of_dif_pri);
 +
 +      for (i = 0; i < cos_data.num_of_cos ; i++) {
 +              struct bnx2x_dcbx_cos_params *p =
 +                      &bp->dcbx_port_params.ets.cos_params[i];
 +
 +              p->strict = cos_data.data[i].strict;
 +              p->bw_tbl = cos_data.data[i].cos_bw;
 +              p->pri_bitmask = cos_data.data[i].pri_join_mask;
 +              p->pauseable = cos_data.data[i].pausable;
 +
 +              /* sanity */
 +              if (p->bw_tbl != DCBX_INVALID_COS_BW ||
 +                  p->strict != BNX2X_DCBX_STRICT_INVALID) {
 +                      if (p->pri_bitmask == 0)
 +                              BNX2X_ERR("Invalid pri_bitmask for %d\n", i);
 +
 +                      if (CHIP_IS_E2(bp) || CHIP_IS_E3A0(bp)) {
 +
 +                              if (p->pauseable &&
 +                                  DCBX_PFC_PRI_GET_NON_PAUSE(bp,
 +                                              p->pri_bitmask) != 0)
 +                                      BNX2X_ERR("Inconsistent config for "
 +                                                "pausable COS %d\n", i);
 +
 +                              if (!p->pauseable &&
 +                                  DCBX_PFC_PRI_GET_PAUSE(bp,
 +                                              p->pri_bitmask) != 0)
 +                                      BNX2X_ERR("Inconsistent config for "
 +                                                "nonpausable COS %d\n", i);
 +                      }
 +              }
 +
 +              if (p->pauseable)
 +                      DP(NETIF_MSG_LINK, "COS %d PAUSABLE prijoinmask 0x%x\n",
 +                                i, cos_data.data[i].pri_join_mask);
 +              else
 +                      DP(NETIF_MSG_LINK, "COS %d NONPAUSABLE prijoinmask "
 +                                        "0x%x\n",
 +                                i, cos_data.data[i].pri_join_mask);
 +      }
 +
 +      bp->dcbx_port_params.ets.num_of_cos = cos_data.num_of_cos ;
 +}
 +
 +static void bnx2x_dcbx_get_ets_pri_pg_tbl(struct bnx2x *bp,
 +                              u32 *set_configuration_ets_pg,
 +                              u32 *pri_pg_tbl)
 +{
 +      int i;
 +
 +      for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES; i++) {
 +              set_configuration_ets_pg[i] = DCBX_PRI_PG_GET(pri_pg_tbl, i);
 +
 +              DP(NETIF_MSG_LINK, "set_configuration_ets_pg[%d] = 0x%x\n",
 +                 i, set_configuration_ets_pg[i]);
 +      }
 +}
 +
 +static void bnx2x_dcbx_fw_struct(struct bnx2x *bp,
 +                               struct bnx2x_func_tx_start_params *pfc_fw_cfg)
 +{
 +      u16 pri_bit = 0;
 +      u8 cos = 0, pri = 0;
 +      struct priority_cos *tt2cos;
 +      u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority;
 +
 +      memset(pfc_fw_cfg, 0, sizeof(*pfc_fw_cfg));
 +
 +      /* to disable DCB - the structure must be zeroed */
 +      if (bp->dcbx_error & DCBX_REMOTE_MIB_ERROR)
 +              return;
 +
 +      /*shortcut*/
 +      tt2cos = pfc_fw_cfg->traffic_type_to_priority_cos;
 +
 +      /* Fw version should be incremented each update */
 +      pfc_fw_cfg->dcb_version = ++bp->dcb_version;
 +      pfc_fw_cfg->dcb_enabled = 1;
 +
 +      /* Fill priority parameters */
 +      for (pri = 0; pri < LLFC_DRIVER_TRAFFIC_TYPE_MAX; pri++) {
 +              tt2cos[pri].priority = ttp[pri];
 +              pri_bit = 1 << tt2cos[pri].priority;
 +
 +              /* Fill COS parameters based on COS calculated to
 +               * make it more general for future use */
 +              for (cos = 0; cos < bp->dcbx_port_params.ets.num_of_cos; cos++)
 +                      if (bp->dcbx_port_params.ets.cos_params[cos].
 +                                              pri_bitmask & pri_bit)
 +                                      tt2cos[pri].cos = cos;
 +      }
 +
 +      /* we never want the FW to add a 0 vlan tag */
 +      pfc_fw_cfg->dont_add_pri_0_en = 1;
 +
 +      bnx2x_dcbx_print_cos_params(bp, pfc_fw_cfg);
 +}
 +
 +void bnx2x_dcbx_pmf_update(struct bnx2x *bp)
 +{
 +      /* if we need to syncronize DCBX result from prev PMF
 +       * read it from shmem and update bp accordingly
 +       */
 +      if (SHMEM2_HAS(bp, drv_flags) &&
 +         GET_FLAGS(SHMEM2_RD(bp, drv_flags), DRV_FLAGS_DCB_CONFIGURED)) {
 +              /* Read neg results if dcbx is in the FW */
 +              if (bnx2x_dcbx_read_shmem_neg_results(bp))
 +                      return;
 +
 +              bnx2x_dump_dcbx_drv_param(bp, &bp->dcbx_local_feat,
 +                                        bp->dcbx_error);
 +              bnx2x_get_dcbx_drv_param(bp, &bp->dcbx_local_feat,
 +                                       bp->dcbx_error);
 +      }
 +}
 +
 +/* DCB netlink */
 +#ifdef BCM_DCBNL
 +
 +#define BNX2X_DCBX_CAPS               (DCB_CAP_DCBX_LLD_MANAGED | \
 +                              DCB_CAP_DCBX_VER_CEE | DCB_CAP_DCBX_STATIC)
 +
 +static inline bool bnx2x_dcbnl_set_valid(struct bnx2x *bp)
 +{
 +      /* validate dcbnl call that may change HW state:
 +       * DCB is on and DCBX mode was SUCCESSFULLY set by the user.
 +       */
 +      return bp->dcb_state && bp->dcbx_mode_uset;
 +}
 +
 +static u8 bnx2x_dcbnl_get_state(struct net_device *netdev)
 +{
 +      struct bnx2x *bp = netdev_priv(netdev);
 +      DP(NETIF_MSG_LINK, "state = %d\n", bp->dcb_state);
 +      return bp->dcb_state;
 +}
 +
 +static u8 bnx2x_dcbnl_set_state(struct net_device *netdev, u8 state)
 +{
 +      struct bnx2x *bp = netdev_priv(netdev);
 +      DP(NETIF_MSG_LINK, "state = %s\n", state ? "on" : "off");
 +
 +      bnx2x_dcbx_set_state(bp, (state ? true : false), bp->dcbx_enabled);
 +      return 0;
 +}
 +
 +static void bnx2x_dcbnl_get_perm_hw_addr(struct net_device *netdev,
 +                                       u8 *perm_addr)
 +{
 +      struct bnx2x *bp = netdev_priv(netdev);
 +      DP(NETIF_MSG_LINK, "GET-PERM-ADDR\n");
 +
 +      /* first the HW mac address */
 +      memcpy(perm_addr, netdev->dev_addr, netdev->addr_len);
 +
 +#ifdef BCM_CNIC
 +      /* second SAN address */
 +      memcpy(perm_addr+netdev->addr_len, bp->fip_mac, netdev->addr_len);
 +#endif
 +}
 +
 +static void bnx2x_dcbnl_set_pg_tccfg_tx(struct net_device *netdev, int prio,
 +                                      u8 prio_type, u8 pgid, u8 bw_pct,
 +                                      u8 up_map)
 +{
 +      struct bnx2x *bp = netdev_priv(netdev);
 +
 +      DP(NETIF_MSG_LINK, "prio[%d] = %d\n", prio, pgid);
 +      if (!bnx2x_dcbnl_set_valid(bp) || prio >= DCBX_MAX_NUM_PRI_PG_ENTRIES)
 +              return;
 +
 +      /**
 +       * bw_pct ingnored -    band-width percentage devision between user
 +       *                      priorities within the same group is not
 +       *                      standard and hence not supported
 +       *
 +       * prio_type igonred -  priority levels within the same group are not
 +       *                      standard and hence are not supported. According
 +       *                      to the standard pgid 15 is dedicated to strict
 +       *                      prioirty traffic (on the port level).
 +       *
 +       * up_map ignored
 +       */
 +
 +      bp->dcbx_config_params.admin_configuration_ets_pg[prio] = pgid;
 +      bp->dcbx_config_params.admin_ets_configuration_tx_enable = 1;
 +}
 +
 +static void bnx2x_dcbnl_set_pg_bwgcfg_tx(struct net_device *netdev,
 +                                       int pgid, u8 bw_pct)
 +{
 +      struct bnx2x *bp = netdev_priv(netdev);
 +      DP(NETIF_MSG_LINK, "pgid[%d] = %d\n", pgid, bw_pct);
 +
 +      if (!bnx2x_dcbnl_set_valid(bp) || pgid >= DCBX_MAX_NUM_PG_BW_ENTRIES)
 +              return;
 +
 +      bp->dcbx_config_params.admin_configuration_bw_precentage[pgid] = bw_pct;
 +      bp->dcbx_config_params.admin_ets_configuration_tx_enable = 1;
 +}
 +
 +static void bnx2x_dcbnl_set_pg_tccfg_rx(struct net_device *netdev, int prio,
 +                                      u8 prio_type, u8 pgid, u8 bw_pct,
 +                                      u8 up_map)
 +{
 +      struct bnx2x *bp = netdev_priv(netdev);
 +      DP(NETIF_MSG_LINK, "Nothing to set; No RX support\n");
 +}
 +
 +static void bnx2x_dcbnl_set_pg_bwgcfg_rx(struct net_device *netdev,
 +                                       int pgid, u8 bw_pct)
 +{
 +      struct bnx2x *bp = netdev_priv(netdev);
 +      DP(NETIF_MSG_LINK, "Nothing to set; No RX support\n");
 +}
 +
 +static void bnx2x_dcbnl_get_pg_tccfg_tx(struct net_device *netdev, int prio,
 +                                      u8 *prio_type, u8 *pgid, u8 *bw_pct,
 +                                      u8 *up_map)
 +{
 +      struct bnx2x *bp = netdev_priv(netdev);
 +      DP(NETIF_MSG_LINK, "prio = %d\n", prio);
 +
 +      /**
 +       * bw_pct ingnored -    band-width percentage devision between user
 +       *                      priorities within the same group is not
 +       *                      standard and hence not supported
 +       *
 +       * prio_type igonred -  priority levels within the same group are not
 +       *                      standard and hence are not supported. According
 +       *                      to the standard pgid 15 is dedicated to strict
 +       *                      prioirty traffic (on the port level).
 +       *
 +       * up_map ignored
 +       */
 +      *up_map = *bw_pct = *prio_type = *pgid = 0;
 +
 +      if (!bp->dcb_state || prio >= DCBX_MAX_NUM_PRI_PG_ENTRIES)
 +              return;
 +
 +      *pgid = DCBX_PRI_PG_GET(bp->dcbx_local_feat.ets.pri_pg_tbl, prio);
 +}
 +
 +static void bnx2x_dcbnl_get_pg_bwgcfg_tx(struct net_device *netdev,
 +                                       int pgid, u8 *bw_pct)
 +{
 +      struct bnx2x *bp = netdev_priv(netdev);
 +      DP(NETIF_MSG_LINK, "pgid = %d\n", pgid);
 +
 +      *bw_pct = 0;
 +
 +      if (!bp->dcb_state || pgid >= DCBX_MAX_NUM_PG_BW_ENTRIES)
 +              return;
 +
 +      *bw_pct = DCBX_PG_BW_GET(bp->dcbx_local_feat.ets.pg_bw_tbl, pgid);
 +}
 +
 +static void bnx2x_dcbnl_get_pg_tccfg_rx(struct net_device *netdev, int prio,
 +                                      u8 *prio_type, u8 *pgid, u8 *bw_pct,
 +                                      u8 *up_map)
 +{
 +      struct bnx2x *bp = netdev_priv(netdev);
 +      DP(NETIF_MSG_LINK, "Nothing to get; No RX support\n");
 +
 +      *prio_type = *pgid = *bw_pct = *up_map = 0;
 +}
 +
 +static void bnx2x_dcbnl_get_pg_bwgcfg_rx(struct net_device *netdev,
 +                                       int pgid, u8 *bw_pct)
 +{
 +      struct bnx2x *bp = netdev_priv(netdev);
 +      DP(NETIF_MSG_LINK, "Nothing to get; No RX support\n");
 +
 +      *bw_pct = 0;
 +}
 +
 +static void bnx2x_dcbnl_set_pfc_cfg(struct net_device *netdev, int prio,
 +                                  u8 setting)
 +{
 +      struct bnx2x *bp = netdev_priv(netdev);
 +      DP(NETIF_MSG_LINK, "prio[%d] = %d\n", prio, setting);
 +
 +      if (!bnx2x_dcbnl_set_valid(bp) || prio >= MAX_PFC_PRIORITIES)
 +              return;
 +
 +      bp->dcbx_config_params.admin_pfc_bitmap |= ((setting ? 1 : 0) << prio);
 +
 +      if (setting)
 +              bp->dcbx_config_params.admin_pfc_tx_enable = 1;
 +}
 +
 +static void bnx2x_dcbnl_get_pfc_cfg(struct net_device *netdev, int prio,
 +                                  u8 *setting)
 +{
 +      struct bnx2x *bp = netdev_priv(netdev);
 +      DP(NETIF_MSG_LINK, "prio = %d\n", prio);
 +
 +      *setting = 0;
 +
 +      if (!bp->dcb_state || prio >= MAX_PFC_PRIORITIES)
 +              return;
 +
 +      *setting = (bp->dcbx_local_feat.pfc.pri_en_bitmap >> prio) & 0x1;
 +}
 +
 +static u8 bnx2x_dcbnl_set_all(struct net_device *netdev)
 +{
 +      struct bnx2x *bp = netdev_priv(netdev);
 +      int rc = 0;
 +
 +      DP(NETIF_MSG_LINK, "SET-ALL\n");
 +
 +      if (!bnx2x_dcbnl_set_valid(bp))
 +              return 1;
 +
 +      if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
 +              netdev_err(bp->dev, "Handling parity error recovery. "
 +                              "Try again later\n");
 +              return 1;
 +      }
 +      if (netif_running(bp->dev)) {
 +              bnx2x_nic_unload(bp, UNLOAD_NORMAL);
 +              rc = bnx2x_nic_load(bp, LOAD_NORMAL);
 +      }
 +      DP(NETIF_MSG_LINK, "set_dcbx_params done (%d)\n", rc);
 +      if (rc)
 +              return 1;
 +
 +      return 0;
 +}
 +
 +static u8 bnx2x_dcbnl_get_cap(struct net_device *netdev, int capid, u8 *cap)
 +{
 +      struct bnx2x *bp = netdev_priv(netdev);
 +      u8 rval = 0;
 +
 +      if (bp->dcb_state) {
 +              switch (capid) {
 +              case DCB_CAP_ATTR_PG:
 +                      *cap = true;
 +                      break;
 +              case DCB_CAP_ATTR_PFC:
 +                      *cap = true;
 +                      break;
 +              case DCB_CAP_ATTR_UP2TC:
 +                      *cap = false;
 +                      break;
 +              case DCB_CAP_ATTR_PG_TCS:
 +                      *cap = 0x80;    /* 8 priorities for PGs */
 +                      break;
 +              case DCB_CAP_ATTR_PFC_TCS:
 +                      *cap = 0x80;    /* 8 priorities for PFC */
 +                      break;
 +              case DCB_CAP_ATTR_GSP:
 +                      *cap = true;
 +                      break;
 +              case DCB_CAP_ATTR_BCN:
 +                      *cap = false;
 +                      break;
 +              case DCB_CAP_ATTR_DCBX:
 +                      *cap = BNX2X_DCBX_CAPS;
++                      break;
 +              default:
 +                      rval = -EINVAL;
 +                      break;
 +              }
 +      } else
 +              rval = -EINVAL;
 +
 +      DP(NETIF_MSG_LINK, "capid %d:%x\n", capid, *cap);
 +      return rval;
 +}
 +
 +static u8 bnx2x_dcbnl_get_numtcs(struct net_device *netdev, int tcid, u8 *num)
 +{
 +      struct bnx2x *bp = netdev_priv(netdev);
 +      u8 rval = 0;
 +
 +      DP(NETIF_MSG_LINK, "tcid %d\n", tcid);
 +
 +      if (bp->dcb_state) {
 +              switch (tcid) {
 +              case DCB_NUMTCS_ATTR_PG:
 +                      *num = CHIP_IS_E3B0(bp) ? DCBX_COS_MAX_NUM_E3B0 :
 +                                                DCBX_COS_MAX_NUM_E2;
 +                      break;
 +              case DCB_NUMTCS_ATTR_PFC:
 +                      *num = CHIP_IS_E3B0(bp) ? DCBX_COS_MAX_NUM_E3B0 :
 +                                                DCBX_COS_MAX_NUM_E2;
 +                      break;
 +              default:
 +                      rval = -EINVAL;
 +                      break;
 +              }
 +      } else
 +              rval = -EINVAL;
 +
 +      return rval;
 +}
 +
 +static u8 bnx2x_dcbnl_set_numtcs(struct net_device *netdev, int tcid, u8 num)
 +{
 +      struct bnx2x *bp = netdev_priv(netdev);
 +      DP(NETIF_MSG_LINK, "num tcs = %d; Not supported\n", num);
 +      return -EINVAL;
 +}
 +
 +static u8  bnx2x_dcbnl_get_pfc_state(struct net_device *netdev)
 +{
 +      struct bnx2x *bp = netdev_priv(netdev);
 +      DP(NETIF_MSG_LINK, "state = %d\n", bp->dcbx_local_feat.pfc.enabled);
 +
 +      if (!bp->dcb_state)
 +              return 0;
 +
 +      return bp->dcbx_local_feat.pfc.enabled;
 +}
 +
 +static void bnx2x_dcbnl_set_pfc_state(struct net_device *netdev, u8 state)
 +{
 +      struct bnx2x *bp = netdev_priv(netdev);
 +      DP(NETIF_MSG_LINK, "state = %s\n", state ? "on" : "off");
 +
 +      if (!bnx2x_dcbnl_set_valid(bp))
 +              return;
 +
 +      bp->dcbx_config_params.admin_pfc_tx_enable =
 +      bp->dcbx_config_params.admin_pfc_enable = (state ? 1 : 0);
 +}
 +
 +static void bnx2x_admin_app_set_ent(
 +      struct bnx2x_admin_priority_app_table *app_ent,
 +      u8 idtype, u16 idval, u8 up)
 +{
 +      app_ent->valid = 1;
 +
 +      switch (idtype) {
 +      case DCB_APP_IDTYPE_ETHTYPE:
 +              app_ent->traffic_type = TRAFFIC_TYPE_ETH;
 +              break;
 +      case DCB_APP_IDTYPE_PORTNUM:
 +              app_ent->traffic_type = TRAFFIC_TYPE_PORT;
 +              break;
 +      default:
 +              break; /* never gets here */
 +      }
 +      app_ent->app_id = idval;
 +      app_ent->priority = up;
 +}
 +
 +static bool bnx2x_admin_app_is_equal(
 +      struct bnx2x_admin_priority_app_table *app_ent,
 +      u8 idtype, u16 idval)
 +{
 +      if (!app_ent->valid)
 +              return false;
 +
 +      switch (idtype) {
 +      case DCB_APP_IDTYPE_ETHTYPE:
 +              if (app_ent->traffic_type != TRAFFIC_TYPE_ETH)
 +                      return false;
 +              break;
 +      case DCB_APP_IDTYPE_PORTNUM:
 +              if (app_ent->traffic_type != TRAFFIC_TYPE_PORT)
 +                      return false;
 +              break;
 +      default:
 +              return false;
 +      }
 +      if (app_ent->app_id != idval)
 +              return false;
 +
 +      return true;
 +}
 +
 +static int bnx2x_set_admin_app_up(struct bnx2x *bp, u8 idtype, u16 idval, u8 up)
 +{
 +      int i, ff;
 +
 +      /* iterate over the app entries looking for idtype and idval */
 +      for (i = 0, ff = -1; i < 4; i++) {
 +              struct bnx2x_admin_priority_app_table *app_ent =
 +                      &bp->dcbx_config_params.admin_priority_app_table[i];
 +              if (bnx2x_admin_app_is_equal(app_ent, idtype, idval))
 +                      break;
 +
 +              if (ff < 0 && !app_ent->valid)
 +                      ff = i;
 +      }
 +      if (i < 4)
 +              /* if found overwrite up */
 +              bp->dcbx_config_params.
 +                      admin_priority_app_table[i].priority = up;
 +      else if (ff >= 0)
 +              /* not found use first-free */
 +              bnx2x_admin_app_set_ent(
 +                      &bp->dcbx_config_params.admin_priority_app_table[ff],
 +                      idtype, idval, up);
 +      else
 +              /* app table is full */
 +              return -EBUSY;
 +
 +      /* up configured, if not 0 make sure feature is enabled */
 +      if (up)
 +              bp->dcbx_config_params.admin_application_priority_tx_enable = 1;
 +
 +      return 0;
 +}
 +
 +static u8 bnx2x_dcbnl_set_app_up(struct net_device *netdev, u8 idtype,
 +                               u16 idval, u8 up)
 +{
 +      struct bnx2x *bp = netdev_priv(netdev);
 +
 +      DP(NETIF_MSG_LINK, "app_type %d, app_id %x, prio bitmap %d\n",
 +         idtype, idval, up);
 +
 +      if (!bnx2x_dcbnl_set_valid(bp))
 +              return -EINVAL;
 +
 +      /* verify idtype */
 +      switch (idtype) {
 +      case DCB_APP_IDTYPE_ETHTYPE:
 +      case DCB_APP_IDTYPE_PORTNUM:
 +              break;
 +      default:
 +              return -EINVAL;
 +      }
 +      return bnx2x_set_admin_app_up(bp, idtype, idval, up);
 +}
 +
 +static u8 bnx2x_dcbnl_get_dcbx(struct net_device *netdev)
 +{
 +      struct bnx2x *bp = netdev_priv(netdev);
 +      u8 state;
 +
 +      state = DCB_CAP_DCBX_LLD_MANAGED | DCB_CAP_DCBX_VER_CEE;
 +
 +      if (bp->dcbx_enabled == BNX2X_DCBX_ENABLED_ON_NEG_OFF)
 +              state |= DCB_CAP_DCBX_STATIC;
 +
 +      return state;
 +}
 +
 +static u8 bnx2x_dcbnl_set_dcbx(struct net_device *netdev, u8 state)
 +{
 +      struct bnx2x *bp = netdev_priv(netdev);
 +      DP(NETIF_MSG_LINK, "state = %02x\n", state);
 +
 +      /* set dcbx mode */
 +
 +      if ((state & BNX2X_DCBX_CAPS) != state) {
 +              BNX2X_ERR("Requested DCBX mode %x is beyond advertised "
 +                        "capabilities\n", state);
 +              return 1;
 +      }
 +
 +      if (bp->dcb_state != BNX2X_DCB_STATE_ON) {
 +              BNX2X_ERR("DCB turned off, DCBX configuration is invalid\n");
 +              return 1;
 +      }
 +
 +      if (state & DCB_CAP_DCBX_STATIC)
 +              bp->dcbx_enabled = BNX2X_DCBX_ENABLED_ON_NEG_OFF;
 +      else
 +              bp->dcbx_enabled = BNX2X_DCBX_ENABLED_ON_NEG_ON;
 +
 +      bp->dcbx_mode_uset = true;
 +      return 0;
 +}
 +
 +static u8 bnx2x_dcbnl_get_featcfg(struct net_device *netdev, int featid,
 +                                u8 *flags)
 +{
 +      struct bnx2x *bp = netdev_priv(netdev);
 +      u8 rval = 0;
 +
 +      DP(NETIF_MSG_LINK, "featid %d\n", featid);
 +
 +      if (bp->dcb_state) {
 +              *flags = 0;
 +              switch (featid) {
 +              case DCB_FEATCFG_ATTR_PG:
 +                      if (bp->dcbx_local_feat.ets.enabled)
 +                              *flags |= DCB_FEATCFG_ENABLE;
 +                      if (bp->dcbx_error & DCBX_LOCAL_ETS_ERROR)
 +                              *flags |= DCB_FEATCFG_ERROR;
 +                      break;
 +              case DCB_FEATCFG_ATTR_PFC:
 +                      if (bp->dcbx_local_feat.pfc.enabled)
 +                              *flags |= DCB_FEATCFG_ENABLE;
 +                      if (bp->dcbx_error & (DCBX_LOCAL_PFC_ERROR |
 +                          DCBX_LOCAL_PFC_MISMATCH))
 +                              *flags |= DCB_FEATCFG_ERROR;
 +                      break;
 +              case DCB_FEATCFG_ATTR_APP:
 +                      if (bp->dcbx_local_feat.app.enabled)
 +                              *flags |= DCB_FEATCFG_ENABLE;
 +                      if (bp->dcbx_error & (DCBX_LOCAL_APP_ERROR |
 +                          DCBX_LOCAL_APP_MISMATCH))
 +                              *flags |= DCB_FEATCFG_ERROR;
 +                      break;
 +              default:
 +                      rval = -EINVAL;
 +                      break;
 +              }
 +      } else
 +              rval = -EINVAL;
 +
 +      return rval;
 +}
 +
 +static u8 bnx2x_dcbnl_set_featcfg(struct net_device *netdev, int featid,
 +                                u8 flags)
 +{
 +      struct bnx2x *bp = netdev_priv(netdev);
 +      u8 rval = 0;
 +
 +      DP(NETIF_MSG_LINK, "featid = %d flags = %02x\n", featid, flags);
 +
 +      /* ignore the 'advertise' flag */
 +      if (bnx2x_dcbnl_set_valid(bp)) {
 +              switch (featid) {
 +              case DCB_FEATCFG_ATTR_PG:
 +                      bp->dcbx_config_params.admin_ets_enable =
 +                              flags & DCB_FEATCFG_ENABLE ? 1 : 0;
 +                      bp->dcbx_config_params.admin_ets_willing =
 +                              flags & DCB_FEATCFG_WILLING ? 1 : 0;
 +                      break;
 +              case DCB_FEATCFG_ATTR_PFC:
 +                      bp->dcbx_config_params.admin_pfc_enable =
 +                              flags & DCB_FEATCFG_ENABLE ? 1 : 0;
 +                      bp->dcbx_config_params.admin_pfc_willing =
 +                              flags & DCB_FEATCFG_WILLING ? 1 : 0;
 +                      break;
 +              case DCB_FEATCFG_ATTR_APP:
 +                      /* ignore enable, always enabled */
 +                      bp->dcbx_config_params.admin_app_priority_willing =
 +                              flags & DCB_FEATCFG_WILLING ? 1 : 0;
 +                      break;
 +              default:
 +                      rval = -EINVAL;
 +                      break;
 +              }
 +      } else
 +              rval = -EINVAL;
 +
 +      return rval;
 +}
 +
 +static int bnx2x_peer_appinfo(struct net_device *netdev,
 +                            struct dcb_peer_app_info *info, u16* app_count)
 +{
 +      int i;
 +      struct bnx2x *bp = netdev_priv(netdev);
 +
 +      DP(NETIF_MSG_LINK, "APP-INFO\n");
 +
 +      info->willing = (bp->dcbx_remote_flags & DCBX_APP_REM_WILLING) ?: 0;
 +      info->error = (bp->dcbx_remote_flags & DCBX_APP_RX_ERROR) ?: 0;
 +      *app_count = 0;
 +
 +      for (i = 0; i < DCBX_MAX_APP_PROTOCOL; i++)
 +              if (bp->dcbx_remote_feat.app.app_pri_tbl[i].appBitfield &
 +                  DCBX_APP_ENTRY_VALID)
 +                      (*app_count)++;
 +      return 0;
 +}
 +
 +static int bnx2x_peer_apptable(struct net_device *netdev,
 +                             struct dcb_app *table)
 +{
 +      int i, j;
 +      struct bnx2x *bp = netdev_priv(netdev);
 +
 +      DP(NETIF_MSG_LINK, "APP-TABLE\n");
 +
 +      for (i = 0, j = 0; i < DCBX_MAX_APP_PROTOCOL; i++) {
 +              struct dcbx_app_priority_entry *ent =
 +                      &bp->dcbx_remote_feat.app.app_pri_tbl[i];
 +
 +              if (ent->appBitfield & DCBX_APP_ENTRY_VALID) {
 +                      table[j].selector = bnx2x_dcbx_dcbnl_app_idtype(ent);
 +                      table[j].priority = bnx2x_dcbx_dcbnl_app_up(ent);
 +                      table[j++].protocol = ent->app_id;
 +              }
 +      }
 +      return 0;
 +}
 +
 +static int bnx2x_cee_peer_getpg(struct net_device *netdev, struct cee_pg *pg)
 +{
 +      int i;
 +      struct bnx2x *bp = netdev_priv(netdev);
 +
 +      pg->willing = (bp->dcbx_remote_flags & DCBX_ETS_REM_WILLING) ?: 0;
 +
 +      for (i = 0; i < CEE_DCBX_MAX_PGS; i++) {
 +              pg->pg_bw[i] =
 +                      DCBX_PG_BW_GET(bp->dcbx_remote_feat.ets.pg_bw_tbl, i);
 +              pg->prio_pg[i] =
 +                      DCBX_PRI_PG_GET(bp->dcbx_remote_feat.ets.pri_pg_tbl, i);
 +      }
 +      return 0;
 +}
 +
 +static int bnx2x_cee_peer_getpfc(struct net_device *netdev,
 +                               struct cee_pfc *pfc)
 +{
 +      struct bnx2x *bp = netdev_priv(netdev);
 +      pfc->tcs_supported = bp->dcbx_remote_feat.pfc.pfc_caps;
 +      pfc->pfc_en = bp->dcbx_remote_feat.pfc.pri_en_bitmap;
 +      return 0;
 +}
 +
 +const struct dcbnl_rtnl_ops bnx2x_dcbnl_ops = {
 +      .getstate               = bnx2x_dcbnl_get_state,
 +      .setstate               = bnx2x_dcbnl_set_state,
 +      .getpermhwaddr          = bnx2x_dcbnl_get_perm_hw_addr,
 +      .setpgtccfgtx           = bnx2x_dcbnl_set_pg_tccfg_tx,
 +      .setpgbwgcfgtx          = bnx2x_dcbnl_set_pg_bwgcfg_tx,
 +      .setpgtccfgrx           = bnx2x_dcbnl_set_pg_tccfg_rx,
 +      .setpgbwgcfgrx          = bnx2x_dcbnl_set_pg_bwgcfg_rx,
 +      .getpgtccfgtx           = bnx2x_dcbnl_get_pg_tccfg_tx,
 +      .getpgbwgcfgtx          = bnx2x_dcbnl_get_pg_bwgcfg_tx,
 +      .getpgtccfgrx           = bnx2x_dcbnl_get_pg_tccfg_rx,
 +      .getpgbwgcfgrx          = bnx2x_dcbnl_get_pg_bwgcfg_rx,
 +      .setpfccfg              = bnx2x_dcbnl_set_pfc_cfg,
 +      .getpfccfg              = bnx2x_dcbnl_get_pfc_cfg,
 +      .setall                 = bnx2x_dcbnl_set_all,
 +      .getcap                 = bnx2x_dcbnl_get_cap,
 +      .getnumtcs              = bnx2x_dcbnl_get_numtcs,
 +      .setnumtcs              = bnx2x_dcbnl_set_numtcs,
 +      .getpfcstate            = bnx2x_dcbnl_get_pfc_state,
 +      .setpfcstate            = bnx2x_dcbnl_set_pfc_state,
 +      .setapp                 = bnx2x_dcbnl_set_app_up,
 +      .getdcbx                = bnx2x_dcbnl_get_dcbx,
 +      .setdcbx                = bnx2x_dcbnl_set_dcbx,
 +      .getfeatcfg             = bnx2x_dcbnl_get_featcfg,
 +      .setfeatcfg             = bnx2x_dcbnl_set_featcfg,
 +      .peer_getappinfo        = bnx2x_peer_appinfo,
 +      .peer_getapptable       = bnx2x_peer_apptable,
 +      .cee_peer_getpg         = bnx2x_cee_peer_getpg,
 +      .cee_peer_getpfc        = bnx2x_cee_peer_getpfc,
 +};
 +
 +#endif /* BCM_DCBNL */
index 28bde16,0000000..6486ab8
mode 100644,000000..100644
--- /dev/null
@@@ -1,11607 -1,0 +1,11617 @@@
 +/* bnx2x_main.c: Broadcom Everest network driver.
 + *
 + * Copyright (c) 2007-2011 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
 + * the Free Software Foundation.
 + *
 + * Maintained by: Eilon Greenstein <eilong@broadcom.com>
 + * Written by: Eliezer Tamir
 + * Based on code from Michael Chan's bnx2 driver
 + * UDP CSUM errata workaround by Arik Gendelman
 + * Slowpath and fastpath rework by Vladislav Zolotarov
 + * Statistics and Link management by Yitchak Gertner
 + *
 + */
 +
 +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 +
 +#include <linux/module.h>
 +#include <linux/moduleparam.h>
 +#include <linux/kernel.h>
 +#include <linux/device.h>  /* for dev_info() */
 +#include <linux/timer.h>
 +#include <linux/errno.h>
 +#include <linux/ioport.h>
 +#include <linux/slab.h>
 +#include <linux/interrupt.h>
 +#include <linux/pci.h>
 +#include <linux/init.h>
 +#include <linux/netdevice.h>
 +#include <linux/etherdevice.h>
 +#include <linux/skbuff.h>
 +#include <linux/dma-mapping.h>
 +#include <linux/bitops.h>
 +#include <linux/irq.h>
 +#include <linux/delay.h>
 +#include <asm/byteorder.h>
 +#include <linux/time.h>
 +#include <linux/ethtool.h>
 +#include <linux/mii.h>
 +#include <linux/if.h>
 +#include <linux/if_vlan.h>
 +#include <net/ip.h>
 +#include <net/ipv6.h>
 +#include <net/tcp.h>
 +#include <net/checksum.h>
 +#include <net/ip6_checksum.h>
 +#include <linux/workqueue.h>
 +#include <linux/crc32.h>
 +#include <linux/crc32c.h>
 +#include <linux/prefetch.h>
 +#include <linux/zlib.h>
 +#include <linux/io.h>
 +#include <linux/stringify.h>
 +#include <linux/vmalloc.h>
 +
 +#include "bnx2x.h"
 +#include "bnx2x_init.h"
 +#include "bnx2x_init_ops.h"
 +#include "bnx2x_cmn.h"
 +#include "bnx2x_dcb.h"
 +#include "bnx2x_sp.h"
 +
 +#include <linux/firmware.h>
 +#include "bnx2x_fw_file_hdr.h"
 +/* FW files */
 +#define FW_FILE_VERSION                                       \
 +      __stringify(BCM_5710_FW_MAJOR_VERSION) "."      \
 +      __stringify(BCM_5710_FW_MINOR_VERSION) "."      \
 +      __stringify(BCM_5710_FW_REVISION_VERSION) "."   \
 +      __stringify(BCM_5710_FW_ENGINEERING_VERSION)
 +#define FW_FILE_NAME_E1               "bnx2x/bnx2x-e1-" FW_FILE_VERSION ".fw"
 +#define FW_FILE_NAME_E1H      "bnx2x/bnx2x-e1h-" FW_FILE_VERSION ".fw"
 +#define FW_FILE_NAME_E2               "bnx2x/bnx2x-e2-" FW_FILE_VERSION ".fw"
 +
 +/* Time in jiffies before concluding the transmitter is hung */
 +#define TX_TIMEOUT            (5*HZ)
 +
 +static char version[] __devinitdata =
 +      "Broadcom NetXtreme II 5771x/578xx 10/20-Gigabit Ethernet Driver "
 +      DRV_MODULE_NAME " " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
 +
 +MODULE_AUTHOR("Eliezer Tamir");
 +MODULE_DESCRIPTION("Broadcom NetXtreme II "
 +                 "BCM57710/57711/57711E/"
 +                 "57712/57712_MF/57800/57800_MF/57810/57810_MF/"
 +                 "57840/57840_MF Driver");
 +MODULE_LICENSE("GPL");
 +MODULE_VERSION(DRV_MODULE_VERSION);
 +MODULE_FIRMWARE(FW_FILE_NAME_E1);
 +MODULE_FIRMWARE(FW_FILE_NAME_E1H);
 +MODULE_FIRMWARE(FW_FILE_NAME_E2);
 +
 +static int multi_mode = 1;
 +module_param(multi_mode, int, 0);
 +MODULE_PARM_DESC(multi_mode, " Multi queue mode "
 +                           "(0 Disable; 1 Enable (default))");
 +
 +int num_queues;
 +module_param(num_queues, int, 0);
 +MODULE_PARM_DESC(num_queues, " Number of queues for multi_mode=1"
 +                              " (default is as a number of CPUs)");
 +
 +static int disable_tpa;
 +module_param(disable_tpa, int, 0);
 +MODULE_PARM_DESC(disable_tpa, " Disable the TPA (LRO) feature");
 +
 +#define INT_MODE_INTx                 1
 +#define INT_MODE_MSI                  2
 +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)");
 +
 +static int dropless_fc;
 +module_param(dropless_fc, int, 0);
 +MODULE_PARM_DESC(dropless_fc, " Pause on exhausted host ring");
 +
 +static int poll;
 +module_param(poll, int, 0);
 +MODULE_PARM_DESC(poll, " Use polling (for debug)");
 +
 +static int mrrs = -1;
 +module_param(mrrs, int, 0);
 +MODULE_PARM_DESC(mrrs, " Force Max Read Req Size (0..3) (for debug)");
 +
 +static int debug;
 +module_param(debug, int, 0);
 +MODULE_PARM_DESC(debug, " Default debug msglevel");
 +
 +
 +
 +struct workqueue_struct *bnx2x_wq;
 +
 +enum bnx2x_board_type {
 +      BCM57710 = 0,
 +      BCM57711,
 +      BCM57711E,
 +      BCM57712,
 +      BCM57712_MF,
 +      BCM57800,
 +      BCM57800_MF,
 +      BCM57810,
 +      BCM57810_MF,
 +      BCM57840,
 +      BCM57840_MF
 +};
 +
 +/* indexed by board_type, above */
 +static struct {
 +      char *name;
 +} board_info[] __devinitdata = {
 +      { "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/20 Gigabit "
 +                                              "Ethernet Multi Function"}
 +};
 +
 +#ifndef PCI_DEVICE_ID_NX2_57710
 +#define PCI_DEVICE_ID_NX2_57710               CHIP_NUM_57710
 +#endif
 +#ifndef PCI_DEVICE_ID_NX2_57711
 +#define PCI_DEVICE_ID_NX2_57711               CHIP_NUM_57711
 +#endif
 +#ifndef PCI_DEVICE_ID_NX2_57711E
 +#define PCI_DEVICE_ID_NX2_57711E      CHIP_NUM_57711E
 +#endif
 +#ifndef PCI_DEVICE_ID_NX2_57712
 +#define PCI_DEVICE_ID_NX2_57712               CHIP_NUM_57712
 +#endif
 +#ifndef PCI_DEVICE_ID_NX2_57712_MF
 +#define PCI_DEVICE_ID_NX2_57712_MF    CHIP_NUM_57712_MF
 +#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_57810
 +#define PCI_DEVICE_ID_NX2_57810               CHIP_NUM_57810
 +#endif
 +#ifndef PCI_DEVICE_ID_NX2_57810_MF
 +#define PCI_DEVICE_ID_NX2_57810_MF    CHIP_NUM_57810_MF
 +#endif
 +#ifndef PCI_DEVICE_ID_NX2_57840
 +#define PCI_DEVICE_ID_NX2_57840               CHIP_NUM_57840
 +#endif
 +#ifndef PCI_DEVICE_ID_NX2_57840_MF
 +#define PCI_DEVICE_ID_NX2_57840_MF    CHIP_NUM_57840_MF
 +#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_57800), BCM57800 },
 +      { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57800_MF), BCM57800_MF },
 +      { 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), BCM57840 },
 +      { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_MF), BCM57840_MF },
 +      { 0 }
 +};
 +
 +MODULE_DEVICE_TABLE(pci, bnx2x_pci_tbl);
 +
 +/****************************************************************************
 +* General service functions
 +****************************************************************************/
 +
 +static inline void __storm_memset_dma_mapping(struct bnx2x *bp,
 +                                     u32 addr, dma_addr_t mapping)
 +{
 +      REG_WR(bp,  addr, U64_LO(mapping));
 +      REG_WR(bp,  addr + 4, U64_HI(mapping));
 +}
 +
 +static inline void storm_memset_spq_addr(struct bnx2x *bp,
 +                                       dma_addr_t mapping, u16 abs_fid)
 +{
 +      u32 addr = XSEM_REG_FAST_MEMORY +
 +                      XSTORM_SPQ_PAGE_BASE_OFFSET(abs_fid);
 +
 +      __storm_memset_dma_mapping(bp, addr, mapping);
 +}
 +
 +static inline void storm_memset_vf_to_pf(struct bnx2x *bp, u16 abs_fid,
 +                                       u16 pf_id)
 +{
 +      REG_WR8(bp, BAR_XSTRORM_INTMEM + XSTORM_VF_TO_PF_OFFSET(abs_fid),
 +              pf_id);
 +      REG_WR8(bp, BAR_CSTRORM_INTMEM + CSTORM_VF_TO_PF_OFFSET(abs_fid),
 +              pf_id);
 +      REG_WR8(bp, BAR_TSTRORM_INTMEM + TSTORM_VF_TO_PF_OFFSET(abs_fid),
 +              pf_id);
 +      REG_WR8(bp, BAR_USTRORM_INTMEM + USTORM_VF_TO_PF_OFFSET(abs_fid),
 +              pf_id);
 +}
 +
 +static inline void storm_memset_func_en(struct bnx2x *bp, u16 abs_fid,
 +                                      u8 enable)
 +{
 +      REG_WR8(bp, BAR_XSTRORM_INTMEM + XSTORM_FUNC_EN_OFFSET(abs_fid),
 +              enable);
 +      REG_WR8(bp, BAR_CSTRORM_INTMEM + CSTORM_FUNC_EN_OFFSET(abs_fid),
 +              enable);
 +      REG_WR8(bp, BAR_TSTRORM_INTMEM + TSTORM_FUNC_EN_OFFSET(abs_fid),
 +              enable);
 +      REG_WR8(bp, BAR_USTRORM_INTMEM + USTORM_FUNC_EN_OFFSET(abs_fid),
 +              enable);
 +}
 +
 +static inline void storm_memset_eq_data(struct bnx2x *bp,
 +                              struct event_ring_data *eq_data,
 +                              u16 pfid)
 +{
 +      size_t size = sizeof(struct event_ring_data);
 +
 +      u32 addr = BAR_CSTRORM_INTMEM + CSTORM_EVENT_RING_DATA_OFFSET(pfid);
 +
 +      __storm_memset_struct(bp, addr, size, (u32 *)eq_data);
 +}
 +
 +static inline void storm_memset_eq_prod(struct bnx2x *bp, u16 eq_prod,
 +                                      u16 pfid)
 +{
 +      u32 addr = BAR_CSTRORM_INTMEM + CSTORM_EVENT_RING_PROD_OFFSET(pfid);
 +      REG_WR16(bp, addr, eq_prod);
 +}
 +
 +/* used only at init
 + * locking is done by mcp
 + */
 +static void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val)
 +{
 +      pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, addr);
 +      pci_write_config_dword(bp->pdev, PCICFG_GRC_DATA, val);
 +      pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS,
 +                             PCICFG_VENDOR_ID_OFFSET);
 +}
 +
 +static u32 bnx2x_reg_rd_ind(struct bnx2x *bp, u32 addr)
 +{
 +      u32 val;
 +
 +      pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, addr);
 +      pci_read_config_dword(bp->pdev, PCICFG_GRC_DATA, &val);
 +      pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS,
 +                             PCICFG_VENDOR_ID_OFFSET);
 +
 +      return val;
 +}
 +
 +#define DMAE_DP_SRC_GRC               "grc src_addr [%08x]"
 +#define DMAE_DP_SRC_PCI               "pci src_addr [%x:%08x]"
 +#define DMAE_DP_DST_GRC               "grc dst_addr [%08x]"
 +#define DMAE_DP_DST_PCI               "pci dst_addr [%x:%08x]"
 +#define DMAE_DP_DST_NONE      "dst_addr [none]"
 +
 +static 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)
 +{
 +      u32 cmd_offset;
 +      int i;
 +
 +      cmd_offset = (DMAE_REG_CMD_MEM + sizeof(struct dmae_command) * idx);
 +      for (i = 0; i < (sizeof(struct dmae_command)/4); i++) {
 +              REG_WR(bp, cmd_offset + i*4, *(((u32 *)dmae) + i));
 +
 +              DP(BNX2X_MSG_OFF, "DMAE cmd[%d].%d (0x%08x) : 0x%08x\n",
 +                 idx, i, cmd_offset + i*4, *(((u32 *)dmae) + i));
 +      }
 +      REG_WR(bp, dmae_reg_go_c[idx], 1);
 +}
 +
 +u32 bnx2x_dmae_opcode_add_comp(u32 opcode, u8 comp_type)
 +{
 +      return opcode | ((comp_type << DMAE_COMMAND_C_DST_SHIFT) |
 +                         DMAE_CMD_C_ENABLE);
 +}
 +
 +u32 bnx2x_dmae_opcode_clr_src_reset(u32 opcode)
 +{
 +      return opcode & ~DMAE_CMD_SRC_RESET;
 +}
 +
 +u32 bnx2x_dmae_opcode(struct bnx2x *bp, u8 src_type, u8 dst_type,
 +                           bool with_comp, u8 comp_type)
 +{
 +      u32 opcode = 0;
 +
 +      opcode |= ((src_type << DMAE_COMMAND_SRC_SHIFT) |
 +                 (dst_type << DMAE_COMMAND_DST_SHIFT));
 +
 +      opcode |= (DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET);
 +
 +      opcode |= (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0);
 +      opcode |= ((BP_VN(bp) << DMAE_CMD_E1HVN_SHIFT) |
 +                 (BP_VN(bp) << DMAE_COMMAND_DST_VN_SHIFT));
 +      opcode |= (DMAE_COM_SET_ERR << DMAE_COMMAND_ERR_POLICY_SHIFT);
 +
 +#ifdef __BIG_ENDIAN
 +      opcode |= DMAE_CMD_ENDIANITY_B_DW_SWAP;
 +#else
 +      opcode |= DMAE_CMD_ENDIANITY_DW_SWAP;
 +#endif
 +      if (with_comp)
 +              opcode = bnx2x_dmae_opcode_add_comp(opcode, comp_type);
 +      return opcode;
 +}
 +
 +static void bnx2x_prep_dmae_with_comp(struct bnx2x *bp,
 +                                    struct dmae_command *dmae,
 +                                    u8 src_type, u8 dst_type)
 +{
 +      memset(dmae, 0, sizeof(struct dmae_command));
 +
 +      /* set the opcode */
 +      dmae->opcode = bnx2x_dmae_opcode(bp, src_type, dst_type,
 +                                       true, DMAE_COMP_PCI);
 +
 +      /* fill in the completion parameters */
 +      dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp));
 +      dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp));
 +      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)
 +{
 +      u32 *wb_comp = bnx2x_sp(bp, wb_comp);
 +      int cnt = CHIP_REV_IS_SLOW(bp) ? (400000) : 4000;
 +      int rc = 0;
 +
 +      DP(BNX2X_MSG_OFF, "data before [0x%08x 0x%08x 0x%08x 0x%08x]\n",
 +         bp->slowpath->wb_data[0], bp->slowpath->wb_data[1],
 +         bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]);
 +
 +      /*
 +       * Lock the dmae channel. Disable BHs to prevent a dead-lock
 +       * as long as this code is called both from syscall context and
 +       * from ndo_set_rx_mode() flow that may be called from BH.
 +       */
 +      spin_lock_bh(&bp->dmae_lock);
 +
 +      /* reset completion */
 +      *wb_comp = 0;
 +
 +      /* post the command on the channel used for initializations */
 +      bnx2x_post_dmae(bp, dmae, INIT_DMAE_C(bp));
 +
 +      /* wait for completion */
 +      udelay(5);
 +      while ((*wb_comp & ~DMAE_PCI_ERR_FLAG) != DMAE_COMP_VAL) {
 +              DP(BNX2X_MSG_OFF, "wb_comp 0x%08x\n", *wb_comp);
 +
 +              if (!cnt) {
 +                      BNX2X_ERR("DMAE timeout!\n");
 +                      rc = DMAE_TIMEOUT;
 +                      goto unlock;
 +              }
 +              cnt--;
 +              udelay(50);
 +      }
 +      if (*wb_comp & DMAE_PCI_ERR_FLAG) {
 +              BNX2X_ERR("DMAE PCI error!\n");
 +              rc = DMAE_PCI_ERROR;
 +      }
 +
 +      DP(BNX2X_MSG_OFF, "data after [0x%08x 0x%08x 0x%08x 0x%08x]\n",
 +         bp->slowpath->wb_data[0], bp->slowpath->wb_data[1],
 +         bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]);
 +
 +unlock:
 +      spin_unlock_bh(&bp->dmae_lock);
 +      return rc;
 +}
 +
 +void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr,
 +                    u32 len32)
 +{
 +      struct dmae_command dmae;
 +
 +      if (!bp->dmae_ready) {
 +              u32 *data = bnx2x_sp(bp, wb_data[0]);
 +
 +              DP(BNX2X_MSG_OFF, "DMAE is not ready (dst_addr %08x  len32 %d)"
 +                 "  using indirect\n", dst_addr, len32);
 +              bnx2x_init_ind_wr(bp, dst_addr, data, len32);
 +              return;
 +      }
 +
 +      /* set opcode and fixed command fields */
 +      bnx2x_prep_dmae_with_comp(bp, &dmae, DMAE_SRC_PCI, DMAE_DST_GRC);
 +
 +      /* fill in addresses and len */
 +      dmae.src_addr_lo = U64_LO(dma_addr);
 +      dmae.src_addr_hi = U64_HI(dma_addr);
 +      dmae.dst_addr_lo = dst_addr >> 2;
 +      dmae.dst_addr_hi = 0;
 +      dmae.len = len32;
 +
 +      bnx2x_dp_dmae(bp, &dmae, BNX2X_MSG_OFF);
 +
 +      /* issue the command and wait for completion */
 +      bnx2x_issue_dmae_with_comp(bp, &dmae);
 +}
 +
 +void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32)
 +{
 +      struct dmae_command dmae;
 +
 +      if (!bp->dmae_ready) {
 +              u32 *data = bnx2x_sp(bp, wb_data[0]);
 +              int i;
 +
 +              DP(BNX2X_MSG_OFF, "DMAE is not ready (src_addr %08x  len32 %d)"
 +                 "  using indirect\n", src_addr, len32);
 +              for (i = 0; i < len32; i++)
 +                      data[i] = bnx2x_reg_rd_ind(bp, src_addr + i*4);
 +              return;
 +      }
 +
 +      /* set opcode and fixed command fields */
 +      bnx2x_prep_dmae_with_comp(bp, &dmae, DMAE_SRC_GRC, DMAE_DST_PCI);
 +
 +      /* fill in addresses and len */
 +      dmae.src_addr_lo = src_addr >> 2;
 +      dmae.src_addr_hi = 0;
 +      dmae.dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_data));
 +      dmae.dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_data));
 +      dmae.len = len32;
 +
 +      bnx2x_dp_dmae(bp, &dmae, BNX2X_MSG_OFF);
 +
 +      /* issue the command and wait for completion */
 +      bnx2x_issue_dmae_with_comp(bp, &dmae);
 +}
 +
 +static void bnx2x_write_dmae_phys_len(struct bnx2x *bp, dma_addr_t phys_addr,
 +                                    u32 addr, u32 len)
 +{
 +      int dmae_wr_max = DMAE_LEN32_WR_MAX(bp);
 +      int offset = 0;
 +
 +      while (len > dmae_wr_max) {
 +              bnx2x_write_dmae(bp, phys_addr + offset,
 +                               addr + offset, dmae_wr_max);
 +              offset += dmae_wr_max * 4;
 +              len -= dmae_wr_max;
 +      }
 +
 +      bnx2x_write_dmae(bp, phys_addr + offset, addr + offset, len);
 +}
 +
 +/* used only for slowpath so not inlined */
 +static void bnx2x_wb_wr(struct bnx2x *bp, int reg, u32 val_hi, u32 val_lo)
 +{
 +      u32 wb_write[2];
 +
 +      wb_write[0] = val_hi;
 +      wb_write[1] = val_lo;
 +      REG_WR_DMAE(bp, reg, wb_write, 2);
 +}
 +
 +#ifdef USE_WB_RD
 +static u64 bnx2x_wb_rd(struct bnx2x *bp, int reg)
 +{
 +      u32 wb_data[2];
 +
 +      REG_RD_DMAE(bp, reg, wb_data, 2);
 +
 +      return HILO_U64(wb_data[0], wb_data[1]);
 +}
 +#endif
 +
 +static int bnx2x_mc_assert(struct bnx2x *bp)
 +{
 +      char last_idx;
 +      int i, rc = 0;
 +      u32 row0, row1, row2, row3;
 +
 +      /* XSTORM */
 +      last_idx = REG_RD8(bp, BAR_XSTRORM_INTMEM +
 +                         XSTORM_ASSERT_LIST_INDEX_OFFSET);
 +      if (last_idx)
 +              BNX2X_ERR("XSTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx);
 +
 +      /* print the asserts */
 +      for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) {
 +
 +              row0 = REG_RD(bp, BAR_XSTRORM_INTMEM +
 +                            XSTORM_ASSERT_LIST_OFFSET(i));
 +              row1 = REG_RD(bp, BAR_XSTRORM_INTMEM +
 +                            XSTORM_ASSERT_LIST_OFFSET(i) + 4);
 +              row2 = REG_RD(bp, BAR_XSTRORM_INTMEM +
 +                            XSTORM_ASSERT_LIST_OFFSET(i) + 8);
 +              row3 = REG_RD(bp, BAR_XSTRORM_INTMEM +
 +                            XSTORM_ASSERT_LIST_OFFSET(i) + 12);
 +
 +              if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
 +                      BNX2X_ERR("XSTORM_ASSERT_INDEX 0x%x = 0x%08x"
 +                                " 0x%08x 0x%08x 0x%08x\n",
 +                                i, row3, row2, row1, row0);
 +                      rc++;
 +              } else {
 +                      break;
 +              }
 +      }
 +
 +      /* TSTORM */
 +      last_idx = REG_RD8(bp, BAR_TSTRORM_INTMEM +
 +                         TSTORM_ASSERT_LIST_INDEX_OFFSET);
 +      if (last_idx)
 +              BNX2X_ERR("TSTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx);
 +
 +      /* print the asserts */
 +      for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) {
 +
 +              row0 = REG_RD(bp, BAR_TSTRORM_INTMEM +
 +                            TSTORM_ASSERT_LIST_OFFSET(i));
 +              row1 = REG_RD(bp, BAR_TSTRORM_INTMEM +
 +                            TSTORM_ASSERT_LIST_OFFSET(i) + 4);
 +              row2 = REG_RD(bp, BAR_TSTRORM_INTMEM +
 +                            TSTORM_ASSERT_LIST_OFFSET(i) + 8);
 +              row3 = REG_RD(bp, BAR_TSTRORM_INTMEM +
 +                            TSTORM_ASSERT_LIST_OFFSET(i) + 12);
 +
 +              if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
 +                      BNX2X_ERR("TSTORM_ASSERT_INDEX 0x%x = 0x%08x"
 +                                " 0x%08x 0x%08x 0x%08x\n",
 +                                i, row3, row2, row1, row0);
 +                      rc++;
 +              } else {
 +                      break;
 +              }
 +      }
 +
 +      /* CSTORM */
 +      last_idx = REG_RD8(bp, BAR_CSTRORM_INTMEM +
 +                         CSTORM_ASSERT_LIST_INDEX_OFFSET);
 +      if (last_idx)
 +              BNX2X_ERR("CSTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx);
 +
 +      /* print the asserts */
 +      for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) {
 +
 +              row0 = REG_RD(bp, BAR_CSTRORM_INTMEM +
 +                            CSTORM_ASSERT_LIST_OFFSET(i));
 +              row1 = REG_RD(bp, BAR_CSTRORM_INTMEM +
 +                            CSTORM_ASSERT_LIST_OFFSET(i) + 4);
 +              row2 = REG_RD(bp, BAR_CSTRORM_INTMEM +
 +                            CSTORM_ASSERT_LIST_OFFSET(i) + 8);
 +              row3 = REG_RD(bp, BAR_CSTRORM_INTMEM +
 +                            CSTORM_ASSERT_LIST_OFFSET(i) + 12);
 +
 +              if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
 +                      BNX2X_ERR("CSTORM_ASSERT_INDEX 0x%x = 0x%08x"
 +                                " 0x%08x 0x%08x 0x%08x\n",
 +                                i, row3, row2, row1, row0);
 +                      rc++;
 +              } else {
 +                      break;
 +              }
 +      }
 +
 +      /* USTORM */
 +      last_idx = REG_RD8(bp, BAR_USTRORM_INTMEM +
 +                         USTORM_ASSERT_LIST_INDEX_OFFSET);
 +      if (last_idx)
 +              BNX2X_ERR("USTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx);
 +
 +      /* print the asserts */
 +      for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) {
 +
 +              row0 = REG_RD(bp, BAR_USTRORM_INTMEM +
 +                            USTORM_ASSERT_LIST_OFFSET(i));
 +              row1 = REG_RD(bp, BAR_USTRORM_INTMEM +
 +                            USTORM_ASSERT_LIST_OFFSET(i) + 4);
 +              row2 = REG_RD(bp, BAR_USTRORM_INTMEM +
 +                            USTORM_ASSERT_LIST_OFFSET(i) + 8);
 +              row3 = REG_RD(bp, BAR_USTRORM_INTMEM +
 +                            USTORM_ASSERT_LIST_OFFSET(i) + 12);
 +
 +              if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
 +                      BNX2X_ERR("USTORM_ASSERT_INDEX 0x%x = 0x%08x"
 +                                " 0x%08x 0x%08x 0x%08x\n",
 +                                i, row3, row2, row1, row0);
 +                      rc++;
 +              } else {
 +                      break;
 +              }
 +      }
 +
 +      return rc;
 +}
 +
 +void bnx2x_fw_dump_lvl(struct bnx2x *bp, const char *lvl)
 +{
 +      u32 addr, val;
 +      u32 mark, offset;
 +      __be32 data[9];
 +      int word;
 +      u32 trace_shmem_base;
 +      if (BP_NOMCP(bp)) {
 +              BNX2X_ERR("NO MCP - can not dump\n");
 +              return;
 +      }
 +      netdev_printk(lvl, bp->dev, "bc %d.%d.%d\n",
 +              (bp->common.bc_ver & 0xff0000) >> 16,
 +              (bp->common.bc_ver & 0xff00) >> 8,
 +              (bp->common.bc_ver & 0xff));
 +
 +      val = REG_RD(bp, MCP_REG_MCPR_CPU_PROGRAM_COUNTER);
 +      if (val == REG_RD(bp, MCP_REG_MCPR_CPU_PROGRAM_COUNTER))
 +              printk("%s" "MCP PC at 0x%x\n", lvl, val);
 +
 +      if (BP_PATH(bp) == 0)
 +              trace_shmem_base = bp->common.shmem_base;
 +      else
 +              trace_shmem_base = SHMEM2_RD(bp, other_shmem_base_addr);
 +      addr = trace_shmem_base - 0x0800 + 4;
 +      mark = REG_RD(bp, addr);
 +      mark = (CHIP_IS_E1x(bp) ? MCP_REG_MCPR_SCRATCH : MCP_A_REG_MCPR_SCRATCH)
 +                      + ((mark + 0x3) & ~0x3) - 0x08000000;
 +      printk("%s" "begin fw dump (mark 0x%x)\n", lvl, mark);
 +
 +      printk("%s", lvl);
 +      for (offset = mark; offset <= trace_shmem_base; offset += 0x8*4) {
 +              for (word = 0; word < 8; word++)
 +                      data[word] = htonl(REG_RD(bp, offset + 4*word));
 +              data[8] = 0x0;
 +              pr_cont("%s", (char *)data);
 +      }
 +      for (offset = addr + 4; offset <= mark; offset += 0x8*4) {
 +              for (word = 0; word < 8; word++)
 +                      data[word] = htonl(REG_RD(bp, offset + 4*word));
 +              data[8] = 0x0;
 +              pr_cont("%s", (char *)data);
 +      }
 +      printk("%s" "end of fw dump\n", lvl);
 +}
 +
 +static inline void bnx2x_fw_dump(struct bnx2x *bp)
 +{
 +      bnx2x_fw_dump_lvl(bp, KERN_ERR);
 +}
 +
 +void bnx2x_panic_dump(struct bnx2x *bp)
 +{
 +      int i;
 +      u16 j;
 +      struct hc_sp_status_block_data sp_sb_data;
 +      int func = BP_FUNC(bp);
 +#ifdef BNX2X_STOP_ON_ERROR
 +      u16 start = 0, end = 0;
 +      u8 cos;
 +#endif
 +
 +      bp->stats_state = STATS_STATE_DISABLED;
 +      DP(BNX2X_MSG_STATS, "stats_state - DISABLED\n");
 +
 +      BNX2X_ERR("begin crash dump -----------------\n");
 +
 +      /* Indices */
 +      /* Common */
 +      BNX2X_ERR("def_idx(0x%x)  def_att_idx(0x%x)  attn_state(0x%x)"
 +                "  spq_prod_idx(0x%x) next_stats_cnt(0x%x)\n",
 +                bp->def_idx, bp->def_att_idx, bp->attn_state,
 +                bp->spq_prod_idx, bp->stats_counter);
 +      BNX2X_ERR("DSB: attn bits(0x%x)  ack(0x%x)  id(0x%x)  idx(0x%x)\n",
 +                bp->def_status_blk->atten_status_block.attn_bits,
 +                bp->def_status_blk->atten_status_block.attn_bits_ack,
 +                bp->def_status_blk->atten_status_block.status_block_id,
 +                bp->def_status_blk->atten_status_block.attn_bits_index);
 +      BNX2X_ERR("     def (");
 +      for (i = 0; i < HC_SP_SB_MAX_INDICES; i++)
 +              pr_cont("0x%x%s",
 +                      bp->def_status_blk->sp_sb.index_values[i],
 +                      (i == HC_SP_SB_MAX_INDICES - 1) ? ")  " : " ");
 +
 +      for (i = 0; i < sizeof(struct hc_sp_status_block_data)/sizeof(u32); i++)
 +              *((u32 *)&sp_sb_data + i) = REG_RD(bp, BAR_CSTRORM_INTMEM +
 +                      CSTORM_SP_STATUS_BLOCK_DATA_OFFSET(func) +
 +                      i*sizeof(u32));
 +
 +      pr_cont("igu_sb_id(0x%x)  igu_seg_id(0x%x) pf_id(0x%x)  vnic_id(0x%x)  vf_id(0x%x)  vf_valid (0x%x) state(0x%x)\n",
 +             sp_sb_data.igu_sb_id,
 +             sp_sb_data.igu_seg_id,
 +             sp_sb_data.p_func.pf_id,
 +             sp_sb_data.p_func.vnic_id,
 +             sp_sb_data.p_func.vf_id,
 +             sp_sb_data.p_func.vf_valid,
 +             sp_sb_data.state);
 +
 +
 +      for_each_eth_queue(bp, i) {
 +              struct bnx2x_fastpath *fp = &bp->fp[i];
 +              int loop;
 +              struct hc_status_block_data_e2 sb_data_e2;
 +              struct hc_status_block_data_e1x sb_data_e1x;
 +              struct hc_status_block_sm  *hc_sm_p =
 +                      CHIP_IS_E1x(bp) ?
 +                      sb_data_e1x.common.state_machine :
 +                      sb_data_e2.common.state_machine;
 +              struct hc_index_data *hc_index_p =
 +                      CHIP_IS_E1x(bp) ?
 +                      sb_data_e1x.index_data :
 +                      sb_data_e2.index_data;
 +              u8 data_size, cos;
 +              u32 *sb_data_p;
 +              struct bnx2x_fp_txdata txdata;
 +
 +              /* Rx */
 +              BNX2X_ERR("fp%d: rx_bd_prod(0x%x)  rx_bd_cons(0x%x)"
 +                        "  rx_comp_prod(0x%x)"
 +                        "  rx_comp_cons(0x%x)  *rx_cons_sb(0x%x)\n",
 +                        i, fp->rx_bd_prod, fp->rx_bd_cons,
 +                        fp->rx_comp_prod,
 +                        fp->rx_comp_cons, le16_to_cpu(*fp->rx_cons_sb));
 +              BNX2X_ERR("     rx_sge_prod(0x%x)  last_max_sge(0x%x)"
 +                        "  fp_hc_idx(0x%x)\n",
 +                        fp->rx_sge_prod, fp->last_max_sge,
 +                        le16_to_cpu(fp->fp_hc_idx));
 +
 +              /* Tx */
 +              for_each_cos_in_tx_queue(fp, cos)
 +              {
 +                      txdata = fp->txdata[cos];
 +                      BNX2X_ERR("fp%d: tx_pkt_prod(0x%x)  tx_pkt_cons(0x%x)"
 +                                "  tx_bd_prod(0x%x)  tx_bd_cons(0x%x)"
 +                                "  *tx_cons_sb(0x%x)\n",
 +                                i, txdata.tx_pkt_prod,
 +                                txdata.tx_pkt_cons, txdata.tx_bd_prod,
 +                                txdata.tx_bd_cons,
 +                                le16_to_cpu(*txdata.tx_cons_sb));
 +              }
 +
 +              loop = CHIP_IS_E1x(bp) ?
 +                      HC_SB_MAX_INDICES_E1X : HC_SB_MAX_INDICES_E2;
 +
 +              /* host sb data */
 +
 +#ifdef BCM_CNIC
 +              if (IS_FCOE_FP(fp))
 +                      continue;
 +#endif
 +              BNX2X_ERR("     run indexes (");
 +              for (j = 0; j < HC_SB_MAX_SM; j++)
 +                      pr_cont("0x%x%s",
 +                             fp->sb_running_index[j],
 +                             (j == HC_SB_MAX_SM - 1) ? ")" : " ");
 +
 +              BNX2X_ERR("     indexes (");
 +              for (j = 0; j < loop; j++)
 +                      pr_cont("0x%x%s",
 +                             fp->sb_index_values[j],
 +                             (j == loop - 1) ? ")" : " ");
 +              /* fw sb data */
 +              data_size = CHIP_IS_E1x(bp) ?
 +                      sizeof(struct hc_status_block_data_e1x) :
 +                      sizeof(struct hc_status_block_data_e2);
 +              data_size /= sizeof(u32);
 +              sb_data_p = CHIP_IS_E1x(bp) ?
 +                      (u32 *)&sb_data_e1x :
 +                      (u32 *)&sb_data_e2;
 +              /* copy sb data in here */
 +              for (j = 0; j < data_size; j++)
 +                      *(sb_data_p + j) = REG_RD(bp, BAR_CSTRORM_INTMEM +
 +                              CSTORM_STATUS_BLOCK_DATA_OFFSET(fp->fw_sb_id) +
 +                              j * sizeof(u32));
 +
 +              if (!CHIP_IS_E1x(bp)) {
 +                      pr_cont("pf_id(0x%x)  vf_id(0x%x)  vf_valid(0x%x) "
 +                              "vnic_id(0x%x)  same_igu_sb_1b(0x%x) "
 +                              "state(0x%x)\n",
 +                              sb_data_e2.common.p_func.pf_id,
 +                              sb_data_e2.common.p_func.vf_id,
 +                              sb_data_e2.common.p_func.vf_valid,
 +                              sb_data_e2.common.p_func.vnic_id,
 +                              sb_data_e2.common.same_igu_sb_1b,
 +                              sb_data_e2.common.state);
 +              } else {
 +                      pr_cont("pf_id(0x%x)  vf_id(0x%x)  vf_valid(0x%x) "
 +                              "vnic_id(0x%x)  same_igu_sb_1b(0x%x) "
 +                              "state(0x%x)\n",
 +                              sb_data_e1x.common.p_func.pf_id,
 +                              sb_data_e1x.common.p_func.vf_id,
 +                              sb_data_e1x.common.p_func.vf_valid,
 +                              sb_data_e1x.common.p_func.vnic_id,
 +                              sb_data_e1x.common.same_igu_sb_1b,
 +                              sb_data_e1x.common.state);
 +              }
 +
 +              /* SB_SMs data */
 +              for (j = 0; j < HC_SB_MAX_SM; j++) {
 +                      pr_cont("SM[%d] __flags (0x%x) "
 +                             "igu_sb_id (0x%x)  igu_seg_id(0x%x) "
 +                             "time_to_expire (0x%x) "
 +                             "timer_value(0x%x)\n", j,
 +                             hc_sm_p[j].__flags,
 +                             hc_sm_p[j].igu_sb_id,
 +                             hc_sm_p[j].igu_seg_id,
 +                             hc_sm_p[j].time_to_expire,
 +                             hc_sm_p[j].timer_value);
 +              }
 +
 +              /* Indecies data */
 +              for (j = 0; j < loop; j++) {
 +                      pr_cont("INDEX[%d] flags (0x%x) "
 +                                       "timeout (0x%x)\n", j,
 +                             hc_index_p[j].flags,
 +                             hc_index_p[j].timeout);
 +              }
 +      }
 +
 +#ifdef BNX2X_STOP_ON_ERROR
 +      /* Rings */
 +      /* Rx */
 +      for_each_rx_queue(bp, i) {
 +              struct bnx2x_fastpath *fp = &bp->fp[i];
 +
 +              start = RX_BD(le16_to_cpu(*fp->rx_cons_sb) - 10);
 +              end = RX_BD(le16_to_cpu(*fp->rx_cons_sb) + 503);
 +              for (j = start; j != end; j = RX_BD(j + 1)) {
 +                      u32 *rx_bd = (u32 *)&fp->rx_desc_ring[j];
 +                      struct sw_rx_bd *sw_bd = &fp->rx_buf_ring[j];
 +
 +                      BNX2X_ERR("fp%d: rx_bd[%x]=[%x:%x]  sw_bd=[%p]\n",
 +                                i, j, rx_bd[1], rx_bd[0], sw_bd->skb);
 +              }
 +
 +              start = RX_SGE(fp->rx_sge_prod);
 +              end = RX_SGE(fp->last_max_sge);
 +              for (j = start; j != end; j = RX_SGE(j + 1)) {
 +                      u32 *rx_sge = (u32 *)&fp->rx_sge_ring[j];
 +                      struct sw_rx_page *sw_page = &fp->rx_page_ring[j];
 +
 +                      BNX2X_ERR("fp%d: rx_sge[%x]=[%x:%x]  sw_page=[%p]\n",
 +                                i, j, rx_sge[1], rx_sge[0], sw_page->page);
 +              }
 +
 +              start = RCQ_BD(fp->rx_comp_cons - 10);
 +              end = RCQ_BD(fp->rx_comp_cons + 503);
 +              for (j = start; j != end; j = RCQ_BD(j + 1)) {
 +                      u32 *cqe = (u32 *)&fp->rx_comp_ring[j];
 +
 +                      BNX2X_ERR("fp%d: cqe[%x]=[%x:%x:%x:%x]\n",
 +                                i, j, cqe[0], cqe[1], cqe[2], cqe[3]);
 +              }
 +      }
 +
 +      /* Tx */
 +      for_each_tx_queue(bp, i) {
 +              struct bnx2x_fastpath *fp = &bp->fp[i];
 +              for_each_cos_in_tx_queue(fp, cos) {
 +                      struct bnx2x_fp_txdata *txdata = &fp->txdata[cos];
 +
 +                      start = TX_BD(le16_to_cpu(*txdata->tx_cons_sb) - 10);
 +                      end = TX_BD(le16_to_cpu(*txdata->tx_cons_sb) + 245);
 +                      for (j = start; j != end; j = TX_BD(j + 1)) {
 +                              struct sw_tx_bd *sw_bd =
 +                                      &txdata->tx_buf_ring[j];
 +
 +                              BNX2X_ERR("fp%d: txdata %d, "
 +                                        "packet[%x]=[%p,%x]\n",
 +                                        i, cos, j, sw_bd->skb,
 +                                        sw_bd->first_bd);
 +                      }
 +
 +                      start = TX_BD(txdata->tx_bd_cons - 10);
 +                      end = TX_BD(txdata->tx_bd_cons + 254);
 +                      for (j = start; j != end; j = TX_BD(j + 1)) {
 +                              u32 *tx_bd = (u32 *)&txdata->tx_desc_ring[j];
 +
 +                              BNX2X_ERR("fp%d: txdata %d, tx_bd[%x]="
 +                                        "[%x:%x:%x:%x]\n",
 +                                        i, cos, j, tx_bd[0], tx_bd[1],
 +                                        tx_bd[2], tx_bd[3]);
 +                      }
 +              }
 +      }
 +#endif
 +      bnx2x_fw_dump(bp);
 +      bnx2x_mc_assert(bp);
 +      BNX2X_ERR("end crash dump -----------------\n");
 +}
 +
 +/*
 + * FLR Support for E2
 + *
 + * bnx2x_pf_flr_clnup() is called during nic_load in the per function HW
 + * initialization.
 + */
 +#define FLR_WAIT_USEC         10000   /* 10 miliseconds */
 +#define FLR_WAIT_INTERAVAL    50      /* usec */
 +#define       FLR_POLL_CNT            (FLR_WAIT_USEC/FLR_WAIT_INTERAVAL) /* 200 */
 +
 +struct pbf_pN_buf_regs {
 +      int pN;
 +      u32 init_crd;
 +      u32 crd;
 +      u32 crd_freed;
 +};
 +
 +struct pbf_pN_cmd_regs {
 +      int pN;
 +      u32 lines_occup;
 +      u32 lines_freed;
 +};
 +
 +static void bnx2x_pbf_pN_buf_flushed(struct bnx2x *bp,
 +                                   struct pbf_pN_buf_regs *regs,
 +                                   u32 poll_count)
 +{
 +      u32 init_crd, crd, crd_start, crd_freed, crd_freed_start;
 +      u32 cur_cnt = poll_count;
 +
 +      crd_freed = crd_freed_start = REG_RD(bp, regs->crd_freed);
 +      crd = crd_start = REG_RD(bp, regs->crd);
 +      init_crd = REG_RD(bp, regs->init_crd);
 +
 +      DP(BNX2X_MSG_SP, "INIT CREDIT[%d] : %x\n", regs->pN, init_crd);
 +      DP(BNX2X_MSG_SP, "CREDIT[%d]      : s:%x\n", regs->pN, crd);
 +      DP(BNX2X_MSG_SP, "CREDIT_FREED[%d]: s:%x\n", regs->pN, crd_freed);
 +
 +      while ((crd != init_crd) && ((u32)SUB_S32(crd_freed, crd_freed_start) <
 +             (init_crd - crd_start))) {
 +              if (cur_cnt--) {
 +                      udelay(FLR_WAIT_INTERAVAL);
 +                      crd = REG_RD(bp, regs->crd);
 +                      crd_freed = REG_RD(bp, regs->crd_freed);
 +              } else {
 +                      DP(BNX2X_MSG_SP, "PBF tx buffer[%d] timed out\n",
 +                         regs->pN);
 +                      DP(BNX2X_MSG_SP, "CREDIT[%d]      : c:%x\n",
 +                         regs->pN, crd);
 +                      DP(BNX2X_MSG_SP, "CREDIT_FREED[%d]: c:%x\n",
 +                         regs->pN, crd_freed);
 +                      break;
 +              }
 +      }
 +      DP(BNX2X_MSG_SP, "Waited %d*%d usec for PBF tx buffer[%d]\n",
 +         poll_count-cur_cnt, FLR_WAIT_INTERAVAL, regs->pN);
 +}
 +
 +static void bnx2x_pbf_pN_cmd_flushed(struct bnx2x *bp,
 +                                   struct pbf_pN_cmd_regs *regs,
 +                                   u32 poll_count)
 +{
 +      u32 occup, to_free, freed, freed_start;
 +      u32 cur_cnt = poll_count;
 +
 +      occup = to_free = REG_RD(bp, regs->lines_occup);
 +      freed = freed_start = REG_RD(bp, regs->lines_freed);
 +
 +      DP(BNX2X_MSG_SP, "OCCUPANCY[%d]   : s:%x\n", regs->pN, occup);
 +      DP(BNX2X_MSG_SP, "LINES_FREED[%d] : s:%x\n", regs->pN, freed);
 +
 +      while (occup && ((u32)SUB_S32(freed, freed_start) < to_free)) {
 +              if (cur_cnt--) {
 +                      udelay(FLR_WAIT_INTERAVAL);
 +                      occup = REG_RD(bp, regs->lines_occup);
 +                      freed = REG_RD(bp, regs->lines_freed);
 +              } else {
 +                      DP(BNX2X_MSG_SP, "PBF cmd queue[%d] timed out\n",
 +                         regs->pN);
 +                      DP(BNX2X_MSG_SP, "OCCUPANCY[%d]   : s:%x\n",
 +                         regs->pN, occup);
 +                      DP(BNX2X_MSG_SP, "LINES_FREED[%d] : s:%x\n",
 +                         regs->pN, freed);
 +                      break;
 +              }
 +      }
 +      DP(BNX2X_MSG_SP, "Waited %d*%d usec for PBF cmd queue[%d]\n",
 +         poll_count-cur_cnt, FLR_WAIT_INTERAVAL, regs->pN);
 +}
 +
 +static inline u32 bnx2x_flr_clnup_reg_poll(struct bnx2x *bp, u32 reg,
 +                                   u32 expected, u32 poll_count)
 +{
 +      u32 cur_cnt = poll_count;
 +      u32 val;
 +
 +      while ((val = REG_RD(bp, reg)) != expected && cur_cnt--)
 +              udelay(FLR_WAIT_INTERAVAL);
 +
 +      return val;
 +}
 +
 +static inline 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) {
 +              BNX2X_ERR("%s usage count=%d\n", msg, val);
 +              return 1;
 +      }
 +      return 0;
 +}
 +
 +static u32 bnx2x_flr_clnup_poll_count(struct bnx2x *bp)
 +{
 +      /* adjust polling timeout */
 +      if (CHIP_REV_IS_EMUL(bp))
 +              return FLR_POLL_CNT * 2000;
 +
 +      if (CHIP_REV_IS_FPGA(bp))
 +              return FLR_POLL_CNT * 120;
 +
 +      return FLR_POLL_CNT;
 +}
 +
 +static void bnx2x_tx_hw_flushed(struct bnx2x *bp, u32 poll_count)
 +{
 +      struct pbf_pN_cmd_regs cmd_regs[] = {
 +              {0, (CHIP_IS_E3B0(bp)) ?
 +                      PBF_REG_TQ_OCCUPANCY_Q0 :
 +                      PBF_REG_P0_TQ_OCCUPANCY,
 +                  (CHIP_IS_E3B0(bp)) ?
 +                      PBF_REG_TQ_LINES_FREED_CNT_Q0 :
 +                      PBF_REG_P0_TQ_LINES_FREED_CNT},
 +              {1, (CHIP_IS_E3B0(bp)) ?
 +                      PBF_REG_TQ_OCCUPANCY_Q1 :
 +                      PBF_REG_P1_TQ_OCCUPANCY,
 +                  (CHIP_IS_E3B0(bp)) ?
 +                      PBF_REG_TQ_LINES_FREED_CNT_Q1 :
 +                      PBF_REG_P1_TQ_LINES_FREED_CNT},
 +              {4, (CHIP_IS_E3B0(bp)) ?
 +                      PBF_REG_TQ_OCCUPANCY_LB_Q :
 +                      PBF_REG_P4_TQ_OCCUPANCY,
 +                  (CHIP_IS_E3B0(bp)) ?
 +                      PBF_REG_TQ_LINES_FREED_CNT_LB_Q :
 +                      PBF_REG_P4_TQ_LINES_FREED_CNT}
 +      };
 +
 +      struct pbf_pN_buf_regs buf_regs[] = {
 +              {0, (CHIP_IS_E3B0(bp)) ?
 +                      PBF_REG_INIT_CRD_Q0 :
 +                      PBF_REG_P0_INIT_CRD ,
 +                  (CHIP_IS_E3B0(bp)) ?
 +                      PBF_REG_CREDIT_Q0 :
 +                      PBF_REG_P0_CREDIT,
 +                  (CHIP_IS_E3B0(bp)) ?
 +                      PBF_REG_INTERNAL_CRD_FREED_CNT_Q0 :
 +                      PBF_REG_P0_INTERNAL_CRD_FREED_CNT},
 +              {1, (CHIP_IS_E3B0(bp)) ?
 +                      PBF_REG_INIT_CRD_Q1 :
 +                      PBF_REG_P1_INIT_CRD,
 +                  (CHIP_IS_E3B0(bp)) ?
 +                      PBF_REG_CREDIT_Q1 :
 +                      PBF_REG_P1_CREDIT,
 +                  (CHIP_IS_E3B0(bp)) ?
 +                      PBF_REG_INTERNAL_CRD_FREED_CNT_Q1 :
 +                      PBF_REG_P1_INTERNAL_CRD_FREED_CNT},
 +              {4, (CHIP_IS_E3B0(bp)) ?
 +                      PBF_REG_INIT_CRD_LB_Q :
 +                      PBF_REG_P4_INIT_CRD,
 +                  (CHIP_IS_E3B0(bp)) ?
 +                      PBF_REG_CREDIT_LB_Q :
 +                      PBF_REG_P4_CREDIT,
 +                  (CHIP_IS_E3B0(bp)) ?
 +                      PBF_REG_INTERNAL_CRD_FREED_CNT_LB_Q :
 +                      PBF_REG_P4_INTERNAL_CRD_FREED_CNT},
 +      };
 +
 +      int i;
 +
 +      /* Verify the command queues are flushed P0, P1, P4 */
 +      for (i = 0; i < ARRAY_SIZE(cmd_regs); i++)
 +              bnx2x_pbf_pN_cmd_flushed(bp, &cmd_regs[i], poll_count);
 +
 +
 +      /* Verify the transmission buffers are flushed P0, P1, P4 */
 +      for (i = 0; i < ARRAY_SIZE(buf_regs); i++)
 +              bnx2x_pbf_pN_buf_flushed(bp, &buf_regs[i], poll_count);
 +}
 +
 +#define OP_GEN_PARAM(param) \
 +      (((param) << SDM_OP_GEN_COMP_PARAM_SHIFT) & SDM_OP_GEN_COMP_PARAM)
 +
 +#define OP_GEN_TYPE(type) \
 +      (((type) << SDM_OP_GEN_COMP_TYPE_SHIFT) & SDM_OP_GEN_COMP_TYPE)
 +
 +#define OP_GEN_AGG_VECT(index) \
 +      (((index) << SDM_OP_GEN_AGG_VECT_IDX_SHIFT) & SDM_OP_GEN_AGG_VECT_IDX)
 +
 +
 +static inline int bnx2x_send_final_clnup(struct bnx2x *bp, u8 clnup_func,
 +                                       u32 poll_cnt)
 +{
 +      struct sdm_op_gen op_gen = {0};
 +
 +      u32 comp_addr = BAR_CSTRORM_INTMEM +
 +                      CSTORM_FINAL_CLEANUP_COMPLETE_OFFSET(clnup_func);
 +      int ret = 0;
 +
 +      if (REG_RD(bp, comp_addr)) {
 +              BNX2X_ERR("Cleanup complete is not 0\n");
 +              return 1;
 +      }
 +
 +      op_gen.command |= OP_GEN_PARAM(XSTORM_AGG_INT_FINAL_CLEANUP_INDEX);
 +      op_gen.command |= OP_GEN_TYPE(XSTORM_AGG_INT_FINAL_CLEANUP_COMP_TYPE);
 +      op_gen.command |= OP_GEN_AGG_VECT(clnup_func);
 +      op_gen.command |= 1 << SDM_OP_GEN_AGG_VECT_IDX_VALID_SHIFT;
 +
 +      DP(BNX2X_MSG_SP, "FW Final cleanup\n");
 +      REG_WR(bp, XSDM_REG_OPERATION_GEN, op_gen.command);
 +
 +      if (bnx2x_flr_clnup_reg_poll(bp, comp_addr, 1, poll_cnt) != 1) {
 +              BNX2X_ERR("FW final cleanup did not succeed\n");
 +              ret = 1;
 +      }
 +      /* Zero completion for nxt FLR */
 +      REG_WR(bp, comp_addr, 0);
 +
 +      return ret;
 +}
 +
 +static inline u8 bnx2x_is_pcie_pending(struct pci_dev *dev)
 +{
 +      int pos;
 +      u16 status;
 +
 +      pos = pci_pcie_cap(dev);
 +      if (!pos)
 +              return false;
 +
 +      pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, &status);
 +      return status & PCI_EXP_DEVSTA_TRPND;
 +}
 +
 +/* PF FLR specific routines
 +*/
 +static int bnx2x_poll_hw_usage_counters(struct bnx2x *bp, u32 poll_cnt)
 +{
 +
 +      /* wait for CFC PF usage-counter to zero (includes all the VFs) */
 +      if (bnx2x_flr_clnup_poll_hw_counter(bp,
 +                      CFC_REG_NUM_LCIDS_INSIDE_PF,
 +                      "CFC PF usage counter timed out",
 +                      poll_cnt))
 +              return 1;
 +
 +
 +      /* Wait for DQ PF usage-counter to zero (until DQ cleanup) */
 +      if (bnx2x_flr_clnup_poll_hw_counter(bp,
 +                      DORQ_REG_PF_USAGE_CNT,
 +                      "DQ PF usage counter timed out",
 +                      poll_cnt))
 +              return 1;
 +
 +      /* Wait for QM PF usage-counter to zero (until DQ cleanup) */
 +      if (bnx2x_flr_clnup_poll_hw_counter(bp,
 +                      QM_REG_PF_USG_CNT_0 + 4*BP_FUNC(bp),
 +                      "QM PF usage counter timed out",
 +                      poll_cnt))
 +              return 1;
 +
 +      /* Wait for Timer PF usage-counters to zero (until DQ cleanup) */
 +      if (bnx2x_flr_clnup_poll_hw_counter(bp,
 +                      TM_REG_LIN0_VNIC_UC + 4*BP_PORT(bp),
 +                      "Timers VNIC usage counter timed out",
 +                      poll_cnt))
 +              return 1;
 +      if (bnx2x_flr_clnup_poll_hw_counter(bp,
 +                      TM_REG_LIN0_NUM_SCANS + 4*BP_PORT(bp),
 +                      "Timers NUM_SCANS usage counter timed out",
 +                      poll_cnt))
 +              return 1;
 +
 +      /* Wait DMAE PF usage counter to zero */
 +      if (bnx2x_flr_clnup_poll_hw_counter(bp,
 +                      dmae_reg_go_c[INIT_DMAE_C(bp)],
 +                      "DMAE dommand register timed out",
 +                      poll_cnt))
 +              return 1;
 +
 +      return 0;
 +}
 +
 +static void bnx2x_hw_enable_status(struct bnx2x *bp)
 +{
 +      u32 val;
 +
 +      val = REG_RD(bp, CFC_REG_WEAK_ENABLE_PF);
 +      DP(BNX2X_MSG_SP, "CFC_REG_WEAK_ENABLE_PF is 0x%x\n", val);
 +
 +      val = REG_RD(bp, PBF_REG_DISABLE_PF);
 +      DP(BNX2X_MSG_SP, "PBF_REG_DISABLE_PF is 0x%x\n", val);
 +
 +      val = REG_RD(bp, IGU_REG_PCI_PF_MSI_EN);
 +      DP(BNX2X_MSG_SP, "IGU_REG_PCI_PF_MSI_EN is 0x%x\n", val);
 +
 +      val = REG_RD(bp, IGU_REG_PCI_PF_MSIX_EN);
 +      DP(BNX2X_MSG_SP, "IGU_REG_PCI_PF_MSIX_EN is 0x%x\n", val);
 +
 +      val = REG_RD(bp, IGU_REG_PCI_PF_MSIX_FUNC_MASK);
 +      DP(BNX2X_MSG_SP, "IGU_REG_PCI_PF_MSIX_FUNC_MASK is 0x%x\n", val);
 +
 +      val = REG_RD(bp, PGLUE_B_REG_SHADOW_BME_PF_7_0_CLR);
 +      DP(BNX2X_MSG_SP, "PGLUE_B_REG_SHADOW_BME_PF_7_0_CLR is 0x%x\n", val);
 +
 +      val = REG_RD(bp, PGLUE_B_REG_FLR_REQUEST_PF_7_0_CLR);
 +      DP(BNX2X_MSG_SP, "PGLUE_B_REG_FLR_REQUEST_PF_7_0_CLR is 0x%x\n", val);
 +
 +      val = REG_RD(bp, PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER);
 +      DP(BNX2X_MSG_SP, "PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER is 0x%x\n",
 +         val);
 +}
 +
 +static int bnx2x_pf_flr_clnup(struct bnx2x *bp)
 +{
 +      u32 poll_cnt = bnx2x_flr_clnup_poll_count(bp);
 +
 +      DP(BNX2X_MSG_SP, "Cleanup after FLR PF[%d]\n", BP_ABS_FUNC(bp));
 +
 +      /* Re-enable PF target read access */
 +      REG_WR(bp, PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_READ, 1);
 +
 +      /* Poll HW usage counters */
 +      if (bnx2x_poll_hw_usage_counters(bp, poll_cnt))
 +              return -EBUSY;
 +
 +      /* Zero the igu 'trailing edge' and 'leading edge' */
 +
 +      /* Send the FW cleanup command */
 +      if (bnx2x_send_final_clnup(bp, (u8)BP_FUNC(bp), poll_cnt))
 +              return -EBUSY;
 +
 +      /* ATC cleanup */
 +
 +      /* Verify TX hw is flushed */
 +      bnx2x_tx_hw_flushed(bp, poll_cnt);
 +
 +      /* Wait 100ms (not adjusted according to platform) */
 +      msleep(100);
 +
 +      /* Verify no pending pci transactions */
 +      if (bnx2x_is_pcie_pending(bp->pdev))
 +              BNX2X_ERR("PCIE Transactions still pending\n");
 +
 +      /* Debug */
 +      bnx2x_hw_enable_status(bp);
 +
 +      /*
 +       * Master enable - Due to WB DMAE writes performed before this
 +       * register is re-initialized as part of the regular function init
 +       */
 +      REG_WR(bp, PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER, 1);
 +
 +      return 0;
 +}
 +
 +static void bnx2x_hc_int_enable(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);
 +      int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0;
 +      int msi = (bp->flags & USING_MSI_FLAG) ? 1 : 0;
 +
 +      if (msix) {
 +              val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
 +                       HC_CONFIG_0_REG_INT_LINE_EN_0);
 +              val |= (HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
 +                      HC_CONFIG_0_REG_ATTN_BIT_EN_0);
 +      } else if (msi) {
 +              val &= ~HC_CONFIG_0_REG_INT_LINE_EN_0;
 +              val |= (HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
 +                      HC_CONFIG_0_REG_MSI_MSIX_INT_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);
 +
 +              if (!CHIP_IS_E1(bp)) {
 +                      DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x)\n",
 +                         val, port, addr);
 +
 +                      REG_WR(bp, addr, val);
 +
 +                      val &= ~HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0;
 +              }
 +      }
 +
 +      if (CHIP_IS_E1(bp))
 +              REG_WR(bp, HC_REG_INT_MASK + port*4, 0x1FFFF);
 +
 +      DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x)  mode %s\n",
 +         val, port, addr, (msix ? "MSI-X" : (msi ? "MSI" : "INTx")));
 +
 +      REG_WR(bp, addr, val);
 +      /*
 +       * Ensure that HC_CONFIG is written before leading/trailing edge config
 +       */
 +      mmiowb();
 +      barrier();
 +
 +      if (!CHIP_IS_E1(bp)) {
 +              /* init leading/trailing edge */
 +              if (IS_MF(bp)) {
 +                      val = (0xee0f | (1 << (BP_VN(bp) + 4)));
 +                      if (bp->port.pmf)
 +                              /* enable nig and gpio3 attention */
 +                              val |= 0x1100;
 +              } else
 +                      val = 0xffff;
 +
 +              REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, val);
 +              REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, val);
 +      }
 +
 +      /* Make sure that interrupts are indeed enabled from here on */
 +      mmiowb();
 +}
 +
 +static void bnx2x_igu_int_enable(struct bnx2x *bp)
 +{
 +      u32 val;
 +      int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0;
 +      int msi = (bp->flags & USING_MSI_FLAG) ? 1 : 0;
 +
 +      val = REG_RD(bp, IGU_REG_PF_CONFIGURATION);
 +
 +      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 |
 +                      IGU_PF_CONF_ATTN_BIT_EN);
 +      } else if (msi) {
 +              val &= ~IGU_PF_CONF_INT_LINE_EN;
 +              val |= (IGU_PF_CONF_FUNC_EN |
 +                      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 |
 +                      IGU_PF_CONF_ATTN_BIT_EN |
 +                      IGU_PF_CONF_SINGLE_ISR_EN);
 +      }
 +
 +      DP(NETIF_MSG_INTR, "write 0x%x to IGU  mode %s\n",
 +         val, (msix ? "MSI-X" : (msi ? "MSI" : "INTx")));
 +
 +      REG_WR(bp, IGU_REG_PF_CONFIGURATION, val);
 +
 +      barrier();
 +
 +      /* init leading/trailing edge */
 +      if (IS_MF(bp)) {
 +              val = (0xee0f | (1 << (BP_VN(bp) + 4)));
 +              if (bp->port.pmf)
 +                      /* enable nig and gpio3 attention */
 +                      val |= 0x1100;
 +      } else
 +              val = 0xffff;
 +
 +      REG_WR(bp, IGU_REG_TRAILING_EDGE_LATCH, val);
 +      REG_WR(bp, IGU_REG_LEADING_EDGE_LATCH, val);
 +
 +      /* Make sure that interrupts are indeed enabled from here on */
 +      mmiowb();
 +}
 +
 +void bnx2x_int_enable(struct bnx2x *bp)
 +{
 +      if (bp->common.int_block == INT_BLOCK_HC)
 +              bnx2x_hc_int_enable(bp);
 +      else
 +              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_INTR, "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_INTR, "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");
 +}
 +
 +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;
 +      int i, offset;
 +
 +      if (disable_hw)
 +              /* prevent the HW from sending interrupts */
 +              bnx2x_int_disable(bp);
 +
 +      /* make sure all ISRs are done */
 +      if (msix) {
 +              synchronize_irq(bp->msix_table[0].vector);
 +              offset = 1;
 +#ifdef BCM_CNIC
 +              offset++;
 +#endif
 +              for_each_eth_queue(bp, i)
 +                      synchronize_irq(bp->msix_table[offset++].vector);
 +      } else
 +              synchronize_irq(bp->pdev->irq);
 +
 +      /* make sure sp_task is not running */
 +      cancel_delayed_work(&bp->sp_task);
 +      cancel_delayed_work(&bp->period_task);
 +      flush_workqueue(bnx2x_wq);
 +}
 +
 +/* fast path */
 +
 +/*
 + * General service functions
 + */
 +
 +/* Return true if succeeded to acquire the lock */
 +static bool bnx2x_trylock_hw_lock(struct bnx2x *bp, u32 resource)
 +{
 +      u32 lock_status;
 +      u32 resource_bit = (1 << resource);
 +      int func = BP_FUNC(bp);
 +      u32 hw_lock_control_reg;
 +
 +      DP(NETIF_MSG_HW, "Trying to take a lock on resource %d\n", resource);
 +
 +      /* Validating that the resource is within range */
 +      if (resource > HW_LOCK_MAX_RESOURCE_VALUE) {
 +              DP(NETIF_MSG_HW,
 +                 "resource(0x%x) > HW_LOCK_MAX_RESOURCE_VALUE(0x%x)\n",
 +                 resource, HW_LOCK_MAX_RESOURCE_VALUE);
 +              return false;
 +      }
 +
 +      if (func <= 5)
 +              hw_lock_control_reg = (MISC_REG_DRIVER_CONTROL_1 + func*8);
 +      else
 +              hw_lock_control_reg =
 +                              (MISC_REG_DRIVER_CONTROL_7 + (func - 6)*8);
 +
 +      /* Try to acquire the lock */
 +      REG_WR(bp, hw_lock_control_reg + 4, resource_bit);
 +      lock_status = REG_RD(bp, hw_lock_control_reg);
 +      if (lock_status & resource_bit)
 +              return true;
 +
 +      DP(NETIF_MSG_HW, "Failed to get a lock on resource %d\n", resource);
 +      return false;
 +}
 +
 +/**
 + * bnx2x_get_leader_lock_resource - get the recovery leader resource id
 + *
 + * @bp:       driver handle
 + *
 + * Returns the recovery leader resource id according to the engine this function
 + * belongs to. Currently only only 2 engines is supported.
 + */
 +static inline int bnx2x_get_leader_lock_resource(struct bnx2x *bp)
 +{
 +      if (BP_PATH(bp))
 +              return HW_LOCK_RESOURCE_RECOVERY_LEADER_1;
 +      else
 +              return HW_LOCK_RESOURCE_RECOVERY_LEADER_0;
 +}
 +
 +/**
 + * bnx2x_trylock_leader_lock- try to aquire a leader lock.
 + *
 + * @bp: driver handle
 + *
 + * Tries to aquire a leader lock for cuurent engine.
 + */
 +static inline bool bnx2x_trylock_leader_lock(struct bnx2x *bp)
 +{
 +      return bnx2x_trylock_hw_lock(bp, bnx2x_get_leader_lock_resource(bp));
 +}
 +
 +#ifdef BCM_CNIC
 +static void bnx2x_cnic_cfc_comp(struct bnx2x *bp, int cid, u8 err);
 +#endif
 +
 +void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe)
 +{
 +      struct bnx2x *bp = fp->bp;
 +      int cid = SW_CID(rr_cqe->ramrod_cqe.conn_and_cmd_data);
 +      int command = CQE_CMD(rr_cqe->ramrod_cqe.conn_and_cmd_data);
 +      enum bnx2x_queue_cmd drv_cmd = BNX2X_Q_CMD_MAX;
 +      struct bnx2x_queue_sp_obj *q_obj = &fp->q_obj;
 +
 +      DP(BNX2X_MSG_SP,
 +         "fp %d  cid %d  got ramrod #%d  state is %x  type is %d\n",
 +         fp->index, cid, command, bp->state,
 +         rr_cqe->ramrod_cqe.ramrod_type);
 +
 +      switch (command) {
 +      case (RAMROD_CMD_ID_ETH_CLIENT_UPDATE):
 +              DP(BNX2X_MSG_SP, "got UPDATE ramrod. CID %d\n", cid);
 +              drv_cmd = BNX2X_Q_CMD_UPDATE;
 +              break;
 +
 +      case (RAMROD_CMD_ID_ETH_CLIENT_SETUP):
 +              DP(BNX2X_MSG_SP, "got MULTI[%d] setup ramrod\n", cid);
 +              drv_cmd = BNX2X_Q_CMD_SETUP;
 +              break;
 +
 +      case (RAMROD_CMD_ID_ETH_TX_QUEUE_SETUP):
 +              DP(NETIF_MSG_IFUP, "got MULTI[%d] tx-only setup ramrod\n", cid);
 +              drv_cmd = BNX2X_Q_CMD_SETUP_TX_ONLY;
 +              break;
 +
 +      case (RAMROD_CMD_ID_ETH_HALT):
 +              DP(BNX2X_MSG_SP, "got MULTI[%d] halt ramrod\n", cid);
 +              drv_cmd = BNX2X_Q_CMD_HALT;
 +              break;
 +
 +      case (RAMROD_CMD_ID_ETH_TERMINATE):
 +              DP(BNX2X_MSG_SP, "got MULTI[%d] teminate ramrod\n", cid);
 +              drv_cmd = BNX2X_Q_CMD_TERMINATE;
 +              break;
 +
 +      case (RAMROD_CMD_ID_ETH_EMPTY):
 +              DP(BNX2X_MSG_SP, "got MULTI[%d] empty ramrod\n", cid);
 +              drv_cmd = BNX2X_Q_CMD_EMPTY;
 +              break;
 +
 +      default:
 +              BNX2X_ERR("unexpected MC reply (%d) on fp[%d]\n",
 +                        command, fp->index);
 +              return;
 +      }
 +
 +      if ((drv_cmd != BNX2X_Q_CMD_MAX) &&
 +          q_obj->complete_cmd(bp, q_obj, drv_cmd))
 +              /* q_obj->complete_cmd() failure means that this was
 +               * an unexpected completion.
 +               *
 +               * In this case we don't want to increase the bp->spq_left
 +               * because apparently we haven't sent this command the first
 +               * place.
 +               */
 +#ifdef BNX2X_STOP_ON_ERROR
 +              bnx2x_panic();
 +#else
 +              return;
 +#endif
 +
 +      smp_mb__before_atomic_inc();
 +      atomic_inc(&bp->cq_spq_left);
 +      /* push the change in bp->spq_left and towards the memory */
 +      smp_mb__after_atomic_inc();
 +
 +      DP(BNX2X_MSG_SP, "bp->cq_spq_left %x\n", atomic_read(&bp->cq_spq_left));
 +
 +      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);
 +      u16 status = bnx2x_ack_int(bp);
 +      u16 mask;
 +      int i;
 +      u8 cos;
 +
 +      /* Return here if interrupt is shared and it's not for us */
 +      if (unlikely(status == 0)) {
 +              DP(NETIF_MSG_INTR, "not our interrupt!\n");
 +              return IRQ_NONE;
 +      }
 +      DP(NETIF_MSG_INTR, "got an interrupt  status 0x%x\n", status);
 +
 +#ifdef BNX2X_STOP_ON_ERROR
 +      if (unlikely(bp->panic))
 +              return IRQ_HANDLED;
 +#endif
 +
 +      for_each_eth_queue(bp, i) {
 +              struct bnx2x_fastpath *fp = &bp->fp[i];
 +
 +              mask = 0x2 << (fp->index + CNIC_PRESENT);
 +              if (status & mask) {
 +                      /* Handle Rx or Tx according to SB id */
 +                      prefetch(fp->rx_cons_sb);
 +                      for_each_cos_in_tx_queue(fp, cos)
 +                              prefetch(fp->txdata[cos].tx_cons_sb);
 +                      prefetch(&fp->sb_running_index[SM_RX_ID]);
 +                      napi_schedule(&bnx2x_fp(bp, fp->index, napi));
 +                      status &= ~mask;
 +              }
 +      }
 +
 +#ifdef BCM_CNIC
 +      mask = 0x2;
 +      if (status & (mask | 0x1)) {
 +              struct cnic_ops *c_ops = NULL;
 +
 +              if (likely(bp->state == BNX2X_STATE_OPEN)) {
 +                      rcu_read_lock();
 +                      c_ops = rcu_dereference(bp->cnic_ops);
 +                      if (c_ops)
 +                              c_ops->cnic_handler(bp->cnic_data, NULL);
 +                      rcu_read_unlock();
 +              }
 +
 +              status &= ~mask;
 +      }
 +#endif
 +
 +      if (unlikely(status & 0x1)) {
 +              queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
 +
 +              status &= ~0x1;
 +              if (!status)
 +                      return IRQ_HANDLED;
 +      }
 +
 +      if (unlikely(status))
 +              DP(NETIF_MSG_INTR, "got an unknown interrupt! (status 0x%x)\n",
 +                 status);
 +
 +      return IRQ_HANDLED;
 +}
 +
 +/* Link */
 +
 +/*
 + * General service functions
 + */
 +
 +int bnx2x_acquire_hw_lock(struct bnx2x *bp, u32 resource)
 +{
 +      u32 lock_status;
 +      u32 resource_bit = (1 << resource);
 +      int func = BP_FUNC(bp);
 +      u32 hw_lock_control_reg;
 +      int cnt;
 +
 +      /* Validating that the resource is within range */
 +      if (resource > HW_LOCK_MAX_RESOURCE_VALUE) {
 +              DP(NETIF_MSG_HW,
 +                 "resource(0x%x) > HW_LOCK_MAX_RESOURCE_VALUE(0x%x)\n",
 +                 resource, HW_LOCK_MAX_RESOURCE_VALUE);
 +              return -EINVAL;
 +      }
 +
 +      if (func <= 5) {
 +              hw_lock_control_reg = (MISC_REG_DRIVER_CONTROL_1 + func*8);
 +      } else {
 +              hw_lock_control_reg =
 +                              (MISC_REG_DRIVER_CONTROL_7 + (func - 6)*8);
 +      }
 +
 +      /* Validating that the resource is not already taken */
 +      lock_status = REG_RD(bp, hw_lock_control_reg);
 +      if (lock_status & resource_bit) {
 +              DP(NETIF_MSG_HW, "lock_status 0x%x  resource_bit 0x%x\n",
 +                 lock_status, resource_bit);
 +              return -EEXIST;
 +      }
 +
 +      /* Try for 5 second every 5ms */
 +      for (cnt = 0; cnt < 1000; cnt++) {
 +              /* Try to acquire the lock */
 +              REG_WR(bp, hw_lock_control_reg + 4, resource_bit);
 +              lock_status = REG_RD(bp, hw_lock_control_reg);
 +              if (lock_status & resource_bit)
 +                      return 0;
 +
 +              msleep(5);
 +      }
 +      DP(NETIF_MSG_HW, "Timeout\n");
 +      return -EAGAIN;
 +}
 +
 +int bnx2x_release_leader_lock(struct bnx2x *bp)
 +{
 +      return bnx2x_release_hw_lock(bp, bnx2x_get_leader_lock_resource(bp));
 +}
 +
 +int bnx2x_release_hw_lock(struct bnx2x *bp, u32 resource)
 +{
 +      u32 lock_status;
 +      u32 resource_bit = (1 << resource);
 +      int func = BP_FUNC(bp);
 +      u32 hw_lock_control_reg;
 +
 +      DP(NETIF_MSG_HW, "Releasing a lock on resource %d\n", resource);
 +
 +      /* Validating that the resource is within range */
 +      if (resource > HW_LOCK_MAX_RESOURCE_VALUE) {
 +              DP(NETIF_MSG_HW,
 +                 "resource(0x%x) > HW_LOCK_MAX_RESOURCE_VALUE(0x%x)\n",
 +                 resource, HW_LOCK_MAX_RESOURCE_VALUE);
 +              return -EINVAL;
 +      }
 +
 +      if (func <= 5) {
 +              hw_lock_control_reg = (MISC_REG_DRIVER_CONTROL_1 + func*8);
 +      } else {
 +              hw_lock_control_reg =
 +                              (MISC_REG_DRIVER_CONTROL_7 + (func - 6)*8);
 +      }
 +
 +      /* Validating that the resource is currently taken */
 +      lock_status = REG_RD(bp, hw_lock_control_reg);
 +      if (!(lock_status & resource_bit)) {
 +              DP(NETIF_MSG_HW, "lock_status 0x%x  resource_bit 0x%x\n",
 +                 lock_status, resource_bit);
 +              return -EFAULT;
 +      }
 +
 +      REG_WR(bp, hw_lock_control_reg, resource_bit);
 +      return 0;
 +}
 +
 +
 +int bnx2x_get_gpio(struct bnx2x *bp, int gpio_num, u8 port)
 +{
 +      /* The GPIO should be swapped if swap register is set and active */
 +      int gpio_port = (REG_RD(bp, NIG_REG_PORT_SWAP) &&
 +                       REG_RD(bp, NIG_REG_STRAP_OVERRIDE)) ^ port;
 +      int gpio_shift = gpio_num +
 +                      (gpio_port ? MISC_REGISTERS_GPIO_PORT_SHIFT : 0);
 +      u32 gpio_mask = (1 << gpio_shift);
 +      u32 gpio_reg;
 +      int value;
 +
 +      if (gpio_num > MISC_REGISTERS_GPIO_3) {
 +              BNX2X_ERR("Invalid GPIO %d\n", gpio_num);
 +              return -EINVAL;
 +      }
 +
 +      /* read GPIO value */
 +      gpio_reg = REG_RD(bp, MISC_REG_GPIO);
 +
 +      /* get the requested pin value */
 +      if ((gpio_reg & gpio_mask) == gpio_mask)
 +              value = 1;
 +      else
 +              value = 0;
 +
 +      DP(NETIF_MSG_LINK, "pin %d  value 0x%x\n", gpio_num, value);
 +
 +      return value;
 +}
 +
 +int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode, u8 port)
 +{
 +      /* The GPIO should be swapped if swap register is set and active */
 +      int gpio_port = (REG_RD(bp, NIG_REG_PORT_SWAP) &&
 +                       REG_RD(bp, NIG_REG_STRAP_OVERRIDE)) ^ port;
 +      int gpio_shift = gpio_num +
 +                      (gpio_port ? MISC_REGISTERS_GPIO_PORT_SHIFT : 0);
 +      u32 gpio_mask = (1 << gpio_shift);
 +      u32 gpio_reg;
 +
 +      if (gpio_num > MISC_REGISTERS_GPIO_3) {
 +              BNX2X_ERR("Invalid GPIO %d\n", gpio_num);
 +              return -EINVAL;
 +      }
 +
 +      bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_GPIO);
 +      /* read GPIO and mask except the float bits */
 +      gpio_reg = (REG_RD(bp, MISC_REG_GPIO) & MISC_REGISTERS_GPIO_FLOAT);
 +
 +      switch (mode) {
 +      case MISC_REGISTERS_GPIO_OUTPUT_LOW:
 +              DP(NETIF_MSG_LINK, "Set GPIO %d (shift %d) -> output low\n",
 +                 gpio_num, gpio_shift);
 +              /* clear FLOAT and set CLR */
 +              gpio_reg &= ~(gpio_mask << MISC_REGISTERS_GPIO_FLOAT_POS);
 +              gpio_reg |=  (gpio_mask << MISC_REGISTERS_GPIO_CLR_POS);
 +              break;
 +
 +      case MISC_REGISTERS_GPIO_OUTPUT_HIGH:
 +              DP(NETIF_MSG_LINK, "Set GPIO %d (shift %d) -> output high\n",
 +                 gpio_num, gpio_shift);
 +              /* clear FLOAT and set SET */
 +              gpio_reg &= ~(gpio_mask << MISC_REGISTERS_GPIO_FLOAT_POS);
 +              gpio_reg |=  (gpio_mask << MISC_REGISTERS_GPIO_SET_POS);
 +              break;
 +
 +      case MISC_REGISTERS_GPIO_INPUT_HI_Z:
 +              DP(NETIF_MSG_LINK, "Set GPIO %d (shift %d) -> input\n",
 +                 gpio_num, gpio_shift);
 +              /* set FLOAT */
 +              gpio_reg |= (gpio_mask << MISC_REGISTERS_GPIO_FLOAT_POS);
 +              break;
 +
 +      default:
 +              break;
 +      }
 +
 +      REG_WR(bp, MISC_REG_GPIO, gpio_reg);
 +      bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_GPIO);
 +
 +      return 0;
 +}
 +
 +int bnx2x_set_mult_gpio(struct bnx2x *bp, u8 pins, u32 mode)
 +{
 +      u32 gpio_reg = 0;
 +      int rc = 0;
 +
 +      /* Any port swapping should be handled by caller. */
 +
 +      bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_GPIO);
 +      /* read GPIO and mask except the float bits */
 +      gpio_reg = REG_RD(bp, MISC_REG_GPIO);
 +      gpio_reg &= ~(pins << MISC_REGISTERS_GPIO_FLOAT_POS);
 +      gpio_reg &= ~(pins << MISC_REGISTERS_GPIO_CLR_POS);
 +      gpio_reg &= ~(pins << MISC_REGISTERS_GPIO_SET_POS);
 +
 +      switch (mode) {
 +      case MISC_REGISTERS_GPIO_OUTPUT_LOW:
 +              DP(NETIF_MSG_LINK, "Set GPIO 0x%x -> output low\n", pins);
 +              /* set CLR */
 +              gpio_reg |= (pins << MISC_REGISTERS_GPIO_CLR_POS);
 +              break;
 +
 +      case MISC_REGISTERS_GPIO_OUTPUT_HIGH:
 +              DP(NETIF_MSG_LINK, "Set GPIO 0x%x -> output high\n", pins);
 +              /* set SET */
 +              gpio_reg |= (pins << MISC_REGISTERS_GPIO_SET_POS);
 +              break;
 +
 +      case MISC_REGISTERS_GPIO_INPUT_HI_Z:
 +              DP(NETIF_MSG_LINK, "Set GPIO 0x%x -> input\n", pins);
 +              /* set FLOAT */
 +              gpio_reg |= (pins << MISC_REGISTERS_GPIO_FLOAT_POS);
 +              break;
 +
 +      default:
 +              BNX2X_ERR("Invalid GPIO mode assignment %d\n", mode);
 +              rc = -EINVAL;
 +              break;
 +      }
 +
 +      if (rc == 0)
 +              REG_WR(bp, MISC_REG_GPIO, gpio_reg);
 +
 +      bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_GPIO);
 +
 +      return rc;
 +}
 +
 +int bnx2x_set_gpio_int(struct bnx2x *bp, int gpio_num, u32 mode, u8 port)
 +{
 +      /* The GPIO should be swapped if swap register is set and active */
 +      int gpio_port = (REG_RD(bp, NIG_REG_PORT_SWAP) &&
 +                       REG_RD(bp, NIG_REG_STRAP_OVERRIDE)) ^ port;
 +      int gpio_shift = gpio_num +
 +                      (gpio_port ? MISC_REGISTERS_GPIO_PORT_SHIFT : 0);
 +      u32 gpio_mask = (1 << gpio_shift);
 +      u32 gpio_reg;
 +
 +      if (gpio_num > MISC_REGISTERS_GPIO_3) {
 +              BNX2X_ERR("Invalid GPIO %d\n", gpio_num);
 +              return -EINVAL;
 +      }
 +
 +      bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_GPIO);
 +      /* read GPIO int */
 +      gpio_reg = REG_RD(bp, MISC_REG_GPIO_INT);
 +
 +      switch (mode) {
 +      case MISC_REGISTERS_GPIO_INT_OUTPUT_CLR:
 +              DP(NETIF_MSG_LINK, "Clear GPIO INT %d (shift %d) -> "
 +                                 "output low\n", gpio_num, gpio_shift);
 +              /* clear SET and set CLR */
 +              gpio_reg &= ~(gpio_mask << MISC_REGISTERS_GPIO_INT_SET_POS);
 +              gpio_reg |=  (gpio_mask << MISC_REGISTERS_GPIO_INT_CLR_POS);
 +              break;
 +
 +      case MISC_REGISTERS_GPIO_INT_OUTPUT_SET:
 +              DP(NETIF_MSG_LINK, "Set GPIO INT %d (shift %d) -> "
 +                                 "output high\n", gpio_num, gpio_shift);
 +              /* clear CLR and set SET */
 +              gpio_reg &= ~(gpio_mask << MISC_REGISTERS_GPIO_INT_CLR_POS);
 +              gpio_reg |=  (gpio_mask << MISC_REGISTERS_GPIO_INT_SET_POS);
 +              break;
 +
 +      default:
 +              break;
 +      }
 +
 +      REG_WR(bp, MISC_REG_GPIO_INT, gpio_reg);
 +      bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_GPIO);
 +
 +      return 0;
 +}
 +
 +static int bnx2x_set_spio(struct bnx2x *bp, int spio_num, u32 mode)
 +{
 +      u32 spio_mask = (1 << spio_num);
 +      u32 spio_reg;
 +
 +      if ((spio_num < MISC_REGISTERS_SPIO_4) ||
 +          (spio_num > MISC_REGISTERS_SPIO_7)) {
 +              BNX2X_ERR("Invalid SPIO %d\n", spio_num);
 +              return -EINVAL;
 +      }
 +
 +      bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_SPIO);
 +      /* read SPIO and mask except the float bits */
 +      spio_reg = (REG_RD(bp, MISC_REG_SPIO) & MISC_REGISTERS_SPIO_FLOAT);
 +
 +      switch (mode) {
 +      case MISC_REGISTERS_SPIO_OUTPUT_LOW:
 +              DP(NETIF_MSG_LINK, "Set SPIO %d -> output low\n", spio_num);
 +              /* clear FLOAT and set CLR */
 +              spio_reg &= ~(spio_mask << MISC_REGISTERS_SPIO_FLOAT_POS);
 +              spio_reg |=  (spio_mask << MISC_REGISTERS_SPIO_CLR_POS);
 +              break;
 +
 +      case MISC_REGISTERS_SPIO_OUTPUT_HIGH:
 +              DP(NETIF_MSG_LINK, "Set SPIO %d -> output high\n", spio_num);
 +              /* clear FLOAT and set SET */
 +              spio_reg &= ~(spio_mask << MISC_REGISTERS_SPIO_FLOAT_POS);
 +              spio_reg |=  (spio_mask << MISC_REGISTERS_SPIO_SET_POS);
 +              break;
 +
 +      case MISC_REGISTERS_SPIO_INPUT_HI_Z:
 +              DP(NETIF_MSG_LINK, "Set SPIO %d -> input\n", spio_num);
 +              /* set FLOAT */
 +              spio_reg |= (spio_mask << MISC_REGISTERS_SPIO_FLOAT_POS);
 +              break;
 +
 +      default:
 +              break;
 +      }
 +
 +      REG_WR(bp, MISC_REG_SPIO, spio_reg);
 +      bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_SPIO);
 +
 +      return 0;
 +}
 +
 +void bnx2x_calc_fc_adv(struct bnx2x *bp)
 +{
 +      u8 cfg_idx = bnx2x_get_link_cfg_idx(bp);
 +      switch (bp->link_vars.ieee_fc &
 +              MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK) {
 +      case MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE:
 +              bp->port.advertising[cfg_idx] &= ~(ADVERTISED_Asym_Pause |
 +                                                 ADVERTISED_Pause);
 +              break;
 +
 +      case MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH:
 +              bp->port.advertising[cfg_idx] |= (ADVERTISED_Asym_Pause |
 +                                                ADVERTISED_Pause);
 +              break;
 +
 +      case MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC:
 +              bp->port.advertising[cfg_idx] |= ADVERTISED_Asym_Pause;
 +              break;
 +
 +      default:
 +              bp->port.advertising[cfg_idx] &= ~(ADVERTISED_Asym_Pause |
 +                                                 ADVERTISED_Pause);
 +              break;
 +      }
 +}
 +
 +u8 bnx2x_initial_phy_init(struct bnx2x *bp, int load_mode)
 +{
 +      if (!BP_NOMCP(bp)) {
 +              u8 rc;
 +              int cfx_idx = bnx2x_get_link_cfg_idx(bp);
 +              u16 req_line_speed = bp->link_params.req_line_speed[cfx_idx];
 +              /*
 +               * Initialize link parameters structure variables
 +               * It is recommended to turn off RX FC for jumbo frames
 +               * for better performance
 +               */
 +              if (CHIP_IS_E1x(bp) && (bp->dev->mtu > 5000))
 +                      bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_TX;
 +              else
 +                      bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_BOTH;
 +
 +              bnx2x_acquire_phy_lock(bp);
 +
 +              if (load_mode == LOAD_DIAG) {
 +                      struct link_params *lp = &bp->link_params;
 +                      lp->loopback_mode = LOOPBACK_XGXS;
 +                      /* do PHY loopback at 10G speed, if possible */
 +                      if (lp->req_line_speed[cfx_idx] < SPEED_10000) {
 +                              if (lp->speed_cap_mask[cfx_idx] &
 +                                  PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
 +                                      lp->req_line_speed[cfx_idx] =
 +                                      SPEED_10000;
 +                              else
 +                                      lp->req_line_speed[cfx_idx] =
 +                                      SPEED_1000;
 +                      }
 +              }
 +
 +              rc = bnx2x_phy_init(&bp->link_params, &bp->link_vars);
 +
 +              bnx2x_release_phy_lock(bp);
 +
 +              bnx2x_calc_fc_adv(bp);
 +
 +              if (CHIP_REV_IS_SLOW(bp) && bp->link_vars.link_up) {
 +                      bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
 +                      bnx2x_link_report(bp);
 +              } else
 +                      queue_delayed_work(bnx2x_wq, &bp->period_task, 0);
 +              bp->link_params.req_line_speed[cfx_idx] = req_line_speed;
 +              return rc;
 +      }
 +      BNX2X_ERR("Bootcode is missing - can not initialize link\n");
 +      return -EINVAL;
 +}
 +
 +void bnx2x_link_set(struct bnx2x *bp)
 +{
 +      if (!BP_NOMCP(bp)) {
 +              bnx2x_acquire_phy_lock(bp);
 +              bnx2x_link_reset(&bp->link_params, &bp->link_vars, 1);
 +              bnx2x_phy_init(&bp->link_params, &bp->link_vars);
 +              bnx2x_release_phy_lock(bp);
 +
 +              bnx2x_calc_fc_adv(bp);
 +      } else
 +              BNX2X_ERR("Bootcode is missing - can not set link\n");
 +}
 +
 +static void bnx2x__link_reset(struct bnx2x *bp)
 +{
 +      if (!BP_NOMCP(bp)) {
 +              bnx2x_acquire_phy_lock(bp);
 +              bnx2x_link_reset(&bp->link_params, &bp->link_vars, 1);
 +              bnx2x_release_phy_lock(bp);
 +      } else
 +              BNX2X_ERR("Bootcode is missing - can not reset link\n");
 +}
 +
 +u8 bnx2x_link_test(struct bnx2x *bp, u8 is_serdes)
 +{
 +      u8 rc = 0;
 +
 +      if (!BP_NOMCP(bp)) {
 +              bnx2x_acquire_phy_lock(bp);
 +              rc = bnx2x_test_link(&bp->link_params, &bp->link_vars,
 +                                   is_serdes);
 +              bnx2x_release_phy_lock(bp);
 +      } else
 +              BNX2X_ERR("Bootcode is missing - can not test link\n");
 +
 +      return rc;
 +}
 +
 +static void bnx2x_init_port_minmax(struct bnx2x *bp)
 +{
 +      u32 r_param = bp->link_vars.line_speed / 8;
 +      u32 fair_periodic_timeout_usec;
 +      u32 t_fair;
 +
 +      memset(&(bp->cmng.rs_vars), 0,
 +             sizeof(struct rate_shaping_vars_per_port));
 +      memset(&(bp->cmng.fair_vars), 0, sizeof(struct fairness_vars_per_port));
 +
 +      /* 100 usec in SDM ticks = 25 since each tick is 4 usec */
 +      bp->cmng.rs_vars.rs_periodic_timeout = RS_PERIODIC_TIMEOUT_USEC / 4;
 +
 +      /* this is the threshold below which no timer arming will occur
 +         1.25 coefficient is for the threshold to be a little bigger
 +         than the real time, to compensate for timer in-accuracy */
 +      bp->cmng.rs_vars.rs_threshold =
 +                              (RS_PERIODIC_TIMEOUT_USEC * r_param * 5) / 4;
 +
 +      /* resolution of fairness timer */
 +      fair_periodic_timeout_usec = QM_ARB_BYTES / r_param;
 +      /* for 10G it is 1000usec. for 1G it is 10000usec. */
 +      t_fair = T_FAIR_COEF / bp->link_vars.line_speed;
 +
 +      /* this is the threshold below which we won't arm the timer anymore */
 +      bp->cmng.fair_vars.fair_threshold = QM_ARB_BYTES;
 +
 +      /* we multiply by 1e3/8 to get bytes/msec.
 +         We don't want the credits to pass a credit
 +         of the t_fair*FAIR_MEM (algorithm resolution) */
 +      bp->cmng.fair_vars.upper_bound = r_param * t_fair * FAIR_MEM;
 +      /* since each tick is 4 usec */
 +      bp->cmng.fair_vars.fairness_timeout = fair_periodic_timeout_usec / 4;
 +}
 +
 +/* Calculates the sum of vn_min_rates.
 +   It's needed for further normalizing of the min_rates.
 +   Returns:
 +     sum of vn_min_rates.
 +       or
 +     0 - if all the min_rates are 0.
 +     In the later case fainess algorithm should be deactivated.
 +     If not all min_rates are zero then those that are zeroes will be set to 1.
 + */
 +static void bnx2x_calc_vn_weight_sum(struct bnx2x *bp)
 +{
 +      int all_zero = 1;
 +      int vn;
 +
 +      bp->vn_weight_sum = 0;
 +      for (vn = VN_0; vn < BP_MAX_VN_NUM(bp); vn++) {
 +              u32 vn_cfg = bp->mf_config[vn];
 +              u32 vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >>
 +                                 FUNC_MF_CFG_MIN_BW_SHIFT) * 100;
 +
 +              /* Skip hidden vns */
 +              if (vn_cfg & FUNC_MF_CFG_FUNC_HIDE)
 +                      continue;
 +
 +              /* If min rate is zero - set it to 1 */
 +              if (!vn_min_rate)
 +                      vn_min_rate = DEF_MIN_RATE;
 +              else
 +                      all_zero = 0;
 +
 +              bp->vn_weight_sum += vn_min_rate;
 +      }
 +
 +      /* if ETS or all min rates are zeros - disable fairness */
 +      if (BNX2X_IS_ETS_ENABLED(bp)) {
 +              bp->cmng.flags.cmng_enables &=
 +                                      ~CMNG_FLAGS_PER_PORT_FAIRNESS_VN;
 +              DP(NETIF_MSG_IFUP, "Fairness will be disabled due to ETS\n");
 +      } else if (all_zero) {
 +              bp->cmng.flags.cmng_enables &=
 +                                      ~CMNG_FLAGS_PER_PORT_FAIRNESS_VN;
 +              DP(NETIF_MSG_IFUP, "All MIN values are zeroes"
 +                 "  fairness will be disabled\n");
 +      } else
 +              bp->cmng.flags.cmng_enables |=
 +                                      CMNG_FLAGS_PER_PORT_FAIRNESS_VN;
 +}
 +
 +/* returns func by VN for current port */
 +static inline int func_by_vn(struct bnx2x *bp, int vn)
 +{
 +      return 2 * vn + BP_PORT(bp);
 +}
 +
 +static void bnx2x_init_vn_minmax(struct bnx2x *bp, int vn)
 +{
 +      struct rate_shaping_vars_per_vn m_rs_vn;
 +      struct fairness_vars_per_vn m_fair_vn;
 +      u32 vn_cfg = bp->mf_config[vn];
 +      int func = func_by_vn(bp, vn);
 +      u16 vn_min_rate, vn_max_rate;
 +      int i;
 +
 +      /* If function is hidden - set min and max to zeroes */
 +      if (vn_cfg & FUNC_MF_CFG_FUNC_HIDE) {
 +              vn_min_rate = 0;
 +              vn_max_rate = 0;
 +
 +      } else {
 +              u32 maxCfg = bnx2x_extract_max_cfg(bp, vn_cfg);
 +
 +              vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >>
 +                              FUNC_MF_CFG_MIN_BW_SHIFT) * 100;
 +              /* If fairness is enabled (not all min rates are zeroes) and
 +                 if current min rate is zero - set it to 1.
 +                 This is a requirement of the algorithm. */
 +              if (bp->vn_weight_sum && (vn_min_rate == 0))
 +                      vn_min_rate = DEF_MIN_RATE;
 +
 +              if (IS_MF_SI(bp))
 +                      /* maxCfg in percents of linkspeed */
 +                      vn_max_rate = (bp->link_vars.line_speed * maxCfg) / 100;
 +              else
 +                      /* maxCfg is absolute in 100Mb units */
 +                      vn_max_rate = maxCfg * 100;
 +      }
 +
 +      DP(NETIF_MSG_IFUP,
 +         "func %d: vn_min_rate %d  vn_max_rate %d  vn_weight_sum %d\n",
 +         func, vn_min_rate, vn_max_rate, bp->vn_weight_sum);
 +
 +      memset(&m_rs_vn, 0, sizeof(struct rate_shaping_vars_per_vn));
 +      memset(&m_fair_vn, 0, sizeof(struct fairness_vars_per_vn));
 +
 +      /* global vn counter - maximal Mbps for this vn */
 +      m_rs_vn.vn_counter.rate = vn_max_rate;
 +
 +      /* quota - number of bytes transmitted in this period */
 +      m_rs_vn.vn_counter.quota =
 +                              (vn_max_rate * RS_PERIODIC_TIMEOUT_USEC) / 8;
 +
 +      if (bp->vn_weight_sum) {
 +              /* credit for each period of the fairness algorithm:
 +                 number of bytes in T_FAIR (the vn share the port rate).
 +                 vn_weight_sum should not be larger than 10000, thus
 +                 T_FAIR_COEF / (8 * vn_weight_sum) will always be greater
 +                 than zero */
 +              m_fair_vn.vn_credit_delta =
 +                      max_t(u32, (vn_min_rate * (T_FAIR_COEF /
 +                                                 (8 * bp->vn_weight_sum))),
 +                            (bp->cmng.fair_vars.fair_threshold +
 +                                                      MIN_ABOVE_THRESH));
 +              DP(NETIF_MSG_IFUP, "m_fair_vn.vn_credit_delta %d\n",
 +                 m_fair_vn.vn_credit_delta);
 +      }
 +
 +      /* Store it to internal memory */
 +      for (i = 0; i < sizeof(struct rate_shaping_vars_per_vn)/4; i++)
 +              REG_WR(bp, BAR_XSTRORM_INTMEM +
 +                     XSTORM_RATE_SHAPING_PER_VN_VARS_OFFSET(func) + i * 4,
 +                     ((u32 *)(&m_rs_vn))[i]);
 +
 +      for (i = 0; i < sizeof(struct fairness_vars_per_vn)/4; i++)
 +              REG_WR(bp, BAR_XSTRORM_INTMEM +
 +                     XSTORM_FAIRNESS_PER_VN_VARS_OFFSET(func) + i * 4,
 +                     ((u32 *)(&m_fair_vn))[i]);
 +}
 +
 +static int bnx2x_get_cmng_fns_mode(struct bnx2x *bp)
 +{
 +      if (CHIP_REV_IS_SLOW(bp))
 +              return CMNG_FNS_NONE;
 +      if (IS_MF(bp))
 +              return CMNG_FNS_MINMAX;
 +
 +      return CMNG_FNS_NONE;
 +}
 +
 +void bnx2x_read_mf_cfg(struct bnx2x *bp)
 +{
 +      int vn, n = (CHIP_MODE_IS_4_PORT(bp) ? 2 : 1);
 +
 +      if (BP_NOMCP(bp))
 +              return; /* what should be the default bvalue in this case */
 +
 +      /* For 2 port configuration the absolute function number formula
 +       * is:
 +       *      abs_func = 2 * vn + BP_PORT + BP_PATH
 +       *
 +       *      and there are 4 functions per port
 +       *
 +       * For 4 port configuration it is
 +       *      abs_func = 4 * vn + 2 * BP_PORT + BP_PATH
 +       *
 +       *      and there are 2 functions per port
 +       */
 +      for (vn = VN_0; vn < BP_MAX_VN_NUM(bp); vn++) {
 +              int /*abs*/func = n * (2 * vn + BP_PORT(bp)) + BP_PATH(bp);
 +
 +              if (func >= E1H_FUNC_MAX)
 +                      break;
 +
 +              bp->mf_config[vn] =
 +                      MF_CFG_RD(bp, func_mf_config[func].config);
 +      }
 +}
 +
 +static void bnx2x_cmng_fns_init(struct bnx2x *bp, u8 read_cfg, u8 cmng_type)
 +{
 +
 +      if (cmng_type == CMNG_FNS_MINMAX) {
 +              int vn;
 +
 +              /* clear cmng_enables */
 +              bp->cmng.flags.cmng_enables = 0;
 +
 +              /* read mf conf from shmem */
 +              if (read_cfg)
 +                      bnx2x_read_mf_cfg(bp);
 +
 +              /* Init rate shaping and fairness contexts */
 +              bnx2x_init_port_minmax(bp);
 +
 +              /* vn_weight_sum and enable fairness if not 0 */
 +              bnx2x_calc_vn_weight_sum(bp);
 +
 +              /* calculate and set min-max rate for each vn */
 +              if (bp->port.pmf)
 +                      for (vn = VN_0; vn < BP_MAX_VN_NUM(bp); vn++)
 +                              bnx2x_init_vn_minmax(bp, vn);
 +
 +              /* always enable rate shaping and fairness */
 +              bp->cmng.flags.cmng_enables |=
 +                                      CMNG_FLAGS_PER_PORT_RATE_SHAPING_VN;
 +              if (!bp->vn_weight_sum)
 +                      DP(NETIF_MSG_IFUP, "All MIN values are zeroes"
 +                                 "  fairness will be disabled\n");
 +              return;
 +      }
 +
 +      /* rate shaping and fairness are disabled */
 +      DP(NETIF_MSG_IFUP,
 +         "rate shaping and fairness are disabled\n");
 +}
 +
 +static inline void bnx2x_link_sync_notify(struct bnx2x *bp)
 +{
 +      int func;
 +      int vn;
 +
 +      /* Set the attention towards other drivers on the same port */
 +      for (vn = VN_0; vn < BP_MAX_VN_NUM(bp); vn++) {
 +              if (vn == BP_VN(bp))
 +                      continue;
 +
 +              func = func_by_vn(bp, vn);
 +              REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_0 +
 +                     (LINK_SYNC_ATTENTION_BIT_FUNC_0 + func)*4, 1);
 +      }
 +}
 +
 +/* This function is called upon link interrupt */
 +static void bnx2x_link_attn(struct bnx2x *bp)
 +{
 +      /* Make sure that we are synced with the current statistics */
 +      bnx2x_stats_handle(bp, STATS_EVENT_STOP);
 +
 +      bnx2x_link_update(&bp->link_params, &bp->link_vars);
 +
 +      if (bp->link_vars.link_up) {
 +
 +              /* dropless flow control */
 +              if (!CHIP_IS_E1(bp) && bp->dropless_fc) {
 +                      int port = BP_PORT(bp);
 +                      u32 pause_enabled = 0;
 +
 +                      if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX)
 +                              pause_enabled = 1;
 +
 +                      REG_WR(bp, BAR_USTRORM_INTMEM +
 +                             USTORM_ETH_PAUSE_ENABLED_OFFSET(port),
 +                             pause_enabled);
 +              }
 +
 +              if (bp->link_vars.mac_type != MAC_TYPE_EMAC) {
 +                      struct host_port_stats *pstats;
 +
 +                      pstats = bnx2x_sp(bp, port_stats);
 +                      /* reset old mac stats */
 +                      memset(&(pstats->mac_stx[0]), 0,
 +                             sizeof(struct mac_stx));
 +              }
 +              if (bp->state == BNX2X_STATE_OPEN)
 +                      bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
 +      }
 +
 +      if (bp->link_vars.link_up && bp->link_vars.line_speed) {
 +              int cmng_fns = bnx2x_get_cmng_fns_mode(bp);
 +
 +              if (cmng_fns != CMNG_FNS_NONE) {
 +                      bnx2x_cmng_fns_init(bp, false, cmng_fns);
 +                      storm_memset_cmng(bp, &bp->cmng, BP_PORT(bp));
 +              } else
 +                      /* rate shaping and fairness are disabled */
 +                      DP(NETIF_MSG_IFUP,
 +                         "single function mode without fairness\n");
 +      }
 +
 +      __bnx2x_link_report(bp);
 +
 +      if (IS_MF(bp))
 +              bnx2x_link_sync_notify(bp);
 +}
 +
 +void bnx2x__link_status_update(struct bnx2x *bp)
 +{
 +      if (bp->state != BNX2X_STATE_OPEN)
 +              return;
 +
 +      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);
 +}
 +
 +static void bnx2x_pmf_update(struct bnx2x *bp)
 +{
 +      int port = BP_PORT(bp);
 +      u32 val;
 +
 +      bp->port.pmf = 1;
 +      DP(NETIF_MSG_LINK, "pmf %d\n", bp->port.pmf);
 +
 +      /*
 +       * We need the mb() to ensure the ordering between the writing to
 +       * bp->port.pmf here and reading it from the bnx2x_periodic_task().
 +       */
 +      smp_mb();
 +
 +      /* queue a periodic task */
 +      queue_delayed_work(bnx2x_wq, &bp->period_task, 0);
 +
 +      bnx2x_dcbx_pmf_update(bp);
 +
 +      /* enable nig attention */
 +      val = (0xff0f | (1 << (BP_VN(bp) + 4)));
 +      if (bp->common.int_block == INT_BLOCK_HC) {
 +              REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, val);
 +              REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, val);
 +      } else if (!CHIP_IS_E1x(bp)) {
 +              REG_WR(bp, IGU_REG_TRAILING_EDGE_LATCH, val);
 +              REG_WR(bp, IGU_REG_LEADING_EDGE_LATCH, val);
 +      }
 +
 +      bnx2x_stats_handle(bp, STATS_EVENT_PMF);
 +}
 +
 +/* end of Link */
 +
 +/* slow path */
 +
 +/*
 + * General service functions
 + */
 +
 +/* send the MCP a request, block until there is a reply */
 +u32 bnx2x_fw_command(struct bnx2x *bp, u32 command, u32 param)
 +{
 +      int mb_idx = BP_FW_MB_IDX(bp);
 +      u32 seq;
 +      u32 rc = 0;
 +      u32 cnt = 1;
 +      u8 delay = CHIP_REV_IS_SLOW(bp) ? 100 : 10;
 +
 +      mutex_lock(&bp->fw_mb_mutex);
 +      seq = ++bp->fw_seq;
 +      SHMEM_WR(bp, func_mb[mb_idx].drv_mb_param, param);
 +      SHMEM_WR(bp, func_mb[mb_idx].drv_mb_header, (command | seq));
 +
 +      DP(BNX2X_MSG_MCP, "wrote command (%x) to FW MB param 0x%08x\n",
 +                      (command | seq), param);
 +
 +      do {
 +              /* let the FW do it's magic ... */
 +              msleep(delay);
 +
 +              rc = SHMEM_RD(bp, func_mb[mb_idx].fw_mb_header);
 +
 +              /* Give the FW up to 5 second (500*10ms) */
 +      } while ((seq != (rc & FW_MSG_SEQ_NUMBER_MASK)) && (cnt++ < 500));
 +
 +      DP(BNX2X_MSG_MCP, "[after %d ms] read (%x) seq is (%x) from FW MB\n",
 +         cnt*delay, rc, seq);
 +
 +      /* is this a reply to our command? */
 +      if (seq == (rc & FW_MSG_SEQ_NUMBER_MASK))
 +              rc &= FW_MSG_CODE_MASK;
 +      else {
 +              /* FW BUG! */
 +              BNX2X_ERR("FW failed to respond!\n");
 +              bnx2x_fw_dump(bp);
 +              rc = 0;
 +      }
 +      mutex_unlock(&bp->fw_mb_mutex);
 +
 +      return rc;
 +}
 +
 +static u8 stat_counter_valid(struct bnx2x *bp, struct bnx2x_fastpath *fp)
 +{
 +#ifdef BCM_CNIC
 +      /* Statistics are not supported for CNIC Clients at the moment */
 +      if (IS_FCOE_FP(fp))
 +              return false;
 +#endif
 +      return true;
 +}
 +
 +void bnx2x_func_init(struct bnx2x *bp, struct bnx2x_func_init_params *p)
 +{
 +      if (CHIP_IS_E1x(bp)) {
 +              struct tstorm_eth_function_common_config tcfg = {0};
 +
 +              storm_memset_func_cfg(bp, &tcfg, p->func_id);
 +      }
 +
 +      /* Enable the function in the FW */
 +      storm_memset_vf_to_pf(bp, p->func_id, p->pf_id);
 +      storm_memset_func_en(bp, p->func_id, 1);
 +
 +      /* spq */
 +      if (p->func_flgs & FUNC_FLG_SPQ) {
 +              storm_memset_spq_addr(bp, p->spq_map, p->func_id);
 +              REG_WR(bp, XSEM_REG_FAST_MEMORY +
 +                     XSTORM_SPQ_PROD_OFFSET(p->func_id), p->spq_prod);
 +      }
 +}
 +
 +/**
 + * bnx2x_get_tx_only_flags - Return common flags
 + *
 + * @bp                device handle
 + * @fp                queue handle
 + * @zero_stats        TRUE if statistics zeroing is needed
 + *
 + * Return the flags that are common for the Tx-only and not normal connections.
 + */
 +static inline unsigned long bnx2x_get_common_flags(struct bnx2x *bp,
 +                                                 struct bnx2x_fastpath *fp,
 +                                                 bool zero_stats)
 +{
 +      unsigned long flags = 0;
 +
 +      /* PF driver will always initialize the Queue to an ACTIVE state */
 +      __set_bit(BNX2X_Q_FLG_ACTIVE, &flags);
 +
 +      /* tx only connections collect statistics (on the same index as the
 +       *  parent connection). The statistics are zeroed when the parent
 +       *  connection is initialized.
 +       */
 +      if (stat_counter_valid(bp, fp)) {
 +              __set_bit(BNX2X_Q_FLG_STATS, &flags);
 +              if (zero_stats)
 +                      __set_bit(BNX2X_Q_FLG_ZERO_STATS, &flags);
 +      }
 +
 +      return flags;
 +}
 +
 +static inline unsigned long bnx2x_get_q_flags(struct bnx2x *bp,
 +                                            struct bnx2x_fastpath *fp,
 +                                            bool leading)
 +{
 +      unsigned long flags = 0;
 +
 +      /* calculate other queue flags */
 +      if (IS_MF_SD(bp))
 +              __set_bit(BNX2X_Q_FLG_OV, &flags);
 +
 +      if (IS_FCOE_FP(fp))
 +              __set_bit(BNX2X_Q_FLG_FCOE, &flags);
 +
 +      if (!fp->disable_tpa) {
 +              __set_bit(BNX2X_Q_FLG_TPA, &flags);
 +              __set_bit(BNX2X_Q_FLG_TPA_IPV6, &flags);
 +      }
 +
 +      if (leading) {
 +              __set_bit(BNX2X_Q_FLG_LEADING_RSS, &flags);
 +              __set_bit(BNX2X_Q_FLG_MCAST, &flags);
 +      }
 +
 +      /* Always set HW VLAN stripping */
 +      __set_bit(BNX2X_Q_FLG_VLAN, &flags);
 +
 +
 +      return flags | bnx2x_get_common_flags(bp, fp, true);
 +}
 +
 +static void bnx2x_pf_q_prep_general(struct bnx2x *bp,
 +      struct bnx2x_fastpath *fp, struct bnx2x_general_setup_params *gen_init,
 +      u8 cos)
 +{
 +      gen_init->stat_id = bnx2x_stats_id(fp);
 +      gen_init->spcl_id = fp->cl_id;
 +
 +      /* Always use mini-jumbo MTU for FCoE L2 ring */
 +      if (IS_FCOE_FP(fp))
 +              gen_init->mtu = BNX2X_FCOE_MINI_JUMBO_MTU;
 +      else
 +              gen_init->mtu = bp->dev->mtu;
 +
 +      gen_init->cos = cos;
 +}
 +
 +static void bnx2x_pf_rx_q_prep(struct bnx2x *bp,
 +      struct bnx2x_fastpath *fp, struct rxq_pause_params *pause,
 +      struct bnx2x_rxq_setup_params *rxq_init)
 +{
 +      u8 max_sge = 0;
 +      u16 sge_sz = 0;
 +      u16 tpa_agg_size = 0;
 +
 +      if (!fp->disable_tpa) {
 +              pause->sge_th_lo = SGE_TH_LO(bp);
 +              pause->sge_th_hi = SGE_TH_HI(bp);
 +
 +              /* validate SGE ring has enough to cross high threshold */
 +              WARN_ON(bp->dropless_fc &&
 +                              pause->sge_th_hi + FW_PREFETCH_CNT >
 +                              MAX_RX_SGE_CNT * NUM_RX_SGE_PAGES);
 +
 +              tpa_agg_size = min_t(u32,
 +                      (min_t(u32, 8, MAX_SKB_FRAGS) *
 +                      SGE_PAGE_SIZE * PAGES_PER_SGE), 0xffff);
 +              max_sge = SGE_PAGE_ALIGN(bp->dev->mtu) >>
 +                      SGE_PAGE_SHIFT;
 +              max_sge = ((max_sge + PAGES_PER_SGE - 1) &
 +                        (~(PAGES_PER_SGE-1))) >> PAGES_PER_SGE_SHIFT;
 +              sge_sz = (u16)min_t(u32, SGE_PAGE_SIZE * PAGES_PER_SGE,
 +                                  0xffff);
 +      }
 +
 +      /* pause - not for e1 */
 +      if (!CHIP_IS_E1(bp)) {
 +              pause->bd_th_lo = BD_TH_LO(bp);
 +              pause->bd_th_hi = BD_TH_HI(bp);
 +
 +              pause->rcq_th_lo = RCQ_TH_LO(bp);
 +              pause->rcq_th_hi = RCQ_TH_HI(bp);
 +              /*
 +               * validate that rings have enough entries to cross
 +               * high thresholds
 +               */
 +              WARN_ON(bp->dropless_fc &&
 +                              pause->bd_th_hi + FW_PREFETCH_CNT >
 +                              bp->rx_ring_size);
 +              WARN_ON(bp->dropless_fc &&
 +                              pause->rcq_th_hi + FW_PREFETCH_CNT >
 +                              NUM_RCQ_RINGS * MAX_RCQ_DESC_CNT);
 +
 +              pause->pri_map = 1;
 +      }
 +
 +      /* rxq setup */
 +      rxq_init->dscr_map = fp->rx_desc_mapping;
 +      rxq_init->sge_map = fp->rx_sge_mapping;
 +      rxq_init->rcq_map = fp->rx_comp_mapping;
 +      rxq_init->rcq_np_map = fp->rx_comp_mapping + BCM_PAGE_SIZE;
 +
 +      /* This should be a maximum number of data bytes that may be
 +       * placed on the BD (not including paddings).
 +       */
 +      rxq_init->buf_sz = fp->rx_buf_size - BNX2X_FW_RX_ALIGN -
 +              IP_HEADER_ALIGNMENT_PADDING;
 +
 +      rxq_init->cl_qzone_id = fp->cl_qzone_id;
 +      rxq_init->tpa_agg_sz = tpa_agg_size;
 +      rxq_init->sge_buf_sz = sge_sz;
 +      rxq_init->max_sges_pkt = max_sge;
 +      rxq_init->rss_engine_id = BP_FUNC(bp);
 +
 +      /* Maximum number or simultaneous TPA aggregation for this Queue.
 +       *
 +       * For PF Clients it should be the maximum avaliable number.
 +       * VF driver(s) may want to define it to a smaller value.
 +       */
 +      rxq_init->max_tpa_queues = MAX_AGG_QS(bp);
 +
 +      rxq_init->cache_line_log = BNX2X_RX_ALIGN_SHIFT;
 +      rxq_init->fw_sb_id = fp->fw_sb_id;
 +
 +      if (IS_FCOE_FP(fp))
 +              rxq_init->sb_cq_index = HC_SP_INDEX_ETH_FCOE_RX_CQ_CONS;
 +      else
 +              rxq_init->sb_cq_index = HC_INDEX_ETH_RX_CQ_CONS;
 +}
 +
 +static void bnx2x_pf_tx_q_prep(struct bnx2x *bp,
 +      struct bnx2x_fastpath *fp, struct bnx2x_txq_setup_params *txq_init,
 +      u8 cos)
 +{
 +      txq_init->dscr_map = fp->txdata[cos].tx_desc_mapping;
 +      txq_init->sb_cq_index = HC_INDEX_ETH_FIRST_TX_CQ_CONS + cos;
 +      txq_init->traffic_type = LLFC_TRAFFIC_TYPE_NW;
 +      txq_init->fw_sb_id = fp->fw_sb_id;
 +
 +      /*
 +       * set the tss leading client id for TX classfication ==
 +       * leading RSS client id
 +       */
 +      txq_init->tss_leading_cl_id = bnx2x_fp(bp, 0, cl_id);
 +
 +      if (IS_FCOE_FP(fp)) {
 +              txq_init->sb_cq_index = HC_SP_INDEX_ETH_FCOE_TX_CQ_CONS;
 +              txq_init->traffic_type = LLFC_TRAFFIC_TYPE_FCOE;
 +      }
 +}
 +
 +static void bnx2x_pf_init(struct bnx2x *bp)
 +{
 +      struct bnx2x_func_init_params func_init = {0};
 +      struct event_ring_data eq_data = { {0} };
 +      u16 flags;
 +
 +      if (!CHIP_IS_E1x(bp)) {
 +              /* reset IGU PF statistics: MSIX + ATTN */
 +              /* PF */
 +              REG_WR(bp, IGU_REG_STATISTIC_NUM_MESSAGE_SENT +
 +                         BNX2X_IGU_STAS_MSG_VF_CNT*4 +
 +                         (CHIP_MODE_IS_4_PORT(bp) ?
 +                              BP_FUNC(bp) : BP_VN(bp))*4, 0);
 +              /* ATTN */
 +              REG_WR(bp, IGU_REG_STATISTIC_NUM_MESSAGE_SENT +
 +                         BNX2X_IGU_STAS_MSG_VF_CNT*4 +
 +                         BNX2X_IGU_STAS_MSG_PF_CNT*4 +
 +                         (CHIP_MODE_IS_4_PORT(bp) ?
 +                              BP_FUNC(bp) : BP_VN(bp))*4, 0);
 +      }
 +
 +      /* function setup flags */
 +      flags = (FUNC_FLG_STATS | FUNC_FLG_LEADING | FUNC_FLG_SPQ);
 +
 +      /* This flag is relevant for E1x only.
 +       * E2 doesn't have a TPA configuration in a function level.
 +       */
 +      flags |= (bp->flags & TPA_ENABLE_FLAG) ? FUNC_FLG_TPA : 0;
 +
 +      func_init.func_flgs = flags;
 +      func_init.pf_id = BP_FUNC(bp);
 +      func_init.func_id = BP_FUNC(bp);
 +      func_init.spq_map = bp->spq_mapping;
 +      func_init.spq_prod = bp->spq_prod_idx;
 +
 +      bnx2x_func_init(bp, &func_init);
 +
 +      memset(&(bp->cmng), 0, sizeof(struct cmng_struct_per_port));
 +
 +      /*
 +       * Congestion management values depend on the link rate
 +       * There is no active link so initial link rate is set to 10 Gbps.
 +       * When the link comes up The congestion management values are
 +       * re-calculated according to the actual link rate.
 +       */
 +      bp->link_vars.line_speed = SPEED_10000;
 +      bnx2x_cmng_fns_init(bp, true, bnx2x_get_cmng_fns_mode(bp));
 +
 +      /* Only the PMF sets the HW */
 +      if (bp->port.pmf)
 +              storm_memset_cmng(bp, &bp->cmng, BP_PORT(bp));
 +
 +      /* init Event Queue */
 +      eq_data.base_addr.hi = U64_HI(bp->eq_mapping);
 +      eq_data.base_addr.lo = U64_LO(bp->eq_mapping);
 +      eq_data.producer = bp->eq_prod;
 +      eq_data.index_id = HC_SP_INDEX_EQ_CONS;
 +      eq_data.sb_id = DEF_SB_ID;
 +      storm_memset_eq_data(bp, &eq_data, BP_FUNC(bp));
 +}
 +
 +
 +static void bnx2x_e1h_disable(struct bnx2x *bp)
 +{
 +      int port = BP_PORT(bp);
 +
 +      bnx2x_tx_disable(bp);
 +
 +      REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 0);
 +}
 +
 +static void bnx2x_e1h_enable(struct bnx2x *bp)
 +{
 +      int port = BP_PORT(bp);
 +
 +      REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 1);
 +
 +      /* Tx queue should be only reenabled */
 +      netif_tx_wake_all_queues(bp->dev);
 +
 +      /*
 +       * Should not call netif_carrier_on since it will be called if the link
 +       * is up when checking for link state
 +       */
 +}
 +
 +/* called due to MCP event (on pmf):
 + *    reread new bandwidth configuration
 + *    configure FW
 + *    notify others function about the change
 + */
 +static inline void bnx2x_config_mf_bw(struct bnx2x *bp)
 +{
 +      if (bp->link_vars.link_up) {
 +              bnx2x_cmng_fns_init(bp, true, CMNG_FNS_MINMAX);
 +              bnx2x_link_sync_notify(bp);
 +      }
 +      storm_memset_cmng(bp, &bp->cmng, BP_PORT(bp));
 +}
 +
 +static inline void bnx2x_set_mf_bw(struct bnx2x *bp)
 +{
 +      bnx2x_config_mf_bw(bp);
 +      bnx2x_fw_command(bp, DRV_MSG_CODE_SET_MF_BW_ACK, 0);
 +}
 +
 +static void bnx2x_dcc_event(struct bnx2x *bp, u32 dcc_event)
 +{
 +      DP(BNX2X_MSG_MCP, "dcc_event 0x%x\n", dcc_event);
 +
 +      if (dcc_event & DRV_STATUS_DCC_DISABLE_ENABLE_PF) {
 +
 +              /*
 +               * This is the only place besides the function initialization
 +               * where the bp->flags can change so it is done without any
 +               * locks
 +               */
 +              if (bp->mf_config[BP_VN(bp)] & FUNC_MF_CFG_FUNC_DISABLED) {
 +                      DP(NETIF_MSG_IFDOWN, "mf_cfg function disabled\n");
 +                      bp->flags |= MF_FUNC_DIS;
 +
 +                      bnx2x_e1h_disable(bp);
 +              } else {
 +                      DP(NETIF_MSG_IFUP, "mf_cfg function enabled\n");
 +                      bp->flags &= ~MF_FUNC_DIS;
 +
 +                      bnx2x_e1h_enable(bp);
 +              }
 +              dcc_event &= ~DRV_STATUS_DCC_DISABLE_ENABLE_PF;
 +      }
 +      if (dcc_event & DRV_STATUS_DCC_BANDWIDTH_ALLOCATION) {
 +              bnx2x_config_mf_bw(bp);
 +              dcc_event &= ~DRV_STATUS_DCC_BANDWIDTH_ALLOCATION;
 +      }
 +
 +      /* Report results to MCP */
 +      if (dcc_event)
 +              bnx2x_fw_command(bp, DRV_MSG_CODE_DCC_FAILURE, 0);
 +      else
 +              bnx2x_fw_command(bp, DRV_MSG_CODE_DCC_OK, 0);
 +}
 +
 +/* must be called under the spq lock */
 +static inline struct eth_spe *bnx2x_sp_get_next(struct bnx2x *bp)
 +{
 +      struct eth_spe *next_spe = bp->spq_prod_bd;
 +
 +      if (bp->spq_prod_bd == bp->spq_last_bd) {
 +              bp->spq_prod_bd = bp->spq;
 +              bp->spq_prod_idx = 0;
 +              DP(NETIF_MSG_TIMER, "end of spq\n");
 +      } else {
 +              bp->spq_prod_bd++;
 +              bp->spq_prod_idx++;
 +      }
 +      return next_spe;
 +}
 +
 +/* must be called under the spq lock */
 +static inline void bnx2x_sp_prod_update(struct bnx2x *bp)
 +{
 +      int func = BP_FUNC(bp);
 +
 +      /*
 +       * Make sure that BD data is updated before writing the producer:
 +       * BD data is written to the memory, the producer is read from the
 +       * memory, thus we need a full memory barrier to ensure the ordering.
 +       */
 +      mb();
 +
 +      REG_WR16(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PROD_OFFSET(func),
 +               bp->spq_prod_idx);
 +      mmiowb();
 +}
 +
 +/**
 + * bnx2x_is_contextless_ramrod - check if the current command ends on EQ
 + *
 + * @cmd:      command to check
 + * @cmd_type: command type
 + */
 +static inline bool bnx2x_is_contextless_ramrod(int cmd, int cmd_type)
 +{
 +      if ((cmd_type == NONE_CONNECTION_TYPE) ||
 +          (cmd == RAMROD_CMD_ID_ETH_FORWARD_SETUP) ||
 +          (cmd == RAMROD_CMD_ID_ETH_CLASSIFICATION_RULES) ||
 +          (cmd == RAMROD_CMD_ID_ETH_FILTER_RULES) ||
 +          (cmd == RAMROD_CMD_ID_ETH_MULTICAST_RULES) ||
 +          (cmd == RAMROD_CMD_ID_ETH_SET_MAC) ||
 +          (cmd == RAMROD_CMD_ID_ETH_RSS_UPDATE))
 +              return true;
 +      else
 +              return false;
 +
 +}
 +
 +
 +/**
 + * bnx2x_sp_post - place a single command on an SP ring
 + *
 + * @bp:               driver handle
 + * @command:  command to place (e.g. SETUP, FILTER_RULES, etc.)
 + * @cid:      SW CID the command is related to
 + * @data_hi:  command private data address (high 32 bits)
 + * @data_lo:  command private data address (low 32 bits)
 + * @cmd_type: command type (e.g. NONE, ETH)
 + *
 + * SP data is handled as if it's always an address pair, thus data fields are
 + * not swapped to little endian in upper functions. Instead this function swaps
 + * data as if it's two u32 fields.
 + */
 +int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
 +                u32 data_hi, u32 data_lo, int cmd_type)
 +{
 +      struct eth_spe *spe;
 +      u16 type;
 +      bool common = bnx2x_is_contextless_ramrod(command, cmd_type);
 +
 +#ifdef BNX2X_STOP_ON_ERROR
 +      if (unlikely(bp->panic))
 +              return -EIO;
 +#endif
 +
 +      spin_lock_bh(&bp->spq_lock);
 +
 +      if (common) {
 +              if (!atomic_read(&bp->eq_spq_left)) {
 +                      BNX2X_ERR("BUG! EQ ring full!\n");
 +                      spin_unlock_bh(&bp->spq_lock);
 +                      bnx2x_panic();
 +                      return -EBUSY;
 +              }
 +      } else if (!atomic_read(&bp->cq_spq_left)) {
 +                      BNX2X_ERR("BUG! SPQ ring full!\n");
 +                      spin_unlock_bh(&bp->spq_lock);
 +                      bnx2x_panic();
 +                      return -EBUSY;
 +      }
 +
 +      spe = bnx2x_sp_get_next(bp);
 +
 +      /* CID needs port number to be encoded int it */
 +      spe->hdr.conn_and_cmd_data =
 +                      cpu_to_le32((command << SPE_HDR_CMD_ID_SHIFT) |
 +                                  HW_CID(bp, cid));
 +
 +      type = (cmd_type << SPE_HDR_CONN_TYPE_SHIFT) & SPE_HDR_CONN_TYPE;
 +
 +      type |= ((BP_FUNC(bp) << SPE_HDR_FUNCTION_ID_SHIFT) &
 +               SPE_HDR_FUNCTION_ID);
 +
 +      spe->hdr.type = cpu_to_le16(type);
 +
 +      spe->data.update_data_addr.hi = cpu_to_le32(data_hi);
 +      spe->data.update_data_addr.lo = cpu_to_le32(data_lo);
 +
 +      /*
 +       * It's ok if the actual decrement is issued towards the memory
 +       * somewhere between the spin_lock and spin_unlock. Thus no
 +       * more explict memory barrier is needed.
 +       */
 +      if (common)
 +              atomic_dec(&bp->eq_spq_left);
 +      else
 +              atomic_dec(&bp->cq_spq_left);
 +
 +
 +      DP(BNX2X_MSG_SP/*NETIF_MSG_TIMER*/,
 +         "SPQE[%x] (%x:%x)  (cmd, common?) (%d,%d)  hw_cid %x  data (%x:%x) "
 +         "type(0x%x) left (CQ, EQ) (%x,%x)\n",
 +         bp->spq_prod_idx, (u32)U64_HI(bp->spq_mapping),
 +         (u32)(U64_LO(bp->spq_mapping) +
 +         (void *)bp->spq_prod_bd - (void *)bp->spq), command, common,
 +         HW_CID(bp, cid), data_hi, data_lo, type,
 +         atomic_read(&bp->cq_spq_left), atomic_read(&bp->eq_spq_left));
 +
 +      bnx2x_sp_prod_update(bp);
 +      spin_unlock_bh(&bp->spq_lock);
 +      return 0;
 +}
 +
 +/* acquire split MCP access lock register */
 +static int bnx2x_acquire_alr(struct bnx2x *bp)
 +{
 +      u32 j, val;
 +      int rc = 0;
 +
 +      might_sleep();
 +      for (j = 0; j < 1000; j++) {
 +              val = (1UL << 31);
 +              REG_WR(bp, GRCBASE_MCP + 0x9c, val);
 +              val = REG_RD(bp, GRCBASE_MCP + 0x9c);
 +              if (val & (1L << 31))
 +                      break;
 +
 +              msleep(5);
 +      }
 +      if (!(val & (1L << 31))) {
 +              BNX2X_ERR("Cannot acquire MCP access lock register\n");
 +              rc = -EBUSY;
 +      }
 +
 +      return rc;
 +}
 +
 +/* release split MCP access lock register */
 +static void bnx2x_release_alr(struct bnx2x *bp)
 +{
 +      REG_WR(bp, GRCBASE_MCP + 0x9c, 0);
 +}
 +
 +#define BNX2X_DEF_SB_ATT_IDX  0x0001
 +#define BNX2X_DEF_SB_IDX      0x0002
 +
 +static inline u16 bnx2x_update_dsb_idx(struct bnx2x *bp)
 +{
 +      struct host_sp_status_block *def_sb = bp->def_status_blk;
 +      u16 rc = 0;
 +
 +      barrier(); /* status block is written to by the chip */
 +      if (bp->def_att_idx != def_sb->atten_status_block.attn_bits_index) {
 +              bp->def_att_idx = def_sb->atten_status_block.attn_bits_index;
 +              rc |= BNX2X_DEF_SB_ATT_IDX;
 +      }
 +
 +      if (bp->def_idx != def_sb->sp_sb.running_index) {
 +              bp->def_idx = def_sb->sp_sb.running_index;
 +              rc |= BNX2X_DEF_SB_IDX;
 +      }
 +
 +      /* Do not reorder: indecies reading should complete before handling */
 +      barrier();
 +      return rc;
 +}
 +
 +/*
 + * slow path service functions
 + */
 +
 +static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
 +{
 +      int port = BP_PORT(bp);
 +      u32 aeu_addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 :
 +                            MISC_REG_AEU_MASK_ATTN_FUNC_0;
 +      u32 nig_int_mask_addr = port ? NIG_REG_MASK_INTERRUPT_PORT1 :
 +                                     NIG_REG_MASK_INTERRUPT_PORT0;
 +      u32 aeu_mask;
 +      u32 nig_mask = 0;
 +      u32 reg_addr;
 +
 +      if (bp->attn_state & asserted)
 +              BNX2X_ERR("IGU ERROR\n");
 +
 +      bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_PORT0_ATT_MASK + port);
 +      aeu_mask = REG_RD(bp, aeu_addr);
 +
 +      DP(NETIF_MSG_HW, "aeu_mask %x  newly asserted %x\n",
 +         aeu_mask, asserted);
 +      aeu_mask &= ~(asserted & 0x3ff);
 +      DP(NETIF_MSG_HW, "new mask %x\n", aeu_mask);
 +
 +      REG_WR(bp, aeu_addr, aeu_mask);
 +      bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_PORT0_ATT_MASK + port);
 +
 +      DP(NETIF_MSG_HW, "attn_state %x\n", bp->attn_state);
 +      bp->attn_state |= asserted;
 +      DP(NETIF_MSG_HW, "new state %x\n", bp->attn_state);
 +
 +      if (asserted & ATTN_HARD_WIRED_MASK) {
 +              if (asserted & ATTN_NIG_FOR_FUNC) {
 +
 +                      bnx2x_acquire_phy_lock(bp);
 +
 +                      /* save nig interrupt mask */
 +                      nig_mask = REG_RD(bp, nig_int_mask_addr);
 +
 +                      /* If nig_mask is not set, no need to call the update
 +                       * function.
 +                       */
 +                      if (nig_mask) {
 +                              REG_WR(bp, nig_int_mask_addr, 0);
 +
 +                              bnx2x_link_attn(bp);
 +                      }
 +
 +                      /* handle unicore attn? */
 +              }
 +              if (asserted & ATTN_SW_TIMER_4_FUNC)
 +                      DP(NETIF_MSG_HW, "ATTN_SW_TIMER_4_FUNC!\n");
 +
 +              if (asserted & GPIO_2_FUNC)
 +                      DP(NETIF_MSG_HW, "GPIO_2_FUNC!\n");
 +
 +              if (asserted & GPIO_3_FUNC)
 +                      DP(NETIF_MSG_HW, "GPIO_3_FUNC!\n");
 +
 +              if (asserted & GPIO_4_FUNC)
 +                      DP(NETIF_MSG_HW, "GPIO_4_FUNC!\n");
 +
 +              if (port == 0) {
 +                      if (asserted & ATTN_GENERAL_ATTN_1) {
 +                              DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_1!\n");
 +                              REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_1, 0x0);
 +                      }
 +                      if (asserted & ATTN_GENERAL_ATTN_2) {
 +                              DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_2!\n");
 +                              REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_2, 0x0);
 +                      }
 +                      if (asserted & ATTN_GENERAL_ATTN_3) {
 +                              DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_3!\n");
 +                              REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_3, 0x0);
 +                      }
 +              } else {
 +                      if (asserted & ATTN_GENERAL_ATTN_4) {
 +                              DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_4!\n");
 +                              REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_4, 0x0);
 +                      }
 +                      if (asserted & ATTN_GENERAL_ATTN_5) {
 +                              DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_5!\n");
 +                              REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_5, 0x0);
 +                      }
 +                      if (asserted & ATTN_GENERAL_ATTN_6) {
 +                              DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_6!\n");
 +                              REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_6, 0x0);
 +                      }
 +              }
 +
 +      } /* if hardwired */
 +
 +      if (bp->common.int_block == INT_BLOCK_HC)
 +              reg_addr = (HC_REG_COMMAND_REG + port*32 +
 +                          COMMAND_REG_ATTN_BITS_SET);
 +      else
 +              reg_addr = (BAR_IGU_INTMEM + IGU_CMD_ATTN_BIT_SET_UPPER*8);
 +
 +      DP(NETIF_MSG_HW, "about to mask 0x%08x at %s addr 0x%x\n", asserted,
 +         (bp->common.int_block == INT_BLOCK_HC) ? "HC" : "IGU", reg_addr);
 +      REG_WR(bp, reg_addr, asserted);
 +
 +      /* now set back the mask */
 +      if (asserted & ATTN_NIG_FOR_FUNC) {
 +              REG_WR(bp, nig_int_mask_addr, nig_mask);
 +              bnx2x_release_phy_lock(bp);
 +      }
 +}
 +
 +static inline void bnx2x_fan_failure(struct bnx2x *bp)
 +{
 +      int port = BP_PORT(bp);
 +      u32 ext_phy_config;
 +      /* mark the failure */
 +      ext_phy_config =
 +              SHMEM_RD(bp,
 +                       dev_info.port_hw_config[port].external_phy_config);
 +
 +      ext_phy_config &= ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
 +      ext_phy_config |= PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE;
 +      SHMEM_WR(bp, dev_info.port_hw_config[port].external_phy_config,
 +               ext_phy_config);
 +
 +      /* log the failure */
 +      netdev_err(bp->dev, "Fan Failure on Network Controller has caused"
 +             " the driver to shutdown the card to prevent permanent"
 +             " damage.  Please contact OEM Support for assistance\n");
 +}
 +
 +static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
 +{
 +      int port = BP_PORT(bp);
 +      int reg_offset;
 +      u32 val;
 +
 +      reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
 +                           MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
 +
 +      if (attn & AEU_INPUTS_ATTN_BITS_SPIO5) {
 +
 +              val = REG_RD(bp, reg_offset);
 +              val &= ~AEU_INPUTS_ATTN_BITS_SPIO5;
 +              REG_WR(bp, reg_offset, val);
 +
 +              BNX2X_ERR("SPIO5 hw attention\n");
 +
 +              /* Fan failure attention */
 +              bnx2x_hw_reset_phy(&bp->link_params);
 +              bnx2x_fan_failure(bp);
 +      }
 +
 +      if ((attn & bp->link_vars.aeu_int_mask) && bp->port.pmf) {
 +              bnx2x_acquire_phy_lock(bp);
 +              bnx2x_handle_module_detect_int(&bp->link_params);
 +              bnx2x_release_phy_lock(bp);
 +      }
 +
 +      if (attn & HW_INTERRUT_ASSERT_SET_0) {
 +
 +              val = REG_RD(bp, reg_offset);
 +              val &= ~(attn & HW_INTERRUT_ASSERT_SET_0);
 +              REG_WR(bp, reg_offset, val);
 +
 +              BNX2X_ERR("FATAL HW block attention set0 0x%x\n",
 +                        (u32)(attn & HW_INTERRUT_ASSERT_SET_0));
 +              bnx2x_panic();
 +      }
 +}
 +
 +static inline void bnx2x_attn_int_deasserted1(struct bnx2x *bp, u32 attn)
 +{
 +      u32 val;
 +
 +      if (attn & AEU_INPUTS_ATTN_BITS_DOORBELLQ_HW_INTERRUPT) {
 +
 +              val = REG_RD(bp, DORQ_REG_DORQ_INT_STS_CLR);
 +              BNX2X_ERR("DB hw attention 0x%x\n", val);
 +              /* DORQ discard attention */
 +              if (val & 0x2)
 +                      BNX2X_ERR("FATAL error from DORQ\n");
 +      }
 +
 +      if (attn & HW_INTERRUT_ASSERT_SET_1) {
 +
 +              int port = BP_PORT(bp);
 +              int reg_offset;
 +
 +              reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_1 :
 +                                   MISC_REG_AEU_ENABLE1_FUNC_0_OUT_1);
 +
 +              val = REG_RD(bp, reg_offset);
 +              val &= ~(attn & HW_INTERRUT_ASSERT_SET_1);
 +              REG_WR(bp, reg_offset, val);
 +
 +              BNX2X_ERR("FATAL HW block attention set1 0x%x\n",
 +                        (u32)(attn & HW_INTERRUT_ASSERT_SET_1));
 +              bnx2x_panic();
 +      }
 +}
 +
 +static inline void bnx2x_attn_int_deasserted2(struct bnx2x *bp, u32 attn)
 +{
 +      u32 val;
 +
 +      if (attn & AEU_INPUTS_ATTN_BITS_CFC_HW_INTERRUPT) {
 +
 +              val = REG_RD(bp, CFC_REG_CFC_INT_STS_CLR);
 +              BNX2X_ERR("CFC hw attention 0x%x\n", val);
 +              /* CFC error attention */
 +              if (val & 0x2)
 +                      BNX2X_ERR("FATAL error from CFC\n");
 +      }
 +
 +      if (attn & AEU_INPUTS_ATTN_BITS_PXP_HW_INTERRUPT) {
 +              val = REG_RD(bp, PXP_REG_PXP_INT_STS_CLR_0);
 +              BNX2X_ERR("PXP hw attention-0 0x%x\n", val);
 +              /* RQ_USDMDP_FIFO_OVERFLOW */
 +              if (val & 0x18000)
 +                      BNX2X_ERR("FATAL error from PXP\n");
 +
 +              if (!CHIP_IS_E1x(bp)) {
 +                      val = REG_RD(bp, PXP_REG_PXP_INT_STS_CLR_1);
 +                      BNX2X_ERR("PXP hw attention-1 0x%x\n", val);
 +              }
 +      }
 +
 +      if (attn & HW_INTERRUT_ASSERT_SET_2) {
 +
 +              int port = BP_PORT(bp);
 +              int reg_offset;
 +
 +              reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_2 :
 +                                   MISC_REG_AEU_ENABLE1_FUNC_0_OUT_2);
 +
 +              val = REG_RD(bp, reg_offset);
 +              val &= ~(attn & HW_INTERRUT_ASSERT_SET_2);
 +              REG_WR(bp, reg_offset, val);
 +
 +              BNX2X_ERR("FATAL HW block attention set2 0x%x\n",
 +                        (u32)(attn & HW_INTERRUT_ASSERT_SET_2));
 +              bnx2x_panic();
 +      }
 +}
 +
 +static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
 +{
 +      u32 val;
 +
 +      if (attn & EVEREST_GEN_ATTN_IN_USE_MASK) {
 +
 +              if (attn & BNX2X_PMF_LINK_ASSERT) {
 +                      int func = BP_FUNC(bp);
 +
 +                      REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_12 + func*4, 0);
 +                      bp->mf_config[BP_VN(bp)] = MF_CFG_RD(bp,
 +                                      func_mf_config[BP_ABS_FUNC(bp)].config);
 +                      val = SHMEM_RD(bp,
 +                                     func_mb[BP_FW_MB_IDX(bp)].drv_status);
 +                      if (val & DRV_STATUS_DCC_EVENT_MASK)
 +                              bnx2x_dcc_event(bp,
 +                                          (val & DRV_STATUS_DCC_EVENT_MASK));
 +
 +                      if (val & DRV_STATUS_SET_MF_BW)
 +                              bnx2x_set_mf_bw(bp);
 +
 +                      if ((bp->port.pmf == 0) && (val & DRV_STATUS_PMF))
 +                              bnx2x_pmf_update(bp);
 +
 +                      if (bp->port.pmf &&
 +                          (val & DRV_STATUS_DCBX_NEGOTIATION_RESULTS) &&
 +                              bp->dcbx_enabled > 0)
 +                              /* start dcbx state machine */
 +                              bnx2x_dcbx_set_params(bp,
 +                                      BNX2X_DCBX_STATE_NEG_RECEIVED);
 +                      if (bp->link_vars.periodic_flags &
 +                          PERIODIC_FLAGS_LINK_EVENT) {
 +                              /*  sync with link */
 +                              bnx2x_acquire_phy_lock(bp);
 +                              bp->link_vars.periodic_flags &=
 +                                      ~PERIODIC_FLAGS_LINK_EVENT;
 +                              bnx2x_release_phy_lock(bp);
 +                              if (IS_MF(bp))
 +                                      bnx2x_link_sync_notify(bp);
 +                              bnx2x_link_report(bp);
 +                      }
 +                      /* Always call it here: bnx2x_link_report() will
 +                       * prevent the link indication duplication.
 +                       */
 +                      bnx2x__link_status_update(bp);
 +              } else if (attn & BNX2X_MC_ASSERT_BITS) {
 +
 +                      BNX2X_ERR("MC assert!\n");
 +                      bnx2x_mc_assert(bp);
 +                      REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_10, 0);
 +                      REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_9, 0);
 +                      REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_8, 0);
 +                      REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_7, 0);
 +                      bnx2x_panic();
 +
 +              } else if (attn & BNX2X_MCP_ASSERT) {
 +
 +                      BNX2X_ERR("MCP assert!\n");
 +                      REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_11, 0);
 +                      bnx2x_fw_dump(bp);
 +
 +              } else
 +                      BNX2X_ERR("Unknown HW assert! (attn 0x%x)\n", attn);
 +      }
 +
 +      if (attn & EVEREST_LATCHED_ATTN_IN_USE_MASK) {
 +              BNX2X_ERR("LATCHED attention 0x%08x (masked)\n", attn);
 +              if (attn & BNX2X_GRC_TIMEOUT) {
 +                      val = CHIP_IS_E1(bp) ? 0 :
 +                                      REG_RD(bp, MISC_REG_GRC_TIMEOUT_ATTN);
 +                      BNX2X_ERR("GRC time-out 0x%08x\n", val);
 +              }
 +              if (attn & BNX2X_GRC_RSV) {
 +                      val = CHIP_IS_E1(bp) ? 0 :
 +                                      REG_RD(bp, MISC_REG_GRC_RSV_ATTN);
 +                      BNX2X_ERR("GRC reserved 0x%08x\n", val);
 +              }
 +              REG_WR(bp, MISC_REG_AEU_CLR_LATCH_SIGNAL, 0x7ff);
 +      }
 +}
 +
 +/*
 + * Bits map:
 + * 0-7   - Engine0 load counter.
 + * 8-15  - Engine1 load counter.
 + * 16    - Engine0 RESET_IN_PROGRESS bit.
 + * 17    - Engine1 RESET_IN_PROGRESS bit.
 + * 18    - Engine0 ONE_IS_LOADED. Set when there is at least one active function
 + *         on the engine
 + * 19    - Engine1 ONE_IS_LOADED.
 + * 20    - Chip reset flow bit. When set none-leader must wait for both engines
 + *         leader to complete (check for both RESET_IN_PROGRESS bits and not for
 + *         just the one belonging to its engine).
 + *
 + */
 +#define BNX2X_RECOVERY_GLOB_REG               MISC_REG_GENERIC_POR_1
 +
 +#define BNX2X_PATH0_LOAD_CNT_MASK     0x000000ff
 +#define BNX2X_PATH0_LOAD_CNT_SHIFT    0
 +#define BNX2X_PATH1_LOAD_CNT_MASK     0x0000ff00
 +#define BNX2X_PATH1_LOAD_CNT_SHIFT    8
 +#define BNX2X_PATH0_RST_IN_PROG_BIT   0x00010000
 +#define BNX2X_PATH1_RST_IN_PROG_BIT   0x00020000
 +#define BNX2X_GLOBAL_RESET_BIT                0x00040000
 +
 +/*
 + * Set the GLOBAL_RESET bit.
 + *
 + * Should be run under rtnl lock
 + */
 +void bnx2x_set_reset_global(struct bnx2x *bp)
 +{
 +      u32 val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG);
 +
 +      REG_WR(bp, BNX2X_RECOVERY_GLOB_REG, val | BNX2X_GLOBAL_RESET_BIT);
 +      barrier();
 +      mmiowb();
 +}
 +
 +/*
 + * Clear the GLOBAL_RESET bit.
 + *
 + * Should be run under rtnl lock
 + */
 +static inline void bnx2x_clear_reset_global(struct bnx2x *bp)
 +{
 +      u32 val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG);
 +
 +      REG_WR(bp, BNX2X_RECOVERY_GLOB_REG, val & (~BNX2X_GLOBAL_RESET_BIT));
 +      barrier();
 +      mmiowb();
 +}
 +
 +/*
 + * Checks the GLOBAL_RESET bit.
 + *
 + * should be run under rtnl lock
 + */
 +static inline bool bnx2x_reset_is_global(struct bnx2x *bp)
 +{
 +      u32 val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG);
 +
 +      DP(NETIF_MSG_HW, "GEN_REG_VAL=0x%08x\n", val);
 +      return (val & BNX2X_GLOBAL_RESET_BIT) ? true : false;
 +}
 +
 +/*
 + * Clear RESET_IN_PROGRESS bit for the current engine.
 + *
 + * Should be run under rtnl lock
 + */
 +static inline void bnx2x_set_reset_done(struct bnx2x *bp)
 +{
 +      u32 val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG);
 +      u32 bit = BP_PATH(bp) ?
 +              BNX2X_PATH1_RST_IN_PROG_BIT : BNX2X_PATH0_RST_IN_PROG_BIT;
 +
 +      /* Clear the bit */
 +      val &= ~bit;
 +      REG_WR(bp, BNX2X_RECOVERY_GLOB_REG, val);
 +      barrier();
 +      mmiowb();
 +}
 +
 +/*
 + * Set RESET_IN_PROGRESS for the current engine.
 + *
 + * should be run under rtnl lock
 + */
 +void bnx2x_set_reset_in_progress(struct bnx2x *bp)
 +{
 +      u32 val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG);
 +      u32 bit = BP_PATH(bp) ?
 +              BNX2X_PATH1_RST_IN_PROG_BIT : BNX2X_PATH0_RST_IN_PROG_BIT;
 +
 +      /* Set the bit */
 +      val |= bit;
 +      REG_WR(bp, BNX2X_RECOVERY_GLOB_REG, val);
 +      barrier();
 +      mmiowb();
 +}
 +
 +/*
 + * Checks the RESET_IN_PROGRESS bit for the given engine.
 + * should be run under rtnl lock
 + */
 +bool bnx2x_reset_is_done(struct bnx2x *bp, int engine)
 +{
 +      u32 val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG);
 +      u32 bit = engine ?
 +              BNX2X_PATH1_RST_IN_PROG_BIT : BNX2X_PATH0_RST_IN_PROG_BIT;
 +
 +      /* return false if bit is set */
 +      return (val & bit) ? false : true;
 +}
 +
 +/*
 + * Increment the load counter for the current engine.
 + *
 + * should be run under rtnl lock
 + */
 +void bnx2x_inc_load_cnt(struct bnx2x *bp)
 +{
 +      u32 val1, val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG);
 +      u32 mask = BP_PATH(bp) ? BNX2X_PATH1_LOAD_CNT_MASK :
 +                           BNX2X_PATH0_LOAD_CNT_MASK;
 +      u32 shift = BP_PATH(bp) ? BNX2X_PATH1_LOAD_CNT_SHIFT :
 +                           BNX2X_PATH0_LOAD_CNT_SHIFT;
 +
 +      DP(NETIF_MSG_HW, "Old GEN_REG_VAL=0x%08x\n", val);
 +
 +      /* get the current counter value */
 +      val1 = (val & mask) >> shift;
 +
 +      /* increment... */
 +      val1++;
 +
 +      /* clear the old value */
 +      val &= ~mask;
 +
 +      /* set the new one */
 +      val |= ((val1 << shift) & mask);
 +
 +      REG_WR(bp, BNX2X_RECOVERY_GLOB_REG, val);
 +      barrier();
 +      mmiowb();
 +}
 +
 +/**
 + * bnx2x_dec_load_cnt - decrement the load counter
 + *
 + * @bp:               driver handle
 + *
 + * Should be run under rtnl lock.
 + * Decrements the load counter for the current engine. Returns
 + * the new counter value.
 + */
 +u32 bnx2x_dec_load_cnt(struct bnx2x *bp)
 +{
 +      u32 val1, val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG);
 +      u32 mask = BP_PATH(bp) ? BNX2X_PATH1_LOAD_CNT_MASK :
 +                           BNX2X_PATH0_LOAD_CNT_MASK;
 +      u32 shift = BP_PATH(bp) ? BNX2X_PATH1_LOAD_CNT_SHIFT :
 +                           BNX2X_PATH0_LOAD_CNT_SHIFT;
 +
 +      DP(NETIF_MSG_HW, "Old GEN_REG_VAL=0x%08x\n", val);
 +
 +      /* get the current counter value */
 +      val1 = (val & mask) >> shift;
 +
 +      /* decrement... */
 +      val1--;
 +
 +      /* clear the old value */
 +      val &= ~mask;
 +
 +      /* set the new one */
 +      val |= ((val1 << shift) & mask);
 +
 +      REG_WR(bp, BNX2X_RECOVERY_GLOB_REG, val);
 +      barrier();
 +      mmiowb();
 +
 +      return val1;
 +}
 +
 +/*
 + * Read the load counter for the current engine.
 + *
 + * should be run under rtnl lock
 + */
 +static inline u32 bnx2x_get_load_cnt(struct bnx2x *bp, int engine)
 +{
 +      u32 mask = (engine ? BNX2X_PATH1_LOAD_CNT_MASK :
 +                           BNX2X_PATH0_LOAD_CNT_MASK);
 +      u32 shift = (engine ? BNX2X_PATH1_LOAD_CNT_SHIFT :
 +                           BNX2X_PATH0_LOAD_CNT_SHIFT);
 +      u32 val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG);
 +
 +      DP(NETIF_MSG_HW, "GLOB_REG=0x%08x\n", val);
 +
 +      val = (val & mask) >> shift;
 +
 +      DP(NETIF_MSG_HW, "load_cnt for engine %d = %d\n", engine, val);
 +
 +      return val;
 +}
 +
 +/*
 + * Reset the load counter for the current engine.
 + *
 + * should be run under rtnl lock
 + */
 +static inline void bnx2x_clear_load_cnt(struct bnx2x *bp)
 +{
 +      u32 val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG);
 +      u32 mask = (BP_PATH(bp) ? BNX2X_PATH1_LOAD_CNT_MASK :
 +                           BNX2X_PATH0_LOAD_CNT_MASK);
 +
 +      REG_WR(bp, BNX2X_RECOVERY_GLOB_REG, val & (~mask));
 +}
 +
 +static inline void _print_next_block(int idx, const char *blk)
 +{
 +      pr_cont("%s%s", idx ? ", " : "", blk);
 +}
 +
 +static inline int bnx2x_check_blocks_with_parity0(u32 sig, int par_num,
 +                                                bool print)
 +{
 +      int i = 0;
 +      u32 cur_bit = 0;
 +      for (i = 0; sig; i++) {
 +              cur_bit = ((u32)0x1 << i);
 +              if (sig & cur_bit) {
 +                      switch (cur_bit) {
 +                      case AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "BRB");
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_PARSER_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "PARSER");
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_TSDM_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "TSDM");
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_SEARCHER_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++,
 +                                                        "SEARCHER");
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_TCM_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "TCM");
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_TSEMI_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "TSEMI");
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_PBCLIENT_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "XPB");
 +                              break;
 +                      }
 +
 +                      /* Clear the bit */
 +                      sig &= ~cur_bit;
 +              }
 +      }
 +
 +      return par_num;
 +}
 +
 +static inline int bnx2x_check_blocks_with_parity1(u32 sig, int par_num,
 +                                                bool *global, bool print)
 +{
 +      int i = 0;
 +      u32 cur_bit = 0;
 +      for (i = 0; sig; i++) {
 +              cur_bit = ((u32)0x1 << i);
 +              if (sig & cur_bit) {
 +                      switch (cur_bit) {
 +                      case AEU_INPUTS_ATTN_BITS_PBF_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "PBF");
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_QM_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "QM");
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_TIMERS_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "TM");
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_XSDM_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "XSDM");
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_XCM_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "XCM");
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_XSEMI_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "XSEMI");
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_DOORBELLQ_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++,
 +                                                        "DOORBELLQ");
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_NIG_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "NIG");
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_VAUX_PCI_CORE_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++,
 +                                                        "VAUX PCI CORE");
 +                              *global = true;
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_DEBUG_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "DEBUG");
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_USDM_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "USDM");
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_UCM_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "UCM");
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_USEMI_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "USEMI");
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_UPB_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "UPB");
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_CSDM_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "CSDM");
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_CCM_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "CCM");
 +                              break;
 +                      }
 +
 +                      /* Clear the bit */
 +                      sig &= ~cur_bit;
 +              }
 +      }
 +
 +      return par_num;
 +}
 +
 +static inline int bnx2x_check_blocks_with_parity2(u32 sig, int par_num,
 +                                                bool print)
 +{
 +      int i = 0;
 +      u32 cur_bit = 0;
 +      for (i = 0; sig; i++) {
 +              cur_bit = ((u32)0x1 << i);
 +              if (sig & cur_bit) {
 +                      switch (cur_bit) {
 +                      case AEU_INPUTS_ATTN_BITS_CSEMI_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "CSEMI");
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_PXP_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "PXP");
 +                              break;
 +                      case AEU_IN_ATTN_BITS_PXPPCICLOCKCLIENT_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++,
 +                                      "PXPPCICLOCKCLIENT");
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_CFC_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "CFC");
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_CDU_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "CDU");
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_DMAE_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "DMAE");
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_IGU_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "IGU");
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_MISC_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "MISC");
 +                              break;
 +                      }
 +
 +                      /* Clear the bit */
 +                      sig &= ~cur_bit;
 +              }
 +      }
 +
 +      return par_num;
 +}
 +
 +static inline int bnx2x_check_blocks_with_parity3(u32 sig, int par_num,
 +                                                bool *global, bool print)
 +{
 +      int i = 0;
 +      u32 cur_bit = 0;
 +      for (i = 0; sig; i++) {
 +              cur_bit = ((u32)0x1 << i);
 +              if (sig & cur_bit) {
 +                      switch (cur_bit) {
 +                      case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_ROM_PARITY:
 +                              if (print)
 +                                      _print_next_block(par_num++, "MCP ROM");
 +                              *global = true;
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_RX_PARITY:
 +                              if (print)
 +                                      _print_next_block(par_num++,
 +                                                        "MCP UMP RX");
 +                              *global = true;
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_TX_PARITY:
 +                              if (print)
 +                                      _print_next_block(par_num++,
 +                                                        "MCP UMP TX");
 +                              *global = true;
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_SCPAD_PARITY:
 +                              if (print)
 +                                      _print_next_block(par_num++,
 +                                                        "MCP SCPAD");
 +                              *global = true;
 +                              break;
 +                      }
 +
 +                      /* Clear the bit */
 +                      sig &= ~cur_bit;
 +              }
 +      }
 +
 +      return par_num;
 +}
 +
 +static inline int bnx2x_check_blocks_with_parity4(u32 sig, int par_num,
 +                                                bool print)
 +{
 +      int i = 0;
 +      u32 cur_bit = 0;
 +      for (i = 0; sig; i++) {
 +              cur_bit = ((u32)0x1 << i);
 +              if (sig & cur_bit) {
 +                      switch (cur_bit) {
 +                      case AEU_INPUTS_ATTN_BITS_PGLUE_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "PGLUE_B");
 +                              break;
 +                      case AEU_INPUTS_ATTN_BITS_ATC_PARITY_ERROR:
 +                              if (print)
 +                                      _print_next_block(par_num++, "ATC");
 +                              break;
 +                      }
 +
 +                      /* Clear the bit */
 +                      sig &= ~cur_bit;
 +              }
 +      }
 +
 +      return par_num;
 +}
 +
 +static inline bool bnx2x_parity_attn(struct bnx2x *bp, bool *global, bool print,
 +                                   u32 *sig)
 +{
 +      if ((sig[0] & HW_PRTY_ASSERT_SET_0) ||
 +          (sig[1] & HW_PRTY_ASSERT_SET_1) ||
 +          (sig[2] & HW_PRTY_ASSERT_SET_2) ||
 +          (sig[3] & HW_PRTY_ASSERT_SET_3) ||
 +          (sig[4] & HW_PRTY_ASSERT_SET_4)) {
 +              int par_num = 0;
 +              DP(NETIF_MSG_HW, "Was parity error: HW block parity attention: "
 +                      "[0]:0x%08x [1]:0x%08x [2]:0x%08x [3]:0x%08x "
 +                      "[4]:0x%08x\n",
 +                        sig[0] & HW_PRTY_ASSERT_SET_0,
 +                        sig[1] & HW_PRTY_ASSERT_SET_1,
 +                        sig[2] & HW_PRTY_ASSERT_SET_2,
 +                        sig[3] & HW_PRTY_ASSERT_SET_3,
 +                        sig[4] & HW_PRTY_ASSERT_SET_4);
 +              if (print)
 +                      netdev_err(bp->dev,
 +                                 "Parity errors detected in blocks: ");
 +              par_num = bnx2x_check_blocks_with_parity0(
 +                      sig[0] & HW_PRTY_ASSERT_SET_0, par_num, print);
 +              par_num = bnx2x_check_blocks_with_parity1(
 +                      sig[1] & HW_PRTY_ASSERT_SET_1, par_num, global, print);
 +              par_num = bnx2x_check_blocks_with_parity2(
 +                      sig[2] & HW_PRTY_ASSERT_SET_2, par_num, print);
 +              par_num = bnx2x_check_blocks_with_parity3(
 +                      sig[3] & HW_PRTY_ASSERT_SET_3, par_num, global, print);
 +              par_num = bnx2x_check_blocks_with_parity4(
 +                      sig[4] & HW_PRTY_ASSERT_SET_4, par_num, print);
 +
 +              if (print)
 +                      pr_cont("\n");
 +
 +              return true;
 +      } else
 +              return false;
 +}
 +
 +/**
 + * bnx2x_chk_parity_attn - checks for parity attentions.
 + *
 + * @bp:               driver handle
 + * @global:   true if there was a global attention
 + * @print:    show parity attention in syslog
 + */
 +bool bnx2x_chk_parity_attn(struct bnx2x *bp, bool *global, bool print)
 +{
 +      struct attn_route attn = { {0} };
 +      int port = BP_PORT(bp);
 +
 +      attn.sig[0] = REG_RD(bp,
 +              MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 +
 +                           port*4);
 +      attn.sig[1] = REG_RD(bp,
 +              MISC_REG_AEU_AFTER_INVERT_2_FUNC_0 +
 +                           port*4);
 +      attn.sig[2] = REG_RD(bp,
 +              MISC_REG_AEU_AFTER_INVERT_3_FUNC_0 +
 +                           port*4);
 +      attn.sig[3] = REG_RD(bp,
 +              MISC_REG_AEU_AFTER_INVERT_4_FUNC_0 +
 +                           port*4);
 +
 +      if (!CHIP_IS_E1x(bp))
 +              attn.sig[4] = REG_RD(bp,
 +                      MISC_REG_AEU_AFTER_INVERT_5_FUNC_0 +
 +                                   port*4);
 +
 +      return bnx2x_parity_attn(bp, global, print, attn.sig);
 +}
 +
 +
 +static inline void bnx2x_attn_int_deasserted4(struct bnx2x *bp, u32 attn)
 +{
 +      u32 val;
 +      if (attn & AEU_INPUTS_ATTN_BITS_PGLUE_HW_INTERRUPT) {
 +
 +              val = REG_RD(bp, PGLUE_B_REG_PGLUE_B_INT_STS_CLR);
 +              BNX2X_ERR("PGLUE hw attention 0x%x\n", val);
 +              if (val & PGLUE_B_PGLUE_B_INT_STS_REG_ADDRESS_ERROR)
 +                      BNX2X_ERR("PGLUE_B_PGLUE_B_INT_STS_REG_"
 +                                "ADDRESS_ERROR\n");
 +              if (val & PGLUE_B_PGLUE_B_INT_STS_REG_INCORRECT_RCV_BEHAVIOR)
 +                      BNX2X_ERR("PGLUE_B_PGLUE_B_INT_STS_REG_"
 +                                "INCORRECT_RCV_BEHAVIOR\n");
 +              if (val & PGLUE_B_PGLUE_B_INT_STS_REG_WAS_ERROR_ATTN)
 +                      BNX2X_ERR("PGLUE_B_PGLUE_B_INT_STS_REG_"
 +                                "WAS_ERROR_ATTN\n");
 +              if (val & PGLUE_B_PGLUE_B_INT_STS_REG_VF_LENGTH_VIOLATION_ATTN)
 +                      BNX2X_ERR("PGLUE_B_PGLUE_B_INT_STS_REG_"
 +                                "VF_LENGTH_VIOLATION_ATTN\n");
 +              if (val &
 +                  PGLUE_B_PGLUE_B_INT_STS_REG_VF_GRC_SPACE_VIOLATION_ATTN)
 +                      BNX2X_ERR("PGLUE_B_PGLUE_B_INT_STS_REG_"
 +                                "VF_GRC_SPACE_VIOLATION_ATTN\n");
 +              if (val &
 +                  PGLUE_B_PGLUE_B_INT_STS_REG_VF_MSIX_BAR_VIOLATION_ATTN)
 +                      BNX2X_ERR("PGLUE_B_PGLUE_B_INT_STS_REG_"
 +                                "VF_MSIX_BAR_VIOLATION_ATTN\n");
 +              if (val & PGLUE_B_PGLUE_B_INT_STS_REG_TCPL_ERROR_ATTN)
 +                      BNX2X_ERR("PGLUE_B_PGLUE_B_INT_STS_REG_"
 +                                "TCPL_ERROR_ATTN\n");
 +              if (val & PGLUE_B_PGLUE_B_INT_STS_REG_TCPL_IN_TWO_RCBS_ATTN)
 +                      BNX2X_ERR("PGLUE_B_PGLUE_B_INT_STS_REG_"
 +                                "TCPL_IN_TWO_RCBS_ATTN\n");
 +              if (val & PGLUE_B_PGLUE_B_INT_STS_REG_CSSNOOP_FIFO_OVERFLOW)
 +                      BNX2X_ERR("PGLUE_B_PGLUE_B_INT_STS_REG_"
 +                                "CSSNOOP_FIFO_OVERFLOW\n");
 +      }
 +      if (attn & AEU_INPUTS_ATTN_BITS_ATC_HW_INTERRUPT) {
 +              val = REG_RD(bp, ATC_REG_ATC_INT_STS_CLR);
 +              BNX2X_ERR("ATC hw attention 0x%x\n", val);
 +              if (val & ATC_ATC_INT_STS_REG_ADDRESS_ERROR)
 +                      BNX2X_ERR("ATC_ATC_INT_STS_REG_ADDRESS_ERROR\n");
 +              if (val & ATC_ATC_INT_STS_REG_ATC_TCPL_TO_NOT_PEND)
 +                      BNX2X_ERR("ATC_ATC_INT_STS_REG"
 +                                "_ATC_TCPL_TO_NOT_PEND\n");
 +              if (val & ATC_ATC_INT_STS_REG_ATC_GPA_MULTIPLE_HITS)
 +                      BNX2X_ERR("ATC_ATC_INT_STS_REG_"
 +                                "ATC_GPA_MULTIPLE_HITS\n");
 +              if (val & ATC_ATC_INT_STS_REG_ATC_RCPL_TO_EMPTY_CNT)
 +                      BNX2X_ERR("ATC_ATC_INT_STS_REG_"
 +                                "ATC_RCPL_TO_EMPTY_CNT\n");
 +              if (val & ATC_ATC_INT_STS_REG_ATC_TCPL_ERROR)
 +                      BNX2X_ERR("ATC_ATC_INT_STS_REG_ATC_TCPL_ERROR\n");
 +              if (val & ATC_ATC_INT_STS_REG_ATC_IREQ_LESS_THAN_STU)
 +                      BNX2X_ERR("ATC_ATC_INT_STS_REG_"
 +                                "ATC_IREQ_LESS_THAN_STU\n");
 +      }
 +
 +      if (attn & (AEU_INPUTS_ATTN_BITS_PGLUE_PARITY_ERROR |
 +                  AEU_INPUTS_ATTN_BITS_ATC_PARITY_ERROR)) {
 +              BNX2X_ERR("FATAL parity attention set4 0x%x\n",
 +              (u32)(attn & (AEU_INPUTS_ATTN_BITS_PGLUE_PARITY_ERROR |
 +                  AEU_INPUTS_ATTN_BITS_ATC_PARITY_ERROR)));
 +      }
 +
 +}
 +
 +static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
 +{
 +      struct attn_route attn, *group_mask;
 +      int port = BP_PORT(bp);
 +      int index;
 +      u32 reg_addr;
 +      u32 val;
 +      u32 aeu_mask;
 +      bool global = false;
 +
 +      /* need to take HW lock because MCP or other port might also
 +         try to handle this event */
 +      bnx2x_acquire_alr(bp);
 +
 +      if (bnx2x_chk_parity_attn(bp, &global, true)) {
 +#ifndef BNX2X_STOP_ON_ERROR
 +              bp->recovery_state = BNX2X_RECOVERY_INIT;
 +              schedule_delayed_work(&bp->sp_rtnl_task, 0);
 +              /* Disable HW interrupts */
 +              bnx2x_int_disable(bp);
 +              /* In case of parity errors don't handle attentions so that
 +               * other function would "see" parity errors.
 +               */
 +#else
 +              bnx2x_panic();
 +#endif
 +              bnx2x_release_alr(bp);
 +              return;
 +      }
 +
 +      attn.sig[0] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 + port*4);
 +      attn.sig[1] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_2_FUNC_0 + port*4);
 +      attn.sig[2] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_3_FUNC_0 + port*4);
 +      attn.sig[3] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_4_FUNC_0 + port*4);
 +      if (!CHIP_IS_E1x(bp))
 +              attn.sig[4] =
 +                    REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_5_FUNC_0 + port*4);
 +      else
 +              attn.sig[4] = 0;
 +
 +      DP(NETIF_MSG_HW, "attn: %08x %08x %08x %08x %08x\n",
 +         attn.sig[0], attn.sig[1], attn.sig[2], attn.sig[3], attn.sig[4]);
 +
 +      for (index = 0; index < MAX_DYNAMIC_ATTN_GRPS; index++) {
 +              if (deasserted & (1 << index)) {
 +                      group_mask = &bp->attn_group[index];
 +
 +                      DP(NETIF_MSG_HW, "group[%d]: %08x %08x "
 +                                       "%08x %08x %08x\n",
 +                         index,
 +                         group_mask->sig[0], group_mask->sig[1],
 +                         group_mask->sig[2], group_mask->sig[3],
 +                         group_mask->sig[4]);
 +
 +                      bnx2x_attn_int_deasserted4(bp,
 +                                      attn.sig[4] & group_mask->sig[4]);
 +                      bnx2x_attn_int_deasserted3(bp,
 +                                      attn.sig[3] & group_mask->sig[3]);
 +                      bnx2x_attn_int_deasserted1(bp,
 +                                      attn.sig[1] & group_mask->sig[1]);
 +                      bnx2x_attn_int_deasserted2(bp,
 +                                      attn.sig[2] & group_mask->sig[2]);
 +                      bnx2x_attn_int_deasserted0(bp,
 +                                      attn.sig[0] & group_mask->sig[0]);
 +              }
 +      }
 +
 +      bnx2x_release_alr(bp);
 +
 +      if (bp->common.int_block == INT_BLOCK_HC)
 +              reg_addr = (HC_REG_COMMAND_REG + port*32 +
 +                          COMMAND_REG_ATTN_BITS_CLR);
 +      else
 +              reg_addr = (BAR_IGU_INTMEM + IGU_CMD_ATTN_BIT_CLR_UPPER*8);
 +
 +      val = ~deasserted;
 +      DP(NETIF_MSG_HW, "about to mask 0x%08x at %s addr 0x%x\n", val,
 +         (bp->common.int_block == INT_BLOCK_HC) ? "HC" : "IGU", reg_addr);
 +      REG_WR(bp, reg_addr, val);
 +
 +      if (~bp->attn_state & deasserted)
 +              BNX2X_ERR("IGU ERROR\n");
 +
 +      reg_addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 :
 +                        MISC_REG_AEU_MASK_ATTN_FUNC_0;
 +
 +      bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_PORT0_ATT_MASK + port);
 +      aeu_mask = REG_RD(bp, reg_addr);
 +
 +      DP(NETIF_MSG_HW, "aeu_mask %x  newly deasserted %x\n",
 +         aeu_mask, deasserted);
 +      aeu_mask |= (deasserted & 0x3ff);
 +      DP(NETIF_MSG_HW, "new mask %x\n", aeu_mask);
 +
 +      REG_WR(bp, reg_addr, aeu_mask);
 +      bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_PORT0_ATT_MASK + port);
 +
 +      DP(NETIF_MSG_HW, "attn_state %x\n", bp->attn_state);
 +      bp->attn_state &= ~deasserted;
 +      DP(NETIF_MSG_HW, "new state %x\n", bp->attn_state);
 +}
 +
 +static void bnx2x_attn_int(struct bnx2x *bp)
 +{
 +      /* read local copy of bits */
 +      u32 attn_bits = le32_to_cpu(bp->def_status_blk->atten_status_block.
 +                                                              attn_bits);
 +      u32 attn_ack = le32_to_cpu(bp->def_status_blk->atten_status_block.
 +                                                              attn_bits_ack);
 +      u32 attn_state = bp->attn_state;
 +
 +      /* look for changed bits */
 +      u32 asserted   =  attn_bits & ~attn_ack & ~attn_state;
 +      u32 deasserted = ~attn_bits &  attn_ack &  attn_state;
 +
 +      DP(NETIF_MSG_HW,
 +         "attn_bits %x  attn_ack %x  asserted %x  deasserted %x\n",
 +         attn_bits, attn_ack, asserted, deasserted);
 +
 +      if (~(attn_bits ^ attn_ack) & (attn_bits ^ attn_state))
 +              BNX2X_ERR("BAD attention state\n");
 +
 +      /* handle bits that were raised */
 +      if (asserted)
 +              bnx2x_attn_int_asserted(bp, asserted);
 +
 +      if (deasserted)
 +              bnx2x_attn_int_deasserted(bp, deasserted);
 +}
 +
 +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;
 +
 +      bnx2x_igu_ack_sb_gen(bp, igu_sb_id, segment, index, op, update,
 +                           igu_addr);
 +}
 +
 +static inline void bnx2x_update_eq_prod(struct bnx2x *bp, u16 prod)
 +{
 +      /* No memory barriers */
 +      storm_memset_eq_prod(bp, prod, BP_FUNC(bp));
 +      mmiowb(); /* keep prod updates ordered */
 +}
 +
 +#ifdef BCM_CNIC
 +static int  bnx2x_cnic_handle_cfc_del(struct bnx2x *bp, u32 cid,
 +                                    union event_ring_elem *elem)
 +{
 +      u8 err = elem->message.error;
 +
 +      if (!bp->cnic_eth_dev.starting_cid  ||
 +          (cid < bp->cnic_eth_dev.starting_cid &&
 +          cid != bp->cnic_eth_dev.iscsi_l2_cid))
 +              return 1;
 +
 +      DP(BNX2X_MSG_SP, "got delete ramrod for CNIC CID %d\n", cid);
 +
 +      if (unlikely(err)) {
 +
 +              BNX2X_ERR("got delete ramrod for CNIC CID %d with error!\n",
 +                        cid);
 +              bnx2x_panic_dump(bp);
 +      }
 +      bnx2x_cnic_cfc_comp(bp, cid, err);
 +      return 0;
 +}
 +#endif
 +
 +static inline void bnx2x_handle_mcast_eqe(struct bnx2x *bp)
 +{
 +      struct bnx2x_mcast_ramrod_params rparam;
 +      int rc;
 +
 +      memset(&rparam, 0, sizeof(rparam));
 +
 +      rparam.mcast_obj = &bp->mcast_obj;
 +
 +      netif_addr_lock_bh(bp->dev);
 +
 +      /* Clear pending state for the last command */
 +      bp->mcast_obj.raw.clear_pending(&bp->mcast_obj.raw);
 +
 +      /* If there are pending mcast commands - send them */
 +      if (bp->mcast_obj.check_pending(&bp->mcast_obj)) {
 +              rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_CONT);
 +              if (rc < 0)
 +                      BNX2X_ERR("Failed to send pending mcast commands: %d\n",
 +                                rc);
 +      }
 +
 +      netif_addr_unlock_bh(bp->dev);
 +}
 +
 +static inline void bnx2x_handle_classification_eqe(struct bnx2x *bp,
 +                                                 union event_ring_elem *elem)
 +{
 +      unsigned long ramrod_flags = 0;
 +      int rc = 0;
 +      u32 cid = elem->message.data.eth_event.echo & BNX2X_SWCID_MASK;
 +      struct bnx2x_vlan_mac_obj *vlan_mac_obj;
 +
 +      /* Always push next commands out, don't wait here */
 +      __set_bit(RAMROD_CONT, &ramrod_flags);
 +
 +      switch (elem->message.data.eth_event.echo >> BNX2X_SWCID_SHIFT) {
 +      case BNX2X_FILTER_MAC_PENDING:
 +#ifdef BCM_CNIC
 +              if (cid == BNX2X_ISCSI_ETH_CID)
 +                      vlan_mac_obj = &bp->iscsi_l2_mac_obj;
 +              else
 +#endif
 +                      vlan_mac_obj = &bp->fp[cid].mac_obj;
 +
 +              break;
 +      case BNX2X_FILTER_MCAST_PENDING:
 +              /* This is only relevant for 57710 where multicast MACs are
 +               * configured as unicast MACs using the same ramrod.
 +               */
 +              bnx2x_handle_mcast_eqe(bp);
 +              return;
 +      default:
 +              BNX2X_ERR("Unsupported classification command: %d\n",
 +                        elem->message.data.eth_event.echo);
 +              return;
 +      }
 +
 +      rc = vlan_mac_obj->complete(bp, vlan_mac_obj, elem, &ramrod_flags);
 +
 +      if (rc < 0)
 +              BNX2X_ERR("Failed to schedule new commands: %d\n", rc);
 +      else if (rc > 0)
 +              DP(BNX2X_MSG_SP, "Scheduled next pending commands...\n");
 +
 +}
 +
 +#ifdef BCM_CNIC
 +static void bnx2x_set_iscsi_eth_rx_mode(struct bnx2x *bp, bool start);
 +#endif
 +
 +static inline void bnx2x_handle_rx_mode_eqe(struct bnx2x *bp)
 +{
 +      netif_addr_lock_bh(bp->dev);
 +
 +      clear_bit(BNX2X_FILTER_RX_MODE_PENDING, &bp->sp_state);
 +
 +      /* Send rx_mode command again if was requested */
 +      if (test_and_clear_bit(BNX2X_FILTER_RX_MODE_SCHED, &bp->sp_state))
 +              bnx2x_set_storm_rx_mode(bp);
 +#ifdef BCM_CNIC
 +      else if (test_and_clear_bit(BNX2X_FILTER_ISCSI_ETH_START_SCHED,
 +                                  &bp->sp_state))
 +              bnx2x_set_iscsi_eth_rx_mode(bp, true);
 +      else if (test_and_clear_bit(BNX2X_FILTER_ISCSI_ETH_STOP_SCHED,
 +                                  &bp->sp_state))
 +              bnx2x_set_iscsi_eth_rx_mode(bp, false);
 +#endif
 +
 +      netif_addr_unlock_bh(bp->dev);
 +}
 +
 +static inline struct bnx2x_queue_sp_obj *bnx2x_cid_to_q_obj(
 +      struct bnx2x *bp, u32 cid)
 +{
 +      DP(BNX2X_MSG_SP, "retrieving fp from cid %d\n", cid);
 +#ifdef BCM_CNIC
 +      if (cid == BNX2X_FCOE_ETH_CID)
 +              return &bnx2x_fcoe(bp, q_obj);
 +      else
 +#endif
 +              return &bnx2x_fp(bp, CID_TO_FP(cid), q_obj);
 +}
 +
 +static void bnx2x_eq_int(struct bnx2x *bp)
 +{
 +      u16 hw_cons, sw_cons, sw_prod;
 +      union event_ring_elem *elem;
 +      u32 cid;
 +      u8 opcode;
 +      int 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;
 +
 +      hw_cons = le16_to_cpu(*bp->eq_cons_sb);
 +
 +      /* The hw_cos range is 1-255, 257 - the sw_cons range is 0-254, 256.
 +       * when we get the the next-page we nned to adjust so the loop
 +       * condition below will be met. The next element is the size of a
 +       * regular element and hence incrementing by 1
 +       */
 +      if ((hw_cons & EQ_DESC_MAX_PAGE) == EQ_DESC_MAX_PAGE)
 +              hw_cons++;
 +
 +      /* This function may never run in parallel with itself for a
 +       * specific bp, thus there is no need in "paired" read memory
 +       * barrier here.
 +       */
 +      sw_cons = bp->eq_cons;
 +      sw_prod = bp->eq_prod;
 +
 +      DP(BNX2X_MSG_SP, "EQ:  hw_cons %u  sw_cons %u bp->eq_spq_left %x\n",
 +                      hw_cons, sw_cons, atomic_read(&bp->eq_spq_left));
 +
 +      for (; sw_cons != hw_cons;
 +            sw_prod = NEXT_EQ_IDX(sw_prod), sw_cons = NEXT_EQ_IDX(sw_cons)) {
 +
 +
 +              elem = &bp->eq_ring[EQ_DESC(sw_cons)];
 +
 +              cid = SW_CID(elem->message.data.cfc_del_event.cid);
 +              opcode = elem->message.opcode;
 +
 +
 +              /* handle eq element */
 +              switch (opcode) {
 +              case EVENT_RING_OPCODE_STAT_QUERY:
 +                      DP(NETIF_MSG_TIMER, "got statistics comp event %d\n",
 +                         bp->stats_comp++);
 +                      /* nothing to do with stats comp */
 +                      goto next_spqe;
 +
 +              case EVENT_RING_OPCODE_CFC_DEL:
 +                      /* handle according to cid range */
 +                      /*
 +                       * we may want to verify here that the bp state is
 +                       * HALTING
 +                       */
 +                      DP(BNX2X_MSG_SP,
 +                         "got delete ramrod for MULTI[%d]\n", cid);
 +#ifdef BCM_CNIC
 +                      if (!bnx2x_cnic_handle_cfc_del(bp, cid, elem))
 +                              goto next_spqe;
 +#endif
 +                      q_obj = bnx2x_cid_to_q_obj(bp, cid);
 +
 +                      if (q_obj->complete_cmd(bp, q_obj, BNX2X_Q_CMD_CFC_DEL))
 +                              break;
 +
 +
 +
 +                      goto next_spqe;
 +
 +              case EVENT_RING_OPCODE_STOP_TRAFFIC:
 +                      DP(BNX2X_MSG_SP, "got STOP TRAFFIC\n");
 +                      if (f_obj->complete_cmd(bp, f_obj,
 +                                              BNX2X_F_CMD_TX_STOP))
 +                              break;
 +                      bnx2x_dcbx_set_params(bp, BNX2X_DCBX_STATE_TX_PAUSED);
 +                      goto next_spqe;
 +
 +              case EVENT_RING_OPCODE_START_TRAFFIC:
 +                      DP(BNX2X_MSG_SP, "got START TRAFFIC\n");
 +                      if (f_obj->complete_cmd(bp, f_obj,
 +                                              BNX2X_F_CMD_TX_START))
 +                              break;
 +                      bnx2x_dcbx_set_params(bp, BNX2X_DCBX_STATE_TX_RELEASED);
 +                      goto next_spqe;
 +              case EVENT_RING_OPCODE_FUNCTION_START:
 +                      DP(BNX2X_MSG_SP, "got FUNC_START ramrod\n");
 +                      if (f_obj->complete_cmd(bp, f_obj, BNX2X_F_CMD_START))
 +                              break;
 +
 +                      goto next_spqe;
 +
 +              case EVENT_RING_OPCODE_FUNCTION_STOP:
 +                      DP(BNX2X_MSG_SP, "got FUNC_STOP ramrod\n");
 +                      if (f_obj->complete_cmd(bp, f_obj, BNX2X_F_CMD_STOP))
 +                              break;
 +
 +                      goto next_spqe;
 +              }
 +
 +              switch (opcode | bp->state) {
 +              case (EVENT_RING_OPCODE_RSS_UPDATE_RULES |
 +                    BNX2X_STATE_OPEN):
 +              case (EVENT_RING_OPCODE_RSS_UPDATE_RULES |
 +                    BNX2X_STATE_OPENING_WAIT4_PORT):
 +                      cid = elem->message.data.eth_event.echo &
 +                              BNX2X_SWCID_MASK;
 +                      DP(BNX2X_MSG_SP, "got RSS_UPDATE ramrod. CID %d\n",
 +                         cid);
 +                      rss_raw->clear_pending(rss_raw);
 +                      break;
 +
 +              case (EVENT_RING_OPCODE_SET_MAC | BNX2X_STATE_OPEN):
 +              case (EVENT_RING_OPCODE_SET_MAC | BNX2X_STATE_DIAG):
 +              case (EVENT_RING_OPCODE_SET_MAC |
 +                    BNX2X_STATE_CLOSING_WAIT4_HALT):
 +              case (EVENT_RING_OPCODE_CLASSIFICATION_RULES |
 +                    BNX2X_STATE_OPEN):
 +              case (EVENT_RING_OPCODE_CLASSIFICATION_RULES |
 +                    BNX2X_STATE_DIAG):
 +              case (EVENT_RING_OPCODE_CLASSIFICATION_RULES |
 +                    BNX2X_STATE_CLOSING_WAIT4_HALT):
 +                      DP(BNX2X_MSG_SP, "got (un)set mac ramrod\n");
 +                      bnx2x_handle_classification_eqe(bp, elem);
 +                      break;
 +
 +              case (EVENT_RING_OPCODE_MULTICAST_RULES |
 +                    BNX2X_STATE_OPEN):
 +              case (EVENT_RING_OPCODE_MULTICAST_RULES |
 +                    BNX2X_STATE_DIAG):
 +              case (EVENT_RING_OPCODE_MULTICAST_RULES |
 +                    BNX2X_STATE_CLOSING_WAIT4_HALT):
 +                      DP(BNX2X_MSG_SP, "got mcast ramrod\n");
 +                      bnx2x_handle_mcast_eqe(bp);
 +                      break;
 +
 +              case (EVENT_RING_OPCODE_FILTERS_RULES |
 +                    BNX2X_STATE_OPEN):
 +              case (EVENT_RING_OPCODE_FILTERS_RULES |
 +                    BNX2X_STATE_DIAG):
 +              case (EVENT_RING_OPCODE_FILTERS_RULES |
 +                    BNX2X_STATE_CLOSING_WAIT4_HALT):
 +                      DP(BNX2X_MSG_SP, "got rx_mode ramrod\n");
 +                      bnx2x_handle_rx_mode_eqe(bp);
 +                      break;
 +              default:
 +                      /* unknown event log error and continue */
 +                      BNX2X_ERR("Unknown EQ event %d, bp->state 0x%x\n",
 +                                elem->message.opcode, bp->state);
 +              }
 +next_spqe:
 +              spqe_cnt++;
 +      } /* for */
 +
 +      smp_mb__before_atomic_inc();
 +      atomic_add(spqe_cnt, &bp->eq_spq_left);
 +
 +      bp->eq_cons = sw_cons;
 +      bp->eq_prod = sw_prod;
 +      /* Make sure that above mem writes were issued towards the memory */
 +      smp_wmb();
 +
 +      /* update producer */
 +      bnx2x_update_eq_prod(bp, bp->eq_prod);
 +}
 +
 +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(NETIF_MSG_INTR, "got a slowpath interrupt (status 0x%x)\n", status);
 +
 +      /* 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) {
 +#ifdef BCM_CNIC
 +              struct bnx2x_fastpath *fp = bnx2x_fcoe_fp(bp);
 +
 +              if ((!NO_FCOE(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();
 +              }
 +#endif
 +              /* 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;
 +      }
 +
 +      if (unlikely(status))
 +              DP(NETIF_MSG_INTR, "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);
 +}
 +
 +irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)
 +{
 +      struct net_device *dev = dev_instance;
 +      struct bnx2x *bp = netdev_priv(dev);
 +
 +      bnx2x_ack_sb(bp, bp->igu_dsb_id, USTORM_ID, 0,
 +                   IGU_INT_DISABLE, 0);
 +
 +#ifdef BNX2X_STOP_ON_ERROR
 +      if (unlikely(bp->panic))
 +              return IRQ_HANDLED;
 +#endif
 +
 +#ifdef BCM_CNIC
 +      {
 +              struct cnic_ops *c_ops;
 +
 +              rcu_read_lock();
 +              c_ops = rcu_dereference(bp->cnic_ops);
 +              if (c_ops)
 +                      c_ops->cnic_handler(bp->cnic_data, NULL);
 +              rcu_read_unlock();
 +      }
 +#endif
 +      queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
 +
 +      return IRQ_HANDLED;
 +}
 +
 +/* end of slow path */
 +
 +
 +void bnx2x_drv_pulse(struct bnx2x *bp)
 +{
 +      SHMEM_WR(bp, func_mb[BP_FW_MB_IDX(bp)].drv_pulse_mb,
 +               bp->fw_drv_pulse_wr_seq);
 +}
 +
 +
 +static void bnx2x_timer(unsigned long data)
 +{
 +      u8 cos;
 +      struct bnx2x *bp = (struct bnx2x *) data;
 +
 +      if (!netif_running(bp->dev))
 +              return;
 +
 +      if (poll) {
 +              struct bnx2x_fastpath *fp = &bp->fp[0];
 +
 +              for_each_cos_in_tx_queue(fp, cos)
 +                      bnx2x_tx_int(bp, &fp->txdata[cos]);
 +              bnx2x_rx_int(fp, 1000);
 +      }
 +
 +      if (!BP_NOMCP(bp)) {
 +              int mb_idx = BP_FW_MB_IDX(bp);
 +              u32 drv_pulse;
 +              u32 mcp_pulse;
 +
 +              ++bp->fw_drv_pulse_wr_seq;
 +              bp->fw_drv_pulse_wr_seq &= DRV_PULSE_SEQ_MASK;
 +              /* TBD - add SYSTEM_TIME */
 +              drv_pulse = bp->fw_drv_pulse_wr_seq;
 +              bnx2x_drv_pulse(bp);
 +
 +              mcp_pulse = (SHMEM_RD(bp, func_mb[mb_idx].mcp_pulse_mb) &
 +                           MCP_PULSE_SEQ_MASK);
 +              /* The delta between driver pulse and mcp response
 +               * should be 1 (before mcp response) or 0 (after mcp response)
 +               */
 +              if ((drv_pulse != mcp_pulse) &&
 +                  (drv_pulse != ((mcp_pulse + 1) & MCP_PULSE_SEQ_MASK))) {
 +                      /* someone lost a heartbeat... */
 +                      BNX2X_ERR("drv_pulse (0x%x) != mcp_pulse (0x%x)\n",
 +                                drv_pulse, mcp_pulse);
 +              }
 +      }
 +
 +      if (bp->state == BNX2X_STATE_OPEN)
 +              bnx2x_stats_handle(bp, STATS_EVENT_UPDATE);
 +
 +      mod_timer(&bp->timer, jiffies + bp->current_interval);
 +}
 +
 +/* end of Statistics */
 +
 +/* nic init */
 +
 +/*
 + * nic init service functions
 + */
 +
 +static inline void bnx2x_fill(struct bnx2x *bp, u32 addr, int fill, u32 len)
 +{
 +      u32 i;
 +      if (!(len%4) && !(addr%4))
 +              for (i = 0; i < len; i += 4)
 +                      REG_WR(bp, addr + i, fill);
 +      else
 +              for (i = 0; i < len; i++)
 +                      REG_WR8(bp, addr + i, fill);
 +
 +}
 +
 +/* helper: writes FP SP data to FW - data_size in dwords */
 +static inline void bnx2x_wr_fp_sb_data(struct bnx2x *bp,
 +                                     int fw_sb_id,
 +                                     u32 *sb_data_p,
 +                                     u32 data_size)
 +{
 +      int index;
 +      for (index = 0; index < data_size; index++)
 +              REG_WR(bp, BAR_CSTRORM_INTMEM +
 +                      CSTORM_STATUS_BLOCK_DATA_OFFSET(fw_sb_id) +
 +                      sizeof(u32)*index,
 +                      *(sb_data_p + index));
 +}
 +
 +static inline void bnx2x_zero_fp_sb(struct bnx2x *bp, int fw_sb_id)
 +{
 +      u32 *sb_data_p;
 +      u32 data_size = 0;
 +      struct hc_status_block_data_e2 sb_data_e2;
 +      struct hc_status_block_data_e1x sb_data_e1x;
 +
 +      /* disable the function first */
 +      if (!CHIP_IS_E1x(bp)) {
 +              memset(&sb_data_e2, 0, sizeof(struct hc_status_block_data_e2));
 +              sb_data_e2.common.state = SB_DISABLED;
 +              sb_data_e2.common.p_func.vf_valid = false;
 +              sb_data_p = (u32 *)&sb_data_e2;
 +              data_size = sizeof(struct hc_status_block_data_e2)/sizeof(u32);
 +      } else {
 +              memset(&sb_data_e1x, 0,
 +                     sizeof(struct hc_status_block_data_e1x));
 +              sb_data_e1x.common.state = SB_DISABLED;
 +              sb_data_e1x.common.p_func.vf_valid = false;
 +              sb_data_p = (u32 *)&sb_data_e1x;
 +              data_size = sizeof(struct hc_status_block_data_e1x)/sizeof(u32);
 +      }
 +      bnx2x_wr_fp_sb_data(bp, fw_sb_id, sb_data_p, data_size);
 +
 +      bnx2x_fill(bp, BAR_CSTRORM_INTMEM +
 +                      CSTORM_STATUS_BLOCK_OFFSET(fw_sb_id), 0,
 +                      CSTORM_STATUS_BLOCK_SIZE);
 +      bnx2x_fill(bp, BAR_CSTRORM_INTMEM +
 +                      CSTORM_SYNC_BLOCK_OFFSET(fw_sb_id), 0,
 +                      CSTORM_SYNC_BLOCK_SIZE);
 +}
 +
 +/* helper:  writes SP SB data to FW */
 +static inline void bnx2x_wr_sp_sb_data(struct bnx2x *bp,
 +              struct hc_sp_status_block_data *sp_sb_data)
 +{
 +      int func = BP_FUNC(bp);
 +      int i;
 +      for (i = 0; i < sizeof(struct hc_sp_status_block_data)/sizeof(u32); i++)
 +              REG_WR(bp, BAR_CSTRORM_INTMEM +
 +                      CSTORM_SP_STATUS_BLOCK_DATA_OFFSET(func) +
 +                      i*sizeof(u32),
 +                      *((u32 *)sp_sb_data + i));
 +}
 +
 +static inline void bnx2x_zero_sp_sb(struct bnx2x *bp)
 +{
 +      int func = BP_FUNC(bp);
 +      struct hc_sp_status_block_data sp_sb_data;
 +      memset(&sp_sb_data, 0, sizeof(struct hc_sp_status_block_data));
 +
 +      sp_sb_data.state = SB_DISABLED;
 +      sp_sb_data.p_func.vf_valid = false;
 +