Skip to content

Commit

Permalink
e1000e: check return code from NVM accesses and fix bank detection
Browse files Browse the repository at this point in the history
Check return code for all NVM accesses[1] and error out accordingly; log
a debug message for failed accesses.

For ICH8/9, the valid NVM bank detect function was not checking whether the
SEC1VAL (sector 1 valid) bit in the EECD register was itself valid (bits 8
and 9 also have to be set).  If invalid, it would have defaulted to the
possibly invalid bank 0.  Instead, try to use the valid bank detection
method used by ICH10 which has been cleaned up a bit.

[1] - reads and updates only; not writes because those are only writing to
the Shadow RAM, the update following the write is the only thing actually
writing the modified Shadow RAM contents to the NVM.

Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Bruce Allan authored and David S. Miller committed Nov 22, 2008
1 parent a20e4cf commit e243455
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 63 deletions.
5 changes: 3 additions & 2 deletions drivers/net/e1000e/82571.c
Original file line number Diff line number Diff line change
Expand Up @@ -332,8 +332,9 @@ static s32 e1000_get_variants_82571(struct e1000_adapter *adapter)

case e1000_82573:
if (pdev->device == E1000_DEV_ID_82573L) {
e1000_read_nvm(&adapter->hw, NVM_INIT_3GIO_3, 1,
&eeprom_data);
if (e1000_read_nvm(&adapter->hw, NVM_INIT_3GIO_3, 1,
&eeprom_data) < 0)
break;
if (eeprom_data & NVM_WORD1A_ASPM_MASK)
adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES;
}
Expand Down
1 change: 1 addition & 0 deletions drivers/net/e1000e/defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,7 @@
#define E1000_EECD_FLUPD 0x00080000 /* Update FLASH */
#define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */
#define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */
#define E1000_EECD_SEC1VAL_VALID_MASK (E1000_EECD_AUTO_RD | E1000_EECD_PRES)

#define E1000_NVM_RW_REG_DATA 16 /* Offset to data in NVM read/write registers */
#define E1000_NVM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */
Expand Down
35 changes: 21 additions & 14 deletions drivers/net/e1000e/ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -492,18 +492,19 @@ static int e1000_get_eeprom(struct net_device *netdev,
for (i = 0; i < last_word - first_word + 1; i++) {
ret_val = e1000_read_nvm(hw, first_word + i, 1,
&eeprom_buff[i]);
if (ret_val) {
/* a read error occurred, throw away the
* result */
memset(eeprom_buff, 0xff, sizeof(eeprom_buff));
if (ret_val)
break;
}
}
}

/* Device's eeprom is always little-endian, word addressable */
for (i = 0; i < last_word - first_word + 1; i++)
le16_to_cpus(&eeprom_buff[i]);
if (ret_val) {
/* a read error occurred, throw away the result */
memset(eeprom_buff, 0xff, sizeof(eeprom_buff));
} else {
/* Device's eeprom is always little-endian, word addressable */
for (i = 0; i < last_word - first_word + 1; i++)
le16_to_cpus(&eeprom_buff[i]);
}

memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len);
kfree(eeprom_buff);
Expand Down Expand Up @@ -555,6 +556,9 @@ static int e1000_set_eeprom(struct net_device *netdev,
ret_val = e1000_read_nvm(hw, last_word, 1,
&eeprom_buff[last_word - first_word]);

if (ret_val)
goto out;

/* Device's eeprom is always little-endian, word addressable */
for (i = 0; i < last_word - first_word + 1; i++)
le16_to_cpus(&eeprom_buff[i]);
Expand All @@ -567,15 +571,18 @@ static int e1000_set_eeprom(struct net_device *netdev,
ret_val = e1000_write_nvm(hw, first_word,
last_word - first_word + 1, eeprom_buff);

if (ret_val)
goto out;

/*
* Update the checksum over the first part of the EEPROM if needed
* and flush shadow RAM for 82573 controllers
* and flush shadow RAM for applicable controllers
*/
if ((ret_val == 0) && ((first_word <= NVM_CHECKSUM_REG) ||
(hw->mac.type == e1000_82574) ||
(hw->mac.type == e1000_82573)))
e1000e_update_nvm_checksum(hw);
if ((first_word <= NVM_CHECKSUM_REG) ||
(hw->mac.type == e1000_82574) || (hw->mac.type == e1000_82573))
ret_val = e1000e_update_nvm_checksum(hw);

out:
kfree(eeprom_buff);
return ret_val;
}
Expand Down Expand Up @@ -860,7 +867,7 @@ static int e1000_eeprom_test(struct e1000_adapter *adapter, u64 *data)
for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
if ((e1000_read_nvm(&adapter->hw, i, 1, &temp)) < 0) {
*data = 1;
break;
return *data;
}
checksum += temp;
}
Expand Down
134 changes: 89 additions & 45 deletions drivers/net/e1000e/ich8lan.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@

#define E1000_ICH_NVM_SIG_WORD 0x13
#define E1000_ICH_NVM_SIG_MASK 0xC000
#define E1000_ICH_NVM_VALID_SIG_MASK 0xC0
#define E1000_ICH_NVM_SIG_VALUE 0x80

#define E1000_ICH8_LAN_INIT_TIMEOUT 1500

Expand Down Expand Up @@ -958,45 +960,62 @@ static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
* @bank: pointer to the variable that returns the active bank
*
* Reads signature byte from the NVM using the flash access registers.
* Word 0x13 bits 15:14 = 10b indicate a valid signature for that bank.
**/
static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
{
u32 eecd;
struct e1000_nvm_info *nvm = &hw->nvm;
/* flash bank size is in words */
u32 bank1_offset = nvm->flash_bank_size * sizeof(u16);
u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1;
u8 bank_high_byte = 0;
u8 sig_byte = 0;
s32 ret_val = 0;

if (hw->mac.type != e1000_ich10lan) {
if (er32(EECD) & E1000_EECD_SEC1VAL)
*bank = 1;
else
*bank = 0;
} else {
/*
* Make sure the signature for bank 0 is valid,
* if not check for bank1
*/
e1000_read_flash_byte_ich8lan(hw, act_offset, &bank_high_byte);
if ((bank_high_byte & 0xC0) == 0x80) {
switch (hw->mac.type) {
case e1000_ich8lan:
case e1000_ich9lan:
eecd = er32(EECD);
if ((eecd & E1000_EECD_SEC1VAL_VALID_MASK) ==
E1000_EECD_SEC1VAL_VALID_MASK) {
if (eecd & E1000_EECD_SEC1VAL)
*bank = 1;
else
*bank = 0;

return 0;
}
hw_dbg(hw, "Unable to determine valid NVM bank via EEC - "
"reading flash signature\n");
/* fall-thru */
default:
/* set bank to 0 in case flash read fails */
*bank = 0;

/* Check bank 0 */
ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset,
&sig_byte);
if (ret_val)
return ret_val;
if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
E1000_ICH_NVM_SIG_VALUE) {
*bank = 0;
} else {
/*
* find if segment 1 is valid by verifying
* bit 15:14 = 10b in word 0x13
*/
e1000_read_flash_byte_ich8lan(hw,
act_offset + bank1_offset,
&bank_high_byte);
return 0;
}

/* bank1 has a valid signature equivalent to SEC1V */
if ((bank_high_byte & 0xC0) == 0x80) {
*bank = 1;
} else {
hw_dbg(hw, "ERROR: EEPROM not present\n");
return -E1000_ERR_NVM;
}
/* Check bank 1 */
ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset +
bank1_offset,
&sig_byte);
if (ret_val)
return ret_val;
if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
E1000_ICH_NVM_SIG_VALUE) {
*bank = 1;
return 0;
}

hw_dbg(hw, "ERROR: No valid NVM bank present\n");
return -E1000_ERR_NVM;
}

return 0;
Expand Down Expand Up @@ -1029,11 +1048,11 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,

ret_val = e1000_acquire_swflag_ich8lan(hw);
if (ret_val)
return ret_val;
goto out;

ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
if (ret_val)
return ret_val;
goto release;

act_offset = (bank) ? nvm->flash_bank_size : 0;
act_offset += offset;
Expand All @@ -1052,8 +1071,13 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
}
}

release:
e1000_release_swflag_ich8lan(hw);

out:
if (ret_val)
hw_dbg(hw, "NVM read error: %d\n", ret_val);

return ret_val;
}

Expand Down Expand Up @@ -1342,32 +1366,42 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)

ret_val = e1000e_update_nvm_checksum_generic(hw);
if (ret_val)
return ret_val;
goto out;

if (nvm->type != e1000_nvm_flash_sw)
return ret_val;
goto out;

ret_val = e1000_acquire_swflag_ich8lan(hw);
if (ret_val)
return ret_val;
goto out;

/*
* We're writing to the opposite bank so if we're on bank 1,
* write to bank 0 etc. We also need to erase the segment that
* is going to be written
*/
ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
if (ret_val)
return ret_val;
if (ret_val) {
e1000_release_swflag_ich8lan(hw);
goto out;
}

if (bank == 0) {
new_bank_offset = nvm->flash_bank_size;
old_bank_offset = 0;
e1000_erase_flash_bank_ich8lan(hw, 1);
ret_val = e1000_erase_flash_bank_ich8lan(hw, 1);
if (ret_val) {
e1000_release_swflag_ich8lan(hw);
goto out;
}
} else {
old_bank_offset = nvm->flash_bank_size;
new_bank_offset = 0;
e1000_erase_flash_bank_ich8lan(hw, 0);
ret_val = e1000_erase_flash_bank_ich8lan(hw, 0);
if (ret_val) {
e1000_release_swflag_ich8lan(hw);
goto out;
}
}

for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) {
Expand All @@ -1379,9 +1413,11 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
if (dev_spec->shadow_ram[i].modified) {
data = dev_spec->shadow_ram[i].value;
} else {
e1000_read_flash_word_ich8lan(hw,
i + old_bank_offset,
&data);
ret_val = e1000_read_flash_word_ich8lan(hw, i +
old_bank_offset,
&data);
if (ret_val)
break;
}

/*
Expand Down Expand Up @@ -1422,7 +1458,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
/* Possibly read-only, see e1000e_write_protect_nvm_ich8lan() */
hw_dbg(hw, "Flash commit failed.\n");
e1000_release_swflag_ich8lan(hw);
return ret_val;
goto out;
}

/*
Expand All @@ -1432,14 +1468,18 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
* and we need to change bit 14 to 0b
*/
act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
e1000_read_flash_word_ich8lan(hw, act_offset, &data);
ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data);
if (ret_val) {
e1000_release_swflag_ich8lan(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);
return ret_val;
goto out;
}

/*
Expand All @@ -1452,7 +1492,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0);
if (ret_val) {
e1000_release_swflag_ich8lan(hw);
return ret_val;
goto out;
}

/* Great! Everything worked, we can now clear the cached entries. */
Expand All @@ -1470,6 +1510,10 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
e1000e_reload_nvm(hw);
msleep(10);

out:
if (ret_val)
hw_dbg(hw, "NVM update error: %d\n", ret_val);

return ret_val;
}

Expand Down
4 changes: 2 additions & 2 deletions drivers/net/e1000e/netdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -4723,14 +4723,14 @@ static void e1000_eeprom_checks(struct e1000_adapter *adapter)
return;

ret_val = e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &buf);
if (!(le16_to_cpu(buf) & (1 << 0))) {
if (!ret_val && (!(le16_to_cpu(buf) & (1 << 0)))) {
/* Deep Smart Power Down (DSPD) */
dev_warn(&adapter->pdev->dev,
"Warning: detected DSPD enabled in EEPROM\n");
}

ret_val = e1000_read_nvm(hw, NVM_INIT_3GIO_3, 1, &buf);
if (le16_to_cpu(buf) & (3 << 2)) {
if (!ret_val && (le16_to_cpu(buf) & (3 << 2))) {
/* ASPM enable */
dev_warn(&adapter->pdev->dev,
"Warning: detected ASPM enabled in EEPROM\n");
Expand Down

0 comments on commit e243455

Please sign in to comment.