Skip to content

Commit

Permalink
e1000e: separate mutex usage between NVM and PHY/CSR register for ICH…
Browse files Browse the repository at this point in the history
…x/PCH

Accesses to NVM and PHY/CSR registers on ICHx/PCH-based parts are protected
from concurrent accesses with a mutex that is acquired when the access is
initiated and released when the access has completed.  However, the two
types of accesses should not be protected by the same mutex because the
driver may have to access the NVM while already holding the mutex over
several consecutive PHY/CSR accesses which would result in livelock.

Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Bruce Allan authored and David S. Miller committed Oct 26, 2009
1 parent fa2ce13 commit ca15df5
Showing 1 changed file with 58 additions and 31 deletions.
89 changes: 58 additions & 31 deletions drivers/net/e1000e/ich8lan.c
Original file line number Diff line number Diff line change
Expand Up @@ -577,13 +577,40 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)

static DEFINE_MUTEX(nvm_mutex);

/**
* e1000_acquire_nvm_ich8lan - Acquire NVM mutex
* @hw: pointer to the HW structure
*
* Acquires the mutex for performing NVM operations.
**/
static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw)
{
mutex_lock(&nvm_mutex);

return 0;
}

/**
* e1000_release_nvm_ich8lan - Release NVM mutex
* @hw: pointer to the HW structure
*
* Releases the mutex used while performing NVM operations.
**/
static void e1000_release_nvm_ich8lan(struct e1000_hw *hw)
{
mutex_unlock(&nvm_mutex);

return;
}

static DEFINE_MUTEX(swflag_mutex);

/**
* e1000_acquire_swflag_ich8lan - Acquire software control flag
* @hw: pointer to the HW structure
*
* Acquires the software control flag for performing NVM and PHY
* operations. This is a function pointer entry point only called by
* read/write routines for the PHY and NVM parts.
* Acquires the software control flag for performing PHY and select
* MAC CSR accesses.
**/
static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
{
Expand All @@ -592,7 +619,7 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)

might_sleep();

mutex_lock(&nvm_mutex);
mutex_lock(&swflag_mutex);

while (timeout) {
extcnf_ctrl = er32(EXTCNF_CTRL);
Expand Down Expand Up @@ -633,7 +660,7 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)

out:
if (ret_val)
mutex_unlock(&nvm_mutex);
mutex_unlock(&swflag_mutex);

return ret_val;
}
Expand All @@ -642,9 +669,8 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
* e1000_release_swflag_ich8lan - Release software control flag
* @hw: pointer to the HW structure
*
* Releases the software control flag for performing NVM and PHY operations.
* This is a function pointer entry point only called by read/write
* routines for the PHY and NVM parts.
* Releases the software control flag for performing PHY and select
* MAC CSR accesses.
**/
static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
{
Expand All @@ -654,7 +680,9 @@ static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
ew32(EXTCNF_CTRL, extcnf_ctrl);

mutex_unlock(&nvm_mutex);
mutex_unlock(&swflag_mutex);

return;
}

/**
Expand Down Expand Up @@ -1360,12 +1388,11 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
(words == 0)) {
hw_dbg(hw, "nvm parameter(s) out of bounds\n");
return -E1000_ERR_NVM;
ret_val = -E1000_ERR_NVM;
goto out;
}

ret_val = e1000_acquire_swflag_ich8lan(hw);
if (ret_val)
goto out;
nvm->ops.acquire_nvm(hw);

ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
if (ret_val) {
Expand All @@ -1391,7 +1418,7 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
}
}

e1000_release_swflag_ich8lan(hw);
nvm->ops.release_nvm(hw);

out:
if (ret_val)
Expand Down Expand Up @@ -1649,11 +1676,15 @@ static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
return -E1000_ERR_NVM;
}

nvm->ops.acquire_nvm(hw);

for (i = 0; i < words; i++) {
dev_spec->shadow_ram[offset+i].modified = 1;
dev_spec->shadow_ram[offset+i].value = data[i];
}

nvm->ops.release_nvm(hw);

return 0;
}

Expand Down Expand Up @@ -1683,9 +1714,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
if (nvm->type != e1000_nvm_flash_sw)
goto out;

ret_val = e1000_acquire_swflag_ich8lan(hw);
if (ret_val)
goto out;
nvm->ops.acquire_nvm(hw);

/*
* We're writing to the opposite bank so if we're on bank 1,
Expand All @@ -1703,15 +1732,15 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
old_bank_offset = 0;
ret_val = e1000_erase_flash_bank_ich8lan(hw, 1);
if (ret_val) {
e1000_release_swflag_ich8lan(hw);
nvm->ops.release_nvm(hw);
goto out;
}
} else {
old_bank_offset = nvm->flash_bank_size;
new_bank_offset = 0;
ret_val = e1000_erase_flash_bank_ich8lan(hw, 0);
if (ret_val) {
e1000_release_swflag_ich8lan(hw);
nvm->ops.release_nvm(hw);
goto out;
}
}
Expand Down Expand Up @@ -1769,7 +1798,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
if (ret_val) {
/* Possibly read-only, see e1000e_write_protect_nvm_ich8lan() */
hw_dbg(hw, "Flash commit failed.\n");
e1000_release_swflag_ich8lan(hw);
nvm->ops.release_nvm(hw);
goto out;
}

Expand All @@ -1782,15 +1811,15 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data);
if (ret_val) {
e1000_release_swflag_ich8lan(hw);
nvm->ops.release_nvm(hw);
goto out;
}
data &= 0xBFFF;
ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
act_offset * 2 + 1,
(u8)(data >> 8));
if (ret_val) {
e1000_release_swflag_ich8lan(hw);
nvm->ops.release_nvm(hw);
goto out;
}

Expand All @@ -1803,7 +1832,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1;
ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0);
if (ret_val) {
e1000_release_swflag_ich8lan(hw);
nvm->ops.release_nvm(hw);
goto out;
}

Expand All @@ -1813,7 +1842,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
dev_spec->shadow_ram[i].value = 0xFFFF;
}

e1000_release_swflag_ich8lan(hw);
nvm->ops.release_nvm(hw);

/*
* Reload the EEPROM, or else modifications will not appear
Expand Down Expand Up @@ -1877,14 +1906,12 @@ static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
**/
void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw)
{
struct e1000_nvm_info *nvm = &hw->nvm;
union ich8_flash_protected_range pr0;
union ich8_hws_flash_status hsfsts;
u32 gfpreg;
s32 ret_val;

ret_val = e1000_acquire_swflag_ich8lan(hw);
if (ret_val)
return;
nvm->ops.acquire_nvm(hw);

gfpreg = er32flash(ICH_FLASH_GFPREG);

Expand All @@ -1905,7 +1932,7 @@ void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw)
hsfsts.hsf_status.flockdn = true;
ew32flash(ICH_FLASH_HSFSTS, hsfsts.regval);

e1000_release_swflag_ich8lan(hw);
nvm->ops.release_nvm(hw);
}

/**
Expand Down Expand Up @@ -3162,9 +3189,9 @@ static struct e1000_phy_operations ich8_phy_ops = {
};

static struct e1000_nvm_operations ich8_nvm_ops = {
.acquire_nvm = e1000_acquire_swflag_ich8lan,
.acquire_nvm = e1000_acquire_nvm_ich8lan,
.read_nvm = e1000_read_nvm_ich8lan,
.release_nvm = e1000_release_swflag_ich8lan,
.release_nvm = e1000_release_nvm_ich8lan,
.update_nvm = e1000_update_nvm_checksum_ich8lan,
.valid_led_default = e1000_valid_led_default_ich8lan,
.validate_nvm = e1000_validate_nvm_checksum_ich8lan,
Expand Down

0 comments on commit ca15df5

Please sign in to comment.