net/hns3: fix typos on comments
[dpdk.git] / drivers / net / txgbe / base / txgbe_hw.c
index 7a6c309..3e7f2f9 100644 (file)
@@ -6,6 +6,7 @@
 #include "txgbe_mbx.h"
 #include "txgbe_phy.h"
 #include "txgbe_dcb.h"
+#include "txgbe_vf.h"
 #include "txgbe_eeprom.h"
 #include "txgbe_mng.h"
 #include "txgbe_hw.h"
@@ -59,9 +60,9 @@ bool txgbe_device_supports_autoneg_fc(struct txgbe_hw *hw)
                break;
        case txgbe_media_type_copper:
                /* only some copper devices support flow control autoneg */
-               switch (hw->device_id) {
-               case TXGBE_DEV_ID_RAPTOR_XAUI:
-               case TXGBE_DEV_ID_RAPTOR_SGMII:
+               switch (hw->subsystem_device_id & 0xFF) {
+               case TXGBE_DEV_ID_XAUI:
+               case TXGBE_DEV_ID_SGMII:
                        supported = true;
                        break;
                default:
@@ -90,7 +91,6 @@ s32 txgbe_setup_fc(struct txgbe_hw *hw)
        u16 reg_cu = 0;
        u32 value = 0;
        u64 reg_bp = 0;
-       bool locked = false;
 
        DEBUGFUNC("txgbe_setup_fc");
 
@@ -108,29 +108,6 @@ s32 txgbe_setup_fc(struct txgbe_hw *hw)
        if (hw->fc.requested_mode == txgbe_fc_default)
                hw->fc.requested_mode = txgbe_fc_full;
 
-       /*
-        * Set up the 1G and 10G flow control advertisement registers so the
-        * HW will be able to do fc autoneg once the cable is plugged in.  If
-        * we link at 10G, the 1G advertisement is harmless and vice versa.
-        */
-       switch (hw->phy.media_type) {
-       case txgbe_media_type_backplane:
-               /* some MAC's need RMW protection on AUTOC */
-               err = hw->mac.prot_autoc_read(hw, &locked, &reg_bp);
-               if (err != 0)
-                       goto out;
-
-               /* fall through - only backplane uses autoc */
-       case txgbe_media_type_fiber_qsfp:
-       case txgbe_media_type_fiber:
-       case txgbe_media_type_copper:
-               hw->phy.read_reg(hw, TXGBE_MD_AUTO_NEG_ADVT,
-                                    TXGBE_MD_DEV_AUTO_NEG, &reg_cu);
-               break;
-       default:
-               break;
-       }
-
        /*
         * The possible values of fc.requested_mode are:
         * 0: Flow control is completely disabled
@@ -144,13 +121,6 @@ s32 txgbe_setup_fc(struct txgbe_hw *hw)
        switch (hw->fc.requested_mode) {
        case txgbe_fc_none:
                /* Flow control completely disabled by software override. */
-               reg &= ~(SR_MII_MMD_AN_ADV_PAUSE_SYM |
-                       SR_MII_MMD_AN_ADV_PAUSE_ASM);
-               if (hw->phy.media_type == txgbe_media_type_backplane)
-                       reg_bp &= ~(TXGBE_AUTOC_SYM_PAUSE |
-                                   TXGBE_AUTOC_ASM_PAUSE);
-               else if (hw->phy.media_type == txgbe_media_type_copper)
-                       reg_cu &= ~(TXGBE_TAF_SYM_PAUSE | TXGBE_TAF_ASM_PAUSE);
                break;
        case txgbe_fc_tx_pause:
                /*
@@ -158,15 +128,6 @@ s32 txgbe_setup_fc(struct txgbe_hw *hw)
                 * disabled by software override.
                 */
                reg |= SR_MII_MMD_AN_ADV_PAUSE_ASM;
-               reg &= ~SR_MII_MMD_AN_ADV_PAUSE_SYM;
-               if (hw->phy.media_type == txgbe_media_type_backplane) {
-                       reg_bp |= TXGBE_AUTOC_ASM_PAUSE;
-                       reg_bp &= ~TXGBE_AUTOC_SYM_PAUSE;
-               } else if (hw->phy.media_type == txgbe_media_type_copper) {
-                       reg_cu |= TXGBE_TAF_ASM_PAUSE;
-                       reg_cu &= ~TXGBE_TAF_SYM_PAUSE;
-               }
-               reg |= SR_MII_MMD_AN_ADV_PAUSE_ASM;
                reg_bp |= SR_AN_MMD_ADV_REG1_PAUSE_ASM;
                break;
        case txgbe_fc_rx_pause:
@@ -181,13 +142,6 @@ s32 txgbe_setup_fc(struct txgbe_hw *hw)
                 */
        case txgbe_fc_full:
                /* Flow control (both Rx and Tx) is enabled by SW override. */
-               reg |= SR_MII_MMD_AN_ADV_PAUSE_SYM |
-                       SR_MII_MMD_AN_ADV_PAUSE_ASM;
-               if (hw->phy.media_type == txgbe_media_type_backplane)
-                       reg_bp |= TXGBE_AUTOC_SYM_PAUSE |
-                                 TXGBE_AUTOC_ASM_PAUSE;
-               else if (hw->phy.media_type == txgbe_media_type_copper)
-                       reg_cu |= TXGBE_TAF_SYM_PAUSE | TXGBE_TAF_ASM_PAUSE;
                reg |= SR_MII_MMD_AN_ADV_PAUSE_SYM |
                        SR_MII_MMD_AN_ADV_PAUSE_ASM;
                reg_bp |= SR_AN_MMD_ADV_REG1_PAUSE_SYM |
@@ -322,6 +276,9 @@ s32 txgbe_init_hw(struct txgbe_hw *hw)
 
        DEBUGFUNC("txgbe_init_hw");
 
+       /* Get firmware version */
+       hw->phy.get_fw_version(hw, &hw->fw_version);
+
        /* Reset the hardware */
        status = hw->mac.reset_hw(hw);
        if (status == 0 || status == TXGBE_ERR_SFP_NOT_PRESENT) {
@@ -560,6 +517,52 @@ s32 txgbe_stop_hw(struct txgbe_hw *hw)
        return 0;
 }
 
+/**
+ *  txgbe_led_on - Turns on the software controllable LEDs.
+ *  @hw: pointer to hardware structure
+ *  @index: led number to turn on
+ **/
+s32 txgbe_led_on(struct txgbe_hw *hw, u32 index)
+{
+       u32 led_reg = rd32(hw, TXGBE_LEDCTL);
+
+       DEBUGFUNC("txgbe_led_on");
+
+       if (index > 4)
+               return TXGBE_ERR_PARAM;
+
+       /* To turn on the LED, set mode to ON. */
+       led_reg |= TXGBE_LEDCTL_SEL(index);
+       led_reg |= TXGBE_LEDCTL_ORD(index);
+       wr32(hw, TXGBE_LEDCTL, led_reg);
+       txgbe_flush(hw);
+
+       return 0;
+}
+
+/**
+ *  txgbe_led_off - Turns off the software controllable LEDs.
+ *  @hw: pointer to hardware structure
+ *  @index: led number to turn off
+ **/
+s32 txgbe_led_off(struct txgbe_hw *hw, u32 index)
+{
+       u32 led_reg = rd32(hw, TXGBE_LEDCTL);
+
+       DEBUGFUNC("txgbe_led_off");
+
+       if (index > 4)
+               return TXGBE_ERR_PARAM;
+
+       /* To turn off the LED, set mode to OFF. */
+       led_reg &= ~(TXGBE_LEDCTL_SEL(index));
+       led_reg &= ~(TXGBE_LEDCTL_ORD(index));
+       wr32(hw, TXGBE_LEDCTL, led_reg);
+       txgbe_flush(hw);
+
+       return 0;
+}
+
 /**
  *  txgbe_validate_mac_addr - Validate MAC address
  *  @mac_addr: pointer to MAC address.
@@ -1016,6 +1019,205 @@ out:
        return err;
 }
 
+/**
+ *  txgbe_negotiate_fc - Negotiate flow control
+ *  @hw: pointer to hardware structure
+ *  @adv_reg: flow control advertised settings
+ *  @lp_reg: link partner's flow control settings
+ *  @adv_sym: symmetric pause bit in advertisement
+ *  @adv_asm: asymmetric pause bit in advertisement
+ *  @lp_sym: symmetric pause bit in link partner advertisement
+ *  @lp_asm: asymmetric pause bit in link partner advertisement
+ *
+ *  Find the intersection between advertised settings and link partner's
+ *  advertised settings
+ **/
+s32 txgbe_negotiate_fc(struct txgbe_hw *hw, u32 adv_reg, u32 lp_reg,
+                      u32 adv_sym, u32 adv_asm, u32 lp_sym, u32 lp_asm)
+{
+       if ((!(adv_reg)) ||  (!(lp_reg))) {
+               DEBUGOUT("Local or link partner's advertised flow control "
+                             "settings are NULL. Local: %x, link partner: %x\n",
+                             adv_reg, lp_reg);
+               return TXGBE_ERR_FC_NOT_NEGOTIATED;
+       }
+
+       if ((adv_reg & adv_sym) && (lp_reg & lp_sym)) {
+               /*
+                * Now we need to check if the user selected Rx ONLY
+                * of pause frames.  In this case, we had to advertise
+                * FULL flow control because we could not advertise RX
+                * ONLY. Hence, we must now check to see if we need to
+                * turn OFF the TRANSMISSION of PAUSE frames.
+                */
+               if (hw->fc.requested_mode == txgbe_fc_full) {
+                       hw->fc.current_mode = txgbe_fc_full;
+                       DEBUGOUT("Flow Control = FULL.\n");
+               } else {
+                       hw->fc.current_mode = txgbe_fc_rx_pause;
+                       DEBUGOUT("Flow Control=RX PAUSE frames only\n");
+               }
+       } else if (!(adv_reg & adv_sym) && (adv_reg & adv_asm) &&
+                  (lp_reg & lp_sym) && (lp_reg & lp_asm)) {
+               hw->fc.current_mode = txgbe_fc_tx_pause;
+               DEBUGOUT("Flow Control = TX PAUSE frames only.\n");
+       } else if ((adv_reg & adv_sym) && (adv_reg & adv_asm) &&
+                  !(lp_reg & lp_sym) && (lp_reg & lp_asm)) {
+               hw->fc.current_mode = txgbe_fc_rx_pause;
+               DEBUGOUT("Flow Control = RX PAUSE frames only.\n");
+       } else {
+               hw->fc.current_mode = txgbe_fc_none;
+               DEBUGOUT("Flow Control = NONE.\n");
+       }
+       return 0;
+}
+
+/**
+ *  txgbe_fc_autoneg_fiber - Enable flow control on 1 gig fiber
+ *  @hw: pointer to hardware structure
+ *
+ *  Enable flow control according on 1 gig fiber.
+ **/
+STATIC s32 txgbe_fc_autoneg_fiber(struct txgbe_hw *hw)
+{
+       u32 pcs_anadv_reg, pcs_lpab_reg;
+       s32 err = TXGBE_ERR_FC_NOT_NEGOTIATED;
+
+       /*
+        * On multispeed fiber at 1g, bail out if
+        * - link is up but AN did not complete, or if
+        * - link is up and AN completed but timed out
+        */
+
+       pcs_anadv_reg = rd32_epcs(hw, SR_MII_MMD_AN_ADV);
+       pcs_lpab_reg = rd32_epcs(hw, SR_MII_MMD_LP_BABL);
+
+       err =  txgbe_negotiate_fc(hw, pcs_anadv_reg,
+                                     pcs_lpab_reg,
+                                     SR_MII_MMD_AN_ADV_PAUSE_SYM,
+                                     SR_MII_MMD_AN_ADV_PAUSE_ASM,
+                                     SR_MII_MMD_AN_ADV_PAUSE_SYM,
+                                     SR_MII_MMD_AN_ADV_PAUSE_ASM);
+
+       return err;
+}
+
+/**
+ *  txgbe_fc_autoneg_backplane - Enable flow control IEEE clause 37
+ *  @hw: pointer to hardware structure
+ *
+ *  Enable flow control according to IEEE clause 37.
+ **/
+STATIC s32 txgbe_fc_autoneg_backplane(struct txgbe_hw *hw)
+{
+       u32 anlp1_reg, autoc_reg;
+       s32 err = TXGBE_ERR_FC_NOT_NEGOTIATED;
+
+       /*
+        * Read the 10g AN autoc and LP ability registers and resolve
+        * local flow control settings accordingly
+        */
+       autoc_reg = rd32_epcs(hw, SR_AN_MMD_ADV_REG1);
+       anlp1_reg = rd32_epcs(hw, SR_AN_MMD_LP_ABL1);
+
+       err = txgbe_negotiate_fc(hw, autoc_reg,
+               anlp1_reg,
+               SR_AN_MMD_ADV_REG1_PAUSE_SYM,
+               SR_AN_MMD_ADV_REG1_PAUSE_ASM,
+               SR_AN_MMD_ADV_REG1_PAUSE_SYM,
+               SR_AN_MMD_ADV_REG1_PAUSE_ASM);
+
+       return err;
+}
+
+/**
+ *  txgbe_fc_autoneg_copper - Enable flow control IEEE clause 37
+ *  @hw: pointer to hardware structure
+ *
+ *  Enable flow control according to IEEE clause 37.
+ **/
+STATIC s32 txgbe_fc_autoneg_copper(struct txgbe_hw *hw)
+{
+       u16 technology_ability_reg = 0;
+       u16 lp_technology_ability_reg = 0;
+
+       hw->phy.read_reg(hw, TXGBE_MD_AUTO_NEG_ADVT,
+                            TXGBE_MD_DEV_AUTO_NEG,
+                            &technology_ability_reg);
+       hw->phy.read_reg(hw, TXGBE_MD_AUTO_NEG_LP,
+                            TXGBE_MD_DEV_AUTO_NEG,
+                            &lp_technology_ability_reg);
+
+       return txgbe_negotiate_fc(hw, (u32)technology_ability_reg,
+                                 (u32)lp_technology_ability_reg,
+                                 TXGBE_TAF_SYM_PAUSE, TXGBE_TAF_ASM_PAUSE,
+                                 TXGBE_TAF_SYM_PAUSE, TXGBE_TAF_ASM_PAUSE);
+}
+
+/**
+ *  txgbe_fc_autoneg - Configure flow control
+ *  @hw: pointer to hardware structure
+ *
+ *  Compares our advertised flow control capabilities to those advertised by
+ *  our link partner, and determines the proper flow control mode to use.
+ **/
+void txgbe_fc_autoneg(struct txgbe_hw *hw)
+{
+       s32 err = TXGBE_ERR_FC_NOT_NEGOTIATED;
+       u32 speed;
+       bool link_up;
+
+       DEBUGFUNC("txgbe_fc_autoneg");
+
+       /*
+        * AN should have completed when the cable was plugged in.
+        * Look for reasons to bail out.  Bail out if:
+        * - FC autoneg is disabled, or if
+        * - link is not up.
+        */
+       if (hw->fc.disable_fc_autoneg) {
+               DEBUGOUT("Flow control autoneg is disabled");
+               goto out;
+       }
+
+       hw->mac.check_link(hw, &speed, &link_up, false);
+       if (!link_up) {
+               DEBUGOUT("The link is down");
+               goto out;
+       }
+
+       switch (hw->phy.media_type) {
+       /* Autoneg flow control on fiber adapters */
+       case txgbe_media_type_fiber_qsfp:
+       case txgbe_media_type_fiber:
+               if (speed == TXGBE_LINK_SPEED_1GB_FULL)
+                       err = txgbe_fc_autoneg_fiber(hw);
+               break;
+
+       /* Autoneg flow control on backplane adapters */
+       case txgbe_media_type_backplane:
+               err = txgbe_fc_autoneg_backplane(hw);
+               break;
+
+       /* Autoneg flow control on copper adapters */
+       case txgbe_media_type_copper:
+               if (txgbe_device_supports_autoneg_fc(hw))
+                       err = txgbe_fc_autoneg_copper(hw);
+               break;
+
+       default:
+               break;
+       }
+
+out:
+       if (err == 0) {
+               hw->fc.fc_was_autonegged = true;
+       } else {
+               hw->fc.fc_was_autonegged = false;
+               hw->fc.current_mode = hw->fc.requested_mode;
+       }
+}
+
 /**
  *  txgbe_acquire_swfw_sync - Acquire SWFW semaphore
  *  @hw: pointer to hardware structure
@@ -2246,6 +2448,9 @@ s32 txgbe_init_shared_code(struct txgbe_hw *hw)
        case txgbe_mac_raptor:
                status = txgbe_init_ops_pf(hw);
                break;
+       case txgbe_mac_raptor_vf:
+               status = txgbe_init_ops_vf(hw);
+               break;
        default:
                status = TXGBE_ERR_DEVICE_NOT_SUPPORTED;
                break;
@@ -2276,26 +2481,12 @@ s32 txgbe_set_mac_type(struct txgbe_hw *hw)
        }
 
        switch (hw->device_id) {
-       case TXGBE_DEV_ID_RAPTOR_KR_KX_KX4:
-               hw->phy.media_type = txgbe_media_type_backplane;
+       case TXGBE_DEV_ID_SP1000:
+       case TXGBE_DEV_ID_WX1820:
                hw->mac.type = txgbe_mac_raptor;
                break;
-       case TXGBE_DEV_ID_RAPTOR_XAUI:
-       case TXGBE_DEV_ID_RAPTOR_SGMII:
-               hw->phy.media_type = txgbe_media_type_copper;
-               hw->mac.type = txgbe_mac_raptor;
-               break;
-       case TXGBE_DEV_ID_RAPTOR_SFP:
-       case TXGBE_DEV_ID_WX1820_SFP:
-               hw->phy.media_type = txgbe_media_type_fiber;
-               hw->mac.type = txgbe_mac_raptor;
-               break;
-       case TXGBE_DEV_ID_RAPTOR_QSFP:
-               hw->phy.media_type = txgbe_media_type_fiber_qsfp;
-               hw->mac.type = txgbe_mac_raptor;
-               break;
-       case TXGBE_DEV_ID_RAPTOR_VF:
-       case TXGBE_DEV_ID_RAPTOR_VF_HV:
+       case TXGBE_DEV_ID_SP1000_VF:
+       case TXGBE_DEV_ID_WX1820_VF:
                hw->phy.media_type = txgbe_media_type_virtual;
                hw->mac.type = txgbe_mac_raptor_vf;
                break;
@@ -2305,8 +2496,8 @@ s32 txgbe_set_mac_type(struct txgbe_hw *hw)
                break;
        }
 
-       DEBUGOUT("found mac: %d media: %d, returns: %d\n",
-                 hw->mac.type, hw->phy.media_type, err);
+       DEBUGOUT("found mac: %d, returns: %d\n",
+                 hw->mac.type, err);
        return err;
 }
 
@@ -2337,13 +2528,9 @@ void txgbe_init_mac_link_ops(struct txgbe_hw *hw)
                mac->setup_link = txgbe_setup_mac_link_multispeed_fiber;
                mac->setup_mac_link = txgbe_setup_mac_link;
                mac->set_rate_select_speed = txgbe_set_hard_rate_select_speed;
-       } else if ((hw->phy.media_type == txgbe_media_type_backplane) &&
-                   (hw->phy.smart_speed == txgbe_smart_speed_auto ||
-                    hw->phy.smart_speed == txgbe_smart_speed_on) &&
-                    !txgbe_verify_lesm_fw_enabled_raptor(hw)) {
-               mac->setup_link = txgbe_setup_mac_link_smartspeed;
        } else {
                mac->setup_link = txgbe_setup_mac_link;
+               mac->set_rate_select_speed = txgbe_set_hard_rate_select_speed;
        }
 }
 
@@ -2364,7 +2551,7 @@ s32 txgbe_init_phy_raptor(struct txgbe_hw *hw)
 
        DEBUGFUNC("txgbe_init_phy_raptor");
 
-       if (hw->device_id == TXGBE_DEV_ID_RAPTOR_QSFP) {
+       if ((hw->device_id & 0xFF) == TXGBE_DEV_ID_QSFP) {
                /* Store flag indicating I2C bus access control unit. */
                hw->phy.qsfp_shared_i2c_bus = TRUE;
 
@@ -2387,6 +2574,11 @@ s32 txgbe_init_phy_raptor(struct txgbe_hw *hw)
                                  txgbe_get_copper_link_capabilities;
        }
 
+       if (phy->media_type == txgbe_media_type_backplane) {
+               mac->kr_handle = txgbe_kr_handle;
+               mac->bp_down_event = txgbe_bp_down_event;
+       }
+
        /* Set necessary function pointers based on PHY type */
        switch (hw->phy.type) {
        case txgbe_phy_tn:
@@ -2539,10 +2731,15 @@ s32 txgbe_init_ops_pf(struct txgbe_hw *hw)
        phy->write_reg_mdi = txgbe_write_phy_reg_mdi;
        phy->setup_link = txgbe_setup_phy_link;
        phy->setup_link_speed = txgbe_setup_phy_link_speed;
+       phy->get_fw_version = txgbe_get_phy_fw_version;
        phy->read_i2c_byte = txgbe_read_i2c_byte;
        phy->write_i2c_byte = txgbe_write_i2c_byte;
+       phy->read_i2c_sff8472 = txgbe_read_i2c_sff8472;
        phy->read_i2c_eeprom = txgbe_read_i2c_eeprom;
        phy->write_i2c_eeprom = txgbe_write_i2c_eeprom;
+       phy->identify_sfp = txgbe_identify_module;
+       phy->read_i2c_byte_unlocked = txgbe_read_i2c_byte_unlocked;
+       phy->write_i2c_byte_unlocked = txgbe_write_i2c_byte_unlocked;
        phy->reset = txgbe_reset_phy;
 
        /* MAC */
@@ -2555,6 +2752,7 @@ s32 txgbe_init_ops_pf(struct txgbe_hw *hw)
        mac->acquire_swfw_sync = txgbe_acquire_swfw_sync;
        mac->release_swfw_sync = txgbe_release_swfw_sync;
        mac->reset_hw = txgbe_reset_hw;
+       mac->update_mc_addr_list = txgbe_update_mc_addr_list;
 
        mac->disable_sec_rx_path = txgbe_disable_sec_rx_path;
        mac->enable_sec_rx_path = txgbe_enable_sec_rx_path;
@@ -2588,6 +2786,7 @@ s32 txgbe_init_ops_pf(struct txgbe_hw *hw)
        /* Flow Control */
        mac->fc_enable = txgbe_fc_enable;
        mac->setup_fc = txgbe_setup_fc;
+       mac->fc_autoneg = txgbe_fc_autoneg;
 
        /* Link */
        mac->get_link_capabilities = txgbe_get_link_capabilities_raptor;
@@ -2752,6 +2951,9 @@ u32 txgbe_get_media_type_raptor(struct txgbe_hw *hw)
 
        DEBUGFUNC("txgbe_get_media_type_raptor");
 
+       if (hw->phy.ffe_set)
+               txgbe_bp_mode_set(hw);
+
        /* Detect if there is a copper PHY attached. */
        switch (hw->phy.type) {
        case txgbe_phy_cu_unknown:
@@ -2762,22 +2964,29 @@ u32 txgbe_get_media_type_raptor(struct txgbe_hw *hw)
                break;
        }
 
-       switch (hw->device_id) {
-       case TXGBE_DEV_ID_RAPTOR_KR_KX_KX4:
+       switch (hw->subsystem_device_id & 0xFF) {
+       case TXGBE_DEV_ID_KR_KX_KX4:
+       case TXGBE_DEV_ID_MAC_SGMII:
+       case TXGBE_DEV_ID_MAC_XAUI:
                /* Default device ID is mezzanine card KX/KX4 */
                media_type = txgbe_media_type_backplane;
                break;
-       case TXGBE_DEV_ID_RAPTOR_SFP:
-       case TXGBE_DEV_ID_WX1820_SFP:
+       case TXGBE_DEV_ID_SFP:
                media_type = txgbe_media_type_fiber;
                break;
-       case TXGBE_DEV_ID_RAPTOR_QSFP:
+       case TXGBE_DEV_ID_QSFP:
                media_type = txgbe_media_type_fiber_qsfp;
                break;
-       case TXGBE_DEV_ID_RAPTOR_XAUI:
-       case TXGBE_DEV_ID_RAPTOR_SGMII:
+       case TXGBE_DEV_ID_XAUI:
+       case TXGBE_DEV_ID_SGMII:
                media_type = txgbe_media_type_copper;
                break;
+       case TXGBE_DEV_ID_SFI_XAUI:
+               if (hw->bus.lan_id == 0)
+                       media_type = txgbe_media_type_fiber;
+               else
+                       media_type = txgbe_media_type_copper;
+               break;
        default:
                media_type = txgbe_media_type_unknown;
                break;
@@ -3057,13 +3266,11 @@ s32 txgbe_setup_mac_link(struct txgbe_hw *hw,
        u64 pma_pmd_10gs = autoc & TXGBE_AUTOC_10GS_PMA_PMD_MASK;
        u64 pma_pmd_1g = autoc & TXGBE_AUTOC_1G_PMA_PMD_MASK;
        u64 link_mode = autoc & TXGBE_AUTOC_LMS_MASK;
-       u64 current_autoc = autoc;
        u64 orig_autoc = 0;
-       u32 links_reg;
-       u32 i;
        u32 link_capabilities = TXGBE_LINK_SPEED_UNKNOWN;
 
        DEBUGFUNC("txgbe_setup_mac_link");
+       UNREFERENCED_PARAMETER(autoneg_wait_to_complete);
 
        /* Check to see if speed passed in is supported. */
        status = hw->mac.get_link_capabilities(hw,
@@ -3094,8 +3301,7 @@ s32 txgbe_setup_mac_link(struct txgbe_hw *hw,
                if (speed & TXGBE_LINK_SPEED_10GB_FULL) {
                        if (orig_autoc & TXGBE_AUTOC_KX4_SUPP)
                                autoc |= TXGBE_AUTOC_KX4_SUPP;
-                       if ((orig_autoc & TXGBE_AUTOC_KR_SUPP) &&
-                           !hw->phy.smart_speed_active)
+                       if (orig_autoc & TXGBE_AUTOC_KR_SUPP)
                                autoc |= TXGBE_AUTOC_KR_SUPP;
                }
                if (speed & TXGBE_LINK_SPEED_1GB_FULL)
@@ -3122,35 +3328,14 @@ s32 txgbe_setup_mac_link(struct txgbe_hw *hw,
                }
        }
 
-       if (autoc == current_autoc)
-               return status;
-
        autoc &= ~TXGBE_AUTOC_SPEED_MASK;
        autoc |= TXGBE_AUTOC_SPEED(speed);
+       autoc &= ~TXGBE_AUTOC_AUTONEG;
        autoc |= (autoneg ? TXGBE_AUTOC_AUTONEG : 0);
 
        /* Restart link */
        hw->mac.autoc_write(hw, autoc);
 
-       /* Only poll for autoneg to complete if specified to do so */
-       if (autoneg_wait_to_complete) {
-               if (link_mode == TXGBE_AUTOC_LMS_KX4_KX_KR ||
-                   link_mode == TXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN ||
-                   link_mode == TXGBE_AUTOC_LMS_KX4_KX_KR_SGMII) {
-                       links_reg = 0; /*Just in case Autoneg time=0*/
-                       for (i = 0; i < TXGBE_AUTO_NEG_TIME; i++) {
-                               links_reg = rd32(hw, TXGBE_PORTSTAT);
-                               if (links_reg & TXGBE_PORTSTAT_UP)
-                                       break;
-                               msec_delay(100);
-                       }
-                       if (!(links_reg & TXGBE_PORTSTAT_UP)) {
-                               status = TXGBE_ERR_AUTONEG_NOT_COMPLETE;
-                               DEBUGOUT("Autoneg did not complete.\n");
-                       }
-               }
-       }
-
        /* Add delay to filter out noises during initial link setup */
        msec_delay(50);
 
@@ -3263,6 +3448,7 @@ txgbe_reset_misc(struct txgbe_hw *hw)
        /* enable mac transmitter */
        wr32m(hw, TXGBE_MACTXCFG, TXGBE_MACTXCFG_TXE, TXGBE_MACTXCFG_TXE);
 
+       hw->mac.autoc = hw->mac.orig_autoc;
        for (i = 0; i < 4; i++)
                wr32m(hw, TXGBE_IVAR(i), 0x80808080, 0);
 }
@@ -3356,12 +3542,19 @@ mac_reset_top:
         */
        if (!hw->mac.orig_link_settings_stored) {
                hw->mac.orig_autoc = hw->mac.autoc_read(hw);
-               hw->mac.autoc_write(hw, hw->mac.orig_autoc);
                hw->mac.orig_link_settings_stored = true;
        } else {
                hw->mac.orig_autoc = autoc;
        }
 
+       if (hw->phy.ffe_set) {
+               /* Make sure phy power is up */
+               msec_delay(50);
+
+               /* A temporary solution to set phy */
+               txgbe_set_phy_temp(hw);
+       }
+
        /* Store the permanent mac address */
        hw->mac.get_mac_addr(hw, hw->mac.perm_addr);
 
@@ -3399,6 +3592,93 @@ mac_reset_top:
        return status;
 }
 
+/**
+ * txgbe_fdir_check_cmd_complete - poll to check whether FDIRPICMD is complete
+ * @hw: pointer to hardware structure
+ * @fdircmd: current value of FDIRCMD register
+ */
+static s32 txgbe_fdir_check_cmd_complete(struct txgbe_hw *hw, u32 *fdircmd)
+{
+       int i;
+
+       for (i = 0; i < TXGBE_FDIRCMD_CMD_POLL; i++) {
+               *fdircmd = rd32(hw, TXGBE_FDIRPICMD);
+               if (!(*fdircmd & TXGBE_FDIRPICMD_OP_MASK))
+                       return 0;
+               usec_delay(10);
+       }
+
+       return TXGBE_ERR_FDIR_CMD_INCOMPLETE;
+}
+
+/**
+ *  txgbe_reinit_fdir_tables - Reinitialize Flow Director tables.
+ *  @hw: pointer to hardware structure
+ **/
+s32 txgbe_reinit_fdir_tables(struct txgbe_hw *hw)
+{
+       s32 err;
+       int i;
+       u32 fdirctrl = rd32(hw, TXGBE_FDIRCTL);
+       u32 fdircmd;
+       fdirctrl &= ~TXGBE_FDIRCTL_INITDONE;
+
+       DEBUGFUNC("txgbe_reinit_fdir_tables");
+
+       /*
+        * Before starting reinitialization process,
+        * FDIRPICMD.OP must be zero.
+        */
+       err = txgbe_fdir_check_cmd_complete(hw, &fdircmd);
+       if (err) {
+               DEBUGOUT("Flow Director previous command did not complete, aborting table re-initialization.\n");
+               return err;
+       }
+
+       wr32(hw, TXGBE_FDIRFREE, 0);
+       txgbe_flush(hw);
+       /*
+        * adapters flow director init flow cannot be restarted,
+        * Workaround silicon errata by performing the following steps
+        * before re-writing the FDIRCTL control register with the same value.
+        * - write 1 to bit 8 of FDIRPICMD register &
+        * - write 0 to bit 8 of FDIRPICMD register
+        */
+       wr32m(hw, TXGBE_FDIRPICMD, TXGBE_FDIRPICMD_CLR, TXGBE_FDIRPICMD_CLR);
+       txgbe_flush(hw);
+       wr32m(hw, TXGBE_FDIRPICMD, TXGBE_FDIRPICMD_CLR, 0);
+       txgbe_flush(hw);
+       /*
+        * Clear FDIR Hash register to clear any leftover hashes
+        * waiting to be programmed.
+        */
+       wr32(hw, TXGBE_FDIRPIHASH, 0x00);
+       txgbe_flush(hw);
+
+       wr32(hw, TXGBE_FDIRCTL, fdirctrl);
+       txgbe_flush(hw);
+
+       /* Poll init-done after we write FDIRCTL register */
+       for (i = 0; i < TXGBE_FDIR_INIT_DONE_POLL; i++) {
+               if (rd32m(hw, TXGBE_FDIRCTL, TXGBE_FDIRCTL_INITDONE))
+                       break;
+               msec_delay(1);
+       }
+       if (i >= TXGBE_FDIR_INIT_DONE_POLL) {
+               DEBUGOUT("Flow Director Signature poll time exceeded!\n");
+               return TXGBE_ERR_FDIR_REINIT_FAILED;
+       }
+
+       /* Clear FDIR statistics registers (read to clear) */
+       rd32(hw, TXGBE_FDIRUSED);
+       rd32(hw, TXGBE_FDIRFAIL);
+       rd32(hw, TXGBE_FDIRMATCH);
+       rd32(hw, TXGBE_FDIRMISS);
+       rd32(hw, TXGBE_FDIRLEN);
+
+       return 0;
+}
+
 /**
  *  txgbe_start_hw_raptor - Prepare hardware for Tx/Rx
  *  @hw: pointer to hardware structure