Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[firefly-linux-kernel-4.4.55.git] / drivers / net / ethernet / intel / igb / e1000_i210.c
index 6a42344f24f1805ed6b3e2fe1c4afa98cb1534cf..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,13 +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);
+               /* Firmware currently using resource (fwmask) */
+               igb_put_hw_semaphore(hw);
                mdelay(5);
                i++;
        }
@@ -158,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;
 }
@@ -182,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);
 }
 
 /**
@@ -203,7 +214,8 @@ s32 igb_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset, u16 words,
 
        /* We cannot hold synchronization semaphores for too long,
         * because of forceful takeover procedure. However it is more efficient
-        * to read in bursts than synchronizing access for each word. */
+        * to read in bursts than synchronizing access for each word.
+        */
        for (i = 0; i < words; i += E1000_EERD_EEWR_MAX_COUNT) {
                count = (words - i) / E1000_EERD_EEWR_MAX_COUNT > 0 ?
                        E1000_EERD_EEWR_MAX_COUNT : (words - i);
@@ -242,8 +254,7 @@ static s32 igb_write_nvm_srwr(struct e1000_hw *hw, u16 offset, u16 words,
        u32 attempts = 100000;
        s32 ret_val = E1000_SUCCESS;
 
-       /*
-        * A check for invalid values:  offset too large, too many words,
+       /* A check for invalid values:  offset too large, too many words,
         * too many words for the offset, and not enough words.
         */
        if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
@@ -294,7 +305,7 @@ out:
  *
  *  If error code is returned, data and Shadow RAM may be inconsistent - buffer
  *  partially written.
- */
+ **/
 s32 igb_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset, u16 words,
                              u16 *data)
 {
@@ -326,7 +337,7 @@ s32 igb_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset, u16 words,
 /**
  *  igb_read_nvm_i211 - Read NVM wrapper function for I211
  *  @hw: pointer to the HW structure
- *  @address: the word address (aka eeprom offset) to read
+ *  @words: number of words to read
  *  @data: pointer to the data read
  *
  *  Wrapper function to return data formerly found in the NVM.
@@ -549,8 +560,7 @@ s32 igb_validate_nvm_checksum_i210(struct e1000_hw *hw)
 
        if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) {
 
-               /*
-                * Replace the read function with semaphore grabbing with
+               /* Replace the read function with semaphore grabbing with
                 * the one that skips this for a while.
                 * We have semaphore taken already here.
                 */
@@ -570,7 +580,6 @@ s32 igb_validate_nvm_checksum_i210(struct e1000_hw *hw)
        return status;
 }
 
-
 /**
  *  igb_update_nvm_checksum_i210 - Update EEPROM checksum
  *  @hw: pointer to the HW structure
@@ -585,8 +594,7 @@ s32 igb_update_nvm_checksum_i210(struct e1000_hw *hw)
        u16 checksum = 0;
        u16 i, nvm_data;
 
-       /*
-        * Read the first word from the EEPROM. If this times out or fails, do
+       /* Read the first word from the EEPROM. If this times out or fails, do
         * not continue or we could be in for a very long wait while every
         * EEPROM read fails
         */
@@ -597,8 +605,7 @@ s32 igb_update_nvm_checksum_i210(struct e1000_hw *hw)
        }
 
        if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) {
-               /*
-                * Do not use hw->nvm.ops.write, hw->nvm.ops.read
+               /* Do not use hw->nvm.ops.write, hw->nvm.ops.read
                 * because we do not want to take the synchronization
                 * semaphores twice here.
                 */
@@ -635,7 +642,7 @@ out:
  *  igb_pool_flash_update_done_i210 - Pool FLUDONE status.
  *  @hw: pointer to the HW structure
  *
- */
+ **/
 static s32 igb_pool_flash_update_done_i210(struct e1000_hw *hw)
 {
        s32 ret_val = -E1000_ERR_NVM;
@@ -714,3 +721,68 @@ s32 igb_valid_led_default_i210(struct e1000_hw *hw, u16 *data)
 out:
        return ret_val;
 }
+
+/**
+ *  __igb_access_xmdio_reg - Read/write XMDIO register
+ *  @hw: pointer to the HW structure
+ *  @address: XMDIO address to program
+ *  @dev_addr: device address to program
+ *  @data: pointer to value to read/write from/to the XMDIO address
+ *  @read: boolean flag to indicate read or write
+ **/
+static s32 __igb_access_xmdio_reg(struct e1000_hw *hw, u16 address,
+                                 u8 dev_addr, u16 *data, bool read)
+{
+       s32 ret_val = E1000_SUCCESS;
+
+       ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAC, dev_addr);
+       if (ret_val)
+               return ret_val;
+
+       ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAAD, address);
+       if (ret_val)
+               return ret_val;
+
+       ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAC, E1000_MMDAC_FUNC_DATA |
+                                                        dev_addr);
+       if (ret_val)
+               return ret_val;
+
+       if (read)
+               ret_val = hw->phy.ops.read_reg(hw, E1000_MMDAAD, data);
+       else
+               ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAAD, *data);
+       if (ret_val)
+               return ret_val;
+
+       /* Recalibrate the device back to 0 */
+       ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAC, 0);
+       if (ret_val)
+               return ret_val;
+
+       return ret_val;
+}
+
+/**
+ *  igb_read_xmdio_reg - Read XMDIO register
+ *  @hw: pointer to the HW structure
+ *  @addr: XMDIO address to program
+ *  @dev_addr: device address to program
+ *  @data: value to be read from the EMI address
+ **/
+s32 igb_read_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr, u16 *data)
+{
+       return __igb_access_xmdio_reg(hw, addr, dev_addr, data, true);
+}
+
+/**
+ *  igb_write_xmdio_reg - Write XMDIO register
+ *  @hw: pointer to the HW structure
+ *  @addr: XMDIO address to program
+ *  @dev_addr: device address to program
+ *  @data: value to be written to the XMDIO address
+ **/
+s32 igb_write_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr, u16 data)
+{
+       return __igb_access_xmdio_reg(hw, addr, dev_addr, &data, false);
+}