diff options
Diffstat (limited to 'drivers/net/bnx2x/bnx2x_link.c')
-rw-r--r-- | drivers/net/bnx2x/bnx2x_link.c | 218 |
1 files changed, 147 insertions, 71 deletions
diff --git a/drivers/net/bnx2x/bnx2x_link.c b/drivers/net/bnx2x/bnx2x_link.c index bcd8f003862..d45b1555a60 100644 --- a/drivers/net/bnx2x/bnx2x_link.c +++ b/drivers/net/bnx2x/bnx2x_link.c @@ -1546,6 +1546,12 @@ static void bnx2x_umac_enable(struct link_params *params, vars->line_speed); break; } + if (!(vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)) + val |= UMAC_COMMAND_CONFIG_REG_IGNORE_TX_PAUSE; + + if (!(vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)) + val |= UMAC_COMMAND_CONFIG_REG_PAUSE_IGNORE; + REG_WR(bp, umac_base + UMAC_REG_COMMAND_CONFIG, val); udelay(50); @@ -1661,10 +1667,20 @@ static void bnx2x_xmac_disable(struct link_params *params) { u8 port = params->port; struct bnx2x *bp = params->bp; - u32 xmac_base = (port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0; + u32 pfc_ctrl, xmac_base = (port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0; if (REG_RD(bp, MISC_REG_RESET_REG_2) & MISC_REGISTERS_RESET_REG_2_XMAC) { + /* + * Send an indication to change the state in the NIG back to XON + * Clearing this bit enables the next set of this bit to get + * rising edge + */ + pfc_ctrl = REG_RD(bp, xmac_base + XMAC_REG_PFC_CTRL_HI); + REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL_HI, + (pfc_ctrl & ~(1<<1))); + REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL_HI, + (pfc_ctrl | (1<<1))); DP(NETIF_MSG_LINK, "Disable XMAC on port %x\n", port); REG_WR(bp, xmac_base + XMAC_REG_CTRL, 0); usleep_range(1000, 1000); @@ -1729,6 +1745,10 @@ static int bnx2x_emac_enable(struct link_params *params, DP(NETIF_MSG_LINK, "enabling EMAC\n"); + /* Disable BMAC */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); + /* enable emac and not bmac */ REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1); @@ -2583,12 +2603,6 @@ static int bnx2x_bmac1_enable(struct link_params *params, REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS, wb_data, 2); - if (vars->phy_flags & PHY_TX_ERROR_CHECK_FLAG) { - REG_RD_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LSS_STATUS, - wb_data, 2); - if (wb_data[0] > 0) - return -ESRCH; - } return 0; } @@ -2654,16 +2668,6 @@ static int bnx2x_bmac2_enable(struct link_params *params, udelay(30); bnx2x_update_pfc_bmac2(params, vars, is_lb); - if (vars->phy_flags & PHY_TX_ERROR_CHECK_FLAG) { - REG_RD_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_LSS_STAT, - wb_data, 2); - if (wb_data[0] > 0) { - DP(NETIF_MSG_LINK, "Got bad LSS status 0x%x\n", - wb_data[0]); - return -ESRCH; - } - } - return 0; } @@ -2949,7 +2953,9 @@ static int bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy, u32 val; u16 i; int rc = 0; - + if (phy->flags & FLAGS_MDC_MDIO_WA_B0) + bnx2x_bits_en(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_STATUS, + EMAC_MDIO_STATUS_10MB); /* address */ val = ((phy->addr << 21) | (devad << 16) | reg | EMAC_MDIO_COMM_COMMAND_ADDRESS | @@ -3003,6 +3009,9 @@ static int bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy, } } + if (phy->flags & FLAGS_MDC_MDIO_WA_B0) + bnx2x_bits_dis(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_STATUS, + EMAC_MDIO_STATUS_10MB); return rc; } @@ -3012,6 +3021,9 @@ static int bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy, u32 tmp; u8 i; int rc = 0; + if (phy->flags & FLAGS_MDC_MDIO_WA_B0) + bnx2x_bits_en(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_STATUS, + EMAC_MDIO_STATUS_10MB); /* address */ @@ -3065,7 +3077,9 @@ static int bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy, bnx2x_cl45_read(bp, phy, devad, 0xf, &temp_val); } } - + if (phy->flags & FLAGS_MDC_MDIO_WA_B0) + bnx2x_bits_dis(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_STATUS, + EMAC_MDIO_STATUS_10MB); return rc; } @@ -4353,6 +4367,9 @@ void bnx2x_link_status_update(struct link_params *params, vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP); vars->phy_flags = PHY_XGXS_FLAG; + if (vars->link_status & LINK_STATUS_PHYSICAL_LINK_FLAG) + vars->phy_flags |= PHY_PHYSICAL_LINK_FLAG; + if (vars->link_up) { DP(NETIF_MSG_LINK, "phy link up\n"); @@ -4444,6 +4461,8 @@ void bnx2x_link_status_update(struct link_params *params, /* indicate no mac active */ vars->mac_type = MAC_TYPE_NONE; + if (vars->link_status & LINK_STATUS_PHYSICAL_LINK_FLAG) + vars->phy_flags |= PHY_HALF_OPEN_CONN_FLAG; } /* Sync media type */ @@ -5903,20 +5922,30 @@ int bnx2x_set_led(struct link_params *params, tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED); EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE)); - return rc; + /* + * return here without enabling traffic + * LED blink andsetting rate in ON mode. + * In oper mode, enabling LED blink + * and setting rate is needed. + */ + if (mode == LED_MODE_ON) + return rc; } - } else if (SINGLE_MEDIA_DIRECT(params) && - (CHIP_IS_E1x(bp) || - CHIP_IS_E2(bp))) { + } else if (SINGLE_MEDIA_DIRECT(params)) { /* * This is a work-around for HW issue found when link * is up in CL73 */ - REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0); REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1); - } else { + if (CHIP_IS_E1x(bp) || + CHIP_IS_E2(bp) || + (mode == LED_MODE_ON)) + REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0); + else + REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, + hw_led_mode); + } else REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, hw_led_mode); - } REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 + port*4, 0); /* Set blinking rate to ~15.9Hz */ @@ -6160,6 +6189,7 @@ static int bnx2x_update_link_down(struct link_params *params, /* update shared memory */ vars->link_status &= ~(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 | @@ -6197,7 +6227,8 @@ static int bnx2x_update_link_up(struct link_params *params, u8 port = params->port; int rc = 0; - vars->link_status |= LINK_STATUS_LINK_UP; + vars->link_status |= (LINK_STATUS_LINK_UP | + LINK_STATUS_PHYSICAL_LINK_FLAG); vars->phy_flags |= PHY_PHYSICAL_LINK_FLAG; if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) @@ -7998,6 +8029,9 @@ static void bnx2x_warpcore_set_limiting_mode(struct link_params *params, bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE, &val); + /* Restart microcode to re-read the new mode */ + bnx2x_warpcore_reset_lane(bp, phy, 1); + bnx2x_warpcore_reset_lane(bp, phy, 0); } @@ -8116,7 +8150,6 @@ void bnx2x_handle_module_detect_int(struct link_params *params) offsetof(struct shmem_region, dev_info. port_feature_config[params->port]. config)); - bnx2x_set_gpio_int(bp, gpio_num, MISC_REGISTERS_GPIO_INT_OUTPUT_SET, gpio_port); @@ -8125,8 +8158,9 @@ void bnx2x_handle_module_detect_int(struct link_params *params) * Disable transmit for this module */ phy->media_type = ETH_PHY_NOT_PRESENT; - if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == - PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) + if (((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == + PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) || + CHIP_IS_E3(bp)) bnx2x_sfp_set_transmitter(params, phy, 0); } } @@ -8228,9 +8262,6 @@ static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy, u16 cnt, val, tmp1; struct bnx2x *bp = params->bp; - /* SPF+ PHY: Set flag to check for Tx error */ - vars->phy_flags = PHY_TX_ERROR_CHECK_FLAG; - bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port); /* HW reset */ @@ -8414,9 +8445,6 @@ static int bnx2x_8726_config_init(struct bnx2x_phy *phy, struct bnx2x *bp = params->bp; DP(NETIF_MSG_LINK, "Initializing BCM8726\n"); - /* SPF+ PHY: Set flag to check for Tx error */ - vars->phy_flags = PHY_TX_ERROR_CHECK_FLAG; - bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15); bnx2x_wait_reset_complete(bp, phy, params); @@ -8585,9 +8613,6 @@ static int bnx2x_8727_config_init(struct bnx2x_phy *phy, struct bnx2x *bp = params->bp; /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */ - /* SPF+ PHY: Set flag to check for Tx error */ - vars->phy_flags = PHY_TX_ERROR_CHECK_FLAG; - bnx2x_wait_reset_complete(bp, phy, params); rx_alarm_ctrl_val = (1<<2) | (1<<5) ; /* Should be 0x6 to enable XS on Tx side. */ @@ -9243,7 +9268,13 @@ static int bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy, if (phy->req_duplex == DUPLEX_FULL) autoneg_val |= (1<<8); - bnx2x_cl45_write(bp, phy, + /* + * Always write this if this is not 84833. + * For 84833, write it only when it's a forced speed. + */ + if ((phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) || + ((autoneg_val & (1<<12)) == 0)) + bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_MII_CTRL, autoneg_val); @@ -9257,13 +9288,12 @@ static int bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy, bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x3200); - } else if (phy->req_line_speed != SPEED_10 && - phy->req_line_speed != SPEED_100) { + } else bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8481_10GBASE_T_AN_CTRL, 1); - } + /* Save spirom version */ bnx2x_save_848xx_spirom_version(phy, params); @@ -9756,11 +9786,9 @@ static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy, bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, 0x400f, &val16); - /* Put to low power mode on newer FW */ - if ((val16 & 0x303f) > 0x1009) - bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_CTRL, 0x800); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, 0x800); } } @@ -10191,8 +10219,15 @@ static void bnx2x_54618se_link_reset(struct bnx2x_phy *phy, u32 cfg_pin; u8 port; - /* This works with E3 only, no need to check the chip - before determining the port. */ + /* + * In case of no EPIO routed to reset the GPHY, put it + * in low power mode. + */ + bnx2x_cl22_write(bp, phy, MDIO_PMA_REG_CTRL, 0x800); + /* + * This works with E3 only, no need to check the chip + * before determining the port. + */ port = params->port; cfg_pin = (REG_RD(bp, params->shmem_base + offsetof(struct shmem_region, @@ -10603,7 +10638,8 @@ static struct bnx2x_phy phy_warpcore = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT, .addr = 0xff, .def_md_devad = 0, - .flags = FLAGS_HW_LOCK_REQUIRED, + .flags = (FLAGS_HW_LOCK_REQUIRED | + FLAGS_TX_ERROR_CHECK), .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, @@ -10729,7 +10765,8 @@ static struct bnx2x_phy phy_8706 = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706, .addr = 0xff, .def_md_devad = 0, - .flags = FLAGS_INIT_XGXS_FIRST, + .flags = (FLAGS_INIT_XGXS_FIRST | + FLAGS_TX_ERROR_CHECK), .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, @@ -10760,7 +10797,8 @@ static struct bnx2x_phy phy_8726 = { .addr = 0xff, .def_md_devad = 0, .flags = (FLAGS_HW_LOCK_REQUIRED | - FLAGS_INIT_XGXS_FIRST), + FLAGS_INIT_XGXS_FIRST | + FLAGS_TX_ERROR_CHECK), .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, @@ -10791,7 +10829,8 @@ static struct bnx2x_phy phy_8727 = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, .addr = 0xff, .def_md_devad = 0, - .flags = FLAGS_FAN_FAILURE_DET_REQ, + .flags = (FLAGS_FAN_FAILURE_DET_REQ | + FLAGS_TX_ERROR_CHECK), .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, @@ -11112,6 +11151,8 @@ static int bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port, */ if (CHIP_REV(bp) == CHIP_REV_Ax) phy->flags |= FLAGS_MDC_MDIO_WA; + else + phy->flags |= FLAGS_MDC_MDIO_WA_B0; } else { switch (switch_cfg) { case SWITCH_CFG_1G: @@ -11500,13 +11541,12 @@ void bnx2x_init_xmac_loopback(struct link_params *params, * Set WC to loopback mode since link is required to provide clock * to the XMAC in 20G mode */ - if (vars->line_speed == SPEED_20000) { - bnx2x_set_aer_mmd(params, ¶ms->phy[0]); - bnx2x_warpcore_reset_lane(bp, ¶ms->phy[0], 0); - params->phy[INT_PHY].config_loopback( + bnx2x_set_aer_mmd(params, ¶ms->phy[0]); + bnx2x_warpcore_reset_lane(bp, ¶ms->phy[0], 0); + params->phy[INT_PHY].config_loopback( ¶ms->phy[INT_PHY], params); - } + bnx2x_xmac_enable(params, vars, 1); REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); } @@ -11684,12 +11724,16 @@ int bnx2x_link_reset(struct link_params *params, struct link_vars *vars, bnx2x_set_led(params, vars, LED_MODE_OFF, 0); if (reset_ext_phy) { + bnx2x_set_mdio_clk(bp, params->chip_id, port); for (phy_index = EXT_PHY1; phy_index < params->num_phys; phy_index++) { - if (params->phy[phy_index].link_reset) + if (params->phy[phy_index].link_reset) { + bnx2x_set_aer_mmd(params, + ¶ms->phy[phy_index]); params->phy[phy_index].link_reset( ¶ms->phy[phy_index], params); + } if (params->phy[phy_index].flags & FLAGS_REARM_LATCH_SIGNAL) clear_latch_ind = 1; @@ -12178,10 +12222,6 @@ static void bnx2x_analyze_link_error(struct link_params *params, u8 led_mode; u32 half_open_conn = (vars->phy_flags & PHY_HALF_OPEN_CONN_FLAG) > 0; - /*DP(NETIF_MSG_LINK, "CHECK LINK: %x half_open:%x-> lss:%x\n", - vars->link_up, - half_open_conn, lss_status);*/ - if ((lss_status ^ half_open_conn) == 0) return; @@ -12194,6 +12234,7 @@ static void bnx2x_analyze_link_error(struct link_params *params, * b. Update link_vars->link_up */ if (lss_status) { + DP(NETIF_MSG_LINK, "Remote Fault detected !!!\n"); vars->link_status &= ~LINK_STATUS_LINK_UP; vars->link_up = 0; vars->phy_flags |= PHY_HALF_OPEN_CONN_FLAG; @@ -12203,6 +12244,7 @@ static void bnx2x_analyze_link_error(struct link_params *params, */ led_mode = LED_MODE_OFF; } else { + DP(NETIF_MSG_LINK, "Remote Fault cleared\n"); vars->link_status |= LINK_STATUS_LINK_UP; vars->link_up = 1; vars->phy_flags &= ~PHY_HALF_OPEN_CONN_FLAG; @@ -12219,6 +12261,15 @@ static void bnx2x_analyze_link_error(struct link_params *params, bnx2x_notify_link_changed(bp); } +/****************************************************************************** +* Description: +* This function checks for half opened connection change indication. +* When such change occurs, it calls the bnx2x_analyze_link_error +* to check if Remote Fault is set or cleared. Reception of remote fault +* status message in the MAC indicates that the peer's MAC has detected +* a fault, for example, due to break in the TX side of fiber. +* +******************************************************************************/ static void bnx2x_check_half_open_conn(struct link_params *params, struct link_vars *vars) { @@ -12229,9 +12280,28 @@ static void bnx2x_check_half_open_conn(struct link_params *params, if ((vars->phy_flags & PHY_PHYSICAL_LINK_FLAG) == 0) return; - if (!CHIP_IS_E3(bp) && + if (CHIP_IS_E3(bp) && (REG_RD(bp, MISC_REG_RESET_REG_2) & - (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port))) { + (MISC_REGISTERS_RESET_REG_2_XMAC))) { + /* Check E3 XMAC */ + /* + * Note that link speed cannot be queried here, since it may be + * zero while link is down. In case UMAC is active, LSS will + * simply not be set + */ + mac_base = (params->port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0; + + /* Clear stick bits (Requires rising edge) */ + REG_WR(bp, mac_base + XMAC_REG_CLEAR_RX_LSS_STATUS, 0); + REG_WR(bp, mac_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); + if (REG_RD(bp, mac_base + XMAC_REG_RX_LSS_STATUS)) + lss_status = 1; + + bnx2x_analyze_link_error(params, vars, lss_status); + } else if (REG_RD(bp, MISC_REG_RESET_REG_2) & + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port)) { /* Check E1X / E2 BMAC */ u32 lss_status_reg; u32 wb_data[2]; @@ -12253,14 +12323,20 @@ static void bnx2x_check_half_open_conn(struct link_params *params, void bnx2x_period_func(struct link_params *params, struct link_vars *vars) { struct bnx2x *bp = params->bp; + u16 phy_idx; if (!params) { - DP(NETIF_MSG_LINK, "Ininitliazed params !\n"); + DP(NETIF_MSG_LINK, "Uninitialized params !\n"); return; } - /* DP(NETIF_MSG_LINK, "Periodic called vars->phy_flags 0x%x speed 0x%x - RESET_REG_2 0x%x\n", vars->phy_flags, vars->line_speed, - REG_RD(bp, MISC_REG_RESET_REG_2)); */ - bnx2x_check_half_open_conn(params, vars); + + for (phy_idx = INT_PHY; phy_idx < MAX_PHYS; phy_idx++) { + if (params->phy[phy_idx].flags & FLAGS_TX_ERROR_CHECK) { + bnx2x_set_aer_mmd(params, ¶ms->phy[phy_idx]); + bnx2x_check_half_open_conn(params, vars); + break; + } + } + if (CHIP_IS_E3(bp)) bnx2x_check_over_curr(params, vars); } |