summaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
diff options
context:
space:
mode:
authorEmil Tantilov2013-05-29 08:23:05 +0200
committerJeff Kirsher2013-07-31 02:50:01 +0200
commit3dcc2f4142610cc7212a757348d45f1e815927c9 (patch)
tree5d3708afec6dcd91ebe98c1857aa17c48b8be594 /drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
parentixgbe: bump version number (diff)
downloadkernel-qcow2-linux-3dcc2f4142610cc7212a757348d45f1e815927c9.tar.gz
kernel-qcow2-linux-3dcc2f4142610cc7212a757348d45f1e815927c9.tar.xz
kernel-qcow2-linux-3dcc2f4142610cc7212a757348d45f1e815927c9.zip
ixgbe: fix semaphore lock for I2C read/writes on 82598
ixgbe_read/write_i2c_phy_82598() does not hold the SWFW_SYNC semaphore for the entire function. Instead the lock is held only during the phy.ops.read/write_reg operations. As result when the function is being called simultaneously the I2C read/writes can be corrupted. The following patch introduces the SWFW_SYNC semaphore for the entire ixgbe_read/write_i2c_phy_82598() function. To accomplish this I had to create 2 separate functions: ixgbe_read_phy_reg_mdi() ixgbe_write_phy_reg_mdi() Those functions are identical to ixgbe_read/write_phy_reg_generic() sans the locking, and can be used in ixgbe_read/write_i2c_phy_82598() with the SWFW_SYNC semaphore being held. Signed-off-by: Emil Tantilov <emil.s.tantilov@intel.com> Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c')
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c32
1 files changed, 22 insertions, 10 deletions
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
index 4a5bfb6b3af0..d011d5c3c856 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
@@ -1018,8 +1018,17 @@ static s32 ixgbe_read_i2c_phy_82598(struct ixgbe_hw *hw, u8 dev_addr,
u16 sfp_addr = 0;
u16 sfp_data = 0;
u16 sfp_stat = 0;
+ u16 gssr;
u32 i;
+ if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)
+ gssr = IXGBE_GSSR_PHY1_SM;
+ else
+ gssr = IXGBE_GSSR_PHY0_SM;
+
+ if (hw->mac.ops.acquire_swfw_sync(hw, gssr) != 0)
+ return IXGBE_ERR_SWFW_SYNC;
+
if (hw->phy.type == ixgbe_phy_nl) {
/*
* phy SDA/SCL registers are at addresses 0xC30A to
@@ -1028,17 +1037,17 @@ static s32 ixgbe_read_i2c_phy_82598(struct ixgbe_hw *hw, u8 dev_addr,
*/
sfp_addr = (dev_addr << 8) + byte_offset;
sfp_addr = (sfp_addr | IXGBE_I2C_EEPROM_READ_MASK);
- hw->phy.ops.write_reg(hw,
- IXGBE_MDIO_PMA_PMD_SDA_SCL_ADDR,
- MDIO_MMD_PMAPMD,
- sfp_addr);
+ hw->phy.ops.write_reg_mdi(hw,
+ IXGBE_MDIO_PMA_PMD_SDA_SCL_ADDR,
+ MDIO_MMD_PMAPMD,
+ sfp_addr);
/* Poll status */
for (i = 0; i < 100; i++) {
- hw->phy.ops.read_reg(hw,
- IXGBE_MDIO_PMA_PMD_SDA_SCL_STAT,
- MDIO_MMD_PMAPMD,
- &sfp_stat);
+ hw->phy.ops.read_reg_mdi(hw,
+ IXGBE_MDIO_PMA_PMD_SDA_SCL_STAT,
+ MDIO_MMD_PMAPMD,
+ &sfp_stat);
sfp_stat = sfp_stat & IXGBE_I2C_EEPROM_STATUS_MASK;
if (sfp_stat != IXGBE_I2C_EEPROM_STATUS_IN_PROGRESS)
break;
@@ -1052,8 +1061,8 @@ static s32 ixgbe_read_i2c_phy_82598(struct ixgbe_hw *hw, u8 dev_addr,
}
/* Read data */
- hw->phy.ops.read_reg(hw, IXGBE_MDIO_PMA_PMD_SDA_SCL_DATA,
- MDIO_MMD_PMAPMD, &sfp_data);
+ hw->phy.ops.read_reg_mdi(hw, IXGBE_MDIO_PMA_PMD_SDA_SCL_DATA,
+ MDIO_MMD_PMAPMD, &sfp_data);
*eeprom_data = (u8)(sfp_data >> 8);
} else {
@@ -1061,6 +1070,7 @@ static s32 ixgbe_read_i2c_phy_82598(struct ixgbe_hw *hw, u8 dev_addr,
}
out:
+ hw->mac.ops.release_swfw_sync(hw, gssr);
return status;
}
@@ -1326,6 +1336,8 @@ static struct ixgbe_phy_operations phy_ops_82598 = {
.reset = &ixgbe_reset_phy_generic,
.read_reg = &ixgbe_read_phy_reg_generic,
.write_reg = &ixgbe_write_phy_reg_generic,
+ .read_reg_mdi = &ixgbe_read_phy_reg_mdi,
+ .write_reg_mdi = &ixgbe_write_phy_reg_mdi,
.setup_link = &ixgbe_setup_phy_link_generic,
.setup_link_speed = &ixgbe_setup_phy_link_speed_generic,
.read_i2c_sff8472 = &ixgbe_read_i2c_sff8472_82598,