+
+int
+iavf_fdir_add(struct iavf_adapter *adapter,
+ struct iavf_fdir_conf *filter)
+{
+ struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(adapter);
+ struct virtchnl_fdir_add *fdir_ret;
+
+ struct iavf_cmd_info args;
+ int err;
+
+ filter->add_fltr.vsi_id = vf->vsi_res->vsi_id;
+ filter->add_fltr.validate_only = 0;
+
+ args.ops = VIRTCHNL_OP_ADD_FDIR_FILTER;
+ args.in_args = (uint8_t *)(&filter->add_fltr);
+ args.in_args_size = sizeof(*(&filter->add_fltr));
+ args.out_buffer = vf->aq_resp;
+ args.out_size = IAVF_AQ_BUF_SZ;
+
+ err = iavf_execute_vf_cmd(adapter, &args);
+ if (err) {
+ PMD_DRV_LOG(ERR, "fail to execute command OP_ADD_FDIR_FILTER");
+ return err;
+ }
+
+ fdir_ret = (struct virtchnl_fdir_add *)args.out_buffer;
+ filter->flow_id = fdir_ret->flow_id;
+
+ if (fdir_ret->status == VIRTCHNL_FDIR_SUCCESS) {
+ PMD_DRV_LOG(INFO,
+ "Succeed in adding rule request by PF");
+ } else if (fdir_ret->status == VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE) {
+ PMD_DRV_LOG(ERR,
+ "Failed to add rule request due to no hw resource");
+ return -1;
+ } else if (fdir_ret->status == VIRTCHNL_FDIR_FAILURE_RULE_EXIST) {
+ PMD_DRV_LOG(ERR,
+ "Failed to add rule request due to the rule is already existed");
+ return -1;
+ } else if (fdir_ret->status == VIRTCHNL_FDIR_FAILURE_RULE_CONFLICT) {
+ PMD_DRV_LOG(ERR,
+ "Failed to add rule request due to the rule is conflict with existing rule");
+ return -1;
+ } else if (fdir_ret->status == VIRTCHNL_FDIR_FAILURE_RULE_INVALID) {
+ PMD_DRV_LOG(ERR,
+ "Failed to add rule request due to the hw doesn't support");
+ return -1;
+ } else if (fdir_ret->status == VIRTCHNL_FDIR_FAILURE_RULE_TIMEOUT) {
+ PMD_DRV_LOG(ERR,
+ "Failed to add rule request due to time out for programming");
+ return -1;
+ } else {
+ PMD_DRV_LOG(ERR,
+ "Failed to add rule request due to other reasons");
+ return -1;
+ }
+
+ return 0;
+};
+
+int
+iavf_fdir_del(struct iavf_adapter *adapter,
+ struct iavf_fdir_conf *filter)
+{
+ struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(adapter);
+ struct virtchnl_fdir_del *fdir_ret;
+
+ struct iavf_cmd_info args;
+ int err;
+
+ filter->del_fltr.vsi_id = vf->vsi_res->vsi_id;
+ filter->del_fltr.flow_id = filter->flow_id;
+
+ args.ops = VIRTCHNL_OP_DEL_FDIR_FILTER;
+ args.in_args = (uint8_t *)(&filter->del_fltr);
+ args.in_args_size = sizeof(filter->del_fltr);
+ args.out_buffer = vf->aq_resp;
+ args.out_size = IAVF_AQ_BUF_SZ;
+
+ err = iavf_execute_vf_cmd(adapter, &args);
+ if (err) {
+ PMD_DRV_LOG(ERR, "fail to execute command OP_DEL_FDIR_FILTER");
+ return err;
+ }
+
+ fdir_ret = (struct virtchnl_fdir_del *)args.out_buffer;
+
+ if (fdir_ret->status == VIRTCHNL_FDIR_SUCCESS) {
+ PMD_DRV_LOG(INFO,
+ "Succeed in deleting rule request by PF");
+ } else if (fdir_ret->status == VIRTCHNL_FDIR_FAILURE_RULE_NONEXIST) {
+ PMD_DRV_LOG(ERR,
+ "Failed to delete rule request due to this rule doesn't exist");
+ return -1;
+ } else if (fdir_ret->status == VIRTCHNL_FDIR_FAILURE_RULE_TIMEOUT) {
+ PMD_DRV_LOG(ERR,
+ "Failed to delete rule request due to time out for programming");
+ return -1;
+ } else {
+ PMD_DRV_LOG(ERR,
+ "Failed to delete rule request due to other reasons");
+ return -1;
+ }
+
+ return 0;
+};
+
+int
+iavf_fdir_check(struct iavf_adapter *adapter,
+ struct iavf_fdir_conf *filter)
+{
+ struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(adapter);
+ struct virtchnl_fdir_add *fdir_ret;
+
+ struct iavf_cmd_info args;
+ int err;
+
+ filter->add_fltr.vsi_id = vf->vsi_res->vsi_id;
+ filter->add_fltr.validate_only = 1;
+
+ args.ops = VIRTCHNL_OP_ADD_FDIR_FILTER;
+ args.in_args = (uint8_t *)(&filter->add_fltr);
+ args.in_args_size = sizeof(*(&filter->add_fltr));
+ args.out_buffer = vf->aq_resp;
+ args.out_size = IAVF_AQ_BUF_SZ;
+
+ err = iavf_execute_vf_cmd(adapter, &args);
+ if (err) {
+ PMD_DRV_LOG(ERR, "fail to check flow direcotor rule");
+ return err;
+ }
+
+ fdir_ret = (struct virtchnl_fdir_add *)args.out_buffer;
+
+ if (fdir_ret->status == VIRTCHNL_FDIR_SUCCESS) {
+ PMD_DRV_LOG(INFO,
+ "Succeed in checking rule request by PF");
+ } else if (fdir_ret->status == VIRTCHNL_FDIR_FAILURE_RULE_INVALID) {
+ PMD_DRV_LOG(ERR,
+ "Failed to check rule request due to parameters validation"
+ " or HW doesn't support");
+ return -1;
+ } else {
+ PMD_DRV_LOG(ERR,
+ "Failed to check rule request due to other reasons");
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+iavf_add_del_rss_cfg(struct iavf_adapter *adapter,
+ struct virtchnl_rss_cfg *rss_cfg, bool add)
+{
+ struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(adapter);
+ struct iavf_cmd_info args;
+ int err;
+
+ memset(&args, 0, sizeof(args));
+ args.ops = add ? VIRTCHNL_OP_ADD_RSS_CFG :
+ VIRTCHNL_OP_DEL_RSS_CFG;
+ args.in_args = (u8 *)rss_cfg;
+ args.in_args_size = sizeof(*rss_cfg);
+ args.out_buffer = vf->aq_resp;
+ args.out_size = IAVF_AQ_BUF_SZ;
+
+ err = iavf_execute_vf_cmd(adapter, &args);
+ if (err)
+ PMD_DRV_LOG(ERR,
+ "Failed to execute command of %s",
+ add ? "OP_ADD_RSS_CFG" :
+ "OP_DEL_RSS_INPUT_CFG");
+
+ return err;
+}
+
+int
+iavf_set_hena(struct iavf_adapter *adapter, uint64_t hena)
+{
+ struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(adapter);
+ struct virtchnl_rss_hena vrh;
+ struct iavf_cmd_info args;
+ int err;
+
+ vrh.hena = hena;
+ args.ops = VIRTCHNL_OP_SET_RSS_HENA;
+ args.in_args = (u8 *)&vrh;
+ args.in_args_size = sizeof(vrh);
+ args.out_buffer = vf->aq_resp;
+ args.out_size = IAVF_AQ_BUF_SZ;
+
+ err = iavf_execute_vf_cmd(adapter, &args);
+ if (err)
+ PMD_DRV_LOG(ERR,
+ "Failed to execute command of OP_SET_RSS_HENA");
+
+ return err;
+}
+
+int
+iavf_add_del_mc_addr_list(struct iavf_adapter *adapter,
+ struct rte_ether_addr *mc_addrs,
+ uint32_t mc_addrs_num, bool add)
+{
+ struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(adapter);
+ uint8_t cmd_buffer[sizeof(struct virtchnl_ether_addr_list) +
+ (IAVF_NUM_MACADDR_MAX * sizeof(struct virtchnl_ether_addr))];
+ struct virtchnl_ether_addr_list *list;
+ struct iavf_cmd_info args;
+ uint32_t i;
+ int err;
+
+ if (mc_addrs == NULL || mc_addrs_num == 0)
+ return 0;
+
+ list = (struct virtchnl_ether_addr_list *)cmd_buffer;
+ list->vsi_id = vf->vsi_res->vsi_id;
+ list->num_elements = mc_addrs_num;
+
+ for (i = 0; i < mc_addrs_num; i++) {
+ if (!IAVF_IS_MULTICAST(mc_addrs[i].addr_bytes)) {
+ PMD_DRV_LOG(ERR, "Invalid mac:%x:%x:%x:%x:%x:%x",
+ mc_addrs[i].addr_bytes[0],
+ mc_addrs[i].addr_bytes[1],
+ mc_addrs[i].addr_bytes[2],
+ mc_addrs[i].addr_bytes[3],
+ mc_addrs[i].addr_bytes[4],
+ mc_addrs[i].addr_bytes[5]);
+ return -EINVAL;
+ }
+
+ memcpy(list->list[i].addr, mc_addrs[i].addr_bytes,
+ sizeof(list->list[i].addr));
+ }
+
+ args.ops = add ? VIRTCHNL_OP_ADD_ETH_ADDR : VIRTCHNL_OP_DEL_ETH_ADDR;
+ args.in_args = cmd_buffer;
+ args.in_args_size = sizeof(struct virtchnl_ether_addr_list) +
+ i * sizeof(struct virtchnl_ether_addr);
+ args.out_buffer = vf->aq_resp;
+ args.out_size = IAVF_AQ_BUF_SZ;
+ err = iavf_execute_vf_cmd(adapter, &args);
+
+ if (err) {
+ PMD_DRV_LOG(ERR, "fail to execute command %s",
+ add ? "OP_ADD_ETH_ADDR" : "OP_DEL_ETH_ADDR");
+ return err;
+ }
+
+ return 0;
+}
+
+int
+iavf_request_queues(struct iavf_adapter *adapter, uint16_t num)
+{
+ struct rte_eth_dev *dev = adapter->eth_dev;
+ struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(adapter);
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+ struct virtchnl_vf_res_request vfres;
+ struct iavf_cmd_info args;
+ uint16_t num_queue_pairs;
+ int err;
+
+ if (!(vf->vf_res->vf_cap_flags &
+ VIRTCHNL_VF_OFFLOAD_REQ_QUEUES)) {
+ PMD_DRV_LOG(ERR, "request queues not supported");
+ return -1;
+ }
+
+ if (num == 0) {
+ PMD_DRV_LOG(ERR, "queue number cannot be zero");
+ return -1;
+ }
+ vfres.num_queue_pairs = num;
+
+ args.ops = VIRTCHNL_OP_REQUEST_QUEUES;
+ args.in_args = (u8 *)&vfres;
+ args.in_args_size = sizeof(vfres);
+ args.out_buffer = vf->aq_resp;
+ args.out_size = IAVF_AQ_BUF_SZ;
+
+ /*
+ * disable interrupt to avoid the admin queue message to be read
+ * before iavf_read_msg_from_pf.
+ */
+ rte_intr_disable(&pci_dev->intr_handle);
+ err = iavf_execute_vf_cmd(adapter, &args);
+ rte_intr_enable(&pci_dev->intr_handle);
+ if (err) {
+ PMD_DRV_LOG(ERR, "fail to execute command OP_REQUEST_QUEUES");
+ return err;
+ }
+
+ /* request queues succeeded, vf is resetting */
+ if (vf->vf_reset) {
+ PMD_DRV_LOG(INFO, "vf is resetting");
+ return 0;
+ }
+
+ /* request additional queues failed, return available number */
+ num_queue_pairs =
+ ((struct virtchnl_vf_res_request *)args.out_buffer)->num_queue_pairs;
+ PMD_DRV_LOG(ERR, "request queues failed, only %u queues "
+ "available", num_queue_pairs);
+
+ return -1;
+}
+
+int
+iavf_get_max_rss_queue_region(struct iavf_adapter *adapter)
+{
+ struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(adapter);
+ struct iavf_cmd_info args;
+ uint16_t qregion_width;
+ int err;
+
+ args.ops = VIRTCHNL_OP_GET_MAX_RSS_QREGION;
+ args.in_args = NULL;
+ args.in_args_size = 0;
+ args.out_buffer = vf->aq_resp;
+ args.out_size = IAVF_AQ_BUF_SZ;
+
+ err = iavf_execute_vf_cmd(adapter, &args);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to execute command of VIRTCHNL_OP_GET_MAX_RSS_QREGION");
+ return err;
+ }
+
+ qregion_width =
+ ((struct virtchnl_max_rss_qregion *)args.out_buffer)->qregion_width;
+
+ vf->max_rss_qregion = (uint16_t)(1 << qregion_width);
+
+ return 0;
+}