diff options
author | Bruce Allan <bruce.w.allan@intel.com> | 2009-12-08 02:28:20 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-12-08 23:10:12 -0500 |
commit | 3421eecdee750bafc78b12ac25b3e980195265eb (patch) | |
tree | 40df8a228f3971487a3f48bd1e880df1f88d5861 /drivers | |
parent | 0781895067444db98050a1537bafbc7a0235ec9f (diff) |
e1000e: only perform ESB2 MDIC workaround on certain configurations
A workaround added for all ESB2 devices (adds a delay for all MDIC accesses
which resolves an issue with the MDIC ready bit being set prematurely) is
applicable only to devices in which the MAC-PHY interconnect is not
operating in a certain mode with in-band MDIO. Check the control register
for the operating mode and enable the workaround accordingly.
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')
-rw-r--r-- | drivers/net/e1000e/es2lan.c | 97 | ||||
-rw-r--r-- | drivers/net/e1000e/hw.h | 5 |
2 files changed, 69 insertions, 33 deletions
diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c index d2a104794609..3028f23da891 100644 --- a/drivers/net/e1000e/es2lan.c +++ b/drivers/net/e1000e/es2lan.c | |||
@@ -46,6 +46,9 @@ | |||
46 | #define E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT 0x0000 | 46 | #define E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT 0x0000 |
47 | #define E1000_KMRNCTRLSTA_OPMODE_E_IDLE 0x2000 | 47 | #define E1000_KMRNCTRLSTA_OPMODE_E_IDLE 0x2000 |
48 | 48 | ||
49 | #define E1000_KMRNCTRLSTA_OPMODE_MASK 0x000C | ||
50 | #define E1000_KMRNCTRLSTA_OPMODE_INBAND_MDIO 0x0004 | ||
51 | |||
49 | #define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */ | 52 | #define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */ |
50 | #define DEFAULT_TCTL_EXT_GCEX_80003ES2LAN 0x00010000 | 53 | #define DEFAULT_TCTL_EXT_GCEX_80003ES2LAN 0x00010000 |
51 | 54 | ||
@@ -462,28 +465,36 @@ static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw, | |||
462 | return ret_val; | 465 | return ret_val; |
463 | } | 466 | } |
464 | 467 | ||
465 | /* | 468 | if (hw->dev_spec.e80003es2lan.mdic_wa_enable == true) { |
466 | * The "ready" bit in the MDIC register may be incorrectly set | 469 | /* |
467 | * before the device has completed the "Page Select" MDI | 470 | * The "ready" bit in the MDIC register may be incorrectly set |
468 | * transaction. So we wait 200us after each MDI command... | 471 | * before the device has completed the "Page Select" MDI |
469 | */ | 472 | * transaction. So we wait 200us after each MDI command... |
470 | udelay(200); | 473 | */ |
474 | udelay(200); | ||
471 | 475 | ||
472 | /* ...and verify the command was successful. */ | 476 | /* ...and verify the command was successful. */ |
473 | ret_val = e1000e_read_phy_reg_mdic(hw, page_select, &temp); | 477 | ret_val = e1000e_read_phy_reg_mdic(hw, page_select, &temp); |
474 | 478 | ||
475 | if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) { | 479 | if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) { |
476 | ret_val = -E1000_ERR_PHY; | 480 | ret_val = -E1000_ERR_PHY; |
477 | e1000_release_phy_80003es2lan(hw); | 481 | e1000_release_phy_80003es2lan(hw); |
478 | return ret_val; | 482 | return ret_val; |
479 | } | 483 | } |
480 | 484 | ||
481 | udelay(200); | 485 | udelay(200); |
482 | 486 | ||
483 | ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, | 487 | ret_val = e1000e_read_phy_reg_mdic(hw, |
484 | data); | 488 | MAX_PHY_REG_ADDRESS & offset, |
489 | data); | ||
490 | |||
491 | udelay(200); | ||
492 | } else { | ||
493 | ret_val = e1000e_read_phy_reg_mdic(hw, | ||
494 | MAX_PHY_REG_ADDRESS & offset, | ||
495 | data); | ||
496 | } | ||
485 | 497 | ||
486 | udelay(200); | ||
487 | e1000_release_phy_80003es2lan(hw); | 498 | e1000_release_phy_80003es2lan(hw); |
488 | 499 | ||
489 | return ret_val; | 500 | return ret_val; |
@@ -526,28 +537,35 @@ static s32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw, | |||
526 | return ret_val; | 537 | return ret_val; |
527 | } | 538 | } |
528 | 539 | ||
540 | if (hw->dev_spec.e80003es2lan.mdic_wa_enable == true) { | ||
541 | /* | ||
542 | * The "ready" bit in the MDIC register may be incorrectly set | ||
543 | * before the device has completed the "Page Select" MDI | ||
544 | * transaction. So we wait 200us after each MDI command... | ||
545 | */ | ||
546 | udelay(200); | ||
529 | 547 | ||
530 | /* | 548 | /* ...and verify the command was successful. */ |
531 | * The "ready" bit in the MDIC register may be incorrectly set | 549 | ret_val = e1000e_read_phy_reg_mdic(hw, page_select, &temp); |
532 | * before the device has completed the "Page Select" MDI | ||
533 | * transaction. So we wait 200us after each MDI command... | ||
534 | */ | ||
535 | udelay(200); | ||
536 | 550 | ||
537 | /* ...and verify the command was successful. */ | 551 | if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) { |
538 | ret_val = e1000e_read_phy_reg_mdic(hw, page_select, &temp); | 552 | e1000_release_phy_80003es2lan(hw); |
553 | return -E1000_ERR_PHY; | ||
554 | } | ||
539 | 555 | ||
540 | if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) { | 556 | udelay(200); |
541 | e1000_release_phy_80003es2lan(hw); | ||
542 | return -E1000_ERR_PHY; | ||
543 | } | ||
544 | 557 | ||
545 | udelay(200); | 558 | ret_val = e1000e_write_phy_reg_mdic(hw, |
559 | MAX_PHY_REG_ADDRESS & offset, | ||
560 | data); | ||
546 | 561 | ||
547 | ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, | 562 | udelay(200); |
548 | data); | 563 | } else { |
564 | ret_val = e1000e_write_phy_reg_mdic(hw, | ||
565 | MAX_PHY_REG_ADDRESS & offset, | ||
566 | data); | ||
567 | } | ||
549 | 568 | ||
550 | udelay(200); | ||
551 | e1000_release_phy_80003es2lan(hw); | 569 | e1000_release_phy_80003es2lan(hw); |
552 | 570 | ||
553 | return ret_val; | 571 | return ret_val; |
@@ -866,6 +884,19 @@ static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw) | |||
866 | reg_data &= ~0x00100000; | 884 | reg_data &= ~0x00100000; |
867 | E1000_WRITE_REG_ARRAY(hw, E1000_FFLT, 0x0001, reg_data); | 885 | E1000_WRITE_REG_ARRAY(hw, E1000_FFLT, 0x0001, reg_data); |
868 | 886 | ||
887 | /* default to true to enable the MDIC W/A */ | ||
888 | hw->dev_spec.e80003es2lan.mdic_wa_enable = true; | ||
889 | |||
890 | ret_val = e1000_read_kmrn_reg_80003es2lan(hw, | ||
891 | E1000_KMRNCTRLSTA_OFFSET >> | ||
892 | E1000_KMRNCTRLSTA_OFFSET_SHIFT, | ||
893 | &i); | ||
894 | if (!ret_val) { | ||
895 | if ((i & E1000_KMRNCTRLSTA_OPMODE_MASK) == | ||
896 | E1000_KMRNCTRLSTA_OPMODE_INBAND_MDIO) | ||
897 | hw->dev_spec.e80003es2lan.mdic_wa_enable = false; | ||
898 | } | ||
899 | |||
869 | /* | 900 | /* |
870 | * Clear all of the statistics registers (clear on read). It is | 901 | * Clear all of the statistics registers (clear on read). It is |
871 | * important that we do this after we have tried to establish link | 902 | * important that we do this after we have tried to establish link |
diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h index 5ed17889e64d..2784cf44a6f3 100644 --- a/drivers/net/e1000e/hw.h +++ b/drivers/net/e1000e/hw.h | |||
@@ -900,6 +900,10 @@ struct e1000_dev_spec_82571 { | |||
900 | u32 smb_counter; | 900 | u32 smb_counter; |
901 | }; | 901 | }; |
902 | 902 | ||
903 | struct e1000_dev_spec_80003es2lan { | ||
904 | bool mdic_wa_enable; | ||
905 | }; | ||
906 | |||
903 | struct e1000_shadow_ram { | 907 | struct e1000_shadow_ram { |
904 | u16 value; | 908 | u16 value; |
905 | bool modified; | 909 | bool modified; |
@@ -928,6 +932,7 @@ struct e1000_hw { | |||
928 | 932 | ||
929 | union { | 933 | union { |
930 | struct e1000_dev_spec_82571 e82571; | 934 | struct e1000_dev_spec_82571 e82571; |
935 | struct e1000_dev_spec_80003es2lan e80003es2lan; | ||
931 | struct e1000_dev_spec_ich8lan ich8lan; | 936 | struct e1000_dev_spec_ich8lan ich8lan; |
932 | } dev_spec; | 937 | } dev_spec; |
933 | }; | 938 | }; |