From: Przemek Kitszel Start removing stuff from virt/rss.c that will be kept in the main virtchnl file. Signed-off-by: Przemek Kitszel Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/virt/rss.c | 1408 --------------------- 1 file changed, 1408 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/virt/rss.c b/drivers/net/ethernet/intel/ice/virt/rss.c index 68135d1307f4..5003f48e8a84 100644 --- a/drivers/net/ethernet/intel/ice/virt/rss.c +++ b/drivers/net/ethernet/intel/ice/virt/rss.c @@ -1,18 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (C) 2022, Intel Corporation. */ -#include "virtchnl.h" -#include "queues.h" #include "ice_vf_lib_private.h" #include "ice.h" -#include "ice_base.h" -#include "ice_lib.h" -#include "ice_fltr.h" -#include "allowlist.h" -#include "ice_vf_vsi_vlan_ops.h" -#include "ice_vlan.h" -#include "ice_flex_pipe.h" -#include "ice_dcb_lib.h" #define FIELD_SELECTOR(proto_hdr_field) \ BIT((proto_hdr_field) & PROTO_HDR_FIELD_MASK) @@ -166,377 +156,6 @@ ice_vc_hash_field_match_type ice_vc_hash_field_list[] = { BIT_ULL(ICE_FLOW_FIELD_IDX_PFCP_SEID)}, }; -/** - * ice_vc_vf_broadcast - Broadcast a message to all VFs on PF - * @pf: pointer to the PF structure - * @v_opcode: operation code - * @v_retval: return value - * @msg: pointer to the msg buffer - * @msglen: msg length - */ -static void -ice_vc_vf_broadcast(struct ice_pf *pf, enum virtchnl_ops v_opcode, - enum virtchnl_status_code v_retval, u8 *msg, u16 msglen) -{ - struct ice_hw *hw = &pf->hw; - struct ice_vf *vf; - unsigned int bkt; - - mutex_lock(&pf->vfs.table_lock); - ice_for_each_vf(pf, bkt, vf) { - /* Not all vfs are enabled so skip the ones that are not */ - if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states) && - !test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) - continue; - - /* Ignore return value on purpose - a given VF may fail, but - * we need to keep going and send to all of them - */ - ice_aq_send_msg_to_vf(hw, vf->vf_id, v_opcode, v_retval, msg, - msglen, NULL); - } - mutex_unlock(&pf->vfs.table_lock); -} - -/** - * ice_set_pfe_link - Set the link speed/status of the virtchnl_pf_event - * @vf: pointer to the VF structure - * @pfe: pointer to the virtchnl_pf_event to set link speed/status for - * @ice_link_speed: link speed specified by ICE_AQ_LINK_SPEED_* - * @link_up: whether or not to set the link up/down - */ -static void -ice_set_pfe_link(struct ice_vf *vf, struct virtchnl_pf_event *pfe, - int ice_link_speed, bool link_up) -{ - if (vf->driver_caps & VIRTCHNL_VF_CAP_ADV_LINK_SPEED) { - pfe->event_data.link_event_adv.link_status = link_up; - /* Speed in Mbps */ - pfe->event_data.link_event_adv.link_speed = - ice_conv_link_speed_to_virtchnl(true, ice_link_speed); - } else { - pfe->event_data.link_event.link_status = link_up; - /* Legacy method for virtchnl link speeds */ - pfe->event_data.link_event.link_speed = - (enum virtchnl_link_speed) - ice_conv_link_speed_to_virtchnl(false, ice_link_speed); - } -} - -/** - * ice_vc_notify_vf_link_state - Inform a VF of link status - * @vf: pointer to the VF structure - * - * send a link status message to a single VF - */ -void ice_vc_notify_vf_link_state(struct ice_vf *vf) -{ - struct virtchnl_pf_event pfe = { 0 }; - struct ice_hw *hw = &vf->pf->hw; - - pfe.event = VIRTCHNL_EVENT_LINK_CHANGE; - pfe.severity = PF_EVENT_SEVERITY_INFO; - - if (ice_is_vf_link_up(vf)) - ice_set_pfe_link(vf, &pfe, - hw->port_info->phy.link_info.link_speed, true); - else - ice_set_pfe_link(vf, &pfe, ICE_AQ_LINK_SPEED_UNKNOWN, false); - - ice_aq_send_msg_to_vf(hw, vf->vf_id, VIRTCHNL_OP_EVENT, - VIRTCHNL_STATUS_SUCCESS, (u8 *)&pfe, - sizeof(pfe), NULL); -} - -/** - * ice_vc_notify_link_state - Inform all VFs on a PF of link status - * @pf: pointer to the PF structure - */ -void ice_vc_notify_link_state(struct ice_pf *pf) -{ - struct ice_vf *vf; - unsigned int bkt; - - mutex_lock(&pf->vfs.table_lock); - ice_for_each_vf(pf, bkt, vf) - ice_vc_notify_vf_link_state(vf); - mutex_unlock(&pf->vfs.table_lock); -} - -/** - * ice_vc_notify_reset - Send pending reset message to all VFs - * @pf: pointer to the PF structure - * - * indicate a pending reset to all VFs on a given PF - */ -void ice_vc_notify_reset(struct ice_pf *pf) -{ - struct virtchnl_pf_event pfe; - - if (!ice_has_vfs(pf)) - return; - - pfe.event = VIRTCHNL_EVENT_RESET_IMPENDING; - pfe.severity = PF_EVENT_SEVERITY_CERTAIN_DOOM; - ice_vc_vf_broadcast(pf, VIRTCHNL_OP_EVENT, VIRTCHNL_STATUS_SUCCESS, - (u8 *)&pfe, sizeof(struct virtchnl_pf_event)); -} - -/** - * ice_vc_send_msg_to_vf - Send message to VF - * @vf: pointer to the VF info - * @v_opcode: virtual channel opcode - * @v_retval: virtual channel return value - * @msg: pointer to the msg buffer - * @msglen: msg length - * - * send msg to VF - */ -int -ice_vc_send_msg_to_vf(struct ice_vf *vf, u32 v_opcode, - enum virtchnl_status_code v_retval, u8 *msg, u16 msglen) -{ - struct device *dev; - struct ice_pf *pf; - int aq_ret; - - pf = vf->pf; - dev = ice_pf_to_dev(pf); - - aq_ret = ice_aq_send_msg_to_vf(&pf->hw, vf->vf_id, v_opcode, v_retval, - msg, msglen, NULL); - if (aq_ret && pf->hw.mailboxq.sq_last_status != LIBIE_AQ_RC_ENOSYS) { - dev_info(dev, "Unable to send the message to VF %d ret %d aq_err %s\n", - vf->vf_id, aq_ret, - libie_aq_str(pf->hw.mailboxq.sq_last_status)); - return -EIO; - } - - return 0; -} - -/** - * ice_vc_get_ver_msg - * @vf: pointer to the VF info - * @msg: pointer to the msg buffer - * - * called from the VF to request the API version used by the PF - */ -static int ice_vc_get_ver_msg(struct ice_vf *vf, u8 *msg) -{ - struct virtchnl_version_info info = { - VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR - }; - - vf->vf_ver = *(struct virtchnl_version_info *)msg; - /* VFs running the 1.0 API expect to get 1.0 back or they will cry. */ - if (VF_IS_V10(&vf->vf_ver)) - info.minor = VIRTCHNL_VERSION_MINOR_NO_VF_CAPS; - - return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_VERSION, - VIRTCHNL_STATUS_SUCCESS, (u8 *)&info, - sizeof(struct virtchnl_version_info)); -} - -/** - * ice_vc_get_vlan_caps - * @hw: pointer to the hw - * @vf: pointer to the VF info - * @vsi: pointer to the VSI - * @driver_caps: current driver caps - * - * Return 0 if there is no VLAN caps supported, or VLAN caps value - */ -static u32 -ice_vc_get_vlan_caps(struct ice_hw *hw, struct ice_vf *vf, struct ice_vsi *vsi, - u32 driver_caps) -{ - if (ice_is_eswitch_mode_switchdev(vf->pf)) - /* In switchdev setting VLAN from VF isn't supported */ - return 0; - - if (driver_caps & VIRTCHNL_VF_OFFLOAD_VLAN_V2) { - /* VLAN offloads based on current device configuration */ - return VIRTCHNL_VF_OFFLOAD_VLAN_V2; - } else if (driver_caps & VIRTCHNL_VF_OFFLOAD_VLAN) { - /* allow VF to negotiate VIRTCHNL_VF_OFFLOAD explicitly for - * these two conditions, which amounts to guest VLAN filtering - * and offloads being based on the inner VLAN or the - * inner/single VLAN respectively and don't allow VF to - * negotiate VIRTCHNL_VF_OFFLOAD in any other cases - */ - if (ice_is_dvm_ena(hw) && ice_vf_is_port_vlan_ena(vf)) { - return VIRTCHNL_VF_OFFLOAD_VLAN; - } else if (!ice_is_dvm_ena(hw) && - !ice_vf_is_port_vlan_ena(vf)) { - /* configure backward compatible support for VFs that - * only support VIRTCHNL_VF_OFFLOAD_VLAN, the PF is - * configured in SVM, and no port VLAN is configured - */ - ice_vf_vsi_cfg_svm_legacy_vlan_mode(vsi); - return VIRTCHNL_VF_OFFLOAD_VLAN; - } else if (ice_is_dvm_ena(hw)) { - /* configure software offloaded VLAN support when DVM - * is enabled, but no port VLAN is enabled - */ - ice_vf_vsi_cfg_dvm_legacy_vlan_mode(vsi); - } - } - - return 0; -} - -/** - * ice_vc_get_vf_res_msg - * @vf: pointer to the VF info - * @msg: pointer to the msg buffer - * - * called from the VF to request its resources - */ -static int ice_vc_get_vf_res_msg(struct ice_vf *vf, u8 *msg) -{ - enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; - struct virtchnl_vf_resource *vfres = NULL; - struct ice_hw *hw = &vf->pf->hw; - struct ice_vsi *vsi; - int len = 0; - int ret; - - if (ice_check_vf_init(vf)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto err; - } - - len = virtchnl_struct_size(vfres, vsi_res, 0); - - vfres = kzalloc(len, GFP_KERNEL); - if (!vfres) { - v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; - len = 0; - goto err; - } - if (VF_IS_V11(&vf->vf_ver)) - vf->driver_caps = *(u32 *)msg; - else - vf->driver_caps = VIRTCHNL_VF_OFFLOAD_L2 | - VIRTCHNL_VF_OFFLOAD_VLAN; - - vfres->vf_cap_flags = VIRTCHNL_VF_OFFLOAD_L2; - vsi = ice_get_vf_vsi(vf); - if (!vsi) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto err; - } - - vfres->vf_cap_flags |= ice_vc_get_vlan_caps(hw, vf, vsi, - vf->driver_caps); - - if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PF) - vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_PF; - - if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC) - vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC; - - if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_FDIR_PF) - vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_FDIR_PF; - - if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_TC_U32 && - vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_FDIR_PF) - vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_TC_U32; - - if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2) - vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2; - - if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ENCAP) - vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_ENCAP; - - if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM) - vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM; - - if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RX_POLLING) - vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RX_POLLING; - - if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_WB_ON_ITR) - vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_WB_ON_ITR; - - if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_REQ_QUEUES) - vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_REQ_QUEUES; - - if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_CRC) - vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_CRC; - - if (vf->driver_caps & VIRTCHNL_VF_CAP_ADV_LINK_SPEED) - vfres->vf_cap_flags |= VIRTCHNL_VF_CAP_ADV_LINK_SPEED; - - if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF) - vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF; - - 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; - - if (vf->driver_caps & VIRTCHNL_VF_CAP_PTP) - vfres->vf_cap_flags |= VIRTCHNL_VF_CAP_PTP; - - vfres->num_vsis = 1; - /* Tx and Rx queue are equal for VF */ - vfres->num_queue_pairs = vsi->num_txq; - vfres->max_vectors = vf->num_msix; - vfres->rss_key_size = ICE_VSIQF_HKEY_ARRAY_SIZE; - vfres->rss_lut_size = ICE_LUT_VSI_SIZE; - vfres->max_mtu = ice_vc_get_max_frame_size(vf); - - vfres->vsi_res[0].vsi_id = ICE_VF_VSI_ID; - vfres->vsi_res[0].vsi_type = VIRTCHNL_VSI_SRIOV; - vfres->vsi_res[0].num_queue_pairs = vsi->num_txq; - ether_addr_copy(vfres->vsi_res[0].default_mac_addr, - vf->hw_lan_addr); - - /* match guest capabilities */ - vf->driver_caps = vfres->vf_cap_flags; - - ice_vc_set_caps_allowlist(vf); - ice_vc_set_working_allowlist(vf); - - set_bit(ICE_VF_STATE_ACTIVE, vf->vf_states); - -err: - /* send the response back to the VF */ - ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_VF_RESOURCES, v_ret, - (u8 *)vfres, len); - - kfree(vfres); - return ret; -} - -/** - * ice_vc_reset_vf_msg - * @vf: pointer to the VF info - * - * called from the VF to reset itself, - * unlike other virtchnl messages, PF driver - * doesn't send the response back to the VF - */ -static void ice_vc_reset_vf_msg(struct ice_vf *vf) -{ - if (test_bit(ICE_VF_STATE_INIT, vf->vf_states)) - ice_reset_vf(vf, 0); -} - -/** - * ice_vc_isvalid_vsi_id - * @vf: pointer to the VF info - * @vsi_id: VF relative VSI ID - * - * check for the valid VSI ID - */ -bool ice_vc_isvalid_vsi_id(struct ice_vf *vf, u16 vsi_id) -{ - return vsi_id == ICE_VF_VSI_ID; -} - /** * ice_vc_validate_pattern * @vf: pointer to the VF info @@ -991,1033 +610,6 @@ static int ice_vc_config_rss_hfunc(struct ice_vf *vf, u8 *msg) 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_vc_cfg_promiscuous_mode_msg - * @vf: pointer to the VF info - * @msg: pointer to the msg buffer - * - * called from the VF to configure VF VSIs promiscuous mode - */ -static int ice_vc_cfg_promiscuous_mode_msg(struct ice_vf *vf, u8 *msg) -{ - enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; - bool rm_promisc, alluni = false, allmulti = false; - struct virtchnl_promisc_info *info = - (struct virtchnl_promisc_info *)msg; - struct ice_vsi_vlan_ops *vlan_ops; - int mcast_err = 0, ucast_err = 0; - struct ice_pf *pf = vf->pf; - struct ice_vsi *vsi; - u8 mcast_m, ucast_m; - struct device *dev; - int ret = 0; - - if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (!ice_vc_isvalid_vsi_id(vf, info->vsi_id)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - vsi = ice_get_vf_vsi(vf); - if (!vsi) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - dev = ice_pf_to_dev(pf); - if (!ice_is_vf_trusted(vf)) { - dev_err(dev, "Unprivileged VF %d is attempting to configure promiscuous mode\n", - vf->vf_id); - /* Leave v_ret alone, lie to the VF on purpose. */ - goto error_param; - } - - if (info->flags & FLAG_VF_UNICAST_PROMISC) - alluni = true; - - if (info->flags & FLAG_VF_MULTICAST_PROMISC) - allmulti = true; - - rm_promisc = !allmulti && !alluni; - - vlan_ops = ice_get_compat_vsi_vlan_ops(vsi); - if (rm_promisc) - ret = vlan_ops->ena_rx_filtering(vsi); - else - ret = vlan_ops->dis_rx_filtering(vsi); - if (ret) { - dev_err(dev, "Failed to configure VLAN pruning in promiscuous mode\n"); - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - ice_vf_get_promisc_masks(vf, vsi, &ucast_m, &mcast_m); - - if (!test_bit(ICE_FLAG_VF_TRUE_PROMISC_ENA, pf->flags)) { - if (alluni) { - /* in this case we're turning on promiscuous mode */ - ret = ice_set_dflt_vsi(vsi); - } else { - /* in this case we're turning off promiscuous mode */ - if (ice_is_dflt_vsi_in_use(vsi->port_info)) - ret = ice_clear_dflt_vsi(vsi); - } - - /* in this case we're turning on/off only - * allmulticast - */ - if (allmulti) - mcast_err = ice_vf_set_vsi_promisc(vf, vsi, mcast_m); - else - mcast_err = ice_vf_clear_vsi_promisc(vf, vsi, mcast_m); - - if (ret) { - dev_err(dev, "Turning on/off promiscuous mode for VF %d failed, error: %d\n", - vf->vf_id, ret); - v_ret = VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR; - goto error_param; - } - } else { - if (alluni) - ucast_err = ice_vf_set_vsi_promisc(vf, vsi, ucast_m); - else - ucast_err = ice_vf_clear_vsi_promisc(vf, vsi, ucast_m); - - if (allmulti) - mcast_err = ice_vf_set_vsi_promisc(vf, vsi, mcast_m); - else - mcast_err = ice_vf_clear_vsi_promisc(vf, vsi, mcast_m); - - if (ucast_err || mcast_err) - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - } - - if (!mcast_err) { - if (allmulti && - !test_and_set_bit(ICE_VF_STATE_MC_PROMISC, vf->vf_states)) - dev_info(dev, "VF %u successfully set multicast promiscuous mode\n", - vf->vf_id); - else if (!allmulti && - test_and_clear_bit(ICE_VF_STATE_MC_PROMISC, - vf->vf_states)) - dev_info(dev, "VF %u successfully unset multicast promiscuous mode\n", - vf->vf_id); - } else { - dev_err(dev, "Error while modifying multicast promiscuous mode for VF %u, error: %d\n", - vf->vf_id, mcast_err); - } - - if (!ucast_err) { - if (alluni && - !test_and_set_bit(ICE_VF_STATE_UC_PROMISC, vf->vf_states)) - dev_info(dev, "VF %u successfully set unicast promiscuous mode\n", - vf->vf_id); - else if (!alluni && - test_and_clear_bit(ICE_VF_STATE_UC_PROMISC, - vf->vf_states)) - dev_info(dev, "VF %u successfully unset unicast promiscuous mode\n", - vf->vf_id); - } else { - dev_err(dev, "Error while modifying unicast promiscuous mode for VF %u, error: %d\n", - vf->vf_id, ucast_err); - } - -error_param: - return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, - v_ret, NULL, 0); -} - -/** - * ice_vc_get_stats_msg - * @vf: pointer to the VF info - * @msg: pointer to the msg buffer - * - * called from the VF to get VSI stats - */ -static int ice_vc_get_stats_msg(struct ice_vf *vf, u8 *msg) -{ - enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; - struct virtchnl_queue_select *vqs = - (struct virtchnl_queue_select *)msg; - struct ice_eth_stats stats = { 0 }; - struct ice_vsi *vsi; - - if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (!ice_vc_isvalid_vsi_id(vf, vqs->vsi_id)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - vsi = ice_get_vf_vsi(vf); - if (!vsi) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - ice_update_eth_stats(vsi); - - stats = vsi->eth_stats; - -error_param: - /* send the response to the VF */ - return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_STATS, v_ret, - (u8 *)&stats, sizeof(stats)); -} - -/** - * ice_can_vf_change_mac - * @vf: pointer to the VF info - * - * Return true if the VF is allowed to change its MAC filters, false otherwise - */ -static bool ice_can_vf_change_mac(struct ice_vf *vf) -{ - /* If the VF MAC address has been set administratively (via the - * ndo_set_vf_mac command), then deny permission to the VF to - * add/delete unicast MAC addresses, unless the VF is trusted - */ - if (vf->pf_set_mac && !ice_is_vf_trusted(vf)) - return false; - - return true; -} - -/** - * ice_vc_ether_addr_type - get type of virtchnl_ether_addr - * @vc_ether_addr: used to extract the type - */ -static u8 -ice_vc_ether_addr_type(struct virtchnl_ether_addr *vc_ether_addr) -{ - return (vc_ether_addr->type & VIRTCHNL_ETHER_ADDR_TYPE_MASK); -} - -/** - * ice_is_vc_addr_legacy - check if the MAC address is from an older VF - * @vc_ether_addr: VIRTCHNL structure that contains MAC and type - */ -static bool -ice_is_vc_addr_legacy(struct virtchnl_ether_addr *vc_ether_addr) -{ - u8 type = ice_vc_ether_addr_type(vc_ether_addr); - - return (type == VIRTCHNL_ETHER_ADDR_LEGACY); -} - -/** - * ice_is_vc_addr_primary - check if the MAC address is the VF's primary MAC - * @vc_ether_addr: VIRTCHNL structure that contains MAC and type - * - * This function should only be called when the MAC address in - * virtchnl_ether_addr is a valid unicast MAC - */ -static bool -ice_is_vc_addr_primary(struct virtchnl_ether_addr __maybe_unused *vc_ether_addr) -{ - u8 type = ice_vc_ether_addr_type(vc_ether_addr); - - return (type == VIRTCHNL_ETHER_ADDR_PRIMARY); -} - -/** - * ice_vfhw_mac_add - update the VF's cached hardware MAC if allowed - * @vf: VF to update - * @vc_ether_addr: structure from VIRTCHNL with MAC to add - */ -static void -ice_vfhw_mac_add(struct ice_vf *vf, struct virtchnl_ether_addr *vc_ether_addr) -{ - u8 *mac_addr = vc_ether_addr->addr; - - if (!is_valid_ether_addr(mac_addr)) - return; - - /* only allow legacy VF drivers to set the device and hardware MAC if it - * is zero and allow new VF drivers to set the hardware MAC if the type - * was correctly specified over VIRTCHNL - */ - if ((ice_is_vc_addr_legacy(vc_ether_addr) && - is_zero_ether_addr(vf->hw_lan_addr)) || - ice_is_vc_addr_primary(vc_ether_addr)) { - ether_addr_copy(vf->dev_lan_addr, mac_addr); - ether_addr_copy(vf->hw_lan_addr, mac_addr); - } - - /* hardware and device MACs are already set, but its possible that the - * VF driver sent the VIRTCHNL_OP_ADD_ETH_ADDR message before the - * VIRTCHNL_OP_DEL_ETH_ADDR when trying to update its MAC, so save it - * away for the legacy VF driver case as it will be updated in the - * delete flow for this case - */ - if (ice_is_vc_addr_legacy(vc_ether_addr)) { - ether_addr_copy(vf->legacy_last_added_umac.addr, - mac_addr); - vf->legacy_last_added_umac.time_modified = jiffies; - } -} - -/** - * ice_is_mc_lldp_eth_addr - check if the given MAC is a multicast LLDP address - * @mac: address to check - * - * Return: true if the address is one of the three possible LLDP multicast - * addresses, false otherwise. - */ -static bool ice_is_mc_lldp_eth_addr(const u8 *mac) -{ - const u8 lldp_mac_base[] = {0x01, 0x80, 0xc2, 0x00, 0x00}; - - if (memcmp(mac, lldp_mac_base, sizeof(lldp_mac_base))) - return false; - - return (mac[5] == 0x0e || mac[5] == 0x03 || mac[5] == 0x00); -} - -/** - * ice_vc_can_add_mac - check if the VF is allowed to add a given MAC - * @vf: a VF to add the address to - * @mac: address to check - * - * Return: true if the VF is allowed to add such MAC address, false otherwise. - */ -static bool ice_vc_can_add_mac(const struct ice_vf *vf, const u8 *mac) -{ - struct device *dev = ice_pf_to_dev(vf->pf); - - if (is_unicast_ether_addr(mac) && - !ice_can_vf_change_mac((struct ice_vf *)vf)) { - dev_err(dev, - "VF attempting to override administratively set MAC address, bring down and up the VF interface to resume normal operation\n"); - return false; - } - - if (!vf->trusted && ice_is_mc_lldp_eth_addr(mac)) { - dev_warn(dev, - "An untrusted VF %u is attempting to configure an LLDP multicast address\n", - vf->vf_id); - return false; - } - - return true; -} - -/** - * ice_vc_add_mac_addr - attempt to add the MAC address passed in - * @vf: pointer to the VF info - * @vsi: pointer to the VF's VSI - * @vc_ether_addr: VIRTCHNL MAC address structure used to add MAC - */ -static int -ice_vc_add_mac_addr(struct ice_vf *vf, struct ice_vsi *vsi, - struct virtchnl_ether_addr *vc_ether_addr) -{ - struct device *dev = ice_pf_to_dev(vf->pf); - u8 *mac_addr = vc_ether_addr->addr; - int ret; - - /* device MAC already added */ - if (ether_addr_equal(mac_addr, vf->dev_lan_addr)) - return 0; - - if (!ice_vc_can_add_mac(vf, mac_addr)) - return -EPERM; - - ret = ice_fltr_add_mac(vsi, mac_addr, ICE_FWD_TO_VSI); - if (ret == -EEXIST) { - dev_dbg(dev, "MAC %pM already exists for VF %d\n", mac_addr, - vf->vf_id); - /* don't return since we might need to update - * the primary MAC in ice_vfhw_mac_add() below - */ - } else if (ret) { - dev_err(dev, "Failed to add MAC %pM for VF %d\n, error %d\n", - mac_addr, vf->vf_id, ret); - return ret; - } else { - vf->num_mac++; - if (ice_is_mc_lldp_eth_addr(mac_addr)) - ice_vf_update_mac_lldp_num(vf, vsi, true); - } - - ice_vfhw_mac_add(vf, vc_ether_addr); - - return ret; -} - -/** - * ice_is_legacy_umac_expired - check if last added legacy unicast MAC expired - * @last_added_umac: structure used to check expiration - */ -static bool ice_is_legacy_umac_expired(struct ice_time_mac *last_added_umac) -{ -#define ICE_LEGACY_VF_MAC_CHANGE_EXPIRE_TIME msecs_to_jiffies(3000) - return time_is_before_jiffies(last_added_umac->time_modified + - ICE_LEGACY_VF_MAC_CHANGE_EXPIRE_TIME); -} - -/** - * ice_update_legacy_cached_mac - update cached hardware MAC for legacy VF - * @vf: VF to update - * @vc_ether_addr: structure from VIRTCHNL with MAC to check - * - * only update cached hardware MAC for legacy VF drivers on delete - * because we cannot guarantee order/type of MAC from the VF driver - */ -static void -ice_update_legacy_cached_mac(struct ice_vf *vf, - struct virtchnl_ether_addr *vc_ether_addr) -{ - if (!ice_is_vc_addr_legacy(vc_ether_addr) || - ice_is_legacy_umac_expired(&vf->legacy_last_added_umac)) - return; - - ether_addr_copy(vf->dev_lan_addr, vf->legacy_last_added_umac.addr); - ether_addr_copy(vf->hw_lan_addr, vf->legacy_last_added_umac.addr); -} - -/** - * ice_vfhw_mac_del - update the VF's cached hardware MAC if allowed - * @vf: VF to update - * @vc_ether_addr: structure from VIRTCHNL with MAC to delete - */ -static void -ice_vfhw_mac_del(struct ice_vf *vf, struct virtchnl_ether_addr *vc_ether_addr) -{ - u8 *mac_addr = vc_ether_addr->addr; - - if (!is_valid_ether_addr(mac_addr) || - !ether_addr_equal(vf->dev_lan_addr, mac_addr)) - return; - - /* allow the device MAC to be repopulated in the add flow and don't - * clear the hardware MAC (i.e. hw_lan_addr) here as that is meant - * to be persistent on VM reboot and across driver unload/load, which - * won't work if we clear the hardware MAC here - */ - eth_zero_addr(vf->dev_lan_addr); - - ice_update_legacy_cached_mac(vf, vc_ether_addr); -} - -/** - * ice_vc_del_mac_addr - attempt to delete the MAC address passed in - * @vf: pointer to the VF info - * @vsi: pointer to the VF's VSI - * @vc_ether_addr: VIRTCHNL MAC address structure used to delete MAC - */ -static int -ice_vc_del_mac_addr(struct ice_vf *vf, struct ice_vsi *vsi, - struct virtchnl_ether_addr *vc_ether_addr) -{ - struct device *dev = ice_pf_to_dev(vf->pf); - u8 *mac_addr = vc_ether_addr->addr; - int status; - - if (!ice_can_vf_change_mac(vf) && - ether_addr_equal(vf->dev_lan_addr, mac_addr)) - return 0; - - status = ice_fltr_remove_mac(vsi, mac_addr, ICE_FWD_TO_VSI); - if (status == -ENOENT) { - dev_err(dev, "MAC %pM does not exist for VF %d\n", mac_addr, - vf->vf_id); - return -ENOENT; - } else if (status) { - dev_err(dev, "Failed to delete MAC %pM for VF %d, error %d\n", - mac_addr, vf->vf_id, status); - return -EIO; - } - - ice_vfhw_mac_del(vf, vc_ether_addr); - - vf->num_mac--; - if (ice_is_mc_lldp_eth_addr(mac_addr)) - ice_vf_update_mac_lldp_num(vf, vsi, false); - - return 0; -} - -/** - * ice_vc_handle_mac_addr_msg - * @vf: pointer to the VF info - * @msg: pointer to the msg buffer - * @set: true if MAC filters are being set, false otherwise - * - * add guest MAC address filter - */ -static int -ice_vc_handle_mac_addr_msg(struct ice_vf *vf, u8 *msg, bool set) -{ - int (*ice_vc_cfg_mac) - (struct ice_vf *vf, struct ice_vsi *vsi, - struct virtchnl_ether_addr *virtchnl_ether_addr); - enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; - struct virtchnl_ether_addr_list *al = - (struct virtchnl_ether_addr_list *)msg; - struct ice_pf *pf = vf->pf; - enum virtchnl_ops vc_op; - struct ice_vsi *vsi; - int i; - - if (set) { - vc_op = VIRTCHNL_OP_ADD_ETH_ADDR; - ice_vc_cfg_mac = ice_vc_add_mac_addr; - } else { - vc_op = VIRTCHNL_OP_DEL_ETH_ADDR; - ice_vc_cfg_mac = ice_vc_del_mac_addr; - } - - if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states) || - !ice_vc_isvalid_vsi_id(vf, al->vsi_id)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto handle_mac_exit; - } - - /* If this VF is not privileged, then we can't add more than a - * limited number of addresses. Check to make sure that the - * additions do not push us over the limit. - */ - if (set && !ice_is_vf_trusted(vf) && - (vf->num_mac + al->num_elements) > ICE_MAX_MACADDR_PER_VF) { - dev_err(ice_pf_to_dev(pf), "Can't add more MAC addresses, because VF-%d is not trusted, switch the VF to trusted mode in order to add more functionalities\n", - vf->vf_id); - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto handle_mac_exit; - } - - vsi = ice_get_vf_vsi(vf); - if (!vsi) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto handle_mac_exit; - } - - for (i = 0; i < al->num_elements; i++) { - u8 *mac_addr = al->list[i].addr; - int result; - - if (is_broadcast_ether_addr(mac_addr) || - is_zero_ether_addr(mac_addr)) - continue; - - result = ice_vc_cfg_mac(vf, vsi, &al->list[i]); - if (result == -EEXIST || result == -ENOENT) { - continue; - } else if (result) { - v_ret = VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR; - goto handle_mac_exit; - } - } - -handle_mac_exit: - /* send the response to the VF */ - return ice_vc_send_msg_to_vf(vf, vc_op, v_ret, NULL, 0); -} - -/** - * ice_vc_add_mac_addr_msg - * @vf: pointer to the VF info - * @msg: pointer to the msg buffer - * - * add guest MAC address filter - */ -static int ice_vc_add_mac_addr_msg(struct ice_vf *vf, u8 *msg) -{ - return ice_vc_handle_mac_addr_msg(vf, msg, true); -} - -/** - * ice_vc_del_mac_addr_msg - * @vf: pointer to the VF info - * @msg: pointer to the msg buffer - * - * remove guest MAC address filter - */ -static int ice_vc_del_mac_addr_msg(struct ice_vf *vf, u8 *msg) -{ - return ice_vc_handle_mac_addr_msg(vf, msg, false); -} - -/** - * ice_vf_vlan_offload_ena - determine if capabilities support VLAN offloads - * @caps: VF driver negotiated capabilities - * - * Return true if VIRTCHNL_VF_OFFLOAD_VLAN capability is set, else return false - */ -static bool ice_vf_vlan_offload_ena(u32 caps) -{ - return !!(caps & VIRTCHNL_VF_OFFLOAD_VLAN); -} - -/** - * ice_is_vlan_promisc_allowed - check if VLAN promiscuous config is allowed - * @vf: VF used to determine if VLAN promiscuous config is allowed - */ -bool ice_is_vlan_promisc_allowed(struct ice_vf *vf) -{ - if ((test_bit(ICE_VF_STATE_UC_PROMISC, vf->vf_states) || - test_bit(ICE_VF_STATE_MC_PROMISC, vf->vf_states)) && - test_bit(ICE_FLAG_VF_TRUE_PROMISC_ENA, vf->pf->flags)) - return true; - - return false; -} - -/** - * ice_vf_ena_vlan_promisc - Enable Tx/Rx VLAN promiscuous for the VLAN - * @vf: VF to enable VLAN promisc on - * @vsi: VF's VSI used to enable VLAN promiscuous mode - * @vlan: VLAN used to enable VLAN promiscuous - * - * This function should only be called if VLAN promiscuous mode is allowed, - * which can be determined via ice_is_vlan_promisc_allowed(). - */ -int ice_vf_ena_vlan_promisc(struct ice_vf *vf, struct ice_vsi *vsi, - struct ice_vlan *vlan) -{ - u8 promisc_m = 0; - int status; - - if (test_bit(ICE_VF_STATE_UC_PROMISC, vf->vf_states)) - promisc_m |= ICE_UCAST_VLAN_PROMISC_BITS; - if (test_bit(ICE_VF_STATE_MC_PROMISC, vf->vf_states)) - promisc_m |= ICE_MCAST_VLAN_PROMISC_BITS; - - if (!promisc_m) - return 0; - - status = ice_fltr_set_vsi_promisc(&vsi->back->hw, vsi->idx, promisc_m, - vlan->vid); - if (status && status != -EEXIST) - return status; - - return 0; -} - -/** - * ice_vf_dis_vlan_promisc - Disable Tx/Rx VLAN promiscuous for the VLAN - * @vsi: VF's VSI used to disable VLAN promiscuous mode for - * @vlan: VLAN used to disable VLAN promiscuous - * - * This function should only be called if VLAN promiscuous mode is allowed, - * which can be determined via ice_is_vlan_promisc_allowed(). - */ -static int ice_vf_dis_vlan_promisc(struct ice_vsi *vsi, struct ice_vlan *vlan) -{ - u8 promisc_m = ICE_UCAST_VLAN_PROMISC_BITS | ICE_MCAST_VLAN_PROMISC_BITS; - int status; - - status = ice_fltr_clear_vsi_promisc(&vsi->back->hw, vsi->idx, promisc_m, - vlan->vid); - if (status && status != -ENOENT) - return status; - - return 0; -} - -/** - * ice_vf_has_max_vlans - check if VF already has the max allowed VLAN filters - * @vf: VF to check against - * @vsi: VF's VSI - * - * If the VF is trusted then the VF is allowed to add as many VLANs as it - * wants to, so return false. - * - * When the VF is untrusted compare the number of non-zero VLANs + 1 to the max - * allowed VLANs for an untrusted VF. Return the result of this comparison. - */ -static bool ice_vf_has_max_vlans(struct ice_vf *vf, struct ice_vsi *vsi) -{ - if (ice_is_vf_trusted(vf)) - return false; - -#define ICE_VF_ADDED_VLAN_ZERO_FLTRS 1 - return ((ice_vsi_num_non_zero_vlans(vsi) + - ICE_VF_ADDED_VLAN_ZERO_FLTRS) >= ICE_MAX_VLAN_PER_VF); -} - -/** - * ice_vc_process_vlan_msg - * @vf: pointer to the VF info - * @msg: pointer to the msg buffer - * @add_v: Add VLAN if true, otherwise delete VLAN - * - * Process virtchnl op to add or remove programmed guest VLAN ID - */ -static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v) -{ - enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; - struct virtchnl_vlan_filter_list *vfl = - (struct virtchnl_vlan_filter_list *)msg; - struct ice_pf *pf = vf->pf; - bool vlan_promisc = false; - struct ice_vsi *vsi; - struct device *dev; - int status = 0; - int i; - - dev = ice_pf_to_dev(pf); - if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (!ice_vf_vlan_offload_ena(vf->driver_caps)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (!ice_vc_isvalid_vsi_id(vf, vfl->vsi_id)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - for (i = 0; i < vfl->num_elements; i++) { - if (vfl->vlan_id[i] >= VLAN_N_VID) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - dev_err(dev, "invalid VF VLAN id %d\n", - vfl->vlan_id[i]); - goto error_param; - } - } - - vsi = ice_get_vf_vsi(vf); - if (!vsi) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (add_v && ice_vf_has_max_vlans(vf, vsi)) { - dev_info(dev, "VF-%d is not trusted, switch the VF to trusted mode, in order to add more VLAN addresses\n", - vf->vf_id); - /* There is no need to let VF know about being not trusted, - * so we can just return success message here - */ - goto error_param; - } - - /* in DVM a VF can add/delete inner VLAN filters when - * VIRTCHNL_VF_OFFLOAD_VLAN is negotiated, so only reject in SVM - */ - if (ice_vf_is_port_vlan_ena(vf) && !ice_is_dvm_ena(&pf->hw)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - /* in DVM VLAN promiscuous is based on the outer VLAN, which would be - * the port VLAN if VIRTCHNL_VF_OFFLOAD_VLAN was negotiated, so only - * allow vlan_promisc = true in SVM and if no port VLAN is configured - */ - vlan_promisc = ice_is_vlan_promisc_allowed(vf) && - !ice_is_dvm_ena(&pf->hw) && - !ice_vf_is_port_vlan_ena(vf); - - if (add_v) { - for (i = 0; i < vfl->num_elements; i++) { - u16 vid = vfl->vlan_id[i]; - struct ice_vlan vlan; - - if (ice_vf_has_max_vlans(vf, vsi)) { - dev_info(dev, "VF-%d is not trusted, switch the VF to trusted mode, in order to add more VLAN addresses\n", - vf->vf_id); - /* There is no need to let VF know about being - * not trusted, so we can just return success - * message here as well. - */ - goto error_param; - } - - /* we add VLAN 0 by default for each VF so we can enable - * Tx VLAN anti-spoof without triggering MDD events so - * we don't need to add it again here - */ - if (!vid) - continue; - - vlan = ICE_VLAN(ETH_P_8021Q, vid, 0); - status = vsi->inner_vlan_ops.add_vlan(vsi, &vlan); - if (status) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - /* Enable VLAN filtering on first non-zero VLAN */ - if (!vlan_promisc && vid && !ice_is_dvm_ena(&pf->hw)) { - if (vf->spoofchk) { - status = vsi->inner_vlan_ops.ena_tx_filtering(vsi); - if (status) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - dev_err(dev, "Enable VLAN anti-spoofing on VLAN ID: %d failed error-%d\n", - vid, status); - goto error_param; - } - } - if (vsi->inner_vlan_ops.ena_rx_filtering(vsi)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - dev_err(dev, "Enable VLAN pruning on VLAN ID: %d failed error-%d\n", - vid, status); - goto error_param; - } - } else if (vlan_promisc) { - status = ice_vf_ena_vlan_promisc(vf, vsi, &vlan); - if (status) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - dev_err(dev, "Enable Unicast/multicast promiscuous mode on VLAN ID:%d failed error-%d\n", - vid, status); - } - } - } - } else { - /* In case of non_trusted VF, number of VLAN elements passed - * to PF for removal might be greater than number of VLANs - * filter programmed for that VF - So, use actual number of - * VLANS added earlier with add VLAN opcode. In order to avoid - * removing VLAN that doesn't exist, which result to sending - * erroneous failed message back to the VF - */ - int num_vf_vlan; - - num_vf_vlan = vsi->num_vlan; - for (i = 0; i < vfl->num_elements && i < num_vf_vlan; i++) { - u16 vid = vfl->vlan_id[i]; - struct ice_vlan vlan; - - /* we add VLAN 0 by default for each VF so we can enable - * Tx VLAN anti-spoof without triggering MDD events so - * we don't want a VIRTCHNL request to remove it - */ - if (!vid) - continue; - - vlan = ICE_VLAN(ETH_P_8021Q, vid, 0); - status = vsi->inner_vlan_ops.del_vlan(vsi, &vlan); - if (status) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - /* Disable VLAN filtering when only VLAN 0 is left */ - if (!ice_vsi_has_non_zero_vlans(vsi)) { - vsi->inner_vlan_ops.dis_tx_filtering(vsi); - vsi->inner_vlan_ops.dis_rx_filtering(vsi); - } - - if (vlan_promisc) - ice_vf_dis_vlan_promisc(vsi, &vlan); - } - } - -error_param: - /* send the response to the VF */ - if (add_v) - return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ADD_VLAN, v_ret, - NULL, 0); - else - return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DEL_VLAN, v_ret, - NULL, 0); -} - -/** - * ice_vc_add_vlan_msg - * @vf: pointer to the VF info - * @msg: pointer to the msg buffer - * - * Add and program guest VLAN ID - */ -static int ice_vc_add_vlan_msg(struct ice_vf *vf, u8 *msg) -{ - return ice_vc_process_vlan_msg(vf, msg, true); -} - -/** - * ice_vc_remove_vlan_msg - * @vf: pointer to the VF info - * @msg: pointer to the msg buffer - * - * remove programmed guest VLAN ID - */ -static int ice_vc_remove_vlan_msg(struct ice_vf *vf, u8 *msg) -{ - return ice_vc_process_vlan_msg(vf, msg, false); -} - -/** - * ice_vsi_is_rxq_crc_strip_dis - check if Rx queue CRC strip is disabled or not - * @vsi: pointer to the VF VSI info - */ -static bool ice_vsi_is_rxq_crc_strip_dis(struct ice_vsi *vsi) -{ - unsigned int i; - - ice_for_each_alloc_rxq(vsi, i) - if (vsi->rx_rings[i]->flags & ICE_RX_FLAGS_CRC_STRIP_DIS) - return true; - - return false; -} - -/** - * ice_vc_ena_vlan_stripping - * @vf: pointer to the VF info - * - * Enable VLAN header stripping for a given VF - */ -static int ice_vc_ena_vlan_stripping(struct ice_vf *vf) -{ - enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; - struct ice_vsi *vsi; - - if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (!ice_vf_vlan_offload_ena(vf->driver_caps)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - vsi = ice_get_vf_vsi(vf); - if (!vsi) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (vsi->inner_vlan_ops.ena_stripping(vsi, ETH_P_8021Q)) - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - else - vf->vlan_strip_ena |= ICE_INNER_VLAN_STRIP_ENA; - -error_param: - return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ENABLE_VLAN_STRIPPING, - v_ret, NULL, 0); -} - -/** - * ice_vc_dis_vlan_stripping - * @vf: pointer to the VF info - * - * Disable VLAN header stripping for a given VF - */ -static int ice_vc_dis_vlan_stripping(struct ice_vf *vf) -{ - enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; - struct ice_vsi *vsi; - - if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (!ice_vf_vlan_offload_ena(vf->driver_caps)) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - vsi = ice_get_vf_vsi(vf); - if (!vsi) { - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - - if (vsi->inner_vlan_ops.dis_stripping(vsi)) - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - else - vf->vlan_strip_ena &= ~ICE_INNER_VLAN_STRIP_ENA; - -error_param: - return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DISABLE_VLAN_STRIPPING, - v_ret, NULL, 0); -} - /** * ice_vc_get_rss_hashcfg - return the RSS Hash configuration * @vf: pointer to the VF info -- 2.47.1