Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/net/ethernet/broadcom/bnx2x/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 408 kB image not shown  

Quelle  bnx2x_link.c   Sprache: C

 
/* Copyright 2008-2013 Broadcom Corporation
 * Copyright (c) 2014 QLogic Corporation
 * All rights reserved
 *
 * Unless you and QLogic 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/gpl-2.0.html (the "GPL").
 *
 * Notwithstanding the above, under no circumstances may you combine this
 * software in any way with any other Qlogic software provided under a
 * license other than the GPL, without Qlogic's express prior written
 * consent.
 *
 * Written by Yaniv Rosner
 *
 */


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/delay.h>
#include <linux/ethtool.h>
#include <linux/mutex.h>

#include "bnx2x.h"
#include "bnx2x_cmn.h"

typedef int (*read_sfp_module_eeprom_func_p)(struct bnx2x_phy *phy,
          struct link_params *params,
          u8 dev_addr, u16 addr, u8 byte_cnt,
          u8 *o_buf, u8);
/********************************************************/
#define MDIO_ACCESS_TIMEOUT  1000
#define WC_LANE_MAX   4
#define I2C_SWITCH_WIDTH  2
#define I2C_BSC0   0
#define I2C_BSC1   1
#define I2C_WA_RETRY_CNT  3
#define I2C_WA_PWR_ITER   (I2C_WA_RETRY_CNT - 1)
#define MCPR_IMC_COMMAND_READ_OP 1
#define MCPR_IMC_COMMAND_WRITE_OP 2

/* LED Blink rate that will achieve ~15.9Hz */
#define LED_BLINK_RATE_VAL_E3  354
#define LED_BLINK_RATE_VAL_E1X_E2 480
/***********************************************************/
/* Shortcut definitions    */
/***********************************************************/

#define NIG_LATCH_BC_ENABLE_MI_INT 0

#define NIG_STATUS_EMAC0_MI_INT \
  NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_EMAC0_MISC_MI_INT
#define NIG_STATUS_XGXS0_LINK10G \
  NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G
#define NIG_STATUS_XGXS0_LINK_STATUS \
  NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS
#define NIG_STATUS_XGXS0_LINK_STATUS_SIZE \
  NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE
#define NIG_STATUS_SERDES0_LINK_STATUS \
  NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS
#define NIG_MASK_MI_INT \
  NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT
#define NIG_MASK_XGXS0_LINK10G \
  NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G
#define NIG_MASK_XGXS0_LINK_STATUS \
  NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK_STATUS
#define NIG_MASK_SERDES0_LINK_STATUS \
  NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS

#define MDIO_AN_CL73_OR_37_COMPLETE \
  (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE | \
   MDIO_GP_STATUS_TOP_AN_STATUS1_CL37_AUTONEG_COMPLETE)

#define XGXS_RESET_BITS \
 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_RSTB_HW |   \
  MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_IDDQ |      \
  MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN |    \
  MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN_SD | \
  MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_TXD_FIFO_RSTB)

#define SERDES_RESET_BITS \
 (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_RSTB_HW | \
  MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_IDDQ |    \
  MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN |  \
  MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN_SD)

#define AUTONEG_CL37  SHARED_HW_CFG_AN_ENABLE_CL37
#define AUTONEG_CL73  SHARED_HW_CFG_AN_ENABLE_CL73
#define AUTONEG_BAM  SHARED_HW_CFG_AN_ENABLE_BAM
#define AUTONEG_PARALLEL \
    SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION
#define AUTONEG_SGMII_FIBER_AUTODET \
    SHARED_HW_CFG_AN_EN_SGMII_FIBER_AUTO_DETECT
#define AUTONEG_REMOTE_PHY SHARED_HW_CFG_AN_ENABLE_REMOTE_PHY

#define GP_STATUS_PAUSE_RSOLUTION_TXSIDE \
   MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE
#define GP_STATUS_PAUSE_RSOLUTION_RXSIDE \
   MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE
#define GP_STATUS_SPEED_MASK \
   MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK
#define GP_STATUS_10M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M
#define GP_STATUS_100M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M
#define GP_STATUS_1G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G
#define GP_STATUS_2_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G
#define GP_STATUS_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G
#define GP_STATUS_6G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G
#define GP_STATUS_10G_HIG \
   MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG
#define GP_STATUS_10G_CX4 \
   MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4
#define GP_STATUS_1G_KX MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX
#define GP_STATUS_10G_KX4 \
   MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4
#define GP_STATUS_10G_KR MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KR
#define GP_STATUS_10G_XFI   MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_XFI
#define GP_STATUS_20G_DXGXS MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_20G_DXGXS
#define GP_STATUS_10G_SFI   MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_SFI
#define GP_STATUS_20G_KR2 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_20G_KR2
#define LINK_10THD  LINK_STATUS_SPEED_AND_DUPLEX_10THD
#define LINK_10TFD  LINK_STATUS_SPEED_AND_DUPLEX_10TFD
#define LINK_100TXHD  LINK_STATUS_SPEED_AND_DUPLEX_100TXHD
#define LINK_100T4  LINK_STATUS_SPEED_AND_DUPLEX_100T4
#define LINK_100TXFD  LINK_STATUS_SPEED_AND_DUPLEX_100TXFD
#define LINK_1000THD  LINK_STATUS_SPEED_AND_DUPLEX_1000THD
#define LINK_1000TFD  LINK_STATUS_SPEED_AND_DUPLEX_1000TFD
#define LINK_1000XFD  LINK_STATUS_SPEED_AND_DUPLEX_1000XFD
#define LINK_2500THD  LINK_STATUS_SPEED_AND_DUPLEX_2500THD
#define LINK_2500TFD  LINK_STATUS_SPEED_AND_DUPLEX_2500TFD
#define LINK_2500XFD  LINK_STATUS_SPEED_AND_DUPLEX_2500XFD
#define LINK_10GTFD  LINK_STATUS_SPEED_AND_DUPLEX_10GTFD
#define LINK_10GXFD  LINK_STATUS_SPEED_AND_DUPLEX_10GXFD
#define LINK_20GTFD  LINK_STATUS_SPEED_AND_DUPLEX_20GTFD
#define LINK_20GXFD  LINK_STATUS_SPEED_AND_DUPLEX_20GXFD

#define LINK_UPDATE_MASK \
   (LINK_STATUS_SPEED_AND_DUPLEX_MASK | \
    LINK_STATUS_LINK_UP | \
    LINK_STATUS_PHYSICAL_LINK_FLAG | \
    LINK_STATUS_AUTO_NEGOTIATE_COMPLETE | \
    LINK_STATUS_RX_FLOW_CONTROL_FLAG_MASK | \
    LINK_STATUS_TX_FLOW_CONTROL_FLAG_MASK | \
    LINK_STATUS_PARALLEL_DETECTION_FLAG_MASK | \
    LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE | \
    LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE)

#define SFP_EEPROM_CON_TYPE_ADDR  0x2
 #define SFP_EEPROM_CON_TYPE_VAL_UNKNOWN 0x0
 #define SFP_EEPROM_CON_TYPE_VAL_LC 0x7
 #define SFP_EEPROM_CON_TYPE_VAL_COPPER 0x21
 #define SFP_EEPROM_CON_TYPE_VAL_RJ45 0x22


#define SFP_EEPROM_10G_COMP_CODE_ADDR  0x3
 #define SFP_EEPROM_10G_COMP_CODE_SR_MASK (1<<4)
 #define SFP_EEPROM_10G_COMP_CODE_LR_MASK (1<<5)
 #define SFP_EEPROM_10G_COMP_CODE_LRM_MASK (1<<6)

#define SFP_EEPROM_1G_COMP_CODE_ADDR  0x6
 #define SFP_EEPROM_1G_COMP_CODE_SX (1<<0)
 #define SFP_EEPROM_1G_COMP_CODE_LX (1<<1)
 #define SFP_EEPROM_1G_COMP_CODE_CX (1<<2)
 #define SFP_EEPROM_1G_COMP_CODE_BASE_T (1<<3)

#define SFP_EEPROM_FC_TX_TECH_ADDR  0x8
 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE 0x4
 #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE  0x8

#define SFP_EEPROM_OPTIONS_ADDR   0x40
 #define SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK 0x1
#define SFP_EEPROM_OPTIONS_SIZE   2

#define EDC_MODE_LINEAR    0x0022
#define EDC_MODE_LIMITING    0x0044
#define EDC_MODE_PASSIVE_DAC   0x0055
#define EDC_MODE_ACTIVE_DAC   0x0066

/* ETS defines*/
#define DCBX_INVALID_COS     (0xFF)

#define ETS_BW_LIMIT_CREDIT_UPPER_BOUND  (0x5000)
#define ETS_BW_LIMIT_CREDIT_WEIGHT  (0x5000)
#define ETS_E3B0_NIG_MIN_W_VAL_UP_TO_10GBPS  (1360)
#define ETS_E3B0_NIG_MIN_W_VAL_20GBPS   (2720)
#define ETS_E3B0_PBF_MIN_W_VAL    (10000)

#define MAX_PACKET_SIZE     (9700)
#define MAX_KR_LINK_RETRY    4
#define DEFAULT_TX_DRV_BRDCT  2
#define DEFAULT_TX_DRV_IFIR  0
#define DEFAULT_TX_DRV_POST2  3
#define DEFAULT_TX_DRV_IPRE_DRIVER 6

/**********************************************************/
/*                     INTERFACE                          */
/**********************************************************/

#define CL22_WR_OVER_CL45(_bp, _phy, _bank, _addr, _val) \
 bnx2x_cl45_write(_bp, _phy, \
  (_phy)->def_md_devad, \
  (_bank + (_addr & 0xf)), \
  _val)

#define CL22_RD_OVER_CL45(_bp, _phy, _bank, _addr, _val) \
 bnx2x_cl45_read(_bp, _phy, \
  (_phy)->def_md_devad, \
  (_bank + (_addr & 0xf)), \
  _val)

static int bnx2x_check_half_open_conn(struct link_params *params,
          struct link_vars *vars, u8 notify);
static int bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
          struct link_params *params);

static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits)
{
 u32 val = REG_RD(bp, reg);

 val |= bits;
 REG_WR(bp, reg, val);
 return val;
}

static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits)
{
 u32 val = REG_RD(bp, reg);

 val &= ~bits;
 REG_WR(bp, reg, val);
 return val;
}

/*
 * bnx2x_check_lfa - This function checks if link reinitialization is required,
 *                   or link flap can be avoided.
 *
 * @params: link parameters
 * Returns 0 if Link Flap Avoidance conditions are met otherwise, the failed
 *         condition code.
 */

static int bnx2x_check_lfa(struct link_params *params)
{
 u32 link_status, cfg_idx, lfa_mask, cfg_size;
 u32 cur_speed_cap_mask, cur_req_fc_auto_adv, additional_config;
 u32 saved_val, req_val, eee_status;
 struct bnx2x *bp = params->bp;

 additional_config =
  REG_RD(bp, params->lfa_base +
      offsetof(struct shmem_lfa, additional_config));

 /* NOTE: must be first condition checked -
* to verify DCC bit is cleared in any case!
*/

 if (additional_config & NO_LFA_DUE_TO_DCC_MASK) {
  DP(NETIF_MSG_LINK, "No LFA due to DCC flap after clp exit\n");
  REG_WR(bp, params->lfa_base +
      offsetof(struct shmem_lfa, additional_config),
         additional_config & ~NO_LFA_DUE_TO_DCC_MASK);
  return LFA_DCC_LFA_DISABLED;
 }

 /* Verify that link is up */
 link_status = REG_RD(bp, params->shmem_base +
        offsetof(struct shmem_region,
          port_mb[params->port].link_status));
 if (!(link_status & LINK_STATUS_LINK_UP))
  return LFA_LINK_DOWN;

 /* if loaded after BOOT from SAN, don't flap the link in any case and
 * rely on link set by preboot driver
 */

 if (params->feature_config_flags & FEATURE_CONFIG_BOOT_FROM_SAN)
  return 0;

 /* Verify that loopback mode is not set */
 if (params->loopback_mode)
  return LFA_LOOPBACK_ENABLED;

 /* Verify that MFW supports LFA */
 if (!params->lfa_base)
  return LFA_MFW_IS_TOO_OLD;

 if (params->num_phys == 3) {
  cfg_size = 2;
  lfa_mask = 0xffffffff;
 } else {
  cfg_size = 1;
  lfa_mask = 0xffff;
 }

 /* Compare Duplex */
 saved_val = REG_RD(bp, params->lfa_base +
      offsetof(struct shmem_lfa, req_duplex));
 req_val = params->req_duplex[0] | (params->req_duplex[1] << 16);
 if ((saved_val & lfa_mask) != (req_val & lfa_mask)) {
  DP(NETIF_MSG_LINK, "Duplex mismatch %x vs. %x\n",
          (saved_val & lfa_mask), (req_val & lfa_mask));
  return LFA_DUPLEX_MISMATCH;
 }
 /* Compare Flow Control */
 saved_val = REG_RD(bp, params->lfa_base +
      offsetof(struct shmem_lfa, req_flow_ctrl));
 req_val = params->req_flow_ctrl[0] | (params->req_flow_ctrl[1] << 16);
 if ((saved_val & lfa_mask) != (req_val & lfa_mask)) {
  DP(NETIF_MSG_LINK, "Flow control mismatch %x vs. %x\n",
          (saved_val & lfa_mask), (req_val & lfa_mask));
  return LFA_FLOW_CTRL_MISMATCH;
 }
 /* Compare Link Speed */
 saved_val = REG_RD(bp, params->lfa_base +
      offsetof(struct shmem_lfa, req_line_speed));
 req_val = params->req_line_speed[0] | (params->req_line_speed[1] << 16);
 if ((saved_val & lfa_mask) != (req_val & lfa_mask)) {
  DP(NETIF_MSG_LINK, "Link speed mismatch %x vs. %x\n",
          (saved_val & lfa_mask), (req_val & lfa_mask));
  return LFA_LINK_SPEED_MISMATCH;
 }

 for (cfg_idx = 0; cfg_idx < cfg_size; cfg_idx++) {
  cur_speed_cap_mask = REG_RD(bp, params->lfa_base +
         offsetof(struct shmem_lfa,
           speed_cap_mask[cfg_idx]));

  if (cur_speed_cap_mask != params->speed_cap_mask[cfg_idx]) {
   DP(NETIF_MSG_LINK, "Speed Cap mismatch %x vs. %x\n",
           cur_speed_cap_mask,
           params->speed_cap_mask[cfg_idx]);
   return LFA_SPEED_CAP_MISMATCH;
  }
 }

 cur_req_fc_auto_adv =
  REG_RD(bp, params->lfa_base +
         offsetof(struct shmem_lfa, additional_config)) &
  REQ_FC_AUTO_ADV_MASK;

 if ((u16)cur_req_fc_auto_adv != params->req_fc_auto_adv) {
  DP(NETIF_MSG_LINK, "Flow Ctrl AN mismatch %x vs. %x\n",
          cur_req_fc_auto_adv, params->req_fc_auto_adv);
  return LFA_FLOW_CTRL_MISMATCH;
 }

 eee_status = REG_RD(bp, params->shmem2_base +
       offsetof(struct shmem2_region,
         eee_status[params->port]));

 if (((eee_status & SHMEM_EEE_LPI_REQUESTED_BIT) ^
      (params->eee_mode & EEE_MODE_ENABLE_LPI)) ||
     ((eee_status & SHMEM_EEE_REQUESTED_BIT) ^
      (params->eee_mode & EEE_MODE_ADV_LPI))) {
  DP(NETIF_MSG_LINK, "EEE mismatch %x vs. %x\n", params->eee_mode,
          eee_status);
  return LFA_EEE_MISMATCH;
 }

 /* LFA conditions are met */
 return 0;
}
/******************************************************************/
/* EPIO/GPIO section   */
/******************************************************************/
static void bnx2x_get_epio(struct bnx2x *bp, u32 epio_pin, u32 *en)
{
 u32 epio_mask, gp_oenable;
 *en = 0;
 /* Sanity check */
 if (epio_pin > 31) {
  DP(NETIF_MSG_LINK, "Invalid EPIO pin %d to get\n", epio_pin);
  return;
 }

 epio_mask = 1 << epio_pin;
 /* Set this EPIO to output */
 gp_oenable = REG_RD(bp, MCP_REG_MCPR_GP_OENABLE);
 REG_WR(bp, MCP_REG_MCPR_GP_OENABLE, gp_oenable & ~epio_mask);

 *en = (REG_RD(bp, MCP_REG_MCPR_GP_INPUTS) & epio_mask) >> epio_pin;
}
static void bnx2x_set_epio(struct bnx2x *bp, u32 epio_pin, u32 en)
{
 u32 epio_mask, gp_output, gp_oenable;

 /* Sanity check */
 if (epio_pin > 31) {
  DP(NETIF_MSG_LINK, "Invalid EPIO pin %d to set\n", epio_pin);
  return;
 }
 DP(NETIF_MSG_LINK, "Setting EPIO pin %d to %d\n", epio_pin, en);
 epio_mask = 1 << epio_pin;
 /* Set this EPIO to output */
 gp_output = REG_RD(bp, MCP_REG_MCPR_GP_OUTPUTS);
 if (en)
  gp_output |= epio_mask;
 else
  gp_output &= ~epio_mask;

 REG_WR(bp, MCP_REG_MCPR_GP_OUTPUTS, gp_output);

 /* Set the value for this EPIO */
 gp_oenable = REG_RD(bp, MCP_REG_MCPR_GP_OENABLE);
 REG_WR(bp, MCP_REG_MCPR_GP_OENABLE, gp_oenable | epio_mask);
}

static void bnx2x_set_cfg_pin(struct bnx2x *bp, u32 pin_cfg, u32 val)
{
 if (pin_cfg == PIN_CFG_NA)
  return;
 if (pin_cfg >= PIN_CFG_EPIO0) {
  bnx2x_set_epio(bp, pin_cfg - PIN_CFG_EPIO0, val);
 } else {
  u8 gpio_num = (pin_cfg - PIN_CFG_GPIO0_P0) & 0x3;
  u8 gpio_port = (pin_cfg - PIN_CFG_GPIO0_P0) >> 2;
  bnx2x_set_gpio(bp, gpio_num, (u8)val, gpio_port);
 }
}

static u32 bnx2x_get_cfg_pin(struct bnx2x *bp, u32 pin_cfg, u32 *val)
{
 if (pin_cfg == PIN_CFG_NA)
  return -EINVAL;
 if (pin_cfg >= PIN_CFG_EPIO0) {
  bnx2x_get_epio(bp, pin_cfg - PIN_CFG_EPIO0, val);
 } else {
  u8 gpio_num = (pin_cfg - PIN_CFG_GPIO0_P0) & 0x3;
  u8 gpio_port = (pin_cfg - PIN_CFG_GPIO0_P0) >> 2;
  *val = bnx2x_get_gpio(bp, gpio_num, gpio_port);
 }
 return 0;

}
/******************************************************************/
/* ETS section   */
/******************************************************************/
static void bnx2x_ets_e2e3a0_disabled(struct link_params *params)
{
 /* ETS disabled configuration*/
 struct bnx2x *bp = params->bp;

 DP(NETIF_MSG_LINK, "ETS E2E3 disabled configuration\n");

 /* mapping between entry  priority to client number (0,1,2 -debug and
 * management clients, 3 - COS0 client, 4 - COS client)(HIGHEST)
 * 3bits client num.
 *   PRI4    |    PRI3    |    PRI2    |    PRI1    |    PRI0
 * cos1-100     cos0-011     dbg1-010     dbg0-001     MCP-000
 */


 REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, 0x4688);
 /* Bitmap of 5bits length. Each bit specifies whether the entry behaves
 * as strict.  Bits 0,1,2 - debug and management entries, 3 -
 * COS0 entry, 4 - COS1 entry.
 * COS1 | COS0 | DEBUG1 | DEBUG0 | MGMT
 * bit4   bit3   bit2   bit1   bit0
 * MCP and debug are strict
 */


 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7);
 /* defines which entries (clients) are subjected to WFQ arbitration */
 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0);
 /* For strict priority entries defines the number of consecutive
 * slots for the highest priority.
 */

 REG_WR(bp, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100);
 /* mapping between the CREDIT_WEIGHT registers and actual client
 * numbers
 */

 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0);
 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, 0);
 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, 0);

 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0, 0);
 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1, 0);
 REG_WR(bp, PBF_REG_HIGH_PRIORITY_COS_NUM, 0);
 /* ETS mode disable */
 REG_WR(bp, PBF_REG_ETS_ENABLED, 0);
 /* If ETS mode is enabled (there is no strict priority) defines a WFQ
 * weight for COS0/COS1.
 */

 REG_WR(bp, PBF_REG_COS0_WEIGHT, 0x2710);
 REG_WR(bp, PBF_REG_COS1_WEIGHT, 0x2710);
 /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter */
 REG_WR(bp, PBF_REG_COS0_UPPER_BOUND, 0x989680);
 REG_WR(bp, PBF_REG_COS1_UPPER_BOUND, 0x989680);
 /* Defines the number of consecutive slots for the strict priority */
 REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0);
}
/******************************************************************************
* Description:
* Getting min_w_val will be set according to line speed .
*.
******************************************************************************/

static u32 bnx2x_ets_get_min_w_val_nig(const struct link_vars *vars)
{
 u32 min_w_val = 0;
 /* Calculate min_w_val.*/
 if (vars->link_up) {
  if (vars->line_speed == SPEED_20000)
   min_w_val = ETS_E3B0_NIG_MIN_W_VAL_20GBPS;
  else
   min_w_val = ETS_E3B0_NIG_MIN_W_VAL_UP_TO_10GBPS;
 } else
  min_w_val = ETS_E3B0_NIG_MIN_W_VAL_20GBPS;
 /* If the link isn't up (static configuration for example ) The
 * link will be according to 20GBPS.
 */

 return min_w_val;
}
/******************************************************************************
* Description:
* Getting credit upper bound form min_w_val.
*.
******************************************************************************/

static u32 bnx2x_ets_get_credit_upper_bound(const u32 min_w_val)
{
 const u32 credit_upper_bound = (u32)MAXVAL((150 * min_w_val),
      MAX_PACKET_SIZE);
 return credit_upper_bound;
}
/******************************************************************************
* Description:
* Set credit upper bound for NIG.
*.
******************************************************************************/

static void bnx2x_ets_e3b0_set_credit_upper_bound_nig(
 const struct link_params *params,
 const u32 min_w_val)
{
 struct bnx2x *bp = params->bp;
 const u8 port = params->port;
 const u32 credit_upper_bound =
     bnx2x_ets_get_credit_upper_bound(min_w_val);

 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_0 :
  NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0, credit_upper_bound);
 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_1 :
     NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1, credit_upper_bound);
 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_2 :
     NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_2, credit_upper_bound);
 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_3 :
     NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_3, credit_upper_bound);
 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_4 :
     NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_4, credit_upper_bound);
 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_5 :
     NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_5, credit_upper_bound);

 if (!port) {
  REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_6,
   credit_upper_bound);
  REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_7,
   credit_upper_bound);
  REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_8,
   credit_upper_bound);
 }
}
/******************************************************************************
* Description:
* Will return the NIG ETS registers to init values.Except
* credit_upper_bound.
* That isn't used in this configuration (No WFQ is enabled) and will be
* configured according to spec
*.
******************************************************************************/

static void bnx2x_ets_e3b0_nig_disabled(const struct link_params *params,
     const struct link_vars *vars)
{
 struct bnx2x *bp = params->bp;
 const u8 port = params->port;
 const u32 min_w_val = bnx2x_ets_get_min_w_val_nig(vars);
 /* Mapping between entry  priority to client number (0,1,2 -debug and
 * management clients, 3 - COS0 client, 4 - COS1, ... 8 -
 * COS5)(HIGHEST) 4bits client num.TODO_ETS - Should be done by
 * reset value or init tool
 */

 if (port) {
  REG_WR(bp, NIG_REG_P1_TX_ARB_PRIORITY_CLIENT2_LSB, 0x543210);
  REG_WR(bp, NIG_REG_P1_TX_ARB_PRIORITY_CLIENT2_MSB, 0x0);
 } else {
  REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT2_LSB, 0x76543210);
  REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT2_MSB, 0x8);
 }
 /* For strict priority entries defines the number of consecutive
 * slots for the highest priority.
 */

 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_NUM_STRICT_ARB_SLOTS :
     NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100);
 /* Mapping between the CREDIT_WEIGHT registers and actual client
 * numbers
 */

 if (port) {
  /*Port 1 has 6 COS*/
  REG_WR(bp, NIG_REG_P1_TX_ARB_CLIENT_CREDIT_MAP2_LSB, 0x210543);
  REG_WR(bp, NIG_REG_P1_TX_ARB_CLIENT_CREDIT_MAP2_MSB, 0x0);
 } else {
  /*Port 0 has 9 COS*/
  REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP2_LSB,
         0x43210876);
  REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP2_MSB, 0x5);
 }

 /* Bitmap of 5bits length. Each bit specifies whether the entry behaves
 * as strict.  Bits 0,1,2 - debug and management entries, 3 -
 * COS0 entry, 4 - COS1 entry.
 * COS1 | COS0 | DEBUG1 | DEBUG0 | MGMT
 * bit4   bit3   bit2   bit1   bit0
 * MCP and debug are strict
 */

 if (port)
  REG_WR(bp, NIG_REG_P1_TX_ARB_CLIENT_IS_STRICT, 0x3f);
 else
  REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x1ff);
 /* defines which entries (clients) are subjected to WFQ arbitration */
 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CLIENT_IS_SUBJECT2WFQ :
     NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0);

 /* Please notice the register address are note continuous and a
 * for here is note appropriate.In 2 port mode port0 only COS0-5
 * can be used. DEBUG1,DEBUG1,MGMT are never used for WFQ* In 4
 * port mode port1 only COS0-2 can be used. DEBUG1,DEBUG1,MGMT
 * are never used for WFQ
 */

 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_0 :
     NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, 0x0);
 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_1 :
     NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, 0x0);
 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_2 :
     NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_2, 0x0);
 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_3 :
     NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_3, 0x0);
 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_4 :
     NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_4, 0x0);
 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_5 :
     NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_5, 0x0);
 if (!port) {
  REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_6, 0x0);
  REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_7, 0x0);
  REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_8, 0x0);
 }

 bnx2x_ets_e3b0_set_credit_upper_bound_nig(params, min_w_val);
}
/******************************************************************************
* Description:
* Set credit upper bound for PBF.
*.
******************************************************************************/

static void bnx2x_ets_e3b0_set_credit_upper_bound_pbf(
 const struct link_params *params,
 const u32 min_w_val)
{
 struct bnx2x *bp = params->bp;
 const u32 credit_upper_bound =
     bnx2x_ets_get_credit_upper_bound(min_w_val);
 const u8 port = params->port;
 u32 base_upper_bound = 0;
 u8 max_cos = 0;
 u8 i = 0;
 /* In 2 port mode port0 has COS0-5 that can be used for WFQ.In 4
 * port mode port1 has COS0-2 that can be used for WFQ.
 */

 if (!port) {
  base_upper_bound = PBF_REG_COS0_UPPER_BOUND_P0;
  max_cos = DCBX_E3B0_MAX_NUM_COS_PORT0;
 } else {
  base_upper_bound = PBF_REG_COS0_UPPER_BOUND_P1;
  max_cos = DCBX_E3B0_MAX_NUM_COS_PORT1;
 }

 for (i = 0; i < max_cos; i++)
  REG_WR(bp, base_upper_bound + (i << 2), credit_upper_bound);
}

/******************************************************************************
* Description:
* Will return the PBF ETS registers to init values.Except
* credit_upper_bound.
* That isn't used in this configuration (No WFQ is enabled) and will be
* configured according to spec
*.
******************************************************************************/

static void bnx2x_ets_e3b0_pbf_disabled(const struct link_params *params)
{
 struct bnx2x *bp = params->bp;
 const u8 port = params->port;
 const u32 min_w_val_pbf = ETS_E3B0_PBF_MIN_W_VAL;
 u8 i = 0;
 u32 base_weight = 0;
 u8 max_cos = 0;

 /* Mapping between entry  priority to client number 0 - COS0
 * client, 2 - COS1, ... 5 - COS5)(HIGHEST) 4bits client num.
 * TODO_ETS - Should be done by reset value or init tool
 */

 if (port)
  /*  0x688 (|011|0 10|00 1|000) */
  REG_WR(bp, PBF_REG_ETS_ARB_PRIORITY_CLIENT_P1 , 0x688);
 else
  /*  (10 1|100 |011|0 10|00 1|000) */
  REG_WR(bp, PBF_REG_ETS_ARB_PRIORITY_CLIENT_P0 , 0x2C688);

 /* TODO_ETS - Should be done by reset value or init tool */
 if (port)
  /* 0x688 (|011|0 10|00 1|000)*/
  REG_WR(bp, PBF_REG_ETS_ARB_CLIENT_CREDIT_MAP_P1, 0x688);
 else
 /* 0x2C688 (10 1|100 |011|0 10|00 1|000) */
 REG_WR(bp, PBF_REG_ETS_ARB_CLIENT_CREDIT_MAP_P0, 0x2C688);

 REG_WR(bp, (port) ? PBF_REG_ETS_ARB_NUM_STRICT_ARB_SLOTS_P1 :
     PBF_REG_ETS_ARB_NUM_STRICT_ARB_SLOTS_P0 , 0x100);


 REG_WR(bp, (port) ? PBF_REG_ETS_ARB_CLIENT_IS_STRICT_P1 :
     PBF_REG_ETS_ARB_CLIENT_IS_STRICT_P0 , 0);

 REG_WR(bp, (port) ? PBF_REG_ETS_ARB_CLIENT_IS_SUBJECT2WFQ_P1 :
     PBF_REG_ETS_ARB_CLIENT_IS_SUBJECT2WFQ_P0 , 0);
 /* In 2 port mode port0 has COS0-5 that can be used for WFQ.
 * In 4 port mode port1 has COS0-2 that can be used for WFQ.
 */

 if (!port) {
  base_weight = PBF_REG_COS0_WEIGHT_P0;
  max_cos = DCBX_E3B0_MAX_NUM_COS_PORT0;
 } else {
  base_weight = PBF_REG_COS0_WEIGHT_P1;
  max_cos = DCBX_E3B0_MAX_NUM_COS_PORT1;
 }

 for (i = 0; i < max_cos; i++)
  REG_WR(bp, base_weight + (0x4 * i), 0);

 bnx2x_ets_e3b0_set_credit_upper_bound_pbf(params, min_w_val_pbf);
}
/******************************************************************************
* Description:
* E3B0 disable will return basically the values to init values.
*.
******************************************************************************/

static int bnx2x_ets_e3b0_disabled(const struct link_params *params,
       const struct link_vars *vars)
{
 struct bnx2x *bp = params->bp;

 if (!CHIP_IS_E3B0(bp)) {
  DP(NETIF_MSG_LINK,
     "bnx2x_ets_e3b0_disabled the chip isn't E3B0\n");
  return -EINVAL;
 }

 bnx2x_ets_e3b0_nig_disabled(params, vars);

 bnx2x_ets_e3b0_pbf_disabled(params);

 return 0;
}

/******************************************************************************
* Description:
* Disable will return basically the values to init values.
*
******************************************************************************/

int bnx2x_ets_disabled(struct link_params *params,
        struct link_vars *vars)
{
 struct bnx2x *bp = params->bp;
 int bnx2x_status = 0;

 if ((CHIP_IS_E2(bp)) || (CHIP_IS_E3A0(bp)))
  bnx2x_ets_e2e3a0_disabled(params);
 else if (CHIP_IS_E3B0(bp))
  bnx2x_status = bnx2x_ets_e3b0_disabled(params, vars);
 else {
  DP(NETIF_MSG_LINK, "bnx2x_ets_disabled - chip not supported\n");
  return -EINVAL;
 }

 return bnx2x_status;
}

/******************************************************************************
* Description
* Set the COS mappimg to SP and BW until this point all the COS are not
* set as SP or BW.
******************************************************************************/

static int bnx2x_ets_e3b0_cli_map(const struct link_params *params,
      const struct bnx2x_ets_params *ets_params,
      const u8 cos_sp_bitmap,
      const u8 cos_bw_bitmap)
{
 struct bnx2x *bp = params->bp;
 const u8 port = params->port;
 const u8 nig_cli_sp_bitmap = 0x7 | (cos_sp_bitmap << 3);
 const u8 pbf_cli_sp_bitmap = cos_sp_bitmap;
 const u8 nig_cli_subject2wfq_bitmap = cos_bw_bitmap << 3;
 const u8 pbf_cli_subject2wfq_bitmap = cos_bw_bitmap;

 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CLIENT_IS_STRICT :
        NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, nig_cli_sp_bitmap);

 REG_WR(bp, (port) ? PBF_REG_ETS_ARB_CLIENT_IS_STRICT_P1 :
        PBF_REG_ETS_ARB_CLIENT_IS_STRICT_P0 , pbf_cli_sp_bitmap);

 REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CLIENT_IS_SUBJECT2WFQ :
        NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ,
        nig_cli_subject2wfq_bitmap);

 REG_WR(bp, (port) ? PBF_REG_ETS_ARB_CLIENT_IS_SUBJECT2WFQ_P1 :
        PBF_REG_ETS_ARB_CLIENT_IS_SUBJECT2WFQ_P0,
        pbf_cli_subject2wfq_bitmap);

 return 0;
}

/******************************************************************************
* Description:
* This function is needed because NIG ARB_CREDIT_WEIGHT_X are
* not continues and ARB_CREDIT_WEIGHT_0 + offset is suitable.
******************************************************************************/

static int bnx2x_ets_e3b0_set_cos_bw(struct bnx2x *bp,
         const u8 cos_entry,
         const u32 min_w_val_nig,
         const u32 min_w_val_pbf,
         const u16 total_bw,
         const u8 bw,
         const u8 port)
{
 u32 nig_reg_adress_crd_weight = 0;
 u32 pbf_reg_adress_crd_weight = 0;
 /* Calculate and set BW for this COS - use 1 instead of 0 for BW */
 const u32 cos_bw_nig = ((bw ? bw : 1) * min_w_val_nig) / total_bw;
 const u32 cos_bw_pbf = ((bw ? bw : 1) * min_w_val_pbf) / total_bw;

 switch (cos_entry) {
 case 0:
  nig_reg_adress_crd_weight =
   (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_0 :
   NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0;
  pbf_reg_adress_crd_weight = (port) ?
      PBF_REG_COS0_WEIGHT_P1 : PBF_REG_COS0_WEIGHT_P0;
  break;
 case 1:
  nig_reg_adress_crd_weight = (port) ?
   NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_1 :
   NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1;
  pbf_reg_adress_crd_weight = (port) ?
   PBF_REG_COS1_WEIGHT_P1 : PBF_REG_COS1_WEIGHT_P0;
  break;
 case 2:
  nig_reg_adress_crd_weight = (port) ?
   NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_2 :
   NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_2;

  pbf_reg_adress_crd_weight = (port) ?
   PBF_REG_COS2_WEIGHT_P1 : PBF_REG_COS2_WEIGHT_P0;
  break;
 case 3:
  if (port)
   return -EINVAL;
  nig_reg_adress_crd_weight = NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_3;
  pbf_reg_adress_crd_weight = PBF_REG_COS3_WEIGHT_P0;
  break;
 case 4:
  if (port)
   return -EINVAL;
  nig_reg_adress_crd_weight = NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_4;
  pbf_reg_adress_crd_weight = PBF_REG_COS4_WEIGHT_P0;
  break;
 case 5:
  if (port)
   return -EINVAL;
  nig_reg_adress_crd_weight = NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_5;
  pbf_reg_adress_crd_weight = PBF_REG_COS5_WEIGHT_P0;
  break;
 }

 REG_WR(bp, nig_reg_adress_crd_weight, cos_bw_nig);

 REG_WR(bp, pbf_reg_adress_crd_weight, cos_bw_pbf);

 return 0;
}
/******************************************************************************
* Description:
* Calculate the total BW.A value of 0 isn't legal.
*
******************************************************************************/

static int bnx2x_ets_e3b0_get_total_bw(
 const struct link_params *params,
 struct bnx2x_ets_params *ets_params,
 u16 *total_bw)
{
 struct bnx2x *bp = params->bp;
 u8 cos_idx = 0;
 u8 is_bw_cos_exist = 0;

 *total_bw = 0 ;
 /* Calculate total BW requested */
 for (cos_idx = 0; cos_idx < ets_params->num_of_cos; cos_idx++) {
  if (ets_params->cos[cos_idx].state == bnx2x_cos_state_bw) {
   is_bw_cos_exist = 1;
   if (!ets_params->cos[cos_idx].params.bw_params.bw) {
    DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config BW"
         "was set to 0\n");
    /* This is to prevent a state when ramrods
 * can't be sent
 */

    ets_params->cos[cos_idx].params.bw_params.bw
      = 1;
   }
   *total_bw +=
    ets_params->cos[cos_idx].params.bw_params.bw;
  }
 }

 /* Check total BW is valid */
 if ((is_bw_cos_exist == 1) && (*total_bw != 100)) {
  if (*total_bw == 0) {
   DP(NETIF_MSG_LINK,
      "bnx2x_ets_E3B0_config total BW shouldn't be 0\n");
   return -EINVAL;
  }
  DP(NETIF_MSG_LINK,
     "bnx2x_ets_E3B0_config total BW should be 100\n");
  /* We can handle a case whre the BW isn't 100 this can happen
 * if the TC are joined.
 */

 }
 return 0;
}

/******************************************************************************
* Description:
* Invalidate all the sp_pri_to_cos.
*
******************************************************************************/

static void bnx2x_ets_e3b0_sp_pri_to_cos_init(u8 *sp_pri_to_cos)
{
 u8 pri = 0;
 for (pri = 0; pri < DCBX_MAX_NUM_COS; pri++)
  sp_pri_to_cos[pri] = DCBX_INVALID_COS;
}
/******************************************************************************
* Description:
* Calculate and set the SP (ARB_PRIORITY_CLIENT) NIG and PBF registers
* according to sp_pri_to_cos.
*
******************************************************************************/

static int bnx2x_ets_e3b0_sp_pri_to_cos_set(const struct link_params *params,
         u8 *sp_pri_to_cos, const u8 pri,
         const u8 cos_entry)
{
 struct bnx2x *bp = params->bp;
 const u8 port = params->port;
 const u8 max_num_of_cos = (port) ? DCBX_E3B0_MAX_NUM_COS_PORT1 :
  DCBX_E3B0_MAX_NUM_COS_PORT0;

 if (pri >= max_num_of_cos) {
  DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_sp_pri_to_cos_set invalid "
     "parameter Illegal strict priority\n");
  return -EINVAL;
 }

 if (sp_pri_to_cos[pri] != DCBX_INVALID_COS) {
  DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_sp_pri_to_cos_set invalid "
       "parameter There can't be two COS's with "
       "the same strict pri\n");
  return -EINVAL;
 }

 sp_pri_to_cos[pri] = cos_entry;
 return 0;

}

/******************************************************************************
* Description:
* Returns the correct value according to COS and priority in
* the sp_pri_cli register.
*
******************************************************************************/

static u64 bnx2x_e3b0_sp_get_pri_cli_reg(const u8 cos, const u8 cos_offset,
      const u8 pri_set,
      const u8 pri_offset,
      const u8 entry_size)
{
 u64 pri_cli_nig = 0;
 pri_cli_nig = ((u64)(cos + cos_offset)) << (entry_size *
          (pri_set + pri_offset));

 return pri_cli_nig;
}
/******************************************************************************
* Description:
* Returns the correct value according to COS and priority in the
* sp_pri_cli register for NIG.
*
******************************************************************************/

static u64 bnx2x_e3b0_sp_get_pri_cli_reg_nig(const u8 cos, const u8 pri_set)
{
 /* MCP Dbg0 and dbg1 are always with higher strict pri*/
 const u8 nig_cos_offset = 3;
 const u8 nig_pri_offset = 3;

 return bnx2x_e3b0_sp_get_pri_cli_reg(cos, nig_cos_offset, pri_set,
  nig_pri_offset, 4);

}
/******************************************************************************
* Description:
* Returns the correct value according to COS and priority in the
* sp_pri_cli register for PBF.
*
******************************************************************************/

static u64 bnx2x_e3b0_sp_get_pri_cli_reg_pbf(const u8 cos, const u8 pri_set)
{
 const u8 pbf_cos_offset = 0;
 const u8 pbf_pri_offset = 0;

 return bnx2x_e3b0_sp_get_pri_cli_reg(cos, pbf_cos_offset, pri_set,
  pbf_pri_offset, 3);

}

/******************************************************************************
* Description:
* Calculate and set the SP (ARB_PRIORITY_CLIENT) NIG and PBF registers
* according to sp_pri_to_cos.(which COS has higher priority)
*
******************************************************************************/

static int bnx2x_ets_e3b0_sp_set_pri_cli_reg(const struct link_params *params,
          u8 *sp_pri_to_cos)
{
 struct bnx2x *bp = params->bp;
 u8 i = 0;
 const u8 port = params->port;
 /* MCP Dbg0 and dbg1 are always with higher strict pri*/
 u64 pri_cli_nig = 0x210;
 u32 pri_cli_pbf = 0x0;
 u8 pri_set = 0;
 u8 pri_bitmask = 0;
 const u8 max_num_of_cos = (port) ? DCBX_E3B0_MAX_NUM_COS_PORT1 :
  DCBX_E3B0_MAX_NUM_COS_PORT0;

 u8 cos_bit_to_set = (1 << max_num_of_cos) - 1;

 /* Set all the strict priority first */
 for (i = 0; i < max_num_of_cos; i++) {
  if (sp_pri_to_cos[i] != DCBX_INVALID_COS) {
   if (sp_pri_to_cos[i] >= DCBX_MAX_NUM_COS) {
    DP(NETIF_MSG_LINK,
        "bnx2x_ets_e3b0_sp_set_pri_cli_reg "
        "invalid cos entry\n");
    return -EINVAL;
   }

   pri_cli_nig |= bnx2x_e3b0_sp_get_pri_cli_reg_nig(
       sp_pri_to_cos[i], pri_set);

   pri_cli_pbf |= bnx2x_e3b0_sp_get_pri_cli_reg_pbf(
       sp_pri_to_cos[i], pri_set);
   pri_bitmask = 1 << sp_pri_to_cos[i];
   /* COS is used remove it from bitmap.*/
   if (!(pri_bitmask & cos_bit_to_set)) {
    DP(NETIF_MSG_LINK,
     "bnx2x_ets_e3b0_sp_set_pri_cli_reg "
     "invalid There can't be two COS's with"
     " the same strict pri\n");
    return -EINVAL;
   }
   cos_bit_to_set &= ~pri_bitmask;
   pri_set++;
  }
 }

 /* Set all the Non strict priority i= COS*/
 for (i = 0; i < max_num_of_cos; i++) {
  pri_bitmask = 1 << i;
  /* Check if COS was already used for SP */
  if (pri_bitmask & cos_bit_to_set) {
   /* COS wasn't used for SP */
   pri_cli_nig |= bnx2x_e3b0_sp_get_pri_cli_reg_nig(
       i, pri_set);

   pri_cli_pbf |= bnx2x_e3b0_sp_get_pri_cli_reg_pbf(
       i, pri_set);
   /* COS is used remove it from bitmap.*/
   cos_bit_to_set &= ~pri_bitmask;
   pri_set++;
  }
 }

 if (pri_set != max_num_of_cos) {
  DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_sp_set_pri_cli_reg not all "
       "entries were set\n");
  return -EINVAL;
 }

 if (port) {
  /* Only 6 usable clients*/
  REG_WR(bp, NIG_REG_P1_TX_ARB_PRIORITY_CLIENT2_LSB,
         (u32)pri_cli_nig);

  REG_WR(bp, PBF_REG_ETS_ARB_PRIORITY_CLIENT_P1 , pri_cli_pbf);
 } else {
  /* Only 9 usable clients*/
  const u32 pri_cli_nig_lsb = (u32) (pri_cli_nig);
  const u32 pri_cli_nig_msb = (u32) ((pri_cli_nig >> 32) & 0xF);

  REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT2_LSB,
         pri_cli_nig_lsb);
  REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT2_MSB,
         pri_cli_nig_msb);

  REG_WR(bp, PBF_REG_ETS_ARB_PRIORITY_CLIENT_P0 , pri_cli_pbf);
 }
 return 0;
}

/******************************************************************************
* Description:
* Configure the COS to ETS according to BW and SP settings.
******************************************************************************/

int bnx2x_ets_e3b0_config(const struct link_params *params,
    const struct link_vars *vars,
    struct bnx2x_ets_params *ets_params)
{
 struct bnx2x *bp = params->bp;
 int bnx2x_status = 0;
 const u8 port = params->port;
 u16 total_bw = 0;
 const u32 min_w_val_nig = bnx2x_ets_get_min_w_val_nig(vars);
 const u32 min_w_val_pbf = ETS_E3B0_PBF_MIN_W_VAL;
 u8 cos_bw_bitmap = 0;
 u8 cos_sp_bitmap = 0;
 u8 sp_pri_to_cos[DCBX_MAX_NUM_COS] = {0};
 const u8 max_num_of_cos = (port) ? DCBX_E3B0_MAX_NUM_COS_PORT1 :
  DCBX_E3B0_MAX_NUM_COS_PORT0;
 u8 cos_entry = 0;

 if (!CHIP_IS_E3B0(bp)) {
  DP(NETIF_MSG_LINK,
     "bnx2x_ets_e3b0_disabled the chip isn't E3B0\n");
  return -EINVAL;
 }

 if ((ets_params->num_of_cos > max_num_of_cos)) {
  DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config the number of COS "
       "isn't supported\n");
  return -EINVAL;
 }

 /* Prepare sp strict priority parameters*/
 bnx2x_ets_e3b0_sp_pri_to_cos_init(sp_pri_to_cos);

 /* Prepare BW parameters*/
 bnx2x_status = bnx2x_ets_e3b0_get_total_bw(params, ets_params,
         &total_bw);
 if (bnx2x_status) {
  DP(NETIF_MSG_LINK,
     "bnx2x_ets_E3B0_config get_total_bw failed\n");
  return -EINVAL;
 }

 /* Upper bound is set according to current link speed (min_w_val
 * should be the same for upper bound and COS credit val).
 */

 bnx2x_ets_e3b0_set_credit_upper_bound_nig(params, min_w_val_nig);
 bnx2x_ets_e3b0_set_credit_upper_bound_pbf(params, min_w_val_pbf);


 for (cos_entry = 0; cos_entry < ets_params->num_of_cos; cos_entry++) {
  if (bnx2x_cos_state_bw == ets_params->cos[cos_entry].state) {
   cos_bw_bitmap |= (1 << cos_entry);
   /* The function also sets the BW in HW(not the mappin
 * yet)
 */

   bnx2x_status = bnx2x_ets_e3b0_set_cos_bw(
    bp, cos_entry, min_w_val_nig, min_w_val_pbf,
    total_bw,
    ets_params->cos[cos_entry].params.bw_params.bw,
     port);
  } else if (bnx2x_cos_state_strict ==
   ets_params->cos[cos_entry].state){
   cos_sp_bitmap |= (1 << cos_entry);

   bnx2x_status = bnx2x_ets_e3b0_sp_pri_to_cos_set(
    params,
    sp_pri_to_cos,
    ets_params->cos[cos_entry].params.sp_params.pri,
    cos_entry);

  } else {
   DP(NETIF_MSG_LINK,
      "bnx2x_ets_e3b0_config cos state not valid\n");
   return -EINVAL;
  }
  if (bnx2x_status) {
   DP(NETIF_MSG_LINK,
      "bnx2x_ets_e3b0_config set cos bw failed\n");
   return bnx2x_status;
  }
 }

 /* Set SP register (which COS has higher priority) */
 bnx2x_status = bnx2x_ets_e3b0_sp_set_pri_cli_reg(params,
        sp_pri_to_cos);

 if (bnx2x_status) {
  DP(NETIF_MSG_LINK,
     "bnx2x_ets_E3B0_config set_pri_cli_reg failed\n");
  return bnx2x_status;
 }

 /* Set client mapping of BW and strict */
 bnx2x_status = bnx2x_ets_e3b0_cli_map(params, ets_params,
           cos_sp_bitmap,
           cos_bw_bitmap);

 if (bnx2x_status) {
  DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config SP failed\n");
  return bnx2x_status;
 }
 return 0;
}
static void bnx2x_ets_bw_limit_common(const struct link_params *params)
{
 /* ETS disabled configuration */
 struct bnx2x *bp = params->bp;
 DP(NETIF_MSG_LINK, "ETS enabled BW limit configuration\n");
 /* Defines which entries (clients) are subjected to WFQ arbitration
 * COS0 0x8
 * COS1 0x10
 */

 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0x18);
 /* Mapping between the ARB_CREDIT_WEIGHT registers and actual
 * client numbers (WEIGHT_0 does not actually have to represent
 * client 0)
 *    PRI4    |    PRI3    |    PRI2    |    PRI1    |    PRI0
 *  cos1-001     cos0-000     dbg1-100     dbg0-011     MCP-010
 */

 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0x111A);

 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0,
        ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1,
        ETS_BW_LIMIT_CREDIT_UPPER_BOUND);

 /* ETS mode enabled*/
 REG_WR(bp, PBF_REG_ETS_ENABLED, 1);

 /* Defines the number of consecutive slots for the strict priority */
 REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0);
 /* Bitmap of 5bits length. Each bit specifies whether the entry behaves
 * as strict.  Bits 0,1,2 - debug and management entries, 3 - COS0
 * entry, 4 - COS1 entry.
 * COS1 | COS0 | DEBUG21 | DEBUG0 | MGMT
 * bit4   bit3   bit2     bit1    bit0
 * MCP and debug are strict
 */

 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7);

 /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter.*/
 REG_WR(bp, PBF_REG_COS0_UPPER_BOUND,
        ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
 REG_WR(bp, PBF_REG_COS1_UPPER_BOUND,
        ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
}

void bnx2x_ets_bw_limit(const struct link_params *params, const u32 cos0_bw,
   const u32 cos1_bw)
{
 /* ETS disabled configuration*/
 struct bnx2x *bp = params->bp;
 const u32 total_bw = cos0_bw + cos1_bw;
 u32 cos0_credit_weight = 0;
 u32 cos1_credit_weight = 0;

 DP(NETIF_MSG_LINK, "ETS enabled BW limit configuration\n");

 if ((!total_bw) ||
     (!cos0_bw) ||
     (!cos1_bw)) {
  DP(NETIF_MSG_LINK, "Total BW can't be zero\n");
  return;
 }

 cos0_credit_weight = (cos0_bw * ETS_BW_LIMIT_CREDIT_WEIGHT)/
  total_bw;
 cos1_credit_weight = (cos1_bw * ETS_BW_LIMIT_CREDIT_WEIGHT)/
  total_bw;

 bnx2x_ets_bw_limit_common(params);

 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, cos0_credit_weight);
 REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, cos1_credit_weight);

 REG_WR(bp, PBF_REG_COS0_WEIGHT, cos0_credit_weight);
 REG_WR(bp, PBF_REG_COS1_WEIGHT, cos1_credit_weight);
}

int bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos)
{
 /* ETS disabled configuration*/
 struct bnx2x *bp = params->bp;
 u32 val = 0;

 DP(NETIF_MSG_LINK, "ETS enabled strict configuration\n");
 /* Bitmap of 5bits length. Each bit specifies whether the entry behaves
 * as strict.  Bits 0,1,2 - debug and management entries,
 * 3 - COS0 entry, 4 - COS1 entry.
 *  COS1 | COS0 | DEBUG21 | DEBUG0 | MGMT
 *  bit4   bit3   bit2      bit1     bit0
 * MCP and debug are strict
 */

 REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x1F);
 /* For strict priority entries defines the number of consecutive slots
 * for the highest priority.
 */

 REG_WR(bp, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100);
 /* ETS mode disable */
 REG_WR(bp, PBF_REG_ETS_ENABLED, 0);
 /* Defines the number of consecutive slots for the strict priority */
 REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0x100);

 /* Defines the number of consecutive slots for the strict priority */
 REG_WR(bp, PBF_REG_HIGH_PRIORITY_COS_NUM, strict_cos);

 /* Mapping between entry  priority to client number (0,1,2 -debug and
 * management clients, 3 - COS0 client, 4 - COS client)(HIGHEST)
 * 3bits client num.
 *   PRI4    |    PRI3    |    PRI2    |    PRI1    |    PRI0
 * dbg0-010     dbg1-001     cos1-100     cos0-011     MCP-000
 * dbg0-010     dbg1-001     cos0-011     cos1-100     MCP-000
 */

 val = (!strict_cos) ? 0x2318 : 0x22E0;
 REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, val);

 return 0;
}

/******************************************************************/
/* PFC section   */
/******************************************************************/
static void bnx2x_update_pfc_xmac(struct link_params *params,
      struct link_vars *vars,
      u8 is_lb)
{
 struct bnx2x *bp = params->bp;
 u32 xmac_base;
 u32 pause_val, pfc0_val, pfc1_val;

 /* XMAC base adrr */
 xmac_base = (params->port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0;

 /* Initialize pause and pfc registers */
 pause_val = 0x18000;
 pfc0_val = 0xFFFF8000;
 pfc1_val = 0x2;

 /* No PFC support */
 if (!(params->feature_config_flags &
       FEATURE_CONFIG_PFC_ENABLED)) {

  /* RX flow control - Process pause frame in receive direction
 */

  if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
   pause_val |= XMAC_PAUSE_CTRL_REG_RX_PAUSE_EN;

  /* TX flow control - Send pause packet when buffer is full */
  if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
   pause_val |= XMAC_PAUSE_CTRL_REG_TX_PAUSE_EN;
 } else {/* PFC support */
  pfc1_val |= XMAC_PFC_CTRL_HI_REG_PFC_REFRESH_EN |
   XMAC_PFC_CTRL_HI_REG_PFC_STATS_EN |
   XMAC_PFC_CTRL_HI_REG_RX_PFC_EN |
   XMAC_PFC_CTRL_HI_REG_TX_PFC_EN |
   XMAC_PFC_CTRL_HI_REG_FORCE_PFC_XON;
  /* Write pause and PFC registers */
  REG_WR(bp, xmac_base + XMAC_REG_PAUSE_CTRL, pause_val);
  REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL, pfc0_val);
  REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL_HI, pfc1_val);
  pfc1_val &= ~XMAC_PFC_CTRL_HI_REG_FORCE_PFC_XON;

 }

 /* Write pause and PFC registers */
 REG_WR(bp, xmac_base + XMAC_REG_PAUSE_CTRL, pause_val);
 REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL, pfc0_val);
 REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL_HI, pfc1_val);


 /* Set MAC address for source TX Pause/PFC frames */
 REG_WR(bp, xmac_base + XMAC_REG_CTRL_SA_LO,
        ((params->mac_addr[2] << 24) |
  (params->mac_addr[3] << 16) |
  (params->mac_addr[4] << 8) |
  (params->mac_addr[5])));
 REG_WR(bp, xmac_base + XMAC_REG_CTRL_SA_HI,
        ((params->mac_addr[0] << 8) |
  (params->mac_addr[1])));

 udelay(30);
}

/******************************************************************/
/* MAC/PBF section   */
/******************************************************************/
static void bnx2x_set_mdio_clk(struct bnx2x *bp, u32 chip_id,
          u32 emac_base)
{
 u32 new_mode, cur_mode;
 u32 clc_cnt;
 /* Set clause 45 mode, slow down the MDIO clock to 2.5MHz
 * (a value of 49==0x31) and make sure that the AUTO poll is off
 */

 cur_mode = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);

 if (USES_WARPCORE(bp))
  clc_cnt = 74L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT;
 else
  clc_cnt = 49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT;

 if (((cur_mode & EMAC_MDIO_MODE_CLOCK_CNT) == clc_cnt) &&
     (cur_mode & (EMAC_MDIO_MODE_CLAUSE_45)))
  return;

 new_mode = cur_mode &
  ~(EMAC_MDIO_MODE_AUTO_POLL | EMAC_MDIO_MODE_CLOCK_CNT);
 new_mode |= clc_cnt;
 new_mode |= (EMAC_MDIO_MODE_CLAUSE_45);

 DP(NETIF_MSG_LINK, "Changing emac_mode from 0x%x to 0x%x\n",
    cur_mode, new_mode);
 REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE, new_mode);
 udelay(40);
}

static void bnx2x_set_mdio_emac_per_phy(struct bnx2x *bp,
     struct link_params *params)
{
 u8 phy_index;
 /* Set mdio clock per phy */
 for (phy_index = INT_PHY; phy_index < params->num_phys;
       phy_index++)
  bnx2x_set_mdio_clk(bp, params->chip_id,
       params->phy[phy_index].mdio_ctrl);
}

static u8 bnx2x_is_4_port_mode(struct bnx2x *bp)
{
 u32 port4mode_ovwr_val;
 /* Check 4-port override enabled */
 port4mode_ovwr_val = REG_RD(bp, MISC_REG_PORT4MODE_EN_OVWR);
 if (port4mode_ovwr_val & (1<<0)) {
  /* Return 4-port mode override value */
  return ((port4mode_ovwr_val & (1<<1)) == (1<<1));
 }
 /* Return 4-port mode from input pin */
 return (u8)REG_RD(bp, MISC_REG_PORT4MODE_EN);
}

static void bnx2x_emac_init(struct link_params *params,
       struct link_vars *vars)
{
 /* reset and unreset the emac core */
 struct bnx2x *bp = params->bp;
 u8 port = params->port;
 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
 u32 val;
 u16 timeout;

 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
        (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
 udelay(5);
 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
        (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));

 /* init emac - use read-modify-write */
 /* self clear reset */
 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
 EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET));

 timeout = 200;
 do {
  val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
  DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val);
  if (!timeout) {
   DP(NETIF_MSG_LINK, "EMAC timeout!\n");
   return;
  }
  timeout--;
 } while (val & EMAC_MODE_RESET);

 bnx2x_set_mdio_emac_per_phy(bp, params);
 /* Set mac address */
 val = ((params->mac_addr[0] << 8) |
  params->mac_addr[1]);
 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH, val);

 val = ((params->mac_addr[2] << 24) |
        (params->mac_addr[3] << 16) |
        (params->mac_addr[4] << 8) |
  params->mac_addr[5]);
 EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + 4, val);
}

static void bnx2x_set_xumac_nig(struct link_params *params,
    u16 tx_pause_en,
    u8 enable)
{
 struct bnx2x *bp = params->bp;

 REG_WR(bp, params->port ? NIG_REG_P1_MAC_IN_EN : NIG_REG_P0_MAC_IN_EN,
        enable);
 REG_WR(bp, params->port ? NIG_REG_P1_MAC_OUT_EN : NIG_REG_P0_MAC_OUT_EN,
        enable);
 REG_WR(bp, params->port ? NIG_REG_P1_MAC_PAUSE_OUT_EN :
        NIG_REG_P0_MAC_PAUSE_OUT_EN, tx_pause_en);
}

static void bnx2x_set_umac_rxtx(struct link_params *params, u8 en)
{
 u32 umac_base = params->port ? GRCBASE_UMAC1 : GRCBASE_UMAC0;
 u32 val;
 struct bnx2x *bp = params->bp;
 if (!(REG_RD(bp, MISC_REG_RESET_REG_2) &
     (MISC_REGISTERS_RESET_REG_2_UMAC0 << params->port)))
  return;
 val = REG_RD(bp, umac_base + UMAC_REG_COMMAND_CONFIG);
 if (en)
  val |= (UMAC_COMMAND_CONFIG_REG_TX_ENA |
   UMAC_COMMAND_CONFIG_REG_RX_ENA);
 else
  val &= ~(UMAC_COMMAND_CONFIG_REG_TX_ENA |
    UMAC_COMMAND_CONFIG_REG_RX_ENA);
 /* Disable RX and TX */
 REG_WR(bp, umac_base + UMAC_REG_COMMAND_CONFIG, val);
}

static void bnx2x_umac_enable(struct link_params *params,
       struct link_vars *vars, u8 lb)
{
 u32 val;
 u32 umac_base = params->port ? GRCBASE_UMAC1 : GRCBASE_UMAC0;
 struct bnx2x *bp = params->bp;
 /* Reset UMAC */
 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
        (MISC_REGISTERS_RESET_REG_2_UMAC0 << params->port));
 usleep_range(1000, 2000);

 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
        (MISC_REGISTERS_RESET_REG_2_UMAC0 << params->port));

 DP(NETIF_MSG_LINK, "enabling UMAC\n");

 /* This register opens the gate for the UMAC despite its name */
 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + params->port*4, 1);

 val = UMAC_COMMAND_CONFIG_REG_PROMIS_EN |
  UMAC_COMMAND_CONFIG_REG_PAD_EN |
  UMAC_COMMAND_CONFIG_REG_SW_RESET |
  UMAC_COMMAND_CONFIG_REG_NO_LGTH_CHECK;
 switch (vars->line_speed) {
 case SPEED_10:
  val |= (0<<2);
  break;
 case SPEED_100:
  val |= (1<<2);
  break;
 case SPEED_1000:
  val |= (2<<2);
  break;
 case SPEED_2500:
  val |= (3<<2);
  break;
 default:
  DP(NETIF_MSG_LINK, "Invalid speed for UMAC %d\n",
          vars->line_speed);
  break;
 }
 if (!(vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
  val |= UMAC_COMMAND_CONFIG_REG_IGNORE_TX_PAUSE;

 if (!(vars->flow_ctrl & BNX2X_FLOW_CTRL_RX))
  val |= UMAC_COMMAND_CONFIG_REG_PAUSE_IGNORE;

 if (vars->duplex == DUPLEX_HALF)
  val |= UMAC_COMMAND_CONFIG_REG_HD_ENA;

 REG_WR(bp, umac_base + UMAC_REG_COMMAND_CONFIG, val);
 udelay(50);

 /* Configure UMAC for EEE */
 if (vars->eee_status & SHMEM_EEE_ADV_STATUS_MASK) {
  DP(NETIF_MSG_LINK, "configured UMAC for EEE\n");
  REG_WR(bp, umac_base + UMAC_REG_UMAC_EEE_CTRL,
         UMAC_UMAC_EEE_CTRL_REG_EEE_EN);
  REG_WR(bp, umac_base + UMAC_REG_EEE_WAKE_TIMER, 0x11);
 } else {
  REG_WR(bp, umac_base + UMAC_REG_UMAC_EEE_CTRL, 0x0);
 }

 /* Set MAC address for source TX Pause/PFC frames (under SW reset) */
 REG_WR(bp, umac_base + UMAC_REG_MAC_ADDR0,
        ((params->mac_addr[2] << 24) |
  (params->mac_addr[3] << 16) |
  (params->mac_addr[4] << 8) |
  (params->mac_addr[5])));
 REG_WR(bp, umac_base + UMAC_REG_MAC_ADDR1,
        ((params->mac_addr[0] << 8) |
  (params->mac_addr[1])));

 /* Enable RX and TX */
 val &= ~UMAC_COMMAND_CONFIG_REG_PAD_EN;
 val |= UMAC_COMMAND_CONFIG_REG_TX_ENA |
  UMAC_COMMAND_CONFIG_REG_RX_ENA;
 REG_WR(bp, umac_base + UMAC_REG_COMMAND_CONFIG, val);
 udelay(50);

 /* Remove SW Reset */
 val &= ~UMAC_COMMAND_CONFIG_REG_SW_RESET;

 /* Check loopback mode */
 if (lb)
  val |= UMAC_COMMAND_CONFIG_REG_LOOP_ENA;
 REG_WR(bp, umac_base + UMAC_REG_COMMAND_CONFIG, val);

 /* Maximum Frame Length (RW). Defines a 14-Bit maximum frame
 * length used by the MAC receive logic to check frames.
 */

 REG_WR(bp, umac_base + UMAC_REG_MAXFR, 0x2710);
 bnx2x_set_xumac_nig(params,
       ((vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) != 0), 1);
 vars->mac_type = MAC_TYPE_UMAC;

}

/* Define the XMAC mode */
static void bnx2x_xmac_init(struct link_params *params, u32 max_speed)
{
 struct bnx2x *bp = params->bp;
 u32 is_port4mode = bnx2x_is_4_port_mode(bp);

 /* In 4-port mode, need to set the mode only once, so if XMAC is
 * already out of reset, it means the mode has already been set,
 * and it must not* reset the XMAC again, since it controls both
 * ports of the path
 */


 if (((CHIP_NUM(bp) == CHIP_NUM_57840_4_10) ||
      (CHIP_NUM(bp) == CHIP_NUM_57840_2_20) ||
      (CHIP_NUM(bp) == CHIP_NUM_57840_OBSOLETE)) &&
     is_port4mode &&
     (REG_RD(bp, MISC_REG_RESET_REG_2) &
      MISC_REGISTERS_RESET_REG_2_XMAC)) {
  DP(NETIF_MSG_LINK,
     "XMAC already out of reset in 4-port mode\n");
  return;
 }

 /* Hard reset */
 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
        MISC_REGISTERS_RESET_REG_2_XMAC);
 usleep_range(1000, 2000);

 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
        MISC_REGISTERS_RESET_REG_2_XMAC);
 if (is_port4mode) {
  DP(NETIF_MSG_LINK, "Init XMAC to 2 ports x 10G per path\n");

  /* Set the number of ports on the system side to up to 2 */
  REG_WR(bp, MISC_REG_XMAC_CORE_PORT_MODE, 1);

  /* Set the number of ports on the Warp Core to 10G */
  REG_WR(bp, MISC_REG_XMAC_PHY_PORT_MODE, 3);
 } else {
  /* Set the number of ports on the system side to 1 */
  REG_WR(bp, MISC_REG_XMAC_CORE_PORT_MODE, 0);
  if (max_speed == SPEED_10000) {
   DP(NETIF_MSG_LINK,
      "Init XMAC to 10G x 1 port per path\n");
   /* Set the number of ports on the Warp Core to 10G */
   REG_WR(bp, MISC_REG_XMAC_PHY_PORT_MODE, 3);
  } else {
   DP(NETIF_MSG_LINK,
      "Init XMAC to 20G x 2 ports per path\n");
   /* Set the number of ports on the Warp Core to 20G */
   REG_WR(bp, MISC_REG_XMAC_PHY_PORT_MODE, 1);
  }
 }
 /* Soft reset */
 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
        MISC_REGISTERS_RESET_REG_2_XMAC_SOFT);
 usleep_range(1000, 2000);

 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
        MISC_REGISTERS_RESET_REG_2_XMAC_SOFT);

}

static void bnx2x_set_xmac_rxtx(struct link_params *params, u8 en)
{
 u8 port = params->port;
 struct bnx2x *bp = params->bp;
 u32 pfc_ctrl, xmac_base = (port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0;
 u32 val;

 if (REG_RD(bp, MISC_REG_RESET_REG_2) &
     MISC_REGISTERS_RESET_REG_2_XMAC) {
  /* Send an indication to change the state in the NIG back to XON
 * Clearing this bit enables the next set of this bit to get
 * rising edge
 */

  pfc_ctrl = REG_RD(bp, xmac_base + XMAC_REG_PFC_CTRL_HI);
  REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL_HI,
         (pfc_ctrl & ~(1<<1)));
  REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL_HI,
         (pfc_ctrl | (1<<1)));
  DP(NETIF_MSG_LINK, "Disable XMAC on port %x\n", port);
  val = REG_RD(bp, xmac_base + XMAC_REG_CTRL);
  if (en)
   val |= (XMAC_CTRL_REG_TX_EN | XMAC_CTRL_REG_RX_EN);
  else
   val &= ~(XMAC_CTRL_REG_TX_EN | XMAC_CTRL_REG_RX_EN);
  REG_WR(bp, xmac_base + XMAC_REG_CTRL, val);
 }
}

static int bnx2x_xmac_enable(struct link_params *params,
        struct link_vars *vars, u8 lb)
{
 u32 val, xmac_base;
 struct bnx2x *bp = params->bp;
 DP(NETIF_MSG_LINK, "enabling XMAC\n");

 xmac_base = (params->port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0;

 bnx2x_xmac_init(params, vars->line_speed);

 /* This register determines on which events the MAC will assert
 * error on the i/f to the NIG along w/ EOP.
 */


 /* This register tells the NIG whether to send traffic to UMAC
 * or XMAC
 */

 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + params->port*4, 0);

 /* When XMAC is in XLGMII mode, disable sending idles for fault
 * detection.
 */

 if (!(params->phy[INT_PHY].flags & FLAGS_TX_ERROR_CHECK)) {
  REG_WR(bp, xmac_base + XMAC_REG_RX_LSS_CTRL,
         (XMAC_RX_LSS_CTRL_REG_LOCAL_FAULT_DISABLE |
   XMAC_RX_LSS_CTRL_REG_REMOTE_FAULT_DISABLE));
  REG_WR(bp, xmac_base + XMAC_REG_CLEAR_RX_LSS_STATUS, 0);
  REG_WR(bp, xmac_base + XMAC_REG_CLEAR_RX_LSS_STATUS,
         XMAC_CLEAR_RX_LSS_STATUS_REG_CLEAR_LOCAL_FAULT_STATUS |
         XMAC_CLEAR_RX_LSS_STATUS_REG_CLEAR_REMOTE_FAULT_STATUS);
 }
 /* Set Max packet size */
 REG_WR(bp, xmac_base + XMAC_REG_RX_MAX_SIZE, 0x2710);

 /* CRC append for Tx packets */
 REG_WR(bp, xmac_base + XMAC_REG_TX_CTRL, 0xC800);

 /* update PFC */
 bnx2x_update_pfc_xmac(params, vars, 0);

 if (vars->eee_status & SHMEM_EEE_ADV_STATUS_MASK) {
  DP(NETIF_MSG_LINK, "Setting XMAC for EEE\n");
  REG_WR(bp, xmac_base + XMAC_REG_EEE_TIMERS_HI, 0x1380008);
  REG_WR(bp, xmac_base + XMAC_REG_EEE_CTRL, 0x1);
 } else {
  REG_WR(bp, xmac_base + XMAC_REG_EEE_CTRL, 0x0);
 }

 /* Enable TX and RX */
 val = XMAC_CTRL_REG_TX_EN | XMAC_CTRL_REG_RX_EN;

 /* Set MAC in XLGMII mode for dual-mode */
 if ((vars->line_speed == SPEED_20000) &&
     (params->phy[INT_PHY].supported &
      SUPPORTED_20000baseKR2_Full))
  val |= XMAC_CTRL_REG_XLGMII_ALIGN_ENB;

 /* Check loopback mode */
 if (lb)
  val |= XMAC_CTRL_REG_LINE_LOCAL_LPBK;
 REG_WR(bp, xmac_base + XMAC_REG_CTRL, val);
 bnx2x_set_xumac_nig(params,
       ((vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) != 0), 1);

 vars->mac_type = MAC_TYPE_XMAC;

 return 0;
}

static int bnx2x_emac_enable(struct link_params *params,
        struct link_vars *vars, u8 lb)
{
 struct bnx2x *bp = params->bp;
 u8 port = params->port;
 u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
 u32 val;

 DP(NETIF_MSG_LINK, "enabling EMAC\n");

 /* Disable BMAC */
 REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
        (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));

 /* enable emac and not bmac */
 REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1);

 /* ASIC */
 if (vars->phy_flags & PHY_XGXS_FLAG) {
  u32 ser_lane = ((params->lane_config &
     PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
    PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);

  DP(NETIF_MSG_LINK, "XGXS\n");
  /* select the master lanes (out of 0-3) */
  REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, ser_lane);
  /* select XGXS */
  REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 1);

 } else { /* SerDes */
  DP(NETIF_MSG_LINK, "SerDes\n");
  /* select SerDes */
  REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0);
 }

 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
        EMAC_RX_MODE_RESET);
 bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
        EMAC_TX_MODE_RESET);

 /* pause enable/disable */
 bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
         EMAC_RX_MODE_FLOW_EN);

 bnx2x_bits_dis(bp,  emac_base + EMAC_REG_EMAC_TX_MODE,
         (EMAC_TX_MODE_EXT_PAUSE_EN |
   EMAC_TX_MODE_FLOW_EN));
 if (!(params->feature_config_flags &
       FEATURE_CONFIG_PFC_ENABLED)) {
  if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
   bnx2x_bits_en(bp, emac_base +
          EMAC_REG_EMAC_RX_MODE,
          EMAC_RX_MODE_FLOW_EN);

  if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
   bnx2x_bits_en(bp, emac_base +
          EMAC_REG_EMAC_TX_MODE,
          (EMAC_TX_MODE_EXT_PAUSE_EN |
           EMAC_TX_MODE_FLOW_EN));
 } else
  bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
         EMAC_TX_MODE_FLOW_EN);

 /* KEEP_VLAN_TAG, promiscuous */
 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
 val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS;

 /* Setting this bit causes MAC control frames (except for pause
 * frames) to be passed on for processing. This setting has no
 * affect on the operation of the pause frames. This bit effects
 * all packets regardless of RX Parser packet sorting logic.
 * Turn the PFC off to make sure we are in Xon state before
 * enabling it.
 */

 EMAC_WR(bp, EMAC_REG_RX_PFC_MODE, 0);
 if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) {
  DP(NETIF_MSG_LINK, "PFC is enabled\n");
  /* Enable PFC again */
  EMAC_WR(bp, EMAC_REG_RX_PFC_MODE,
   EMAC_REG_RX_PFC_MODE_RX_EN |
   EMAC_REG_RX_PFC_MODE_TX_EN |
   EMAC_REG_RX_PFC_MODE_PRIORITIES);

  EMAC_WR(bp, EMAC_REG_RX_PFC_PARAM,
   ((0x0101 <<
     EMAC_REG_RX_PFC_PARAM_OPCODE_BITSHIFT) |
    (0x00ff <<
     EMAC_REG_RX_PFC_PARAM_PRIORITY_EN_BITSHIFT)));
  val |= EMAC_RX_MODE_KEEP_MAC_CONTROL;
 }
 EMAC_WR(bp, EMAC_REG_EMAC_RX_MODE, val);

 /* Set Loopback */
 val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
 if (lb)
  val |= 0x810;
 else
  val &= ~0x810;
 EMAC_WR(bp, EMAC_REG_EMAC_MODE, val);

 /* Enable emac */
 REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1);

 /* Enable emac for jumbo packets */
 EMAC_WR(bp, EMAC_REG_EMAC_RX_MTU_SIZE,
  (EMAC_RX_MTU_SIZE_JUMBO_ENA |
   (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVERHEAD)));

 /* Strip CRC */
 REG_WR(bp, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1);

 /* Disable the NIG in/out to the bmac */
 REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0);
 REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0);
 REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0);

 /* Enable the NIG in/out to the emac */
 REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
 val = 0;
 if ((params->feature_config_flags &
       FEATURE_CONFIG_PFC_ENABLED) ||
     (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
  val = 1;

 REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val);
 REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1);

 REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x0);

 vars->mac_type = MAC_TYPE_EMAC;
 return 0;
}

static void bnx2x_update_pfc_bmac1(struct link_params *params,
       struct link_vars *vars)
{
 u32 wb_data[2];
 struct bnx2x *bp = params->bp;
 u32 bmac_addr =  params->port ? NIG_REG_INGRESS_BMAC1_MEM :
  NIG_REG_INGRESS_BMAC0_MEM;

 u32 val = 0x14;
 if ((!(params->feature_config_flags &
       FEATURE_CONFIG_PFC_ENABLED)) &&
  (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX))
  /* Enable BigMAC to react on received Pause packets */
  val |= (1<<5);
 wb_data[0] = val;
 wb_data[1] = 0;
 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL, wb_data, 2);

 /* TX control */
 val = 0xc0;
 if (!(params->feature_config_flags &
       FEATURE_CONFIG_PFC_ENABLED) &&
  (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
  val |= 0x800000;
 wb_data[0] = val;
 wb_data[1] = 0;
 REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL, wb_data, 2);
}

static void bnx2x_update_pfc_bmac2(struct link_params *params,
       struct link_vars *vars,
       u8 is_lb)
{
 /* Set rx control: Strip CRC and enable BigMAC to relay
 * control packets to the system as well
 */

 u32 wb_data[2];
 struct bnx2x *bp = params->bp;
 u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM :
  NIG_REG_INGRESS_BMAC0_MEM;
 u32 val = 0x14;

 if ((!(params->feature_config_flags &
       FEATURE_CONFIG_PFC_ENABLED)) &&
  (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX))
  /* Enable BigMAC to react on received Pause packets */
  val |= (1<<5);
 wb_data[0] = val;
 wb_data[1] = 0;
 REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_CONTROL, wb_data, 2);
 udelay(30);

 /* Tx control */
 val = 0xc0;
 if (!(params->feature_config_flags &
    FEATURE_CONFIG_PFC_ENABLED) &&
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=91 H=89 G=89

¤ Dauer der Verarbeitung: 0.22 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.