| #ifdef __LINUX |
| #include <linux/kernel.h> |
| #include <linux/types.h> |
| #include <asm/byteorder.h> |
| #endif |
| #ifdef USER_LINUX |
| #include <stdio.h> |
| #include <unistd.h> |
| #include <sys/types.h> |
| #include <sys/socket.h> |
| #include <netinet/in.h> |
| #include <arpa/inet.h> |
| #include <sys/ioctl.h> |
| #include <net/if.h> |
| #include <linux/sockios.h> |
| #include <string.h> |
| #include <malloc.h> |
| #endif |
| #ifdef __FreeBSD__ |
| #include <sys/types.h> |
| #endif |
| #include "bcmtype.h" |
| #ifdef EDEBUG |
| #include "edebug_types.h" |
| #endif |
| #include "clc.h" |
| #include "grc_addr.h" |
| #include "bigmac_addresses.h" |
| #include "emac_reg_driver.h" |
| #include "misc_bits.h" |
| #include "57712_reg.h" |
| #include "clc_reg.h" |
| #include "dev_info.h" |
| #include "license.h" |
| #include "shmem.h" |
| #include "aeu_inputs.h" |
| |
| typedef elink_status_t (*read_sfp_module_eeprom_func_p)(struct elink_phy *phy, |
| struct elink_params *params, |
| u8 dev_addr, u16 addr, u8 byte_cnt, |
| u8 *o_buf, u8); |
| /********************************************************/ |
| #define ELINK_ETH_HLEN 14 |
| /* L2 header size + 2*VLANs (8 bytes) + LLC SNAP (8 bytes) */ |
| #define ELINK_ETH_OVREHEAD (ELINK_ETH_HLEN + 8 + 8) |
| #define ELINK_ETH_MIN_PACKET_SIZE 60 |
| #define ELINK_ETH_MAX_PACKET_SIZE 1500 |
| #define ELINK_ETH_MAX_JUMBO_PACKET_SIZE 9600 |
| #define ELINK_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 |
| /***********************************************************/ |
| /* Macros */ |
| /***********************************************************/ |
| #define MSLEEP(cb, ms) elink_cb_udelay(cb, 1000*ms) |
| #define USLEEP(cb, us) elink_cb_udelay(cb, us) |
| #define REG_RD(cb, reg) elink_cb_reg_read(cb, reg) |
| #define REG_WR(cb, reg, val) elink_cb_reg_write(cb, reg, val) |
| #define EMAC_RD(cb, reg) REG_RD(cb, emac_base + reg) |
| #define EMAC_WR(cb, reg, val) REG_WR(cb, emac_base + reg, val) |
| #define REG_WR_DMAE(cb, offset, wb_data, len) \ |
| elink_cb_reg_wb_write(cb, offset, wb_data, len) |
| #define REG_RD_DMAE(cb, offset, wb_data, len) \ |
| elink_cb_reg_wb_read(cb, offset, wb_data, len) |
| #define PATH_ID(cb) elink_cb_path_id(cb) |
| |
| #define ELINK_SET_GPIO elink_cb_gpio_write |
| #define ELINK_SET_MULT_GPIO elink_cb_gpio_mult_write |
| #define ELINK_GET_GPIO elink_cb_gpio_read |
| #define ELINK_SET_GPIO_INT elink_cb_gpio_int_write |
| |
| #ifndef OFFSETOF |
| #define OFFSETOF(_s, _m) ((u32) ((u8 *)(&((_s *) 0)->_m) - \ |
| (u8 *)((u8 *) 0))) |
| #endif |
| |
| #define CHIP_REV_SHIFT 12 |
| #define CHIP_REV_MASK (0xF<<CHIP_REV_SHIFT) |
| #define CHIP_REV(_chip_id) ((_chip_id) & CHIP_REV_MASK) |
| |
| #define CHIP_REV_Ax (0x0<<CHIP_REV_SHIFT) |
| #define CHIP_REV_Bx (0x1<<CHIP_REV_SHIFT) |
| #define CHIP_REV_IS_SLOW(_chip_id) \ |
| (CHIP_REV(_chip_id) > 0x00005000) |
| #define CHIP_REV_IS_FPGA(_chip_id) \ |
| (CHIP_REV_IS_SLOW(_chip_id)&& \ |
| (CHIP_REV(_chip_id) & 0x00001000)) |
| #define CHIP_REV_IS_EMUL(_chip_id) \ |
| (CHIP_REV_IS_SLOW(_chip_id)&& \ |
| !(CHIP_REV(_chip_id) & 0x00001000)) |
| |
| #define CHIP_NUM(_chip_id) (_chip_id >> 16) |
| #define CHIP_NUM_57710 0x164e |
| #define CHIP_NUM_57711 0x164f |
| #define CHIP_NUM_57711E 0x1650 |
| #define CHIP_NUM_57712 0x1662 |
| #define CHIP_NUM_57712E 0x1663 |
| #define CHIP_NUM_57713 0x1651 |
| #define CHIP_NUM_57713E 0x1652 |
| #define CHIP_NUM_57840_OBSOLETE 0x168d |
| #define CHIP_NUM_57840_4_10 0x16a1 |
| #define CHIP_NUM_57840_2_20 0x16a2 |
| #define CHIP_NUM_57810 0x168e |
| #define CHIP_NUM_57800 0x168a |
| #define CHIP_NUM_57811 0x163d |
| #define CHIP_NUM_57811_MF 0x163e |
| #define CHIP_IS_E1(_chip_id) (CHIP_NUM(_chip_id) == \ |
| CHIP_NUM_57710) |
| #define CHIP_IS_E1X(_chip_id) ((CHIP_NUM(_chip_id) == \ |
| CHIP_NUM_57710) || \ |
| (CHIP_NUM(_chip_id) == \ |
| CHIP_NUM_57711) || \ |
| (CHIP_NUM(_chip_id) == \ |
| CHIP_NUM_57711E)) |
| |
| #define CHIP_IS_E2(_chip_id) ((CHIP_NUM(_chip_id) == \ |
| CHIP_NUM_57712) || \ |
| (CHIP_NUM(_chip_id) == \ |
| CHIP_NUM_57712E) || \ |
| (CHIP_NUM(_chip_id) == \ |
| CHIP_NUM_57713) || \ |
| (CHIP_NUM(_chip_id) == \ |
| CHIP_NUM_57713E)) |
| |
| #define CHIP_IS_57711(_chip_id) (CHIP_NUM(_chip_id) == \ |
| CHIP_NUM_57711) |
| #define CHIP_IS_57711E(_chip_id) (CHIP_NUM(_chip_id) == \ |
| CHIP_NUM_57711E) |
| #define DO_CHIP_IS_E3(_chip_family) ((_chip_family == 0x1630) || \ |
| (_chip_family == 0x1680) || \ |
| (_chip_family == 0x16a0)) |
| #define CHIP_IS_E3(_chip_id) (DO_CHIP_IS_E3(((CHIP_NUM(_chip_id)) & 0xfff0))) |
| |
| |
| /* For EMUL: Ax=0xE, Bx=0xC, Cx=0xA. For FPGA: Ax=0xF, Bx=0xD, |
| * Cx=0xB. |
| */ |
| #define CHIP_REV_SIM(_p) (((0xF - (CHIP_REV(_p) >> CHIP_REV_SHIFT)) \ |
| >>1) << CHIP_REV_SHIFT) |
| |
| #define CHIP_IS_E3B0(_p) (CHIP_IS_E3(_p) && \ |
| ((CHIP_REV(_p) == CHIP_REV_Bx) || \ |
| (CHIP_REV_SIM(_p) == CHIP_REV_Bx))) |
| |
| #define CHIP_IS_E3A0(_p) (CHIP_IS_E3(_p) && \ |
| ((CHIP_REV(_p) == CHIP_REV_Ax) || \ |
| (CHIP_REV_SIM(_p) == CHIP_REV_Ax))) |
| |
| #define ELINK_USES_WARPCORE(_chip_id) (CHIP_IS_E3(_chip_id)) |
| |
| #define SHMEM2_RD(cb, shmem2_base, _field) \ |
| REG_RD(cb, shmem2_base + \ |
| OFFSETOF(struct shmem2_region, \ |
| _field)) |
| |
| #define SHMEM2_HAS(cb, shmem2_base, field) (shmem2_base && \ |
| (SHMEM2_RD(cb, shmem2_base, size) > \ |
| OFFSETOF(struct shmem2_region, field))) |
| #ifndef NULL |
| #define NULL ((void *) 0) |
| #endif |
| |
| /***********************************************************/ |
| /* Shortcut definitions */ |
| /***********************************************************/ |
| |
| #define ELINK_NIG_LATCH_BC_ENABLE_MI_INT 0 |
| |
| #define ELINK_NIG_STATUS_EMAC0_MI_INT \ |
| NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_EMAC0_MISC_MI_INT |
| #define ELINK_NIG_STATUS_XGXS0_LINK10G \ |
| NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G |
| #define ELINK_NIG_STATUS_XGXS0_LINK_STATUS \ |
| NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS |
| #define ELINK_NIG_STATUS_XGXS0_LINK_STATUS_SIZE \ |
| NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE |
| #define ELINK_NIG_STATUS_SERDES0_LINK_STATUS \ |
| NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS |
| #define ELINK_NIG_MASK_MI_INT \ |
| NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT |
| #define ELINK_NIG_MASK_XGXS0_LINK10G \ |
| NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G |
| #define ELINK_NIG_MASK_XGXS0_LINK_STATUS \ |
| NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK_STATUS |
| #define ELINK_NIG_MASK_SERDES0_LINK_STATUS \ |
| NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS |
| |
| #define ELINK_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 ELINK_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 ELINK_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 ELINK_AUTONEG_CL37 SHARED_HW_CFG_AN_ENABLE_CL37 |
| #define ELINK_AUTONEG_CL73 SHARED_HW_CFG_AN_ENABLE_CL73 |
| #define ELINK_AUTONEG_BAM SHARED_HW_CFG_AN_ENABLE_BAM |
| #define ELINK_AUTONEG_PARALLEL \ |
| SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION |
| #define ELINK_AUTONEG_SGMII_FIBER_AUTODET \ |
| SHARED_HW_CFG_AN_EN_SGMII_FIBER_AUTO_DETECT |
| #define ELINK_AUTONEG_REMOTE_PHY SHARED_HW_CFG_AN_ENABLE_REMOTE_PHY |
| |
| #define ELINK_GP_STATUS_PAUSE_RSOLUTION_TXSIDE \ |
| MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE |
| #define ELINK_GP_STATUS_PAUSE_RSOLUTION_RXSIDE \ |
| MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE |
| #define ELINK_GP_STATUS_SPEED_MASK \ |
| MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK |
| #define ELINK_GP_STATUS_10M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M |
| #define ELINK_GP_STATUS_100M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M |
| #define ELINK_GP_STATUS_1G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G |
| #define ELINK_GP_STATUS_2_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G |
| #define ELINK_GP_STATUS_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G |
| #define ELINK_GP_STATUS_6G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G |
| #define ELINK_GP_STATUS_10G_HIG \ |
| MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG |
| #define ELINK_GP_STATUS_10G_CX4 \ |
| MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4 |
| #define ELINK_GP_STATUS_1G_KX MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX |
| #define ELINK_GP_STATUS_10G_KX4 \ |
| MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4 |
| #define ELINK_GP_STATUS_10G_KR MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KR |
| #define ELINK_GP_STATUS_10G_XFI MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_XFI |
| #define ELINK_GP_STATUS_20G_DXGXS MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_20G_DXGXS |
| #define ELINK_GP_STATUS_10G_SFI MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_SFI |
| #define ELINK_GP_STATUS_20G_KR2 MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_20G_KR2 |
| #define ELINK_LINK_10THD LINK_STATUS_SPEED_AND_DUPLEX_10THD |
| #define ELINK_LINK_10TFD LINK_STATUS_SPEED_AND_DUPLEX_10TFD |
| #define ELINK_LINK_100TXHD LINK_STATUS_SPEED_AND_DUPLEX_100TXHD |
| #define ELINK_LINK_100T4 LINK_STATUS_SPEED_AND_DUPLEX_100T4 |
| #define ELINK_LINK_100TXFD LINK_STATUS_SPEED_AND_DUPLEX_100TXFD |
| #define ELINK_LINK_1000THD LINK_STATUS_SPEED_AND_DUPLEX_1000THD |
| #define ELINK_LINK_1000TFD LINK_STATUS_SPEED_AND_DUPLEX_1000TFD |
| #define ELINK_LINK_1000XFD LINK_STATUS_SPEED_AND_DUPLEX_1000XFD |
| #define ELINK_LINK_2500THD LINK_STATUS_SPEED_AND_DUPLEX_2500THD |
| #define ELINK_LINK_2500TFD LINK_STATUS_SPEED_AND_DUPLEX_2500TFD |
| #define ELINK_LINK_2500XFD LINK_STATUS_SPEED_AND_DUPLEX_2500XFD |
| #define ELINK_LINK_10GTFD LINK_STATUS_SPEED_AND_DUPLEX_10GTFD |
| #define ELINK_LINK_10GXFD LINK_STATUS_SPEED_AND_DUPLEX_10GXFD |
| #define ELINK_LINK_20GTFD LINK_STATUS_SPEED_AND_DUPLEX_20GTFD |
| #define ELINK_LINK_20GXFD LINK_STATUS_SPEED_AND_DUPLEX_20GXFD |
| |
| #define ELINK_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 ELINK_SFP_EEPROM_CON_TYPE_ADDR 0x2 |
| #define ELINK_SFP_EEPROM_CON_TYPE_VAL_UNKNOWN 0x0 |
| #define ELINK_SFP_EEPROM_CON_TYPE_VAL_LC 0x7 |
| #define ELINK_SFP_EEPROM_CON_TYPE_VAL_COPPER 0x21 |
| #define ELINK_SFP_EEPROM_CON_TYPE_VAL_RJ45 0x22 |
| |
| |
| #define ELINK_SFP_EEPROM_10G_COMP_CODE_ADDR 0x3 |
| #define ELINK_SFP_EEPROM_10G_COMP_CODE_SR_MASK (1<<4) |
| #define ELINK_SFP_EEPROM_10G_COMP_CODE_LR_MASK (1<<5) |
| #define ELINK_SFP_EEPROM_10G_COMP_CODE_LRM_MASK (1<<6) |
| |
| #define ELINK_SFP_EEPROM_1G_COMP_CODE_ADDR 0x6 |
| #define ELINK_SFP_EEPROM_1G_COMP_CODE_SX (1<<0) |
| #define ELINK_SFP_EEPROM_1G_COMP_CODE_LX (1<<1) |
| #define ELINK_SFP_EEPROM_1G_COMP_CODE_CX (1<<2) |
| #define ELINK_SFP_EEPROM_1G_COMP_CODE_BASE_T (1<<3) |
| |
| #define ELINK_SFP_EEPROM_FC_TX_TECH_ADDR 0x8 |
| #define ELINK_SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE 0x4 |
| #define ELINK_SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE 0x8 |
| |
| #define ELINK_SFP_EEPROM_OPTIONS_ADDR 0x40 |
| #define ELINK_SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK 0x1 |
| #define ELINK_SFP_EEPROM_OPTIONS_SIZE 2 |
| |
| #define ELINK_EDC_MODE_LINEAR 0x0022 |
| #define ELINK_EDC_MODE_LIMITING 0x0044 |
| #define ELINK_EDC_MODE_PASSIVE_DAC 0x0055 |
| #define ELINK_EDC_MODE_ACTIVE_DAC 0x0066 |
| |
| /* ETS defines*/ |
| #define DCBX_INVALID_COS (0xFF) |
| |
| #define ELINK_ETS_BW_LIMIT_CREDIT_UPPER_BOUND (0x5000) |
| #define ELINK_ETS_BW_LIMIT_CREDIT_WEIGHT (0x5000) |
| #define ELINK_ETS_E3B0_NIG_MIN_W_VAL_UP_TO_10GBPS (1360) |
| #define ELINK_ETS_E3B0_NIG_MIN_W_VAL_20GBPS (2720) |
| #define ELINK_ETS_E3B0_PBF_MIN_W_VAL (10000) |
| |
| #define ELINK_MAX_PACKET_SIZE (9700) |
| #ifdef INCLUDE_WARPCORE_UC_LOAD |
| #define ELINK_WC_UC_TIMEOUT 1000 |
| #define ELINK_WC_RDY_TIMEOUT_MSEC 100 |
| #endif |
| #define MAX_KR_LINK_RETRY 4 |
| |
| /**********************************************************/ |
| /* INTERFACE */ |
| /**********************************************************/ |
| |
| #define CL22_WR_OVER_CL45(_cb, _phy, _bank, _addr, _val) \ |
| elink_cl45_write(_cb, _phy, \ |
| (_phy)->def_md_devad, \ |
| (_bank + (_addr & 0xf)), \ |
| _val) |
| |
| #define CL22_RD_OVER_CL45(_cb, _phy, _bank, _addr, _val) \ |
| elink_cl45_read(_cb, _phy, \ |
| (_phy)->def_md_devad, \ |
| (_bank + (_addr & 0xf)), \ |
| _val) |
| |
| #ifdef BNX2X_ADD /* BNX2X_ADD */ |
| static int elink_check_half_open_conn(struct elink_params *params, |
| struct elink_vars *vars, u8 notify); |
| static int elink_sfp_module_detection(struct elink_phy *phy, |
| struct elink_params *params); |
| #endif |
| |
| static u32 elink_bits_en(struct elink_dev *cb, u32 reg, u32 bits) |
| { |
| u32 val = REG_RD(cb, reg); |
| |
| val |= bits; |
| REG_WR(cb, reg, val); |
| return val; |
| } |
| |
| static u32 elink_bits_dis(struct elink_dev *cb, u32 reg, u32 bits) |
| { |
| u32 val = REG_RD(cb, reg); |
| |
| val &= ~bits; |
| REG_WR(cb, reg, val); |
| return val; |
| } |
| |
| /* |
| * elink_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. |
| */ |
| #ifndef EXCLUDE_NON_COMMON_INIT |
| static int elink_check_lfa(struct elink_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 elink_dev *cb = params->cb; |
| |
| additional_config = |
| REG_RD(cb, 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) { |
| ELINK_DEBUG_P0(cb, "No LFA due to DCC flap after clp exit\n"); |
| REG_WR(cb, 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(cb, 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 & ELINK_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(cb, 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)) { |
| ELINK_DEBUG_P2(cb, "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(cb, 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)) { |
| ELINK_DEBUG_P2(cb, "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(cb, 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)) { |
| ELINK_DEBUG_P2(cb, "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(cb, params->lfa_base + |
| OFFSETOF(struct shmem_lfa, |
| speed_cap_mask[cfg_idx])); |
| |
| if (cur_speed_cap_mask != params->speed_cap_mask[cfg_idx]) { |
| ELINK_DEBUG_P2(cb, "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(cb, 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) { |
| ELINK_DEBUG_P2(cb, "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(cb, params->shmem2_base + |
| OFFSETOF(struct shmem2_region, |
| eee_status[params->port])); |
| |
| if (((eee_status & SHMEM_EEE_LPI_REQUESTED_BIT) ^ |
| (params->eee_mode & ELINK_EEE_MODE_ENABLE_LPI)) || |
| ((eee_status & SHMEM_EEE_REQUESTED_BIT) ^ |
| (params->eee_mode & ELINK_EEE_MODE_ADV_LPI))) { |
| ELINK_DEBUG_P2(cb, "EEE mismatch %x vs. %x\n", params->eee_mode, |
| eee_status); |
| return LFA_EEE_MISMATCH; |
| } |
| |
| /* LFA conditions are met */ |
| return 0; |
| } |
| #endif |
| /******************************************************************/ |
| /* EPIO/GPIO section */ |
| /******************************************************************/ |
| #if (!defined EXCLUDE_WARPCORE) |
| static void elink_get_epio(struct elink_dev *cb, u32 epio_pin, u32 *en) |
| { |
| u32 epio_mask, gp_oenable; |
| *en = 0; |
| /* Sanity check */ |
| if (epio_pin > 31) { |
| ELINK_DEBUG_P1(cb, "Invalid EPIO pin %d to get\n", epio_pin); |
| return; |
| } |
| |
| epio_mask = 1 << epio_pin; |
| /* Set this EPIO to output */ |
| gp_oenable = REG_RD(cb, MCP_REG_MCPR_GP_OENABLE); |
| REG_WR(cb, MCP_REG_MCPR_GP_OENABLE, gp_oenable & ~epio_mask); |
| |
| *en = (REG_RD(cb, MCP_REG_MCPR_GP_INPUTS) & epio_mask) >> epio_pin; |
| } |
| static void elink_set_epio(struct elink_dev *cb, u32 epio_pin, u32 en) |
| { |
| u32 epio_mask, gp_output, gp_oenable; |
| |
| /* Sanity check */ |
| if (epio_pin > 31) { |
| ELINK_DEBUG_P1(cb, "Invalid EPIO pin %d to set\n", epio_pin); |
| return; |
| } |
| ELINK_DEBUG_P2(cb, "Setting EPIO pin %d to %d\n", epio_pin, en); |
| epio_mask = 1 << epio_pin; |
| /* Set this EPIO to output */ |
| gp_output = REG_RD(cb, MCP_REG_MCPR_GP_OUTPUTS); |
| if (en) |
| gp_output |= epio_mask; |
| else |
| gp_output &= ~epio_mask; |
| |
| REG_WR(cb, MCP_REG_MCPR_GP_OUTPUTS, gp_output); |
| |
| /* Set the value for this EPIO */ |
| gp_oenable = REG_RD(cb, MCP_REG_MCPR_GP_OENABLE); |
| REG_WR(cb, MCP_REG_MCPR_GP_OENABLE, gp_oenable | epio_mask); |
| } |
| |
| static void elink_set_cfg_pin(struct elink_dev *cb, u32 pin_cfg, u32 val) |
| { |
| if (pin_cfg == PIN_CFG_NA) |
| return; |
| if (pin_cfg >= PIN_CFG_EPIO0) { |
| elink_set_epio(cb, 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; |
| ELINK_SET_GPIO(cb, gpio_num, (u8)val, gpio_port); |
| } |
| } |
| |
| static u32 elink_get_cfg_pin(struct elink_dev *cb, u32 pin_cfg, u32 *val) |
| { |
| if (pin_cfg == PIN_CFG_NA) |
| return ELINK_STATUS_ERROR; |
| if (pin_cfg >= PIN_CFG_EPIO0) { |
| elink_get_epio(cb, 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 = ELINK_GET_GPIO(cb, gpio_num, gpio_port); |
| } |
| return ELINK_STATUS_OK; |
| |
| } |
| #endif /* (!defined EXCLUDE_WARPCORE) */ |
| /******************************************************************/ |
| /* ETS section */ |
| /******************************************************************/ |
| #ifdef ELINK_ENHANCEMENTS |
| static void elink_ets_e2e3a0_disabled(struct elink_params *params) |
| { |
| /* ETS disabled configuration*/ |
| struct elink_dev *cb = params->cb; |
| |
| ELINK_DEBUG_P0(cb, "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(cb, 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(cb, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7); |
| /* defines which entries (clients) are subjected to WFQ arbitration */ |
| REG_WR(cb, 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(cb, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100); |
| /* mapping between the CREDIT_WEIGHT registers and actual client |
| * numbers |
| */ |
| REG_WR(cb, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0); |
| REG_WR(cb, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, 0); |
| REG_WR(cb, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, 0); |
| |
| REG_WR(cb, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0, 0); |
| REG_WR(cb, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1, 0); |
| REG_WR(cb, PBF_REG_HIGH_PRIORITY_COS_NUM, 0); |
| /* ETS mode disable */ |
| REG_WR(cb, PBF_REG_ETS_ENABLED, 0); |
| /* If ETS mode is enabled (there is no strict priority) defines a WFQ |
| * weight for COS0/COS1. |
| */ |
| REG_WR(cb, PBF_REG_COS0_WEIGHT, 0x2710); |
| REG_WR(cb, PBF_REG_COS1_WEIGHT, 0x2710); |
| /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter */ |
| REG_WR(cb, PBF_REG_COS0_UPPER_BOUND, 0x989680); |
| REG_WR(cb, PBF_REG_COS1_UPPER_BOUND, 0x989680); |
| /* Defines the number of consecutive slots for the strict priority */ |
| REG_WR(cb, PBF_REG_NUM_STRICT_ARB_SLOTS, 0); |
| } |
| /****************************************************************************** |
| * Description: |
| * Getting min_w_val will be set according to line speed . |
| *. |
| ******************************************************************************/ |
| static u32 elink_ets_get_min_w_val_nig(const struct elink_vars *vars) |
| { |
| u32 min_w_val = 0; |
| /* Calculate min_w_val.*/ |
| if (vars->link_up) { |
| if (vars->line_speed == ELINK_SPEED_20000) |
| min_w_val = ELINK_ETS_E3B0_NIG_MIN_W_VAL_20GBPS; |
| else |
| min_w_val = ELINK_ETS_E3B0_NIG_MIN_W_VAL_UP_TO_10GBPS; |
| } else |
| min_w_val = ELINK_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 elink_ets_get_credit_upper_bound(const u32 min_w_val) |
| { |
| const u32 credit_upper_bound = (u32)ELINK_MAXVAL((150 * min_w_val), |
| ELINK_MAX_PACKET_SIZE); |
| return credit_upper_bound; |
| } |
| /****************************************************************************** |
| * Description: |
| * Set credit upper bound for NIG. |
| *. |
| ******************************************************************************/ |
| static void elink_ets_e3b0_set_credit_upper_bound_nig( |
| const struct elink_params *params, |
| const u32 min_w_val) |
| { |
| struct elink_dev *cb = params->cb; |
| const u8 port = params->port; |
| const u32 credit_upper_bound = |
| elink_ets_get_credit_upper_bound(min_w_val); |
| |
| REG_WR(cb, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_0 : |
| NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0, credit_upper_bound); |
| REG_WR(cb, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_1 : |
| NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1, credit_upper_bound); |
| REG_WR(cb, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_2 : |
| NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_2, credit_upper_bound); |
| REG_WR(cb, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_3 : |
| NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_3, credit_upper_bound); |
| REG_WR(cb, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_4 : |
| NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_4, credit_upper_bound); |
| REG_WR(cb, (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(cb, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_6, |
| credit_upper_bound); |
| REG_WR(cb, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_7, |
| credit_upper_bound); |
| REG_WR(cb, 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 acording to spec |
| *. |
| ******************************************************************************/ |
| static void elink_ets_e3b0_nig_disabled(const struct elink_params *params, |
| const struct elink_vars *vars) |
| { |
| struct elink_dev *cb = params->cb; |
| const u8 port = params->port; |
| const u32 min_w_val = elink_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(cb, NIG_REG_P1_TX_ARB_PRIORITY_CLIENT2_LSB, 0x543210); |
| REG_WR(cb, NIG_REG_P1_TX_ARB_PRIORITY_CLIENT2_MSB, 0x0); |
| } else { |
| REG_WR(cb, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT2_LSB, 0x76543210); |
| REG_WR(cb, 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(cb, (port) ? NIG_REG_P1_TX_ARB_NUM_STRICT_ARB_SLOTS : |
| NIG_REG_P1_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(cb, NIG_REG_P1_TX_ARB_CLIENT_CREDIT_MAP2_LSB, 0x210543); |
| REG_WR(cb, NIG_REG_P1_TX_ARB_CLIENT_CREDIT_MAP2_MSB, 0x0); |
| } else { |
| /*Port 0 has 9 COS*/ |
| REG_WR(cb, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP2_LSB, |
| 0x43210876); |
| REG_WR(cb, 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(cb, NIG_REG_P1_TX_ARB_CLIENT_IS_STRICT, 0x3f); |
| else |
| REG_WR(cb, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x1ff); |
| /* defines which entries (clients) are subjected to WFQ arbitration */ |
| REG_WR(cb, (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(cb, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_0 : |
| NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, 0x0); |
| REG_WR(cb, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_1 : |
| NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, 0x0); |
| REG_WR(cb, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_2 : |
| NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_2, 0x0); |
| REG_WR(cb, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_3 : |
| NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_3, 0x0); |
| REG_WR(cb, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_4 : |
| NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_4, 0x0); |
| REG_WR(cb, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_5 : |
| NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_5, 0x0); |
| if (!port) { |
| REG_WR(cb, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_6, 0x0); |
| REG_WR(cb, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_7, 0x0); |
| REG_WR(cb, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_8, 0x0); |
| } |
| |
| elink_ets_e3b0_set_credit_upper_bound_nig(params, min_w_val); |
| } |
| /****************************************************************************** |
| * Description: |
| * Set credit upper bound for PBF. |
| *. |
| ******************************************************************************/ |
| static void elink_ets_e3b0_set_credit_upper_bound_pbf( |
| const struct elink_params *params, |
| const u32 min_w_val) |
| { |
| struct elink_dev *cb = params->cb; |
| const u32 credit_upper_bound = |
| elink_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 = ELINK_DCBX_E3B0_MAX_NUM_COS_PORT0; |
| } else { |
| base_upper_bound = PBF_REG_COS0_UPPER_BOUND_P1; |
| max_cos = ELINK_DCBX_E3B0_MAX_NUM_COS_PORT1; |
| } |
| |
| for (i = 0; i < max_cos; i++) |
| REG_WR(cb, 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 acording to spec |
| *. |
| ******************************************************************************/ |
| static void elink_ets_e3b0_pbf_disabled(const struct elink_params *params) |
| { |
| struct elink_dev *cb = params->cb; |
| const u8 port = params->port; |
| const u32 min_w_val_pbf = ELINK_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(cb, PBF_REG_ETS_ARB_PRIORITY_CLIENT_P1 , 0x688); |
| else |
| /* (10 1|100 |011|0 10|00 1|000) */ |
| REG_WR(cb, 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(cb, PBF_REG_ETS_ARB_CLIENT_CREDIT_MAP_P1, 0x688); |
| else |
| /* 0x2C688 (10 1|100 |011|0 10|00 1|000) */ |
| REG_WR(cb, PBF_REG_ETS_ARB_CLIENT_CREDIT_MAP_P0, 0x2C688); |
| |
| REG_WR(cb, (port) ? PBF_REG_ETS_ARB_NUM_STRICT_ARB_SLOTS_P1 : |
| PBF_REG_ETS_ARB_NUM_STRICT_ARB_SLOTS_P0 , 0x100); |
| |
| |
| REG_WR(cb, (port) ? PBF_REG_ETS_ARB_CLIENT_IS_STRICT_P1 : |
| PBF_REG_ETS_ARB_CLIENT_IS_STRICT_P0 , 0); |
| |
| REG_WR(cb, (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 = ELINK_DCBX_E3B0_MAX_NUM_COS_PORT0; |
| } else { |
| base_weight = PBF_REG_COS0_WEIGHT_P1; |
| max_cos = ELINK_DCBX_E3B0_MAX_NUM_COS_PORT1; |
| } |
| |
| for (i = 0; i < max_cos; i++) |
| REG_WR(cb, base_weight + (0x4 * i), 0); |
| |
| elink_ets_e3b0_set_credit_upper_bound_pbf(params, min_w_val_pbf); |
| } |
| /****************************************************************************** |
| * Description: |
| * E3B0 disable will return basicly the values to init values. |
| *. |
| ******************************************************************************/ |
| static elink_status_t elink_ets_e3b0_disabled(const struct elink_params *params, |
| const struct elink_vars *vars) |
| { |
| struct elink_dev *cb = params->cb; |
| |
| if (!CHIP_IS_E3B0(params->chip_id)) { |
| ELINK_DEBUG_P0(cb, |
| "elink_ets_e3b0_disabled the chip isn't E3B0\n"); |
| return ELINK_STATUS_ERROR; |
| } |
| |
| elink_ets_e3b0_nig_disabled(params, vars); |
| |
| elink_ets_e3b0_pbf_disabled(params); |
| |
| return ELINK_STATUS_OK; |
| } |
| |
| /****************************************************************************** |
| * Description: |
| * Disable will return basicly the values to init values. |
| * |
| ******************************************************************************/ |
| elink_status_t elink_ets_disabled(struct elink_params *params, |
| struct elink_vars *vars) |
| { |
| struct elink_dev *cb = params->cb; |
| elink_status_t elink_status = ELINK_STATUS_OK; |
| |
| if ((CHIP_IS_E2(params->chip_id)) || (CHIP_IS_E3A0(params->chip_id))) |
| elink_ets_e2e3a0_disabled(params); |
| else if (CHIP_IS_E3B0(params->chip_id)) |
| elink_status = elink_ets_e3b0_disabled(params, vars); |
| else { |
| ELINK_DEBUG_P0(cb, "elink_ets_disabled - chip not supported\n"); |
| return ELINK_STATUS_ERROR; |
| } |
| |
| return elink_status; |
| } |
| |
| /****************************************************************************** |
| * Description |
| * Set the COS mappimg to SP and BW until this point all the COS are not |
| * set as SP or BW. |
| ******************************************************************************/ |
| static elink_status_t elink_ets_e3b0_cli_map(const struct elink_params *params, |
| const struct elink_ets_params *ets_params, |
| const u8 cos_sp_bitmap, |
| const u8 cos_bw_bitmap) |
| { |
| struct elink_dev *cb = params->cb; |
| 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(cb, (port) ? NIG_REG_P1_TX_ARB_CLIENT_IS_STRICT : |
| NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, nig_cli_sp_bitmap); |
| |
| REG_WR(cb, (port) ? PBF_REG_ETS_ARB_CLIENT_IS_STRICT_P1 : |
| PBF_REG_ETS_ARB_CLIENT_IS_STRICT_P0 , pbf_cli_sp_bitmap); |
| |
| REG_WR(cb, (port) ? NIG_REG_P1_TX_ARB_CLIENT_IS_SUBJECT2WFQ : |
| NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, |
| nig_cli_subject2wfq_bitmap); |
| |
| REG_WR(cb, (port) ? PBF_REG_ETS_ARB_CLIENT_IS_SUBJECT2WFQ_P1 : |
| PBF_REG_ETS_ARB_CLIENT_IS_SUBJECT2WFQ_P0, |
| pbf_cli_subject2wfq_bitmap); |
| |
| return ELINK_STATUS_OK; |
| } |
| |
| /****************************************************************************** |
| * Description: |
| * This function is needed because NIG ARB_CREDIT_WEIGHT_X are |
| * not continues and ARB_CREDIT_WEIGHT_0 + offset is suitable. |
| ******************************************************************************/ |
| static elink_status_t elink_ets_e3b0_set_cos_bw(struct elink_dev *cb, |
| 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 ELINK_STATUS_ERROR; |
| 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 ELINK_STATUS_ERROR; |
| 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 ELINK_STATUS_ERROR; |
| 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(cb, nig_reg_adress_crd_weight, cos_bw_nig); |
| |
| REG_WR(cb, pbf_reg_adress_crd_weight, cos_bw_pbf); |
| |
| return ELINK_STATUS_OK; |
| } |
| /****************************************************************************** |
| * Description: |
| * Calculate the total BW.A value of 0 isn't legal. |
| * |
| ******************************************************************************/ |
| static elink_status_t elink_ets_e3b0_get_total_bw( |
| const struct elink_params *params, |
| struct elink_ets_params *ets_params, |
| u16 *total_bw) |
| { |
| struct elink_dev *cb = params->cb; |
| 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 == elink_cos_state_bw) { |
| is_bw_cos_exist = 1; |
| if (!ets_params->cos[cos_idx].params.bw_params.bw) { |
| ELINK_DEBUG_P0(cb, "elink_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) { |
| ELINK_DEBUG_P0(cb, |
| "elink_ets_E3B0_config total BW shouldn't be 0\n"); |
| return ELINK_STATUS_ERROR; |
| } |
| ELINK_DEBUG_P0(cb, |
| "elink_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 ELINK_STATUS_OK; |
| } |
| |
| /****************************************************************************** |
| * Description: |
| * Invalidate all the sp_pri_to_cos. |
| * |
| ******************************************************************************/ |
| static void elink_ets_e3b0_sp_pri_to_cos_init(u8 *sp_pri_to_cos) |
| { |
| u8 pri = 0; |
| for (pri = 0; pri < ELINK_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 elink_status_t elink_ets_e3b0_sp_pri_to_cos_set(const struct elink_params *params, |
| u8 *sp_pri_to_cos, const u8 pri, |
| const u8 cos_entry) |
| { |
| struct elink_dev *cb = params->cb; |
| const u8 port = params->port; |
| const u8 max_num_of_cos = (port) ? ELINK_DCBX_E3B0_MAX_NUM_COS_PORT1 : |
| ELINK_DCBX_E3B0_MAX_NUM_COS_PORT0; |
| |
| if (pri >= max_num_of_cos) { |
| ELINK_DEBUG_P0(cb, "elink_ets_e3b0_sp_pri_to_cos_set invalid " |
| "parameter Illegal strict priority\n"); |
| return ELINK_STATUS_ERROR; |
| } |
| |
| if (sp_pri_to_cos[pri] != DCBX_INVALID_COS) { |
| ELINK_DEBUG_P0(cb, "elink_ets_e3b0_sp_pri_to_cos_set invalid " |
| "parameter There can't be two COS's with " |
| "the same strict pri\n"); |
| return ELINK_STATUS_ERROR; |
| } |
| |
| sp_pri_to_cos[pri] = cos_entry; |
| return ELINK_STATUS_OK; |
| |
| } |
| |
| /****************************************************************************** |
| * Description: |
| * Returns the correct value according to COS and priority in |
| * the sp_pri_cli register. |
| * |
| ******************************************************************************/ |
| static u64 elink_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 elink_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 elink_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 elink_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 elink_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 elink_status_t elink_ets_e3b0_sp_set_pri_cli_reg(const struct elink_params *params, |
| u8 *sp_pri_to_cos) |
| { |
| struct elink_dev *cb = params->cb; |
| 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) ? ELINK_DCBX_E3B0_MAX_NUM_COS_PORT1 : |
| ELINK_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] >= ELINK_DCBX_MAX_NUM_COS) { |
| ELINK_DEBUG_P0(cb, |
| "elink_ets_e3b0_sp_set_pri_cli_reg " |
| "invalid cos entry\n"); |
| return ELINK_STATUS_ERROR; |
| } |
| |
| pri_cli_nig |= elink_e3b0_sp_get_pri_cli_reg_nig( |
| sp_pri_to_cos[i], pri_set); |
| |
| pri_cli_pbf |= elink_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)) { |
| ELINK_DEBUG_P0(cb, |
| "elink_ets_e3b0_sp_set_pri_cli_reg " |
| "invalid There can't be two COS's with" |
| " the same strict pri\n"); |
| return ELINK_STATUS_ERROR; |
| } |
| 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 |= elink_e3b0_sp_get_pri_cli_reg_nig( |
| i, pri_set); |
| |
| pri_cli_pbf |= elink_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) { |
| ELINK_DEBUG_P0(cb, "elink_ets_e3b0_sp_set_pri_cli_reg not all " |
| "entries were set\n"); |
| return ELINK_STATUS_ERROR; |
| } |
| |
| if (port) { |
| /* Only 6 usable clients*/ |
| REG_WR(cb, NIG_REG_P1_TX_ARB_PRIORITY_CLIENT2_LSB, |
| (u32)pri_cli_nig); |
| |
| REG_WR(cb, 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(cb, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT2_LSB, |
| pri_cli_nig_lsb); |
| REG_WR(cb, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT2_MSB, |
| pri_cli_nig_msb); |
| |
| REG_WR(cb, PBF_REG_ETS_ARB_PRIORITY_CLIENT_P0 , pri_cli_pbf); |
| } |
| return ELINK_STATUS_OK; |
| } |
| |
| /****************************************************************************** |
| * Description: |
| * Configure the COS to ETS according to BW and SP settings. |
| ******************************************************************************/ |
| elink_status_t elink_ets_e3b0_config(const struct elink_params *params, |
| const struct elink_vars *vars, |
| struct elink_ets_params *ets_params) |
| { |
| struct elink_dev *cb = params->cb; |
| elink_status_t elink_status = ELINK_STATUS_OK; |
| const u8 port = params->port; |
| u16 total_bw = 0; |
| const u32 min_w_val_nig = elink_ets_get_min_w_val_nig(vars); |
| const u32 min_w_val_pbf = ELINK_ETS_E3B0_PBF_MIN_W_VAL; |
| u8 cos_bw_bitmap = 0; |
| u8 cos_sp_bitmap = 0; |
| u8 sp_pri_to_cos[ELINK_DCBX_MAX_NUM_COS] = {0}; |
| const u8 max_num_of_cos = (port) ? ELINK_DCBX_E3B0_MAX_NUM_COS_PORT1 : |
| ELINK_DCBX_E3B0_MAX_NUM_COS_PORT0; |
| u8 cos_entry = 0; |
| |
| if (!CHIP_IS_E3B0(params->chip_id)) { |
| ELINK_DEBUG_P0(cb, |
| "elink_ets_e3b0_disabled the chip isn't E3B0\n"); |
| return ELINK_STATUS_ERROR; |
| } |
| |
| if ((ets_params->num_of_cos > max_num_of_cos)) { |
| ELINK_DEBUG_P0(cb, "elink_ets_E3B0_config the number of COS " |
| "isn't supported\n"); |
| return ELINK_STATUS_ERROR; |
| } |
| |
| /* Prepare sp strict priority parameters*/ |
| elink_ets_e3b0_sp_pri_to_cos_init(sp_pri_to_cos); |
| |
| /* Prepare BW parameters*/ |
| elink_status = elink_ets_e3b0_get_total_bw(params, ets_params, |
| &total_bw); |
| if (elink_status != ELINK_STATUS_OK) { |
| ELINK_DEBUG_P0(cb, |
| "elink_ets_E3B0_config get_total_bw failed\n"); |
| return ELINK_STATUS_ERROR; |
| } |
| |
| /* Upper bound is set according to current link speed (min_w_val |
| * should be the same for upper bound and COS credit val). |
| */ |
| elink_ets_e3b0_set_credit_upper_bound_nig(params, min_w_val_nig); |
| elink_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 (elink_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) |
| */ |
| elink_status = elink_ets_e3b0_set_cos_bw( |
| cb, cos_entry, min_w_val_nig, min_w_val_pbf, |
| total_bw, |
| ets_params->cos[cos_entry].params.bw_params.bw, |
| port); |
| } else if (elink_cos_state_strict == |
| ets_params->cos[cos_entry].state){ |
| cos_sp_bitmap |= (1 << cos_entry); |
| |
| elink_status = elink_ets_e3b0_sp_pri_to_cos_set( |
| params, |
| sp_pri_to_cos, |
| ets_params->cos[cos_entry].params.sp_params.pri, |
| cos_entry); |
| |
| } else { |
| ELINK_DEBUG_P0(cb, |
| "elink_ets_e3b0_config cos state not valid\n"); |
| return ELINK_STATUS_ERROR; |
| } |
| if (elink_status != ELINK_STATUS_OK) { |
| ELINK_DEBUG_P0(cb, |
| "elink_ets_e3b0_config set cos bw failed\n"); |
| return elink_status; |
| } |
| } |
| |
| /* Set SP register (which COS has higher priority) */ |
| elink_status = elink_ets_e3b0_sp_set_pri_cli_reg(params, |
| sp_pri_to_cos); |
| |
| if (elink_status != ELINK_STATUS_OK) { |
| ELINK_DEBUG_P0(cb, |
| "elink_ets_E3B0_config set_pri_cli_reg failed\n"); |
| return elink_status; |
| } |
| |
| /* Set client mapping of BW and strict */ |
| elink_status = elink_ets_e3b0_cli_map(params, ets_params, |
| cos_sp_bitmap, |
| cos_bw_bitmap); |
| |
| if (elink_status != ELINK_STATUS_OK) { |
| ELINK_DEBUG_P0(cb, "elink_ets_E3B0_config SP failed\n"); |
| return elink_status; |
| } |
| return ELINK_STATUS_OK; |
| } |
| static void elink_ets_bw_limit_common(const struct elink_params *params) |
| { |
| /* ETS disabled configuration */ |
| struct elink_dev *cb = params->cb; |
| ELINK_DEBUG_P0(cb, "ETS enabled BW limit configuration\n"); |
| /* Defines which entries (clients) are subjected to WFQ arbitration |
| * COS0 0x8 |
| * COS1 0x10 |
| */ |
| REG_WR(cb, 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(cb, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0x111A); |
| |
| REG_WR(cb, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0, |
| ELINK_ETS_BW_LIMIT_CREDIT_UPPER_BOUND); |
| REG_WR(cb, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1, |
| ELINK_ETS_BW_LIMIT_CREDIT_UPPER_BOUND); |
| |
| /* ETS mode enabled*/ |
| REG_WR(cb, PBF_REG_ETS_ENABLED, 1); |
| |
| /* Defines the number of consecutive slots for the strict priority */ |
| REG_WR(cb, 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(cb, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7); |
| |
| /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter.*/ |
| REG_WR(cb, PBF_REG_COS0_UPPER_BOUND, |
| ELINK_ETS_BW_LIMIT_CREDIT_UPPER_BOUND); |
| REG_WR(cb, PBF_REG_COS1_UPPER_BOUND, |
| ELINK_ETS_BW_LIMIT_CREDIT_UPPER_BOUND); |
| } |
| |
| void elink_ets_bw_limit(const struct elink_params *params, const u32 cos0_bw, |
| const u32 cos1_bw) |
| { |
| /* ETS disabled configuration*/ |
| struct elink_dev *cb = params->cb; |
| const u32 total_bw = cos0_bw + cos1_bw; |
| u32 cos0_credit_weight = 0; |
| u32 cos1_credit_weight = 0; |
| |
| ELINK_DEBUG_P0(cb, "ETS enabled BW limit configuration\n"); |
| |
| if ((!total_bw) || |
| (!cos0_bw) || |
| (!cos1_bw)) { |
| ELINK_DEBUG_P0(cb, "Total BW can't be zero\n"); |
| return; |
| } |
| |
| cos0_credit_weight = (cos0_bw * ELINK_ETS_BW_LIMIT_CREDIT_WEIGHT)/ |
| total_bw; |
| cos1_credit_weight = (cos1_bw * ELINK_ETS_BW_LIMIT_CREDIT_WEIGHT)/ |
| total_bw; |
| |
| elink_ets_bw_limit_common(params); |
| |
| REG_WR(cb, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, cos0_credit_weight); |
| REG_WR(cb, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, cos1_credit_weight); |
| |
| REG_WR(cb, PBF_REG_COS0_WEIGHT, cos0_credit_weight); |
| REG_WR(cb, PBF_REG_COS1_WEIGHT, cos1_credit_weight); |
| } |
| |
| elink_status_t elink_ets_strict(const struct elink_params *params, const u8 strict_cos) |
| { |
| /* ETS disabled configuration*/ |
| struct elink_dev *cb = params->cb; |
| u32 val = 0; |
| |
| ELINK_DEBUG_P0(cb, "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(cb, 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(cb, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100); |
| /* ETS mode disable */ |
| REG_WR(cb, PBF_REG_ETS_ENABLED, 0); |
| /* Defines the number of consecutive slots for the strict priority */ |
| REG_WR(cb, PBF_REG_NUM_STRICT_ARB_SLOTS, 0x100); |
| |
| /* Defines the number of consecutive slots for the strict priority */ |
| REG_WR(cb, 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(cb, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, val); |
| |
| return ELINK_STATUS_OK; |
| } |
| #endif /* ELINK_ENHANCEMENTS */ |
| |
| /******************************************************************/ |
| /* PFC section */ |
| /******************************************************************/ |
| #ifndef EXCLUDE_NON_COMMON_INIT |
| #ifndef EXCLUDE_WARPCORE |
| static void elink_update_pfc_xmac(struct elink_params *params, |
| struct elink_vars *vars, |
| u8 is_lb) |
| { |
| struct elink_dev *cb = params->cb; |
| 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 & |
| ELINK_FEATURE_CONFIG_PFC_ENABLED)) { |
| |
| /* RX flow control - Process pause frame in receive direction |
| */ |
| if (vars->flow_ctrl & ELINK_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 & ELINK_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(cb, xmac_base + XMAC_REG_PAUSE_CTRL, pause_val); |
| REG_WR(cb, xmac_base + XMAC_REG_PFC_CTRL, pfc0_val); |
| REG_WR(cb, 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(cb, xmac_base + XMAC_REG_PAUSE_CTRL, pause_val); |
| REG_WR(cb, xmac_base + XMAC_REG_PFC_CTRL, pfc0_val); |
| REG_WR(cb, xmac_base + XMAC_REG_PFC_CTRL_HI, pfc1_val); |
| |
| |
| /* Set MAC address for source TX Pause/PFC frames */ |
| REG_WR(cb, 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(cb, xmac_base + XMAC_REG_CTRL_SA_HI, |
| ((params->mac_addr[0] << 8) | |
| (params->mac_addr[1]))); |
| |
| USLEEP(cb, 30); |
| } |
| |
| #endif // EXCLUDE_WARPCORE |
| #endif // #ifndef EXCLUDE_NON_COMMON_INIT |
| #ifdef ELINK_ENHANCEMENTS |
| #ifndef BNX2X_UPSTREAM /* ! BNX2X_UPSTREAM */ |
| static void elink_emac_get_pfc_stat(struct elink_params *params, |
| u32 pfc_frames_sent[2], |
| u32 pfc_frames_received[2]) |
| { |
| /* Read pfc statistic */ |
| struct elink_dev *cb = params->cb; |
| u32 emac_base = params->port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; |
| u32 val_xon = 0; |
| u32 val_xoff = 0; |
| |
| ELINK_DEBUG_P0(cb, "pfc statistic read from EMAC\n"); |
| |
| /* PFC received frames */ |
| val_xoff = REG_RD(cb, emac_base + |
| EMAC_REG_RX_PFC_STATS_XOFF_RCVD); |
| val_xoff &= EMAC_REG_RX_PFC_STATS_XOFF_RCVD_COUNT; |
| val_xon = REG_RD(cb, emac_base + EMAC_REG_RX_PFC_STATS_XON_RCVD); |
| val_xon &= EMAC_REG_RX_PFC_STATS_XON_RCVD_COUNT; |
| |
| pfc_frames_received[0] = val_xon + val_xoff; |
| |
| /* PFC received sent */ |
| val_xoff = REG_RD(cb, emac_base + |
| EMAC_REG_RX_PFC_STATS_XOFF_SENT); |
| val_xoff &= EMAC_REG_RX_PFC_STATS_XOFF_SENT_COUNT; |
| val_xon = REG_RD(cb, emac_base + EMAC_REG_RX_PFC_STATS_XON_SENT); |
| val_xon &= EMAC_REG_RX_PFC_STATS_XON_SENT_COUNT; |
| |
| pfc_frames_sent[0] = val_xon + val_xoff; |
| } |
| |
| /* Read pfc statistic*/ |
| void elink_pfc_statistic(struct elink_params *params, struct elink_vars *vars, |
| u32 pfc_frames_sent[2], |
| u32 pfc_frames_received[2]) |
| { |
| /* Read pfc statistic */ |
| struct elink_dev *cb = params->cb; |
| |
| ELINK_DEBUG_P0(cb, "pfc statistic\n"); |
| |
| if (!vars->link_up) |
| return; |
| |
| if (vars->mac_type == ELINK_MAC_TYPE_EMAC) { |
| ELINK_DEBUG_P0(cb, "About to read PFC stats from EMAC\n"); |
| elink_emac_get_pfc_stat(params, pfc_frames_sent, |
| pfc_frames_received); |
| } |
| } |
| #endif /* ! BNX2X_UPSTREAM */ |
| #endif /* ELINK_ENHANCEMENTS */ |
| /******************************************************************/ |
| /* MAC/PBF section */ |
| /******************************************************************/ |
| static void elink_set_mdio_clk(struct elink_dev *cb, 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(cb, emac_base + EMAC_REG_EMAC_MDIO_MODE); |
| |
| if (ELINK_USES_WARPCORE(chip_id)) |
| 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); |
| |
| ELINK_DEBUG_P2(cb, "Changing emac_mode from 0x%x to 0x%x\n", |
| cur_mode, new_mode); |
| REG_WR(cb, emac_base + EMAC_REG_EMAC_MDIO_MODE, new_mode); |
| USLEEP(cb, 40); |
| } |
| |
| #ifndef EXCLUDE_WARPCORE |
| static u8 elink_is_4_port_mode(struct elink_dev *cb) |
| { |
| u32 port4mode_ovwr_val; |
| /* Check 4-port override enabled */ |
| port4mode_ovwr_val = REG_RD(cb, 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(cb, MISC_REG_PORT4MODE_EN); |
| } |
| #endif |
| |
| #ifndef EXCLUDE_NON_COMMON_INIT |
| static void elink_set_mdio_emac_per_phy(struct elink_dev *cb, |
| struct elink_params *params) |
| { |
| u8 phy_index; |
| |
| /* Set mdio clock per phy */ |
| for (phy_index = ELINK_INT_PHY; phy_index < params->num_phys; |
| phy_index++) |
| elink_set_mdio_clk(cb, params->chip_id, |
| params->phy[phy_index].mdio_ctrl); |
| } |
| |
| static void elink_emac_init(struct elink_params *params, |
| struct elink_vars *vars) |
| { |
| /* reset and unreset the emac core */ |
| struct elink_dev *cb = params->cb; |
| u8 port = params->port; |
| u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; |
| u32 val; |
| u16 timeout; |
| |
| REG_WR(cb, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, |
| (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port)); |
| USLEEP(cb, 5); |
| REG_WR(cb, 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(cb, emac_base + EMAC_REG_EMAC_MODE); |
| EMAC_WR(cb, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET)); |
| |
| timeout = 200; |
| do { |
| val = REG_RD(cb, emac_base + EMAC_REG_EMAC_MODE); |
| ELINK_DEBUG_P1(cb, "EMAC reset reg is %u\n", val); |
| if (!timeout) { |
| ELINK_DEBUG_P0(cb, "EMAC timeout!\n"); |
| return; |
| } |
| timeout--; |
| } while (val & EMAC_MODE_RESET); |
| |
| elink_set_mdio_emac_per_phy(cb, params); |
| /* Set mac address */ |
| val = ((params->mac_addr[0] << 8) | |
| params->mac_addr[1]); |
| EMAC_WR(cb, 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(cb, EMAC_REG_EMAC_MAC_MATCH + 4, val); |
| } |
| |
| #ifndef EXCLUDE_WARPCORE |
| static void elink_set_xumac_nig(struct elink_params *params, |
| u16 tx_pause_en, |
| u8 enable) |
| { |
| struct elink_dev *cb = params->cb; |
| |
| REG_WR(cb, params->port ? NIG_REG_P1_MAC_IN_EN : NIG_REG_P0_MAC_IN_EN, |
| enable); |
| REG_WR(cb, params->port ? NIG_REG_P1_MAC_OUT_EN : NIG_REG_P0_MAC_OUT_EN, |
| enable); |
| REG_WR(cb, params->port ? NIG_REG_P1_MAC_PAUSE_OUT_EN : |
| NIG_REG_P0_MAC_PAUSE_OUT_EN, tx_pause_en); |
| } |
| |
| static void elink_set_umac_rxtx(struct elink_params *params, u8 en) |
| { |
| u32 umac_base = params->port ? GRCBASE_UMAC1 : GRCBASE_UMAC0; |
| u32 val; |
| struct elink_dev *cb = params->cb; |
| if (!(REG_RD(cb, MISC_REG_RESET_REG_2) & |
| (MISC_REGISTERS_RESET_REG_2_UMAC0 << params->port))) |
| return; |
| val = REG_RD(cb, 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(cb, umac_base + UMAC_REG_COMMAND_CONFIG, val); |
| } |
| |
| static void elink_umac_enable(struct elink_params *params, |
| struct elink_vars *vars, u8 lb) |
| { |
| u32 val; |
| u32 umac_base = params->port ? GRCBASE_UMAC1 : GRCBASE_UMAC0; |
| struct elink_dev *cb = params->cb; |
| /* Reset UMAC */ |
| REG_WR(cb, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, |
| (MISC_REGISTERS_RESET_REG_2_UMAC0 << params->port)); |
| MSLEEP(cb, 1); |
| |
| REG_WR(cb, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, |
| (MISC_REGISTERS_RESET_REG_2_UMAC0 << params->port)); |
| |
| ELINK_DEBUG_P0(cb, "enabling UMAC\n"); |
| |
| /* This register opens the gate for the UMAC despite its name */ |
| REG_WR(cb, 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 ELINK_SPEED_10: |
| val |= (0<<2); |
| break; |
| case ELINK_SPEED_100: |
| val |= (1<<2); |
| break; |
| case ELINK_SPEED_1000: |
| val |= (2<<2); |
| break; |
| case ELINK_SPEED_2500: |
| val |= (3<<2); |
| break; |
| default: |
| ELINK_DEBUG_P1(cb, "Invalid speed for UMAC %d\n", |
| vars->line_speed); |
| break; |
| } |
| if (!(vars->flow_ctrl & ELINK_FLOW_CTRL_TX)) |
| val |= UMAC_COMMAND_CONFIG_REG_IGNORE_TX_PAUSE; |
| |
| if (!(vars->flow_ctrl & ELINK_FLOW_CTRL_RX)) |
| val |= UMAC_COMMAND_CONFIG_REG_PAUSE_IGNORE; |
| |
| if (vars->duplex == DUPLEX_HALF) |
| val |= UMAC_COMMAND_CONFIG_REG_HD_ENA; |
| |
| REG_WR(cb, umac_base + UMAC_REG_COMMAND_CONFIG, val); |
| USLEEP(cb, 50); |
| |
| /* Configure UMAC for EEE */ |
| if (vars->eee_status & SHMEM_EEE_ADV_STATUS_MASK) { |
| ELINK_DEBUG_P0(cb, "configured UMAC for EEE\n"); |
| REG_WR(cb, umac_base + UMAC_REG_UMAC_EEE_CTRL, |
| UMAC_UMAC_EEE_CTRL_REG_EEE_EN); |
| REG_WR(cb, umac_base + UMAC_REG_EEE_WAKE_TIMER, 0x11); |
| } else { |
| REG_WR(cb, umac_base + UMAC_REG_UMAC_EEE_CTRL, 0x0); |
| } |
| |
| /* Set MAC address for source TX Pause/PFC frames (under SW reset) */ |
| REG_WR(cb, 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(cb, 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(cb, umac_base + UMAC_REG_COMMAND_CONFIG, val); |
| USLEEP(cb, 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(cb, 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(cb, umac_base + UMAC_REG_MAXFR, 0x2710); |
| elink_set_xumac_nig(params, |
| ((vars->flow_ctrl & ELINK_FLOW_CTRL_TX) != 0), 1); |
| vars->mac_type = ELINK_MAC_TYPE_UMAC; |
| |
| } |
| |
| /* Define the XMAC mode */ |
| static void elink_xmac_init(struct elink_params *params, u32 max_speed) |
| { |
| struct elink_dev *cb = params->cb; |
| u32 is_port4mode = elink_is_4_port_mode(cb); |
| |
| /* 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(params->chip_id) == CHIP_NUM_57840_4_10) || |
| (CHIP_NUM(params->chip_id) == CHIP_NUM_57840_2_20) || |
| (CHIP_NUM(params->chip_id) == CHIP_NUM_57840_OBSOLETE)) && |
| is_port4mode && |
| (REG_RD(cb, MISC_REG_RESET_REG_2) & |
| MISC_REGISTERS_RESET_REG_2_XMAC)) { |
| ELINK_DEBUG_P0(cb, |
| "XMAC already out of reset in 4-port mode\n"); |
| return; |
| } |
| |
| /* Hard reset */ |
| REG_WR(cb, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, |
| MISC_REGISTERS_RESET_REG_2_XMAC); |
| MSLEEP(cb, 1); |
| |
| REG_WR(cb, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, |
| MISC_REGISTERS_RESET_REG_2_XMAC); |
| if (is_port4mode) { |
| ELINK_DEBUG_P0(cb, "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(cb, MISC_REG_XMAC_CORE_PORT_MODE, 1); |
| |
| /* Set the number of ports on the Warp Core to 10G */ |
| REG_WR(cb, MISC_REG_XMAC_PHY_PORT_MODE, 3); |
| } else { |
| /* Set the number of ports on the system side to 1 */ |
| REG_WR(cb, MISC_REG_XMAC_CORE_PORT_MODE, 0); |
| if (max_speed == ELINK_SPEED_10000) { |
| ELINK_DEBUG_P0(cb, |
| "Init XMAC to 10G x 1 port per path\n"); |
| /* Set the number of ports on the Warp Core to 10G */ |
| REG_WR(cb, MISC_REG_XMAC_PHY_PORT_MODE, 3); |
| } else { |
| ELINK_DEBUG_P0(cb, |
| "Init XMAC to 20G x 2 ports per path\n"); |
| /* Set the number of ports on the Warp Core to 20G */ |
| REG_WR(cb, MISC_REG_XMAC_PHY_PORT_MODE, 1); |
| } |
| } |
| /* Soft reset */ |
| REG_WR(cb, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, |
| MISC_REGISTERS_RESET_REG_2_XMAC_SOFT); |
| MSLEEP(cb, 1); |
| |
| REG_WR(cb, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, |
| MISC_REGISTERS_RESET_REG_2_XMAC_SOFT); |
| |
| } |
| |
| static void elink_set_xmac_rxtx(struct elink_params *params, u8 en) |
| { |
| u8 port = params->port; |
| struct elink_dev *cb = params->cb; |
| u32 pfc_ctrl, xmac_base = (port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0; |
| u32 val; |
| |
| if (REG_RD(cb, 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(cb, xmac_base + XMAC_REG_PFC_CTRL_HI); |
| REG_WR(cb, xmac_base + XMAC_REG_PFC_CTRL_HI, |
| (pfc_ctrl & ~(1<<1))); |
| REG_WR(cb, xmac_base + XMAC_REG_PFC_CTRL_HI, |
| (pfc_ctrl | (1<<1))); |
| ELINK_DEBUG_P1(cb, "Disable XMAC on port %x\n", port); |
| val = REG_RD(cb, 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(cb, xmac_base + XMAC_REG_CTRL, val); |
| } |
| } |
| |
| static elink_status_t elink_xmac_enable(struct elink_params *params, |
| struct elink_vars *vars, u8 lb) |
| { |
| u32 val, xmac_base; |
| struct elink_dev *cb = params->cb; |
| ELINK_DEBUG_P0(cb, "enabling XMAC\n"); |
| |
| xmac_base = (params->port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0; |
| |
| elink_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(cb, NIG_REG_EGRESS_EMAC0_PORT + params->port*4, 0); |
| |
| /* When XMAC is in XLGMII mode, disable sending idles for fault |
| * detection. |
| */ |
| if (!(params->phy[ELINK_INT_PHY].flags & ELINK_FLAGS_TX_ERROR_CHECK)) { |
| REG_WR(cb, 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(cb, xmac_base + XMAC_REG_CLEAR_RX_LSS_STATUS, 0); |
| REG_WR(cb, 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(cb, xmac_base + XMAC_REG_RX_MAX_SIZE, 0x2710); |
| |
| /* CRC append for Tx packets */ |
| REG_WR(cb, xmac_base + XMAC_REG_TX_CTRL, 0xC800); |
| |
| /* update PFC */ |
| elink_update_pfc_xmac(params, vars, 0); |
| |
| if (vars->eee_status & SHMEM_EEE_ADV_STATUS_MASK) { |
| ELINK_DEBUG_P0(cb, "Setting XMAC for EEE\n"); |
| REG_WR(cb, xmac_base + XMAC_REG_EEE_TIMERS_HI, 0x1380008); |
| REG_WR(cb, xmac_base + XMAC_REG_EEE_CTRL, 0x1); |
| } else { |
| REG_WR(cb, 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 == ELINK_SPEED_20000) && |
| (params->phy[ELINK_INT_PHY].supported & |
| ELINK_SUPPORTED_20000baseKR2_Full)) |
| val |= XMAC_CTRL_REG_XLGMII_ALIGN_ENB; |
| |
| /* Check loopback mode */ |
| if (lb) |
| val |= XMAC_CTRL_REG_LINE_LOCAL_LPBK; |
| REG_WR(cb, xmac_base + XMAC_REG_CTRL, val); |
| elink_set_xumac_nig(params, |
| ((vars->flow_ctrl & ELINK_FLOW_CTRL_TX) != 0), 1); |
| |
| vars->mac_type = ELINK_MAC_TYPE_XMAC; |
| |
| return ELINK_STATUS_OK; |
| } |
| #endif // EXCLUDE_WARPCORE |
| |
| #ifndef EXCLUDE_EMAC |
| static elink_status_t elink_emac_enable(struct elink_params *params, |
| struct elink_vars *vars, u8 lb) |
| { |
| struct elink_dev *cb = params->cb; |
| u8 port = params->port; |
| u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; |
| u32 val; |
| |
| ELINK_DEBUG_P0(cb, "enabling EMAC\n"); |
| |
| /* Disable BMAC */ |
| REG_WR(cb, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, |
| (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); |
| |
| /* enable emac and not bmac */ |
| REG_WR(cb, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1); |
| |
| #ifdef ELINK_INCLUDE_EMUL |
| /* for paladium */ |
| if (CHIP_REV_IS_EMUL(params->chip_id)) { |
| /* Use lane 1 (of lanes 0-3) */ |
| REG_WR(cb, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1); |
| REG_WR(cb, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 1); |
| } |
| /* for fpga */ |
| else |
| #endif |
| #ifdef ELINK_INCLUDE_FPGA |
| if (CHIP_REV_IS_FPGA(params->chip_id)) { |
| /* Use lane 1 (of lanes 0-3) */ |
| ELINK_DEBUG_P0(cb, "elink_emac_enable: Setting FPGA\n"); |
| |
| REG_WR(cb, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1); |
| REG_WR(cb, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0); |
| } else |
| #endif |
| /* 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); |
| |
| ELINK_DEBUG_P0(cb, "XGXS\n"); |
| /* select the master lanes (out of 0-3) */ |
| REG_WR(cb, NIG_REG_XGXS_LANE_SEL_P0 + port*4, ser_lane); |
| /* select XGXS */ |
| REG_WR(cb, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 1); |
| |
| } else { /* SerDes */ |
| ELINK_DEBUG_P0(cb, "SerDes\n"); |
| /* select SerDes */ |
| REG_WR(cb, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0); |
| } |
| |
| elink_bits_en(cb, emac_base + EMAC_REG_EMAC_RX_MODE, |
| EMAC_RX_MODE_RESET); |
| elink_bits_en(cb, emac_base + EMAC_REG_EMAC_TX_MODE, |
| EMAC_TX_MODE_RESET); |
| |
| #if defined(ELINK_INCLUDE_EMUL) || defined(ELINK_INCLUDE_FPGA) |
| if (CHIP_REV_IS_SLOW(params->chip_id)) { |
| /* config GMII mode */ |
| val = REG_RD(cb, emac_base + EMAC_REG_EMAC_MODE); |
| EMAC_WR(cb, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_PORT_GMII)); |
| } else { /* ASIC */ |
| #endif /* defined(ELINK_INCLUDE_EMUL) || defined(ELINK_INCLUDE_FPGA)*/ |
| /* pause enable/disable */ |
| elink_bits_dis(cb, emac_base + EMAC_REG_EMAC_RX_MODE, |
| EMAC_RX_MODE_FLOW_EN); |
| |
| elink_bits_dis(cb, emac_base + EMAC_REG_EMAC_TX_MODE, |
| (EMAC_TX_MODE_EXT_PAUSE_EN | |
| EMAC_TX_MODE_FLOW_EN)); |
| if (!(params->feature_config_flags & |
| ELINK_FEATURE_CONFIG_PFC_ENABLED)) { |
| if (vars->flow_ctrl & ELINK_FLOW_CTRL_RX) |
| elink_bits_en(cb, emac_base + |
| EMAC_REG_EMAC_RX_MODE, |
| EMAC_RX_MODE_FLOW_EN); |
| |
| if (vars->flow_ctrl & ELINK_FLOW_CTRL_TX) |
| elink_bits_en(cb, emac_base + |
| EMAC_REG_EMAC_TX_MODE, |
| (EMAC_TX_MODE_EXT_PAUSE_EN | |
| EMAC_TX_MODE_FLOW_EN)); |
| } else |
| elink_bits_en(cb, emac_base + EMAC_REG_EMAC_TX_MODE, |
| EMAC_TX_MODE_FLOW_EN); |
| #if defined(ELINK_INCLUDE_EMUL) || defined(ELINK_INCLUDE_FPGA) |
| } |
| #endif /* defined(ELINK_INCLUDE_EMUL) || defined(ELINK_INCLUDE_FPGA) */ |
| |
| /* KEEP_VLAN_TAG, promiscuous */ |
| val = REG_RD(cb, 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(cb, EMAC_REG_RX_PFC_MODE, 0); |
| if (params->feature_config_flags & ELINK_FEATURE_CONFIG_PFC_ENABLED) { |
| ELINK_DEBUG_P0(cb, "PFC is enabled\n"); |
| /* Enable PFC again */ |
| EMAC_WR(cb, 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(cb, 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(cb, EMAC_REG_EMAC_RX_MODE, val); |
| |
| /* Set Loopback */ |
| val = REG_RD(cb, emac_base + EMAC_REG_EMAC_MODE); |
| if (lb) |
| val |= 0x810; |
| else |
| val &= ~0x810; |
| EMAC_WR(cb, EMAC_REG_EMAC_MODE, val); |
| |
| /* Enable emac */ |
| REG_WR(cb, NIG_REG_NIG_EMAC0_EN + port*4, 1); |
| |
| #ifndef ELINK_AUX_POWER |
| /* Enable emac for jumbo packets */ |
| EMAC_WR(cb, EMAC_REG_EMAC_RX_MTU_SIZE, |
| (EMAC_RX_MTU_SIZE_JUMBO_ENA | |
| (ELINK_ETH_MAX_JUMBO_PACKET_SIZE + ELINK_ETH_OVREHEAD))); |
| #endif |
| |
| /* Strip CRC */ |
| REG_WR(cb, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1); |
| |
| /* Disable the NIG in/out to the bmac */ |
| REG_WR(cb, NIG_REG_BMAC0_IN_EN + port*4, 0x0); |
| REG_WR(cb, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0); |
| REG_WR(cb, NIG_REG_BMAC0_OUT_EN + port*4, 0x0); |
| |
| /* Enable the NIG in/out to the emac */ |
| REG_WR(cb, NIG_REG_EMAC0_IN_EN + port*4, 0x1); |
| val = 0; |
| if ((params->feature_config_flags & |
| ELINK_FEATURE_CONFIG_PFC_ENABLED) || |
| (vars->flow_ctrl & ELINK_FLOW_CTRL_TX)) |
| val = 1; |
| |
| REG_WR(cb, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val); |
| REG_WR(cb, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1); |
| |
| #ifdef ELINK_INCLUDE_EMUL |
| if (CHIP_REV_IS_EMUL(params->chip_id)) { |
| /* Take the BigMac out of reset */ |
| REG_WR(cb, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, |
| (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); |
| |
| /* Enable access for bmac registers */ |
| REG_WR(cb, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1); |
| } else |
| #endif /* ELINK_INCLUDE_EMUL */ |
| REG_WR(cb, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x0); |
| |
| vars->mac_type = ELINK_MAC_TYPE_EMAC; |
| return ELINK_STATUS_OK; |
| } |
| |
| #endif //EXCLUDE_EMAC |
| #ifndef EXCLUDE_BMAC1 |
| static void elink_update_pfc_bmac1(struct elink_params *params, |
| struct elink_vars *vars) |
| { |
| u32 wb_data[2]; |
| struct elink_dev *cb = params->cb; |
| u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM : |
| NIG_REG_INGRESS_BMAC0_MEM; |
| |
| u32 val = 0x14; |
| if ((!(params->feature_config_flags & |
| ELINK_FEATURE_CONFIG_PFC_ENABLED)) && |
| (vars->flow_ctrl & ELINK_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(cb, bmac_addr + BIGMAC_REGISTER_RX_CONTROL, wb_data, 2); |
| |
| /* TX control */ |
| val = 0xc0; |
| if (!(params->feature_config_flags & |
| ELINK_FEATURE_CONFIG_PFC_ENABLED) && |
| (vars->flow_ctrl & ELINK_FLOW_CTRL_TX)) |
| val |= 0x800000; |
| wb_data[0] = val; |
| wb_data[1] = 0; |
| REG_WR_DMAE(cb, bmac_addr + BIGMAC_REGISTER_TX_CONTROL, wb_data, 2); |
| } |
| #endif // EXCLUDE_BMAC1 |
| |
| #ifndef EXCLUDE_BMAC2 |
| static void elink_update_pfc_bmac2(struct elink_params *params, |
| struct elink_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 elink_dev *cb = params->cb; |
| u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM : |
| NIG_REG_INGRESS_BMAC0_MEM; |
| u32 val = 0x14; |
| |
| if ((!(params->feature_config_flags & |
| ELINK_FEATURE_CONFIG_PFC_ENABLED)) && |
| (vars->flow_ctrl & ELINK_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(cb, bmac_addr + BIGMAC2_REGISTER_RX_CONTROL, wb_data, 2); |
| USLEEP(cb, 30); |
| |
| /* Tx control */ |
| val = 0xc0; |
| if (!(params->feature_config_flags & |
| ELINK_FEATURE_CONFIG_PFC_ENABLED) && |
| (vars->flow_ctrl & ELINK_FLOW_CTRL_TX)) |
| val |= 0x800000; |
| wb_data[0] = val; |
| wb_data[1] = 0; |
| REG_WR_DMAE(cb, bmac_addr + BIGMAC2_REGISTER_TX_CONTROL, wb_data, 2); |
| |
| if (params->feature_config_flags & ELINK_FEATURE_CONFIG_PFC_ENABLED) { |
| ELINK_DEBUG_P0(cb, "PFC is enabled\n"); |
| /* Enable PFC RX & TX & STATS and set 8 COS */ |
| wb_data[0] = 0x0; |
| wb_data[0] |= (1<<0); /* RX */ |
| wb_data[0] |= (1<<1); /* TX */ |
| wb_data[0] |= (1<<2); /* Force initial Xon */ |
| wb_data[0] |= (1<<3); /* 8 cos */ |
| wb_data[0] |= (1<<5); /* STATS */ |
| wb_data[1] = 0; |
| REG_WR_DMAE(cb, bmac_addr + BIGMAC2_REGISTER_PFC_CONTROL, |
| wb_data, 2); |
| /* Clear the force Xon */ |
| wb_data[0] &= ~(1<<2); |
| } else { |
| ELINK_DEBUG_P0(cb, "PFC is disabled\n"); |
| /* Disable PFC RX & TX & STATS and set 8 COS */ |
| wb_data[0] = 0x8; |
| wb_data[1] = 0; |
| } |
| |
| REG_WR_DMAE(cb, bmac_addr + BIGMAC2_REGISTER_PFC_CONTROL, wb_data, 2); |
| |
| /* Set Time (based unit is 512 bit time) between automatic |
| * re-sending of PP packets amd enable automatic re-send of |
| * Per-Priroity Packet as long as pp_gen is asserted and |
| * pp_disable is low. |
| */ |
| val = 0x8000; |
| if (params->feature_config_flags & ELINK_FEATURE_CONFIG_PFC_ENABLED) |
| val |= (1<<16); /* enable automatic re-send */ |
| |
| wb_data[0] = val; |
| wb_data[1] = 0; |
| REG_WR_DMAE(cb, bmac_addr + BIGMAC2_REGISTER_TX_PAUSE_CONTROL, |
| wb_data, 2); |
| |
| /* mac control */ |
| val = 0x3; /* Enable RX and TX */ |
| if (is_lb) { |
| val |= 0x4; /* Local loopback */ |
| ELINK_DEBUG_P0(cb, "enable bmac loopback\n"); |
| } |
| /* When PFC enabled, Pass pause frames towards the NIG. */ |
| if (params->feature_config_flags & ELINK_FEATURE_CONFIG_PFC_ENABLED) |
| val |= ((1<<6)|(1<<5)); |
| |
| wb_data[0] = val; |
| wb_data[1] = 0; |
| REG_WR_DMAE(cb, bmac_addr + BIGMAC2_REGISTER_BMAC_CONTROL, wb_data, 2); |
| } |
| #endif // EXCLUDE_BMAC2 |
| #endif // EXCLUDE_NON_COMMON_INIT |
| #ifdef ELINK_ENHANCEMENTS |
| |
| /****************************************************************************** |
| * Description: |
| * This function is needed because NIG ARB_CREDIT_WEIGHT_X are |
| * not continues and ARB_CREDIT_WEIGHT_0 + offset is suitable. |
| ******************************************************************************/ |
| static elink_status_t elink_pfc_nig_rx_priority_mask(struct elink_dev *cb, |
| u8 cos_entry, |
| u32 priority_mask, u8 port) |
| { |
| u32 nig_reg_rx_priority_mask_add = 0; |
| |
| switch (cos_entry) { |
| case 0: |
| nig_reg_rx_priority_mask_add = (port) ? |
| NIG_REG_P1_RX_COS0_PRIORITY_MASK : |
| NIG_REG_P0_RX_COS0_PRIORITY_MASK; |
| break; |
| case 1: |
| nig_reg_rx_priority_mask_add = (port) ? |
| NIG_REG_P1_RX_COS1_PRIORITY_MASK : |
| NIG_REG_P0_RX_COS1_PRIORITY_MASK; |
| break; |
| case 2: |
| nig_reg_rx_priority_mask_add = (port) ? |
| NIG_REG_P1_RX_COS2_PRIORITY_MASK : |
| NIG_REG_P0_RX_COS2_PRIORITY_MASK; |
| break; |
| case 3: |
| if (port) |
| return ELINK_STATUS_ERROR; |
| nig_reg_rx_priority_mask_add = NIG_REG_P0_RX_COS3_PRIORITY_MASK; |
| break; |
| case 4: |
| if (port) |
| return ELINK_STATUS_ERROR; |
| nig_reg_rx_priority_mask_add = NIG_REG_P0_RX_COS4_PRIORITY_MASK; |
| break; |
| case 5: |
| if (port) |
| return ELINK_STATUS_ERROR; |
| nig_reg_rx_priority_mask_add = NIG_REG_P0_RX_COS5_PRIORITY_MASK; |
| break; |
| } |
| |
| REG_WR(cb, nig_reg_rx_priority_mask_add, priority_mask); |
| |
| return ELINK_STATUS_OK; |
| } |
| #endif // ELINK_ENHANCEMENTS |
| #ifndef EXCLUDE_NON_COMMON_INIT |
| static void elink_update_mng(struct elink_params *params, u32 link_status) |
| { |
| struct elink_dev *cb = params->cb; |
| |
| REG_WR(cb, params->shmem_base + |
| OFFSETOF(struct shmem_region, |
| port_mb[params->port].link_status), link_status); |
| } |
| |
| #ifdef ELINK_ENHANCEMENTS |
| static void elink_update_pfc_nig(struct elink_params *params, |
| struct elink_vars *vars, |
| struct elink_nig_brb_pfc_port_params *nig_params) |
| { |
| u32 xcm_mask = 0, ppp_enable = 0, pause_enable = 0, llfc_out_en = 0; |
| u32 llfc_enable = 0, xcm_out_en = 0, hwpfc_enable = 0; |
| u32 pkt_priority_to_cos = 0; |
| struct elink_dev *cb = params->cb; |
| u8 port = params->port; |
| |
| int set_pfc = params->feature_config_flags & |
| ELINK_FEATURE_CONFIG_PFC_ENABLED; |
| ELINK_DEBUG_P0(cb, "updating pfc nig parameters\n"); |
| |
| /* When NIG_LLH0_XCM_MASK_REG_LLHX_XCM_MASK_BCN bit is set |
| * MAC control frames (that are not pause packets) |
| * will be forwarded to the XCM. |
| */ |
| xcm_mask = REG_RD(cb, port ? NIG_REG_LLH1_XCM_MASK : |
| NIG_REG_LLH0_XCM_MASK); |
| /* NIG params will override non PFC params, since it's possible to |
| * do transition from PFC to SAFC |
| */ |
| if (set_pfc) { |
| pause_enable = 0; |
| llfc_out_en = 0; |
| llfc_enable = 0; |
| if (CHIP_IS_E3(params->chip_id)) |
| ppp_enable = 0; |
| else |
| ppp_enable = 1; |
| xcm_mask &= ~(port ? NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN : |
| NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN); |
| xcm_out_en = 0; |
| hwpfc_enable = 1; |
| } else { |
| if (nig_params) { |
| llfc_out_en = nig_params->llfc_out_en; |
| llfc_enable = nig_params->llfc_enable; |
| pause_enable = nig_params->pause_enable; |
| } else /* Default non PFC mode - PAUSE */ |
| pause_enable = 1; |
| |
| xcm_mask |= (port ? NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN : |
| NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN); |
| xcm_out_en = 1; |
| } |
| |
| if (CHIP_IS_E3(params->chip_id)) |
| REG_WR(cb, port ? NIG_REG_BRB1_PAUSE_IN_EN : |
| NIG_REG_BRB0_PAUSE_IN_EN, pause_enable); |
| REG_WR(cb, port ? NIG_REG_LLFC_OUT_EN_1 : |
| NIG_REG_LLFC_OUT_EN_0, llfc_out_en); |
| REG_WR(cb, port ? NIG_REG_LLFC_ENABLE_1 : |
| NIG_REG_LLFC_ENABLE_0, llfc_enable); |
| REG_WR(cb, port ? NIG_REG_PAUSE_ENABLE_1 : |
| NIG_REG_PAUSE_ENABLE_0, pause_enable); |
| |
| REG_WR(cb, port ? NIG_REG_PPP_ENABLE_1 : |
| NIG_REG_PPP_ENABLE_0, ppp_enable); |
| |
| REG_WR(cb, port ? NIG_REG_LLH1_XCM_MASK : |
| NIG_REG_LLH0_XCM_MASK, xcm_mask); |
| |
| REG_WR(cb, port ? NIG_REG_LLFC_EGRESS_SRC_ENABLE_1 : |
| NIG_REG_LLFC_EGRESS_SRC_ENABLE_0, 0x7); |
| |
| /* Output enable for RX_XCM # IF */ |
| REG_WR(cb, port ? NIG_REG_XCM1_OUT_EN : |
| NIG_REG_XCM0_OUT_EN, xcm_out_en); |
| |
| /* HW PFC TX enable */ |
| REG_WR(cb, port ? NIG_REG_P1_HWPFC_ENABLE : |
| NIG_REG_P0_HWPFC_ENABLE, hwpfc_enable); |
| |
| if (nig_params) { |
| u8 i = 0; |
| pkt_priority_to_cos = nig_params->pkt_priority_to_cos; |
| |
| for (i = 0; i < nig_params->num_of_rx_cos_priority_mask; i++) |
| elink_pfc_nig_rx_priority_mask(cb, i, |
| nig_params->rx_cos_priority_mask[i], port); |
| |
| REG_WR(cb, port ? NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_1 : |
| NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_0, |
| nig_params->llfc_high_priority_classes); |
| |
| REG_WR(cb, port ? NIG_REG_LLFC_LOW_PRIORITY_CLASSES_1 : |
| NIG_REG_LLFC_LOW_PRIORITY_CLASSES_0, |
| nig_params->llfc_low_priority_classes); |
| } |
| REG_WR(cb, port ? NIG_REG_P1_PKT_PRIORITY_TO_COS : |
| NIG_REG_P0_PKT_PRIORITY_TO_COS, |
| pkt_priority_to_cos); |
| } |
| |
| elink_status_t elink_update_pfc(struct elink_params *params, |
| struct elink_vars *vars, |
| struct elink_nig_brb_pfc_port_params *pfc_params) |
| { |
| /* The PFC and pause are orthogonal to one another, meaning when |
| * PFC is enabled, the pause are disabled, and when PFC is |
| * disabled, pause are set according to the pause result. |
| */ |
| u32 val; |
| struct elink_dev *cb = params->cb; |
| u8 bmac_loopback = (params->loopback_mode == ELINK_LOOPBACK_BMAC); |
| |
| if (params->feature_config_flags & ELINK_FEATURE_CONFIG_PFC_ENABLED) |
| vars->link_status |= LINK_STATUS_PFC_ENABLED; |
| else |
| vars->link_status &= ~LINK_STATUS_PFC_ENABLED; |
| |
| elink_update_mng(params, vars->link_status); |
| |
| /* Update NIG params */ |
| elink_update_pfc_nig(params, vars, pfc_params); |
| |
| if (!vars->link_up) |
| return ELINK_STATUS_OK; |
| |
| ELINK_DEBUG_P0(cb, "About to update PFC in BMAC\n"); |
| |
| if (CHIP_IS_E3(params->chip_id)) { |
| if (vars->mac_type == ELINK_MAC_TYPE_XMAC) |
| elink_update_pfc_xmac(params, vars, 0); |
| } else { |
| val = REG_RD(cb, MISC_REG_RESET_REG_2); |
| if ((val & |
| (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port)) |
| == 0) { |
| ELINK_DEBUG_P0(cb, "About to update PFC in EMAC\n"); |
| elink_emac_enable(params, vars, 0); |
| return ELINK_STATUS_OK; |
| } |
| if (CHIP_IS_E2(params->chip_id)) |
| elink_update_pfc_bmac2(params, vars, bmac_loopback); |
| else |
| elink_update_pfc_bmac1(params, vars); |
| |
| val = 0; |
| if ((params->feature_config_flags & |
| ELINK_FEATURE_CONFIG_PFC_ENABLED) || |
| (vars->flow_ctrl & ELINK_FLOW_CTRL_TX)) |
| val = 1; |
| REG_WR(cb, NIG_REG_BMAC0_PAUSE_OUT_EN + params->port*4, val); |
| } |
| return ELINK_STATUS_OK; |
| } |
| |
| #endif /* ELINK_ENHANCEMENTS */ |
| #ifndef EXCLUDE_BMAC1 |
| static elink_status_t elink_bmac1_enable(struct elink_params *params, |
| struct elink_vars *vars, |
| u8 is_lb) |
| { |
| struct elink_dev *cb = params->cb; |
| u8 port = params->port; |
| u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM : |
| NIG_REG_INGRESS_BMAC0_MEM; |
| u32 wb_data[2]; |
| u32 val; |
| |
| ELINK_DEBUG_P0(cb, "Enabling BigMAC1\n"); |
| |
| /* XGXS control */ |
| wb_data[0] = 0x3c; |
| wb_data[1] = 0; |
| REG_WR_DMAE(cb, bmac_addr + BIGMAC_REGISTER_BMAC_XGXS_CONTROL, |
| wb_data, 2); |
| |
| /* TX MAC SA */ |
| wb_data[0] = ((params->mac_addr[2] << 24) | |
| (params->mac_addr[3] << 16) | |
| (params->mac_addr[4] << 8) | |
| params->mac_addr[5]); |
| wb_data[1] = ((params->mac_addr[0] << 8) | |
| params->mac_addr[1]); |
| REG_WR_DMAE(cb, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR, wb_data, 2); |
| |
| /* MAC control */ |
| val = 0x3; |
| if (is_lb) { |
| val |= 0x4; |
| ELINK_DEBUG_P0(cb, "enable bmac loopback\n"); |
| } |
| wb_data[0] = val; |
| wb_data[1] = 0; |
| REG_WR_DMAE(cb, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL, wb_data, 2); |
| |
| /* Set rx mtu */ |
| wb_data[0] = ELINK_ETH_MAX_JUMBO_PACKET_SIZE + ELINK_ETH_OVREHEAD; |
| wb_data[1] = 0; |
| REG_WR_DMAE(cb, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE, wb_data, 2); |
| |
| elink_update_pfc_bmac1(params, vars); |
| |
| /* Set tx mtu */ |
| wb_data[0] = ELINK_ETH_MAX_JUMBO_PACKET_SIZE + ELINK_ETH_OVREHEAD; |
| wb_data[1] = 0; |
| REG_WR_DMAE(cb, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE, wb_data, 2); |
| |
| /* Set cnt max size */ |
| wb_data[0] = ELINK_ETH_MAX_JUMBO_PACKET_SIZE + ELINK_ETH_OVREHEAD; |
| wb_data[1] = 0; |
| REG_WR_DMAE(cb, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE, wb_data, 2); |
| |
| /* Configure SAFC */ |
| wb_data[0] = 0x1000200; |
| wb_data[1] = 0; |
| REG_WR_DMAE(cb, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS, |
| wb_data, 2); |
| #ifdef ELINK_INCLUDE_EMUL |
| /* Fix for emulation */ |
| if (CHIP_REV_IS_EMUL(params->chip_id)) { |
| wb_data[0] = 0xf000; |
| wb_data[1] = 0; |
| REG_WR_DMAE(cb, bmac_addr + BIGMAC_REGISTER_TX_PAUSE_THRESHOLD, |
| wb_data, 2); |
| } |
| #endif /* ELINK_INCLUDE_EMUL */ |
| |
| return ELINK_STATUS_OK; |
| } |
| #endif /* EXCLUDE_BMAC1 */ |
| |
| #ifndef EXCLUDE_BMAC2 |
| static elink_status_t elink_bmac2_enable(struct elink_params *params, |
| struct elink_vars *vars, |
| u8 is_lb) |
| { |
| struct elink_dev *cb = params->cb; |
| u8 port = params->port; |
| u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM : |
| NIG_REG_INGRESS_BMAC0_MEM; |
| u32 wb_data[2]; |
| |
| ELINK_DEBUG_P0(cb, "Enabling BigMAC2\n"); |
| |
| wb_data[0] = 0; |
| wb_data[1] = 0; |
| REG_WR_DMAE(cb, bmac_addr + BIGMAC2_REGISTER_BMAC_CONTROL, wb_data, 2); |
| USLEEP(cb, 30); |
| |
| /* XGXS control: Reset phy HW, MDIO registers, PHY PLL and BMAC */ |
| wb_data[0] = 0x3c; |
| wb_data[1] = 0; |
| REG_WR_DMAE(cb, bmac_addr + BIGMAC2_REGISTER_BMAC_XGXS_CONTROL, |
| wb_data, 2); |
| |
| USLEEP(cb, 30); |
| |
| /* TX MAC SA */ |
| wb_data[0] = ((params->mac_addr[2] << 24) | |
| (params->mac_addr[3] << 16) | |
| (params->mac_addr[4] << 8) | |
| params->mac_addr[5]); |
| wb_data[1] = ((params->mac_addr[0] << 8) | |
| params->mac_addr[1]); |
| REG_WR_DMAE(cb, bmac_addr + BIGMAC2_REGISTER_TX_SOURCE_ADDR, |
| wb_data, 2); |
| |
| USLEEP(cb, 30); |
| |
| /* Configure SAFC */ |
| wb_data[0] = 0x1000200; |
| wb_data[1] = 0; |
| REG_WR_DMAE(cb, bmac_addr + BIGMAC2_REGISTER_RX_LLFC_MSG_FLDS, |
| wb_data, 2); |
| USLEEP(cb, 30); |
| |
| /* Set RX MTU */ |
| wb_data[0] = ELINK_ETH_MAX_JUMBO_PACKET_SIZE + ELINK_ETH_OVREHEAD; |
| wb_data[1] = 0; |
| REG_WR_DMAE(cb, bmac_addr + BIGMAC2_REGISTER_RX_MAX_SIZE, wb_data, 2); |
| USLEEP(cb, 30); |
| |
| /* Set TX MTU */ |
| wb_data[0] = ELINK_ETH_MAX_JUMBO_PACKET_SIZE + ELINK_ETH_OVREHEAD; |
| wb_data[1] = 0; |
| REG_WR_DMAE(cb, bmac_addr + BIGMAC2_REGISTER_TX_MAX_SIZE, wb_data, 2); |
| USLEEP(cb, 30); |
| /* Set cnt max size */ |
| wb_data[0] = ELINK_ETH_MAX_JUMBO_PACKET_SIZE + ELINK_ETH_OVREHEAD - 2; |
| wb_data[1] = 0; |
| REG_WR_DMAE(cb, bmac_addr + BIGMAC2_REGISTER_CNT_MAX_SIZE, wb_data, 2); |
| USLEEP(cb, 30); |
| elink_update_pfc_bmac2(params, vars, is_lb); |
| |
| return ELINK_STATUS_OK; |
| } |
| #endif /* EXCLUDE_BMAC2 */ |
| |
| #if !defined(EXCLUDE_BMAC2) |
| static elink_status_t elink_bmac_enable(struct elink_params *params, |
| struct elink_vars *vars, |
| u8 is_lb, u8 reset_bmac) |
| { |
| elink_status_t rc = ELINK_STATUS_OK; |
| u8 port = params->port; |
| struct elink_dev *cb = params->cb; |
| u32 val; |
| /* Reset and unreset the BigMac */ |
| if (reset_bmac) { |
| REG_WR(cb, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, |
| (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); |
| MSLEEP(cb, 1); |
| } |
| |
| REG_WR(cb, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, |
| (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); |
| |
| /* Enable access for bmac registers */ |
| REG_WR(cb, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1); |
| |
| /* Enable BMAC according to BMAC type*/ |
| #ifdef ELINK_ENHANCEMENTS |
| if (CHIP_IS_E2(params->chip_id)) |
| #endif |
| #ifndef EXCLUDE_BMAC2 |
| rc = elink_bmac2_enable(params, vars, is_lb); |
| #endif |
| #ifdef ELINK_ENHANCEMENTS |
| else |
| #endif |
| #ifndef EXCLUDE_BMAC1 |
| rc = elink_bmac1_enable(params, vars, is_lb); |
| #endif |
| REG_WR(cb, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1); |
| REG_WR(cb, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0); |
| REG_WR(cb, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0); |
| val = 0; |
| if ((params->feature_config_flags & |
| ELINK_FEATURE_CONFIG_PFC_ENABLED) || |
| (vars->flow_ctrl & ELINK_FLOW_CTRL_TX)) |
| val = 1; |
| REG_WR(cb, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val); |
| REG_WR(cb, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0); |
| REG_WR(cb, NIG_REG_EMAC0_IN_EN + port*4, 0x0); |
| REG_WR(cb, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0); |
| REG_WR(cb, NIG_REG_BMAC0_IN_EN + port*4, 0x1); |
| REG_WR(cb, NIG_REG_BMAC0_OUT_EN + port*4, 0x1); |
| |
| vars->mac_type = ELINK_MAC_TYPE_BMAC; |
| return rc; |
| } |
| #endif /* #if !defined(EXCLUDE_BMAC2) && !defined(EXCLUDE_BMAC1) */ |
| |
| #if !defined(EXCLUDE_BMAC2) && !defined(EXCLUDE_BMAC1) |
| static void elink_set_bmac_rx(struct elink_dev *cb, u32 chip_id, u8 port, u8 en) |
| { |
| u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM : |
| NIG_REG_INGRESS_BMAC0_MEM; |
| u32 wb_data[2]; |
| u32 nig_bmac_enable = REG_RD(cb, NIG_REG_BMAC0_REGS_OUT_EN + port*4); |
| |
| if (CHIP_IS_E2(chip_id)) |
| bmac_addr += BIGMAC2_REGISTER_BMAC_CONTROL; |
| else |
| bmac_addr += BIGMAC_REGISTER_BMAC_CONTROL; |
| /* Only if the bmac is out of reset */ |
| if (REG_RD(cb, MISC_REG_RESET_REG_2) & |
| (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) && |
| nig_bmac_enable) { |
| /* Clear Rx Enable bit in BMAC_CONTROL register */ |
| REG_RD_DMAE(cb, bmac_addr, wb_data, 2); |
| if (en) |
| wb_data[0] |= ELINK_BMAC_CONTROL_RX_ENABLE; |
| else |
| wb_data[0] &= ~ELINK_BMAC_CONTROL_RX_ENABLE; |
| REG_WR_DMAE(cb, bmac_addr, wb_data, 2); |
| MSLEEP(cb, 1); |
| } |
| } |
| #endif /* !defined(EXCLUDE_BMAC2) && !defined(EXCLUDE_BMAC1) */ |
| #endif // EXCLUDE_NON_COMMON_INIT |
| |
| #ifndef ELINK_AUX_POWER |
| static elink_status_t elink_pbf_update(struct elink_params *params, u32 flow_ctrl, |
| u32 line_speed) |
| { |
| struct elink_dev *cb = params->cb; |
| u8 port = params->port; |
| u32 init_crd, crd; |
| u32 count = 1000; |
| |
| /* Disable port */ |
| REG_WR(cb, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1); |
| |
| /* Wait for init credit */ |
| init_crd = REG_RD(cb, PBF_REG_P0_INIT_CRD + port*4); |
| crd = REG_RD(cb, PBF_REG_P0_CREDIT + port*8); |
| ELINK_DEBUG_P2(cb, "init_crd 0x%x crd 0x%x\n", init_crd, crd); |
| |
| while ((init_crd != crd) && count) { |
| MSLEEP(cb, 5); |
| crd = REG_RD(cb, PBF_REG_P0_CREDIT + port*8); |
| count--; |
| } |
| crd = REG_RD(cb, PBF_REG_P0_CREDIT + port*8); |
| if (init_crd != crd) { |
| ELINK_DEBUG_P2(cb, "BUG! init_crd 0x%x != crd 0x%x\n", |
| init_crd, crd); |
| return ELINK_STATUS_ERROR; |
| } |
| |
| if (flow_ctrl & ELINK_FLOW_CTRL_RX || |
| line_speed == ELINK_SPEED_10 || |
| line_speed == ELINK_SPEED_100 || |
| line_speed == ELINK_SPEED_1000 || |
| line_speed == ELINK_SPEED_2500) { |
| REG_WR(cb, PBF_REG_P0_PAUSE_ENABLE + port* |