net/ixgbe/base: fix build error
[dpdk.git] / drivers / net / ixgbe / base / ixgbe_phy.c
index 5985deb..f44a11e 100644 (file)
@@ -100,19 +100,20 @@ STATIC u8 ixgbe_ones_comp_byte_add(u8 add1, u8 add2)
 }
 
 /**
- * ixgbe_read_i2c_combined_generic - Perform I2C read combined operation
+ * ixgbe_read_i2c_combined_generic_int - Perform I2C read combined operation
  * @hw: pointer to the hardware structure
  * @addr: I2C bus address to read from
  * @reg: I2C device register to read from
  * @val: pointer to location to receive read value
+ * @lock: true if to take and release semaphore
  *
  * Returns an error code on error.
  */
-STATIC s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr,
-                                          u16 reg, u16 *val)
+s32 ixgbe_read_i2c_combined_generic_int(struct ixgbe_hw *hw, u8 addr, u16 reg,
+                                       u16 *val, bool lock)
 {
        u32 swfw_mask = hw->phy.phy_semaphore_mask;
-       int max_retry = 10;
+       int max_retry = 3;
        int retry = 0;
        u8 csum_byte;
        u8 high_bits;
@@ -124,7 +125,7 @@ STATIC s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr,
        csum = ixgbe_ones_comp_byte_add(reg_high, reg & 0xFF);
        csum = ~csum;
        do {
-               if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
+               if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
                        return IXGBE_ERR_SWFW_SYNC;
                ixgbe_i2c_start(hw);
                /* Device Address and write indication */
@@ -157,13 +158,15 @@ STATIC s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr,
                if (ixgbe_clock_out_i2c_bit(hw, false))
                        goto fail;
                ixgbe_i2c_stop(hw);
-               hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+               if (lock)
+                       hw->mac.ops.release_swfw_sync(hw, swfw_mask);
                *val = (high_bits << 8) | low_bits;
                return 0;
 
 fail:
                ixgbe_i2c_bus_clear(hw);
-               hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+               if (lock)
+                       hw->mac.ops.release_swfw_sync(hw, swfw_mask);
                retry++;
                if (retry < max_retry)
                        DEBUGOUT("I2C byte read combined error - Retrying.\n");
@@ -175,17 +178,19 @@ fail:
 }
 
 /**
- * ixgbe_write_i2c_combined_generic - Perform I2C write combined operation
+ * ixgbe_write_i2c_combined_generic_int - Perform I2C write combined operation
  * @hw: pointer to the hardware structure
  * @addr: I2C bus address to write to
  * @reg: I2C device register to write to
  * @val: value to write
+ * @lock: true if to take and release semaphore
  *
  * Returns an error code on error.
  */
-STATIC s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw,
-                                           u8 addr, u16 reg, u16 val)
+s32 ixgbe_write_i2c_combined_generic_int(struct ixgbe_hw *hw, u8 addr, u16 reg,
+                                        u16 val, bool lock)
 {
+       u32 swfw_mask = hw->phy.phy_semaphore_mask;
        int max_retry = 1;
        int retry = 0;
        u8 reg_high;
@@ -197,6 +202,8 @@ STATIC s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw,
        csum = ixgbe_ones_comp_byte_add(csum, val & 0xFF);
        csum = ~csum;
        do {
+               if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
+                       return IXGBE_ERR_SWFW_SYNC;
                ixgbe_i2c_start(hw);
                /* Device Address and write indication */
                if (ixgbe_out_i2c_byte_ack(hw, addr))
@@ -217,10 +224,14 @@ STATIC s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw,
                if (ixgbe_out_i2c_byte_ack(hw, csum))
                        goto fail;
                ixgbe_i2c_stop(hw);
+               if (lock)
+                       hw->mac.ops.release_swfw_sync(hw, swfw_mask);
                return 0;
 
 fail:
                ixgbe_i2c_bus_clear(hw);
+               if (lock)
+                       hw->mac.ops.release_swfw_sync(hw, swfw_mask);
                retry++;
                if (retry < max_retry)
                        DEBUGOUT("I2C byte write combined error - Retrying.\n");
@@ -262,12 +273,49 @@ s32 ixgbe_init_phy_ops_generic(struct ixgbe_hw *hw)
        phy->ops.i2c_bus_clear = ixgbe_i2c_bus_clear;
        phy->ops.identify_sfp = ixgbe_identify_module_generic;
        phy->sfp_type = ixgbe_sfp_type_unknown;
-       phy->ops.read_i2c_combined = ixgbe_read_i2c_combined_generic;
-       phy->ops.write_i2c_combined = ixgbe_write_i2c_combined_generic;
+       phy->ops.read_i2c_byte_unlocked = ixgbe_read_i2c_byte_generic_unlocked;
+       phy->ops.write_i2c_byte_unlocked =
+                               ixgbe_write_i2c_byte_generic_unlocked;
        phy->ops.check_overtemp = ixgbe_tn_check_overtemp;
        return IXGBE_SUCCESS;
 }
 
+/**
+ * ixgbe_probe_phy - Probe a single address for a PHY
+ * @hw: pointer to hardware structure
+ * @phy_addr: PHY address to probe
+ *
+ * Returns true if PHY found
+ */
+static bool ixgbe_probe_phy(struct ixgbe_hw *hw, u16 phy_addr)
+{
+       u16 ext_ability = 0;
+
+       if (!ixgbe_validate_phy_addr(hw, phy_addr)) {
+               DEBUGOUT1("Unable to validate PHY address 0x%04X\n",
+                       phy_addr);
+               return false;
+       }
+
+       if (ixgbe_get_phy_id(hw))
+               return false;
+
+       hw->phy.type = ixgbe_get_phy_type_from_id(hw->phy.id);
+
+       if (hw->phy.type == ixgbe_phy_unknown) {
+               hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_EXT_ABILITY,
+                                    IXGBE_MDIO_PMA_PMD_DEV_TYPE, &ext_ability);
+               if (ext_ability &
+                   (IXGBE_MDIO_PHY_10GBASET_ABILITY |
+                    IXGBE_MDIO_PHY_1000BASET_ABILITY))
+                       hw->phy.type = ixgbe_phy_cu_unknown;
+               else
+                       hw->phy.type = ixgbe_phy_generic;
+       }
+
+       return true;
+}
+
 /**
  *  ixgbe_identify_phy_generic - Get physical layer module
  *  @hw: pointer to hardware structure
@@ -277,8 +325,7 @@ s32 ixgbe_init_phy_ops_generic(struct ixgbe_hw *hw)
 s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw)
 {
        s32 status = IXGBE_ERR_PHY_ADDR_INVALID;
-       u32 phy_addr;
-       u16 ext_ability = 0;
+       u16 phy_addr;
 
        DEBUGFUNC("ixgbe_identify_phy_generic");
 
@@ -289,45 +336,33 @@ s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw)
                        hw->phy.phy_semaphore_mask = IXGBE_GSSR_PHY0_SM;
        }
 
-       if (hw->phy.type == ixgbe_phy_unknown) {
-               for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) {
-                       if (ixgbe_validate_phy_addr(hw, phy_addr)) {
-                               hw->phy.addr = phy_addr;
-                               ixgbe_get_phy_id(hw);
-                               hw->phy.type =
-                                       ixgbe_get_phy_type_from_id(hw->phy.id);
-
-                               if (hw->phy.type == ixgbe_phy_unknown) {
-                                       hw->phy.ops.read_reg(hw,
-                                                 IXGBE_MDIO_PHY_EXT_ABILITY,
-                                                 IXGBE_MDIO_PMA_PMD_DEV_TYPE,
-                                                 &ext_ability);
-                                       if (ext_ability &
-                                           (IXGBE_MDIO_PHY_10GBASET_ABILITY |
-                                            IXGBE_MDIO_PHY_1000BASET_ABILITY))
-                                               hw->phy.type =
-                                                        ixgbe_phy_cu_unknown;
-                                       else
-                                               hw->phy.type =
-                                                        ixgbe_phy_generic;
-                               }
+       if (hw->phy.type != ixgbe_phy_unknown)
+               return IXGBE_SUCCESS;
 
-                               status = IXGBE_SUCCESS;
-                               break;
-                       }
-               }
+       if (hw->phy.nw_mng_if_sel) {
+               phy_addr = (hw->phy.nw_mng_if_sel &
+                           IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD) >>
+                          IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD_SHIFT;
+               if (ixgbe_probe_phy(hw, phy_addr))
+                       return IXGBE_SUCCESS;
+               else
+                       return IXGBE_ERR_PHY_ADDR_INVALID;
+       }
 
-               /* Certain media types do not have a phy so an address will not
-                * be found and the code will take this path.  Caller has to
-                * decide if it is an error or not.
-                */
-               if (status != IXGBE_SUCCESS) {
-                       hw->phy.addr = 0;
+       for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) {
+               if (ixgbe_probe_phy(hw, phy_addr)) {
+                       status = IXGBE_SUCCESS;
+                       break;
                }
-       } else {
-               status = IXGBE_SUCCESS;
        }
 
+       /* Certain media types do not have a phy so an address will not
+        * be found and the code will take this path.  Caller has to
+        * decide if it is an error or not.
+        */
+       if (status != IXGBE_SUCCESS)
+               hw->phy.addr = 0;
+
        return status;
 }
 
@@ -379,6 +414,8 @@ bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr)
        if (phy_id != 0xFFFF && phy_id != 0x0)
                valid = true;
 
+       DEBUGOUT1("PHY ID HIGH is 0x%04X\n", phy_id);
+
        return valid;
 }
 
@@ -407,12 +444,15 @@ s32 ixgbe_get_phy_id(struct ixgbe_hw *hw)
                hw->phy.id |= (u32)(phy_id_low & IXGBE_PHY_REVISION_MASK);
                hw->phy.revision = (u32)(phy_id_low & ~IXGBE_PHY_REVISION_MASK);
        }
+       DEBUGOUT2("PHY_ID_HIGH 0x%04X, PHY_ID_LOW 0x%04X\n",
+                 phy_id_high, phy_id_low);
+
        return status;
 }
 
 /**
  *  ixgbe_get_phy_type_from_id - Get the phy type
- *  @hw: pointer to hardware structure
+ *  @phy_id: PHY ID information
  *
  **/
 enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id)
@@ -425,7 +465,8 @@ enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id)
        case TN1010_PHY_ID:
                phy_type = ixgbe_phy_tn;
                break;
-       case X550_PHY_ID:
+       case X550_PHY_ID2:
+       case X550_PHY_ID3:
        case X540_PHY_ID:
                phy_type = ixgbe_phy_aq;
                break;
@@ -436,14 +477,17 @@ enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id)
                phy_type = ixgbe_phy_nl;
                break;
        case X557_PHY_ID:
+       case X557_PHY_ID2:
                phy_type = ixgbe_phy_x550em_ext_t;
                break;
+       case IXGBE_M88E1500_E_PHY_ID:
+       case IXGBE_M88E1543_E_PHY_ID:
+               phy_type = ixgbe_phy_ext_1g_t;
+               break;
        default:
                phy_type = ixgbe_phy_unknown;
                break;
        }
-
-       DEBUGOUT1("phy type found is %d\n", phy_type);
        return phy_type;
 }
 
@@ -489,11 +533,30 @@ s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw)
         */
        for (i = 0; i < 30; i++) {
                msec_delay(100);
-               hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
-                                    IXGBE_MDIO_PHY_XS_DEV_TYPE, &ctrl);
-               if (!(ctrl & IXGBE_MDIO_PHY_XS_RESET)) {
-                       usec_delay(2);
-                       break;
+               if (hw->phy.type == ixgbe_phy_x550em_ext_t) {
+                       status = hw->phy.ops.read_reg(hw,
+                                                 IXGBE_MDIO_TX_VENDOR_ALARMS_3,
+                                                 IXGBE_MDIO_PMA_PMD_DEV_TYPE,
+                                                 &ctrl);
+                       if (status != IXGBE_SUCCESS)
+                               return status;
+
+                       if (ctrl & IXGBE_MDIO_TX_VENDOR_ALARMS_3_RST_MASK) {
+                               usec_delay(2);
+                               break;
+                       }
+               } else {
+                       status = hw->phy.ops.read_reg(hw,
+                                                    IXGBE_MDIO_PHY_XS_CONTROL,
+                                                    IXGBE_MDIO_PHY_XS_DEV_TYPE,
+                                                    &ctrl);
+                       if (status != IXGBE_SUCCESS)
+                               return status;
+
+                       if (!(ctrl & IXGBE_MDIO_PHY_XS_RESET)) {
+                               usec_delay(2);
+                               break;
+                       }
                }
        }
 
@@ -515,7 +578,7 @@ out:
  *  @phy_data: Pointer to read data from PHY register
  **/
 s32 ixgbe_read_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type,
-                      u16 *phy_data)
+                          u16 *phy_data)
 {
        u32 i, data, command;
 
@@ -537,12 +600,13 @@ s32 ixgbe_read_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type,
 
                command = IXGBE_READ_REG(hw, IXGBE_MSCA);
                if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
-                               break;
+                       break;
        }
 
 
        if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
                ERROR_REPORT1(IXGBE_ERROR_POLLING, "PHY address command did not complete.\n");
+               DEBUGOUT("PHY address command did not complete, returning IXGBE_ERR_PHY\n");
                return IXGBE_ERR_PHY;
        }
 
@@ -572,6 +636,7 @@ s32 ixgbe_read_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type,
 
        if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
                ERROR_REPORT1(IXGBE_ERROR_POLLING, "PHY read command didn't complete\n");
+               DEBUGOUT("PHY read command didn't complete, returning IXGBE_ERR_PHY\n");
                return IXGBE_ERR_PHY;
        }
 
@@ -601,13 +666,12 @@ s32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
 
        DEBUGFUNC("ixgbe_read_phy_reg_generic");
 
-       if (hw->mac.ops.acquire_swfw_sync(hw, gssr) == IXGBE_SUCCESS) {
-               status = ixgbe_read_phy_reg_mdi(hw, reg_addr, device_type,
-                                               phy_data);
-               hw->mac.ops.release_swfw_sync(hw, gssr);
-       } else {
-               status = IXGBE_ERR_SWFW_SYNC;
-       }
+       if (hw->mac.ops.acquire_swfw_sync(hw, gssr))
+               return IXGBE_ERR_SWFW_SYNC;
+
+       status = hw->phy.ops.read_reg_mdi(hw, reg_addr, device_type, phy_data);
+
+       hw->mac.ops.release_swfw_sync(hw, gssr);
 
        return status;
 }
@@ -703,7 +767,7 @@ s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
        DEBUGFUNC("ixgbe_write_phy_reg_generic");
 
        if (hw->mac.ops.acquire_swfw_sync(hw, gssr) == IXGBE_SUCCESS) {
-               status = ixgbe_write_phy_reg_mdi(hw, reg_addr, device_type,
+               status = hw->phy.ops.write_reg_mdi(hw, reg_addr, device_type,
                                                 phy_data);
                hw->mac.ops.release_swfw_sync(hw, gssr);
        } else {
@@ -730,91 +794,63 @@ s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw)
 
        ixgbe_get_copper_link_capabilities_generic(hw, &speed, &autoneg);
 
-       if (speed & IXGBE_LINK_SPEED_10GB_FULL) {
-               /* Set or unset auto-negotiation 10G advertisement */
-               hw->phy.ops.read_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG,
-                                    IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
-                                    &autoneg_reg);
+       /* Set or unset auto-negotiation 10G advertisement */
+       hw->phy.ops.read_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG,
+                            IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+                            &autoneg_reg);
 
-               autoneg_reg &= ~IXGBE_MII_10GBASE_T_ADVERTISE;
-               if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL)
-                       autoneg_reg |= IXGBE_MII_10GBASE_T_ADVERTISE;
+       autoneg_reg &= ~IXGBE_MII_10GBASE_T_ADVERTISE;
+       if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) &&
+           (speed & IXGBE_LINK_SPEED_10GB_FULL))
+               autoneg_reg |= IXGBE_MII_10GBASE_T_ADVERTISE;
 
-               hw->phy.ops.write_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG,
-                                     IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
-                                     autoneg_reg);
-       }
+       hw->phy.ops.write_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG,
+                             IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+                             autoneg_reg);
 
-       if (hw->mac.type == ixgbe_mac_X550) {
-               if (speed & IXGBE_LINK_SPEED_5GB_FULL) {
-                       /* Set or unset auto-negotiation 1G advertisement */
-                       hw->phy.ops.read_reg(hw,
-                               IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG,
-                               IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
-                               &autoneg_reg);
-
-                       autoneg_reg &= ~IXGBE_MII_5GBASE_T_ADVERTISE;
-                       if (hw->phy.autoneg_advertised &
-                            IXGBE_LINK_SPEED_5GB_FULL)
-                               autoneg_reg |= IXGBE_MII_5GBASE_T_ADVERTISE;
-
-                       hw->phy.ops.write_reg(hw,
-                               IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG,
-                               IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
-                               autoneg_reg);
-               }
+       hw->phy.ops.read_reg(hw, IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG,
+                            IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+                            &autoneg_reg);
 
-               if (speed & IXGBE_LINK_SPEED_2_5GB_FULL) {
-                       /* Set or unset auto-negotiation 1G advertisement */
-                       hw->phy.ops.read_reg(hw,
-                               IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG,
-                               IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
-                               &autoneg_reg);
-
-                       autoneg_reg &= ~IXGBE_MII_2_5GBASE_T_ADVERTISE;
-                       if (hw->phy.autoneg_advertised &
-                           IXGBE_LINK_SPEED_2_5GB_FULL)
-                               autoneg_reg |= IXGBE_MII_2_5GBASE_T_ADVERTISE;
-
-                       hw->phy.ops.write_reg(hw,
-                               IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG,
-                               IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
-                               autoneg_reg);
-               }
+       if (hw->mac.type == ixgbe_mac_X550) {
+               /* Set or unset auto-negotiation 5G advertisement */
+               autoneg_reg &= ~IXGBE_MII_5GBASE_T_ADVERTISE;
+               if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_5GB_FULL) &&
+                   (speed & IXGBE_LINK_SPEED_5GB_FULL))
+                       autoneg_reg |= IXGBE_MII_5GBASE_T_ADVERTISE;
+
+               /* Set or unset auto-negotiation 2.5G advertisement */
+               autoneg_reg &= ~IXGBE_MII_2_5GBASE_T_ADVERTISE;
+               if ((hw->phy.autoneg_advertised &
+                    IXGBE_LINK_SPEED_2_5GB_FULL) &&
+                   (speed & IXGBE_LINK_SPEED_2_5GB_FULL))
+                       autoneg_reg |= IXGBE_MII_2_5GBASE_T_ADVERTISE;
        }
 
-       if (speed & IXGBE_LINK_SPEED_1GB_FULL) {
-               /* Set or unset auto-negotiation 1G advertisement */
-               hw->phy.ops.read_reg(hw,
-                                    IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG,
-                                    IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
-                                    &autoneg_reg);
+       /* Set or unset auto-negotiation 1G advertisement */
+       autoneg_reg &= ~IXGBE_MII_1GBASE_T_ADVERTISE;
+       if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) &&
+           (speed & IXGBE_LINK_SPEED_1GB_FULL))
+               autoneg_reg |= IXGBE_MII_1GBASE_T_ADVERTISE;
 
-               autoneg_reg &= ~IXGBE_MII_1GBASE_T_ADVERTISE;
-               if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL)
-                       autoneg_reg |= IXGBE_MII_1GBASE_T_ADVERTISE;
+       hw->phy.ops.write_reg(hw, IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG,
+                             IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+                             autoneg_reg);
 
-               hw->phy.ops.write_reg(hw,
-                                     IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG,
-                                     IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
-                                     autoneg_reg);
-       }
+       /* Set or unset auto-negotiation 100M advertisement */
+       hw->phy.ops.read_reg(hw, IXGBE_MII_AUTONEG_ADVERTISE_REG,
+                            IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+                            &autoneg_reg);
 
-       if (speed & IXGBE_LINK_SPEED_100_FULL) {
-               /* Set or unset auto-negotiation 100M advertisement */
-               hw->phy.ops.read_reg(hw, IXGBE_MII_AUTONEG_ADVERTISE_REG,
-                                    IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
-                                    &autoneg_reg);
+       autoneg_reg &= ~(IXGBE_MII_100BASE_T_ADVERTISE |
+                        IXGBE_MII_100BASE_T_ADVERTISE_HALF);
+       if ((hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL) &&
+           (speed & IXGBE_LINK_SPEED_100_FULL))
+               autoneg_reg |= IXGBE_MII_100BASE_T_ADVERTISE;
 
-               autoneg_reg &= ~(IXGBE_MII_100BASE_T_ADVERTISE |
-                                IXGBE_MII_100BASE_T_ADVERTISE_HALF);
-               if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL)
-                       autoneg_reg |= IXGBE_MII_100BASE_T_ADVERTISE;
-
-               hw->phy.ops.write_reg(hw, IXGBE_MII_AUTONEG_ADVERTISE_REG,
-                                     IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
-                                     autoneg_reg);
-       }
+       hw->phy.ops.write_reg(hw, IXGBE_MII_AUTONEG_ADVERTISE_REG,
+                             IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+                             autoneg_reg);
 
        /* Blocked by MNG FW so don't reset PHY */
        if (ixgbe_check_reset_blocked(hw))
@@ -866,55 +902,75 @@ s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw,
        if (speed & IXGBE_LINK_SPEED_100_FULL)
                hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_100_FULL;
 
+       if (speed & IXGBE_LINK_SPEED_10_FULL)
+               hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10_FULL;
+
        /* Setup link based on the new speed settings */
-       hw->phy.ops.setup_link(hw);
+       ixgbe_setup_phy_link(hw);
 
        return IXGBE_SUCCESS;
 }
 
 /**
- *  ixgbe_get_copper_link_capabilities_generic - Determines link capabilities
- *  @hw: pointer to hardware structure
- *  @speed: pointer to link speed
- *  @autoneg: boolean auto-negotiation value
+ * ixgbe_get_copper_speeds_supported - Get copper link speeds from phy
+ * @hw: pointer to hardware structure
  *
- *  Determines the supported link capabilities by reading the PHY auto
- *  negotiation register.
+ * Determines the supported link capabilities by reading the PHY auto
+ * negotiation register.
  **/
-s32 ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw,
-                                              ixgbe_link_speed *speed,
-                                              bool *autoneg)
+static s32 ixgbe_get_copper_speeds_supported(struct ixgbe_hw *hw)
 {
        s32 status;
        u16 speed_ability;
 
-       DEBUGFUNC("ixgbe_get_copper_link_capabilities_generic");
-
-       *speed = 0;
-       *autoneg = true;
-
        status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_SPEED_ABILITY,
                                      IXGBE_MDIO_PMA_PMD_DEV_TYPE,
                                      &speed_ability);
+       if (status)
+               return status;
 
-       if (status == IXGBE_SUCCESS) {
-               if (speed_ability & IXGBE_MDIO_PHY_SPEED_10G)
-                       *speed |= IXGBE_LINK_SPEED_10GB_FULL;
-               if (speed_ability & IXGBE_MDIO_PHY_SPEED_1G)
-                       *speed |= IXGBE_LINK_SPEED_1GB_FULL;
-               if (speed_ability & IXGBE_MDIO_PHY_SPEED_100M)
-                       *speed |= IXGBE_LINK_SPEED_100_FULL;
+       if (speed_ability & IXGBE_MDIO_PHY_SPEED_10G)
+               hw->phy.speeds_supported |= IXGBE_LINK_SPEED_10GB_FULL;
+       if (speed_ability & IXGBE_MDIO_PHY_SPEED_1G)
+               hw->phy.speeds_supported |= IXGBE_LINK_SPEED_1GB_FULL;
+       if (speed_ability & IXGBE_MDIO_PHY_SPEED_100M)
+               hw->phy.speeds_supported |= IXGBE_LINK_SPEED_100_FULL;
+
+       switch (hw->mac.type) {
+       case ixgbe_mac_X550:
+               hw->phy.speeds_supported |= IXGBE_LINK_SPEED_2_5GB_FULL;
+               hw->phy.speeds_supported |= IXGBE_LINK_SPEED_5GB_FULL;
+               break;
+       case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_X550EM_a:
+               hw->phy.speeds_supported &= ~IXGBE_LINK_SPEED_100_FULL;
+               break;
+       default:
+               break;
        }
 
-       /* Internal PHY does not support 100 Mbps */
-       if (hw->mac.type == ixgbe_mac_X550EM_x)
-               *speed &= ~IXGBE_LINK_SPEED_100_FULL;
+       return status;
+}
 
-       if (hw->mac.type == ixgbe_mac_X550) {
-               *speed |= IXGBE_LINK_SPEED_2_5GB_FULL;
-               *speed |= IXGBE_LINK_SPEED_5GB_FULL;
-       }
+/**
+ *  ixgbe_get_copper_link_capabilities_generic - Determines link capabilities
+ *  @hw: pointer to hardware structure
+ *  @speed: pointer to link speed
+ *  @autoneg: boolean auto-negotiation value
+ **/
+s32 ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw,
+                                              ixgbe_link_speed *speed,
+                                              bool *autoneg)
+{
+       s32 status = IXGBE_SUCCESS;
+
+       DEBUGFUNC("ixgbe_get_copper_link_capabilities_generic");
+
+       *autoneg = true;
+       if (!hw->phy.speeds_supported)
+               status = ixgbe_get_copper_speeds_supported(hw);
 
+       *speed = hw->phy.speeds_supported;
        return status;
 }
 
@@ -1484,16 +1540,10 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
                                status = IXGBE_SUCCESS;
                        } else {
                                if (hw->allow_unsupported_sfp == true) {
-                                       EWARN(hw, "WARNING: Intel (R) Network "
-                                             "Connections are quality tested "
-                                             "using Intel (R) Ethernet Optics."
-                                             " Using untested modules is not "
-                                             "supported and may cause unstable"
-                                             " operation or damage to the "
-                                             "module or the adapter. Intel "
-                                             "Corporation is not responsible "
-                                             "for any harm caused by using "
-                                             "untested modules.\n", status);
+                                       EWARN(hw,
+                                               "WARNING: Intel (R) Network Connections are quality tested using Intel (R) Ethernet Optics. "
+                                               "Using untested modules is not supported and may cause unstable operation or damage to the module or the adapter. "
+                                               "Intel Corporation is not responsible for any harm caused by using untested modules.\n");
                                        status = IXGBE_SUCCESS;
                                } else {
                                        DEBUGOUT("SFP+ module not supported\n");
@@ -1610,6 +1660,9 @@ s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw)
                goto out;
        }
 
+       /* LAN ID is needed for I2C access */
+       hw->mac.ops.set_lan_id(hw);
+
        status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER,
                                             &identifier);
 
@@ -1624,9 +1677,6 @@ s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw)
 
        hw->phy.id = identifier;
 
-       /* LAN ID is needed for sfp_type determination */
-       hw->mac.ops.set_lan_id(hw);
-
        status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_QSFP_10GBE_COMP,
                                             &comp_codes_10g);
 
@@ -1746,16 +1796,10 @@ s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw)
                                status = IXGBE_SUCCESS;
                        } else {
                                if (hw->allow_unsupported_sfp == true) {
-                                       EWARN(hw, "WARNING: Intel (R) Network "
-                                             "Connections are quality tested "
-                                             "using Intel (R) Ethernet Optics."
-                                             " Using untested modules is not "
-                                             "supported and may cause unstable"
-                                             " operation or damage to the "
-                                             "module or the adapter. Intel "
-                                             "Corporation is not responsible "
-                                             "for any harm caused by using "
-                                             "untested modules.\n", status);
+                                       EWARN(hw,
+                                               "WARNING: Intel (R) Network Connections are quality tested using Intel (R) Ethernet Optics. "
+                                               "Using untested modules is not supported and may cause unstable operation or damage to the module or the adapter. "
+                                               "Intel Corporation is not responsible for any harm caused by using untested modules.\n");
                                        status = IXGBE_SUCCESS;
                                } else {
                                        DEBUGOUT("QSFP module not supported\n");
@@ -1780,7 +1824,6 @@ err_read_i2c_eeprom:
        return IXGBE_ERR_SFP_NOT_PRESENT;
 }
 
-
 /**
  *  ixgbe_get_sfp_init_sequence_offsets - Provides offset of PHY init sequence
  *  @hw: pointer to hardware structure
@@ -1944,16 +1987,17 @@ STATIC bool ixgbe_is_sfp_probe(struct ixgbe_hw *hw, u8 offset, u8 addr)
 }
 
 /**
- *  ixgbe_read_i2c_byte_generic - Reads 8 bit word over I2C
+ *  ixgbe_read_i2c_byte_generic_int - Reads 8 bit word over I2C
  *  @hw: pointer to hardware structure
  *  @byte_offset: byte offset to read
  *  @data: value read
+ *  @lock: true if to take and release semaphore
  *
  *  Performs byte read operation to SFP module's EEPROM over I2C interface at
  *  a specified device address.
  **/
-s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
-                               u8 dev_addr, u8 *data)
+STATIC s32 ixgbe_read_i2c_byte_generic_int(struct ixgbe_hw *hw, u8 byte_offset,
+                                          u8 dev_addr, u8 *data, bool lock)
 {
        s32 status;
        u32 max_retry = 10;
@@ -1964,11 +2008,13 @@ s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
 
        DEBUGFUNC("ixgbe_read_i2c_byte_generic");
 
+       if (hw->mac.type >= ixgbe_mac_X550)
+               max_retry = 3;
        if (ixgbe_is_sfp_probe(hw, byte_offset, dev_addr))
                max_retry = IXGBE_SFP_DETECT_RETRIES;
 
        do {
-               if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
+               if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
                        return IXGBE_ERR_SWFW_SYNC;
 
                ixgbe_i2c_start(hw);
@@ -2010,13 +2056,16 @@ s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
                        goto fail;
 
                ixgbe_i2c_stop(hw);
-               hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+               if (lock)
+                       hw->mac.ops.release_swfw_sync(hw, swfw_mask);
                return IXGBE_SUCCESS;
 
 fail:
                ixgbe_i2c_bus_clear(hw);
-               hw->mac.ops.release_swfw_sync(hw, swfw_mask);
-               msec_delay(100);
+               if (lock) {
+                       hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+                       msec_delay(100);
+               }
                retry++;
                if (retry < max_retry)
                        DEBUGOUT("I2C byte read error - Retrying.\n");
@@ -2029,28 +2078,60 @@ fail:
 }
 
 /**
- *  ixgbe_write_i2c_byte_generic - Writes 8 bit word over I2C
+ *  ixgbe_read_i2c_byte_generic - Reads 8 bit word over I2C
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: byte offset to read
+ *  @data: value read
+ *
+ *  Performs byte read operation to SFP module's EEPROM over I2C interface at
+ *  a specified device address.
+ **/
+s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
+                               u8 dev_addr, u8 *data)
+{
+       return ixgbe_read_i2c_byte_generic_int(hw, byte_offset, dev_addr,
+                                              data, true);
+}
+
+/**
+ *  ixgbe_read_i2c_byte_generic_unlocked - Reads 8 bit word over I2C
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: byte offset to read
+ *  @data: value read
+ *
+ *  Performs byte read operation to SFP module's EEPROM over I2C interface at
+ *  a specified device address.
+ **/
+s32 ixgbe_read_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset,
+                                        u8 dev_addr, u8 *data)
+{
+       return ixgbe_read_i2c_byte_generic_int(hw, byte_offset, dev_addr,
+                                              data, false);
+}
+
+/**
+ *  ixgbe_write_i2c_byte_generic_int - Writes 8 bit word over I2C
  *  @hw: pointer to hardware structure
  *  @byte_offset: byte offset to write
  *  @data: value to write
+ *  @lock: true if to take and release semaphore
  *
  *  Performs byte write operation to SFP module's EEPROM over I2C interface at
  *  a specified device address.
  **/
-s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
-                                u8 dev_addr, u8 data)
+STATIC s32 ixgbe_write_i2c_byte_generic_int(struct ixgbe_hw *hw, u8 byte_offset,
+                                           u8 dev_addr, u8 data, bool lock)
 {
-       s32 status = IXGBE_SUCCESS;
+       s32 status;
        u32 max_retry = 1;
        u32 retry = 0;
        u32 swfw_mask = hw->phy.phy_semaphore_mask;
 
        DEBUGFUNC("ixgbe_write_i2c_byte_generic");
 
-       if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask) != IXGBE_SUCCESS) {
-               status = IXGBE_ERR_SWFW_SYNC;
-               goto write_byte_out;
-       }
+       if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask) !=
+           IXGBE_SUCCESS)
+               return IXGBE_ERR_SWFW_SYNC;
 
        do {
                ixgbe_i2c_start(hw);
@@ -2080,7 +2161,8 @@ s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
                        goto fail;
 
                ixgbe_i2c_stop(hw);
-               hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+               if (lock)
+                       hw->mac.ops.release_swfw_sync(hw, swfw_mask);
                return IXGBE_SUCCESS;
 
 fail:
@@ -2092,12 +2174,44 @@ fail:
                        DEBUGOUT("I2C byte write error.\n");
        } while (retry < max_retry);
 
-       hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+       if (lock)
+               hw->mac.ops.release_swfw_sync(hw, swfw_mask);
 
-write_byte_out:
        return status;
 }
 
+/**
+ *  ixgbe_write_i2c_byte_generic - Writes 8 bit word over I2C
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: byte offset to write
+ *  @data: value to write
+ *
+ *  Performs byte write operation to SFP module's EEPROM over I2C interface at
+ *  a specified device address.
+ **/
+s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
+                                u8 dev_addr, u8 data)
+{
+       return ixgbe_write_i2c_byte_generic_int(hw, byte_offset, dev_addr,
+                                               data, true);
+}
+
+/**
+ *  ixgbe_write_i2c_byte_generic_unlocked - Writes 8 bit word over I2C
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: byte offset to write
+ *  @data: value to write
+ *
+ *  Performs byte write operation to SFP module's EEPROM over I2C interface at
+ *  a specified device address.
+ **/
+s32 ixgbe_write_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset,
+                                         u8 dev_addr, u8 data)
+{
+       return ixgbe_write_i2c_byte_generic_int(hw, byte_offset, dev_addr,
+                                               data, false);
+}
+
 /**
  *  ixgbe_i2c_start - Sets I2C start condition
  *  @hw: pointer to hardware structure
@@ -2562,6 +2676,9 @@ s32 ixgbe_set_copper_phy_power(struct ixgbe_hw *hw, bool on)
        u32 status;
        u16 reg;
 
+       if (!on && ixgbe_mng_present(hw))
+               return 0;
+
        status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_VENDOR_SPECIFIC_1_CONTROL,
                                      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
                                      &reg);