Print this page
Import some changes from FreeBSD (details later, this is quick-n-dirty for now).

@@ -1,8 +1,8 @@
 /******************************************************************************
 
-  Copyright (c) 2001-2012, Intel Corporation 
+  Copyright (c) 2001-2013, Intel Corporation 
   All rights reserved.
   
   Redistribution and use in source and binary forms, with or without 
   modification, are permitted provided that the following conditions are met:
   

@@ -38,26 +38,48 @@
 #include "ixgbe_common.h"
 #include "ixgbe_phy.h"
 
 static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw,
                                          ixgbe_link_speed speed,
-                                         bool autoneg,
                                          bool autoneg_wait_to_complete);
 static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw);
 static s32 ixgbe_read_eeprom_82599(struct ixgbe_hw *hw,
                                    u16 offset, u16 *data);
 static s32 ixgbe_read_eeprom_buffer_82599(struct ixgbe_hw *hw, u16 offset,
                                           u16 words, u16 *data);
 
+static bool ixgbe_mng_enabled(struct ixgbe_hw *hw)
+{
+        u32 fwsm, manc, factps;
+
+        fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM);
+        if ((fwsm & IXGBE_FWSM_MODE_MASK) != IXGBE_FWSM_FW_MODE_PT)
+                return FALSE;
+
+        manc = IXGBE_READ_REG(hw, IXGBE_MANC);
+        if (!(manc & IXGBE_MANC_RCV_TCO_EN))
+                return FALSE;
+
+        factps = IXGBE_READ_REG(hw, IXGBE_FACTPS);
+        if (factps & IXGBE_FACTPS_MNGCG)
+                return FALSE;
+
+        return TRUE;
+}
+
 void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw)
 {
         struct ixgbe_mac_info *mac = &hw->mac;
 
         DEBUGFUNC("ixgbe_init_mac_link_ops_82599");
 
-        /* enable the laser control functions for SFP+ fiber */
-        if (mac->ops.get_media_type(hw) == ixgbe_media_type_fiber) {
+        /*
+         * enable the laser control functions for SFP+ fiber
+         * and MNG not enabled
+         */
+        if ((mac->ops.get_media_type(hw) == ixgbe_media_type_fiber) &&
+            !(ixgbe_mng_enabled(hw))) {
                 mac->ops.disable_tx_laser =
                                        &ixgbe_disable_tx_laser_multispeed_fiber;
                 mac->ops.enable_tx_laser =
                                         &ixgbe_enable_tx_laser_multispeed_fiber;
                 mac->ops.flap_tx_laser = &ixgbe_flap_tx_laser_multispeed_fiber;

@@ -133,13 +155,12 @@
 }
 
 s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw)
 {
         s32 ret_val = IXGBE_SUCCESS;
-        u32 reg_anlp1 = 0;
-        u32 i = 0;
         u16 list_offset, data_offset, data_value;
+        bool got_lock = FALSE;
 
         DEBUGFUNC("ixgbe_setup_sfp_modules_82599");
 
         if (hw->phy.sfp_type != ixgbe_sfp_type_unknown) {
                 ixgbe_init_mac_link_ops_82599(hw);

@@ -169,32 +190,43 @@
                 /* Release the semaphore */
                 hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM);
                 /* Delay obtaining semaphore again to allow FW access */
                 msec_delay(hw->eeprom.semaphore_delay);
 
-                /* Now restart DSP by setting Restart_AN and clearing LMS */
-                IXGBE_WRITE_REG(hw, IXGBE_AUTOC, ((IXGBE_READ_REG(hw,
-                                IXGBE_AUTOC) & ~IXGBE_AUTOC_LMS_MASK) |
-                                IXGBE_AUTOC_AN_RESTART));
+                /* Need SW/FW semaphore around AUTOC writes if LESM on,
+                 * likewise reset_pipeline requires lock as it also writes
+                 * AUTOC.
+                 */
+                if (ixgbe_verify_lesm_fw_enabled_82599(hw)) {
+                        ret_val = hw->mac.ops.acquire_swfw_sync(hw,
+                                                        IXGBE_GSSR_MAC_CSR_SM);
+                        if (ret_val != IXGBE_SUCCESS) {
+                                ret_val = IXGBE_ERR_SWFW_SYNC;
+                                goto setup_sfp_out;
+                        }
 
-                /* Wait for AN to leave state 0 */
-                for (i = 0; i < 10; i++) {
-                        msec_delay(4);
-                        reg_anlp1 = IXGBE_READ_REG(hw, IXGBE_ANLP1);
-                        if (reg_anlp1 & IXGBE_ANLP1_AN_STATE_MASK)
-                                break;
+                        got_lock = TRUE;
                 }
-                if (!(reg_anlp1 & IXGBE_ANLP1_AN_STATE_MASK)) {
+
+                /* Restart DSP and set SFI mode */
+                IXGBE_WRITE_REG(hw, IXGBE_AUTOC, ((hw->mac.orig_autoc) |
+                                IXGBE_AUTOC_LMS_10G_SERIAL));
+                hw->mac.cached_autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+                ret_val = ixgbe_reset_pipeline_82599(hw);
+
+                if (got_lock) {
+                        hw->mac.ops.release_swfw_sync(hw,
+                                                      IXGBE_GSSR_MAC_CSR_SM);
+                        got_lock = FALSE;
+                }
+
+                if (ret_val) {
                         DEBUGOUT("sfp module setup not complete\n");
                         ret_val = IXGBE_ERR_SFP_SETUP_NOT_COMPLETE;
                         goto setup_sfp_out;
                 }
 
-                /* Restart DSP by setting Restart_AN and return to SFI mode */
-                IXGBE_WRITE_REG(hw, IXGBE_AUTOC, (IXGBE_READ_REG(hw,
-                                IXGBE_AUTOC) | IXGBE_AUTOC_LMS_10G_SERIAL |
-                                IXGBE_AUTOC_AN_RESTART));
         }
 
 setup_sfp_out:
         return ret_val;
 }

@@ -214,11 +246,11 @@
         struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
         s32 ret_val;
 
         DEBUGFUNC("ixgbe_init_ops_82599");
 
-        ret_val = ixgbe_init_phy_ops_generic(hw);
+        (void) ixgbe_init_phy_ops_generic(hw);
         ret_val = ixgbe_init_ops_generic(hw);
 
         /* PHY */
         phy->ops.identify = &ixgbe_identify_phy_82599;
         phy->ops.init = &ixgbe_init_phy_ops_82599;

@@ -287,17 +319,17 @@
 
 /**
  *  ixgbe_get_link_capabilities_82599 - Determines link capabilities
  *  @hw: pointer to hardware structure
  *  @speed: pointer to link speed
- *  @negotiation: TRUE when autoneg or autotry is enabled
+ *  @autoneg: TRUE when autoneg or autotry is enabled
  *
  *  Determines the link capabilities by reading the AUTOC register.
  **/
 s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw,
                                       ixgbe_link_speed *speed,
-                                      bool *negotiation)
+                                      bool *autoneg)
 {
         s32 status = IXGBE_SUCCESS;
         u32 autoc = 0;
 
         DEBUGFUNC("ixgbe_get_link_capabilities_82599");

@@ -307,11 +339,11 @@
         if (hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0 ||
             hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 ||
             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;
-                *negotiation = TRUE;
+                *autoneg = TRUE;
                 goto out;
         }
 
         /*
          * Determine link capabilities based on the stored value of AUTOC,

@@ -324,26 +356,26 @@
                 autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
 
         switch (autoc & IXGBE_AUTOC_LMS_MASK) {
         case IXGBE_AUTOC_LMS_1G_LINK_NO_AN:
                 *speed = IXGBE_LINK_SPEED_1GB_FULL;
-                *negotiation = FALSE;
+                *autoneg = FALSE;
                 break;
 
         case IXGBE_AUTOC_LMS_10G_LINK_NO_AN:
                 *speed = IXGBE_LINK_SPEED_10GB_FULL;
-                *negotiation = FALSE;
+                *autoneg = FALSE;
                 break;
 
         case IXGBE_AUTOC_LMS_1G_AN:
                 *speed = IXGBE_LINK_SPEED_1GB_FULL;
-                *negotiation = TRUE;
+                *autoneg = TRUE;
                 break;
 
         case IXGBE_AUTOC_LMS_10G_SERIAL:
                 *speed = IXGBE_LINK_SPEED_10GB_FULL;
-                *negotiation = FALSE;
+                *autoneg = FALSE;
                 break;
 
         case IXGBE_AUTOC_LMS_KX4_KX_KR:
         case IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN:
                 *speed = IXGBE_LINK_SPEED_UNKNOWN;

@@ -351,11 +383,11 @@
                         *speed |= IXGBE_LINK_SPEED_10GB_FULL;
                 if (autoc & IXGBE_AUTOC_KX4_SUPP)
                         *speed |= IXGBE_LINK_SPEED_10GB_FULL;
                 if (autoc & IXGBE_AUTOC_KX_SUPP)
                         *speed |= IXGBE_LINK_SPEED_1GB_FULL;
-                *negotiation = TRUE;
+                *autoneg = TRUE;
                 break;
 
         case IXGBE_AUTOC_LMS_KX4_KX_KR_SGMII:
                 *speed = IXGBE_LINK_SPEED_100_FULL;
                 if (autoc & IXGBE_AUTOC_KR_SUPP)

@@ -362,16 +394,16 @@
                         *speed |= IXGBE_LINK_SPEED_10GB_FULL;
                 if (autoc & IXGBE_AUTOC_KX4_SUPP)
                         *speed |= IXGBE_LINK_SPEED_10GB_FULL;
                 if (autoc & IXGBE_AUTOC_KX_SUPP)
                         *speed |= IXGBE_LINK_SPEED_1GB_FULL;
-                *negotiation = TRUE;
+                *autoneg = TRUE;
                 break;
 
         case IXGBE_AUTOC_LMS_SGMII_1G_100M:
                 *speed = IXGBE_LINK_SPEED_1GB_FULL | IXGBE_LINK_SPEED_100_FULL;
-                *negotiation = FALSE;
+                *autoneg = FALSE;
                 break;
 
         default:
                 status = IXGBE_ERR_LINK_SETUP;
                 goto out;

@@ -378,11 +410,11 @@
         }
 
         if (hw->phy.multispeed_fiber) {
                 *speed |= IXGBE_LINK_SPEED_10GB_FULL |
                           IXGBE_LINK_SPEED_1GB_FULL;
-                *negotiation = TRUE;
+                *autoneg = TRUE;
         }
 
 out:
         return status;
 }

@@ -421,19 +453,24 @@
                 break;
         case IXGBE_DEV_ID_82599_SFP:
         case IXGBE_DEV_ID_82599_SFP_FCOE:
         case IXGBE_DEV_ID_82599_SFP_EM:
         case IXGBE_DEV_ID_82599_SFP_SF2:
+        case IXGBE_DEV_ID_82599_SFP_SF_QP:
         case IXGBE_DEV_ID_82599EN_SFP:
                 media_type = ixgbe_media_type_fiber;
                 break;
         case IXGBE_DEV_ID_82599_CX4:
                 media_type = ixgbe_media_type_cx4;
                 break;
         case IXGBE_DEV_ID_82599_T3_LOM:
                 media_type = ixgbe_media_type_copper;
                 break;
+        case IXGBE_DEV_ID_82599_BYPASS:
+                media_type = ixgbe_media_type_fiber_fixed;
+                hw->phy.multispeed_fiber = TRUE;
+                break;
         default:
                 media_type = ixgbe_media_type_unknown;
                 break;
         }
 out:

@@ -453,21 +490,36 @@
 {
         u32 autoc_reg;
         u32 links_reg;
         u32 i;
         s32 status = IXGBE_SUCCESS;
+        bool got_lock = FALSE;
 
         DEBUGFUNC("ixgbe_start_mac_link_82599");
 
 
+        /*  reset_pipeline requires us to hold this lock as it writes to
+         *  AUTOC.
+         */
+        if (ixgbe_verify_lesm_fw_enabled_82599(hw)) {
+                status = hw->mac.ops.acquire_swfw_sync(hw,
+                                                       IXGBE_GSSR_MAC_CSR_SM);
+                if (status != IXGBE_SUCCESS)
+                        goto out;
+
+                got_lock = TRUE;
+        }
+
         /* Restart link */
-        autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC);
-        autoc_reg |= IXGBE_AUTOC_AN_RESTART;
-        IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg);
+        (void) ixgbe_reset_pipeline_82599(hw);
 
+        if (got_lock)
+                hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM);
+
         /* Only poll for autoneg to complete if specified to do so */
         if (autoneg_wait_to_complete) {
+                autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC);
                 if ((autoc_reg & IXGBE_AUTOC_LMS_MASK) ==
                      IXGBE_AUTOC_LMS_KX4_KX_KR ||
                     (autoc_reg & IXGBE_AUTOC_LMS_MASK) ==
                      IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN ||
                     (autoc_reg & IXGBE_AUTOC_LMS_MASK) ==

@@ -487,10 +539,11 @@
         }
 
         /* Add delay to filter out noises during initial link setup */
         msec_delay(50);
 
+out:
         return status;
 }
 
 /**
  *  ixgbe_disable_tx_laser_multispeed_fiber - Disable Tx laser

@@ -552,35 +605,102 @@
                 hw->mac.autotry_restart = FALSE;
         }
 }
 
 /**
+ *  ixgbe_set_fiber_fixed_speed - Set module link speed for fixed fiber
+ *  @hw: pointer to hardware structure
+ *  @speed: link speed to set
+ *
+ *  We set the module speed differently for fixed fiber.  For other
+ *  multi-speed devices we don't have an error value so here if we
+ *  detect an error we just log it and exit.
+ */
+static void ixgbe_set_fiber_fixed_speed(struct ixgbe_hw *hw,
+                                        ixgbe_link_speed speed)
+{
+        s32 status;
+        u8 rs, eeprom_data;
+
+        switch (speed) {
+        case IXGBE_LINK_SPEED_10GB_FULL:
+                /* one bit mask same as setting on */
+                rs = IXGBE_SFF_SOFT_RS_SELECT_10G;
+                break;
+        case IXGBE_LINK_SPEED_1GB_FULL:
+                rs = IXGBE_SFF_SOFT_RS_SELECT_1G;
+                break;
+        default:
+                DEBUGOUT("Invalid fixed module speed\n");
+                return;
+        }
+
+        /* Set RS0 */
+        status = hw->phy.ops.read_i2c_byte(hw, IXGBE_SFF_SFF_8472_OSCB,
+                                           IXGBE_I2C_EEPROM_DEV_ADDR2,
+                                           &eeprom_data);
+        if (status) {
+                DEBUGOUT("Failed to read Rx Rate Select RS0\n");
+                goto out;
+        }
+
+        eeprom_data = (eeprom_data & ~IXGBE_SFF_SOFT_RS_SELECT_MASK) & rs;
+
+        status = hw->phy.ops.write_i2c_byte(hw, IXGBE_SFF_SFF_8472_OSCB,
+                                            IXGBE_I2C_EEPROM_DEV_ADDR2,
+                                            eeprom_data);
+        if (status) {
+                DEBUGOUT("Failed to write Rx Rate Select RS0\n");
+                goto out;
+        }
+
+        /* Set RS1 */
+        status = hw->phy.ops.read_i2c_byte(hw, IXGBE_SFF_SFF_8472_ESCB,
+                                           IXGBE_I2C_EEPROM_DEV_ADDR2,
+                                           &eeprom_data);
+        if (status) {
+                DEBUGOUT("Failed to read Rx Rate Select RS1\n");
+                goto out;
+        }
+
+        eeprom_data = (eeprom_data & ~IXGBE_SFF_SOFT_RS_SELECT_MASK) & rs;
+
+        status = hw->phy.ops.write_i2c_byte(hw, IXGBE_SFF_SFF_8472_ESCB,
+                                            IXGBE_I2C_EEPROM_DEV_ADDR2,
+                                            eeprom_data);
+        if (status) {
+                DEBUGOUT("Failed to write Rx Rate Select RS1\n");
+                goto out;
+        }
+out:
+        return;
+}
+
+/**
  *  ixgbe_setup_mac_link_multispeed_fiber - Set MAC link speed
  *  @hw: pointer to hardware structure
  *  @speed: new link speed
- *  @autoneg: TRUE if autonegotiation enabled
  *  @autoneg_wait_to_complete: TRUE when waiting for completion is needed
  *
  *  Set the link speed in the AUTOC register and restarts link.
  **/
 s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,
-                                     ixgbe_link_speed speed, bool autoneg,
+                                     ixgbe_link_speed speed,
                                      bool autoneg_wait_to_complete)
 {
         s32 status = IXGBE_SUCCESS;
         ixgbe_link_speed link_speed = IXGBE_LINK_SPEED_UNKNOWN;
         ixgbe_link_speed highest_link_speed = IXGBE_LINK_SPEED_UNKNOWN;
         u32 speedcnt = 0;
         u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP);
         u32 i = 0;
-        bool link_up = FALSE;
-        bool negotiation;
+        bool autoneg, link_up = FALSE;
 
         DEBUGFUNC("ixgbe_setup_mac_link_multispeed_fiber");
 
         /* Mask off requested but non-supported speeds */
-        status = ixgbe_get_link_capabilities(hw, &link_speed, &negotiation);
+        status = ixgbe_get_link_capabilities(hw, &link_speed, &autoneg);
         if (status != IXGBE_SUCCESS)
                 return status;
 
         speed &= link_speed;
 

@@ -599,20 +719,24 @@
 
                 if ((link_speed == IXGBE_LINK_SPEED_10GB_FULL) && link_up)
                         goto out;
 
                 /* Set the module link speed */
+                if (hw->phy.media_type == ixgbe_media_type_fiber_fixed) {
+                        ixgbe_set_fiber_fixed_speed(hw,
+                                                    IXGBE_LINK_SPEED_10GB_FULL);
+                } else {
                 esdp_reg |= (IXGBE_ESDP_SDP5_DIR | IXGBE_ESDP_SDP5);
                 IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
                 IXGBE_WRITE_FLUSH(hw);
+                }
 
                 /* Allow module to change analog characteristics (1G->10G) */
                 msec_delay(40);
 
                 status = ixgbe_setup_mac_link_82599(hw,
                                                     IXGBE_LINK_SPEED_10GB_FULL,
-                                                    autoneg,
                                                     autoneg_wait_to_complete);
                 if (status != IXGBE_SUCCESS)
                         return status;
 
                 /* Flap the tx laser if it has not already been done */

@@ -650,21 +774,25 @@
 
                 if ((link_speed == IXGBE_LINK_SPEED_1GB_FULL) && link_up)
                         goto out;
 
                 /* Set the module link speed */
+                if (hw->phy.media_type == ixgbe_media_type_fiber_fixed) {
+                        ixgbe_set_fiber_fixed_speed(hw,
+                                                    IXGBE_LINK_SPEED_1GB_FULL);
+                } else {
                 esdp_reg &= ~IXGBE_ESDP_SDP5;
                 esdp_reg |= IXGBE_ESDP_SDP5_DIR;
                 IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
                 IXGBE_WRITE_FLUSH(hw);
+                }
 
                 /* Allow module to change analog characteristics (10G->1G) */
                 msec_delay(40);
 
                 status = ixgbe_setup_mac_link_82599(hw,
                                                     IXGBE_LINK_SPEED_1GB_FULL,
-                                                    autoneg,
                                                     autoneg_wait_to_complete);
                 if (status != IXGBE_SUCCESS)
                         return status;
 
                 /* Flap the tx laser if it has not already been done */

@@ -687,11 +815,11 @@
          * (if there was more than one).  We call ourselves back with just the
          * single highest speed that the user requested.
          */
         if (speedcnt > 1)
                 status = ixgbe_setup_mac_link_multispeed_fiber(hw,
-                        highest_link_speed, autoneg, autoneg_wait_to_complete);
+                        highest_link_speed, autoneg_wait_to_complete);
 
 out:
         /* Set autoneg_advertised value based on input link speed */
         hw->phy.autoneg_advertised = 0;
 

@@ -706,17 +834,16 @@
 
 /**
  *  ixgbe_setup_mac_link_smartspeed - Set MAC link speed using SmartSpeed
  *  @hw: pointer to hardware structure
  *  @speed: new link speed
- *  @autoneg: TRUE if autonegotiation enabled
  *  @autoneg_wait_to_complete: TRUE when waiting for completion is needed
  *
  *  Implements the Intel SmartSpeed algorithm.
  **/
 s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw,
-                                    ixgbe_link_speed speed, bool autoneg,
+                                    ixgbe_link_speed speed,
                                     bool autoneg_wait_to_complete)
 {
         s32 status = IXGBE_SUCCESS;
         ixgbe_link_speed link_speed = IXGBE_LINK_SPEED_UNKNOWN;
         s32 i, j;

@@ -745,11 +872,11 @@
          */
 
         /* First, try to get link with full advertisement */
         hw->phy.smart_speed_active = FALSE;
         for (j = 0; j < IXGBE_SMARTSPEED_MAX_RETRIES; j++) {
-                status = ixgbe_setup_mac_link_82599(hw, speed, autoneg,
+                status = ixgbe_setup_mac_link_82599(hw, speed,
                                                     autoneg_wait_to_complete);
                 if (status != IXGBE_SUCCESS)
                         goto out;
 
                 /*

@@ -780,11 +907,11 @@
             ((autoc_reg & IXGBE_AUTOC_KX4_KX_SUPP_MASK) == 0))
                 goto out;
 
         /* Turn SmartSpeed on to disable KR support */
         hw->phy.smart_speed_active = TRUE;
-        status = ixgbe_setup_mac_link_82599(hw, speed, autoneg,
+        status = ixgbe_setup_mac_link_82599(hw, speed,
                                             autoneg_wait_to_complete);
         if (status != IXGBE_SUCCESS)
                 goto out;
 
         /*

@@ -805,11 +932,11 @@
                         goto out;
         }
 
         /* We didn't get link.  Turn SmartSpeed back off. */
         hw->phy.smart_speed_active = FALSE;
-        status = ixgbe_setup_mac_link_82599(hw, speed, autoneg,
+        status = ixgbe_setup_mac_link_82599(hw, speed,
                                             autoneg_wait_to_complete);
 
 out:
         if (link_up && (link_speed == IXGBE_LINK_SPEED_1GB_FULL))
                 DEBUGOUT("Smartspeed has downgraded the link speed "

@@ -819,36 +946,34 @@
 
 /**
  *  ixgbe_setup_mac_link_82599 - Set MAC link speed
  *  @hw: pointer to hardware structure
  *  @speed: new link speed
- *  @autoneg: TRUE if autonegotiation enabled
  *  @autoneg_wait_to_complete: TRUE when waiting for completion is needed
  *
  *  Set the link speed in the AUTOC register and restarts link.
  **/
 s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
-                               ixgbe_link_speed speed, bool autoneg,
+                               ixgbe_link_speed speed,
                                bool autoneg_wait_to_complete)
 {
+        bool autoneg = FALSE;
         s32 status = IXGBE_SUCCESS;
-        u32 autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+        u32 autoc, pma_pmd_1g, link_mode, start_autoc;
         u32 autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2);
-        u32 start_autoc = autoc;
         u32 orig_autoc = 0;
-        u32 link_mode = autoc & IXGBE_AUTOC_LMS_MASK;
-        u32 pma_pmd_1g = autoc & IXGBE_AUTOC_1G_PMA_PMD_MASK;
         u32 pma_pmd_10g_serial = autoc2 & IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_MASK;
         u32 links_reg;
         u32 i;
         ixgbe_link_speed link_capabilities = IXGBE_LINK_SPEED_UNKNOWN;
+        bool got_lock = FALSE;
 
         DEBUGFUNC("ixgbe_setup_mac_link_82599");
 
         /* Check to see if speed passed in is supported. */
         status = ixgbe_get_link_capabilities(hw, &link_capabilities, &autoneg);
-        if (status != IXGBE_SUCCESS)
+        if (status)
                 goto out;
 
         speed &= link_capabilities;
 
         if (speed == IXGBE_LINK_SPEED_UNKNOWN) {

@@ -856,13 +981,18 @@
                 goto out;
         }
 
         /* Use stored value (EEPROM defaults) of AUTOC to find KR/KX4 support*/
         if (hw->mac.orig_link_settings_stored)
-                orig_autoc = hw->mac.orig_autoc;
+                autoc = hw->mac.orig_autoc;
         else
+                autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+
                 orig_autoc = autoc;
+        start_autoc = hw->mac.cached_autoc;
+        link_mode = autoc & IXGBE_AUTOC_LMS_MASK;
+        pma_pmd_1g = autoc & IXGBE_AUTOC_1G_PMA_PMD_MASK;
 
         if (link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR ||
             link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN ||
             link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_SGMII) {
                 /* Set KX4/KX/KR support according to speed requested */

@@ -897,14 +1027,36 @@
                                 autoc |= IXGBE_AUTOC_LMS_1G_LINK_NO_AN;
                 }
         }
 
         if (autoc != start_autoc) {
+                /* Need SW/FW semaphore around AUTOC writes if LESM is on,
+                 * likewise reset_pipeline requires us to hold this lock as
+                 * it also writes to AUTOC.
+                 */
+                if (ixgbe_verify_lesm_fw_enabled_82599(hw)) {
+                        status = hw->mac.ops.acquire_swfw_sync(hw,
+                                                        IXGBE_GSSR_MAC_CSR_SM);
+                        if (status != IXGBE_SUCCESS) {
+                                status = IXGBE_ERR_SWFW_SYNC;
+                                goto out;
+                        }
+
+                        got_lock = TRUE;
+                }
+
                 /* Restart link */
-                autoc |= IXGBE_AUTOC_AN_RESTART;
                 IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc);
+                hw->mac.cached_autoc = autoc;
+                (void) ixgbe_reset_pipeline_82599(hw);
 
+                if (got_lock) {
+                        hw->mac.ops.release_swfw_sync(hw,
+                                                      IXGBE_GSSR_MAC_CSR_SM);
+                        got_lock = FALSE;
+                }
+
                 /* Only poll for autoneg to complete if specified to do so */
                 if (autoneg_wait_to_complete) {
                         if (link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR ||
                             link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN ||
                             link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_SGMII) {

@@ -934,32 +1086,27 @@
 
 /**
  *  ixgbe_setup_copper_link_82599 - Set the PHY autoneg advertised field
  *  @hw: pointer to hardware structure
  *  @speed: new link speed
- *  @autoneg: TRUE if autonegotiation enabled
  *  @autoneg_wait_to_complete: TRUE if waiting is needed to complete
  *
  *  Restarts link on PHY and MAC based on settings passed in.
  **/
 static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw,
                                          ixgbe_link_speed speed,
-                                         bool autoneg,
                                          bool autoneg_wait_to_complete)
 {
         s32 status;
 
         DEBUGFUNC("ixgbe_setup_copper_link_82599");
 
         /* Setup the PHY according to input speed */
-        status = hw->phy.ops.setup_link_speed(hw, speed, autoneg,
+        status = hw->phy.ops.setup_link_speed(hw, speed,
                                               autoneg_wait_to_complete);
-        if (status == IXGBE_SUCCESS) {
                 /* Set up MAC */
-                status =
-                    ixgbe_start_mac_link_82599(hw, autoneg_wait_to_complete);
-        }
+        (void) ixgbe_start_mac_link_82599(hw, autoneg_wait_to_complete);
 
         return status;
 }
 
 /**

@@ -1056,19 +1203,50 @@
          * stored off yet.  Otherwise restore the stored original
          * values since the reset operation sets back to defaults.
          */
         autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
         autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2);
+
+        /* Enable link if disabled in NVM */
+        if (autoc2 & IXGBE_AUTOC2_LINK_DISABLE_MASK) {
+                autoc2 &= ~IXGBE_AUTOC2_LINK_DISABLE_MASK;
+                IXGBE_WRITE_REG(hw, IXGBE_AUTOC2, autoc2);
+                IXGBE_WRITE_FLUSH(hw);
+        }
+
         if (hw->mac.orig_link_settings_stored == FALSE) {
                 hw->mac.orig_autoc = autoc;
                 hw->mac.orig_autoc2 = autoc2;
+                hw->mac.cached_autoc = autoc;
                 hw->mac.orig_link_settings_stored = TRUE;
         } else {
-                if (autoc != hw->mac.orig_autoc)
-                        IXGBE_WRITE_REG(hw, IXGBE_AUTOC, (hw->mac.orig_autoc |
-                                        IXGBE_AUTOC_AN_RESTART));
+                if (autoc != hw->mac.orig_autoc) {
+                        /* Need SW/FW semaphore around AUTOC writes if LESM is
+                         * on, likewise reset_pipeline requires us to hold
+                         * this lock as it also writes to AUTOC.
+                         */
+                        bool got_lock = FALSE;
+                        if (ixgbe_verify_lesm_fw_enabled_82599(hw)) {
+                                status = hw->mac.ops.acquire_swfw_sync(hw,
+                                                        IXGBE_GSSR_MAC_CSR_SM);
+                                if (status != IXGBE_SUCCESS) {
+                                        status = IXGBE_ERR_SWFW_SYNC;
+                                        goto reset_hw_out;
+                                }
 
+                                got_lock = TRUE;
+                        }
+
+                        IXGBE_WRITE_REG(hw, IXGBE_AUTOC, hw->mac.orig_autoc);
+                        hw->mac.cached_autoc = hw->mac.orig_autoc;
+                        (void) ixgbe_reset_pipeline_82599(hw);
+
+                        if (got_lock)
+                                hw->mac.ops.release_swfw_sync(hw,
+                                                      IXGBE_GSSR_MAC_CSR_SM);
+                }
+
                 if ((autoc2 & IXGBE_AUTOC2_UPPER_MASK) !=
                     (hw->mac.orig_autoc2 & IXGBE_AUTOC2_UPPER_MASK)) {
                         autoc2 &= ~IXGBE_AUTOC2_UPPER_MASK;
                         autoc2 |= (hw->mac.orig_autoc2 &
                                    IXGBE_AUTOC2_UPPER_MASK);

@@ -1168,11 +1346,11 @@
         /* Poll init-done after we write FDIRCTRL register */
         for (i = 0; i < IXGBE_FDIR_INIT_DONE_POLL; i++) {
                 if (IXGBE_READ_REG(hw, IXGBE_FDIRCTRL) &
                                    IXGBE_FDIRCTRL_INIT_DONE)
                         break;
-                usec_delay(10);
+                msec_delay(1);
         }
         if (i >= IXGBE_FDIR_INIT_DONE_POLL) {
                 DEBUGOUT("Flow Director Signature poll time exceeded!\n");
                 return IXGBE_ERR_FDIR_REINIT_FAILED;
         }

@@ -2103,11 +2281,11 @@
  *  for SFI devices. All 82599 SFI devices should have version 0.6 or higher.
  *
  *  Returns IXGBE_ERR_EEPROM_VERSION if the FW is not present or
  *  if the FW version is not supported.
  **/
-static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw)
+s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw)
 {
         s32 status = IXGBE_ERR_EEPROM_VERSION;
         u16 fw_offset, fw_ptp_cfg_offset;
         u16 fw_version = 0;
 

@@ -2252,6 +2430,57 @@
                 ret_val = ixgbe_read_eeprom_bit_bang_generic(hw, offset, data);
 
         return ret_val;
 }
 
+/**
+ * ixgbe_reset_pipeline_82599 - perform pipeline reset
+ *
+ *  @hw: pointer to hardware structure
+ *
+ * Reset pipeline by asserting Restart_AN together with LMS change to ensure
+ * full pipeline reset
+ **/
+s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw)
+{
+        s32 ret_val;
+        u32 anlp1_reg = 0;
+        u32 i, autoc_reg, autoc2_reg;
 
+        /* Enable link if disabled in NVM */
+        autoc2_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC2);
+        if (autoc2_reg & IXGBE_AUTOC2_LINK_DISABLE_MASK) {
+                autoc2_reg &= ~IXGBE_AUTOC2_LINK_DISABLE_MASK;
+                IXGBE_WRITE_REG(hw, IXGBE_AUTOC2, autoc2_reg);
+                IXGBE_WRITE_FLUSH(hw);
+        }
+
+        autoc_reg = hw->mac.cached_autoc;
+        autoc_reg |= IXGBE_AUTOC_AN_RESTART;
+        /* Write AUTOC register with toggled LMS[2] bit and Restart_AN */
+        IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg ^ IXGBE_AUTOC_LMS_1G_AN);
+        /* Wait for AN to leave state 0 */
+        for (i = 0; i < 10; i++) {
+                msec_delay(4);
+                anlp1_reg = IXGBE_READ_REG(hw, IXGBE_ANLP1);
+                if (anlp1_reg & IXGBE_ANLP1_AN_STATE_MASK)
+                        break;
+        }
+
+        if (!(anlp1_reg & IXGBE_ANLP1_AN_STATE_MASK)) {
+                DEBUGOUT("auto negotiation not completed\n");
+                ret_val = IXGBE_ERR_RESET_FAILED;
+                goto reset_pipeline_out;
+        }
+
+        ret_val = IXGBE_SUCCESS;
+
+reset_pipeline_out:
+        /* Write AUTOC register with original LMS field and Restart_AN */
+        IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg);
+        IXGBE_WRITE_FLUSH(hw);
+
+        return ret_val;
+}
+
+
+