forked from Minki/linux
igb: add locking to reads of the i2c interface
The current implementation of sgmii support isn't correctly locking the interfaces for reads/writes. This change pulls the read/write functionality out of 82575.c and moves it to phy.c. In addition it replaces the implementation in 82575.c with one that uses locking around the relocated i2c interface calls. Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
008c3422d4
commit
bf6f7a928d
@ -277,45 +277,23 @@ static void igb_release_phy_82575(struct e1000_hw *hw)
|
|||||||
static s32 igb_read_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset,
|
static s32 igb_read_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset,
|
||||||
u16 *data)
|
u16 *data)
|
||||||
{
|
{
|
||||||
struct e1000_phy_info *phy = &hw->phy;
|
s32 ret_val = -E1000_ERR_PARAM;
|
||||||
u32 i, i2ccmd = 0;
|
|
||||||
|
|
||||||
if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) {
|
if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) {
|
||||||
hw_dbg("PHY Address %u is out of range\n", offset);
|
hw_dbg("PHY Address %u is out of range\n", offset);
|
||||||
return -E1000_ERR_PARAM;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
ret_val = hw->phy.ops.acquire(hw);
|
||||||
* Set up Op-code, Phy Address, and register address in the I2CCMD
|
if (ret_val)
|
||||||
* register. The MAC will take care of interfacing with the
|
goto out;
|
||||||
* PHY to retrieve the desired data.
|
|
||||||
*/
|
|
||||||
i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
|
|
||||||
(phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
|
|
||||||
(E1000_I2CCMD_OPCODE_READ));
|
|
||||||
|
|
||||||
wr32(E1000_I2CCMD, i2ccmd);
|
ret_val = igb_read_phy_reg_i2c(hw, offset, data);
|
||||||
|
|
||||||
/* Poll the ready bit to see if the I2C read completed */
|
hw->phy.ops.release(hw);
|
||||||
for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
|
|
||||||
udelay(50);
|
|
||||||
i2ccmd = rd32(E1000_I2CCMD);
|
|
||||||
if (i2ccmd & E1000_I2CCMD_READY)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!(i2ccmd & E1000_I2CCMD_READY)) {
|
|
||||||
hw_dbg("I2CCMD Read did not complete\n");
|
|
||||||
return -E1000_ERR_PHY;
|
|
||||||
}
|
|
||||||
if (i2ccmd & E1000_I2CCMD_ERROR) {
|
|
||||||
hw_dbg("I2CCMD Error bit set\n");
|
|
||||||
return -E1000_ERR_PHY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Need to byte-swap the 16-bit value. */
|
out:
|
||||||
*data = ((i2ccmd >> 8) & 0x00FF) | ((i2ccmd << 8) & 0xFF00);
|
return ret_val;
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -330,47 +308,24 @@ static s32 igb_read_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset,
|
|||||||
static s32 igb_write_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset,
|
static s32 igb_write_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset,
|
||||||
u16 data)
|
u16 data)
|
||||||
{
|
{
|
||||||
struct e1000_phy_info *phy = &hw->phy;
|
s32 ret_val = -E1000_ERR_PARAM;
|
||||||
u32 i, i2ccmd = 0;
|
|
||||||
u16 phy_data_swapped;
|
|
||||||
|
|
||||||
if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) {
|
if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) {
|
||||||
hw_dbg("PHY Address %d is out of range\n", offset);
|
hw_dbg("PHY Address %d is out of range\n", offset);
|
||||||
return -E1000_ERR_PARAM;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Swap the data bytes for the I2C interface */
|
ret_val = hw->phy.ops.acquire(hw);
|
||||||
phy_data_swapped = ((data >> 8) & 0x00FF) | ((data << 8) & 0xFF00);
|
if (ret_val)
|
||||||
|
goto out;
|
||||||
|
|
||||||
/*
|
ret_val = igb_write_phy_reg_i2c(hw, offset, data);
|
||||||
* Set up Op-code, Phy Address, and register address in the I2CCMD
|
|
||||||
* register. The MAC will take care of interfacing with the
|
|
||||||
* PHY to retrieve the desired data.
|
|
||||||
*/
|
|
||||||
i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
|
|
||||||
(phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
|
|
||||||
E1000_I2CCMD_OPCODE_WRITE |
|
|
||||||
phy_data_swapped);
|
|
||||||
|
|
||||||
wr32(E1000_I2CCMD, i2ccmd);
|
hw->phy.ops.release(hw);
|
||||||
|
|
||||||
/* Poll the ready bit to see if the I2C read completed */
|
out:
|
||||||
for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
|
return ret_val;
|
||||||
udelay(50);
|
|
||||||
i2ccmd = rd32(E1000_I2CCMD);
|
|
||||||
if (i2ccmd & E1000_I2CCMD_READY)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!(i2ccmd & E1000_I2CCMD_READY)) {
|
|
||||||
hw_dbg("I2CCMD Write did not complete\n");
|
|
||||||
return -E1000_ERR_PHY;
|
|
||||||
}
|
|
||||||
if (i2ccmd & E1000_I2CCMD_ERROR) {
|
|
||||||
hw_dbg("I2CCMD Error bit set\n");
|
|
||||||
return -E1000_ERR_PHY;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -238,6 +238,103 @@ out:
|
|||||||
return ret_val;
|
return ret_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* igb_read_phy_reg_i2c - Read PHY register using i2c
|
||||||
|
* @hw: pointer to the HW structure
|
||||||
|
* @offset: register offset to be read
|
||||||
|
* @data: pointer to the read data
|
||||||
|
*
|
||||||
|
* Reads the PHY register at offset using the i2c interface and stores the
|
||||||
|
* retrieved information in data.
|
||||||
|
**/
|
||||||
|
s32 igb_read_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 *data)
|
||||||
|
{
|
||||||
|
struct e1000_phy_info *phy = &hw->phy;
|
||||||
|
u32 i, i2ccmd = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up Op-code, Phy Address, and register address in the I2CCMD
|
||||||
|
* register. The MAC will take care of interfacing with the
|
||||||
|
* PHY to retrieve the desired data.
|
||||||
|
*/
|
||||||
|
i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
|
||||||
|
(phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
|
||||||
|
(E1000_I2CCMD_OPCODE_READ));
|
||||||
|
|
||||||
|
wr32(E1000_I2CCMD, i2ccmd);
|
||||||
|
|
||||||
|
/* Poll the ready bit to see if the I2C read completed */
|
||||||
|
for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
|
||||||
|
udelay(50);
|
||||||
|
i2ccmd = rd32(E1000_I2CCMD);
|
||||||
|
if (i2ccmd & E1000_I2CCMD_READY)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!(i2ccmd & E1000_I2CCMD_READY)) {
|
||||||
|
hw_dbg("I2CCMD Read did not complete\n");
|
||||||
|
return -E1000_ERR_PHY;
|
||||||
|
}
|
||||||
|
if (i2ccmd & E1000_I2CCMD_ERROR) {
|
||||||
|
hw_dbg("I2CCMD Error bit set\n");
|
||||||
|
return -E1000_ERR_PHY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Need to byte-swap the 16-bit value. */
|
||||||
|
*data = ((i2ccmd >> 8) & 0x00FF) | ((i2ccmd << 8) & 0xFF00);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* igb_write_phy_reg_i2c - Write PHY register using i2c
|
||||||
|
* @hw: pointer to the HW structure
|
||||||
|
* @offset: register offset to write to
|
||||||
|
* @data: data to write at register offset
|
||||||
|
*
|
||||||
|
* Writes the data to PHY register at the offset using the i2c interface.
|
||||||
|
**/
|
||||||
|
s32 igb_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data)
|
||||||
|
{
|
||||||
|
struct e1000_phy_info *phy = &hw->phy;
|
||||||
|
u32 i, i2ccmd = 0;
|
||||||
|
u16 phy_data_swapped;
|
||||||
|
|
||||||
|
|
||||||
|
/* Swap the data bytes for the I2C interface */
|
||||||
|
phy_data_swapped = ((data >> 8) & 0x00FF) | ((data << 8) & 0xFF00);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up Op-code, Phy Address, and register address in the I2CCMD
|
||||||
|
* register. The MAC will take care of interfacing with the
|
||||||
|
* PHY to retrieve the desired data.
|
||||||
|
*/
|
||||||
|
i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
|
||||||
|
(phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
|
||||||
|
E1000_I2CCMD_OPCODE_WRITE |
|
||||||
|
phy_data_swapped);
|
||||||
|
|
||||||
|
wr32(E1000_I2CCMD, i2ccmd);
|
||||||
|
|
||||||
|
/* Poll the ready bit to see if the I2C read completed */
|
||||||
|
for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
|
||||||
|
udelay(50);
|
||||||
|
i2ccmd = rd32(E1000_I2CCMD);
|
||||||
|
if (i2ccmd & E1000_I2CCMD_READY)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!(i2ccmd & E1000_I2CCMD_READY)) {
|
||||||
|
hw_dbg("I2CCMD Write did not complete\n");
|
||||||
|
return -E1000_ERR_PHY;
|
||||||
|
}
|
||||||
|
if (i2ccmd & E1000_I2CCMD_ERROR) {
|
||||||
|
hw_dbg("I2CCMD Error bit set\n");
|
||||||
|
return -E1000_ERR_PHY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* igb_read_phy_reg_igp - Read igp PHY register
|
* igb_read_phy_reg_igp - Read igp PHY register
|
||||||
* @hw: pointer to the HW structure
|
* @hw: pointer to the HW structure
|
||||||
|
@ -61,6 +61,8 @@ s32 igb_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data);
|
|||||||
s32 igb_phy_has_link(struct e1000_hw *hw, u32 iterations,
|
s32 igb_phy_has_link(struct e1000_hw *hw, u32 iterations,
|
||||||
u32 usec_interval, bool *success);
|
u32 usec_interval, bool *success);
|
||||||
s32 igb_phy_init_script_igp3(struct e1000_hw *hw);
|
s32 igb_phy_init_script_igp3(struct e1000_hw *hw);
|
||||||
|
s32 igb_read_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 *data);
|
||||||
|
s32 igb_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data);
|
||||||
|
|
||||||
/* IGP01E1000 Specific Registers */
|
/* IGP01E1000 Specific Registers */
|
||||||
#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* Port Config */
|
#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* Port Config */
|
||||||
|
Loading…
Reference in New Issue
Block a user