|
@@ -1458,6 +1458,144 @@ static s32 ixgbe_reset_phy_t_X550em(struct ixgbe_hw *hw)
|
|
|
return ixgbe_enable_lasi_ext_t_x550em(hw);
|
|
|
}
|
|
|
|
|
|
+/** ixgbe_get_lcd_x550em - Determine lowest common denominator
|
|
|
+ * @hw: pointer to hardware structure
|
|
|
+ * @lcd_speed: pointer to lowest common link speed
|
|
|
+ *
|
|
|
+ * Determine lowest common link speed with link partner.
|
|
|
+ **/
|
|
|
+static s32 ixgbe_get_lcd_t_x550em(struct ixgbe_hw *hw,
|
|
|
+ ixgbe_link_speed *lcd_speed)
|
|
|
+{
|
|
|
+ u16 an_lp_status;
|
|
|
+ s32 status;
|
|
|
+ u16 word = hw->eeprom.ctrl_word_3;
|
|
|
+
|
|
|
+ *lcd_speed = IXGBE_LINK_SPEED_UNKNOWN;
|
|
|
+
|
|
|
+ status = hw->phy.ops.read_reg(hw, IXGBE_AUTO_NEG_LP_STATUS,
|
|
|
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
|
|
|
+ &an_lp_status);
|
|
|
+ if (status)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ /* If link partner advertised 1G, return 1G */
|
|
|
+ if (an_lp_status & IXGBE_AUTO_NEG_LP_1000BASE_CAP) {
|
|
|
+ *lcd_speed = IXGBE_LINK_SPEED_1GB_FULL;
|
|
|
+ return status;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* If 10G disabled for LPLU via NVM D10GMP, then return no valid LCD */
|
|
|
+ if ((hw->bus.lan_id && (word & NVM_INIT_CTRL_3_D10GMP_PORT1)) ||
|
|
|
+ (word & NVM_INIT_CTRL_3_D10GMP_PORT0))
|
|
|
+ return status;
|
|
|
+
|
|
|
+ /* Link partner not capable of lower speeds, return 10G */
|
|
|
+ *lcd_speed = IXGBE_LINK_SPEED_10GB_FULL;
|
|
|
+ return status;
|
|
|
+}
|
|
|
+
|
|
|
+/** ixgbe_enter_lplu_x550em - Transition to low power states
|
|
|
+ * @hw: pointer to hardware structure
|
|
|
+ *
|
|
|
+ * Configures Low Power Link Up on transition to low power states
|
|
|
+ * (from D0 to non-D0). Link is required to enter LPLU so avoid resetting
|
|
|
+ * the X557 PHY immediately prior to entering LPLU.
|
|
|
+ **/
|
|
|
+static s32 ixgbe_enter_lplu_t_x550em(struct ixgbe_hw *hw)
|
|
|
+{
|
|
|
+ u16 an_10g_cntl_reg, autoneg_reg, speed;
|
|
|
+ s32 status;
|
|
|
+ ixgbe_link_speed lcd_speed;
|
|
|
+ u32 save_autoneg;
|
|
|
+ bool link_up;
|
|
|
+
|
|
|
+ /* SW LPLU not required on later HW revisions. */
|
|
|
+ if (IXGBE_FUSES0_REV1 & IXGBE_READ_REG(hw, IXGBE_FUSES0_GROUP(0)))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ /* If blocked by MNG FW, then don't restart AN */
|
|
|
+ if (ixgbe_check_reset_blocked(hw))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up);
|
|
|
+ if (status)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ status = hw->eeprom.ops.read(hw, NVM_INIT_CTRL_3,
|
|
|
+ &hw->eeprom.ctrl_word_3);
|
|
|
+ if (status)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ /* If link is down, LPLU disabled in NVM, WoL disabled, or
|
|
|
+ * manageability disabled, then force link down by entering
|
|
|
+ * low power mode.
|
|
|
+ */
|
|
|
+ if (!link_up || !(hw->eeprom.ctrl_word_3 & NVM_INIT_CTRL_3_LPLU) ||
|
|
|
+ !(hw->wol_enabled || ixgbe_mng_present(hw)))
|
|
|
+ return ixgbe_set_copper_phy_power(hw, false);
|
|
|
+
|
|
|
+ /* Determine LCD */
|
|
|
+ status = ixgbe_get_lcd_t_x550em(hw, &lcd_speed);
|
|
|
+ if (status)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ /* If no valid LCD link speed, then force link down and exit. */
|
|
|
+ if (lcd_speed == IXGBE_LINK_SPEED_UNKNOWN)
|
|
|
+ return ixgbe_set_copper_phy_power(hw, false);
|
|
|
+
|
|
|
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_STAT,
|
|
|
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
|
|
|
+ &speed);
|
|
|
+ if (status)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ /* If no link now, speed is invalid so take link down */
|
|
|
+ status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up);
|
|
|
+ if (status)
|
|
|
+ return ixgbe_set_copper_phy_power(hw, false);
|
|
|
+
|
|
|
+ /* clear everything but the speed bits */
|
|
|
+ speed &= IXGBE_MDIO_AUTO_NEG_VEN_STAT_SPEED_MASK;
|
|
|
+
|
|
|
+ /* If current speed is already LCD, then exit. */
|
|
|
+ if (((speed == IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_1GB) &&
|
|
|
+ (lcd_speed == IXGBE_LINK_SPEED_1GB_FULL)) ||
|
|
|
+ ((speed == IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_10GB) &&
|
|
|
+ (lcd_speed == IXGBE_LINK_SPEED_10GB_FULL)))
|
|
|
+ return status;
|
|
|
+
|
|
|
+ /* Clear AN completed indication */
|
|
|
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_TX_ALARM,
|
|
|
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
|
|
|
+ &autoneg_reg);
|
|
|
+ if (status)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ status = hw->phy.ops.read_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG,
|
|
|
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
|
|
|
+ &an_10g_cntl_reg);
|
|
|
+ if (status)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ status = hw->phy.ops.read_reg(hw,
|
|
|
+ IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG,
|
|
|
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
|
|
|
+ &autoneg_reg);
|
|
|
+ if (status)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ save_autoneg = hw->phy.autoneg_advertised;
|
|
|
+
|
|
|
+ /* Setup link at least common link speed */
|
|
|
+ status = hw->mac.ops.setup_link(hw, lcd_speed, false);
|
|
|
+
|
|
|
+ /* restore autoneg from before setting lplu speed */
|
|
|
+ hw->phy.autoneg_advertised = save_autoneg;
|
|
|
+
|
|
|
+ return status;
|
|
|
+}
|
|
|
+
|
|
|
/** ixgbe_init_phy_ops_X550em - PHY/SFP specific init
|
|
|
* @hw: pointer to hardware structure
|
|
|
*
|
|
@@ -1528,6 +1666,11 @@ static s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw)
|
|
|
ret_val = ixgbe_setup_kr_speed_x550em(hw, speed);
|
|
|
}
|
|
|
|
|
|
+ /* setup SW LPLU only for first revision */
|
|
|
+ if (!(IXGBE_FUSES0_REV1 & IXGBE_READ_REG(hw,
|
|
|
+ IXGBE_FUSES0_GROUP(0))))
|
|
|
+ phy->ops.enter_lplu = ixgbe_enter_lplu_t_x550em;
|
|
|
+
|
|
|
phy->ops.handle_lasi = ixgbe_handle_lasi_ext_t_x550em;
|
|
|
phy->ops.reset = ixgbe_reset_phy_t_X550em;
|
|
|
break;
|