summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Vick <matthew.vick@intel.com>2013-03-22 07:34:20 +0000
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>2013-04-24 18:05:19 -0700
commitd44e7a9a1f1e56918f8e937dcf750626ac5ad9b4 (patch)
tree889ddc1e236a4e3af2eabdefdfa824e2eccae27f
parent0ba96d3d91882ae27083d8de8634ce0fae20dee6 (diff)
igb: Add SMBI semaphore to I210/I211
It was previously thought that, since I210/I211 are single port devices, they did not need the SMBI semaphore. This is not the case. Add support for the SMBI semaphore. Signed-off-by: Matthew Vick <matthew.vick@intel.com> Tested-by: Aaron Brown <aaron.f.brown@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_82575.c3
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_hw.h1
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_i210.c65
3 files changed, 43 insertions, 26 deletions
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c
index c9bba39d50bd..6cb0ca2869b9 100644
--- a/drivers/net/ethernet/intel/igb/e1000_82575.c
+++ b/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/drivers/net/ethernet/intel/igb/e1000_hw.h b/drivers/net/ethernet/intel/igb/e1000_hw.h
index 1138ccaf95ff..f1dbab920286 100644
--- a/drivers/net/ethernet/intel/igb/e1000_hw.h
+++ b/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/drivers/net/ethernet/intel/igb/e1000_i210.c b/drivers/net/ethernet/intel/igb/e1000_i210.c
index 9764cd3610e5..ddb3cf51b9b9 100644
--- a/drivers/net/ethernet/intel/igb/e1000_i210.c
+++ b/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;
}
/**
@@ -99,23 +129,6 @@ void igb_release_nvm_i210(struct e1000_hw *hw)
}
/**
- * 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
* @mask: specifies which semaphore to acquire
@@ -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);
}
/**