Skip to content

Commit

Permalink
e1000e: fix potential NVM corruption on ICH9 with 8K bank size
Browse files Browse the repository at this point in the history
The bank offset was being incorrectly calculated on ICH9 parts with a bank
size of 8K (instead of the more common 4K bank) which would cause any NVM
writes to be done on the wrong address after switching from bank 1 to bank
0.  Additionally, assume we are meant to use bank 0 if a valid bank is not
detected, and remove the unnecessary acquisition of the SW/FW/HW semaphore
when writing to the shadow ram version of the NVM image.

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 Aug 10, 2009
1 parent 373a88d commit 148675a
Showing 1 changed file with 12 additions and 38 deletions.
50 changes: 12 additions & 38 deletions drivers/net/e1000e/ich8lan.c
Original file line number Diff line number Diff line change
Expand Up @@ -338,10 +338,7 @@ static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
{
struct e1000_nvm_info *nvm = &hw->nvm;
struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
union ich8_hws_flash_status hsfsts;
u32 gfpreg;
u32 sector_base_addr;
u32 sector_end_addr;
u32 gfpreg, sector_base_addr, sector_end_addr;
u16 i;

/* Can't read flash registers if the register set isn't mapped. */
Expand Down Expand Up @@ -375,20 +372,6 @@ static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
/* Adjust to word count */
nvm->flash_bank_size /= sizeof(u16);

/*
* Make sure the flash bank size does not overwrite the 4k
* sector ranges. We may have 64k allotted to us but we only care
* about the first 2 4k sectors. Therefore, if we have anything less
* than 64k set in the HSFSTS register, we will reduce the bank size
* down to 4k and let the rest remain unused. If berasesz == 3, then
* we are working in 64k mode. Otherwise we are not.
*/
if (nvm->flash_bank_size > E1000_ICH8_SHADOW_RAM_WORDS) {
hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
if (hsfsts.hsf_status.berasesz != 3)
nvm->flash_bank_size = E1000_ICH8_SHADOW_RAM_WORDS;
}

nvm->word_size = E1000_ICH8_SHADOW_RAM_WORDS;

/* Clear shadow ram */
Expand Down Expand Up @@ -1324,7 +1307,7 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
struct e1000_nvm_info *nvm = &hw->nvm;
struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
u32 act_offset;
s32 ret_val;
s32 ret_val = 0;
u32 bank = 0;
u16 i, word;

Expand All @@ -1339,12 +1322,15 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
goto out;

ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
if (ret_val)
goto release;
if (ret_val) {
hw_dbg(hw, "Could not detect valid bank, assuming bank 0\n");
bank = 0;
}

act_offset = (bank) ? nvm->flash_bank_size : 0;
act_offset += offset;

ret_val = 0;
for (i = 0; i < words; i++) {
if ((dev_spec->shadow_ram) &&
(dev_spec->shadow_ram[offset+i].modified)) {
Expand All @@ -1359,7 +1345,6 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
}
}

release:
e1000_release_swflag_ich8lan(hw);

out:
Expand Down Expand Up @@ -1610,7 +1595,6 @@ static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
{
struct e1000_nvm_info *nvm = &hw->nvm;
struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
s32 ret_val;
u16 i;

if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
Expand All @@ -1619,17 +1603,11 @@ static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
return -E1000_ERR_NVM;
}

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

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

e1000_release_swflag_ich8lan(hw);

return 0;
}

Expand Down Expand Up @@ -1670,8 +1648,8 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
*/
ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
if (ret_val) {
e1000_release_swflag_ich8lan(hw);
goto out;
hw_dbg(hw, "Could not detect valid bank, assuming bank 0\n");
bank = 0;
}

if (bank == 0) {
Expand Down Expand Up @@ -2057,12 +2035,8 @@ static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
iteration = 1;
break;
case 2:
if (hw->mac.type == e1000_ich9lan) {
sector_size = ICH_FLASH_SEG_SIZE_8K;
iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_8K;
} else {
return -E1000_ERR_NVM;
}
sector_size = ICH_FLASH_SEG_SIZE_8K;
iteration = 1;
break;
case 3:
sector_size = ICH_FLASH_SEG_SIZE_64K;
Expand All @@ -2074,7 +2048,7 @@ static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)

/* Start with the base address, then add the sector offset. */
flash_linear_addr = hw->nvm.flash_base_addr;
flash_linear_addr += (bank) ? (sector_size * iteration) : 0;
flash_linear_addr += (bank) ? flash_bank_size : 0;

for (j = 0; j < iteration ; j++) {
do {
Expand Down

0 comments on commit 148675a

Please sign in to comment.