]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/net/ethernet/intel/ice/ice_lib.c
ice: Restore interrupt throttle settings after VSI rebuild
[linux.git] / drivers / net / ethernet / intel / ice / ice_lib.c
index e7449248fab4c1a4d4566b685edb5b8bd2e1e00c..4cfad81ba4961014a70d94ff9e468d2aebb038ed 100644 (file)
@@ -817,12 +817,23 @@ static int ice_vsi_init(struct ice_vsi *vsi, bool init_vsi)
                ctxt->info.valid_sections |=
                        cpu_to_le16(ICE_AQ_VSI_PROP_RXQ_MAP_VALID);
 
-       /* Enable MAC Antispoof with new VSI being initialized or updated */
-       if (vsi->type == ICE_VSI_VF && pf->vf[vsi->vf_id].spoofchk) {
+       /* enable/disable MAC and VLAN anti-spoof when spoofchk is on/off
+        * respectively
+        */
+       if (vsi->type == ICE_VSI_VF) {
                ctxt->info.valid_sections |=
                        cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID);
-               ctxt->info.sec_flags |=
-                       ICE_AQ_VSI_SEC_FLAG_ENA_MAC_ANTI_SPOOF;
+               if (pf->vf[vsi->vf_id].spoofchk) {
+                       ctxt->info.sec_flags |=
+                               ICE_AQ_VSI_SEC_FLAG_ENA_MAC_ANTI_SPOOF |
+                               (ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA <<
+                                ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S);
+               } else {
+                       ctxt->info.sec_flags &=
+                               ~(ICE_AQ_VSI_SEC_FLAG_ENA_MAC_ANTI_SPOOF |
+                                 (ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA <<
+                                  ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S));
+               }
        }
 
        /* Allow control frames out of main VSI */
@@ -1636,22 +1647,14 @@ int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena, bool vlan_promisc)
 
        ctxt->info = vsi->info;
 
-       if (ena) {
-               ctxt->info.sec_flags |=
-                       ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA <<
-                       ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S;
+       if (ena)
                ctxt->info.sw_flags2 |= ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA;
-       } else {
-               ctxt->info.sec_flags &=
-                       ~(ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA <<
-                         ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S);
+       else
                ctxt->info.sw_flags2 &= ~ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA;
-       }
 
        if (!vlan_promisc)
                ctxt->info.valid_sections =
-                       cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID |
-                                   ICE_AQ_VSI_PROP_SW_VALID);
+                       cpu_to_le16(ICE_AQ_VSI_PROP_SW_VALID);
 
        status = ice_update_vsi(&pf->hw, vsi->idx, ctxt, NULL);
        if (status) {
@@ -1661,7 +1664,6 @@ int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena, bool vlan_promisc)
                goto err_out;
        }
 
-       vsi->info.sec_flags = ctxt->info.sec_flags;
        vsi->info.sw_flags2 = ctxt->info.sw_flags2;
 
        kfree(ctxt);
@@ -2401,6 +2403,97 @@ 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
+ * @coalesce: array of struct with stored coalesce
+ *
+ * Returns array size.
+ */
+static int
+ice_vsi_rebuild_get_coalesce(struct ice_vsi *vsi,
+                            struct ice_coalesce_stored *coalesce)
+{
+       int i;
+
+       ice_for_each_q_vector(vsi, i) {
+               struct ice_q_vector *q_vector = vsi->q_vectors[i];
+
+               coalesce[i].itr_tx = q_vector->tx.itr_setting;
+               coalesce[i].itr_rx = q_vector->rx.itr_setting;
+               coalesce[i].intrl = q_vector->intrl;
+       }
+
+       return vsi->num_q_vectors;
+}
+
+/**
+ * ice_vsi_rebuild_set_coalesce - set coalesce from earlier saved arrays
+ * @vsi: VSI connected with q_vectors
+ * @coalesce: pointer to array of struct with stored coalesce
+ * @size: size of coalesce array
+ *
+ * Before this function, ice_vsi_rebuild_get_coalesce should be called to save
+ * ITR params in arrays. If size is 0 or coalesce wasn't stored set coalesce
+ * to default value.
+ */
+static void
+ice_vsi_rebuild_set_coalesce(struct ice_vsi *vsi,
+                            struct ice_coalesce_stored *coalesce, int size)
+{
+       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]);
+
+       for (; i < vsi->num_q_vectors; i++) {
+               struct ice_coalesce_stored coalesce_dflt = {
+                       .itr_tx = ICE_DFLT_TX_ITR,
+                       .itr_rx = ICE_DFLT_RX_ITR,
+                       .intrl = 0
+               };
+               ice_vsi_rebuild_update_coalesce(vsi->q_vectors[i],
+                                               &coalesce_dflt);
+       }
+}
+
 /**
  * ice_vsi_rebuild - Rebuild VSI after reset
  * @vsi: VSI to be rebuild
@@ -2411,6 +2504,8 @@ int ice_vsi_release(struct ice_vsi *vsi)
 int ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi)
 {
        u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 };
+       struct ice_coalesce_stored *coalesce;
+       int prev_num_q_vectors = 0;
        struct ice_vf *vf = NULL;
        enum ice_status status;
        struct ice_pf *pf;
@@ -2423,6 +2518,11 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi)
        if (vsi->type == 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);
        ice_rm_vsi_lan_cfg(vsi->port_info, vsi->idx);
        ice_vsi_free_q_vectors(vsi);
 
@@ -2535,6 +2635,9 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi)
                        return ice_schedule_reset(pf, ICE_RESET_PFR);
                }
        }
+       ice_vsi_rebuild_set_coalesce(vsi, coalesce, prev_num_q_vectors);
+       kfree(coalesce);
+
        return 0;
 
 err_vectors:
@@ -2549,6 +2652,7 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi)
 err_vsi:
        ice_vsi_clear(vsi);
        set_bit(__ICE_RESET_FAILED, pf->state);
+       kfree(coalesce);
        return ret;
 }
 
@@ -2740,3 +2844,121 @@ ice_vsi_cfg_mac_fltr(struct ice_vsi *vsi, const u8 *macaddr, bool set)
        ice_free_fltr_list(&vsi->back->pdev->dev, &tmp_add_list);
        return status;
 }
+
+/**
+ * ice_is_dflt_vsi_in_use - check if the default forwarding VSI is being used
+ * @sw: switch to check if its default forwarding VSI is free
+ *
+ * Return true if the default forwarding VSI is already being used, else returns
+ * false signalling that it's available to use.
+ */
+bool ice_is_dflt_vsi_in_use(struct ice_sw *sw)
+{
+       return (sw->dflt_vsi && sw->dflt_vsi_ena);
+}
+
+/**
+ * ice_is_vsi_dflt_vsi - check if the VSI passed in is the default VSI
+ * @sw: switch for the default forwarding VSI to compare against
+ * @vsi: VSI to compare against default forwarding VSI
+ *
+ * If this VSI passed in is the default forwarding VSI then return true, else
+ * return false
+ */
+bool ice_is_vsi_dflt_vsi(struct ice_sw *sw, struct ice_vsi *vsi)
+{
+       return (sw->dflt_vsi == vsi && sw->dflt_vsi_ena);
+}
+
+/**
+ * ice_set_dflt_vsi - set the default forwarding VSI
+ * @sw: switch used to assign the default forwarding VSI
+ * @vsi: VSI getting set as the default forwarding VSI on the switch
+ *
+ * If the VSI passed in is already the default VSI and it's enabled just return
+ * success.
+ *
+ * If there is already a default VSI on the switch and it's enabled then return
+ * -EEXIST since there can only be one default VSI per switch.
+ *
+ *  Otherwise try to set the VSI passed in as the switch's default VSI and
+ *  return the result.
+ */
+int ice_set_dflt_vsi(struct ice_sw *sw, struct ice_vsi *vsi)
+{
+       enum ice_status status;
+       struct device *dev;
+
+       if (!sw || !vsi)
+               return -EINVAL;
+
+       dev = ice_pf_to_dev(vsi->back);
+
+       /* the VSI passed in is already the default VSI */
+       if (ice_is_vsi_dflt_vsi(sw, vsi)) {
+               dev_dbg(dev, "VSI %d passed in is already the default forwarding VSI, nothing to do\n",
+                       vsi->vsi_num);
+               return 0;
+       }
+
+       /* another VSI is already the default VSI for this switch */
+       if (ice_is_dflt_vsi_in_use(sw)) {
+               dev_err(dev,
+                       "Default forwarding VSI %d already in use, disable it and try again\n",
+                       sw->dflt_vsi->vsi_num);
+               return -EEXIST;
+       }
+
+       status = ice_cfg_dflt_vsi(&vsi->back->hw, vsi->idx, true, ICE_FLTR_RX);
+       if (status) {
+               dev_err(dev,
+                       "Failed to set VSI %d as the default forwarding VSI, error %d\n",
+                       vsi->vsi_num, status);
+               return -EIO;
+       }
+
+       sw->dflt_vsi = vsi;
+       sw->dflt_vsi_ena = true;
+
+       return 0;
+}
+
+/**
+ * ice_clear_dflt_vsi - clear the default forwarding VSI
+ * @sw: switch used to clear the default VSI
+ *
+ * If the switch has no default VSI or it's not enabled then return error.
+ *
+ * Otherwise try to clear the default VSI and return the result.
+ */
+int ice_clear_dflt_vsi(struct ice_sw *sw)
+{
+       struct ice_vsi *dflt_vsi;
+       enum ice_status status;
+       struct device *dev;
+
+       if (!sw)
+               return -EINVAL;
+
+       dev = ice_pf_to_dev(sw->pf);
+
+       dflt_vsi = sw->dflt_vsi;
+
+       /* there is no default VSI configured */
+       if (!ice_is_dflt_vsi_in_use(sw))
+               return -ENODEV;
+
+       status = ice_cfg_dflt_vsi(&dflt_vsi->back->hw, dflt_vsi->idx, false,
+                                 ICE_FLTR_RX);
+       if (status) {
+               dev_err(dev,
+                       "Failed to clear the default forwarding VSI %d, error %d\n",
+                       dflt_vsi->vsi_num, status);
+               return -EIO;
+       }
+
+       sw->dflt_vsi = NULL;
+       sw->dflt_vsi_ena = false;
+
+       return 0;
+}