diff options
author | Dave Graham <david.graham@intel.com> | 2009-06-08 10:28:17 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-06-09 08:25:35 -0400 |
commit | 23a2d1b233f535fc74f8dca66e488980b4db041b (patch) | |
tree | 7c0102dfbfa8b789a4385d08151268a6fa3f8a3f /drivers | |
parent | 8459464f07cf67cab07b17d5736d75fb86adab22 (diff) |
e1000e: Fixes possible phy corrupton on 82571 designs.
Phy corruption has been observed on 2-port 82571 adapters, and is root-caused
to lack of synchronization between the 2 driver instances, which conflict
when attempting to access the phy via the single MDIC register.
A semaphore exists for this purpose, and is now used on these designs. Because
PXE &/or EFI boot code (which we cannot expect to be built with this fix) may
leave the inter-instance semaphore in an invalid initial state when the driver
first loads, this fix also includes a one-time (per driver load) fix-up of the
semaphore initial state.
Signed-off-by: dave graham <david.graham@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')
-rw-r--r-- | drivers/net/e1000e/82571.c | 86 | ||||
-rw-r--r-- | drivers/net/e1000e/defines.h | 2 | ||||
-rw-r--r-- | drivers/net/e1000e/hw.h | 2 |
3 files changed, 83 insertions, 7 deletions
diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index c4b3f4fe91ae..b53b40ba88a8 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c | |||
@@ -71,6 +71,7 @@ static s32 e1000_setup_link_82571(struct e1000_hw *hw); | |||
71 | static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw); | 71 | static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw); |
72 | static bool e1000_check_mng_mode_82574(struct e1000_hw *hw); | 72 | static bool e1000_check_mng_mode_82574(struct e1000_hw *hw); |
73 | static s32 e1000_led_on_82574(struct e1000_hw *hw); | 73 | static s32 e1000_led_on_82574(struct e1000_hw *hw); |
74 | static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw); | ||
74 | 75 | ||
75 | /** | 76 | /** |
76 | * e1000_init_phy_params_82571 - Init PHY func ptrs. | 77 | * e1000_init_phy_params_82571 - Init PHY func ptrs. |
@@ -212,6 +213,9 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter) | |||
212 | struct e1000_hw *hw = &adapter->hw; | 213 | struct e1000_hw *hw = &adapter->hw; |
213 | struct e1000_mac_info *mac = &hw->mac; | 214 | struct e1000_mac_info *mac = &hw->mac; |
214 | struct e1000_mac_operations *func = &mac->ops; | 215 | struct e1000_mac_operations *func = &mac->ops; |
216 | u32 swsm = 0; | ||
217 | u32 swsm2 = 0; | ||
218 | bool force_clear_smbi = false; | ||
215 | 219 | ||
216 | /* Set media type */ | 220 | /* Set media type */ |
217 | switch (adapter->pdev->device) { | 221 | switch (adapter->pdev->device) { |
@@ -276,6 +280,50 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter) | |||
276 | break; | 280 | break; |
277 | } | 281 | } |
278 | 282 | ||
283 | /* | ||
284 | * Ensure that the inter-port SWSM.SMBI lock bit is clear before | ||
285 | * first NVM or PHY acess. This should be done for single-port | ||
286 | * devices, and for one port only on dual-port devices so that | ||
287 | * for those devices we can still use the SMBI lock to synchronize | ||
288 | * inter-port accesses to the PHY & NVM. | ||
289 | */ | ||
290 | switch (hw->mac.type) { | ||
291 | case e1000_82571: | ||
292 | case e1000_82572: | ||
293 | swsm2 = er32(SWSM2); | ||
294 | |||
295 | if (!(swsm2 & E1000_SWSM2_LOCK)) { | ||
296 | /* Only do this for the first interface on this card */ | ||
297 | ew32(SWSM2, | ||
298 | swsm2 | E1000_SWSM2_LOCK); | ||
299 | force_clear_smbi = true; | ||
300 | } else | ||
301 | force_clear_smbi = false; | ||
302 | break; | ||
303 | default: | ||
304 | force_clear_smbi = true; | ||
305 | break; | ||
306 | } | ||
307 | |||
308 | if (force_clear_smbi) { | ||
309 | /* Make sure SWSM.SMBI is clear */ | ||
310 | swsm = er32(SWSM); | ||
311 | if (swsm & E1000_SWSM_SMBI) { | ||
312 | /* This bit should not be set on a first interface, and | ||
313 | * indicates that the bootagent or EFI code has | ||
314 | * improperly left this bit enabled | ||
315 | */ | ||
316 | hw_dbg(hw, "Please update your 82571 Bootagent\n"); | ||
317 | } | ||
318 | ew32(SWSM, swsm & ~E1000_SWSM_SMBI); | ||
319 | } | ||
320 | |||
321 | /* | ||
322 | * Initialze device specific counter of SMBI acquisition | ||
323 | * timeouts. | ||
324 | */ | ||
325 | hw->dev_spec.e82571.smb_counter = 0; | ||
326 | |||
279 | return 0; | 327 | return 0; |
280 | } | 328 | } |
281 | 329 | ||
@@ -413,11 +461,37 @@ static s32 e1000_get_phy_id_82571(struct e1000_hw *hw) | |||
413 | static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw) | 461 | static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw) |
414 | { | 462 | { |
415 | u32 swsm; | 463 | u32 swsm; |
416 | s32 timeout = hw->nvm.word_size + 1; | 464 | s32 sw_timeout = hw->nvm.word_size + 1; |
465 | s32 fw_timeout = hw->nvm.word_size + 1; | ||
417 | s32 i = 0; | 466 | s32 i = 0; |
418 | 467 | ||
468 | /* | ||
469 | * If we have timedout 3 times on trying to acquire | ||
470 | * the inter-port SMBI semaphore, there is old code | ||
471 | * operating on the other port, and it is not | ||
472 | * releasing SMBI. Modify the number of times that | ||
473 | * we try for the semaphore to interwork with this | ||
474 | * older code. | ||
475 | */ | ||
476 | if (hw->dev_spec.e82571.smb_counter > 2) | ||
477 | sw_timeout = 1; | ||
478 | |||
479 | /* Get the SW semaphore */ | ||
480 | while (i < sw_timeout) { | ||
481 | swsm = er32(SWSM); | ||
482 | if (!(swsm & E1000_SWSM_SMBI)) | ||
483 | break; | ||
484 | |||
485 | udelay(50); | ||
486 | i++; | ||
487 | } | ||
488 | |||
489 | if (i == sw_timeout) { | ||
490 | hw_dbg(hw, "Driver can't access device - SMBI bit is set.\n"); | ||
491 | hw->dev_spec.e82571.smb_counter++; | ||
492 | } | ||
419 | /* Get the FW semaphore. */ | 493 | /* Get the FW semaphore. */ |
420 | for (i = 0; i < timeout; i++) { | 494 | for (i = 0; i < fw_timeout; i++) { |
421 | swsm = er32(SWSM); | 495 | swsm = er32(SWSM); |
422 | ew32(SWSM, swsm | E1000_SWSM_SWESMBI); | 496 | ew32(SWSM, swsm | E1000_SWSM_SWESMBI); |
423 | 497 | ||
@@ -428,9 +502,9 @@ static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw) | |||
428 | udelay(50); | 502 | udelay(50); |
429 | } | 503 | } |
430 | 504 | ||
431 | if (i == timeout) { | 505 | if (i == fw_timeout) { |
432 | /* Release semaphores */ | 506 | /* Release semaphores */ |
433 | e1000e_put_hw_semaphore(hw); | 507 | e1000_put_hw_semaphore_82571(hw); |
434 | hw_dbg(hw, "Driver can't access the NVM\n"); | 508 | hw_dbg(hw, "Driver can't access the NVM\n"); |
435 | return -E1000_ERR_NVM; | 509 | return -E1000_ERR_NVM; |
436 | } | 510 | } |
@@ -449,9 +523,7 @@ static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw) | |||
449 | u32 swsm; | 523 | u32 swsm; |
450 | 524 | ||
451 | swsm = er32(SWSM); | 525 | swsm = er32(SWSM); |
452 | 526 | swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); | |
453 | swsm &= ~E1000_SWSM_SWESMBI; | ||
454 | |||
455 | ew32(SWSM, swsm); | 527 | ew32(SWSM, swsm); |
456 | } | 528 | } |
457 | 529 | ||
diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h index 674a47e43034..8890c97e1120 100644 --- a/drivers/net/e1000e/defines.h +++ b/drivers/net/e1000e/defines.h | |||
@@ -376,6 +376,8 @@ | |||
376 | #define E1000_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ | 376 | #define E1000_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ |
377 | #define E1000_SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */ | 377 | #define E1000_SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */ |
378 | 378 | ||
379 | #define E1000_SWSM2_LOCK 0x00000002 /* Secondary driver semaphore bit */ | ||
380 | |||
379 | /* Interrupt Cause Read */ | 381 | /* Interrupt Cause Read */ |
380 | #define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */ | 382 | #define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */ |
381 | #define E1000_ICR_LSC 0x00000004 /* Link Status Change */ | 383 | #define E1000_ICR_LSC 0x00000004 /* Link Status Change */ |
diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h index fce3f0529e4c..163c1c0cfee7 100644 --- a/drivers/net/e1000e/hw.h +++ b/drivers/net/e1000e/hw.h | |||
@@ -214,6 +214,7 @@ enum e1e_registers { | |||
214 | E1000_FACTPS = 0x05B30, /* Function Active and Power State to MNG */ | 214 | E1000_FACTPS = 0x05B30, /* Function Active and Power State to MNG */ |
215 | E1000_SWSM = 0x05B50, /* SW Semaphore */ | 215 | E1000_SWSM = 0x05B50, /* SW Semaphore */ |
216 | E1000_FWSM = 0x05B54, /* FW Semaphore */ | 216 | E1000_FWSM = 0x05B54, /* FW Semaphore */ |
217 | E1000_SWSM2 = 0x05B58, /* Driver-only SW semaphore */ | ||
217 | E1000_HICR = 0x08F00, /* Host Interface Control */ | 218 | E1000_HICR = 0x08F00, /* Host Interface Control */ |
218 | }; | 219 | }; |
219 | 220 | ||
@@ -883,6 +884,7 @@ struct e1000_fc_info { | |||
883 | struct e1000_dev_spec_82571 { | 884 | struct e1000_dev_spec_82571 { |
884 | bool laa_is_present; | 885 | bool laa_is_present; |
885 | bool alt_mac_addr_is_present; | 886 | bool alt_mac_addr_is_present; |
887 | u32 smb_counter; | ||
886 | }; | 888 | }; |
887 | 889 | ||
888 | struct e1000_shadow_ram { | 890 | struct e1000_shadow_ram { |