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:
Alexander Duyck 2009-10-05 06:32:27 +00:00 committed by David S. Miller
parent 008c3422d4
commit bf6f7a928d
3 changed files with 118 additions and 64 deletions

View File

@ -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;
} }
/** /**

View File

@ -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

View File

@ -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 */