igb: Add SMBI semaphore to I210/I211
authorMatthew Vick <matthew.vick@intel.com>
Fri, 22 Mar 2013 07:34:20 +0000 (07:34 +0000)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Thu, 25 Apr 2013 01:05:19 +0000 (18:05 -0700)
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>
drivers/net/ethernet/intel/igb/e1000_82575.c
drivers/net/ethernet/intel/igb/e1000_hw.h
drivers/net/ethernet/intel/igb/e1000_i210.c

index c9bba39d50bd130cd581a801f7c2abfb33de73ef..6cb0ca2869b981fae5f818eeb0a4d7a20b82913e 100644 (file)
@@ -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)
index 1138ccaf95ff13ad3a78eb74c1a74f6dcccd010d..f1dbab9202862118004abf5f935594de612123a9 100644 (file)
@@ -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 {
index 9764cd3610e5490edd8c24c82c7d19f0b2b612f0..ddb3cf51b9b91825875fa2ecbb84e69fef09dff0 100644 (file)
 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);
 }
 
 /**