Commit 50a29845 authored by Yuval Mintz's avatar Yuval Mintz Committed by David S. Miller

bnx2x: fix I2C non-respondent issue

When I2C is not responding it's usually due to a previous
unexpected reset during I2C operation. We release it by
powering down and up the SFP+ module.
Signed-off-by: default avatarYaniv Rosner <yaniv.rosner@broadcom.com>
Signed-off-by: default avatarYuval Mintz <yuvalmin@broadcom.com>
Signed-off-by: default avatarEilon Greenstein <eilong@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e8803b6c
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#define I2C_BSC0 0 #define I2C_BSC0 0
#define I2C_BSC1 1 #define I2C_BSC1 1
#define I2C_WA_RETRY_CNT 3 #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_READ_OP 1
#define MCPR_IMC_COMMAND_WRITE_OP 2 #define MCPR_IMC_COMMAND_WRITE_OP 2
...@@ -7659,6 +7660,28 @@ static int bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy, ...@@ -7659,6 +7660,28 @@ static int bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
return -EINVAL; return -EINVAL;
} }
static void bnx2x_warpcore_power_module(struct link_params *params,
struct bnx2x_phy *phy,
u8 power)
{
u32 pin_cfg;
struct bnx2x *bp = params->bp;
pin_cfg = (REG_RD(bp, params->shmem_base +
offsetof(struct shmem_region,
dev_info.port_hw_config[params->port].e3_sfp_ctrl)) &
PORT_HW_CFG_E3_PWR_DIS_MASK) >>
PORT_HW_CFG_E3_PWR_DIS_SHIFT;
if (pin_cfg == PIN_CFG_NA)
return;
DP(NETIF_MSG_LINK, "Setting SFP+ module power to %d using pin cfg %d\n",
power, pin_cfg);
/* Low ==> corresponding SFP+ module is powered
* high ==> the SFP+ module is powered down
*/
bnx2x_set_cfg_pin(bp, pin_cfg, power ^ 1);
}
static int bnx2x_warpcore_read_sfp_module_eeprom(struct bnx2x_phy *phy, static int bnx2x_warpcore_read_sfp_module_eeprom(struct bnx2x_phy *phy,
struct link_params *params, struct link_params *params,
u16 addr, u8 byte_cnt, u16 addr, u8 byte_cnt,
...@@ -7678,6 +7701,12 @@ static int bnx2x_warpcore_read_sfp_module_eeprom(struct bnx2x_phy *phy, ...@@ -7678,6 +7701,12 @@ static int bnx2x_warpcore_read_sfp_module_eeprom(struct bnx2x_phy *phy,
/* 4 byte aligned address */ /* 4 byte aligned address */
addr32 = addr & (~0x3); addr32 = addr & (~0x3);
do { do {
if (cnt == I2C_WA_PWR_ITER) {
bnx2x_warpcore_power_module(params, phy, 0);
/* Note that 100us are not enough here */
usleep_range(1000,1000);
bnx2x_warpcore_power_module(params, phy, 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);
} while ((rc != 0) && (++cnt < I2C_WA_RETRY_CNT)); } while ((rc != 0) && (++cnt < I2C_WA_RETRY_CNT));
...@@ -8200,29 +8229,6 @@ static void bnx2x_set_sfp_module_fault_led(struct link_params *params, ...@@ -8200,29 +8229,6 @@ static void bnx2x_set_sfp_module_fault_led(struct link_params *params,
bnx2x_set_e1e2_module_fault_led(params, gpio_mode); bnx2x_set_e1e2_module_fault_led(params, gpio_mode);
} }
static void bnx2x_warpcore_power_module(struct link_params *params,
struct bnx2x_phy *phy,
u8 power)
{
u32 pin_cfg;
struct bnx2x *bp = params->bp;
pin_cfg = (REG_RD(bp, params->shmem_base +
offsetof(struct shmem_region,
dev_info.port_hw_config[params->port].e3_sfp_ctrl)) &
PORT_HW_CFG_E3_PWR_DIS_MASK) >>
PORT_HW_CFG_E3_PWR_DIS_SHIFT;
if (pin_cfg == PIN_CFG_NA)
return;
DP(NETIF_MSG_LINK, "Setting SFP+ module power to %d using pin cfg %d\n",
power, pin_cfg);
/* Low ==> corresponding SFP+ module is powered
* high ==> the SFP+ module is powered down
*/
bnx2x_set_cfg_pin(bp, pin_cfg, power ^ 1);
}
static void bnx2x_warpcore_hw_reset(struct bnx2x_phy *phy, static void bnx2x_warpcore_hw_reset(struct bnx2x_phy *phy,
struct link_params *params) struct link_params *params)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment