From: Brett Creeley <[email protected]>

With new virtchnl offload/capability VFs are able to make use of more than
16 queues. But to old opcodes were designed with a max of 16 queues, so
new ones were added (by iavf/virtchnl commit of this series):
VIRTCHNL_OP_GET_MAX_RSS_QREGION, VIRTCHNL_OP_ENABLE_QUEUES_V2,
VIRTCHNL_OP_DISABLE_QUEUES_V2, VIRTCHNL_OP_MAP_QUEUE_VECTOR.

If a VF wishes to request >16 queues it should first make sure that the
PF supports the VIRTCHNL_VF_LARGE_NUM_QPAIRS capability.

Co-developed-by: Przemek Kitszel <[email protected]>
Signed-off-by: Przemek Kitszel <[email protected]>
Co-developed-by: Aleksandr Loktionov <[email protected]> # msglen 
val
Signed-off-by: Aleksandr Loktionov <[email protected]>
Signed-off-by: Brett Creeley <[email protected]>
---
 drivers/net/ethernet/intel/ice/ice_vf_lib.h   |   1 +
 drivers/net/ethernet/intel/ice/virt/queues.h  |   3 +
 .../net/ethernet/intel/ice/virt/allowlist.c   |   8 +
 drivers/net/ethernet/intel/ice/virt/queues.c  | 324 ++++++++++++++++++
 4 files changed, 336 insertions(+)

diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.h 
b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
index 1b56f7150eb7..5411eaa1761c 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
@@ -125,6 +125,7 @@ struct ice_vf_ops {
        void (*clear_reset_trigger)(struct ice_vf *vf);
        void (*irq_close)(struct ice_vf *vf);
        void (*post_vsi_rebuild)(struct ice_vf *vf);
+       struct ice_q_vector *(*get_q_vector)(struct ice_vsi *vsi, u16 vec_id);
 };
 
 /* Virtchnl/SR-IOV config info */
diff --git a/drivers/net/ethernet/intel/ice/virt/queues.h 
b/drivers/net/ethernet/intel/ice/virt/queues.h
index c4a792cecea1..223f609dd4f3 100644
--- a/drivers/net/ethernet/intel/ice/virt/queues.h
+++ b/drivers/net/ethernet/intel/ice/virt/queues.h
@@ -16,5 +16,8 @@ int ice_vc_cfg_q_bw(struct ice_vf *vf, u8 *msg);
 int ice_vc_cfg_q_quanta(struct ice_vf *vf, u8 *msg);
 int ice_vc_cfg_qs_msg(struct ice_vf *vf, u8 *msg);
 int ice_vc_request_qs_msg(struct ice_vf *vf, u8 *msg);
+int ice_vc_ena_qs_v2_msg(struct ice_vf *vf, u8 *msg, u16 msglen);
+int ice_vc_dis_qs_v2_msg(struct ice_vf *vf, u8 *msg, u16 msglen);
+int ice_vc_map_q_vector_msg(struct ice_vf *vf, u8 *msg, u16 msglen);
 
 #endif /* _ICE_VIRT_QUEUES_H_ */
diff --git a/drivers/net/ethernet/intel/ice/virt/allowlist.c 
b/drivers/net/ethernet/intel/ice/virt/allowlist.c
index a07efec19c45..ef769b843c6f 100644
--- a/drivers/net/ethernet/intel/ice/virt/allowlist.c
+++ b/drivers/net/ethernet/intel/ice/virt/allowlist.c
@@ -95,6 +95,13 @@ static const u32 tc_allowlist_opcodes[] = {
        VIRTCHNL_OP_CONFIG_QUANTA,
 };
 
+static const u32 large_num_qpairs_allowlist_opcodes[] = {
+       VIRTCHNL_OP_GET_MAX_RSS_QREGION,
+       VIRTCHNL_OP_ENABLE_QUEUES_V2,
+       VIRTCHNL_OP_DISABLE_QUEUES_V2,
+       VIRTCHNL_OP_MAP_QUEUE_VECTOR,
+};
+
 struct allowlist_opcode_info {
        const u32 *opcodes;
        size_t size;
@@ -117,6 +124,7 @@ static const struct allowlist_opcode_info 
allowlist_opcodes[] = {
        ALLOW_ITEM(VIRTCHNL_VF_OFFLOAD_VLAN_V2, vlan_v2_allowlist_opcodes),
        ALLOW_ITEM(VIRTCHNL_VF_OFFLOAD_QOS, tc_allowlist_opcodes),
        ALLOW_ITEM(VIRTCHNL_VF_CAP_PTP, ptp_allowlist_opcodes),
+       ALLOW_ITEM(VIRTCHNL_VF_LARGE_NUM_QPAIRS, 
large_num_qpairs_allowlist_opcodes),
 };
 
 /**
diff --git a/drivers/net/ethernet/intel/ice/virt/queues.c 
b/drivers/net/ethernet/intel/ice/virt/queues.c
index 1d9f69026d1b..b99f18a25024 100644
--- a/drivers/net/ethernet/intel/ice/virt/queues.c
+++ b/drivers/net/ethernet/intel/ice/virt/queues.c
@@ -1021,3 +1021,327 @@ int ice_vc_request_qs_msg(struct ice_vf *vf, u8 *msg)
                                     v_ret, (u8 *)vfres, sizeof(*vfres));
 }
 
+static bool ice_vc_supported_queue_type(s32 queue_type)
+{
+       return queue_type == VIRTCHNL_QUEUE_TYPE_RX ||
+              queue_type == VIRTCHNL_QUEUE_TYPE_TX;
+}
+
+/**
+ * ice_vc_validate_qs_v2_msg - validate all qs_msg parameters
+ * @vf: VF the message was received from
+ * @qs_msg: contents of the message from the VF
+ * @msglen: length of @qs_msg
+ *
+ * Used to validate both the VIRTCHNL_OP_ENABLE_QUEUES_V2 and
+ * VIRTCHNL_OP_DISABLE_QUEUES_V2 messages. This should always be called before
+ * attempting to enable and/or disable queues on behalf of a VF in response to
+ * the previously mentioned opcodes.
+ *
+ * Return: If all checks succeed, then return true. Otherwise return
+ *         false, indicating to the caller that the qs_msg is invalid.
+ */
+static bool ice_vc_validate_qs_v2_msg(struct ice_vf *vf,
+                                     struct virtchnl_del_ena_dis_queues 
*qs_msg,
+                                     u16 msglen)
+{
+       if (msglen < virtchnl_struct_size(qs_msg, chunks, 0))
+               return false;
+
+       if (msglen < virtchnl_struct_size(qs_msg, chunks, qs_msg->num_chunks))
+               return false;
+
+       if (!qs_msg->num_chunks)
+               return false;
+
+       if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states))
+               return false;
+
+       if (!ice_vc_isvalid_vsi_id(vf, qs_msg->vport_id))
+               return false;
+
+       for (int i = 0; i < qs_msg->num_chunks; i++) {
+               u32 max_queue_in_chunk;
+
+               if (!ice_vc_supported_queue_type(qs_msg->chunks[i].type))
+                       return false;
+
+               if (!qs_msg->chunks[i].num_queues)
+                       return false;
+
+               max_queue_in_chunk = qs_msg->chunks[i].start_queue_id +
+                                    qs_msg->chunks[i].num_queues;
+               if (max_queue_in_chunk > vf->num_vf_qs)
+                       return false;
+       }
+
+       return true;
+}
+
+#define ice_for_each_q_in_chunk(chunk, q_id) \
+       for ((q_id) = (chunk)->start_queue_id; \
+            (q_id) < (chunk)->start_queue_id + (chunk)->num_queues; \
+            (q_id)++)
+
+static int
+ice_vc_ena_rxq_chunk(struct ice_vf *vf, struct virtchnl_queue_chunk *chunk)
+{
+       struct ice_vsi *vsi;
+       u32 vf_qid;
+
+       ice_for_each_q_in_chunk(chunk, vf_qid) {
+               int err;
+
+               vsi = ice_get_vf_vsi(vf);
+               err = ice_vf_vsi_ena_single_rxq(vf, vsi, vf_qid);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int
+ice_vc_ena_txq_chunk(struct ice_vf *vf, struct virtchnl_queue_chunk *chunk)
+{
+       struct ice_vsi *vsi;
+       u32 vf_qid;
+
+       ice_for_each_q_in_chunk(chunk, vf_qid) {
+               vsi = ice_get_vf_vsi(vf);
+               ice_vf_vsi_ena_single_txq(vf, vsi, vf_qid);
+       }
+
+       return 0;
+}
+
+/**
+ * ice_vc_ena_qs_v2_msg - message handling for VIRTCHNL_OP_ENABLE_QUEUES_V2
+ * @vf: source of the request
+ * @msg: message to handle
+ * @msglen: length of the @msg
+ *
+ * Return: 0 on success or negative on error.
+ */
+int ice_vc_ena_qs_v2_msg(struct ice_vf *vf, u8 *msg, u16 msglen)
+{
+       struct virtchnl_del_ena_dis_queues *ena_qs_msg =
+                       (struct virtchnl_del_ena_dis_queues *)msg;
+       enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
+
+       if (!ice_vc_validate_qs_v2_msg(vf, ena_qs_msg, msglen))
+               goto error_param;
+
+       for (int i = 0; i < ena_qs_msg->num_chunks; i++) {
+               struct virtchnl_queue_chunk *chunk = &ena_qs_msg->chunks[i];
+
+               if (chunk->type == VIRTCHNL_QUEUE_TYPE_RX &&
+                   ice_vc_ena_rxq_chunk(vf, chunk))
+                       v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+               else if (chunk->type == VIRTCHNL_QUEUE_TYPE_TX &&
+                        ice_vc_ena_txq_chunk(vf, chunk))
+                       v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+
+               if (v_ret != VIRTCHNL_STATUS_SUCCESS)
+                       goto error_param;
+       }
+
+       set_bit(ICE_VF_STATE_QS_ENA, vf->vf_states);
+
+error_param:
+       return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ENABLE_QUEUES_V2,
+                                    v_ret, NULL, 0);
+}
+
+static int
+ice_vc_dis_rxq_chunk(struct ice_vf *vf, struct virtchnl_queue_chunk *chunk)
+{
+       struct ice_vsi *vsi;
+       u32 vf_qid;
+
+       ice_for_each_q_in_chunk(chunk, vf_qid) {
+               int err;
+
+               vsi = ice_get_vf_vsi(vf);
+               err = ice_vf_vsi_dis_single_rxq(vf, vsi, vf_qid);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int
+ice_vc_dis_txq_chunk(struct ice_vf *vf, struct virtchnl_queue_chunk *chunk)
+{
+       struct ice_vsi *vsi;
+       u32 vf_qid;
+
+       ice_for_each_q_in_chunk(chunk, vf_qid) {
+               int err;
+
+               vsi = ice_get_vf_vsi(vf);
+               err = ice_vf_vsi_dis_single_txq(vf, vsi, vf_qid);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+/**
+ * ice_vc_dis_qs_v2_msg - message handling for VIRTCHNL_OP_DISABLE_QUEUES_V2
+ * @vf: source of the request
+ * @msg: message to handle
+ * @msglen: length of @msg
+ *
+ * Return: 0 on success or negative on error.
+ */
+int ice_vc_dis_qs_v2_msg(struct ice_vf *vf, u8 *msg, u16 msglen)
+{
+       struct virtchnl_del_ena_dis_queues *dis_qs_msg =
+                       (struct virtchnl_del_ena_dis_queues *)msg;
+       enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
+
+       if (!ice_vc_validate_qs_v2_msg(vf, dis_qs_msg, msglen))
+               goto error_param;
+
+       for (int i = 0; i < dis_qs_msg->num_chunks; i++) {
+               struct virtchnl_queue_chunk *chunk = &dis_qs_msg->chunks[i];
+
+               if (chunk->type == VIRTCHNL_QUEUE_TYPE_RX &&
+                   ice_vc_dis_rxq_chunk(vf, chunk))
+                       v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+               else if (chunk->type == VIRTCHNL_QUEUE_TYPE_TX &&
+                        ice_vc_dis_txq_chunk(vf, chunk))
+                       v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+
+               if (v_ret != VIRTCHNL_STATUS_SUCCESS)
+                       goto error_param;
+       }
+
+       if (ice_vf_has_no_qs_ena(vf))
+               clear_bit(ICE_VF_STATE_QS_ENA, vf->vf_states);
+
+error_param:
+       return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DISABLE_QUEUES_V2,
+                                    v_ret, NULL, 0);
+}
+
+/**
+ * ice_vc_validate_qv_maps - validate parameters sent in the qs_msg structure
+ * @vf: VF the message was received from
+ * @qv_maps: contents of the message from the VF
+ * @msglen: length of the @qv_maps
+ *
+ * Used to validate VIRTCHNL_OP_MAP_QUEUE_VECTOR messages. This should always
+ * be called before attempting map interrupts to queues. If all checks succeed,
+ * then return success indicating to the caller that the qv_maps are valid.
+ * Otherwise return false, indicating to the caller that the qv_maps are
+ * invalid.
+ *
+ * Return: true if parameters are valid, false otherwise.
+ */
+static bool ice_vc_validate_qv_maps(struct ice_vf *vf,
+                                   struct virtchnl_queue_vector_maps *qv_maps,
+                                   u16 msglen)
+{
+       struct ice_vsi *vsi;
+       int total_vectors;
+
+       vsi = vf->pf->vsi[vf->lan_vsi_idx];
+       if (!vsi)
+               return false;
+
+       if (msglen < virtchnl_struct_size(qv_maps, qv_maps, 0))
+               return false;
+
+       if (msglen < virtchnl_struct_size(qv_maps, qv_maps, 
qv_maps->num_qv_maps))
+               return false;
+
+       if (!qv_maps->num_qv_maps)
+               return false;
+
+       if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states))
+               return false;
+
+       if (!ice_vc_isvalid_vsi_id(vf, qv_maps->vport_id))
+               return false;
+
+       total_vectors = vsi->num_q_vectors + ICE_NONQ_VECS_VF;
+
+       for (int i = 0; i < qv_maps->num_qv_maps; i++) {
+               if 
(!ice_vc_supported_queue_type(qv_maps->qv_maps[i].queue_type))
+                       return false;
+
+               if (qv_maps->qv_maps[i].queue_id >= vf->num_vf_qs)
+                       return false;
+
+               if (qv_maps->qv_maps[i].vector_id >= total_vectors ||
+                   qv_maps->qv_maps[i].vector_id < ICE_NONQ_VECS_VF)
+                       return false;
+       }
+
+       return true;
+}
+
+/**
+ * ice_vc_map_q_vector_msg - message handling for VIRTCHNL_OP_MAP_QUEUE_VECTOR
+ * @vf: source of the request
+ * @msg: message to handle
+ * @msglen: length of @msg
+ *
+ * Return: 0 on success or negative on error
+ */
+int ice_vc_map_q_vector_msg(struct ice_vf *vf, u8 *msg, u16 msglen)
+{
+       enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
+       struct virtchnl_queue_vector_maps *qv_maps;
+       struct ice_vsi *vsi;
+
+       qv_maps = (struct virtchnl_queue_vector_maps *)msg;
+
+       if (!ice_vc_validate_qv_maps(vf, qv_maps, msglen)) {
+               v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+               goto error_param;
+       }
+
+       for (int i = 0; i < qv_maps->num_qv_maps; i++) {
+               struct virtchnl_queue_vector *qv_map = &qv_maps->qv_maps[i];
+               struct ice_q_vector *q_vector;
+               u16 vector_id;
+               int vsi_q_id;
+
+               vsi = ice_get_vf_vsi(vf);
+               vsi_q_id = qv_map->queue_id;
+               vector_id = qv_map->vector_id;
+
+               if (!vsi) {
+                       v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+                       goto error_param;
+               }
+
+               q_vector = vf->vf_ops->get_q_vector(vsi, vector_id);
+
+               if (!q_vector) {
+                       v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+                       goto error_param;
+               }
+
+               if (!ice_vc_isvalid_q_id(vsi, vsi_q_id))
+                       return VIRTCHNL_STATUS_ERR_PARAM;
+
+               if (qv_map->queue_type == VIRTCHNL_QUEUE_TYPE_RX)
+                       ice_cfg_rxq_interrupt(vsi, vsi_q_id,
+                                             q_vector->vf_reg_idx,
+                                             qv_map->itr_idx);
+               else if (qv_map->queue_type == VIRTCHNL_QUEUE_TYPE_TX)
+                       ice_cfg_txq_interrupt(vsi, vsi_q_id,
+                                             q_vector->vf_reg_idx,
+                                             qv_map->itr_idx);
+       }
+
+error_param:
+       return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_MAP_QUEUE_VECTOR,
+                                    v_ret, NULL, 0);
+}
-- 
2.39.3

Reply via email to