From 07a16dc3dd51b0c98763b19e98d973c059a0113e Mon Sep 17 00:00:00 2001 From: Matthew Vick Date: Fri, 22 Mar 2013 07:34:20 +0000 Subject: [PATCH] --- yaml --- r: 369727 b: refs/heads/master c: d44e7a9a1f1e56918f8e937dcf750626ac5ad9b4 h: refs/heads/master i: 369725: 73c35c217d312366bd3ca515228b9cad8a7d63d4 369723: 66ac99f3d9051945fc6c19de585471ff9616bebb 369719: 68bce2e258d203d7674afe770635bbdc2105321f 369711: 668f6b7514176c418adfc4a12c4181f3f6b34921 369695: 51611002a88dda3aa07751dd1c1f3796c04c6813 369663: d89d10728077823fa46afd52e56ac1bad1ee069e v: v3 --- [refs] | 2 +- .../net/ethernet/intel/igb/e1000_82575.c | 3 + .../drivers/net/ethernet/intel/igb/e1000_hw.h | 1 + .../net/ethernet/intel/igb/e1000_i210.c | 65 +++++++++++-------- 4 files changed, 44 insertions(+), 27 deletions(-) diff --git a/[refs] b/[refs] index 6aad90687045..4e8e91c21a73 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 0ba96d3d91882ae27083d8de8634ce0fae20dee6 +refs/heads/master: d44e7a9a1f1e56918f8e937dcf750626ac5ad9b4 diff --git a/trunk/drivers/net/ethernet/intel/igb/e1000_82575.c b/trunk/drivers/net/ethernet/intel/igb/e1000_82575.c index c9bba39d50bd..6cb0ca2869b9 100644 --- a/trunk/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/trunk/drivers/net/ethernet/intel/igb/e1000_82575.c @@ -389,6 +389,9 @@ static s32 igb_init_mac_params_82575(struct e1000_hw *hw) dev_spec->eee_disable = false; else dev_spec->eee_disable = true; + /* Allow a single clear of the SW semaphore on I210 and newer */ + if (mac->type >= e1000_i210) + dev_spec->clear_semaphore_once = true; /* physical interface link setup */ mac->ops.setup_physical_interface = (hw->phy.media_type == e1000_media_type_copper) diff --git a/trunk/drivers/net/ethernet/intel/igb/e1000_hw.h b/trunk/drivers/net/ethernet/intel/igb/e1000_hw.h index 1138ccaf95ff..f1dbab920286 100644 --- a/trunk/drivers/net/ethernet/intel/igb/e1000_hw.h +++ b/trunk/drivers/net/ethernet/intel/igb/e1000_hw.h @@ -529,6 +529,7 @@ struct e1000_dev_spec_82575 { bool sgmii_active; bool global_device_reset; bool eee_disable; + bool clear_semaphore_once; }; struct e1000_hw { diff --git a/trunk/drivers/net/ethernet/intel/igb/e1000_i210.c b/trunk/drivers/net/ethernet/intel/igb/e1000_i210.c index 9764cd3610e5..ddb3cf51b9b9 100644 --- a/trunk/drivers/net/ethernet/intel/igb/e1000_i210.c +++ b/trunk/drivers/net/ethernet/intel/igb/e1000_i210.c @@ -44,10 +44,42 @@ static s32 igb_get_hw_semaphore_i210(struct e1000_hw *hw) { u32 swsm; - s32 ret_val = E1000_SUCCESS; s32 timeout = hw->nvm.word_size + 1; s32 i = 0; + /* Get the SW semaphore */ + while (i < timeout) { + swsm = rd32(E1000_SWSM); + if (!(swsm & E1000_SWSM_SMBI)) + break; + + udelay(50); + i++; + } + + if (i == timeout) { + /* In rare circumstances, the SW semaphore may already be held + * unintentionally. Clear the semaphore once before giving up. + */ + if (hw->dev_spec._82575.clear_semaphore_once) { + hw->dev_spec._82575.clear_semaphore_once = false; + igb_put_hw_semaphore(hw); + for (i = 0; i < timeout; i++) { + swsm = rd32(E1000_SWSM); + if (!(swsm & E1000_SWSM_SMBI)) + break; + + udelay(50); + } + } + + /* If we do not have the semaphore here, we have to give up. */ + if (i == timeout) { + hw_dbg("Driver can't access device - SMBI bit is set.\n"); + return -E1000_ERR_NVM; + } + } + /* Get the FW semaphore. */ for (i = 0; i < timeout; i++) { swsm = rd32(E1000_SWSM); @@ -64,12 +96,10 @@ static s32 igb_get_hw_semaphore_i210(struct e1000_hw *hw) /* Release semaphores */ igb_put_hw_semaphore(hw); hw_dbg("Driver can't access the NVM\n"); - ret_val = -E1000_ERR_NVM; - goto out; + return -E1000_ERR_NVM; } -out: - return ret_val; + return E1000_SUCCESS; } /** @@ -98,23 +128,6 @@ void igb_release_nvm_i210(struct e1000_hw *hw) igb_release_swfw_sync_i210(hw, E1000_SWFW_EEP_SM); } -/** - * igb_put_hw_semaphore_i210 - Release hardware semaphore - * @hw: pointer to the HW structure - * - * Release hardware semaphore used to access the PHY or NVM - **/ -static void igb_put_hw_semaphore_i210(struct e1000_hw *hw) -{ - u32 swsm; - - swsm = rd32(E1000_SWSM); - - swsm &= ~E1000_SWSM_SWESMBI; - - wr32(E1000_SWSM, swsm); -} - /** * igb_acquire_swfw_sync_i210 - Acquire SW/FW semaphore * @hw: pointer to the HW structure @@ -138,11 +151,11 @@ s32 igb_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask) } swfw_sync = rd32(E1000_SW_FW_SYNC); - if (!(swfw_sync & fwmask)) + if (!(swfw_sync & (fwmask | swmask))) break; /* Firmware currently using resource (fwmask) */ - igb_put_hw_semaphore_i210(hw); + igb_put_hw_semaphore(hw); mdelay(5); i++; } @@ -156,7 +169,7 @@ s32 igb_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask) swfw_sync |= swmask; wr32(E1000_SW_FW_SYNC, swfw_sync); - igb_put_hw_semaphore_i210(hw); + igb_put_hw_semaphore(hw); out: return ret_val; } @@ -180,7 +193,7 @@ void igb_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask) swfw_sync &= ~mask; wr32(E1000_SW_FW_SYNC, swfw_sync); - igb_put_hw_semaphore_i210(hw); + igb_put_hw_semaphore(hw); } /**