Commit d44e7a9a authored by Matthew Vick's avatar Matthew Vick Committed by Jeff Kirsher

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: default avatarMatthew Vick <matthew.vick@intel.com>
Tested-by: default avatarAaron Brown <aaron.f.brown@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 0ba96d3d
...@@ -389,6 +389,9 @@ static s32 igb_init_mac_params_82575(struct e1000_hw *hw) ...@@ -389,6 +389,9 @@ static s32 igb_init_mac_params_82575(struct e1000_hw *hw)
dev_spec->eee_disable = false; dev_spec->eee_disable = false;
else else
dev_spec->eee_disable = true; 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 */ /* physical interface link setup */
mac->ops.setup_physical_interface = mac->ops.setup_physical_interface =
(hw->phy.media_type == e1000_media_type_copper) (hw->phy.media_type == e1000_media_type_copper)
......
...@@ -529,6 +529,7 @@ struct e1000_dev_spec_82575 { ...@@ -529,6 +529,7 @@ struct e1000_dev_spec_82575 {
bool sgmii_active; bool sgmii_active;
bool global_device_reset; bool global_device_reset;
bool eee_disable; bool eee_disable;
bool clear_semaphore_once;
}; };
struct e1000_hw { struct e1000_hw {
......
...@@ -44,10 +44,42 @@ ...@@ -44,10 +44,42 @@
static s32 igb_get_hw_semaphore_i210(struct e1000_hw *hw) static s32 igb_get_hw_semaphore_i210(struct e1000_hw *hw)
{ {
u32 swsm; u32 swsm;
s32 ret_val = E1000_SUCCESS;
s32 timeout = hw->nvm.word_size + 1; s32 timeout = hw->nvm.word_size + 1;
s32 i = 0; 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. */ /* Get the FW semaphore. */
for (i = 0; i < timeout; i++) { for (i = 0; i < timeout; i++) {
swsm = rd32(E1000_SWSM); swsm = rd32(E1000_SWSM);
...@@ -64,12 +96,10 @@ static s32 igb_get_hw_semaphore_i210(struct e1000_hw *hw) ...@@ -64,12 +96,10 @@ static s32 igb_get_hw_semaphore_i210(struct e1000_hw *hw)
/* Release semaphores */ /* Release semaphores */
igb_put_hw_semaphore(hw); igb_put_hw_semaphore(hw);
hw_dbg("Driver can't access the NVM\n"); hw_dbg("Driver can't access the NVM\n");
ret_val = -E1000_ERR_NVM; return -E1000_ERR_NVM;
goto out;
} }
out: return E1000_SUCCESS;
return ret_val;
} }
/** /**
...@@ -98,23 +128,6 @@ void igb_release_nvm_i210(struct e1000_hw *hw) ...@@ -98,23 +128,6 @@ void igb_release_nvm_i210(struct e1000_hw *hw)
igb_release_swfw_sync_i210(hw, E1000_SWFW_EEP_SM); 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 * igb_acquire_swfw_sync_i210 - Acquire SW/FW semaphore
* @hw: pointer to the HW structure * @hw: pointer to the HW structure
...@@ -138,11 +151,11 @@ s32 igb_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask) ...@@ -138,11 +151,11 @@ s32 igb_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask)
} }
swfw_sync = rd32(E1000_SW_FW_SYNC); swfw_sync = rd32(E1000_SW_FW_SYNC);
if (!(swfw_sync & fwmask)) if (!(swfw_sync & (fwmask | swmask)))
break; break;
/* Firmware currently using resource (fwmask) */ /* Firmware currently using resource (fwmask) */
igb_put_hw_semaphore_i210(hw); igb_put_hw_semaphore(hw);
mdelay(5); mdelay(5);
i++; i++;
} }
...@@ -156,7 +169,7 @@ s32 igb_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask) ...@@ -156,7 +169,7 @@ s32 igb_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask)
swfw_sync |= swmask; swfw_sync |= swmask;
wr32(E1000_SW_FW_SYNC, swfw_sync); wr32(E1000_SW_FW_SYNC, swfw_sync);
igb_put_hw_semaphore_i210(hw); igb_put_hw_semaphore(hw);
out: out:
return ret_val; return ret_val;
} }
...@@ -180,7 +193,7 @@ void igb_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask) ...@@ -180,7 +193,7 @@ void igb_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask)
swfw_sync &= ~mask; swfw_sync &= ~mask;
wr32(E1000_SW_FW_SYNC, swfw_sync); wr32(E1000_SW_FW_SYNC, swfw_sync);
igb_put_hw_semaphore_i210(hw); igb_put_hw_semaphore(hw);
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment