Commit ca15df58 authored by Bruce Allan's avatar Bruce Allan Committed by David S. Miller

e1000e: separate mutex usage between NVM and PHY/CSR register for ICHx/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: default avatarBruce Allan <bruce.w.allan@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent fa2ce13c
...@@ -577,13 +577,40 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter) ...@@ -577,13 +577,40 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
static DEFINE_MUTEX(nvm_mutex); 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 * e1000_acquire_swflag_ich8lan - Acquire software control flag
* @hw: pointer to the HW structure * @hw: pointer to the HW structure
* *
* Acquires the software control flag for performing NVM and PHY * Acquires the software control flag for performing PHY and select
* operations. This is a function pointer entry point only called by * MAC CSR accesses.
* read/write routines for the PHY and NVM parts.
**/ **/
static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
{ {
...@@ -592,7 +619,7 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) ...@@ -592,7 +619,7 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
might_sleep(); might_sleep();
mutex_lock(&nvm_mutex); mutex_lock(&swflag_mutex);
while (timeout) { while (timeout) {
extcnf_ctrl = er32(EXTCNF_CTRL); extcnf_ctrl = er32(EXTCNF_CTRL);
...@@ -633,7 +660,7 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) ...@@ -633,7 +660,7 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
out: out:
if (ret_val) if (ret_val)
mutex_unlock(&nvm_mutex); mutex_unlock(&swflag_mutex);
return ret_val; return ret_val;
} }
...@@ -642,9 +669,8 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) ...@@ -642,9 +669,8 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
* e1000_release_swflag_ich8lan - Release software control flag * e1000_release_swflag_ich8lan - Release software control flag
* @hw: pointer to the HW structure * @hw: pointer to the HW structure
* *
* Releases the software control flag for performing NVM and PHY operations. * Releases the software control flag for performing PHY and select
* This is a function pointer entry point only called by read/write * MAC CSR accesses.
* routines for the PHY and NVM parts.
**/ **/
static void e1000_release_swflag_ich8lan(struct e1000_hw *hw) static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
{ {
...@@ -654,7 +680,9 @@ static void e1000_release_swflag_ich8lan(struct e1000_hw *hw) ...@@ -654,7 +680,9 @@ static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
ew32(EXTCNF_CTRL, extcnf_ctrl); ew32(EXTCNF_CTRL, extcnf_ctrl);
mutex_unlock(&nvm_mutex); mutex_unlock(&swflag_mutex);
return;
} }
/** /**
...@@ -1360,12 +1388,11 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, ...@@ -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) || if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
(words == 0)) { (words == 0)) {
hw_dbg(hw, "nvm parameter(s) out of bounds\n"); 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); nvm->ops.acquire_nvm(hw);
if (ret_val)
goto out;
ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
if (ret_val) { if (ret_val) {
...@@ -1391,7 +1418,7 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, ...@@ -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: out:
if (ret_val) if (ret_val)
...@@ -1649,11 +1676,15 @@ static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, ...@@ -1649,11 +1676,15 @@ static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
return -E1000_ERR_NVM; return -E1000_ERR_NVM;
} }
nvm->ops.acquire_nvm(hw);
for (i = 0; i < words; i++) { for (i = 0; i < words; i++) {
dev_spec->shadow_ram[offset+i].modified = 1; dev_spec->shadow_ram[offset+i].modified = 1;
dev_spec->shadow_ram[offset+i].value = data[i]; dev_spec->shadow_ram[offset+i].value = data[i];
} }
nvm->ops.release_nvm(hw);
return 0; return 0;
} }
...@@ -1683,9 +1714,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) ...@@ -1683,9 +1714,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
if (nvm->type != e1000_nvm_flash_sw) if (nvm->type != e1000_nvm_flash_sw)
goto out; goto out;
ret_val = e1000_acquire_swflag_ich8lan(hw); nvm->ops.acquire_nvm(hw);
if (ret_val)
goto out;
/* /*
* We're writing to the opposite bank so if we're on bank 1, * We're writing to the opposite bank so if we're on bank 1,
...@@ -1703,7 +1732,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) ...@@ -1703,7 +1732,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
old_bank_offset = 0; old_bank_offset = 0;
ret_val = e1000_erase_flash_bank_ich8lan(hw, 1); ret_val = e1000_erase_flash_bank_ich8lan(hw, 1);
if (ret_val) { if (ret_val) {
e1000_release_swflag_ich8lan(hw); nvm->ops.release_nvm(hw);
goto out; goto out;
} }
} else { } else {
...@@ -1711,7 +1740,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) ...@@ -1711,7 +1740,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
new_bank_offset = 0; new_bank_offset = 0;
ret_val = e1000_erase_flash_bank_ich8lan(hw, 0); ret_val = e1000_erase_flash_bank_ich8lan(hw, 0);
if (ret_val) { if (ret_val) {
e1000_release_swflag_ich8lan(hw); nvm->ops.release_nvm(hw);
goto out; goto out;
} }
} }
...@@ -1769,7 +1798,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) ...@@ -1769,7 +1798,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
if (ret_val) { if (ret_val) {
/* Possibly read-only, see e1000e_write_protect_nvm_ich8lan() */ /* Possibly read-only, see e1000e_write_protect_nvm_ich8lan() */
hw_dbg(hw, "Flash commit failed.\n"); hw_dbg(hw, "Flash commit failed.\n");
e1000_release_swflag_ich8lan(hw); nvm->ops.release_nvm(hw);
goto out; goto out;
} }
...@@ -1782,7 +1811,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) ...@@ -1782,7 +1811,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD; act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data); ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data);
if (ret_val) { if (ret_val) {
e1000_release_swflag_ich8lan(hw); nvm->ops.release_nvm(hw);
goto out; goto out;
} }
data &= 0xBFFF; data &= 0xBFFF;
...@@ -1790,7 +1819,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) ...@@ -1790,7 +1819,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
act_offset * 2 + 1, act_offset * 2 + 1,
(u8)(data >> 8)); (u8)(data >> 8));
if (ret_val) { if (ret_val) {
e1000_release_swflag_ich8lan(hw); nvm->ops.release_nvm(hw);
goto out; goto out;
} }
...@@ -1803,7 +1832,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) ...@@ -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; act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1;
ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0); ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0);
if (ret_val) { if (ret_val) {
e1000_release_swflag_ich8lan(hw); nvm->ops.release_nvm(hw);
goto out; goto out;
} }
...@@ -1813,7 +1842,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) ...@@ -1813,7 +1842,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
dev_spec->shadow_ram[i].value = 0xFFFF; 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 * Reload the EEPROM, or else modifications will not appear
...@@ -1877,14 +1906,12 @@ static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw) ...@@ -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) 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_flash_protected_range pr0;
union ich8_hws_flash_status hsfsts; union ich8_hws_flash_status hsfsts;
u32 gfpreg; u32 gfpreg;
s32 ret_val;
ret_val = e1000_acquire_swflag_ich8lan(hw); nvm->ops.acquire_nvm(hw);
if (ret_val)
return;
gfpreg = er32flash(ICH_FLASH_GFPREG); gfpreg = er32flash(ICH_FLASH_GFPREG);
...@@ -1905,7 +1932,7 @@ void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw) ...@@ -1905,7 +1932,7 @@ void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw)
hsfsts.hsf_status.flockdn = true; hsfsts.hsf_status.flockdn = true;
ew32flash(ICH_FLASH_HSFSTS, hsfsts.regval); ew32flash(ICH_FLASH_HSFSTS, hsfsts.regval);
e1000_release_swflag_ich8lan(hw); nvm->ops.release_nvm(hw);
} }
/** /**
...@@ -3162,9 +3189,9 @@ static struct e1000_phy_operations ich8_phy_ops = { ...@@ -3162,9 +3189,9 @@ static struct e1000_phy_operations ich8_phy_ops = {
}; };
static struct e1000_nvm_operations ich8_nvm_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, .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, .update_nvm = e1000_update_nvm_checksum_ich8lan,
.valid_led_default = e1000_valid_led_default_ich8lan, .valid_led_default = e1000_valid_led_default_ich8lan,
.validate_nvm = e1000_validate_nvm_checksum_ich8lan, .validate_nvm = e1000_validate_nvm_checksum_ich8lan,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment