forked from luck/tmp_suning_uos_patched
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>
This commit is contained in:
parent
8459464f07
commit
23a2d1b233
|
@ -71,6 +71,7 @@ static s32 e1000_setup_link_82571(struct e1000_hw *hw);
|
|||
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.
|
||||
|
@ -212,6 +213,9 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter)
|
|||
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) {
|
||||
|
@ -276,6 +280,50 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter)
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -413,11 +461,37 @@ static s32 e1000_get_phy_id_82571(struct e1000_hw *hw)
|
|||
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);
|
||||
|
||||
|
@ -428,9 +502,9 @@ static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw)
|
|||
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;
|
||||
}
|
||||
|
@ -449,9 +523,7 @@ static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw)
|
|||
u32 swsm;
|
||||
|
||||
swsm = er32(SWSM);
|
||||
|
||||
swsm &= ~E1000_SWSM_SWESMBI;
|
||||
|
||||
swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
|
||||
ew32(SWSM, swsm);
|
||||
}
|
||||
|
||||
|
|
|
@ -376,6 +376,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 */
|
||||
|
|
|
@ -214,6 +214,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 */
|
||||
};
|
||||
|
||||
|
@ -883,6 +884,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 {
|
||||
|
|
Loading…
Reference in New Issue
Block a user