Skip to content

Commit

Permalink
e1000: fix concurrent accesses to PHY from watchdog and ethtool
Browse files Browse the repository at this point in the history
The e1000 driver currently does not protect concurrent accesses to the PHY
from both the ethtool callbacks, and from the e1000_watchdog function. This
patchs adds a new spinlock which is used by e1000_{read,write}_phy_reg in
order to serialize concurrent accesses to the PHY.

Signed-off-by: Maxime Bizon <mbizon@freebox.fr>
Signed-off-by: Florian Fainelli <ffainelli@freebox.fr>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
  • Loading branch information
Maxime Bizon authored and Jeff Kirsher committed Nov 1, 2012
1 parent ede4126 commit ac56558
Showing 1 changed file with 15 additions and 2 deletions.
17 changes: 15 additions & 2 deletions drivers/net/ethernet/intel/e1000/e1000_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ u16 e1000_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] = {
};

static DEFINE_SPINLOCK(e1000_eeprom_lock);
static DEFINE_SPINLOCK(e1000_phy_lock);

/**
* e1000_set_phy_type - Set the phy type member in the hw struct.
Expand Down Expand Up @@ -2830,19 +2831,25 @@ static u16 e1000_shift_in_mdi_bits(struct e1000_hw *hw)
s32 e1000_read_phy_reg(struct e1000_hw *hw, u32 reg_addr, u16 *phy_data)
{
u32 ret_val;
unsigned long flags;

e_dbg("e1000_read_phy_reg");

spin_lock_irqsave(&e1000_phy_lock, flags);

if ((hw->phy_type == e1000_phy_igp) &&
(reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
(u16) reg_addr);
if (ret_val)
if (ret_val) {
spin_unlock_irqrestore(&e1000_phy_lock, flags);
return ret_val;
}
}

ret_val = e1000_read_phy_reg_ex(hw, MAX_PHY_REG_ADDRESS & reg_addr,
phy_data);
spin_unlock_irqrestore(&e1000_phy_lock, flags);

return ret_val;
}
Expand Down Expand Up @@ -2965,19 +2972,25 @@ static s32 e1000_read_phy_reg_ex(struct e1000_hw *hw, u32 reg_addr,
s32 e1000_write_phy_reg(struct e1000_hw *hw, u32 reg_addr, u16 phy_data)
{
u32 ret_val;
unsigned long flags;

e_dbg("e1000_write_phy_reg");

spin_lock_irqsave(&e1000_phy_lock, flags);

if ((hw->phy_type == e1000_phy_igp) &&
(reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
(u16) reg_addr);
if (ret_val)
if (ret_val) {
spin_unlock_irqrestore(&e1000_phy_lock, flags);
return ret_val;
}
}

ret_val = e1000_write_phy_reg_ex(hw, MAX_PHY_REG_ADDRESS & reg_addr,
phy_data);
spin_unlock_irqrestore(&e1000_phy_lock, flags);

return ret_val;
}
Expand Down

0 comments on commit ac56558

Please sign in to comment.