diff options
author | Bruce Allan <bruce.w.allan@intel.com> | 2009-08-07 03:41:56 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-08-10 00:45:38 -0400 |
commit | 148675a7b2061b5a5eb194530b7c4d8de1f2887e (patch) | |
tree | 0b89a22585215699357afad86f4850bf9c2f28fd /drivers/net/e1000e | |
parent | 373a88d78be540c1331ea5adcb76610dddcb008b (diff) |
e1000e: fix potential NVM corruption on ICH9 with 8K bank size
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>
Diffstat (limited to 'drivers/net/e1000e')
-rw-r--r-- | drivers/net/e1000e/ich8lan.c | 50 |
1 files changed, 12 insertions, 38 deletions
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index dd61e7e98ddb..99df2abf82a9 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c | |||
@@ -338,10 +338,7 @@ static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw) | |||
338 | { | 338 | { |
339 | struct e1000_nvm_info *nvm = &hw->nvm; | 339 | struct e1000_nvm_info *nvm = &hw->nvm; |
340 | struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; | 340 | struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; |
341 | union ich8_hws_flash_status hsfsts; | 341 | u32 gfpreg, sector_base_addr, sector_end_addr; |
342 | u32 gfpreg; | ||
343 | u32 sector_base_addr; | ||
344 | u32 sector_end_addr; | ||
345 | u16 i; | 342 | u16 i; |
346 | 343 | ||
347 | /* Can't read flash registers if the register set isn't mapped. */ | 344 | /* Can't read flash registers if the register set isn't mapped. */ |
@@ -375,20 +372,6 @@ static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw) | |||
375 | /* Adjust to word count */ | 372 | /* Adjust to word count */ |
376 | nvm->flash_bank_size /= sizeof(u16); | 373 | nvm->flash_bank_size /= sizeof(u16); |
377 | 374 | ||
378 | /* | ||
379 | * Make sure the flash bank size does not overwrite the 4k | ||
380 | * sector ranges. We may have 64k allotted to us but we only care | ||
381 | * about the first 2 4k sectors. Therefore, if we have anything less | ||
382 | * than 64k set in the HSFSTS register, we will reduce the bank size | ||
383 | * down to 4k and let the rest remain unused. If berasesz == 3, then | ||
384 | * we are working in 64k mode. Otherwise we are not. | ||
385 | */ | ||
386 | if (nvm->flash_bank_size > E1000_ICH8_SHADOW_RAM_WORDS) { | ||
387 | hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); | ||
388 | if (hsfsts.hsf_status.berasesz != 3) | ||
389 | nvm->flash_bank_size = E1000_ICH8_SHADOW_RAM_WORDS; | ||
390 | } | ||
391 | |||
392 | nvm->word_size = E1000_ICH8_SHADOW_RAM_WORDS; | 375 | nvm->word_size = E1000_ICH8_SHADOW_RAM_WORDS; |
393 | 376 | ||
394 | /* Clear shadow ram */ | 377 | /* Clear shadow ram */ |
@@ -1324,7 +1307,7 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, | |||
1324 | struct e1000_nvm_info *nvm = &hw->nvm; | 1307 | struct e1000_nvm_info *nvm = &hw->nvm; |
1325 | struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; | 1308 | struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; |
1326 | u32 act_offset; | 1309 | u32 act_offset; |
1327 | s32 ret_val; | 1310 | s32 ret_val = 0; |
1328 | u32 bank = 0; | 1311 | u32 bank = 0; |
1329 | u16 i, word; | 1312 | u16 i, word; |
1330 | 1313 | ||
@@ -1339,12 +1322,15 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, | |||
1339 | goto out; | 1322 | goto out; |
1340 | 1323 | ||
1341 | ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); | 1324 | ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); |
1342 | if (ret_val) | 1325 | if (ret_val) { |
1343 | goto release; | 1326 | hw_dbg(hw, "Could not detect valid bank, assuming bank 0\n"); |
1327 | bank = 0; | ||
1328 | } | ||
1344 | 1329 | ||
1345 | act_offset = (bank) ? nvm->flash_bank_size : 0; | 1330 | act_offset = (bank) ? nvm->flash_bank_size : 0; |
1346 | act_offset += offset; | 1331 | act_offset += offset; |
1347 | 1332 | ||
1333 | ret_val = 0; | ||
1348 | for (i = 0; i < words; i++) { | 1334 | for (i = 0; i < words; i++) { |
1349 | if ((dev_spec->shadow_ram) && | 1335 | if ((dev_spec->shadow_ram) && |
1350 | (dev_spec->shadow_ram[offset+i].modified)) { | 1336 | (dev_spec->shadow_ram[offset+i].modified)) { |
@@ -1359,7 +1345,6 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, | |||
1359 | } | 1345 | } |
1360 | } | 1346 | } |
1361 | 1347 | ||
1362 | release: | ||
1363 | e1000_release_swflag_ich8lan(hw); | 1348 | e1000_release_swflag_ich8lan(hw); |
1364 | 1349 | ||
1365 | out: | 1350 | out: |
@@ -1610,7 +1595,6 @@ static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, | |||
1610 | { | 1595 | { |
1611 | struct e1000_nvm_info *nvm = &hw->nvm; | 1596 | struct e1000_nvm_info *nvm = &hw->nvm; |
1612 | struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; | 1597 | struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; |
1613 | s32 ret_val; | ||
1614 | u16 i; | 1598 | u16 i; |
1615 | 1599 | ||
1616 | if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) || | 1600 | if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) || |
@@ -1619,17 +1603,11 @@ static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, | |||
1619 | return -E1000_ERR_NVM; | 1603 | return -E1000_ERR_NVM; |
1620 | } | 1604 | } |
1621 | 1605 | ||
1622 | ret_val = e1000_acquire_swflag_ich8lan(hw); | ||
1623 | if (ret_val) | ||
1624 | return ret_val; | ||
1625 | |||
1626 | for (i = 0; i < words; i++) { | 1606 | for (i = 0; i < words; i++) { |
1627 | dev_spec->shadow_ram[offset+i].modified = 1; | 1607 | dev_spec->shadow_ram[offset+i].modified = 1; |
1628 | dev_spec->shadow_ram[offset+i].value = data[i]; | 1608 | dev_spec->shadow_ram[offset+i].value = data[i]; |
1629 | } | 1609 | } |
1630 | 1610 | ||
1631 | e1000_release_swflag_ich8lan(hw); | ||
1632 | |||
1633 | return 0; | 1611 | return 0; |
1634 | } | 1612 | } |
1635 | 1613 | ||
@@ -1670,8 +1648,8 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) | |||
1670 | */ | 1648 | */ |
1671 | ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); | 1649 | ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); |
1672 | if (ret_val) { | 1650 | if (ret_val) { |
1673 | e1000_release_swflag_ich8lan(hw); | 1651 | hw_dbg(hw, "Could not detect valid bank, assuming bank 0\n"); |
1674 | goto out; | 1652 | bank = 0; |
1675 | } | 1653 | } |
1676 | 1654 | ||
1677 | if (bank == 0) { | 1655 | if (bank == 0) { |
@@ -2057,12 +2035,8 @@ static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank) | |||
2057 | iteration = 1; | 2035 | iteration = 1; |
2058 | break; | 2036 | break; |
2059 | case 2: | 2037 | case 2: |
2060 | if (hw->mac.type == e1000_ich9lan) { | 2038 | sector_size = ICH_FLASH_SEG_SIZE_8K; |
2061 | sector_size = ICH_FLASH_SEG_SIZE_8K; | 2039 | iteration = 1; |
2062 | iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_8K; | ||
2063 | } else { | ||
2064 | return -E1000_ERR_NVM; | ||
2065 | } | ||
2066 | break; | 2040 | break; |
2067 | case 3: | 2041 | case 3: |
2068 | sector_size = ICH_FLASH_SEG_SIZE_64K; | 2042 | sector_size = ICH_FLASH_SEG_SIZE_64K; |
@@ -2074,7 +2048,7 @@ static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank) | |||
2074 | 2048 | ||
2075 | /* Start with the base address, then add the sector offset. */ | 2049 | /* Start with the base address, then add the sector offset. */ |
2076 | flash_linear_addr = hw->nvm.flash_base_addr; | 2050 | flash_linear_addr = hw->nvm.flash_base_addr; |
2077 | flash_linear_addr += (bank) ? (sector_size * iteration) : 0; | 2051 | flash_linear_addr += (bank) ? flash_bank_size : 0; |
2078 | 2052 | ||
2079 | for (j = 0; j < iteration ; j++) { | 2053 | for (j = 0; j < iteration ; j++) { |
2080 | do { | 2054 | do { |