return status;
 }
 
-/** ixgbe_init_mac_link_ops_X550em - init mac link function pointers
- *  @hw: pointer to hardware structure
- **/
-static void ixgbe_init_mac_link_ops_X550em(struct ixgbe_hw *hw)
-{
-       struct ixgbe_mac_info *mac = &hw->mac;
-
-       /* CS4227 does not support autoneg, so disable the laser control
-        * functions for SFP+ fiber
-        */
-       if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP) {
-               mac->ops.disable_tx_laser = NULL;
-               mac->ops.enable_tx_laser = NULL;
-               mac->ops.flap_tx_laser = NULL;
-       }
-}
-
-/** ixgbe_setup_sfp_modules_X550em - Setup SFP module
- * @hw: pointer to hardware structure
- */
-static s32 ixgbe_setup_sfp_modules_X550em(struct ixgbe_hw *hw)
-{
-       bool setup_linear;
-       u16 reg_slice, edc_mode;
-       s32 ret_val;
-
-       switch (hw->phy.sfp_type) {
-       case ixgbe_sfp_type_unknown:
-               return 0;
-       case ixgbe_sfp_type_not_present:
-               return IXGBE_ERR_SFP_NOT_PRESENT;
-       case ixgbe_sfp_type_da_cu_core0:
-       case ixgbe_sfp_type_da_cu_core1:
-               setup_linear = true;
-               break;
-       case ixgbe_sfp_type_srlr_core0:
-       case ixgbe_sfp_type_srlr_core1:
-       case ixgbe_sfp_type_da_act_lmt_core0:
-       case ixgbe_sfp_type_da_act_lmt_core1:
-       case ixgbe_sfp_type_1g_sx_core0:
-       case ixgbe_sfp_type_1g_sx_core1:
-               setup_linear = false;
-               break;
-       default:
-               return IXGBE_ERR_SFP_NOT_SUPPORTED;
-       }
-
-       ixgbe_init_mac_link_ops_X550em(hw);
-       hw->phy.ops.reset = NULL;
-
-       /* The CS4227 slice address is the base address + the port-pair reg
-        * offset. I.e. Slice 0 = 0x12B0 and slice 1 = 0x22B0.
-        */
-       reg_slice = IXGBE_CS4227_SPARE24_LSB + (hw->bus.lan_id << 12);
-
-       if (setup_linear)
-               edc_mode = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1;
-       else
-               edc_mode = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1;
-
-       /* Configure CS4227 for connection type. */
-       ret_val = hw->phy.ops.write_i2c_combined(hw, IXGBE_CS4227, reg_slice,
-                                                edc_mode);
-
-       if (ret_val)
-               ret_val = hw->phy.ops.write_i2c_combined(hw, 0x80, reg_slice,
-                                                        edc_mode);
-
-       return ret_val;
-}
-
-/** ixgbe_get_link_capabilities_x550em - Determines link capabilities
- * @hw: pointer to hardware structure
- * @speed: pointer to link speed
- * @autoneg: true when autoneg or autotry is enabled
- **/
-static s32 ixgbe_get_link_capabilities_X550em(struct ixgbe_hw *hw,
-                                             ixgbe_link_speed *speed,
-                                             bool *autoneg)
-{
-       /* SFP */
-       if (hw->phy.media_type == ixgbe_media_type_fiber) {
-               /* CS4227 SFP must not enable auto-negotiation */
-               *autoneg = false;
-
-               if (hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
-                   hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1) {
-                       *speed = IXGBE_LINK_SPEED_1GB_FULL;
-                       return 0;
-               }
-
-               /* Link capabilities are based on SFP */
-               if (hw->phy.multispeed_fiber)
-                       *speed = IXGBE_LINK_SPEED_10GB_FULL |
-                                IXGBE_LINK_SPEED_1GB_FULL;
-               else
-                       *speed = IXGBE_LINK_SPEED_10GB_FULL;
-       } else {
-               *speed = IXGBE_LINK_SPEED_10GB_FULL |
-                        IXGBE_LINK_SPEED_1GB_FULL;
-               *autoneg = true;
-       }
-       return 0;
-}
-
 /** ixgbe_write_iosf_sb_reg_x550 - Writes a value to specified register of the
  *  IOSF device
  *
        return status;
 }
 
+/**
+ * ixgbe_setup_mac_link_t_X550em - Sets the auto advertised link speed
+ * @hw: pointer to hardware structure
+ * @speed: new link speed
+ * @autoneg_wait_to_complete: true when waiting for completion is needed
+ *
+ * Setup internal/external PHY link speed based on link speed, then set
+ * external PHY auto advertised link speed.
+ *
+ * Returns error status for any failure
+ **/
+static s32 ixgbe_setup_mac_link_t_X550em(struct ixgbe_hw *hw,
+                                        ixgbe_link_speed speed,
+                                        bool autoneg_wait)
+{
+       s32 status;
+       ixgbe_link_speed force_speed;
+
+       /* Setup internal/external PHY link speed to iXFI (10G), unless
+        * only 1G is auto advertised then setup KX link.
+        */
+       if (speed & IXGBE_LINK_SPEED_10GB_FULL)
+               force_speed = IXGBE_LINK_SPEED_10GB_FULL;
+       else
+               force_speed = IXGBE_LINK_SPEED_1GB_FULL;
+
+       /* If internal link mode is XFI, then setup XFI internal link. */
+       if (!(hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE)) {
+               status = ixgbe_setup_ixfi_x550em(hw, &force_speed);
+
+               if (status)
+                       return status;
+       }
+
+       return hw->phy.ops.setup_link_speed(hw, speed, autoneg_wait);
+}
+
+/** ixgbe_init_mac_link_ops_X550em - init mac link function pointers
+ *  @hw: pointer to hardware structure
+ **/
+static void ixgbe_init_mac_link_ops_X550em(struct ixgbe_hw *hw)
+{
+       struct ixgbe_mac_info *mac = &hw->mac;
+
+       switch (mac->ops.get_media_type(hw)) {
+       case ixgbe_media_type_fiber:
+               /* CS4227 does not support autoneg, so disable the laser control
+                * functions for SFP+ fiber
+                */
+               mac->ops.disable_tx_laser = NULL;
+               mac->ops.enable_tx_laser = NULL;
+               mac->ops.flap_tx_laser = NULL;
+               break;
+       case ixgbe_media_type_copper:
+               mac->ops.setup_link = ixgbe_setup_mac_link_t_X550em;
+               break;
+       default:
+               break;
+       }
+}
+
+/** ixgbe_setup_sfp_modules_X550em - Setup SFP module
+ * @hw: pointer to hardware structure
+ */
+static s32 ixgbe_setup_sfp_modules_X550em(struct ixgbe_hw *hw)
+{
+       bool setup_linear;
+       u16 reg_slice, edc_mode;
+       s32 ret_val;
+
+       switch (hw->phy.sfp_type) {
+       case ixgbe_sfp_type_unknown:
+               return 0;
+       case ixgbe_sfp_type_not_present:
+               return IXGBE_ERR_SFP_NOT_PRESENT;
+       case ixgbe_sfp_type_da_cu_core0:
+       case ixgbe_sfp_type_da_cu_core1:
+               setup_linear = true;
+               break;
+       case ixgbe_sfp_type_srlr_core0:
+       case ixgbe_sfp_type_srlr_core1:
+       case ixgbe_sfp_type_da_act_lmt_core0:
+       case ixgbe_sfp_type_da_act_lmt_core1:
+       case ixgbe_sfp_type_1g_sx_core0:
+       case ixgbe_sfp_type_1g_sx_core1:
+               setup_linear = false;
+               break;
+       default:
+               return IXGBE_ERR_SFP_NOT_SUPPORTED;
+       }
+
+       ixgbe_init_mac_link_ops_X550em(hw);
+       hw->phy.ops.reset = NULL;
+
+       /* The CS4227 slice address is the base address + the port-pair reg
+        * offset. I.e. Slice 0 = 0x12B0 and slice 1 = 0x22B0.
+        */
+       reg_slice = IXGBE_CS4227_SPARE24_LSB + (hw->bus.lan_id << 12);
+
+       if (setup_linear)
+               edc_mode = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1;
+       else
+               edc_mode = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1;
+
+       /* Configure CS4227 for connection type. */
+       ret_val = hw->phy.ops.write_i2c_combined(hw, IXGBE_CS4227, reg_slice,
+                                                edc_mode);
+
+       if (ret_val)
+               ret_val = hw->phy.ops.write_i2c_combined(hw, 0x80, reg_slice,
+                                                        edc_mode);
+
+       return ret_val;
+}
+
+/** ixgbe_get_link_capabilities_x550em - Determines link capabilities
+ * @hw: pointer to hardware structure
+ * @speed: pointer to link speed
+ * @autoneg: true when autoneg or autotry is enabled
+ **/
+static s32 ixgbe_get_link_capabilities_X550em(struct ixgbe_hw *hw,
+                                             ixgbe_link_speed *speed,
+                                             bool *autoneg)
+{
+       /* SFP */
+       if (hw->phy.media_type == ixgbe_media_type_fiber) {
+               /* CS4227 SFP must not enable auto-negotiation */
+               *autoneg = false;
+
+               if (hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
+                   hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1) {
+                       *speed = IXGBE_LINK_SPEED_1GB_FULL;
+                       return 0;
+               }
+
+               /* Link capabilities are based on SFP */
+               if (hw->phy.multispeed_fiber)
+                       *speed = IXGBE_LINK_SPEED_10GB_FULL |
+                                IXGBE_LINK_SPEED_1GB_FULL;
+               else
+                       *speed = IXGBE_LINK_SPEED_10GB_FULL;
+       } else {
+               *speed = IXGBE_LINK_SPEED_10GB_FULL |
+                        IXGBE_LINK_SPEED_1GB_FULL;
+               *autoneg = true;
+       }
+       return 0;
+}
+
+/**
+ * ixgbe_get_lasi_ext_t_x550em - Determime external Base T PHY interrupt cause
+ * @hw: pointer to hardware structure
+ * @lsc: pointer to boolean flag which indicates whether external Base T
+ *      PHY interrupt is lsc
+ *
+ * Determime if external Base T PHY interrupt cause is high temperature
+ * failure alarm or link status change.
+ *
+ * Return IXGBE_ERR_OVERTEMP if interrupt is high temperature
+ * failure alarm, else return PHY access status.
+ **/
+static s32 ixgbe_get_lasi_ext_t_x550em(struct ixgbe_hw *hw, bool *lsc)
+{
+       u32 status;
+       u16 reg;
+
+       *lsc = false;
+
+       /* Vendor alarm triggered */
+       status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_CHIP_STD_INT_FLAG,
+                                     IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+                                     ®);
+
+       if (status || !(reg & IXGBE_MDIO_GLOBAL_VEN_ALM_INT_EN))
+               return status;
+
+       /* Vendor Auto-Neg alarm triggered or Global alarm 1 triggered */
+       status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_VEN_FLAG,
+                                     IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+                                     ®);
+
+       if (status || !(reg & (IXGBE_MDIO_GLOBAL_AN_VEN_ALM_INT_EN |
+                               IXGBE_MDIO_GLOBAL_ALARM_1_INT)))
+               return status;
+
+       /* High temperature failure alarm triggered */
+       status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_ALARM_1,
+                                     IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+                                     ®);
+
+       if (status)
+               return status;
+
+       /* If high temperature failure, then return over temp error and exit */
+       if (reg & IXGBE_MDIO_GLOBAL_ALM_1_HI_TMP_FAIL) {
+               /* power down the PHY in case the PHY FW didn't already */
+               ixgbe_set_copper_phy_power(hw, false);
+               return IXGBE_ERR_OVERTEMP;
+       }
+
+       /* Vendor alarm 2 triggered */
+       status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_CHIP_STD_INT_FLAG,
+                                     IXGBE_MDIO_AUTO_NEG_DEV_TYPE, ®);
+
+       if (status || !(reg & IXGBE_MDIO_GLOBAL_STD_ALM2_INT))
+               return status;
+
+       /* link connect/disconnect event occurred */
+       status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_TX_ALARM2,
+                                     IXGBE_MDIO_AUTO_NEG_DEV_TYPE, ®);
+
+       if (status)
+               return status;
+
+       /* Indicate LSC */
+       if (reg & IXGBE_MDIO_AUTO_NEG_VEN_LSC)
+               *lsc = true;
+
+       return 0;
+}
+
+/**
+ * ixgbe_enable_lasi_ext_t_x550em - Enable external Base T PHY interrupts
+ * @hw: pointer to hardware structure
+ *
+ * Enable link status change and temperature failure alarm for the external
+ * Base T PHY
+ *
+ * Returns PHY access status
+ **/
+static s32 ixgbe_enable_lasi_ext_t_x550em(struct ixgbe_hw *hw)
+{
+       u32 status;
+       u16 reg;
+       bool lsc;
+
+       /* Clear interrupt flags */
+       status = ixgbe_get_lasi_ext_t_x550em(hw, &lsc);
+
+       /* Enable link status change alarm */
+       status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PMA_TX_VEN_LASI_INT_MASK,
+                                     IXGBE_MDIO_AUTO_NEG_DEV_TYPE, ®);
+       if (status)
+               return status;
+
+       reg |= IXGBE_MDIO_PMA_TX_VEN_LASI_INT_EN;
+
+       status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_PMA_TX_VEN_LASI_INT_MASK,
+                                      IXGBE_MDIO_AUTO_NEG_DEV_TYPE, reg);
+       if (status)
+               return status;
+
+       /* Enables high temperature failure alarm */
+       status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_MASK,
+                                     IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+                                     ®);
+       if (status)
+               return status;
+
+       reg |= IXGBE_MDIO_GLOBAL_INT_HI_TEMP_EN;
+
+       status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_GLOBAL_INT_MASK,
+                                      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+                                      reg);
+       if (status)
+               return status;
+
+       /* Enable vendor Auto-Neg alarm and Global Interrupt Mask 1 alarm */
+       status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_VEN_MASK,
+                                     IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+                                     ®);
+       if (status)
+               return status;
+
+       reg |= (IXGBE_MDIO_GLOBAL_AN_VEN_ALM_INT_EN |
+               IXGBE_MDIO_GLOBAL_ALARM_1_INT);
+
+       status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_VEN_MASK,
+                                      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+                                      reg);
+       if (status)
+               return status;
+
+       /* Enable chip-wide vendor alarm */
+       status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_STD_MASK,
+                                     IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+                                     ®);
+       if (status)
+               return status;
+
+       reg |= IXGBE_MDIO_GLOBAL_VEN_ALM_INT_EN;
+
+       status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_STD_MASK,
+                                      IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+                                      reg);
+
+       return status;
+}
+
+/**
+ * ixgbe_handle_lasi_ext_t_x550em - Handle external Base T PHY interrupt
+ * @hw: pointer to hardware structure
+ *
+ * Handle external Base T PHY interrupt. If high temperature
+ * failure alarm then return error, else if link status change
+ * then setup internal/external PHY link
+ *
+ * Return IXGBE_ERR_OVERTEMP if interrupt is high temperature
+ * failure alarm, else return PHY access status.
+ **/
+static s32 ixgbe_handle_lasi_ext_t_x550em(struct ixgbe_hw *hw)
+{
+       struct ixgbe_phy_info *phy = &hw->phy;
+       bool lsc;
+       u32 status;
+
+       status = ixgbe_get_lasi_ext_t_x550em(hw, &lsc);
+       if (status)
+               return status;
+
+       if (lsc)
+               return phy->ops.setup_internal_link(hw);
+
+       return 0;
+}
+
+/**
+ * ixgbe_setup_kr_speed_x550em - Configure the KR PHY for link speed.
+ * @hw: pointer to hardware structure
+ * @speed: link speed
+ *
+ * Configures the integrated KR PHY.
+ **/
+static s32 ixgbe_setup_kr_speed_x550em(struct ixgbe_hw *hw,
+                                      ixgbe_link_speed speed)
+{
+       s32 status;
+       u32 reg_val;
+
+       status = ixgbe_read_iosf_sb_reg_x550(hw,
+                                       IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
+                                       IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val);
+       if (status)
+               return status;
+
+       reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE;
+       reg_val &= ~(IXGBE_KRM_LINK_CTRL_1_TETH_AN_FEC_REQ |
+                    IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_FEC);
+       reg_val &= ~(IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KR |
+                    IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KX);
+
+       /* Advertise 10G support. */
+       if (speed & IXGBE_LINK_SPEED_10GB_FULL)
+               reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KR;
+
+       /* Advertise 1G support. */
+       if (speed & IXGBE_LINK_SPEED_1GB_FULL)
+               reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KX;
+
+       /* Restart auto-negotiation. */
+       reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_RESTART;
+       status = ixgbe_write_iosf_sb_reg_x550(hw,
+                                       IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
+                                       IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
+
+       return status;
+}
+
 /** ixgbe_setup_kx4_x550em - Configure the KX4 PHY.
  *  @hw: pointer to hardware structure
  *
  **/
 static s32 ixgbe_setup_kr_x550em(struct ixgbe_hw *hw)
 {
-       s32 status;
-       u32 reg_val;
+       return ixgbe_setup_kr_speed_x550em(hw, hw->phy.autoneg_advertised);
+}
 
-       status = ixgbe_read_iosf_sb_reg_x550(hw,
-                                       IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
-                                       IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val);
-       if (status)
-               return status;
+/** ixgbe_ext_phy_t_x550em_get_link - Get ext phy link status
+ *  @hw: address of hardware structure
+ *  @link_up: address of boolean to indicate link status
+ *
+ *  Returns error code if unable to get link status.
+ **/
+static s32 ixgbe_ext_phy_t_x550em_get_link(struct ixgbe_hw *hw, bool *link_up)
+{
+       u32 ret;
+       u16 autoneg_status;
 
-       reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE;
-       reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_FEC_REQ;
-       reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_FEC;
-       reg_val &= ~(IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KR |
-                    IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KX);
+       *link_up = false;
 
-       /* Advertise 10G support. */
-       if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL)
-               reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KR;
+       /* read this twice back to back to indicate current status */
+       ret = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
+                                  IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+                                  &autoneg_status);
+       if (ret)
+               return ret;
 
-       /* Advertise 1G support. */
-       if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL)
-               reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KX;
+       ret = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
+                                  IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+                                  &autoneg_status);
+       if (ret)
+               return ret;
 
-       /* Restart auto-negotiation. */
-       reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_RESTART;
-       status = ixgbe_write_iosf_sb_reg_x550(hw,
-                                       IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
-                                       IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
+       *link_up = !!(autoneg_status & IXGBE_MDIO_AUTO_NEG_LINK_STATUS);
 
-       return status;
+       return 0;
 }
 
-/** ixgbe_setup_internal_phy_x550em - Configure integrated KR PHY
+/** ixgbe_setup_internal_phy_t_x550em - Configure KR PHY to X557 link
  *  @hw: point to hardware structure
  *
- *  Configures the integrated KR PHY to talk to the external PHY. The base
- *  driver will call this function when it gets notification via interrupt from
- *  the external PHY. This function forces the internal PHY into iXFI mode at
- *  the correct speed.
+ *  Configures the link between the integrated KR PHY and the external X557 PHY
+ *  The driver will call this function when it gets a link status change
+ *  interrupt from the X557 PHY. This function configures the link speed
+ *  between the PHYs to match the link speed of the BASE-T link.
  *
- *  A return of a non-zero value indicates an error, and the base driver should
- *  not report link up.
+ * A return of a non-zero value indicates an error, and the base driver should
+ * not report link up.
  **/
-static s32 ixgbe_setup_internal_phy_x550em(struct ixgbe_hw *hw)
+static s32 ixgbe_setup_internal_phy_t_x550em(struct ixgbe_hw *hw)
 {
-       s32 status;
-       u16 lasi, autoneg_status, speed;
        ixgbe_link_speed force_speed;
+       bool link_up;
+       u32 status;
+       u16 speed;
+
+       if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper)
+               return IXGBE_ERR_CONFIG;
 
-       /* Verify that the external link status has changed */
-       status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_XENPAK_LASI_STATUS,
-                                     IXGBE_MDIO_PMA_PMD_DEV_TYPE, &lasi);
+       /* If link is not up, then there is no setup necessary so return  */
+       status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up);
        if (status)
                return status;
 
-       /* If there was no change in link status, we can just exit */
-       if (!(lasi & IXGBE_XENPAK_LASI_LINK_STATUS_ALARM))
+       if (!link_up)
                return 0;
 
-       /* we read this twice back to back to indicate current status */
-       status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
+       status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_STAT,
                                      IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
-                                     &autoneg_status);
+                                     &speed);
        if (status)
                return status;
 
-       status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
-                                     IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
-                                     &autoneg_status);
+       /* If link is not still up, then no setup is necessary so return */
+       status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up);
        if (status)
                return status;
 
-       /* If link is not up return an error indicating treat link as down */
-       if (!(autoneg_status & IXGBE_MDIO_AUTO_NEG_LINK_STATUS))
-               return IXGBE_ERR_INVALID_LINK_SETTINGS;
-
-       status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_STAT,
-                                     IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
-                                     &speed);
+       if (!link_up)
+               return 0;
 
        /* clear everything but the speed and duplex bits */
        speed &= IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_MASK;
 static s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw)
 {
        struct ixgbe_phy_info *phy = &hw->phy;
+       ixgbe_link_speed speed;
        s32 ret_val;
 
-       if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP) {
+       if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber) {
                phy->phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM;
                ixgbe_setup_mux_ctl(hw);
+
+               /* Save NW management interface connected on board. This is used
+                * to determine internal PHY mode.
+                */
+               phy->nw_mng_if_sel = IXGBE_READ_REG(hw, IXGBE_NW_MNG_IF_SEL);
+
+               /* If internal PHY mode is KR, then initialize KR link */
+               if (phy->nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE) {
+                       speed = IXGBE_LINK_SPEED_10GB_FULL |
+                               IXGBE_LINK_SPEED_1GB_FULL;
+                       ret_val = ixgbe_setup_kr_speed_x550em(hw, speed);
+               }
        }
 
        /* Identify the PHY or SFP module */
        ret_val = phy->ops.identify(hw);
 
-       /* Setup function pointers based on detected SFP module and speeds */
+       /* Setup function pointers based on detected hardware */
        ixgbe_init_mac_link_ops_X550em(hw);
        if (phy->sfp_type != ixgbe_sfp_type_unknown)
                phy->ops.reset = NULL;
                phy->ops.write_reg = ixgbe_write_phy_reg_x550em;
                break;
        case ixgbe_phy_x550em_ext_t:
-               phy->ops.setup_internal_link = ixgbe_setup_internal_phy_x550em;
+               /* Save NW management interface connected on board. This is used
+                * to determine internal PHY mode
+                */
+               phy->nw_mng_if_sel = IXGBE_READ_REG(hw, IXGBE_NW_MNG_IF_SEL);
+
+               /* If internal link mode is XFI, then setup iXFI internal link,
+                * else setup KR now.
+                */
+               if (!(phy->nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE)) {
+                       phy->ops.setup_internal_link =
+                                       ixgbe_setup_internal_phy_t_x550em;
+               } else {
+                       speed = IXGBE_LINK_SPEED_10GB_FULL |
+                               IXGBE_LINK_SPEED_1GB_FULL;
+                       ret_val = ixgbe_setup_kr_speed_x550em(hw, speed);
+               }
+
+               phy->ops.handle_lasi = ixgbe_handle_lasi_ext_t_x550em;
                break;
        default:
                break;
        }
+
        return ret_val;
 }