bnx2x: Fix SFP+ current leakage
Per measurements, the SFP+ suffered from small current leakage in two cases: - When no module was plugged and TX laser was disabled. The fix was to enable it, and when module is plugged in, check if it needs to be disabled. - When over-current event occurs due to invalid SFP+ module, the HW basically shuts down the current for this module, but the SW needs to complete this by issuing a power down via a GPIO. Signed-off-by: Yaniv Rosner <yanivr@broadcom.com> Signed-off-by: Eilon Greenstein <eilong@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
55386fe883
commit
5a1fbf4046
|
@ -4414,6 +4414,27 @@ static void bnx2x_warpcore_config_sfi(struct bnx2x_phy *phy,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void bnx2x_sfp_e3_set_transmitter(struct link_params *params,
|
||||||
|
struct bnx2x_phy *phy,
|
||||||
|
u8 tx_en)
|
||||||
|
{
|
||||||
|
struct bnx2x *bp = params->bp;
|
||||||
|
u32 cfg_pin;
|
||||||
|
u8 port = params->port;
|
||||||
|
|
||||||
|
cfg_pin = REG_RD(bp, params->shmem_base +
|
||||||
|
offsetof(struct shmem_region,
|
||||||
|
dev_info.port_hw_config[port].e3_sfp_ctrl)) &
|
||||||
|
PORT_HW_CFG_E3_TX_LASER_MASK;
|
||||||
|
/* Set the !tx_en since this pin is DISABLE_TX_LASER */
|
||||||
|
DP(NETIF_MSG_LINK, "Setting WC TX to %d\n", tx_en);
|
||||||
|
|
||||||
|
/* For 20G, the expected pin to be used is 3 pins after the current */
|
||||||
|
bnx2x_set_cfg_pin(bp, cfg_pin, tx_en ^ 1);
|
||||||
|
if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_20G)
|
||||||
|
bnx2x_set_cfg_pin(bp, cfg_pin + 3, tx_en ^ 1);
|
||||||
|
}
|
||||||
|
|
||||||
static void bnx2x_warpcore_config_init(struct bnx2x_phy *phy,
|
static void bnx2x_warpcore_config_init(struct bnx2x_phy *phy,
|
||||||
struct link_params *params,
|
struct link_params *params,
|
||||||
struct link_vars *vars)
|
struct link_vars *vars)
|
||||||
|
@ -4474,9 +4495,14 @@ static void bnx2x_warpcore_config_init(struct bnx2x_phy *phy,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PORT_HW_CFG_NET_SERDES_IF_SFI:
|
case PORT_HW_CFG_NET_SERDES_IF_SFI:
|
||||||
/* Issue Module detection */
|
/* Issue Module detection if module is plugged, or
|
||||||
|
* enabled transmitter to avoid current leakage in case
|
||||||
|
* no module is connected
|
||||||
|
*/
|
||||||
if (bnx2x_is_sfp_module_plugged(phy, params))
|
if (bnx2x_is_sfp_module_plugged(phy, params))
|
||||||
bnx2x_sfp_module_detection(phy, params);
|
bnx2x_sfp_module_detection(phy, params);
|
||||||
|
else
|
||||||
|
bnx2x_sfp_e3_set_transmitter(params, phy, 1);
|
||||||
|
|
||||||
bnx2x_warpcore_config_sfi(phy, params);
|
bnx2x_warpcore_config_sfi(phy, params);
|
||||||
break;
|
break;
|
||||||
|
@ -4513,27 +4539,6 @@ static void bnx2x_warpcore_config_init(struct bnx2x_phy *phy,
|
||||||
DP(NETIF_MSG_LINK, "Exit config init\n");
|
DP(NETIF_MSG_LINK, "Exit config init\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bnx2x_sfp_e3_set_transmitter(struct link_params *params,
|
|
||||||
struct bnx2x_phy *phy,
|
|
||||||
u8 tx_en)
|
|
||||||
{
|
|
||||||
struct bnx2x *bp = params->bp;
|
|
||||||
u32 cfg_pin;
|
|
||||||
u8 port = params->port;
|
|
||||||
|
|
||||||
cfg_pin = REG_RD(bp, params->shmem_base +
|
|
||||||
offsetof(struct shmem_region,
|
|
||||||
dev_info.port_hw_config[port].e3_sfp_ctrl)) &
|
|
||||||
PORT_HW_CFG_TX_LASER_MASK;
|
|
||||||
/* Set the !tx_en since this pin is DISABLE_TX_LASER */
|
|
||||||
DP(NETIF_MSG_LINK, "Setting WC TX to %d\n", tx_en);
|
|
||||||
/* For 20G, the expected pin to be used is 3 pins after the current */
|
|
||||||
|
|
||||||
bnx2x_set_cfg_pin(bp, cfg_pin, tx_en ^ 1);
|
|
||||||
if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_20G)
|
|
||||||
bnx2x_set_cfg_pin(bp, cfg_pin + 3, tx_en ^ 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bnx2x_warpcore_link_reset(struct bnx2x_phy *phy,
|
static void bnx2x_warpcore_link_reset(struct bnx2x_phy *phy,
|
||||||
struct link_params *params)
|
struct link_params *params)
|
||||||
{
|
{
|
||||||
|
@ -7833,7 +7838,6 @@ static int bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bnx2x_warpcore_power_module(struct link_params *params,
|
static void bnx2x_warpcore_power_module(struct link_params *params,
|
||||||
struct bnx2x_phy *phy,
|
|
||||||
u8 power)
|
u8 power)
|
||||||
{
|
{
|
||||||
u32 pin_cfg;
|
u32 pin_cfg;
|
||||||
|
@ -7875,10 +7879,10 @@ static int bnx2x_warpcore_read_sfp_module_eeprom(struct bnx2x_phy *phy,
|
||||||
addr32 = addr & (~0x3);
|
addr32 = addr & (~0x3);
|
||||||
do {
|
do {
|
||||||
if ((!is_init) && (cnt == I2C_WA_PWR_ITER)) {
|
if ((!is_init) && (cnt == I2C_WA_PWR_ITER)) {
|
||||||
bnx2x_warpcore_power_module(params, phy, 0);
|
bnx2x_warpcore_power_module(params, 0);
|
||||||
/* Note that 100us are not enough here */
|
/* Note that 100us are not enough here */
|
||||||
usleep_range(1000, 2000);
|
usleep_range(1000, 2000);
|
||||||
bnx2x_warpcore_power_module(params, phy, 1);
|
bnx2x_warpcore_power_module(params, 1);
|
||||||
}
|
}
|
||||||
rc = bnx2x_bsc_read(params, phy, 0xa0, addr32, 0, byte_cnt,
|
rc = bnx2x_bsc_read(params, phy, 0xa0, addr32, 0, byte_cnt,
|
||||||
data_array);
|
data_array);
|
||||||
|
@ -8464,7 +8468,7 @@ static void bnx2x_warpcore_hw_reset(struct bnx2x_phy *phy,
|
||||||
struct link_params *params)
|
struct link_params *params)
|
||||||
{
|
{
|
||||||
struct bnx2x *bp = params->bp;
|
struct bnx2x *bp = params->bp;
|
||||||
bnx2x_warpcore_power_module(params, phy, 0);
|
bnx2x_warpcore_power_module(params, 0);
|
||||||
/* Put Warpcore in low power mode */
|
/* Put Warpcore in low power mode */
|
||||||
REG_WR(bp, MISC_REG_WC0_RESET, 0x0c0e);
|
REG_WR(bp, MISC_REG_WC0_RESET, 0x0c0e);
|
||||||
|
|
||||||
|
@ -8487,7 +8491,7 @@ static void bnx2x_power_sfp_module(struct link_params *params,
|
||||||
bnx2x_8727_power_module(params->bp, phy, power);
|
bnx2x_8727_power_module(params->bp, phy, power);
|
||||||
break;
|
break;
|
||||||
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
|
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
|
||||||
bnx2x_warpcore_power_module(params, phy, power);
|
bnx2x_warpcore_power_module(params, power);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -8560,7 +8564,8 @@ int bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
|
||||||
u32 val = REG_RD(bp, params->shmem_base +
|
u32 val = REG_RD(bp, params->shmem_base +
|
||||||
offsetof(struct shmem_region, dev_info.
|
offsetof(struct shmem_region, dev_info.
|
||||||
port_feature_config[params->port].config));
|
port_feature_config[params->port].config));
|
||||||
|
/* Enabled transmitter by default */
|
||||||
|
bnx2x_sfp_set_transmitter(params, phy, 1);
|
||||||
DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
|
DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
|
||||||
params->port);
|
params->port);
|
||||||
/* Power up module */
|
/* Power up module */
|
||||||
|
@ -8593,14 +8598,12 @@ int bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
|
||||||
*/
|
*/
|
||||||
bnx2x_set_limiting_mode(params, phy, edc_mode);
|
bnx2x_set_limiting_mode(params, phy, edc_mode);
|
||||||
|
|
||||||
/* Enable transmit for this module if the module is approved, or
|
/* Disable transmit for this module if the module is not approved, and
|
||||||
* if unapproved modules should also enable the Tx laser
|
* laser needs to be disabled.
|
||||||
*/
|
*/
|
||||||
if (rc == 0 ||
|
if ((rc) &&
|
||||||
(val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
|
((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
|
||||||
PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
|
PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER))
|
||||||
bnx2x_sfp_set_transmitter(params, phy, 1);
|
|
||||||
else
|
|
||||||
bnx2x_sfp_set_transmitter(params, phy, 0);
|
bnx2x_sfp_set_transmitter(params, phy, 0);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -8612,11 +8615,13 @@ void bnx2x_handle_module_detect_int(struct link_params *params)
|
||||||
struct bnx2x_phy *phy;
|
struct bnx2x_phy *phy;
|
||||||
u32 gpio_val;
|
u32 gpio_val;
|
||||||
u8 gpio_num, gpio_port;
|
u8 gpio_num, gpio_port;
|
||||||
if (CHIP_IS_E3(bp))
|
if (CHIP_IS_E3(bp)) {
|
||||||
phy = ¶ms->phy[INT_PHY];
|
phy = ¶ms->phy[INT_PHY];
|
||||||
else
|
/* Always enable TX laser,will be disabled in case of fault */
|
||||||
|
bnx2x_sfp_set_transmitter(params, phy, 1);
|
||||||
|
} else {
|
||||||
phy = ¶ms->phy[EXT_PHY1];
|
phy = ¶ms->phy[EXT_PHY1];
|
||||||
|
}
|
||||||
if (bnx2x_get_mod_abs_int_cfg(bp, params->chip_id, params->shmem_base,
|
if (bnx2x_get_mod_abs_int_cfg(bp, params->chip_id, params->shmem_base,
|
||||||
params->port, &gpio_num, &gpio_port) ==
|
params->port, &gpio_num, &gpio_port) ==
|
||||||
-EINVAL) {
|
-EINVAL) {
|
||||||
|
@ -8661,10 +8666,6 @@ void bnx2x_handle_module_detect_int(struct link_params *params)
|
||||||
DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
|
DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
u32 val = REG_RD(bp, params->shmem_base +
|
|
||||||
offsetof(struct shmem_region, dev_info.
|
|
||||||
port_feature_config[params->port].
|
|
||||||
config));
|
|
||||||
bnx2x_set_gpio_int(bp, gpio_num,
|
bnx2x_set_gpio_int(bp, gpio_num,
|
||||||
MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
|
MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
|
||||||
gpio_port);
|
gpio_port);
|
||||||
|
@ -8672,10 +8673,6 @@ void bnx2x_handle_module_detect_int(struct link_params *params)
|
||||||
* Disable transmit for this module
|
* Disable transmit for this module
|
||||||
*/
|
*/
|
||||||
phy->media_type = ETH_PHY_NOT_PRESENT;
|
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) ||
|
|
||||||
CHIP_IS_E3(bp))
|
|
||||||
bnx2x_sfp_set_transmitter(params, phy, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9415,6 +9412,7 @@ static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
|
||||||
bnx2x_cl45_read(bp, phy,
|
bnx2x_cl45_read(bp, phy,
|
||||||
MDIO_PMA_DEVAD,
|
MDIO_PMA_DEVAD,
|
||||||
MDIO_PMA_LASI_RXSTAT, &rx_alarm_status);
|
MDIO_PMA_LASI_RXSTAT, &rx_alarm_status);
|
||||||
|
bnx2x_8727_power_module(params->bp, phy, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} /* Over current check */
|
} /* Over current check */
|
||||||
|
@ -13194,6 +13192,7 @@ static void bnx2x_check_over_curr(struct link_params *params,
|
||||||
" error.\n",
|
" error.\n",
|
||||||
params->port);
|
params->port);
|
||||||
vars->phy_flags |= PHY_OVER_CURRENT_FLAG;
|
vars->phy_flags |= PHY_OVER_CURRENT_FLAG;
|
||||||
|
bnx2x_warpcore_power_module(params, 0);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
vars->phy_flags &= ~PHY_OVER_CURRENT_FLAG;
|
vars->phy_flags &= ~PHY_OVER_CURRENT_FLAG;
|
||||||
|
|
Loading…
Reference in New Issue