X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=src%2Fpatches%2Fsuse-2.6.27.25%2Fpatches.drivers%2Fe1000e-Fixes-possible-phy-corrupton-on-82571-design.patch;fp=src%2Fpatches%2Fsuse-2.6.27.25%2Fpatches.drivers%2Fe1000e-Fixes-possible-phy-corrupton-on-82571-design.patch;h=a235c0a31665062c5704fe0de418e2619b26406b;hb=2e4178199a697105e827d68d66ab7101acd1dd8c;hp=0000000000000000000000000000000000000000;hpb=df2a9a46c7db6362520343d6ec70fbcfe40b2795;p=people%2Fpmueller%2Fipfire-2.x.git diff --git a/src/patches/suse-2.6.27.25/patches.drivers/e1000e-Fixes-possible-phy-corrupton-on-82571-design.patch b/src/patches/suse-2.6.27.25/patches.drivers/e1000e-Fixes-possible-phy-corrupton-on-82571-design.patch new file mode 100644 index 0000000000..a235c0a316 --- /dev/null +++ b/src/patches/suse-2.6.27.25/patches.drivers/e1000e-Fixes-possible-phy-corrupton-on-82571-design.patch @@ -0,0 +1,194 @@ +From 23a2d1b233f535fc74f8dca66e488980b4db041b Mon Sep 17 00:00:00 2001 +From: Dave Graham +Date: Mon, 8 Jun 2009 14:28:17 +0000 +Subject: [PATCH] e1000e: Fixes possible phy corrupton on 82571 designs. +References: bnc#495259 + +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 +Signed-off-by: Jeff Kirsher +Signed-off-by: David S. Miller +Acked-by: Brandon Philips +--- + drivers/net/e1000e/82571.c | 86 +++++++++++++++++++++++++++++++++++++++---- + drivers/net/e1000e/defines.h | 2 + + drivers/net/e1000e/hw.h | 2 + + 3 files changed, 83 insertions(+), 7 deletions(-) + +Index: linux-2.6.27-SLE11_BRANCH/drivers/net/e1000e/82571.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/net/e1000e/82571.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/net/e1000e/82571.c +@@ -68,6 +68,7 @@ static s32 e1000_setup_link_82571(struct + static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw); + static bool e1000_check_mng_mode_82574(struct e1000_hw *hw); + static s32 e1000_led_on_82574(struct e1000_hw *hw); ++static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw); + + /** + * e1000_init_phy_params_82571 - Init PHY func ptrs. +@@ -206,6 +207,9 @@ static s32 e1000_init_mac_params_82571(s + struct e1000_hw *hw = &adapter->hw; + struct e1000_mac_info *mac = &hw->mac; + struct e1000_mac_operations *func = &mac->ops; ++ u32 swsm = 0; ++ u32 swsm2 = 0; ++ bool force_clear_smbi = false; + + /* Set media type */ + switch (adapter->pdev->device) { +@@ -269,6 +273,50 @@ static s32 e1000_init_mac_params_82571(s + break; + } + ++ /* ++ * Ensure that the inter-port SWSM.SMBI lock bit is clear before ++ * first NVM or PHY acess. This should be done for single-port ++ * devices, and for one port only on dual-port devices so that ++ * for those devices we can still use the SMBI lock to synchronize ++ * inter-port accesses to the PHY & NVM. ++ */ ++ switch (hw->mac.type) { ++ case e1000_82571: ++ case e1000_82572: ++ swsm2 = er32(SWSM2); ++ ++ if (!(swsm2 & E1000_SWSM2_LOCK)) { ++ /* Only do this for the first interface on this card */ ++ ew32(SWSM2, ++ swsm2 | E1000_SWSM2_LOCK); ++ force_clear_smbi = true; ++ } else ++ force_clear_smbi = false; ++ break; ++ default: ++ force_clear_smbi = true; ++ break; ++ } ++ ++ if (force_clear_smbi) { ++ /* Make sure SWSM.SMBI is clear */ ++ swsm = er32(SWSM); ++ if (swsm & E1000_SWSM_SMBI) { ++ /* This bit should not be set on a first interface, and ++ * indicates that the bootagent or EFI code has ++ * improperly left this bit enabled ++ */ ++ hw_dbg(hw, "Please update your 82571 Bootagent\n"); ++ } ++ ew32(SWSM, swsm & ~E1000_SWSM_SMBI); ++ } ++ ++ /* ++ * Initialze device specific counter of SMBI acquisition ++ * timeouts. ++ */ ++ hw->dev_spec.e82571.smb_counter = 0; ++ + return 0; + } + +@@ -402,11 +450,37 @@ static s32 e1000_get_phy_id_82571(struct + static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw) + { + u32 swsm; +- s32 timeout = hw->nvm.word_size + 1; ++ s32 sw_timeout = hw->nvm.word_size + 1; ++ s32 fw_timeout = hw->nvm.word_size + 1; + s32 i = 0; + ++ /* ++ * If we have timedout 3 times on trying to acquire ++ * the inter-port SMBI semaphore, there is old code ++ * operating on the other port, and it is not ++ * releasing SMBI. Modify the number of times that ++ * we try for the semaphore to interwork with this ++ * older code. ++ */ ++ if (hw->dev_spec.e82571.smb_counter > 2) ++ sw_timeout = 1; ++ ++ /* Get the SW semaphore */ ++ while (i < sw_timeout) { ++ swsm = er32(SWSM); ++ if (!(swsm & E1000_SWSM_SMBI)) ++ break; ++ ++ udelay(50); ++ i++; ++ } ++ ++ if (i == sw_timeout) { ++ hw_dbg(hw, "Driver can't access device - SMBI bit is set.\n"); ++ hw->dev_spec.e82571.smb_counter++; ++ } + /* Get the FW semaphore. */ +- for (i = 0; i < timeout; i++) { ++ for (i = 0; i < fw_timeout; i++) { + swsm = er32(SWSM); + ew32(SWSM, swsm | E1000_SWSM_SWESMBI); + +@@ -417,9 +491,9 @@ static s32 e1000_get_hw_semaphore_82571( + udelay(50); + } + +- if (i == timeout) { ++ if (i == fw_timeout) { + /* Release semaphores */ +- e1000e_put_hw_semaphore(hw); ++ e1000_put_hw_semaphore_82571(hw); + hw_dbg(hw, "Driver can't access the NVM\n"); + return -E1000_ERR_NVM; + } +@@ -438,9 +512,7 @@ static void e1000_put_hw_semaphore_82571 + u32 swsm; + + swsm = er32(SWSM); +- +- swsm &= ~E1000_SWSM_SWESMBI; +- ++ swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); + ew32(SWSM, swsm); + } + +Index: linux-2.6.27-SLE11_BRANCH/drivers/net/e1000e/defines.h +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/net/e1000e/defines.h ++++ linux-2.6.27-SLE11_BRANCH/drivers/net/e1000e/defines.h +@@ -359,6 +359,8 @@ + #define E1000_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ + #define E1000_SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */ + ++#define E1000_SWSM2_LOCK 0x00000002 /* Secondary driver semaphore bit */ ++ + /* Interrupt Cause Read */ + #define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */ + #define E1000_ICR_LSC 0x00000004 /* Link Status Change */ +Index: linux-2.6.27-SLE11_BRANCH/drivers/net/e1000e/hw.h +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/net/e1000e/hw.h ++++ linux-2.6.27-SLE11_BRANCH/drivers/net/e1000e/hw.h +@@ -209,6 +209,7 @@ enum e1e_registers { + E1000_FACTPS = 0x05B30, /* Function Active and Power State to MNG */ + E1000_SWSM = 0x05B50, /* SW Semaphore */ + E1000_FWSM = 0x05B54, /* FW Semaphore */ ++ E1000_SWSM2 = 0x05B58, /* Driver-only SW semaphore */ + E1000_HICR = 0x08F00, /* Host Interface Control */ + }; + +@@ -856,6 +857,7 @@ struct e1000_fc_info { + struct e1000_dev_spec_82571 { + bool laa_is_present; + bool alt_mac_addr_is_present; ++ u32 smb_counter; + }; + + struct e1000_shadow_ram {