Merge branch 'mvpp2-per-cpu-buffers'
[linux-2.6-block.git] / drivers / net / ethernet / intel / ice / ice_main.c
index 63db08d9bafabfd95b5c4d66035f4dd5e7f5da03..f029aee32913b225fb6a678385e02db6fe49c42e 100644 (file)
@@ -9,7 +9,7 @@
 #include "ice_lib.h"
 #include "ice_dcb_lib.h"
 
-#define DRV_VERSION    "0.7.4-k"
+#define DRV_VERSION    "0.7.5-k"
 #define DRV_SUMMARY    "Intel(R) Ethernet Connection E800 Series Linux Driver"
 const char ice_drv_ver[] = DRV_VERSION;
 static const char ice_driver_string[] = DRV_SUMMARY;
@@ -34,19 +34,17 @@ static const struct net_device_ops ice_netdev_ops;
 static void ice_rebuild(struct ice_pf *pf);
 
 static void ice_vsi_release_all(struct ice_pf *pf);
-static void ice_update_vsi_stats(struct ice_vsi *vsi);
-static void ice_update_pf_stats(struct ice_pf *pf);
 
 /**
  * ice_get_tx_pending - returns number of Tx descriptors not processed
  * @ring: the ring of descriptors
  */
-static u32 ice_get_tx_pending(struct ice_ring *ring)
+static u16 ice_get_tx_pending(struct ice_ring *ring)
 {
-       u32 head, tail;
+       u16 head, tail;
 
        head = ring->next_to_clean;
-       tail = readl(ring->tail);
+       tail = ring->next_to_use;
 
        if (head != tail)
                return (head < tail) ?
@@ -118,10 +116,9 @@ static void ice_check_for_hang_subtask(struct ice_pf *pf)
  */
 static int ice_init_mac_fltr(struct ice_pf *pf)
 {
-       LIST_HEAD(tmp_add_list);
+       enum ice_status status;
        u8 broadcast[ETH_ALEN];
        struct ice_vsi *vsi;
-       int status;
 
        vsi = ice_find_vsi_by_type(pf, ICE_VSI_PF);
        if (!vsi)
@@ -132,8 +129,7 @@ static int ice_init_mac_fltr(struct ice_pf *pf)
         */
 
         /* Add a unicast MAC filter so the VSI can get its packets */
-       status = ice_add_mac_to_list(vsi, &tmp_add_list,
-                                    vsi->port_info->mac.perm_addr);
+       status = ice_vsi_cfg_mac_fltr(vsi, vsi->port_info->mac.perm_addr, true);
        if (status)
                goto unregister;
 
@@ -141,18 +137,11 @@ static int ice_init_mac_fltr(struct ice_pf *pf)
         * MAC address to the list as well.
         */
        eth_broadcast_addr(broadcast);
-       status = ice_add_mac_to_list(vsi, &tmp_add_list, broadcast);
+       status = ice_vsi_cfg_mac_fltr(vsi, broadcast, true);
        if (status)
-               goto free_mac_list;
-
-       /* Program MAC filters for entries in tmp_add_list */
-       status = ice_add_mac(&pf->hw, &tmp_add_list);
-       if (status)
-               status = -ENOMEM;
-
-free_mac_list:
-       ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list);
+               goto unregister;
 
+       return 0;
 unregister:
        /* We aren't useful with no MAC filters, so unregister if we
         * had an error
@@ -166,7 +155,7 @@ unregister:
                vsi->netdev = NULL;
        }
 
-       return status;
+       return -EIO;
 }
 
 /**
@@ -447,13 +436,13 @@ static void ice_dis_vsi(struct ice_vsi *vsi, bool locked)
 
        if (vsi->type == ICE_VSI_PF && vsi->netdev) {
                if (netif_running(vsi->netdev)) {
-                       if (!locked) {
+                       if (!locked)
                                rtnl_lock();
-                               vsi->netdev->netdev_ops->ndo_stop(vsi->netdev);
+
+                       ice_stop(vsi->netdev);
+
+                       if (!locked)
                                rtnl_unlock();
-                       } else {
-                               vsi->netdev->netdev_ops->ndo_stop(vsi->netdev);
-                       }
                } else {
                        ice_vsi_close(vsi);
                }
@@ -488,6 +477,7 @@ static void
 ice_prepare_for_reset(struct ice_pf *pf)
 {
        struct ice_hw *hw = &pf->hw;
+       int i;
 
        /* already prepared for reset */
        if (test_bit(__ICE_PREPARED_FOR_RESET, pf->state))
@@ -497,6 +487,10 @@ ice_prepare_for_reset(struct ice_pf *pf)
        if (ice_check_sq_alive(hw, &hw->mailboxq))
                ice_vc_notify_reset(pf);
 
+       /* Disable VFs until reset is completed */
+       for (i = 0; i < pf->num_alloc_vfs; i++)
+               ice_set_vf_state_qs_dis(&pf->vf[i]);
+
        /* disable the VSIs and their queues that are not already DOWN */
        ice_pf_dis_all_vsi(pf, false);
 
@@ -810,6 +804,20 @@ ice_link_event(struct ice_pf *pf, struct ice_port_info *pi, bool link_up,
        if (!vsi || !vsi->port_info)
                return -EINVAL;
 
+       /* turn off PHY if media was removed */
+       if (!test_bit(ICE_FLAG_NO_MEDIA, pf->flags) &&
+           !(pi->phy.link_info.link_info & ICE_AQ_MEDIA_AVAILABLE)) {
+               set_bit(ICE_FLAG_NO_MEDIA, pf->flags);
+
+               result = ice_aq_set_link_restart_an(pi, false, NULL);
+               if (result) {
+                       dev_dbg(&pf->pdev->dev,
+                               "Failed to set link down, VSI %d error %d\n",
+                               vsi->vsi_num, result);
+                       return result;
+               }
+       }
+
        ice_vsi_link_event(vsi, link_up);
        ice_print_link_msg(vsi, link_up);
 
@@ -1307,13 +1315,133 @@ static void ice_handle_mdd_event(struct ice_pf *pf)
 
                if (vf_mdd_detected) {
                        vf->num_mdd_events++;
-                       if (vf->num_mdd_events > 1)
-                               dev_info(&pf->pdev->dev, "VF %d has had %llu MDD events since last boot\n",
+                       if (vf->num_mdd_events &&
+                           vf->num_mdd_events <= ICE_MDD_EVENTS_THRESHOLD)
+                               dev_info(&pf->pdev->dev,
+                                        "VF %d has had %llu MDD events since last boot, Admin might need to reload AVF driver with this number of events\n",
                                         i, vf->num_mdd_events);
                }
        }
 }
 
+/**
+ * ice_force_phys_link_state - Force the physical link state
+ * @vsi: VSI to force the physical link state to up/down
+ * @link_up: true/false indicates to set the physical link to up/down
+ *
+ * Force the physical link state by getting the current PHY capabilities from
+ * hardware and setting the PHY config based on the determined capabilities. If
+ * link changes a link event will be triggered because both the Enable Automatic
+ * Link Update and LESM Enable bits are set when setting the PHY capabilities.
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int ice_force_phys_link_state(struct ice_vsi *vsi, bool link_up)
+{
+       struct ice_aqc_get_phy_caps_data *pcaps;
+       struct ice_aqc_set_phy_cfg_data *cfg;
+       struct ice_port_info *pi;
+       struct device *dev;
+       int retcode;
+
+       if (!vsi || !vsi->port_info || !vsi->back)
+               return -EINVAL;
+       if (vsi->type != ICE_VSI_PF)
+               return 0;
+
+       dev = &vsi->back->pdev->dev;
+
+       pi = vsi->port_info;
+
+       pcaps = devm_kzalloc(dev, sizeof(*pcaps), GFP_KERNEL);
+       if (!pcaps)
+               return -ENOMEM;
+
+       retcode = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_SW_CFG, pcaps,
+                                     NULL);
+       if (retcode) {
+               dev_err(dev,
+                       "Failed to get phy capabilities, VSI %d error %d\n",
+                       vsi->vsi_num, retcode);
+               retcode = -EIO;
+               goto out;
+       }
+
+       /* No change in link */
+       if (link_up == !!(pcaps->caps & ICE_AQC_PHY_EN_LINK) &&
+           link_up == !!(pi->phy.link_info.link_info & ICE_AQ_LINK_UP))
+               goto out;
+
+       cfg = devm_kzalloc(dev, sizeof(*cfg), GFP_KERNEL);
+       if (!cfg) {
+               retcode = -ENOMEM;
+               goto out;
+       }
+
+       cfg->phy_type_low = pcaps->phy_type_low;
+       cfg->phy_type_high = pcaps->phy_type_high;
+       cfg->caps = pcaps->caps | ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
+       cfg->low_power_ctrl = pcaps->low_power_ctrl;
+       cfg->eee_cap = pcaps->eee_cap;
+       cfg->eeer_value = pcaps->eeer_value;
+       cfg->link_fec_opt = pcaps->link_fec_options;
+       if (link_up)
+               cfg->caps |= ICE_AQ_PHY_ENA_LINK;
+       else
+               cfg->caps &= ~ICE_AQ_PHY_ENA_LINK;
+
+       retcode = ice_aq_set_phy_cfg(&vsi->back->hw, pi->lport, cfg, NULL);
+       if (retcode) {
+               dev_err(dev, "Failed to set phy config, VSI %d error %d\n",
+                       vsi->vsi_num, retcode);
+               retcode = -EIO;
+       }
+
+       devm_kfree(dev, cfg);
+out:
+       devm_kfree(dev, pcaps);
+       return retcode;
+}
+
+/**
+ * ice_check_media_subtask - Check for media; bring link up if detected.
+ * @pf: pointer to PF struct
+ */
+static void ice_check_media_subtask(struct ice_pf *pf)
+{
+       struct ice_port_info *pi;
+       struct ice_vsi *vsi;
+       int err;
+
+       vsi = ice_find_vsi_by_type(pf, ICE_VSI_PF);
+       if (!vsi)
+               return;
+
+       /* No need to check for media if it's already present or the interface
+        * is down
+        */
+       if (!test_bit(ICE_FLAG_NO_MEDIA, pf->flags) ||
+           test_bit(__ICE_DOWN, vsi->state))
+               return;
+
+       /* Refresh link info and check if media is present */
+       pi = vsi->port_info;
+       err = ice_update_link_info(pi);
+       if (err)
+               return;
+
+       if (pi->phy.link_info.link_info & ICE_AQ_MEDIA_AVAILABLE) {
+               err = ice_force_phys_link_state(vsi, true);
+               if (err)
+                       return;
+               clear_bit(ICE_FLAG_NO_MEDIA, pf->flags);
+
+               /* A Link Status Event will be generated; the event handler
+                * will complete bringing the interface up
+                */
+       }
+}
+
 /**
  * ice_service_task - manage and run subtasks
  * @work: pointer to work_struct contained by the PF struct
@@ -1336,6 +1464,7 @@ static void ice_service_task(struct work_struct *work)
                return;
        }
 
+       ice_check_media_subtask(pf);
        ice_check_for_hang_subtask(pf);
        ice_sync_fltr_subtask(pf);
        ice_handle_mdd_event(pf);
@@ -1369,8 +1498,8 @@ static void ice_set_ctrlq_len(struct ice_hw *hw)
        hw->adminq.num_sq_entries = ICE_AQ_LEN;
        hw->adminq.rq_buf_size = ICE_AQ_MAX_BUF_LEN;
        hw->adminq.sq_buf_size = ICE_AQ_MAX_BUF_LEN;
-       hw->mailboxq.num_rq_entries = ICE_MBXQ_LEN;
-       hw->mailboxq.num_sq_entries = ICE_MBXQ_LEN;
+       hw->mailboxq.num_rq_entries = ICE_MBXRQ_LEN;
+       hw->mailboxq.num_sq_entries = ICE_MBXSQ_LEN;
        hw->mailboxq.rq_buf_size = ICE_MBXQ_MAX_BUF_LEN;
        hw->mailboxq.sq_buf_size = ICE_MBXQ_MAX_BUF_LEN;
 }
@@ -1409,15 +1538,11 @@ static void ice_irq_affinity_release(struct kref __always_unused *ref) {}
  */
 static int ice_vsi_ena_irq(struct ice_vsi *vsi)
 {
-       struct ice_pf *pf = vsi->back;
-       struct ice_hw *hw = &pf->hw;
+       struct ice_hw *hw = &vsi->back->hw;
+       int i;
 
-       if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) {
-               int i;
-
-               ice_for_each_q_vector(vsi, i)
-                       ice_irq_dynamic_ena(hw, vsi, vsi->q_vectors[i]);
-       }
+       ice_for_each_q_vector(vsi, i)
+               ice_irq_dynamic_ena(hw, vsi, vsi->q_vectors[i]);
 
        ice_flush(hw);
        return 0;
@@ -1665,7 +1790,7 @@ static void ice_free_irq_msix_misc(struct ice_pf *pf)
        wr32(hw, PFINT_OICR_ENA, 0);
        ice_flush(hw);
 
-       if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags) && pf->msix_entries) {
+       if (pf->msix_entries) {
                synchronize_irq(pf->msix_entries[pf->oicr_idx].vector);
                devm_free_irq(&pf->pdev->dev,
                              pf->msix_entries[pf->oicr_idx].vector, pf);
@@ -2082,16 +2207,25 @@ static void ice_deinit_pf(struct ice_pf *pf)
        ice_service_task_stop(pf);
        mutex_destroy(&pf->sw_mutex);
        mutex_destroy(&pf->avail_q_mutex);
+
+       if (pf->avail_txqs) {
+               bitmap_free(pf->avail_txqs);
+               pf->avail_txqs = NULL;
+       }
+
+       if (pf->avail_rxqs) {
+               bitmap_free(pf->avail_rxqs);
+               pf->avail_rxqs = NULL;
+       }
 }
 
 /**
  * ice_init_pf - Initialize general software structures (struct ice_pf)
  * @pf: board private structure to initialize
  */
-static void ice_init_pf(struct ice_pf *pf)
+static int ice_init_pf(struct ice_pf *pf)
 {
        bitmap_zero(pf->flags, ICE_PF_FLAGS_NBITS);
-       set_bit(ICE_FLAG_MSIX_ENA, pf->flags);
 #ifdef CONFIG_PCI_IOV
        if (pf->hw.func_caps.common_cap.sr_iov_1_1) {
                struct ice_hw *hw = &pf->hw;
@@ -2105,12 +2239,6 @@ static void ice_init_pf(struct ice_pf *pf)
        mutex_init(&pf->sw_mutex);
        mutex_init(&pf->avail_q_mutex);
 
-       /* Clear avail_[t|r]x_qs bitmaps (set all to avail) */
-       mutex_lock(&pf->avail_q_mutex);
-       bitmap_zero(pf->avail_txqs, ICE_MAX_TXQS);
-       bitmap_zero(pf->avail_rxqs, ICE_MAX_RXQS);
-       mutex_unlock(&pf->avail_q_mutex);
-
        if (pf->hw.func_caps.common_cap.rss_table_size)
                set_bit(ICE_FLAG_RSS_ENA, pf->flags);
 
@@ -2119,6 +2247,22 @@ static void ice_init_pf(struct ice_pf *pf)
        pf->serv_tmr_period = HZ;
        INIT_WORK(&pf->serv_task, ice_service_task);
        clear_bit(__ICE_SERVICE_SCHED, pf->state);
+
+       pf->max_pf_txqs = pf->hw.func_caps.common_cap.num_txq;
+       pf->max_pf_rxqs = pf->hw.func_caps.common_cap.num_rxq;
+
+       pf->avail_txqs = bitmap_zalloc(pf->max_pf_txqs, GFP_KERNEL);
+       if (!pf->avail_txqs)
+               return -ENOMEM;
+
+       pf->avail_rxqs = bitmap_zalloc(pf->max_pf_rxqs, GFP_KERNEL);
+       if (!pf->avail_rxqs) {
+               devm_kfree(&pf->pdev->dev, pf->avail_txqs);
+               pf->avail_txqs = NULL;
+               return -ENOMEM;
+       }
+
+       return 0;
 }
 
 /**
@@ -2137,13 +2281,18 @@ static int ice_ena_msix_range(struct ice_pf *pf)
 
        /* reserve one vector for miscellaneous handler */
        needed = 1;
+       if (v_left < needed)
+               goto no_hw_vecs_left_err;
        v_budget += needed;
        v_left -= needed;
 
        /* reserve vectors for LAN traffic */
-       pf->num_lan_msix = min_t(int, num_online_cpus(), v_left);
-       v_budget += pf->num_lan_msix;
-       v_left -= pf->num_lan_msix;
+       needed = min_t(int, num_online_cpus(), v_left);
+       if (v_left < needed)
+               goto no_hw_vecs_left_err;
+       pf->num_lan_msix = needed;
+       v_budget += needed;
+       v_left -= needed;
 
        pf->msix_entries = devm_kcalloc(&pf->pdev->dev, v_budget,
                                        sizeof(*pf->msix_entries), GFP_KERNEL);
@@ -2168,18 +2317,18 @@ static int ice_ena_msix_range(struct ice_pf *pf)
 
        if (v_actual < v_budget) {
                dev_warn(&pf->pdev->dev,
-                        "not enough vectors. requested = %d, obtained = %d\n",
+                        "not enough OS MSI-X vectors. requested = %d, obtained = %d\n",
                         v_budget, v_actual);
-               if (v_actual >= (pf->num_lan_msix + 1)) {
-                       pf->num_avail_sw_msix = v_actual -
-                                               (pf->num_lan_msix + 1);
-               } else if (v_actual >= 2) {
-                       pf->num_lan_msix = 1;
-                       pf->num_avail_sw_msix = v_actual - 2;
-               } else {
+/* 2 vectors for LAN (traffic + OICR) */
+#define ICE_MIN_LAN_VECS 2
+
+               if (v_actual < ICE_MIN_LAN_VECS) {
+                       /* error if we can't get minimum vectors */
                        pci_disable_msix(pf->pdev);
                        err = -ERANGE;
                        goto msix_err;
+               } else {
+                       pf->num_lan_msix = ICE_MIN_LAN_VECS;
                }
        }
 
@@ -2189,9 +2338,13 @@ msix_err:
        devm_kfree(&pf->pdev->dev, pf->msix_entries);
        goto exit_err;
 
+no_hw_vecs_left_err:
+       dev_err(&pf->pdev->dev,
+               "not enough device MSI-X vectors. requested = %d, available = %d\n",
+               needed, v_left);
+       err = -ERANGE;
 exit_err:
        pf->num_lan_msix = 0;
-       clear_bit(ICE_FLAG_MSIX_ENA, pf->flags);
        return err;
 }
 
@@ -2204,7 +2357,6 @@ static void ice_dis_msix(struct ice_pf *pf)
        pci_disable_msix(pf->pdev);
        devm_kfree(&pf->pdev->dev, pf->msix_entries);
        pf->msix_entries = NULL;
-       clear_bit(ICE_FLAG_MSIX_ENA, pf->flags);
 }
 
 /**
@@ -2213,8 +2365,7 @@ static void ice_dis_msix(struct ice_pf *pf)
  */
 static void ice_clear_interrupt_scheme(struct ice_pf *pf)
 {
-       if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags))
-               ice_dis_msix(pf);
+       ice_dis_msix(pf);
 
        if (pf->irq_tracker) {
                devm_kfree(&pf->pdev->dev, pf->irq_tracker);
@@ -2230,10 +2381,7 @@ static int ice_init_interrupt_scheme(struct ice_pf *pf)
 {
        int vectors;
 
-       if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags))
-               vectors = ice_ena_msix_range(pf);
-       else
-               return -ENODEV;
+       vectors = ice_ena_msix_range(pf);
 
        if (vectors < 0)
                return vectors;
@@ -2349,7 +2497,11 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
                 hw->fw_maj_ver, hw->fw_min_ver, hw->fw_build,
                 hw->api_maj_ver, hw->api_min_ver);
 
-       ice_init_pf(pf);
+       err = ice_init_pf(pf);
+       if (err) {
+               dev_err(dev, "ice_init_pf failed: %d\n", err);
+               goto err_init_pf_unroll;
+       }
 
        err = ice_init_pf_dcb(pf, false);
        if (err) {
@@ -2390,12 +2542,10 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
         * the misc functionality and queue processing is combined in
         * the same vector and that gets setup at open.
         */
-       if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) {
-               err = ice_req_irq_msix_misc(pf);
-               if (err) {
-                       dev_err(dev, "setup of misc vector failed: %d\n", err);
-                       goto err_init_interrupt_unroll;
-               }
+       err = ice_req_irq_msix_misc(pf);
+       if (err) {
+               dev_err(dev, "setup of misc vector failed: %d\n", err);
+               goto err_init_interrupt_unroll;
        }
 
        /* create switch struct for the switch element created by FW on boot */
@@ -2483,9 +2633,9 @@ static void ice_remove(struct pci_dev *pdev)
                        continue;
                ice_vsi_free_q_vectors(pf->vsi[i]);
        }
-       ice_clear_interrupt_scheme(pf);
        ice_deinit_pf(pf);
        ice_deinit_hw(&pf->hw);
+       ice_clear_interrupt_scheme(pf);
        pci_disable_pcie_error_reporting(pdev);
 }
 
@@ -2711,10 +2861,8 @@ static int ice_set_mac_address(struct net_device *netdev, void *pi)
        struct ice_hw *hw = &pf->hw;
        struct sockaddr *addr = pi;
        enum ice_status status;
-       LIST_HEAD(a_mac_list);
-       LIST_HEAD(r_mac_list);
        u8 flags = 0;
-       int err;
+       int err = 0;
        u8 *mac;
 
        mac = (u8 *)addr->sa_data;
@@ -2737,42 +2885,23 @@ static int ice_set_mac_address(struct net_device *netdev, void *pi)
        /* When we change the MAC address we also have to change the MAC address
         * based filter rules that were created previously for the old MAC
         * address. So first, we remove the old filter rule using ice_remove_mac
-        * and then create a new filter rule using ice_add_mac. Note that for
-        * both these operations, we first need to form a "list" of MAC
-        * addresses (even though in this case, we have only 1 MAC address to be
-        * added/removed) and this done using ice_add_mac_to_list. Depending on
-        * the ensuing operation this "list" of MAC addresses is either to be
-        * added or removed from the filter.
+        * and then create a new filter rule using ice_add_mac via
+        * ice_vsi_cfg_mac_fltr function call for both add and/or remove
+        * filters.
         */
-       err = ice_add_mac_to_list(vsi, &r_mac_list, netdev->dev_addr);
-       if (err) {
-               err = -EADDRNOTAVAIL;
-               goto free_lists;
-       }
-
-       status = ice_remove_mac(hw, &r_mac_list);
+       status = ice_vsi_cfg_mac_fltr(vsi, netdev->dev_addr, false);
        if (status) {
                err = -EADDRNOTAVAIL;
-               goto free_lists;
+               goto err_update_filters;
        }
 
-       err = ice_add_mac_to_list(vsi, &a_mac_list, mac);
-       if (err) {
-               err = -EADDRNOTAVAIL;
-               goto free_lists;
-       }
-
-       status = ice_add_mac(hw, &a_mac_list);
+       status = ice_vsi_cfg_mac_fltr(vsi, mac, true);
        if (status) {
                err = -EADDRNOTAVAIL;
-               goto free_lists;
+               goto err_update_filters;
        }
 
-free_lists:
-       /* free list entries */
-       ice_free_fltr_list(&pf->pdev->dev, &r_mac_list);
-       ice_free_fltr_list(&pf->pdev->dev, &a_mac_list);
-
+err_update_filters:
        if (err) {
                netdev_err(netdev, "can't set MAC %pM. filter update failed\n",
                           mac);
@@ -2788,8 +2917,8 @@ free_lists:
        flags = ICE_AQC_MAN_MAC_UPDATE_LAA_WOL;
        status = ice_aq_manage_mac_write(hw, mac, flags, NULL);
        if (status) {
-               netdev_err(netdev, "can't set MAC %pM. write to firmware failed.\n",
-                          mac);
+               netdev_err(netdev, "can't set MAC %pM. write to firmware failed error %d\n",
+                          mac, status);
        }
        return 0;
 }
@@ -3008,10 +3137,7 @@ static int ice_up_complete(struct ice_vsi *vsi)
        struct ice_pf *pf = vsi->back;
        int err;
 
-       if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags))
-               ice_vsi_cfg_msix(vsi);
-       else
-               return -ENOTSUPP;
+       ice_vsi_cfg_msix(vsi);
 
        /* Enable only Rx rings, Tx rings were enabled by the FW when the
         * Tx queue group list was configured and the context bits were
@@ -3132,7 +3258,7 @@ static void ice_update_vsi_ring_stats(struct ice_vsi *vsi)
  * ice_update_vsi_stats - Update VSI stats counters
  * @vsi: the VSI to be updated
  */
-static void ice_update_vsi_stats(struct ice_vsi *vsi)
+void ice_update_vsi_stats(struct ice_vsi *vsi)
 {
        struct rtnl_link_stats64 *cur_ns = &vsi->net_stats;
        struct ice_eth_stats *cur_es = &vsi->eth_stats;
@@ -3159,6 +3285,8 @@ static void ice_update_vsi_stats(struct ice_vsi *vsi)
                cur_ns->rx_errors = pf->stats.crc_errors +
                                    pf->stats.illegal_bytes;
                cur_ns->rx_length_errors = pf->stats.rx_len_errors;
+               /* record drops from the port level */
+               cur_ns->rx_missed_errors = pf->stats.eth.rx_discards;
        }
 }
 
@@ -3166,149 +3294,139 @@ static void ice_update_vsi_stats(struct ice_vsi *vsi)
  * ice_update_pf_stats - Update PF port stats counters
  * @pf: PF whose stats needs to be updated
  */
-static void ice_update_pf_stats(struct ice_pf *pf)
+void ice_update_pf_stats(struct ice_pf *pf)
 {
        struct ice_hw_port_stats *prev_ps, *cur_ps;
        struct ice_hw *hw = &pf->hw;
-       u8 pf_id;
+       u8 port;
 
+       port = hw->port_info->lport;
        prev_ps = &pf->stats_prev;
        cur_ps = &pf->stats;
-       pf_id = hw->pf_id;
 
-       ice_stat_update40(hw, GLPRT_GORCH(pf_id), GLPRT_GORCL(pf_id),
-                         pf->stat_prev_loaded, &prev_ps->eth.rx_bytes,
+       ice_stat_update40(hw, GLPRT_GORCL(port), pf->stat_prev_loaded,
+                         &prev_ps->eth.rx_bytes,
                          &cur_ps->eth.rx_bytes);
 
-       ice_stat_update40(hw, GLPRT_UPRCH(pf_id), GLPRT_UPRCL(pf_id),
-                         pf->stat_prev_loaded, &prev_ps->eth.rx_unicast,
+       ice_stat_update40(hw, GLPRT_UPRCL(port), pf->stat_prev_loaded,
+                         &prev_ps->eth.rx_unicast,
                          &cur_ps->eth.rx_unicast);
 
-       ice_stat_update40(hw, GLPRT_MPRCH(pf_id), GLPRT_MPRCL(pf_id),
-                         pf->stat_prev_loaded, &prev_ps->eth.rx_multicast,
+       ice_stat_update40(hw, GLPRT_MPRCL(port), pf->stat_prev_loaded,
+                         &prev_ps->eth.rx_multicast,
                          &cur_ps->eth.rx_multicast);
 
-       ice_stat_update40(hw, GLPRT_BPRCH(pf_id), GLPRT_BPRCL(pf_id),
-                         pf->stat_prev_loaded, &prev_ps->eth.rx_broadcast,
+       ice_stat_update40(hw, GLPRT_BPRCL(port), pf->stat_prev_loaded,
+                         &prev_ps->eth.rx_broadcast,
                          &cur_ps->eth.rx_broadcast);
 
-       ice_stat_update40(hw, GLPRT_GOTCH(pf_id), GLPRT_GOTCL(pf_id),
-                         pf->stat_prev_loaded, &prev_ps->eth.tx_bytes,
+       ice_stat_update32(hw, PRTRPB_RDPC, pf->stat_prev_loaded,
+                         &prev_ps->eth.rx_discards,
+                         &cur_ps->eth.rx_discards);
+
+       ice_stat_update40(hw, GLPRT_GOTCL(port), pf->stat_prev_loaded,
+                         &prev_ps->eth.tx_bytes,
                          &cur_ps->eth.tx_bytes);
 
-       ice_stat_update40(hw, GLPRT_UPTCH(pf_id), GLPRT_UPTCL(pf_id),
-                         pf->stat_prev_loaded, &prev_ps->eth.tx_unicast,
+       ice_stat_update40(hw, GLPRT_UPTCL(port), pf->stat_prev_loaded,
+                         &prev_ps->eth.tx_unicast,
                          &cur_ps->eth.tx_unicast);
 
-       ice_stat_update40(hw, GLPRT_MPTCH(pf_id), GLPRT_MPTCL(pf_id),
-                         pf->stat_prev_loaded, &prev_ps->eth.tx_multicast,
+       ice_stat_update40(hw, GLPRT_MPTCL(port), pf->stat_prev_loaded,
+                         &prev_ps->eth.tx_multicast,
                          &cur_ps->eth.tx_multicast);
 
-       ice_stat_update40(hw, GLPRT_BPTCH(pf_id), GLPRT_BPTCL(pf_id),
-                         pf->stat_prev_loaded, &prev_ps->eth.tx_broadcast,
+       ice_stat_update40(hw, GLPRT_BPTCL(port), pf->stat_prev_loaded,
+                         &prev_ps->eth.tx_broadcast,
                          &cur_ps->eth.tx_broadcast);
 
-       ice_stat_update32(hw, GLPRT_TDOLD(pf_id), pf->stat_prev_loaded,
+       ice_stat_update32(hw, GLPRT_TDOLD(port), pf->stat_prev_loaded,
                          &prev_ps->tx_dropped_link_down,
                          &cur_ps->tx_dropped_link_down);
 
-       ice_stat_update40(hw, GLPRT_PRC64H(pf_id), GLPRT_PRC64L(pf_id),
-                         pf->stat_prev_loaded, &prev_ps->rx_size_64,
-                         &cur_ps->rx_size_64);
+       ice_stat_update40(hw, GLPRT_PRC64L(port), pf->stat_prev_loaded,
+                         &prev_ps->rx_size_64, &cur_ps->rx_size_64);
 
-       ice_stat_update40(hw, GLPRT_PRC127H(pf_id), GLPRT_PRC127L(pf_id),
-                         pf->stat_prev_loaded, &prev_ps->rx_size_127,
-                         &cur_ps->rx_size_127);
+       ice_stat_update40(hw, GLPRT_PRC127L(port), pf->stat_prev_loaded,
+                         &prev_ps->rx_size_127, &cur_ps->rx_size_127);
 
-       ice_stat_update40(hw, GLPRT_PRC255H(pf_id), GLPRT_PRC255L(pf_id),
-                         pf->stat_prev_loaded, &prev_ps->rx_size_255,
-                         &cur_ps->rx_size_255);
+       ice_stat_update40(hw, GLPRT_PRC255L(port), pf->stat_prev_loaded,
+                         &prev_ps->rx_size_255, &cur_ps->rx_size_255);
 
-       ice_stat_update40(hw, GLPRT_PRC511H(pf_id), GLPRT_PRC511L(pf_id),
-                         pf->stat_prev_loaded, &prev_ps->rx_size_511,
-                         &cur_ps->rx_size_511);
+       ice_stat_update40(hw, GLPRT_PRC511L(port), pf->stat_prev_loaded,
+                         &prev_ps->rx_size_511, &cur_ps->rx_size_511);
 
-       ice_stat_update40(hw, GLPRT_PRC1023H(pf_id),
-                         GLPRT_PRC1023L(pf_id), pf->stat_prev_loaded,
+       ice_stat_update40(hw, GLPRT_PRC1023L(port), pf->stat_prev_loaded,
                          &prev_ps->rx_size_1023, &cur_ps->rx_size_1023);
 
-       ice_stat_update40(hw, GLPRT_PRC1522H(pf_id),
-                         GLPRT_PRC1522L(pf_id), pf->stat_prev_loaded,
+       ice_stat_update40(hw, GLPRT_PRC1522L(port), pf->stat_prev_loaded,
                          &prev_ps->rx_size_1522, &cur_ps->rx_size_1522);
 
-       ice_stat_update40(hw, GLPRT_PRC9522H(pf_id),
-                         GLPRT_PRC9522L(pf_id), pf->stat_prev_loaded,
+       ice_stat_update40(hw, GLPRT_PRC9522L(port), pf->stat_prev_loaded,
                          &prev_ps->rx_size_big, &cur_ps->rx_size_big);
 
-       ice_stat_update40(hw, GLPRT_PTC64H(pf_id), GLPRT_PTC64L(pf_id),
-                         pf->stat_prev_loaded, &prev_ps->tx_size_64,
-                         &cur_ps->tx_size_64);
+       ice_stat_update40(hw, GLPRT_PTC64L(port), pf->stat_prev_loaded,
+                         &prev_ps->tx_size_64, &cur_ps->tx_size_64);
 
-       ice_stat_update40(hw, GLPRT_PTC127H(pf_id), GLPRT_PTC127L(pf_id),
-                         pf->stat_prev_loaded, &prev_ps->tx_size_127,
-                         &cur_ps->tx_size_127);
+       ice_stat_update40(hw, GLPRT_PTC127L(port), pf->stat_prev_loaded,
+                         &prev_ps->tx_size_127, &cur_ps->tx_size_127);
 
-       ice_stat_update40(hw, GLPRT_PTC255H(pf_id), GLPRT_PTC255L(pf_id),
-                         pf->stat_prev_loaded, &prev_ps->tx_size_255,
-                         &cur_ps->tx_size_255);
+       ice_stat_update40(hw, GLPRT_PTC255L(port), pf->stat_prev_loaded,
+                         &prev_ps->tx_size_255, &cur_ps->tx_size_255);
 
-       ice_stat_update40(hw, GLPRT_PTC511H(pf_id), GLPRT_PTC511L(pf_id),
-                         pf->stat_prev_loaded, &prev_ps->tx_size_511,
-                         &cur_ps->tx_size_511);
+       ice_stat_update40(hw, GLPRT_PTC511L(port), pf->stat_prev_loaded,
+                         &prev_ps->tx_size_511, &cur_ps->tx_size_511);
 
-       ice_stat_update40(hw, GLPRT_PTC1023H(pf_id),
-                         GLPRT_PTC1023L(pf_id), pf->stat_prev_loaded,
+       ice_stat_update40(hw, GLPRT_PTC1023L(port), pf->stat_prev_loaded,
                          &prev_ps->tx_size_1023, &cur_ps->tx_size_1023);
 
-       ice_stat_update40(hw, GLPRT_PTC1522H(pf_id),
-                         GLPRT_PTC1522L(pf_id), pf->stat_prev_loaded,
+       ice_stat_update40(hw, GLPRT_PTC1522L(port), pf->stat_prev_loaded,
                          &prev_ps->tx_size_1522, &cur_ps->tx_size_1522);
 
-       ice_stat_update40(hw, GLPRT_PTC9522H(pf_id),
-                         GLPRT_PTC9522L(pf_id), pf->stat_prev_loaded,
+       ice_stat_update40(hw, GLPRT_PTC9522L(port), pf->stat_prev_loaded,
                          &prev_ps->tx_size_big, &cur_ps->tx_size_big);
 
-       ice_stat_update32(hw, GLPRT_LXONRXC(pf_id), pf->stat_prev_loaded,
+       ice_stat_update32(hw, GLPRT_LXONRXC(port), pf->stat_prev_loaded,
                          &prev_ps->link_xon_rx, &cur_ps->link_xon_rx);
 
-       ice_stat_update32(hw, GLPRT_LXOFFRXC(pf_id), pf->stat_prev_loaded,
+       ice_stat_update32(hw, GLPRT_LXOFFRXC(port), pf->stat_prev_loaded,
                          &prev_ps->link_xoff_rx, &cur_ps->link_xoff_rx);
 
-       ice_stat_update32(hw, GLPRT_LXONTXC(pf_id), pf->stat_prev_loaded,
+       ice_stat_update32(hw, GLPRT_LXONTXC(port), pf->stat_prev_loaded,
                          &prev_ps->link_xon_tx, &cur_ps->link_xon_tx);
 
-       ice_stat_update32(hw, GLPRT_LXOFFTXC(pf_id), pf->stat_prev_loaded,
+       ice_stat_update32(hw, GLPRT_LXOFFTXC(port), pf->stat_prev_loaded,
                          &prev_ps->link_xoff_tx, &cur_ps->link_xoff_tx);
 
        ice_update_dcb_stats(pf);
 
-       ice_stat_update32(hw, GLPRT_CRCERRS(pf_id), pf->stat_prev_loaded,
+       ice_stat_update32(hw, GLPRT_CRCERRS(port), pf->stat_prev_loaded,
                          &prev_ps->crc_errors, &cur_ps->crc_errors);
 
-       ice_stat_update32(hw, GLPRT_ILLERRC(pf_id), pf->stat_prev_loaded,
+       ice_stat_update32(hw, GLPRT_ILLERRC(port), pf->stat_prev_loaded,
                          &prev_ps->illegal_bytes, &cur_ps->illegal_bytes);
 
-       ice_stat_update32(hw, GLPRT_MLFC(pf_id), pf->stat_prev_loaded,
+       ice_stat_update32(hw, GLPRT_MLFC(port), pf->stat_prev_loaded,
                          &prev_ps->mac_local_faults,
                          &cur_ps->mac_local_faults);
 
-       ice_stat_update32(hw, GLPRT_MRFC(pf_id), pf->stat_prev_loaded,
+       ice_stat_update32(hw, GLPRT_MRFC(port), pf->stat_prev_loaded,
                          &prev_ps->mac_remote_faults,
                          &cur_ps->mac_remote_faults);
 
-       ice_stat_update32(hw, GLPRT_RLEC(pf_id), pf->stat_prev_loaded,
+       ice_stat_update32(hw, GLPRT_RLEC(port), pf->stat_prev_loaded,
                          &prev_ps->rx_len_errors, &cur_ps->rx_len_errors);
 
-       ice_stat_update32(hw, GLPRT_RUC(pf_id), pf->stat_prev_loaded,
+       ice_stat_update32(hw, GLPRT_RUC(port), pf->stat_prev_loaded,
                          &prev_ps->rx_undersize, &cur_ps->rx_undersize);
 
-       ice_stat_update32(hw, GLPRT_RFC(pf_id), pf->stat_prev_loaded,
+       ice_stat_update32(hw, GLPRT_RFC(port), pf->stat_prev_loaded,
                          &prev_ps->rx_fragments, &cur_ps->rx_fragments);
 
-       ice_stat_update32(hw, GLPRT_ROC(pf_id), pf->stat_prev_loaded,
+       ice_stat_update32(hw, GLPRT_ROC(port), pf->stat_prev_loaded,
                          &prev_ps->rx_oversize, &cur_ps->rx_oversize);
 
-       ice_stat_update32(hw, GLPRT_RJC(pf_id), pf->stat_prev_loaded,
+       ice_stat_update32(hw, GLPRT_RJC(port), pf->stat_prev_loaded,
                          &prev_ps->rx_jabber, &cur_ps->rx_jabber);
 
        pf->stat_prev_loaded = true;
@@ -3371,85 +3489,6 @@ static void ice_napi_disable_all(struct ice_vsi *vsi)
        }
 }
 
-/**
- * ice_force_phys_link_state - Force the physical link state
- * @vsi: VSI to force the physical link state to up/down
- * @link_up: true/false indicates to set the physical link to up/down
- *
- * Force the physical link state by getting the current PHY capabilities from
- * hardware and setting the PHY config based on the determined capabilities. If
- * link changes a link event will be triggered because both the Enable Automatic
- * Link Update and LESM Enable bits are set when setting the PHY capabilities.
- *
- * Returns 0 on success, negative on failure
- */
-static int ice_force_phys_link_state(struct ice_vsi *vsi, bool link_up)
-{
-       struct ice_aqc_get_phy_caps_data *pcaps;
-       struct ice_aqc_set_phy_cfg_data *cfg;
-       struct ice_port_info *pi;
-       struct device *dev;
-       int retcode;
-
-       if (!vsi || !vsi->port_info || !vsi->back)
-               return -EINVAL;
-       if (vsi->type != ICE_VSI_PF)
-               return 0;
-
-       dev = &vsi->back->pdev->dev;
-
-       pi = vsi->port_info;
-
-       pcaps = devm_kzalloc(dev, sizeof(*pcaps), GFP_KERNEL);
-       if (!pcaps)
-               return -ENOMEM;
-
-       retcode = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_SW_CFG, pcaps,
-                                     NULL);
-       if (retcode) {
-               dev_err(dev,
-                       "Failed to get phy capabilities, VSI %d error %d\n",
-                       vsi->vsi_num, retcode);
-               retcode = -EIO;
-               goto out;
-       }
-
-       /* No change in link */
-       if (link_up == !!(pcaps->caps & ICE_AQC_PHY_EN_LINK) &&
-           link_up == !!(pi->phy.link_info.link_info & ICE_AQ_LINK_UP))
-               goto out;
-
-       cfg = devm_kzalloc(dev, sizeof(*cfg), GFP_KERNEL);
-       if (!cfg) {
-               retcode = -ENOMEM;
-               goto out;
-       }
-
-       cfg->phy_type_low = pcaps->phy_type_low;
-       cfg->phy_type_high = pcaps->phy_type_high;
-       cfg->caps = pcaps->caps | ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
-       cfg->low_power_ctrl = pcaps->low_power_ctrl;
-       cfg->eee_cap = pcaps->eee_cap;
-       cfg->eeer_value = pcaps->eeer_value;
-       cfg->link_fec_opt = pcaps->link_fec_options;
-       if (link_up)
-               cfg->caps |= ICE_AQ_PHY_ENA_LINK;
-       else
-               cfg->caps &= ~ICE_AQ_PHY_ENA_LINK;
-
-       retcode = ice_aq_set_phy_cfg(&vsi->back->hw, pi->lport, cfg, NULL);
-       if (retcode) {
-               dev_err(dev, "Failed to set phy config, VSI %d error %d\n",
-                       vsi->vsi_num, retcode);
-               retcode = -EIO;
-       }
-
-       devm_kfree(dev, cfg);
-out:
-       devm_kfree(dev, pcaps);
-       return retcode;
-}
-
 /**
  * ice_down - Shutdown the connection
  * @vsi: The VSI being stopped
@@ -3558,24 +3597,6 @@ int ice_vsi_setup_rx_rings(struct ice_vsi *vsi)
        return err;
 }
 
-/**
- * ice_vsi_req_irq - Request IRQ from the OS
- * @vsi: The VSI IRQ is being requested for
- * @basename: name for the vector
- *
- * Return 0 on success and a negative value on error
- */
-static int ice_vsi_req_irq(struct ice_vsi *vsi, char *basename)
-{
-       struct ice_pf *pf = vsi->back;
-       int err = -EINVAL;
-
-       if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags))
-               err = ice_vsi_req_irq_msix(vsi, basename);
-
-       return err;
-}
-
 /**
  * ice_vsi_open - Called when a network interface is made active
  * @vsi: the VSI to open
@@ -3605,7 +3626,7 @@ static int ice_vsi_open(struct ice_vsi *vsi)
 
        snprintf(int_name, sizeof(int_name) - 1, "%s-%s",
                 dev_driver_string(&pf->pdev->dev), vsi->netdev->name);
-       err = ice_vsi_req_irq(vsi, int_name);
+       err = ice_vsi_req_irq_msix(vsi, int_name);
        if (err)
                goto err_setup_rx;
 
@@ -3669,23 +3690,19 @@ static int ice_ena_vsi(struct ice_vsi *vsi, bool locked)
        int err = 0;
 
        if (!test_bit(__ICE_NEEDS_RESTART, vsi->state))
-               return err;
+               return 0;
 
        clear_bit(__ICE_NEEDS_RESTART, vsi->state);
 
        if (vsi->netdev && vsi->type == ICE_VSI_PF) {
-               struct net_device *netd = vsi->netdev;
-
                if (netif_running(vsi->netdev)) {
-                       if (locked) {
-                               err = netd->netdev_ops->ndo_open(netd);
-                       } else {
+                       if (!locked)
                                rtnl_lock();
-                               err = netd->netdev_ops->ndo_open(netd);
+
+                       err = ice_open(vsi->netdev);
+
+                       if (!locked)
                                rtnl_unlock();
-                       }
-               } else {
-                       err = ice_vsi_open(vsi);
                }
        }
 
@@ -3723,22 +3740,23 @@ static int ice_vsi_rebuild_all(struct ice_pf *pf)
 
        /* loop through pf->vsi array and reinit the VSI if found */
        ice_for_each_vsi(pf, i) {
+               struct ice_vsi *vsi = pf->vsi[i];
                int err;
 
-               if (!pf->vsi[i])
+               if (!vsi)
                        continue;
 
-               err = ice_vsi_rebuild(pf->vsi[i]);
+               err = ice_vsi_rebuild(vsi);
                if (err) {
                        dev_err(&pf->pdev->dev,
                                "VSI at index %d rebuild failed\n",
-                               pf->vsi[i]->idx);
+                               vsi->idx);
                        return err;
                }
 
                dev_info(&pf->pdev->dev,
                         "VSI at index %d rebuilt. vsi_num = 0x%x\n",
-                        pf->vsi[i]->idx, pf->vsi[i]->vsi_num);
+                        vsi->idx, vsi->vsi_num);
        }
 
        return 0;
@@ -3756,25 +3774,27 @@ static int ice_vsi_replay_all(struct ice_pf *pf)
 
        /* loop through pf->vsi array and replay the VSI if found */
        ice_for_each_vsi(pf, i) {
-               if (!pf->vsi[i])
+               struct ice_vsi *vsi = pf->vsi[i];
+
+               if (!vsi)
                        continue;
 
-               ret = ice_replay_vsi(hw, pf->vsi[i]->idx);
+               ret = ice_replay_vsi(hw, vsi->idx);
                if (ret) {
                        dev_err(&pf->pdev->dev,
                                "VSI at index %d replay failed %d\n",
-                               pf->vsi[i]->idx, ret);
+                               vsi->idx, ret);
                        return -EIO;
                }
 
                /* Re-map HW VSI number, using VSI handle that has been
                 * previously validated in ice_replay_vsi() call above
                 */
-               pf->vsi[i]->vsi_num = ice_get_hw_vsi_num(hw, pf->vsi[i]->idx);
+               vsi->vsi_num = ice_get_hw_vsi_num(hw, vsi->idx);
 
                dev_info(&pf->pdev->dev,
                         "VSI at index %d filter replayed successfully - vsi_num %i\n",
-                        pf->vsi[i]->idx, pf->vsi[i]->vsi_num);
+                        vsi->idx, vsi->vsi_num);
        }
 
        /* Clean up replay filter after successful re-configuration */
@@ -3842,12 +3862,10 @@ static void ice_rebuild(struct ice_pf *pf)
        }
 
        /* start misc vector */
-       if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) {
-               err = ice_req_irq_msix_misc(pf);
-               if (err) {
-                       dev_err(dev, "misc vector setup failed: %d\n", err);
-                       goto err_vsi_rebuild;
-               }
+       err = ice_req_irq_msix_misc(pf);
+       if (err) {
+               dev_err(dev, "misc vector setup failed: %d\n", err);
+               goto err_vsi_rebuild;
        }
 
        /* restart the VSIs that were rebuilt and running before the reset */
@@ -4244,9 +4262,7 @@ static void ice_tx_timeout(struct net_device *netdev)
                head = (rd32(hw, QTX_COMM_HEAD(vsi->txq_map[hung_queue])) &
                        QTX_COMM_HEAD_HEAD_M) >> QTX_COMM_HEAD_HEAD_S;
                /* Read interrupt register */
-               if (test_bit(ICE_FLAG_MSIX_ENA, pf->flags))
-                       val = rd32(hw,
-                                  GLINT_DYN_CTL(tx_ring->q_vector->reg_idx));
+               val = rd32(hw, GLINT_DYN_CTL(tx_ring->q_vector->reg_idx));
 
                netdev_info(netdev, "tx_timeout: VSI_num: %d, Q %d, NTC: 0x%x, HW_HEAD: 0x%x, NTU: 0x%x, INT: 0x%x\n",
                            vsi->vsi_num, hung_queue, tx_ring->next_to_clean,
@@ -4295,6 +4311,7 @@ int ice_open(struct net_device *netdev)
 {
        struct ice_netdev_priv *np = netdev_priv(netdev);
        struct ice_vsi *vsi = np->vsi;
+       struct ice_port_info *pi;
        int err;
 
        if (test_bit(__ICE_NEEDS_RESTART, vsi->back->state)) {
@@ -4304,13 +4321,33 @@ int ice_open(struct net_device *netdev)
 
        netif_carrier_off(netdev);
 
-       err = ice_force_phys_link_state(vsi, true);
+       pi = vsi->port_info;
+       err = ice_update_link_info(pi);
        if (err) {
-               netdev_err(netdev,
-                          "Failed to set physical link up, error %d\n", err);
+               netdev_err(netdev, "Failed to get link info, error %d\n",
+                          err);
                return err;
        }
 
+       /* Set PHY if there is media, otherwise, turn off PHY */
+       if (pi->phy.link_info.link_info & ICE_AQ_MEDIA_AVAILABLE) {
+               err = ice_force_phys_link_state(vsi, true);
+               if (err) {
+                       netdev_err(netdev,
+                                  "Failed to set physical link up, error %d\n",
+                                  err);
+                       return err;
+               }
+       } else {
+               err = ice_aq_set_link_restart_an(pi, false, NULL);
+               if (err) {
+                       netdev_err(netdev, "Failed to set PHY state, VSI %d error %d\n",
+                                  vsi->vsi_num, err);
+                       return err;
+               }
+               set_bit(ICE_FLAG_NO_MEDIA, vsi->back->flags);
+       }
+
        err = ice_vsi_open(vsi);
        if (err)
                netdev_err(netdev, "Failed to open VSI 0x%04X on switch 0x%04X\n",