aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYaniv Rosner <yanivr@broadcom.com>2012-11-26 22:46:31 -0500
committerDavid S. Miller <davem@davemloft.net>2012-11-28 10:59:21 -0500
commit5a1fbf4046ea05b20811178cb1423e27e3260051 (patch)
tree5cbf751769d7b592d1aec1dd75755182169d0c89
parent55386fe88349706ae570522180d89892883af2b5 (diff)
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>
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c91
1 files changed, 45 insertions, 46 deletions
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
index e054921d45d8..a5fe2b96bf9f 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
@@ -4414,6 +4414,27 @@ static void bnx2x_warpcore_config_sfi(struct bnx2x_phy *phy,
4414 } 4414 }
4415} 4415}
4416 4416
4417static void bnx2x_sfp_e3_set_transmitter(struct link_params *params,
4418 struct bnx2x_phy *phy,
4419 u8 tx_en)
4420{
4421 struct bnx2x *bp = params->bp;
4422 u32 cfg_pin;
4423 u8 port = params->port;
4424
4425 cfg_pin = REG_RD(bp, params->shmem_base +
4426 offsetof(struct shmem_region,
4427 dev_info.port_hw_config[port].e3_sfp_ctrl)) &
4428 PORT_HW_CFG_E3_TX_LASER_MASK;
4429 /* Set the !tx_en since this pin is DISABLE_TX_LASER */
4430 DP(NETIF_MSG_LINK, "Setting WC TX to %d\n", tx_en);
4431
4432 /* For 20G, the expected pin to be used is 3 pins after the current */
4433 bnx2x_set_cfg_pin(bp, cfg_pin, tx_en ^ 1);
4434 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_20G)
4435 bnx2x_set_cfg_pin(bp, cfg_pin + 3, tx_en ^ 1);
4436}
4437
4417static void bnx2x_warpcore_config_init(struct bnx2x_phy *phy, 4438static void bnx2x_warpcore_config_init(struct bnx2x_phy *phy,
4418 struct link_params *params, 4439 struct link_params *params,
4419 struct link_vars *vars) 4440 struct link_vars *vars)
@@ -4474,9 +4495,14 @@ static void bnx2x_warpcore_config_init(struct bnx2x_phy *phy,
4474 break; 4495 break;
4475 4496
4476 case PORT_HW_CFG_NET_SERDES_IF_SFI: 4497 case PORT_HW_CFG_NET_SERDES_IF_SFI:
4477 /* Issue Module detection */ 4498 /* Issue Module detection if module is plugged, or
4499 * enabled transmitter to avoid current leakage in case
4500 * no module is connected
4501 */
4478 if (bnx2x_is_sfp_module_plugged(phy, params)) 4502 if (bnx2x_is_sfp_module_plugged(phy, params))
4479 bnx2x_sfp_module_detection(phy, params); 4503 bnx2x_sfp_module_detection(phy, params);
4504 else
4505 bnx2x_sfp_e3_set_transmitter(params, phy, 1);
4480 4506
4481 bnx2x_warpcore_config_sfi(phy, params); 4507 bnx2x_warpcore_config_sfi(phy, params);
4482 break; 4508 break;
@@ -4513,27 +4539,6 @@ static void bnx2x_warpcore_config_init(struct bnx2x_phy *phy,
4513 DP(NETIF_MSG_LINK, "Exit config init\n"); 4539 DP(NETIF_MSG_LINK, "Exit config init\n");
4514} 4540}
4515 4541
4516static void bnx2x_sfp_e3_set_transmitter(struct link_params *params,
4517 struct bnx2x_phy *phy,
4518 u8 tx_en)
4519{
4520 struct bnx2x *bp = params->bp;
4521 u32 cfg_pin;
4522 u8 port = params->port;
4523
4524 cfg_pin = REG_RD(bp, params->shmem_base +
4525 offsetof(struct shmem_region,
4526 dev_info.port_hw_config[port].e3_sfp_ctrl)) &
4527 PORT_HW_CFG_TX_LASER_MASK;
4528 /* Set the !tx_en since this pin is DISABLE_TX_LASER */
4529 DP(NETIF_MSG_LINK, "Setting WC TX to %d\n", tx_en);
4530 /* For 20G, the expected pin to be used is 3 pins after the current */
4531
4532 bnx2x_set_cfg_pin(bp, cfg_pin, tx_en ^ 1);
4533 if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_20G)
4534 bnx2x_set_cfg_pin(bp, cfg_pin + 3, tx_en ^ 1);
4535}
4536
4537static void bnx2x_warpcore_link_reset(struct bnx2x_phy *phy, 4542static void bnx2x_warpcore_link_reset(struct bnx2x_phy *phy,
4538 struct link_params *params) 4543 struct link_params *params)
4539{ 4544{
@@ -7833,7 +7838,6 @@ static int bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
7833} 7838}
7834 7839
7835static void bnx2x_warpcore_power_module(struct link_params *params, 7840static void bnx2x_warpcore_power_module(struct link_params *params,
7836 struct bnx2x_phy *phy,
7837 u8 power) 7841 u8 power)
7838{ 7842{
7839 u32 pin_cfg; 7843 u32 pin_cfg;
@@ -7875,10 +7879,10 @@ static int bnx2x_warpcore_read_sfp_module_eeprom(struct bnx2x_phy *phy,
7875 addr32 = addr & (~0x3); 7879 addr32 = addr & (~0x3);
7876 do { 7880 do {
7877 if ((!is_init) && (cnt == I2C_WA_PWR_ITER)) { 7881 if ((!is_init) && (cnt == I2C_WA_PWR_ITER)) {
7878 bnx2x_warpcore_power_module(params, phy, 0); 7882 bnx2x_warpcore_power_module(params, 0);
7879 /* Note that 100us are not enough here */ 7883 /* Note that 100us are not enough here */
7880 usleep_range(1000, 2000); 7884 usleep_range(1000, 2000);
7881 bnx2x_warpcore_power_module(params, phy, 1); 7885 bnx2x_warpcore_power_module(params, 1);
7882 } 7886 }
7883 rc = bnx2x_bsc_read(params, phy, 0xa0, addr32, 0, byte_cnt, 7887 rc = bnx2x_bsc_read(params, phy, 0xa0, addr32, 0, byte_cnt,
7884 data_array); 7888 data_array);
@@ -8464,7 +8468,7 @@ static void bnx2x_warpcore_hw_reset(struct bnx2x_phy *phy,
8464 struct link_params *params) 8468 struct link_params *params)
8465{ 8469{
8466 struct bnx2x *bp = params->bp; 8470 struct bnx2x *bp = params->bp;
8467 bnx2x_warpcore_power_module(params, phy, 0); 8471 bnx2x_warpcore_power_module(params, 0);
8468 /* Put Warpcore in low power mode */ 8472 /* Put Warpcore in low power mode */
8469 REG_WR(bp, MISC_REG_WC0_RESET, 0x0c0e); 8473 REG_WR(bp, MISC_REG_WC0_RESET, 0x0c0e);
8470 8474
@@ -8487,7 +8491,7 @@ static void bnx2x_power_sfp_module(struct link_params *params,
8487 bnx2x_8727_power_module(params->bp, phy, power); 8491 bnx2x_8727_power_module(params->bp, phy, power);
8488 break; 8492 break;
8489 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: 8493 case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
8490 bnx2x_warpcore_power_module(params, phy, power); 8494 bnx2x_warpcore_power_module(params, power);
8491 break; 8495 break;
8492 default: 8496 default:
8493 break; 8497 break;
@@ -8560,7 +8564,8 @@ int bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
8560 u32 val = REG_RD(bp, params->shmem_base + 8564 u32 val = REG_RD(bp, params->shmem_base +
8561 offsetof(struct shmem_region, dev_info. 8565 offsetof(struct shmem_region, dev_info.
8562 port_feature_config[params->port].config)); 8566 port_feature_config[params->port].config));
8563 8567 /* Enabled transmitter by default */
8568 bnx2x_sfp_set_transmitter(params, phy, 1);
8564 DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n", 8569 DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
8565 params->port); 8570 params->port);
8566 /* Power up module */ 8571 /* Power up module */
@@ -8593,14 +8598,12 @@ int bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
8593 */ 8598 */
8594 bnx2x_set_limiting_mode(params, phy, edc_mode); 8599 bnx2x_set_limiting_mode(params, phy, edc_mode);
8595 8600
8596 /* Enable transmit for this module if the module is approved, or 8601 /* Disable transmit for this module if the module is not approved, and
8597 * if unapproved modules should also enable the Tx laser 8602 * laser needs to be disabled.
8598 */ 8603 */
8599 if (rc == 0 || 8604 if ((rc) &&
8600 (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) != 8605 ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
8601 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) 8606 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER))
8602 bnx2x_sfp_set_transmitter(params, phy, 1);
8603 else
8604 bnx2x_sfp_set_transmitter(params, phy, 0); 8607 bnx2x_sfp_set_transmitter(params, phy, 0);
8605 8608
8606 return rc; 8609 return rc;
@@ -8612,11 +8615,13 @@ void bnx2x_handle_module_detect_int(struct link_params *params)
8612 struct bnx2x_phy *phy; 8615 struct bnx2x_phy *phy;
8613 u32 gpio_val; 8616 u32 gpio_val;
8614 u8 gpio_num, gpio_port; 8617 u8 gpio_num, gpio_port;
8615 if (CHIP_IS_E3(bp)) 8618 if (CHIP_IS_E3(bp)) {
8616 phy = &params->phy[INT_PHY]; 8619 phy = &params->phy[INT_PHY];
8617 else 8620 /* Always enable TX laser,will be disabled in case of fault */
8621 bnx2x_sfp_set_transmitter(params, phy, 1);
8622 } else {
8618 phy = &params->phy[EXT_PHY1]; 8623 phy = &params->phy[EXT_PHY1];
8619 8624 }
8620 if (bnx2x_get_mod_abs_int_cfg(bp, params->chip_id, params->shmem_base, 8625 if (bnx2x_get_mod_abs_int_cfg(bp, params->chip_id, params->shmem_base,
8621 params->port, &gpio_num, &gpio_port) == 8626 params->port, &gpio_num, &gpio_port) ==
8622 -EINVAL) { 8627 -EINVAL) {
@@ -8661,10 +8666,6 @@ void bnx2x_handle_module_detect_int(struct link_params *params)
8661 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n"); 8666 DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
8662 } 8667 }
8663 } else { 8668 } else {
8664 u32 val = REG_RD(bp, params->shmem_base +
8665 offsetof(struct shmem_region, dev_info.
8666 port_feature_config[params->port].
8667 config));
8668 bnx2x_set_gpio_int(bp, gpio_num, 8669 bnx2x_set_gpio_int(bp, gpio_num,
8669 MISC_REGISTERS_GPIO_INT_OUTPUT_SET, 8670 MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
8670 gpio_port); 8671 gpio_port);
@@ -8672,10 +8673,6 @@ void bnx2x_handle_module_detect_int(struct link_params *params)
8672 * Disable transmit for this module 8673 * Disable transmit for this module
8673 */ 8674 */
8674 phy->media_type = ETH_PHY_NOT_PRESENT; 8675 phy->media_type = ETH_PHY_NOT_PRESENT;
8675 if (((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
8676 PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) ||
8677 CHIP_IS_E3(bp))
8678 bnx2x_sfp_set_transmitter(params, phy, 0);
8679 } 8676 }
8680} 8677}
8681 8678
@@ -9415,6 +9412,7 @@ static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
9415 bnx2x_cl45_read(bp, phy, 9412 bnx2x_cl45_read(bp, phy,
9416 MDIO_PMA_DEVAD, 9413 MDIO_PMA_DEVAD,
9417 MDIO_PMA_LASI_RXSTAT, &rx_alarm_status); 9414 MDIO_PMA_LASI_RXSTAT, &rx_alarm_status);
9415 bnx2x_8727_power_module(params->bp, phy, 0);
9418 return 0; 9416 return 0;
9419 } 9417 }
9420 } /* Over current check */ 9418 } /* Over current check */
@@ -13194,6 +13192,7 @@ static void bnx2x_check_over_curr(struct link_params *params,
13194 " error.\n", 13192 " error.\n",
13195 params->port); 13193 params->port);
13196 vars->phy_flags |= PHY_OVER_CURRENT_FLAG; 13194 vars->phy_flags |= PHY_OVER_CURRENT_FLAG;
13195 bnx2x_warpcore_power_module(params, 0);
13197 } 13196 }
13198 } else 13197 } else
13199 vars->phy_flags &= ~PHY_OVER_CURRENT_FLAG; 13198 vars->phy_flags &= ~PHY_OVER_CURRENT_FLAG;