Merge branch 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa...
[linux-2.6-microblaze.git] / drivers / net / ethernet / intel / ice / ice_lib.c
index d13c7fc..d70ee57 100644 (file)
@@ -105,8 +105,14 @@ static int ice_vsi_alloc_arrays(struct ice_vsi *vsi)
        if (!vsi->q_vectors)
                goto err_vectors;
 
+       vsi->af_xdp_zc_qps = bitmap_zalloc(max_t(int, vsi->alloc_txq, vsi->alloc_rxq), GFP_KERNEL);
+       if (!vsi->af_xdp_zc_qps)
+               goto err_zc_qps;
+
        return 0;
 
+err_zc_qps:
+       devm_kfree(dev, vsi->q_vectors);
 err_vectors:
        devm_kfree(dev, vsi->rxq_map);
 err_rxq_map:
@@ -158,6 +164,8 @@ static void ice_vsi_set_num_qs(struct ice_vsi *vsi, u16 vf_id)
 
        if (vsi->type == ICE_VSI_VF)
                vsi->vf_id = vf_id;
+       else
+               vsi->vf_id = ICE_INVAL_VFID;
 
        switch (vsi->type) {
        case ICE_VSI_PF:
@@ -192,6 +200,8 @@ static void ice_vsi_set_num_qs(struct ice_vsi *vsi, u16 vf_id)
                break;
        case ICE_VSI_VF:
                vf = &pf->vf[vsi->vf_id];
+               if (vf->num_req_qs)
+                       vf->num_vf_qs = vf->num_req_qs;
                vsi->alloc_txq = vf->num_vf_qs;
                vsi->alloc_rxq = vf->num_vf_qs;
                /* pf->num_msix_per_vf includes (VF miscellaneous vector +
@@ -286,6 +296,10 @@ static void ice_vsi_free_arrays(struct ice_vsi *vsi)
 
        dev = ice_pf_to_dev(pf);
 
+       if (vsi->af_xdp_zc_qps) {
+               bitmap_free(vsi->af_xdp_zc_qps);
+               vsi->af_xdp_zc_qps = NULL;
+       }
        /* free the ring and vector containers */
        if (vsi->q_vectors) {
                devm_kfree(dev, vsi->q_vectors);
@@ -343,6 +357,9 @@ static int ice_vsi_clear(struct ice_vsi *vsi)
        pf->vsi[vsi->idx] = NULL;
        if (vsi->idx < pf->next_vsi && vsi->type != ICE_VSI_CTRL)
                pf->next_vsi = vsi->idx;
+       if (vsi->idx < pf->next_vsi && vsi->type == ICE_VSI_CTRL &&
+           vsi->vf_id != ICE_INVAL_VFID)
+               pf->next_vsi = vsi->idx;
 
        ice_vsi_free_arrays(vsi);
        mutex_unlock(&pf->sw_mutex);
@@ -382,6 +399,8 @@ static irqreturn_t ice_msix_clean_rings(int __always_unused irq, void *data)
        if (!q_vector->tx.ring && !q_vector->rx.ring)
                return IRQ_HANDLED;
 
+       q_vector->total_events++;
+
        napi_schedule(&q_vector->napi);
 
        return IRQ_HANDLED;
@@ -419,7 +438,7 @@ ice_vsi_alloc(struct ice_pf *pf, enum ice_vsi_type vsi_type, u16 vf_id)
 
        vsi->type = vsi_type;
        vsi->back = pf;
-       set_bit(__ICE_DOWN, vsi->state);
+       set_bit(ICE_VSI_DOWN, vsi->state);
 
        if (vsi_type == ICE_VSI_VF)
                ice_vsi_set_num_qs(vsi, vf_id);
@@ -454,8 +473,8 @@ ice_vsi_alloc(struct ice_pf *pf, enum ice_vsi_type vsi_type, u16 vf_id)
                goto unlock_pf;
        }
 
-       if (vsi->type == ICE_VSI_CTRL) {
-               /* Use the last VSI slot as the index for the control VSI */
+       if (vsi->type == ICE_VSI_CTRL && vf_id == ICE_INVAL_VFID) {
+               /* Use the last VSI slot as the index for PF control VSI */
                vsi->idx = pf->num_alloc_vsi - 1;
                pf->ctrl_vsi_idx = vsi->idx;
                pf->vsi[vsi->idx] = vsi;
@@ -468,6 +487,9 @@ ice_vsi_alloc(struct ice_pf *pf, enum ice_vsi_type vsi_type, u16 vf_id)
                pf->next_vsi = ice_get_free_slot(pf->vsi, pf->num_alloc_vsi,
                                                 pf->next_vsi);
        }
+
+       if (vsi->type == ICE_VSI_CTRL && vf_id != ICE_INVAL_VFID)
+               pf->vf[vf_id].ctrl_vsi_idx = vsi->idx;
        goto unlock_pf;
 
 err_rings:
@@ -506,7 +528,7 @@ static int ice_alloc_fd_res(struct ice_vsi *vsi)
        if (!b_val)
                return -EPERM;
 
-       if (vsi->type != ICE_VSI_PF)
+       if (!(vsi->type == ICE_VSI_PF || vsi->type == ICE_VSI_VF))
                return -EPERM;
 
        if (!test_bit(ICE_FLAG_FD_ENA, pf->flags))
@@ -517,6 +539,13 @@ static int ice_alloc_fd_res(struct ice_vsi *vsi)
        /* each VSI gets same "best_effort" quota */
        vsi->num_bfltr = b_val;
 
+       if (vsi->type == ICE_VSI_VF) {
+               vsi->num_gfltr = 0;
+
+               /* each VSI gets same "best_effort" quota */
+               vsi->num_bfltr = b_val;
+       }
+
        return 0;
 }
 
@@ -729,11 +758,10 @@ static void ice_set_dflt_vsi_ctx(struct ice_vsi_ctx *ctxt)
  */
 static void ice_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt)
 {
-       u16 offset = 0, qmap = 0, tx_count = 0;
+       u16 offset = 0, qmap = 0, tx_count = 0, pow = 0;
+       u16 num_txq_per_tc, num_rxq_per_tc;
        u16 qcount_tx = vsi->alloc_txq;
        u16 qcount_rx = vsi->alloc_rxq;
-       u16 tx_numq_tc, rx_numq_tc;
-       u16 pow = 0, max_rss = 0;
        bool ena_tc0 = false;
        u8 netdev_tc = 0;
        int i;
@@ -751,12 +779,15 @@ static void ice_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt)
                vsi->tc_cfg.ena_tc |= 1;
        }
 
-       rx_numq_tc = qcount_rx / vsi->tc_cfg.numtc;
-       if (!rx_numq_tc)
-               rx_numq_tc = 1;
-       tx_numq_tc = qcount_tx / vsi->tc_cfg.numtc;
-       if (!tx_numq_tc)
-               tx_numq_tc = 1;
+       num_rxq_per_tc = min_t(u16, qcount_rx / vsi->tc_cfg.numtc, ICE_MAX_RXQS_PER_TC);
+       if (!num_rxq_per_tc)
+               num_rxq_per_tc = 1;
+       num_txq_per_tc = qcount_tx / vsi->tc_cfg.numtc;
+       if (!num_txq_per_tc)
+               num_txq_per_tc = 1;
+
+       /* find the (rounded up) power-of-2 of qcount */
+       pow = (u16)order_base_2(num_rxq_per_tc);
 
        /* TC mapping is a function of the number of Rx queues assigned to the
         * VSI for each traffic class and the offset of these queues.
@@ -769,26 +800,6 @@ static void ice_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt)
         *
         * Setup number and offset of Rx queues for all TCs for the VSI
         */
-
-       qcount_rx = rx_numq_tc;
-
-       /* qcount will change if RSS is enabled */
-       if (test_bit(ICE_FLAG_RSS_ENA, vsi->back->flags)) {
-               if (vsi->type == ICE_VSI_PF || vsi->type == ICE_VSI_VF) {
-                       if (vsi->type == ICE_VSI_PF)
-                               max_rss = ICE_MAX_LG_RSS_QS;
-                       else
-                               max_rss = ICE_MAX_RSS_QS_PER_VF;
-                       qcount_rx = min_t(u16, rx_numq_tc, max_rss);
-                       if (!vsi->req_rxq)
-                               qcount_rx = min_t(u16, qcount_rx,
-                                                 vsi->rss_size);
-               }
-       }
-
-       /* find the (rounded up) power-of-2 of qcount */
-       pow = (u16)order_base_2(qcount_rx);
-
        ice_for_each_traffic_class(i) {
                if (!(vsi->tc_cfg.ena_tc & BIT(i))) {
                        /* TC is not enabled */
@@ -802,16 +813,16 @@ static void ice_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt)
 
                /* TC is enabled */
                vsi->tc_cfg.tc_info[i].qoffset = offset;
-               vsi->tc_cfg.tc_info[i].qcount_rx = qcount_rx;
-               vsi->tc_cfg.tc_info[i].qcount_tx = tx_numq_tc;
+               vsi->tc_cfg.tc_info[i].qcount_rx = num_rxq_per_tc;
+               vsi->tc_cfg.tc_info[i].qcount_tx = num_txq_per_tc;
                vsi->tc_cfg.tc_info[i].netdev_tc = netdev_tc++;
 
                qmap = ((offset << ICE_AQ_VSI_TC_Q_OFFSET_S) &
                        ICE_AQ_VSI_TC_Q_OFFSET_M) |
                        ((pow << ICE_AQ_VSI_TC_Q_NUM_S) &
                         ICE_AQ_VSI_TC_Q_NUM_M);
-               offset += qcount_rx;
-               tx_count += tx_numq_tc;
+               offset += num_rxq_per_tc;
+               tx_count += num_txq_per_tc;
                ctxt->info.tc_mapping[i] = cpu_to_le16(qmap);
        }
 
@@ -824,7 +835,7 @@ static void ice_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt)
        if (offset)
                vsi->num_rxq = offset;
        else
-               vsi->num_rxq = qcount_rx;
+               vsi->num_rxq = num_rxq_per_tc;
 
        vsi->num_txq = tx_count;
 
@@ -856,7 +867,8 @@ static void ice_set_fd_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi)
        u8 dflt_q_group, dflt_q_prio;
        u16 dflt_q, report_q, val;
 
-       if (vsi->type != ICE_VSI_PF && vsi->type != ICE_VSI_CTRL)
+       if (vsi->type != ICE_VSI_PF && vsi->type != ICE_VSI_CTRL &&
+           vsi->type != ICE_VSI_VF)
                return;
 
        val = ICE_AQ_VSI_PROP_FLOW_DIR_VALID;
@@ -1179,7 +1191,24 @@ static int ice_vsi_setup_vector_base(struct ice_vsi *vsi)
 
        num_q_vectors = vsi->num_q_vectors;
        /* reserve slots from OS requested IRQs */
-       base = ice_get_res(pf, pf->irq_tracker, num_q_vectors, vsi->idx);
+       if (vsi->type == ICE_VSI_CTRL && vsi->vf_id != ICE_INVAL_VFID) {
+               struct ice_vf *vf;
+               int i;
+
+               ice_for_each_vf(pf, i) {
+                       vf = &pf->vf[i];
+                       if (i != vsi->vf_id && vf->ctrl_vsi_idx != ICE_NO_VSI) {
+                               base = pf->vsi[vf->ctrl_vsi_idx]->base_vector;
+                               break;
+                       }
+               }
+               if (i == pf->num_alloc_vfs)
+                       base = ice_get_res(pf, pf->irq_tracker, num_q_vectors,
+                                          ICE_RES_VF_CTRL_VEC_ID);
+       } else {
+               base = ice_get_res(pf, pf->irq_tracker, num_q_vectors,
+                                  vsi->idx);
+       }
 
        if (base < 0) {
                dev_err(dev, "%d MSI-X interrupts available. %s %d failed to get %d MSI-X vectors\n",
@@ -1296,14 +1325,13 @@ err_out:
  * LUT, while in the event of enable request for RSS, it will reconfigure RSS
  * LUT.
  */
-int ice_vsi_manage_rss_lut(struct ice_vsi *vsi, bool ena)
+void ice_vsi_manage_rss_lut(struct ice_vsi *vsi, bool ena)
 {
-       int err = 0;
        u8 *lut;
 
        lut = kzalloc(vsi->rss_table_size, GFP_KERNEL);
        if (!lut)
-               return -ENOMEM;
+               return;
 
        if (ena) {
                if (vsi->rss_lut_user)
@@ -1313,9 +1341,8 @@ int ice_vsi_manage_rss_lut(struct ice_vsi *vsi, bool ena)
                                         vsi->rss_size);
        }
 
-       err = ice_set_rss(vsi, NULL, lut, vsi->rss_table_size);
+       ice_set_rss_lut(vsi, lut, vsi->rss_table_size);
        kfree(lut);
-       return err;
 }
 
 /**
@@ -1324,12 +1351,10 @@ int ice_vsi_manage_rss_lut(struct ice_vsi *vsi, bool ena)
  */
 static int ice_vsi_cfg_rss_lut_key(struct ice_vsi *vsi)
 {
-       struct ice_aqc_get_set_rss_keys *key;
        struct ice_pf *pf = vsi->back;
-       enum ice_status status;
        struct device *dev;
-       int err = 0;
-       u8 *lut;
+       u8 *lut, *key;
+       int err;
 
        dev = ice_pf_to_dev(pf);
        vsi->rss_size = min_t(u16, vsi->rss_size, vsi->num_rxq);
@@ -1343,37 +1368,26 @@ static int ice_vsi_cfg_rss_lut_key(struct ice_vsi *vsi)
        else
                ice_fill_rss_lut(lut, vsi->rss_table_size, vsi->rss_size);
 
-       status = ice_aq_set_rss_lut(&pf->hw, vsi->idx, vsi->rss_lut_type, lut,
-                                   vsi->rss_table_size);
-
-       if (status) {
-               dev_err(dev, "set_rss_lut failed, error %s\n",
-                       ice_stat_str(status));
-               err = -EIO;
+       err = ice_set_rss_lut(vsi, lut, vsi->rss_table_size);
+       if (err) {
+               dev_err(dev, "set_rss_lut failed, error %d\n", err);
                goto ice_vsi_cfg_rss_exit;
        }
 
-       key = kzalloc(sizeof(*key), GFP_KERNEL);
+       key = kzalloc(ICE_GET_SET_RSS_KEY_EXTEND_KEY_SIZE, GFP_KERNEL);
        if (!key) {
                err = -ENOMEM;
                goto ice_vsi_cfg_rss_exit;
        }
 
        if (vsi->rss_hkey_user)
-               memcpy(key,
-                      (struct ice_aqc_get_set_rss_keys *)vsi->rss_hkey_user,
-                      ICE_GET_SET_RSS_KEY_EXTEND_KEY_SIZE);
+               memcpy(key, vsi->rss_hkey_user, ICE_GET_SET_RSS_KEY_EXTEND_KEY_SIZE);
        else
-               netdev_rss_key_fill((void *)key,
-                                   ICE_GET_SET_RSS_KEY_EXTEND_KEY_SIZE);
+               netdev_rss_key_fill((void *)key, ICE_GET_SET_RSS_KEY_EXTEND_KEY_SIZE);
 
-       status = ice_aq_set_rss_key(&pf->hw, vsi->idx, key);
-
-       if (status) {
-               dev_err(dev, "set_rss_key failed, error %s\n",
-                       ice_stat_str(status));
-               err = -EIO;
-       }
+       err = ice_set_rss_key(vsi, key);
+       if (err)
+               dev_err(dev, "set_rss_key failed, error %d\n", err);
 
        kfree(key);
 ice_vsi_cfg_rss_exit:
@@ -1502,13 +1516,13 @@ static void ice_vsi_set_rss_flow_fld(struct ice_vsi *vsi)
  */
 bool ice_pf_state_is_nominal(struct ice_pf *pf)
 {
-       DECLARE_BITMAP(check_bits, __ICE_STATE_NBITS) = { 0 };
+       DECLARE_BITMAP(check_bits, ICE_STATE_NBITS) = { 0 };
 
        if (!pf)
                return false;
 
-       bitmap_set(check_bits, 0, __ICE_STATE_NOMINAL_CHECK_BITS);
-       if (bitmap_intersects(pf->state, check_bits, __ICE_STATE_NBITS))
+       bitmap_set(check_bits, 0, ICE_STATE_NOMINAL_CHECK_BITS);
+       if (bitmap_intersects(pf->state, check_bits, ICE_STATE_NBITS))
                return false;
 
        return true;
@@ -1773,7 +1787,7 @@ int ice_vsi_cfg_xdp_txqs(struct ice_vsi *vsi)
  * This function converts a decimal interrupt rate limit in usecs to the format
  * expected by firmware.
  */
-u32 ice_intrl_usec_to_reg(u8 intrl, u8 gran)
+static u32 ice_intrl_usec_to_reg(u8 intrl, u8 gran)
 {
        u32 val = intrl / gran;
 
@@ -1782,6 +1796,51 @@ u32 ice_intrl_usec_to_reg(u8 intrl, u8 gran)
        return 0;
 }
 
+/**
+ * ice_write_intrl - write throttle rate limit to interrupt specific register
+ * @q_vector: pointer to interrupt specific structure
+ * @intrl: throttle rate limit in microseconds to write
+ */
+void ice_write_intrl(struct ice_q_vector *q_vector, u8 intrl)
+{
+       struct ice_hw *hw = &q_vector->vsi->back->hw;
+
+       wr32(hw, GLINT_RATE(q_vector->reg_idx),
+            ice_intrl_usec_to_reg(intrl, ICE_INTRL_GRAN_ABOVE_25));
+}
+
+/**
+ * __ice_write_itr - write throttle rate to register
+ * @q_vector: pointer to interrupt data structure
+ * @rc: pointer to ring container
+ * @itr: throttle rate in microseconds to write
+ */
+static void __ice_write_itr(struct ice_q_vector *q_vector,
+                           struct ice_ring_container *rc, u16 itr)
+{
+       struct ice_hw *hw = &q_vector->vsi->back->hw;
+
+       wr32(hw, GLINT_ITR(rc->itr_idx, q_vector->reg_idx),
+            ITR_REG_ALIGN(itr) >> ICE_ITR_GRAN_S);
+}
+
+/**
+ * ice_write_itr - write throttle rate to queue specific register
+ * @rc: pointer to ring container
+ * @itr: throttle rate in microseconds to write
+ */
+void ice_write_itr(struct ice_ring_container *rc, u16 itr)
+{
+       struct ice_q_vector *q_vector;
+
+       if (!rc->ring)
+               return;
+
+       q_vector = rc->ring->q_vector;
+
+       __ice_write_itr(q_vector, rc, itr);
+}
+
 /**
  * ice_vsi_cfg_msix - MSIX mode Interrupt Config in the HW
  * @vsi: the VSI being configured
@@ -1802,9 +1861,6 @@ void ice_vsi_cfg_msix(struct ice_vsi *vsi)
 
                ice_cfg_itr(hw, q_vector);
 
-               wr32(hw, GLINT_RATE(reg_idx),
-                    ice_intrl_usec_to_reg(q_vector->intrl, hw->intrl_gran));
-
                /* Both Transmit Queue Interrupt Cause Control register
                 * and Receive Queue Interrupt Cause control register
                 * expects MSIX_INDX field to be the vector index
@@ -2308,7 +2364,7 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,
        struct ice_vsi *vsi;
        int ret, i;
 
-       if (vsi_type == ICE_VSI_VF)
+       if (vsi_type == ICE_VSI_VF || vsi_type == ICE_VSI_CTRL)
                vsi = ice_vsi_alloc(pf, vsi_type, vf_id);
        else
                vsi = ice_vsi_alloc(pf, vsi_type, ICE_INVAL_VFID);
@@ -2323,7 +2379,7 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,
        if (vsi->type == ICE_VSI_PF)
                vsi->ethtype = ETH_P_PAUSE;
 
-       if (vsi->type == ICE_VSI_VF)
+       if (vsi->type == ICE_VSI_VF || vsi->type == ICE_VSI_CTRL)
                vsi->vf_id = vf_id;
 
        ice_alloc_fd_res(vsi);
@@ -2492,11 +2548,10 @@ static void ice_vsi_release_msix(struct ice_vsi *vsi)
 
        for (i = 0; i < vsi->num_q_vectors; i++) {
                struct ice_q_vector *q_vector = vsi->q_vectors[i];
-               u16 reg_idx = q_vector->reg_idx;
 
-               wr32(hw, GLINT_ITR(ICE_IDX_ITR0, reg_idx), 0);
-               wr32(hw, GLINT_ITR(ICE_IDX_ITR1, reg_idx), 0);
+               ice_write_intrl(q_vector, 0);
                for (q = 0; q < q_vector->num_ring_tx; q++) {
+                       ice_write_itr(&q_vector->tx, 0);
                        wr32(hw, QINT_TQCTL(vsi->txq_map[txq]), 0);
                        if (ice_is_xdp_ena_vsi(vsi)) {
                                u32 xdp_txq = txq + vsi->num_xdp_txq;
@@ -2507,6 +2562,7 @@ static void ice_vsi_release_msix(struct ice_vsi *vsi)
                }
 
                for (q = 0; q < q_vector->num_ring_rx; q++) {
+                       ice_write_itr(&q_vector->rx, 0);
                        wr32(hw, QINT_RQCTL(vsi->rxq_map[rxq]), 0);
                        rxq++;
                }
@@ -2593,7 +2649,7 @@ void ice_vsi_free_rx_rings(struct ice_vsi *vsi)
  */
 void ice_vsi_close(struct ice_vsi *vsi)
 {
-       if (!test_and_set_bit(__ICE_DOWN, vsi->state))
+       if (!test_and_set_bit(ICE_VSI_DOWN, vsi->state))
                ice_down(vsi);
 
        ice_vsi_free_irq(vsi);
@@ -2610,10 +2666,10 @@ int ice_ena_vsi(struct ice_vsi *vsi, bool locked)
 {
        int err = 0;
 
-       if (!test_bit(__ICE_NEEDS_RESTART, vsi->state))
+       if (!test_bit(ICE_VSI_NEEDS_RESTART, vsi->state))
                return 0;
 
-       clear_bit(__ICE_NEEDS_RESTART, vsi->state);
+       clear_bit(ICE_VSI_NEEDS_RESTART, vsi->state);
 
        if (vsi->netdev && vsi->type == ICE_VSI_PF) {
                if (netif_running(vsi->netdev)) {
@@ -2639,10 +2695,10 @@ int ice_ena_vsi(struct ice_vsi *vsi, bool locked)
  */
 void ice_dis_vsi(struct ice_vsi *vsi, bool locked)
 {
-       if (test_bit(__ICE_DOWN, vsi->state))
+       if (test_bit(ICE_VSI_DOWN, vsi->state))
                return;
 
-       set_bit(__ICE_NEEDS_RESTART, vsi->state);
+       set_bit(ICE_VSI_NEEDS_RESTART, vsi->state);
 
        if (vsi->type == ICE_VSI_PF && vsi->netdev) {
                if (netif_running(vsi->netdev)) {
@@ -2752,11 +2808,14 @@ int ice_vsi_release(struct ice_vsi *vsi)
         * PF that is running the work queue items currently. This is done to
         * avoid check_flush_dependency() warning on this wq
         */
-       if (vsi->netdev && !ice_is_reset_in_progress(pf->state)) {
+       if (vsi->netdev && !ice_is_reset_in_progress(pf->state) &&
+           (test_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state))) {
                unregister_netdev(vsi->netdev);
-               ice_devlink_destroy_port(vsi);
+               clear_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state);
        }
 
+       ice_devlink_destroy_port(vsi);
+
        if (test_bit(ICE_FLAG_RSS_ENA, pf->flags))
                ice_rss_clean(vsi);
 
@@ -2770,7 +2829,24 @@ int ice_vsi_release(struct ice_vsi *vsi)
         * many interrupts each VF needs. SR-IOV MSIX resources are also
         * cleared in the same manner.
         */
-       if (vsi->type != ICE_VSI_VF) {
+       if (vsi->type == ICE_VSI_CTRL && vsi->vf_id != ICE_INVAL_VFID) {
+               struct ice_vf *vf;
+               int i;
+
+               ice_for_each_vf(pf, i) {
+                       vf = &pf->vf[i];
+                       if (i != vsi->vf_id && vf->ctrl_vsi_idx != ICE_NO_VSI)
+                               break;
+               }
+               if (i == pf->num_alloc_vfs) {
+                       /* No other VFs left that have control VSI, reclaim SW
+                        * interrupts back to the common pool
+                        */
+                       ice_free_res(pf->irq_tracker, vsi->base_vector,
+                                    ICE_RES_VF_CTRL_VEC_ID);
+                       pf->num_avail_sw_msix += vsi->num_q_vectors;
+               }
+       } else if (vsi->type != ICE_VSI_VF) {
                /* reclaim SW interrupts back to the common pool */
                ice_free_res(pf->irq_tracker, vsi->base_vector, vsi->idx);
                pf->num_avail_sw_msix += vsi->num_q_vectors;
@@ -2794,10 +2870,16 @@ int ice_vsi_release(struct ice_vsi *vsi)
        ice_vsi_delete(vsi);
        ice_vsi_free_q_vectors(vsi);
 
-       /* make sure unregister_netdev() was called by checking __ICE_DOWN */
-       if (vsi->netdev && test_bit(__ICE_DOWN, vsi->state)) {
-               free_netdev(vsi->netdev);
-               vsi->netdev = NULL;
+       if (vsi->netdev) {
+               if (test_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state)) {
+                       unregister_netdev(vsi->netdev);
+                       clear_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state);
+               }
+               if (test_bit(ICE_VSI_NETDEV_ALLOCD, vsi->state)) {
+                       free_netdev(vsi->netdev);
+                       vsi->netdev = NULL;
+                       clear_bit(ICE_VSI_NETDEV_ALLOCD, vsi->state);
+               }
        }
 
        if (vsi->type == ICE_VSI_VF &&
@@ -2817,39 +2899,6 @@ int ice_vsi_release(struct ice_vsi *vsi)
        return 0;
 }
 
-/**
- * ice_vsi_rebuild_update_coalesce - set coalesce for a q_vector
- * @q_vector: pointer to q_vector which is being updated
- * @coalesce: pointer to array of struct with stored coalesce
- *
- * Set coalesce param in q_vector and update these parameters in HW.
- */
-static void
-ice_vsi_rebuild_update_coalesce(struct ice_q_vector *q_vector,
-                               struct ice_coalesce_stored *coalesce)
-{
-       struct ice_ring_container *rx_rc = &q_vector->rx;
-       struct ice_ring_container *tx_rc = &q_vector->tx;
-       struct ice_hw *hw = &q_vector->vsi->back->hw;
-
-       tx_rc->itr_setting = coalesce->itr_tx;
-       rx_rc->itr_setting = coalesce->itr_rx;
-
-       /* dynamic ITR values will be updated during Tx/Rx */
-       if (!ITR_IS_DYNAMIC(tx_rc->itr_setting))
-               wr32(hw, GLINT_ITR(tx_rc->itr_idx, q_vector->reg_idx),
-                    ITR_REG_ALIGN(tx_rc->itr_setting) >>
-                    ICE_ITR_GRAN_S);
-       if (!ITR_IS_DYNAMIC(rx_rc->itr_setting))
-               wr32(hw, GLINT_ITR(rx_rc->itr_idx, q_vector->reg_idx),
-                    ITR_REG_ALIGN(rx_rc->itr_setting) >>
-                    ICE_ITR_GRAN_S);
-
-       q_vector->intrl = coalesce->intrl;
-       wr32(hw, GLINT_RATE(q_vector->reg_idx),
-            ice_intrl_usec_to_reg(q_vector->intrl, hw->intrl_gran));
-}
-
 /**
  * ice_vsi_rebuild_get_coalesce - get coalesce from all q_vectors
  * @vsi: VSI connected with q_vectors
@@ -2869,6 +2918,11 @@ ice_vsi_rebuild_get_coalesce(struct ice_vsi *vsi,
                coalesce[i].itr_tx = q_vector->tx.itr_setting;
                coalesce[i].itr_rx = q_vector->rx.itr_setting;
                coalesce[i].intrl = q_vector->intrl;
+
+               if (i < vsi->num_txq)
+                       coalesce[i].tx_valid = true;
+               if (i < vsi->num_rxq)
+                       coalesce[i].rx_valid = true;
        }
 
        return vsi->num_q_vectors;
@@ -2888,22 +2942,75 @@ static void
 ice_vsi_rebuild_set_coalesce(struct ice_vsi *vsi,
                             struct ice_coalesce_stored *coalesce, int size)
 {
+       struct ice_ring_container *rc;
        int i;
 
        if ((size && !coalesce) || !vsi)
                return;
 
-       for (i = 0; i < size && i < vsi->num_q_vectors; i++)
-               ice_vsi_rebuild_update_coalesce(vsi->q_vectors[i],
-                                               &coalesce[i]);
+       /* There are a couple of cases that have to be handled here:
+        *   1. The case where the number of queue vectors stays the same, but
+        *      the number of Tx or Rx rings changes (the first for loop)
+        *   2. The case where the number of queue vectors increased (the
+        *      second for loop)
+        */
+       for (i = 0; i < size && i < vsi->num_q_vectors; i++) {
+               /* There are 2 cases to handle here and they are the same for
+                * both Tx and Rx:
+                *   if the entry was valid previously (coalesce[i].[tr]x_valid
+                *   and the loop variable is less than the number of rings
+                *   allocated, then write the previous values
+                *
+                *   if the entry was not valid previously, but the number of
+                *   rings is less than are allocated (this means the number of
+                *   rings increased from previously), then write out the
+                *   values in the first element
+                *
+                *   Also, always write the ITR, even if in ITR_IS_DYNAMIC
+                *   as there is no harm because the dynamic algorithm
+                *   will just overwrite.
+                */
+               if (i < vsi->alloc_rxq && coalesce[i].rx_valid) {
+                       rc = &vsi->q_vectors[i]->rx;
+                       rc->itr_setting = coalesce[i].itr_rx;
+                       ice_write_itr(rc, rc->itr_setting);
+               } else if (i < vsi->alloc_rxq) {
+                       rc = &vsi->q_vectors[i]->rx;
+                       rc->itr_setting = coalesce[0].itr_rx;
+                       ice_write_itr(rc, rc->itr_setting);
+               }
+
+               if (i < vsi->alloc_txq && coalesce[i].tx_valid) {
+                       rc = &vsi->q_vectors[i]->tx;
+                       rc->itr_setting = coalesce[i].itr_tx;
+                       ice_write_itr(rc, rc->itr_setting);
+               } else if (i < vsi->alloc_txq) {
+                       rc = &vsi->q_vectors[i]->tx;
+                       rc->itr_setting = coalesce[0].itr_tx;
+                       ice_write_itr(rc, rc->itr_setting);
+               }
 
-       /* number of q_vectors increased, so assume coalesce settings were
-        * changed globally (i.e. ethtool -C eth0 instead of per-queue) and use
-        * the previous settings from q_vector 0 for all of the new q_vectors
+               vsi->q_vectors[i]->intrl = coalesce[i].intrl;
+               ice_write_intrl(vsi->q_vectors[i], coalesce[i].intrl);
+       }
+
+       /* the number of queue vectors increased so write whatever is in
+        * the first element
         */
-       for (; i < vsi->num_q_vectors; i++)
-               ice_vsi_rebuild_update_coalesce(vsi->q_vectors[i],
-                                               &coalesce[0]);
+       for (; i < vsi->num_q_vectors; i++) {
+               /* transmit */
+               rc = &vsi->q_vectors[i]->tx;
+               rc->itr_setting = coalesce[0].itr_tx;
+               ice_write_itr(rc, rc->itr_setting);
+
+               /* receive */
+               rc = &vsi->q_vectors[i]->rx;
+               rc->itr_setting = coalesce[0].itr_rx;
+               ice_write_itr(rc, rc->itr_setting);
+
+               vsi->q_vectors[i]->intrl = coalesce[0].intrl;
+               ice_write_intrl(vsi->q_vectors[i], coalesce[0].intrl);
+       }
 }
 
 /**
@@ -2919,6 +3026,7 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi)
        struct ice_coalesce_stored *coalesce;
        int prev_num_q_vectors = 0;
        struct ice_vf *vf = NULL;
+       enum ice_vsi_type vtype;
        enum ice_status status;
        struct ice_pf *pf;
        int ret, i;
@@ -2927,14 +3035,17 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi)
                return -EINVAL;
 
        pf = vsi->back;
-       if (vsi->type == ICE_VSI_VF)
+       vtype = vsi->type;
+       if (vtype == ICE_VSI_VF)
                vf = &pf->vf[vsi->vf_id];
 
        coalesce = kcalloc(vsi->num_q_vectors,
                           sizeof(struct ice_coalesce_stored), GFP_KERNEL);
-       if (coalesce)
-               prev_num_q_vectors = ice_vsi_rebuild_get_coalesce(vsi,
-                                                                 coalesce);
+       if (!coalesce)
+               return -ENOMEM;
+
+       prev_num_q_vectors = ice_vsi_rebuild_get_coalesce(vsi, coalesce);
+
        ice_rm_vsi_lan_cfg(vsi->port_info, vsi->idx);
        ice_vsi_free_q_vectors(vsi);
 
@@ -2943,7 +3054,7 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi)
         * many interrupts each VF needs. SR-IOV MSIX resources are also
         * cleared in the same manner.
         */
-       if (vsi->type != ICE_VSI_VF) {
+       if (vtype != ICE_VSI_VF) {
                /* reclaim SW interrupts back to the common pool */
                ice_free_res(pf->irq_tracker, vsi->base_vector, vsi->idx);
                pf->num_avail_sw_msix += vsi->num_q_vectors;
@@ -2958,7 +3069,7 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi)
        ice_vsi_put_qs(vsi);
        ice_vsi_clear_rings(vsi);
        ice_vsi_free_arrays(vsi);
-       if (vsi->type == ICE_VSI_VF)
+       if (vtype == ICE_VSI_VF)
                ice_vsi_set_num_qs(vsi, vf->vf_id);
        else
                ice_vsi_set_num_qs(vsi, ICE_INVAL_VFID);
@@ -2977,7 +3088,7 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi)
        if (ret < 0)
                goto err_vsi;
 
-       switch (vsi->type) {
+       switch (vtype) {
        case ICE_VSI_CTRL:
        case ICE_VSI_PF:
                ret = ice_vsi_alloc_q_vectors(vsi);
@@ -3004,7 +3115,7 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi)
                                goto err_vectors;
                }
                /* ICE_VSI_CTRL does not need RSS so skip RSS processing */
-               if (vsi->type != ICE_VSI_CTRL)
+               if (vtype != ICE_VSI_CTRL)
                        /* Do not exit if configuring RSS had an issue, at
                         * least receive traffic on first queue. Hence no
                         * need to capture return value
@@ -3066,7 +3177,7 @@ err_rings:
        }
 err_vsi:
        ice_vsi_clear(vsi);
-       set_bit(__ICE_RESET_FAILED, pf->state);
+       set_bit(ICE_RESET_FAILED, pf->state);
        kfree(coalesce);
        return ret;
 }
@@ -3077,10 +3188,10 @@ err_vsi:
  */
 bool ice_is_reset_in_progress(unsigned long *state)
 {
-       return test_bit(__ICE_RESET_OICR_RECV, state) ||
-              test_bit(__ICE_PFR_REQ, state) ||
-              test_bit(__ICE_CORER_REQ, state) ||
-              test_bit(__ICE_GLOBR_REQ, state);
+       return test_bit(ICE_RESET_OICR_RECV, state) ||
+              test_bit(ICE_PFR_REQ, state) ||
+              test_bit(ICE_CORER_REQ, state) ||
+              test_bit(ICE_GLOBR_REQ, state);
 }
 
 #ifdef CONFIG_DCB
@@ -3168,20 +3279,15 @@ out:
 /**
  * ice_update_ring_stats - Update ring statistics
  * @ring: ring to update
- * @cont: used to increment per-vector counters
  * @pkts: number of processed packets
  * @bytes: number of processed bytes
  *
  * This function assumes that caller has acquired a u64_stats_sync lock.
  */
-static void
-ice_update_ring_stats(struct ice_ring *ring, struct ice_ring_container *cont,
-                     u64 pkts, u64 bytes)
+static void ice_update_ring_stats(struct ice_ring *ring, u64 pkts, u64 bytes)
 {
        ring->stats.bytes += bytes;
        ring->stats.pkts += pkts;
-       cont->total_bytes += bytes;
-       cont->total_pkts += pkts;
 }
 
 /**
@@ -3193,7 +3299,7 @@ ice_update_ring_stats(struct ice_ring *ring, struct ice_ring_container *cont,
 void ice_update_tx_ring_stats(struct ice_ring *tx_ring, u64 pkts, u64 bytes)
 {
        u64_stats_update_begin(&tx_ring->syncp);
-       ice_update_ring_stats(tx_ring, &tx_ring->q_vector->tx, pkts, bytes);
+       ice_update_ring_stats(tx_ring, pkts, bytes);
        u64_stats_update_end(&tx_ring->syncp);
 }
 
@@ -3206,7 +3312,7 @@ void ice_update_tx_ring_stats(struct ice_ring *tx_ring, u64 pkts, u64 bytes)
 void ice_update_rx_ring_stats(struct ice_ring *rx_ring, u64 pkts, u64 bytes)
 {
        u64_stats_update_begin(&rx_ring->syncp);
-       ice_update_ring_stats(rx_ring, &rx_ring->q_vector->rx, pkts, bytes);
+       ice_update_ring_stats(rx_ring, pkts, bytes);
        u64_stats_update_end(&rx_ring->syncp);
 }
 
@@ -3348,3 +3454,40 @@ int ice_clear_dflt_vsi(struct ice_sw *sw)
 
        return 0;
 }
+
+/**
+ * ice_set_link - turn on/off physical link
+ * @vsi: VSI to modify physical link on
+ * @ena: turn on/off physical link
+ */
+int ice_set_link(struct ice_vsi *vsi, bool ena)
+{
+       struct device *dev = ice_pf_to_dev(vsi->back);
+       struct ice_port_info *pi = vsi->port_info;
+       struct ice_hw *hw = pi->hw;
+       enum ice_status status;
+
+       if (vsi->type != ICE_VSI_PF)
+               return -EINVAL;
+
+       status = ice_aq_set_link_restart_an(pi, ena, NULL);
+
+       /* if link is owned by manageability, FW will return ICE_AQ_RC_EMODE.
+        * this is not a fatal error, so print a warning message and return
+        * a success code. Return an error if FW returns an error code other
+        * than ICE_AQ_RC_EMODE
+        */
+       if (status == ICE_ERR_AQ_ERROR) {
+               if (hw->adminq.sq_last_status == ICE_AQ_RC_EMODE)
+                       dev_warn(dev, "can't set link to %s, err %s aq_err %s. not fatal, continuing\n",
+                                (ena ? "ON" : "OFF"), ice_stat_str(status),
+                                ice_aq_str(hw->adminq.sq_last_status));
+       } else if (status) {
+               dev_err(dev, "can't set link to %s, err %s aq_err %s\n",
+                       (ena ? "ON" : "OFF"), ice_stat_str(status),
+                       ice_aq_str(hw->adminq.sq_last_status));
+               return -EIO;
+       }
+
+       return 0;
+}