ice: Support VF queue rate limit and quanta size configuration
authorWenjun Wu <wenjun1.wu@intel.com>
Wed, 9 Oct 2024 08:09:59 +0000 (10:09 +0200)
committerJakub Kicinski <kuba@kernel.org>
Thu, 10 Oct 2024 15:30:23 +0000 (08:30 -0700)
Add support to configure VF queue rate limit and quanta size.

For quanta size configuration, the quanta profiles are divided evenly
by PF numbers. For each port, the first quanta profile is reserved for
default. When VF is asked to set queue quanta size, PF will search for
an available profile, change the fields and assigned this profile to the
queue.

Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: Wenjun Wu <wenjun1.wu@intel.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Link: https://patch.msgid.link/fddefc2c1ec3ab32b241ce444af401da19e834dd.1728460186.git.pabeni@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/intel/ice/ice.h
drivers/net/ethernet/intel/ice/ice_base.c
drivers/net/ethernet/intel/ice/ice_common.c
drivers/net/ethernet/intel/ice/ice_hw_autogen.h
drivers/net/ethernet/intel/ice/ice_txrx.h
drivers/net/ethernet/intel/ice/ice_type.h
drivers/net/ethernet/intel/ice/ice_vf_lib.h
drivers/net/ethernet/intel/ice/ice_virtchnl.c
drivers/net/ethernet/intel/ice/ice_virtchnl.h
drivers/net/ethernet/intel/ice/ice_virtchnl_allowlist.c

index 558cda577191d6b64ecbdd82fef48b197a2fbf47..c7dbf332de8172cebc9929d979ec0b18b0b890fa 100644 (file)
@@ -669,6 +669,8 @@ struct ice_pf {
        struct ice_agg_node vf_agg_node[ICE_MAX_VF_AGG_NODES];
        struct ice_dplls dplls;
        struct device *hwmon_dev;
+
+       u8 num_quanta_prof_used;
 };
 
 extern struct workqueue_struct *ice_lag_wq;
index 4a9a6899fc453cb53b11ad014abceb1ca0fa7441..892935e78e5b70c0b8d75da80a1f9fef497c7624 100644 (file)
@@ -347,6 +347,8 @@ ice_setup_tx_ctx(struct ice_tx_ring *ring, struct ice_tlan_ctx *tlan_ctx, u16 pf
                break;
        }
 
+       tlan_ctx->quanta_prof_idx = ring->quanta_prof_id;
+
        tlan_ctx->tso_ena = ICE_TX_LEGACY;
        tlan_ctx->tso_qnum = pf_q;
 
index 009716a12a26afbaff3e5962119504dd00713e57..b22e71dc59d4e4ec0efea96e5afd812859a98bdd 100644 (file)
@@ -2436,6 +2436,25 @@ ice_parse_func_caps(struct ice_hw *hw, struct ice_hw_func_caps *func_p,
        ice_recalc_port_limited_caps(hw, &func_p->common_cap);
 }
 
+/**
+ * ice_func_id_to_logical_id - map from function id to logical pf id
+ * @active_function_bitmap: active function bitmap
+ * @pf_id: function number of device
+ *
+ * Return: logical PF ID.
+ */
+static int ice_func_id_to_logical_id(u32 active_function_bitmap, u8 pf_id)
+{
+       u8 logical_id = 0;
+       u8 i;
+
+       for (i = 0; i < pf_id; i++)
+               if (active_function_bitmap & BIT(i))
+                       logical_id++;
+
+       return logical_id;
+}
+
 /**
  * ice_parse_valid_functions_cap - Parse ICE_AQC_CAPS_VALID_FUNCTIONS caps
  * @hw: pointer to the HW struct
@@ -2453,6 +2472,8 @@ ice_parse_valid_functions_cap(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p,
        dev_p->num_funcs = hweight32(number);
        ice_debug(hw, ICE_DBG_INIT, "dev caps: num_funcs = %d\n",
                  dev_p->num_funcs);
+
+       hw->logical_pf_id = ice_func_id_to_logical_id(number, hw->pf_id);
 }
 
 /**
index 91cbae1eec89a0b7267a799a6d2445ff72a31783..af9302f0e3763c8eeca3dd8a8887273528e6654e 100644 (file)
@@ -6,6 +6,14 @@
 #ifndef _ICE_HW_AUTOGEN_H_
 #define _ICE_HW_AUTOGEN_H_
 
+#define GLCOMM_QUANTA_PROF(_i)                 (0x002D2D68 + ((_i) * 4))
+#define GLCOMM_QUANTA_PROF_MAX_INDEX           15
+#define GLCOMM_QUANTA_PROF_QUANTA_SIZE_S       0
+#define GLCOMM_QUANTA_PROF_QUANTA_SIZE_M       ICE_M(0x3FFF, 0)
+#define GLCOMM_QUANTA_PROF_MAX_CMD_S           16
+#define GLCOMM_QUANTA_PROF_MAX_CMD_M           ICE_M(0xFF, 16)
+#define GLCOMM_QUANTA_PROF_MAX_DESC_S          24
+#define GLCOMM_QUANTA_PROF_MAX_DESC_M          ICE_M(0x3F, 24)
 #define QTX_COMM_DBELL(_DBQM)                  (0x002C0000 + ((_DBQM) * 4))
 #define QTX_COMM_HEAD(_DBQM)                   (0x000E0000 + ((_DBQM) * 4))
 #define QTX_COMM_HEAD_HEAD_S                   0
index feba314a3fe4413973a422a27f6c45caeaaf6639..ea2fae9035b55a889e747a54ff13c96d3df49685 100644 (file)
@@ -406,6 +406,7 @@ struct ice_tx_ring {
 #define ICE_TX_FLAGS_RING_VLAN_L2TAG2  BIT(2)
        u8 flags;
        u8 dcb_tc;                      /* Traffic class of ring */
+       u16 quanta_prof_id;
 } ____cacheline_internodealigned_in_smp;
 
 static inline bool ice_ring_uses_build_skb(struct ice_rx_ring *ring)
index 45768796691fecca1b5b3c6640063dbe9fdfbef0..adb168860711c07fb10c55d1da2e2ead2a9a1acd 100644 (file)
@@ -905,6 +905,7 @@ struct ice_hw {
        u8 revision_id;
 
        u8 pf_id;               /* device profile info */
+       u8 logical_pf_id;
 
        u16 max_burst_size;     /* driver sets this value */
 
index be4266899690ab27d11dddff1b7ef2bc2f1d197c..4261fe1c2bcd7029c71547d6ddaf14a6034bc0fd 100644 (file)
@@ -59,6 +59,13 @@ struct ice_fdir_prof_info {
        u64 fdir_active_cnt;
 };
 
+struct ice_vf_qs_bw {
+       u32 committed;
+       u32 peak;
+       u16 queue_id;
+       u8 tc;
+};
+
 /* VF operations */
 struct ice_vf_ops {
        enum ice_disq_rst_src reset_type;
@@ -140,6 +147,7 @@ struct ice_vf {
        struct devlink_port devlink_port;
 
        u16 num_msix;                   /* num of MSI-X configured on this VF */
+       struct ice_vf_qs_bw qs_bw[ICE_MAX_RSS_QS_PER_VF];
 };
 
 /* Flags for controlling behavior of ice_reset_vf */
index 59f62306b9cb02d2743222a50dd44dbb7faa2186..96543f69f5debed22d5d2389673764d707f84511 100644 (file)
@@ -495,6 +495,9 @@ static int ice_vc_get_vf_res_msg(struct ice_vf *vf, u8 *msg)
        if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_USO)
                vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_USO;
 
+       if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_QOS)
+               vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_QOS;
+
        vfres->num_vsis = 1;
        /* Tx and Rx queue are equal for VF */
        vfres->num_queue_pairs = vsi->num_txq;
@@ -1034,6 +1037,191 @@ error_param:
                                     NULL, 0);
 }
 
+/**
+ * ice_vc_get_qos_caps - Get current QoS caps from PF
+ * @vf: pointer to the VF info
+ *
+ * Get VF's QoS capabilities, such as TC number, arbiter and
+ * bandwidth from PF.
+ *
+ * Return: 0 on success or negative error value.
+ */
+static int ice_vc_get_qos_caps(struct ice_vf *vf)
+{
+       enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
+       struct virtchnl_qos_cap_list *cap_list = NULL;
+       u8 tc_prio[ICE_MAX_TRAFFIC_CLASS] = { 0 };
+       struct virtchnl_qos_cap_elem *cfg = NULL;
+       struct ice_vsi_ctx *vsi_ctx;
+       struct ice_pf *pf = vf->pf;
+       struct ice_port_info *pi;
+       struct ice_vsi *vsi;
+       u8 numtc, tc;
+       u16 len = 0;
+       int ret, i;
+
+       if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
+               v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+               goto err;
+       }
+
+       vsi = ice_get_vf_vsi(vf);
+       if (!vsi) {
+               v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+               goto err;
+       }
+
+       pi = pf->hw.port_info;
+       numtc = vsi->tc_cfg.numtc;
+
+       vsi_ctx = ice_get_vsi_ctx(pi->hw, vf->lan_vsi_idx);
+       if (!vsi_ctx) {
+               v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+               goto err;
+       }
+
+       len = struct_size(cap_list, cap, numtc);
+       cap_list = kzalloc(len, GFP_KERNEL);
+       if (!cap_list) {
+               v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY;
+               len = 0;
+               goto err;
+       }
+
+       cap_list->vsi_id = vsi->vsi_num;
+       cap_list->num_elem = numtc;
+
+       /* Store the UP2TC configuration from DCB to a user priority bitmap
+        * of each TC. Each element of prio_of_tc represents one TC. Each
+        * bitmap indicates the user priorities belong to this TC.
+        */
+       for (i = 0; i < ICE_MAX_USER_PRIORITY; i++) {
+               tc = pi->qos_cfg.local_dcbx_cfg.etscfg.prio_table[i];
+               tc_prio[tc] |= BIT(i);
+       }
+
+       for (i = 0; i < numtc; i++) {
+               cfg = &cap_list->cap[i];
+               cfg->tc_num = i;
+               cfg->tc_prio = tc_prio[i];
+               cfg->arbiter = pi->qos_cfg.local_dcbx_cfg.etscfg.tsatable[i];
+               cfg->weight = VIRTCHNL_STRICT_WEIGHT;
+               cfg->type = VIRTCHNL_BW_SHAPER;
+               cfg->shaper.committed = vsi_ctx->sched.bw_t_info[i].cir_bw.bw;
+               cfg->shaper.peak = vsi_ctx->sched.bw_t_info[i].eir_bw.bw;
+       }
+
+err:
+       ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_QOS_CAPS, v_ret,
+                                   (u8 *)cap_list, len);
+       kfree(cap_list);
+       return ret;
+}
+
+/**
+ * ice_vf_cfg_qs_bw - Configure per queue bandwidth
+ * @vf: pointer to the VF info
+ * @num_queues: number of queues to be configured
+ *
+ * Configure per queue bandwidth.
+ *
+ * Return: 0 on success or negative error value.
+ */
+static int ice_vf_cfg_qs_bw(struct ice_vf *vf, u16 num_queues)
+{
+       struct ice_hw *hw = &vf->pf->hw;
+       struct ice_vsi *vsi;
+       int ret;
+       u16 i;
+
+       vsi = ice_get_vf_vsi(vf);
+       if (!vsi)
+               return -EINVAL;
+
+       for (i = 0; i < num_queues; i++) {
+               u32 p_rate, min_rate;
+               u8 tc;
+
+               p_rate = vf->qs_bw[i].peak;
+               min_rate = vf->qs_bw[i].committed;
+               tc = vf->qs_bw[i].tc;
+               if (p_rate)
+                       ret = ice_cfg_q_bw_lmt(hw->port_info, vsi->idx, tc,
+                                              vf->qs_bw[i].queue_id,
+                                              ICE_MAX_BW, p_rate);
+               else
+                       ret = ice_cfg_q_bw_dflt_lmt(hw->port_info, vsi->idx, tc,
+                                                   vf->qs_bw[i].queue_id,
+                                                   ICE_MAX_BW);
+               if (ret)
+                       return ret;
+
+               if (min_rate)
+                       ret = ice_cfg_q_bw_lmt(hw->port_info, vsi->idx, tc,
+                                              vf->qs_bw[i].queue_id,
+                                              ICE_MIN_BW, min_rate);
+               else
+                       ret = ice_cfg_q_bw_dflt_lmt(hw->port_info, vsi->idx, tc,
+                                                   vf->qs_bw[i].queue_id,
+                                                   ICE_MIN_BW);
+
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+/**
+ * ice_vf_cfg_q_quanta_profile - Configure quanta profile
+ * @vf: pointer to the VF info
+ * @quanta_prof_idx: pointer to the quanta profile index
+ * @quanta_size: quanta size to be set
+ *
+ * This function chooses available quanta profile and configures the register.
+ * The quanta profile is evenly divided by the number of device ports, and then
+ * available to the specific PF and VFs. The first profile for each PF is a
+ * reserved default profile. Only quanta size of the rest unused profile can be
+ * modified.
+ *
+ * Return: 0 on success or negative error value.
+ */
+static int ice_vf_cfg_q_quanta_profile(struct ice_vf *vf, u16 quanta_size,
+                                      u16 *quanta_prof_idx)
+{
+       const u16 n_desc = calc_quanta_desc(quanta_size);
+       struct ice_hw *hw = &vf->pf->hw;
+       const u16 n_cmd = 2 * n_desc;
+       struct ice_pf *pf = vf->pf;
+       u16 per_pf, begin_id;
+       u8 n_used;
+       u32 reg;
+
+       begin_id = (GLCOMM_QUANTA_PROF_MAX_INDEX + 1) / hw->dev_caps.num_funcs *
+                  hw->logical_pf_id;
+
+       if (quanta_size == ICE_DFLT_QUANTA) {
+               *quanta_prof_idx = begin_id;
+       } else {
+               per_pf = (GLCOMM_QUANTA_PROF_MAX_INDEX + 1) /
+                        hw->dev_caps.num_funcs;
+               n_used = pf->num_quanta_prof_used;
+               if (n_used < per_pf) {
+                       *quanta_prof_idx = begin_id + 1 + n_used;
+                       pf->num_quanta_prof_used++;
+               } else {
+                       return -EINVAL;
+               }
+       }
+
+       reg = FIELD_PREP(GLCOMM_QUANTA_PROF_QUANTA_SIZE_M, quanta_size) |
+             FIELD_PREP(GLCOMM_QUANTA_PROF_MAX_CMD_M, n_cmd) |
+             FIELD_PREP(GLCOMM_QUANTA_PROF_MAX_DESC_M, n_desc);
+       wr32(hw, GLCOMM_QUANTA_PROF(*quanta_prof_idx), reg);
+
+       return 0;
+}
+
 /**
  * ice_vc_cfg_promiscuous_mode_msg
  * @vf: pointer to the VF info
@@ -1635,6 +1823,141 @@ error_param:
                                     NULL, 0);
 }
 
+/**
+ * ice_vc_cfg_q_bw - Configure per queue bandwidth
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer which holds the command descriptor
+ *
+ * Configure VF queues bandwidth.
+ *
+ * Return: 0 on success or negative error value.
+ */
+static int ice_vc_cfg_q_bw(struct ice_vf *vf, u8 *msg)
+{
+       enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
+       struct virtchnl_queues_bw_cfg *qbw =
+               (struct virtchnl_queues_bw_cfg *)msg;
+       struct ice_vsi *vsi;
+       u16 i;
+
+       if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states) ||
+           !ice_vc_isvalid_vsi_id(vf, qbw->vsi_id)) {
+               v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+               goto err;
+       }
+
+       vsi = ice_get_vf_vsi(vf);
+       if (!vsi) {
+               v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+               goto err;
+       }
+
+       if (qbw->num_queues > ICE_MAX_RSS_QS_PER_VF ||
+           qbw->num_queues > min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)) {
+               dev_err(ice_pf_to_dev(vf->pf), "VF-%d trying to configure more than allocated number of queues: %d\n",
+                       vf->vf_id, min_t(u16, vsi->alloc_txq, vsi->alloc_rxq));
+               v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+               goto err;
+       }
+
+       for (i = 0; i < qbw->num_queues; i++) {
+               if (qbw->cfg[i].shaper.peak != 0 && vf->max_tx_rate != 0 &&
+                   qbw->cfg[i].shaper.peak > vf->max_tx_rate)
+                       dev_warn(ice_pf_to_dev(vf->pf), "The maximum queue %d rate limit configuration may not take effect because the maximum TX rate for VF-%d is %d\n",
+                                qbw->cfg[i].queue_id, vf->vf_id,
+                                vf->max_tx_rate);
+               if (qbw->cfg[i].shaper.committed != 0 && vf->min_tx_rate != 0 &&
+                   qbw->cfg[i].shaper.committed < vf->min_tx_rate)
+                       dev_warn(ice_pf_to_dev(vf->pf), "The minimum queue %d rate limit configuration may not take effect because the minimum TX rate for VF-%d is %d\n",
+                                qbw->cfg[i].queue_id, vf->vf_id,
+                                vf->max_tx_rate);
+       }
+
+       for (i = 0; i < qbw->num_queues; i++) {
+               vf->qs_bw[i].queue_id = qbw->cfg[i].queue_id;
+               vf->qs_bw[i].peak = qbw->cfg[i].shaper.peak;
+               vf->qs_bw[i].committed = qbw->cfg[i].shaper.committed;
+               vf->qs_bw[i].tc = qbw->cfg[i].tc;
+       }
+
+       if (ice_vf_cfg_qs_bw(vf, qbw->num_queues))
+               v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+
+err:
+       /* send the response to the VF */
+       return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_QUEUE_BW,
+                                   v_ret, NULL, 0);
+}
+
+/**
+ * ice_vc_cfg_q_quanta - Configure per queue quanta
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer which holds the command descriptor
+ *
+ * Configure VF queues quanta.
+ *
+ * Return: 0 on success or negative error value.
+ */
+static int ice_vc_cfg_q_quanta(struct ice_vf *vf, u8 *msg)
+{
+       enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
+       u16 quanta_prof_id, quanta_size, start_qid, end_qid, i;
+       struct virtchnl_quanta_cfg *qquanta =
+               (struct virtchnl_quanta_cfg *)msg;
+       struct ice_vsi *vsi;
+       int ret;
+
+       if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
+               v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+               goto err;
+       }
+
+       vsi = ice_get_vf_vsi(vf);
+       if (!vsi) {
+               v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+               goto err;
+       }
+
+       end_qid = qquanta->queue_select.start_queue_id +
+                 qquanta->queue_select.num_queues;
+       if (end_qid > ICE_MAX_RSS_QS_PER_VF ||
+           end_qid > min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)) {
+               dev_err(ice_pf_to_dev(vf->pf), "VF-%d trying to configure more than allocated number of queues: %d\n",
+                       vf->vf_id, min_t(u16, vsi->alloc_txq, vsi->alloc_rxq));
+               v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+               goto err;
+       }
+
+       quanta_size = qquanta->quanta_size;
+       if (quanta_size > ICE_MAX_QUANTA_SIZE ||
+           quanta_size < ICE_MIN_QUANTA_SIZE) {
+               v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+               goto err;
+       }
+
+       if (quanta_size % 64) {
+               dev_err(ice_pf_to_dev(vf->pf), "quanta size should be the product of 64\n");
+               v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+               goto err;
+       }
+
+       ret = ice_vf_cfg_q_quanta_profile(vf, quanta_size,
+                                         &quanta_prof_id);
+       if (ret) {
+               v_ret = VIRTCHNL_STATUS_ERR_NOT_SUPPORTED;
+               goto err;
+       }
+
+       start_qid = qquanta->queue_select.start_queue_id;
+       for (i = start_qid; i < end_qid; i++)
+               vsi->tx_rings[i]->quanta_prof_id = quanta_prof_id;
+
+err:
+       /* send the response to the VF */
+       return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_QUANTA,
+                                    v_ret, NULL, 0);
+}
+
 /**
  * ice_vc_cfg_qs_msg
  * @vf: pointer to the VF info
@@ -3821,6 +4144,9 @@ static const struct ice_virtchnl_ops ice_virtchnl_dflt_ops = {
        .dis_vlan_stripping_v2_msg = ice_vc_dis_vlan_stripping_v2_msg,
        .ena_vlan_insertion_v2_msg = ice_vc_ena_vlan_insertion_v2_msg,
        .dis_vlan_insertion_v2_msg = ice_vc_dis_vlan_insertion_v2_msg,
+       .get_qos_caps = ice_vc_get_qos_caps,
+       .cfg_q_bw = ice_vc_cfg_q_bw,
+       .cfg_q_quanta = ice_vc_cfg_q_quanta,
 };
 
 /**
@@ -4177,6 +4503,15 @@ error_handler:
        case VIRTCHNL_OP_DISABLE_VLAN_INSERTION_V2:
                err = ops->dis_vlan_insertion_v2_msg(vf, msg);
                break;
+       case VIRTCHNL_OP_GET_QOS_CAPS:
+               err = ops->get_qos_caps(vf);
+               break;
+       case VIRTCHNL_OP_CONFIG_QUEUE_BW:
+               err = ops->cfg_q_bw(vf, msg);
+               break;
+       case VIRTCHNL_OP_CONFIG_QUANTA:
+               err = ops->cfg_q_quanta(vf, msg);
+               break;
        case VIRTCHNL_OP_UNKNOWN:
        default:
                dev_err(dev, "Unsupported opcode %d from VF %d\n", v_opcode,
index 3a411586915328ff15cf6f1f47bf6f3d0eb8a388..0c629aef9baf1c3bd788e2c46c5902244d2a7709 100644 (file)
 /* Restrict number of MAC Addr and VLAN that non-trusted VF can programmed */
 #define ICE_MAX_VLAN_PER_VF            8
 
+#define ICE_DFLT_QUANTA 1024
+#define ICE_MAX_QUANTA_SIZE 4096
+#define ICE_MIN_QUANTA_SIZE 256
+
+#define calc_quanta_desc(x)    \
+       max_t(u16, 12, min_t(u16, 63, (((x) + 66) / 132) * 2 + 4))
+
 /* MAC filters: 1 is reserved for the VF's default/perm_addr/LAA MAC, 1 for
  * broadcast, and 16 for additional unicast/multicast filters
  */
@@ -61,6 +68,10 @@ struct ice_virtchnl_ops {
        int (*dis_vlan_stripping_v2_msg)(struct ice_vf *vf, u8 *msg);
        int (*ena_vlan_insertion_v2_msg)(struct ice_vf *vf, u8 *msg);
        int (*dis_vlan_insertion_v2_msg)(struct ice_vf *vf, u8 *msg);
+       int (*get_qos_caps)(struct ice_vf *vf);
+       int (*cfg_q_tc_map)(struct ice_vf *vf, u8 *msg);
+       int (*cfg_q_bw)(struct ice_vf *vf, u8 *msg);
+       int (*cfg_q_quanta)(struct ice_vf *vf, u8 *msg);
 };
 
 #ifdef CONFIG_PCI_IOV
index d796dbd2a440cd550a9147956c6968286ae9cfa2..c105a82ee1364a91e15e557de56f36e1a8c9ad71 100644 (file)
@@ -84,6 +84,11 @@ static const u32 fdir_pf_allowlist_opcodes[] = {
        VIRTCHNL_OP_ADD_FDIR_FILTER, VIRTCHNL_OP_DEL_FDIR_FILTER,
 };
 
+static const u32 tc_allowlist_opcodes[] = {
+       VIRTCHNL_OP_GET_QOS_CAPS, VIRTCHNL_OP_CONFIG_QUEUE_BW,
+       VIRTCHNL_OP_CONFIG_QUANTA,
+};
+
 struct allowlist_opcode_info {
        const u32 *opcodes;
        size_t size;
@@ -104,6 +109,7 @@ static const struct allowlist_opcode_info allowlist_opcodes[] = {
        ALLOW_ITEM(VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF, adv_rss_pf_allowlist_opcodes),
        ALLOW_ITEM(VIRTCHNL_VF_OFFLOAD_FDIR_PF, fdir_pf_allowlist_opcodes),
        ALLOW_ITEM(VIRTCHNL_VF_OFFLOAD_VLAN_V2, vlan_v2_allowlist_opcodes),
+       ALLOW_ITEM(VIRTCHNL_VF_OFFLOAD_QOS, tc_allowlist_opcodes),
 };
 
 /**