162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright (C) 2022, Intel Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include "ice_virtchnl.h" 562306a36Sopenharmony_ci#include "ice_vf_lib_private.h" 662306a36Sopenharmony_ci#include "ice.h" 762306a36Sopenharmony_ci#include "ice_base.h" 862306a36Sopenharmony_ci#include "ice_lib.h" 962306a36Sopenharmony_ci#include "ice_fltr.h" 1062306a36Sopenharmony_ci#include "ice_virtchnl_allowlist.h" 1162306a36Sopenharmony_ci#include "ice_vf_vsi_vlan_ops.h" 1262306a36Sopenharmony_ci#include "ice_vlan.h" 1362306a36Sopenharmony_ci#include "ice_flex_pipe.h" 1462306a36Sopenharmony_ci#include "ice_dcb_lib.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define FIELD_SELECTOR(proto_hdr_field) \ 1762306a36Sopenharmony_ci BIT((proto_hdr_field) & PROTO_HDR_FIELD_MASK) 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistruct ice_vc_hdr_match_type { 2062306a36Sopenharmony_ci u32 vc_hdr; /* virtchnl headers (VIRTCHNL_PROTO_HDR_XXX) */ 2162306a36Sopenharmony_ci u32 ice_hdr; /* ice headers (ICE_FLOW_SEG_HDR_XXX) */ 2262306a36Sopenharmony_ci}; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic const struct ice_vc_hdr_match_type ice_vc_hdr_list[] = { 2562306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_NONE, ICE_FLOW_SEG_HDR_NONE}, 2662306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_ETH, ICE_FLOW_SEG_HDR_ETH}, 2762306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_S_VLAN, ICE_FLOW_SEG_HDR_VLAN}, 2862306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_C_VLAN, ICE_FLOW_SEG_HDR_VLAN}, 2962306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_IPV4, ICE_FLOW_SEG_HDR_IPV4 | 3062306a36Sopenharmony_ci ICE_FLOW_SEG_HDR_IPV_OTHER}, 3162306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_IPV6, ICE_FLOW_SEG_HDR_IPV6 | 3262306a36Sopenharmony_ci ICE_FLOW_SEG_HDR_IPV_OTHER}, 3362306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_TCP, ICE_FLOW_SEG_HDR_TCP}, 3462306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_UDP, ICE_FLOW_SEG_HDR_UDP}, 3562306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_SCTP, ICE_FLOW_SEG_HDR_SCTP}, 3662306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_PPPOE, ICE_FLOW_SEG_HDR_PPPOE}, 3762306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_GTPU_IP, ICE_FLOW_SEG_HDR_GTPU_IP}, 3862306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_GTPU_EH, ICE_FLOW_SEG_HDR_GTPU_EH}, 3962306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_GTPU_EH_PDU_DWN, 4062306a36Sopenharmony_ci ICE_FLOW_SEG_HDR_GTPU_DWN}, 4162306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_GTPU_EH_PDU_UP, 4262306a36Sopenharmony_ci ICE_FLOW_SEG_HDR_GTPU_UP}, 4362306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_L2TPV3, ICE_FLOW_SEG_HDR_L2TPV3}, 4462306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_ESP, ICE_FLOW_SEG_HDR_ESP}, 4562306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_AH, ICE_FLOW_SEG_HDR_AH}, 4662306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_PFCP, ICE_FLOW_SEG_HDR_PFCP_SESSION}, 4762306a36Sopenharmony_ci}; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistruct ice_vc_hash_field_match_type { 5062306a36Sopenharmony_ci u32 vc_hdr; /* virtchnl headers 5162306a36Sopenharmony_ci * (VIRTCHNL_PROTO_HDR_XXX) 5262306a36Sopenharmony_ci */ 5362306a36Sopenharmony_ci u32 vc_hash_field; /* virtchnl hash fields selector 5462306a36Sopenharmony_ci * FIELD_SELECTOR((VIRTCHNL_PROTO_HDR_ETH_XXX)) 5562306a36Sopenharmony_ci */ 5662306a36Sopenharmony_ci u64 ice_hash_field; /* ice hash fields 5762306a36Sopenharmony_ci * (BIT_ULL(ICE_FLOW_FIELD_IDX_XXX)) 5862306a36Sopenharmony_ci */ 5962306a36Sopenharmony_ci}; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic const struct 6262306a36Sopenharmony_ciice_vc_hash_field_match_type ice_vc_hash_field_list[] = { 6362306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_ETH, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_ETH_SRC), 6462306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_ETH_SA)}, 6562306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_ETH, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_ETH_DST), 6662306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_ETH_DA)}, 6762306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_ETH, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_ETH_SRC) | 6862306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_ETH_DST), 6962306a36Sopenharmony_ci ICE_FLOW_HASH_ETH}, 7062306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_ETH, 7162306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_ETH_ETHERTYPE), 7262306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_ETH_TYPE)}, 7362306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_S_VLAN, 7462306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_S_VLAN_ID), 7562306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_S_VLAN)}, 7662306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_C_VLAN, 7762306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_C_VLAN_ID), 7862306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_C_VLAN)}, 7962306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC), 8062306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_SA)}, 8162306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST), 8262306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_DA)}, 8362306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) | 8462306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST), 8562306a36Sopenharmony_ci ICE_FLOW_HASH_IPV4}, 8662306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) | 8762306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT), 8862306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_SA) | 8962306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT)}, 9062306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) | 9162306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT), 9262306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_DA) | 9362306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT)}, 9462306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) | 9562306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) | 9662306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT), 9762306a36Sopenharmony_ci ICE_FLOW_HASH_IPV4 | BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT)}, 9862306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT), 9962306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT)}, 10062306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_SRC), 10162306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_SA)}, 10262306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_DST), 10362306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_DA)}, 10462306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_SRC) | 10562306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_DST), 10662306a36Sopenharmony_ci ICE_FLOW_HASH_IPV6}, 10762306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_SRC) | 10862306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PROT), 10962306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_SA) | 11062306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PROT)}, 11162306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_DST) | 11262306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PROT), 11362306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_DA) | 11462306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PROT)}, 11562306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_SRC) | 11662306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_DST) | 11762306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PROT), 11862306a36Sopenharmony_ci ICE_FLOW_HASH_IPV6 | BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PROT)}, 11962306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PROT), 12062306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PROT)}, 12162306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_TCP, 12262306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_SRC_PORT), 12362306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_SRC_PORT)}, 12462306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_TCP, 12562306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_DST_PORT), 12662306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_DST_PORT)}, 12762306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_TCP, 12862306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_SRC_PORT) | 12962306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_DST_PORT), 13062306a36Sopenharmony_ci ICE_FLOW_HASH_TCP_PORT}, 13162306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_UDP, 13262306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_SRC_PORT), 13362306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_SRC_PORT)}, 13462306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_UDP, 13562306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_DST_PORT), 13662306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_DST_PORT)}, 13762306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_UDP, 13862306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_SRC_PORT) | 13962306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_DST_PORT), 14062306a36Sopenharmony_ci ICE_FLOW_HASH_UDP_PORT}, 14162306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_SCTP, 14262306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_SRC_PORT), 14362306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT)}, 14462306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_SCTP, 14562306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_DST_PORT), 14662306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_DST_PORT)}, 14762306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_SCTP, 14862306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_SRC_PORT) | 14962306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_DST_PORT), 15062306a36Sopenharmony_ci ICE_FLOW_HASH_SCTP_PORT}, 15162306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_PPPOE, 15262306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_PPPOE_SESS_ID), 15362306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_PPPOE_SESS_ID)}, 15462306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_GTPU_IP, 15562306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_GTPU_IP_TEID), 15662306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_GTPU_IP_TEID)}, 15762306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_L2TPV3, 15862306a36Sopenharmony_ci FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_L2TPV3_SESS_ID), 15962306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_L2TPV3_SESS_ID)}, 16062306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_ESP, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_ESP_SPI), 16162306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_ESP_SPI)}, 16262306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_AH, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_AH_SPI), 16362306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_AH_SPI)}, 16462306a36Sopenharmony_ci {VIRTCHNL_PROTO_HDR_PFCP, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_PFCP_SEID), 16562306a36Sopenharmony_ci BIT_ULL(ICE_FLOW_FIELD_IDX_PFCP_SEID)}, 16662306a36Sopenharmony_ci}; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci/** 16962306a36Sopenharmony_ci * ice_vc_vf_broadcast - Broadcast a message to all VFs on PF 17062306a36Sopenharmony_ci * @pf: pointer to the PF structure 17162306a36Sopenharmony_ci * @v_opcode: operation code 17262306a36Sopenharmony_ci * @v_retval: return value 17362306a36Sopenharmony_ci * @msg: pointer to the msg buffer 17462306a36Sopenharmony_ci * @msglen: msg length 17562306a36Sopenharmony_ci */ 17662306a36Sopenharmony_cistatic void 17762306a36Sopenharmony_ciice_vc_vf_broadcast(struct ice_pf *pf, enum virtchnl_ops v_opcode, 17862306a36Sopenharmony_ci enum virtchnl_status_code v_retval, u8 *msg, u16 msglen) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci struct ice_hw *hw = &pf->hw; 18162306a36Sopenharmony_ci struct ice_vf *vf; 18262306a36Sopenharmony_ci unsigned int bkt; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci mutex_lock(&pf->vfs.table_lock); 18562306a36Sopenharmony_ci ice_for_each_vf(pf, bkt, vf) { 18662306a36Sopenharmony_ci /* Not all vfs are enabled so skip the ones that are not */ 18762306a36Sopenharmony_ci if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states) && 18862306a36Sopenharmony_ci !test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) 18962306a36Sopenharmony_ci continue; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci /* Ignore return value on purpose - a given VF may fail, but 19262306a36Sopenharmony_ci * we need to keep going and send to all of them 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_ci ice_aq_send_msg_to_vf(hw, vf->vf_id, v_opcode, v_retval, msg, 19562306a36Sopenharmony_ci msglen, NULL); 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci mutex_unlock(&pf->vfs.table_lock); 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci/** 20162306a36Sopenharmony_ci * ice_set_pfe_link - Set the link speed/status of the virtchnl_pf_event 20262306a36Sopenharmony_ci * @vf: pointer to the VF structure 20362306a36Sopenharmony_ci * @pfe: pointer to the virtchnl_pf_event to set link speed/status for 20462306a36Sopenharmony_ci * @ice_link_speed: link speed specified by ICE_AQ_LINK_SPEED_* 20562306a36Sopenharmony_ci * @link_up: whether or not to set the link up/down 20662306a36Sopenharmony_ci */ 20762306a36Sopenharmony_cistatic void 20862306a36Sopenharmony_ciice_set_pfe_link(struct ice_vf *vf, struct virtchnl_pf_event *pfe, 20962306a36Sopenharmony_ci int ice_link_speed, bool link_up) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci if (vf->driver_caps & VIRTCHNL_VF_CAP_ADV_LINK_SPEED) { 21262306a36Sopenharmony_ci pfe->event_data.link_event_adv.link_status = link_up; 21362306a36Sopenharmony_ci /* Speed in Mbps */ 21462306a36Sopenharmony_ci pfe->event_data.link_event_adv.link_speed = 21562306a36Sopenharmony_ci ice_conv_link_speed_to_virtchnl(true, ice_link_speed); 21662306a36Sopenharmony_ci } else { 21762306a36Sopenharmony_ci pfe->event_data.link_event.link_status = link_up; 21862306a36Sopenharmony_ci /* Legacy method for virtchnl link speeds */ 21962306a36Sopenharmony_ci pfe->event_data.link_event.link_speed = 22062306a36Sopenharmony_ci (enum virtchnl_link_speed) 22162306a36Sopenharmony_ci ice_conv_link_speed_to_virtchnl(false, ice_link_speed); 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci/** 22662306a36Sopenharmony_ci * ice_vc_notify_vf_link_state - Inform a VF of link status 22762306a36Sopenharmony_ci * @vf: pointer to the VF structure 22862306a36Sopenharmony_ci * 22962306a36Sopenharmony_ci * send a link status message to a single VF 23062306a36Sopenharmony_ci */ 23162306a36Sopenharmony_civoid ice_vc_notify_vf_link_state(struct ice_vf *vf) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci struct virtchnl_pf_event pfe = { 0 }; 23462306a36Sopenharmony_ci struct ice_hw *hw = &vf->pf->hw; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci pfe.event = VIRTCHNL_EVENT_LINK_CHANGE; 23762306a36Sopenharmony_ci pfe.severity = PF_EVENT_SEVERITY_INFO; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (ice_is_vf_link_up(vf)) 24062306a36Sopenharmony_ci ice_set_pfe_link(vf, &pfe, 24162306a36Sopenharmony_ci hw->port_info->phy.link_info.link_speed, true); 24262306a36Sopenharmony_ci else 24362306a36Sopenharmony_ci ice_set_pfe_link(vf, &pfe, ICE_AQ_LINK_SPEED_UNKNOWN, false); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci ice_aq_send_msg_to_vf(hw, vf->vf_id, VIRTCHNL_OP_EVENT, 24662306a36Sopenharmony_ci VIRTCHNL_STATUS_SUCCESS, (u8 *)&pfe, 24762306a36Sopenharmony_ci sizeof(pfe), NULL); 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci/** 25162306a36Sopenharmony_ci * ice_vc_notify_link_state - Inform all VFs on a PF of link status 25262306a36Sopenharmony_ci * @pf: pointer to the PF structure 25362306a36Sopenharmony_ci */ 25462306a36Sopenharmony_civoid ice_vc_notify_link_state(struct ice_pf *pf) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci struct ice_vf *vf; 25762306a36Sopenharmony_ci unsigned int bkt; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci mutex_lock(&pf->vfs.table_lock); 26062306a36Sopenharmony_ci ice_for_each_vf(pf, bkt, vf) 26162306a36Sopenharmony_ci ice_vc_notify_vf_link_state(vf); 26262306a36Sopenharmony_ci mutex_unlock(&pf->vfs.table_lock); 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci/** 26662306a36Sopenharmony_ci * ice_vc_notify_reset - Send pending reset message to all VFs 26762306a36Sopenharmony_ci * @pf: pointer to the PF structure 26862306a36Sopenharmony_ci * 26962306a36Sopenharmony_ci * indicate a pending reset to all VFs on a given PF 27062306a36Sopenharmony_ci */ 27162306a36Sopenharmony_civoid ice_vc_notify_reset(struct ice_pf *pf) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci struct virtchnl_pf_event pfe; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (!ice_has_vfs(pf)) 27662306a36Sopenharmony_ci return; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci pfe.event = VIRTCHNL_EVENT_RESET_IMPENDING; 27962306a36Sopenharmony_ci pfe.severity = PF_EVENT_SEVERITY_CERTAIN_DOOM; 28062306a36Sopenharmony_ci ice_vc_vf_broadcast(pf, VIRTCHNL_OP_EVENT, VIRTCHNL_STATUS_SUCCESS, 28162306a36Sopenharmony_ci (u8 *)&pfe, sizeof(struct virtchnl_pf_event)); 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci/** 28562306a36Sopenharmony_ci * ice_vc_send_msg_to_vf - Send message to VF 28662306a36Sopenharmony_ci * @vf: pointer to the VF info 28762306a36Sopenharmony_ci * @v_opcode: virtual channel opcode 28862306a36Sopenharmony_ci * @v_retval: virtual channel return value 28962306a36Sopenharmony_ci * @msg: pointer to the msg buffer 29062306a36Sopenharmony_ci * @msglen: msg length 29162306a36Sopenharmony_ci * 29262306a36Sopenharmony_ci * send msg to VF 29362306a36Sopenharmony_ci */ 29462306a36Sopenharmony_ciint 29562306a36Sopenharmony_ciice_vc_send_msg_to_vf(struct ice_vf *vf, u32 v_opcode, 29662306a36Sopenharmony_ci enum virtchnl_status_code v_retval, u8 *msg, u16 msglen) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci struct device *dev; 29962306a36Sopenharmony_ci struct ice_pf *pf; 30062306a36Sopenharmony_ci int aq_ret; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci pf = vf->pf; 30362306a36Sopenharmony_ci dev = ice_pf_to_dev(pf); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci aq_ret = ice_aq_send_msg_to_vf(&pf->hw, vf->vf_id, v_opcode, v_retval, 30662306a36Sopenharmony_ci msg, msglen, NULL); 30762306a36Sopenharmony_ci if (aq_ret && pf->hw.mailboxq.sq_last_status != ICE_AQ_RC_ENOSYS) { 30862306a36Sopenharmony_ci dev_info(dev, "Unable to send the message to VF %d ret %d aq_err %s\n", 30962306a36Sopenharmony_ci vf->vf_id, aq_ret, 31062306a36Sopenharmony_ci ice_aq_str(pf->hw.mailboxq.sq_last_status)); 31162306a36Sopenharmony_ci return -EIO; 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci return 0; 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci/** 31862306a36Sopenharmony_ci * ice_vc_get_ver_msg 31962306a36Sopenharmony_ci * @vf: pointer to the VF info 32062306a36Sopenharmony_ci * @msg: pointer to the msg buffer 32162306a36Sopenharmony_ci * 32262306a36Sopenharmony_ci * called from the VF to request the API version used by the PF 32362306a36Sopenharmony_ci */ 32462306a36Sopenharmony_cistatic int ice_vc_get_ver_msg(struct ice_vf *vf, u8 *msg) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci struct virtchnl_version_info info = { 32762306a36Sopenharmony_ci VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR 32862306a36Sopenharmony_ci }; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci vf->vf_ver = *(struct virtchnl_version_info *)msg; 33162306a36Sopenharmony_ci /* VFs running the 1.0 API expect to get 1.0 back or they will cry. */ 33262306a36Sopenharmony_ci if (VF_IS_V10(&vf->vf_ver)) 33362306a36Sopenharmony_ci info.minor = VIRTCHNL_VERSION_MINOR_NO_VF_CAPS; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_VERSION, 33662306a36Sopenharmony_ci VIRTCHNL_STATUS_SUCCESS, (u8 *)&info, 33762306a36Sopenharmony_ci sizeof(struct virtchnl_version_info)); 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci/** 34162306a36Sopenharmony_ci * ice_vc_get_max_frame_size - get max frame size allowed for VF 34262306a36Sopenharmony_ci * @vf: VF used to determine max frame size 34362306a36Sopenharmony_ci * 34462306a36Sopenharmony_ci * Max frame size is determined based on the current port's max frame size and 34562306a36Sopenharmony_ci * whether a port VLAN is configured on this VF. The VF is not aware whether 34662306a36Sopenharmony_ci * it's in a port VLAN so the PF needs to account for this in max frame size 34762306a36Sopenharmony_ci * checks and sending the max frame size to the VF. 34862306a36Sopenharmony_ci */ 34962306a36Sopenharmony_cistatic u16 ice_vc_get_max_frame_size(struct ice_vf *vf) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci struct ice_port_info *pi = ice_vf_get_port_info(vf); 35262306a36Sopenharmony_ci u16 max_frame_size; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci max_frame_size = pi->phy.link_info.max_frame_size; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (ice_vf_is_port_vlan_ena(vf)) 35762306a36Sopenharmony_ci max_frame_size -= VLAN_HLEN; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci return max_frame_size; 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci/** 36362306a36Sopenharmony_ci * ice_vc_get_vlan_caps 36462306a36Sopenharmony_ci * @hw: pointer to the hw 36562306a36Sopenharmony_ci * @vf: pointer to the VF info 36662306a36Sopenharmony_ci * @vsi: pointer to the VSI 36762306a36Sopenharmony_ci * @driver_caps: current driver caps 36862306a36Sopenharmony_ci * 36962306a36Sopenharmony_ci * Return 0 if there is no VLAN caps supported, or VLAN caps value 37062306a36Sopenharmony_ci */ 37162306a36Sopenharmony_cistatic u32 37262306a36Sopenharmony_ciice_vc_get_vlan_caps(struct ice_hw *hw, struct ice_vf *vf, struct ice_vsi *vsi, 37362306a36Sopenharmony_ci u32 driver_caps) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci if (ice_is_eswitch_mode_switchdev(vf->pf)) 37662306a36Sopenharmony_ci /* In switchdev setting VLAN from VF isn't supported */ 37762306a36Sopenharmony_ci return 0; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci if (driver_caps & VIRTCHNL_VF_OFFLOAD_VLAN_V2) { 38062306a36Sopenharmony_ci /* VLAN offloads based on current device configuration */ 38162306a36Sopenharmony_ci return VIRTCHNL_VF_OFFLOAD_VLAN_V2; 38262306a36Sopenharmony_ci } else if (driver_caps & VIRTCHNL_VF_OFFLOAD_VLAN) { 38362306a36Sopenharmony_ci /* allow VF to negotiate VIRTCHNL_VF_OFFLOAD explicitly for 38462306a36Sopenharmony_ci * these two conditions, which amounts to guest VLAN filtering 38562306a36Sopenharmony_ci * and offloads being based on the inner VLAN or the 38662306a36Sopenharmony_ci * inner/single VLAN respectively and don't allow VF to 38762306a36Sopenharmony_ci * negotiate VIRTCHNL_VF_OFFLOAD in any other cases 38862306a36Sopenharmony_ci */ 38962306a36Sopenharmony_ci if (ice_is_dvm_ena(hw) && ice_vf_is_port_vlan_ena(vf)) { 39062306a36Sopenharmony_ci return VIRTCHNL_VF_OFFLOAD_VLAN; 39162306a36Sopenharmony_ci } else if (!ice_is_dvm_ena(hw) && 39262306a36Sopenharmony_ci !ice_vf_is_port_vlan_ena(vf)) { 39362306a36Sopenharmony_ci /* configure backward compatible support for VFs that 39462306a36Sopenharmony_ci * only support VIRTCHNL_VF_OFFLOAD_VLAN, the PF is 39562306a36Sopenharmony_ci * configured in SVM, and no port VLAN is configured 39662306a36Sopenharmony_ci */ 39762306a36Sopenharmony_ci ice_vf_vsi_cfg_svm_legacy_vlan_mode(vsi); 39862306a36Sopenharmony_ci return VIRTCHNL_VF_OFFLOAD_VLAN; 39962306a36Sopenharmony_ci } else if (ice_is_dvm_ena(hw)) { 40062306a36Sopenharmony_ci /* configure software offloaded VLAN support when DVM 40162306a36Sopenharmony_ci * is enabled, but no port VLAN is enabled 40262306a36Sopenharmony_ci */ 40362306a36Sopenharmony_ci ice_vf_vsi_cfg_dvm_legacy_vlan_mode(vsi); 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci return 0; 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci/** 41162306a36Sopenharmony_ci * ice_vc_get_vf_res_msg 41262306a36Sopenharmony_ci * @vf: pointer to the VF info 41362306a36Sopenharmony_ci * @msg: pointer to the msg buffer 41462306a36Sopenharmony_ci * 41562306a36Sopenharmony_ci * called from the VF to request its resources 41662306a36Sopenharmony_ci */ 41762306a36Sopenharmony_cistatic int ice_vc_get_vf_res_msg(struct ice_vf *vf, u8 *msg) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 42062306a36Sopenharmony_ci struct virtchnl_vf_resource *vfres = NULL; 42162306a36Sopenharmony_ci struct ice_hw *hw = &vf->pf->hw; 42262306a36Sopenharmony_ci struct ice_vsi *vsi; 42362306a36Sopenharmony_ci int len = 0; 42462306a36Sopenharmony_ci int ret; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci if (ice_check_vf_init(vf)) { 42762306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 42862306a36Sopenharmony_ci goto err; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci len = virtchnl_struct_size(vfres, vsi_res, 0); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci vfres = kzalloc(len, GFP_KERNEL); 43462306a36Sopenharmony_ci if (!vfres) { 43562306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; 43662306a36Sopenharmony_ci len = 0; 43762306a36Sopenharmony_ci goto err; 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci if (VF_IS_V11(&vf->vf_ver)) 44062306a36Sopenharmony_ci vf->driver_caps = *(u32 *)msg; 44162306a36Sopenharmony_ci else 44262306a36Sopenharmony_ci vf->driver_caps = VIRTCHNL_VF_OFFLOAD_L2 | 44362306a36Sopenharmony_ci VIRTCHNL_VF_OFFLOAD_VLAN; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci vfres->vf_cap_flags = VIRTCHNL_VF_OFFLOAD_L2; 44662306a36Sopenharmony_ci vsi = ice_get_vf_vsi(vf); 44762306a36Sopenharmony_ci if (!vsi) { 44862306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 44962306a36Sopenharmony_ci goto err; 45062306a36Sopenharmony_ci } 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci vfres->vf_cap_flags |= ice_vc_get_vlan_caps(hw, vf, vsi, 45362306a36Sopenharmony_ci vf->driver_caps); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PF) 45662306a36Sopenharmony_ci vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_PF; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC) 45962306a36Sopenharmony_ci vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_FDIR_PF) 46262306a36Sopenharmony_ci vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_FDIR_PF; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2) 46562306a36Sopenharmony_ci vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ENCAP) 46862306a36Sopenharmony_ci vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_ENCAP; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM) 47162306a36Sopenharmony_ci vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RX_POLLING) 47462306a36Sopenharmony_ci vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RX_POLLING; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_WB_ON_ITR) 47762306a36Sopenharmony_ci vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_WB_ON_ITR; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_REQ_QUEUES) 48062306a36Sopenharmony_ci vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_REQ_QUEUES; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci if (vf->driver_caps & VIRTCHNL_VF_CAP_ADV_LINK_SPEED) 48362306a36Sopenharmony_ci vfres->vf_cap_flags |= VIRTCHNL_VF_CAP_ADV_LINK_SPEED; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF) 48662306a36Sopenharmony_ci vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_USO) 48962306a36Sopenharmony_ci vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_USO; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci vfres->num_vsis = 1; 49262306a36Sopenharmony_ci /* Tx and Rx queue are equal for VF */ 49362306a36Sopenharmony_ci vfres->num_queue_pairs = vsi->num_txq; 49462306a36Sopenharmony_ci vfres->max_vectors = vf->pf->vfs.num_msix_per; 49562306a36Sopenharmony_ci vfres->rss_key_size = ICE_VSIQF_HKEY_ARRAY_SIZE; 49662306a36Sopenharmony_ci vfres->rss_lut_size = ICE_LUT_VSI_SIZE; 49762306a36Sopenharmony_ci vfres->max_mtu = ice_vc_get_max_frame_size(vf); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci vfres->vsi_res[0].vsi_id = vf->lan_vsi_num; 50062306a36Sopenharmony_ci vfres->vsi_res[0].vsi_type = VIRTCHNL_VSI_SRIOV; 50162306a36Sopenharmony_ci vfres->vsi_res[0].num_queue_pairs = vsi->num_txq; 50262306a36Sopenharmony_ci ether_addr_copy(vfres->vsi_res[0].default_mac_addr, 50362306a36Sopenharmony_ci vf->hw_lan_addr); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* match guest capabilities */ 50662306a36Sopenharmony_ci vf->driver_caps = vfres->vf_cap_flags; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci ice_vc_set_caps_allowlist(vf); 50962306a36Sopenharmony_ci ice_vc_set_working_allowlist(vf); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci set_bit(ICE_VF_STATE_ACTIVE, vf->vf_states); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_cierr: 51462306a36Sopenharmony_ci /* send the response back to the VF */ 51562306a36Sopenharmony_ci ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_VF_RESOURCES, v_ret, 51662306a36Sopenharmony_ci (u8 *)vfres, len); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci kfree(vfres); 51962306a36Sopenharmony_ci return ret; 52062306a36Sopenharmony_ci} 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci/** 52362306a36Sopenharmony_ci * ice_vc_reset_vf_msg 52462306a36Sopenharmony_ci * @vf: pointer to the VF info 52562306a36Sopenharmony_ci * 52662306a36Sopenharmony_ci * called from the VF to reset itself, 52762306a36Sopenharmony_ci * unlike other virtchnl messages, PF driver 52862306a36Sopenharmony_ci * doesn't send the response back to the VF 52962306a36Sopenharmony_ci */ 53062306a36Sopenharmony_cistatic void ice_vc_reset_vf_msg(struct ice_vf *vf) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci if (test_bit(ICE_VF_STATE_INIT, vf->vf_states)) 53362306a36Sopenharmony_ci ice_reset_vf(vf, 0); 53462306a36Sopenharmony_ci} 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci/** 53762306a36Sopenharmony_ci * ice_vc_isvalid_vsi_id 53862306a36Sopenharmony_ci * @vf: pointer to the VF info 53962306a36Sopenharmony_ci * @vsi_id: VF relative VSI ID 54062306a36Sopenharmony_ci * 54162306a36Sopenharmony_ci * check for the valid VSI ID 54262306a36Sopenharmony_ci */ 54362306a36Sopenharmony_cibool ice_vc_isvalid_vsi_id(struct ice_vf *vf, u16 vsi_id) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci struct ice_pf *pf = vf->pf; 54662306a36Sopenharmony_ci struct ice_vsi *vsi; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci vsi = ice_find_vsi(pf, vsi_id); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci return (vsi && (vsi->vf == vf)); 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci/** 55462306a36Sopenharmony_ci * ice_vc_isvalid_q_id 55562306a36Sopenharmony_ci * @vf: pointer to the VF info 55662306a36Sopenharmony_ci * @vsi_id: VSI ID 55762306a36Sopenharmony_ci * @qid: VSI relative queue ID 55862306a36Sopenharmony_ci * 55962306a36Sopenharmony_ci * check for the valid queue ID 56062306a36Sopenharmony_ci */ 56162306a36Sopenharmony_cistatic bool ice_vc_isvalid_q_id(struct ice_vf *vf, u16 vsi_id, u8 qid) 56262306a36Sopenharmony_ci{ 56362306a36Sopenharmony_ci struct ice_vsi *vsi = ice_find_vsi(vf->pf, vsi_id); 56462306a36Sopenharmony_ci /* allocated Tx and Rx queues should be always equal for VF VSI */ 56562306a36Sopenharmony_ci return (vsi && (qid < vsi->alloc_txq)); 56662306a36Sopenharmony_ci} 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci/** 56962306a36Sopenharmony_ci * ice_vc_isvalid_ring_len 57062306a36Sopenharmony_ci * @ring_len: length of ring 57162306a36Sopenharmony_ci * 57262306a36Sopenharmony_ci * check for the valid ring count, should be multiple of ICE_REQ_DESC_MULTIPLE 57362306a36Sopenharmony_ci * or zero 57462306a36Sopenharmony_ci */ 57562306a36Sopenharmony_cistatic bool ice_vc_isvalid_ring_len(u16 ring_len) 57662306a36Sopenharmony_ci{ 57762306a36Sopenharmony_ci return ring_len == 0 || 57862306a36Sopenharmony_ci (ring_len >= ICE_MIN_NUM_DESC && 57962306a36Sopenharmony_ci ring_len <= ICE_MAX_NUM_DESC && 58062306a36Sopenharmony_ci !(ring_len % ICE_REQ_DESC_MULTIPLE)); 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci/** 58462306a36Sopenharmony_ci * ice_vc_validate_pattern 58562306a36Sopenharmony_ci * @vf: pointer to the VF info 58662306a36Sopenharmony_ci * @proto: virtchnl protocol headers 58762306a36Sopenharmony_ci * 58862306a36Sopenharmony_ci * validate the pattern is supported or not. 58962306a36Sopenharmony_ci * 59062306a36Sopenharmony_ci * Return: true on success, false on error. 59162306a36Sopenharmony_ci */ 59262306a36Sopenharmony_cibool 59362306a36Sopenharmony_ciice_vc_validate_pattern(struct ice_vf *vf, struct virtchnl_proto_hdrs *proto) 59462306a36Sopenharmony_ci{ 59562306a36Sopenharmony_ci bool is_ipv4 = false; 59662306a36Sopenharmony_ci bool is_ipv6 = false; 59762306a36Sopenharmony_ci bool is_udp = false; 59862306a36Sopenharmony_ci u16 ptype = -1; 59962306a36Sopenharmony_ci int i = 0; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci while (i < proto->count && 60262306a36Sopenharmony_ci proto->proto_hdr[i].type != VIRTCHNL_PROTO_HDR_NONE) { 60362306a36Sopenharmony_ci switch (proto->proto_hdr[i].type) { 60462306a36Sopenharmony_ci case VIRTCHNL_PROTO_HDR_ETH: 60562306a36Sopenharmony_ci ptype = ICE_PTYPE_MAC_PAY; 60662306a36Sopenharmony_ci break; 60762306a36Sopenharmony_ci case VIRTCHNL_PROTO_HDR_IPV4: 60862306a36Sopenharmony_ci ptype = ICE_PTYPE_IPV4_PAY; 60962306a36Sopenharmony_ci is_ipv4 = true; 61062306a36Sopenharmony_ci break; 61162306a36Sopenharmony_ci case VIRTCHNL_PROTO_HDR_IPV6: 61262306a36Sopenharmony_ci ptype = ICE_PTYPE_IPV6_PAY; 61362306a36Sopenharmony_ci is_ipv6 = true; 61462306a36Sopenharmony_ci break; 61562306a36Sopenharmony_ci case VIRTCHNL_PROTO_HDR_UDP: 61662306a36Sopenharmony_ci if (is_ipv4) 61762306a36Sopenharmony_ci ptype = ICE_PTYPE_IPV4_UDP_PAY; 61862306a36Sopenharmony_ci else if (is_ipv6) 61962306a36Sopenharmony_ci ptype = ICE_PTYPE_IPV6_UDP_PAY; 62062306a36Sopenharmony_ci is_udp = true; 62162306a36Sopenharmony_ci break; 62262306a36Sopenharmony_ci case VIRTCHNL_PROTO_HDR_TCP: 62362306a36Sopenharmony_ci if (is_ipv4) 62462306a36Sopenharmony_ci ptype = ICE_PTYPE_IPV4_TCP_PAY; 62562306a36Sopenharmony_ci else if (is_ipv6) 62662306a36Sopenharmony_ci ptype = ICE_PTYPE_IPV6_TCP_PAY; 62762306a36Sopenharmony_ci break; 62862306a36Sopenharmony_ci case VIRTCHNL_PROTO_HDR_SCTP: 62962306a36Sopenharmony_ci if (is_ipv4) 63062306a36Sopenharmony_ci ptype = ICE_PTYPE_IPV4_SCTP_PAY; 63162306a36Sopenharmony_ci else if (is_ipv6) 63262306a36Sopenharmony_ci ptype = ICE_PTYPE_IPV6_SCTP_PAY; 63362306a36Sopenharmony_ci break; 63462306a36Sopenharmony_ci case VIRTCHNL_PROTO_HDR_GTPU_IP: 63562306a36Sopenharmony_ci case VIRTCHNL_PROTO_HDR_GTPU_EH: 63662306a36Sopenharmony_ci if (is_ipv4) 63762306a36Sopenharmony_ci ptype = ICE_MAC_IPV4_GTPU; 63862306a36Sopenharmony_ci else if (is_ipv6) 63962306a36Sopenharmony_ci ptype = ICE_MAC_IPV6_GTPU; 64062306a36Sopenharmony_ci goto out; 64162306a36Sopenharmony_ci case VIRTCHNL_PROTO_HDR_L2TPV3: 64262306a36Sopenharmony_ci if (is_ipv4) 64362306a36Sopenharmony_ci ptype = ICE_MAC_IPV4_L2TPV3; 64462306a36Sopenharmony_ci else if (is_ipv6) 64562306a36Sopenharmony_ci ptype = ICE_MAC_IPV6_L2TPV3; 64662306a36Sopenharmony_ci goto out; 64762306a36Sopenharmony_ci case VIRTCHNL_PROTO_HDR_ESP: 64862306a36Sopenharmony_ci if (is_ipv4) 64962306a36Sopenharmony_ci ptype = is_udp ? ICE_MAC_IPV4_NAT_T_ESP : 65062306a36Sopenharmony_ci ICE_MAC_IPV4_ESP; 65162306a36Sopenharmony_ci else if (is_ipv6) 65262306a36Sopenharmony_ci ptype = is_udp ? ICE_MAC_IPV6_NAT_T_ESP : 65362306a36Sopenharmony_ci ICE_MAC_IPV6_ESP; 65462306a36Sopenharmony_ci goto out; 65562306a36Sopenharmony_ci case VIRTCHNL_PROTO_HDR_AH: 65662306a36Sopenharmony_ci if (is_ipv4) 65762306a36Sopenharmony_ci ptype = ICE_MAC_IPV4_AH; 65862306a36Sopenharmony_ci else if (is_ipv6) 65962306a36Sopenharmony_ci ptype = ICE_MAC_IPV6_AH; 66062306a36Sopenharmony_ci goto out; 66162306a36Sopenharmony_ci case VIRTCHNL_PROTO_HDR_PFCP: 66262306a36Sopenharmony_ci if (is_ipv4) 66362306a36Sopenharmony_ci ptype = ICE_MAC_IPV4_PFCP_SESSION; 66462306a36Sopenharmony_ci else if (is_ipv6) 66562306a36Sopenharmony_ci ptype = ICE_MAC_IPV6_PFCP_SESSION; 66662306a36Sopenharmony_ci goto out; 66762306a36Sopenharmony_ci default: 66862306a36Sopenharmony_ci break; 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci i++; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ciout: 67462306a36Sopenharmony_ci return ice_hw_ptype_ena(&vf->pf->hw, ptype); 67562306a36Sopenharmony_ci} 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci/** 67862306a36Sopenharmony_ci * ice_vc_parse_rss_cfg - parses hash fields and headers from 67962306a36Sopenharmony_ci * a specific virtchnl RSS cfg 68062306a36Sopenharmony_ci * @hw: pointer to the hardware 68162306a36Sopenharmony_ci * @rss_cfg: pointer to the virtchnl RSS cfg 68262306a36Sopenharmony_ci * @addl_hdrs: pointer to the protocol header fields (ICE_FLOW_SEG_HDR_*) 68362306a36Sopenharmony_ci * to configure 68462306a36Sopenharmony_ci * @hash_flds: pointer to the hash bit fields (ICE_FLOW_HASH_*) to configure 68562306a36Sopenharmony_ci * 68662306a36Sopenharmony_ci * Return true if all the protocol header and hash fields in the RSS cfg could 68762306a36Sopenharmony_ci * be parsed, else return false 68862306a36Sopenharmony_ci * 68962306a36Sopenharmony_ci * This function parses the virtchnl RSS cfg to be the intended 69062306a36Sopenharmony_ci * hash fields and the intended header for RSS configuration 69162306a36Sopenharmony_ci */ 69262306a36Sopenharmony_cistatic bool 69362306a36Sopenharmony_ciice_vc_parse_rss_cfg(struct ice_hw *hw, struct virtchnl_rss_cfg *rss_cfg, 69462306a36Sopenharmony_ci u32 *addl_hdrs, u64 *hash_flds) 69562306a36Sopenharmony_ci{ 69662306a36Sopenharmony_ci const struct ice_vc_hash_field_match_type *hf_list; 69762306a36Sopenharmony_ci const struct ice_vc_hdr_match_type *hdr_list; 69862306a36Sopenharmony_ci int i, hf_list_len, hdr_list_len; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci hf_list = ice_vc_hash_field_list; 70162306a36Sopenharmony_ci hf_list_len = ARRAY_SIZE(ice_vc_hash_field_list); 70262306a36Sopenharmony_ci hdr_list = ice_vc_hdr_list; 70362306a36Sopenharmony_ci hdr_list_len = ARRAY_SIZE(ice_vc_hdr_list); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci for (i = 0; i < rss_cfg->proto_hdrs.count; i++) { 70662306a36Sopenharmony_ci struct virtchnl_proto_hdr *proto_hdr = 70762306a36Sopenharmony_ci &rss_cfg->proto_hdrs.proto_hdr[i]; 70862306a36Sopenharmony_ci bool hdr_found = false; 70962306a36Sopenharmony_ci int j; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci /* Find matched ice headers according to virtchnl headers. */ 71262306a36Sopenharmony_ci for (j = 0; j < hdr_list_len; j++) { 71362306a36Sopenharmony_ci struct ice_vc_hdr_match_type hdr_map = hdr_list[j]; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci if (proto_hdr->type == hdr_map.vc_hdr) { 71662306a36Sopenharmony_ci *addl_hdrs |= hdr_map.ice_hdr; 71762306a36Sopenharmony_ci hdr_found = true; 71862306a36Sopenharmony_ci } 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci if (!hdr_found) 72262306a36Sopenharmony_ci return false; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci /* Find matched ice hash fields according to 72562306a36Sopenharmony_ci * virtchnl hash fields. 72662306a36Sopenharmony_ci */ 72762306a36Sopenharmony_ci for (j = 0; j < hf_list_len; j++) { 72862306a36Sopenharmony_ci struct ice_vc_hash_field_match_type hf_map = hf_list[j]; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci if (proto_hdr->type == hf_map.vc_hdr && 73162306a36Sopenharmony_ci proto_hdr->field_selector == hf_map.vc_hash_field) { 73262306a36Sopenharmony_ci *hash_flds |= hf_map.ice_hash_field; 73362306a36Sopenharmony_ci break; 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci return true; 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci/** 74262306a36Sopenharmony_ci * ice_vf_adv_rss_offload_ena - determine if capabilities support advanced 74362306a36Sopenharmony_ci * RSS offloads 74462306a36Sopenharmony_ci * @caps: VF driver negotiated capabilities 74562306a36Sopenharmony_ci * 74662306a36Sopenharmony_ci * Return true if VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF capability is set, 74762306a36Sopenharmony_ci * else return false 74862306a36Sopenharmony_ci */ 74962306a36Sopenharmony_cistatic bool ice_vf_adv_rss_offload_ena(u32 caps) 75062306a36Sopenharmony_ci{ 75162306a36Sopenharmony_ci return !!(caps & VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF); 75262306a36Sopenharmony_ci} 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci/** 75562306a36Sopenharmony_ci * ice_vc_handle_rss_cfg 75662306a36Sopenharmony_ci * @vf: pointer to the VF info 75762306a36Sopenharmony_ci * @msg: pointer to the message buffer 75862306a36Sopenharmony_ci * @add: add a RSS config if true, otherwise delete a RSS config 75962306a36Sopenharmony_ci * 76062306a36Sopenharmony_ci * This function adds/deletes a RSS config 76162306a36Sopenharmony_ci */ 76262306a36Sopenharmony_cistatic int ice_vc_handle_rss_cfg(struct ice_vf *vf, u8 *msg, bool add) 76362306a36Sopenharmony_ci{ 76462306a36Sopenharmony_ci u32 v_opcode = add ? VIRTCHNL_OP_ADD_RSS_CFG : VIRTCHNL_OP_DEL_RSS_CFG; 76562306a36Sopenharmony_ci struct virtchnl_rss_cfg *rss_cfg = (struct virtchnl_rss_cfg *)msg; 76662306a36Sopenharmony_ci enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 76762306a36Sopenharmony_ci struct device *dev = ice_pf_to_dev(vf->pf); 76862306a36Sopenharmony_ci struct ice_hw *hw = &vf->pf->hw; 76962306a36Sopenharmony_ci struct ice_vsi *vsi; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci if (!test_bit(ICE_FLAG_RSS_ENA, vf->pf->flags)) { 77262306a36Sopenharmony_ci dev_dbg(dev, "VF %d attempting to configure RSS, but RSS is not supported by the PF\n", 77362306a36Sopenharmony_ci vf->vf_id); 77462306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_NOT_SUPPORTED; 77562306a36Sopenharmony_ci goto error_param; 77662306a36Sopenharmony_ci } 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci if (!ice_vf_adv_rss_offload_ena(vf->driver_caps)) { 77962306a36Sopenharmony_ci dev_dbg(dev, "VF %d attempting to configure RSS, but Advanced RSS offload is not supported\n", 78062306a36Sopenharmony_ci vf->vf_id); 78162306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 78262306a36Sopenharmony_ci goto error_param; 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { 78662306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 78762306a36Sopenharmony_ci goto error_param; 78862306a36Sopenharmony_ci } 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci if (rss_cfg->proto_hdrs.count > VIRTCHNL_MAX_NUM_PROTO_HDRS || 79162306a36Sopenharmony_ci rss_cfg->rss_algorithm < VIRTCHNL_RSS_ALG_TOEPLITZ_ASYMMETRIC || 79262306a36Sopenharmony_ci rss_cfg->rss_algorithm > VIRTCHNL_RSS_ALG_XOR_SYMMETRIC) { 79362306a36Sopenharmony_ci dev_dbg(dev, "VF %d attempting to configure RSS, but RSS configuration is not valid\n", 79462306a36Sopenharmony_ci vf->vf_id); 79562306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 79662306a36Sopenharmony_ci goto error_param; 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci vsi = ice_get_vf_vsi(vf); 80062306a36Sopenharmony_ci if (!vsi) { 80162306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 80262306a36Sopenharmony_ci goto error_param; 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci if (!ice_vc_validate_pattern(vf, &rss_cfg->proto_hdrs)) { 80662306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 80762306a36Sopenharmony_ci goto error_param; 80862306a36Sopenharmony_ci } 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci if (rss_cfg->rss_algorithm == VIRTCHNL_RSS_ALG_R_ASYMMETRIC) { 81162306a36Sopenharmony_ci struct ice_vsi_ctx *ctx; 81262306a36Sopenharmony_ci u8 lut_type, hash_type; 81362306a36Sopenharmony_ci int status; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci lut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_VSI; 81662306a36Sopenharmony_ci hash_type = add ? ICE_AQ_VSI_Q_OPT_RSS_HASH_XOR : 81762306a36Sopenharmony_ci ICE_AQ_VSI_Q_OPT_RSS_HASH_TPLZ; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 82062306a36Sopenharmony_ci if (!ctx) { 82162306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; 82262306a36Sopenharmony_ci goto error_param; 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci ctx->info.q_opt_rss = 82662306a36Sopenharmony_ci FIELD_PREP(ICE_AQ_VSI_Q_OPT_RSS_LUT_M, lut_type) | 82762306a36Sopenharmony_ci FIELD_PREP(ICE_AQ_VSI_Q_OPT_RSS_HASH_M, hash_type); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci /* Preserve existing queueing option setting */ 83062306a36Sopenharmony_ci ctx->info.q_opt_rss |= (vsi->info.q_opt_rss & 83162306a36Sopenharmony_ci ICE_AQ_VSI_Q_OPT_RSS_GBL_LUT_M); 83262306a36Sopenharmony_ci ctx->info.q_opt_tc = vsi->info.q_opt_tc; 83362306a36Sopenharmony_ci ctx->info.q_opt_flags = vsi->info.q_opt_rss; 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci ctx->info.valid_sections = 83662306a36Sopenharmony_ci cpu_to_le16(ICE_AQ_VSI_PROP_Q_OPT_VALID); 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci status = ice_update_vsi(hw, vsi->idx, ctx, NULL); 83962306a36Sopenharmony_ci if (status) { 84062306a36Sopenharmony_ci dev_err(dev, "update VSI for RSS failed, err %d aq_err %s\n", 84162306a36Sopenharmony_ci status, ice_aq_str(hw->adminq.sq_last_status)); 84262306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 84362306a36Sopenharmony_ci } else { 84462306a36Sopenharmony_ci vsi->info.q_opt_rss = ctx->info.q_opt_rss; 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci kfree(ctx); 84862306a36Sopenharmony_ci } else { 84962306a36Sopenharmony_ci u32 addl_hdrs = ICE_FLOW_SEG_HDR_NONE; 85062306a36Sopenharmony_ci u64 hash_flds = ICE_HASH_INVALID; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci if (!ice_vc_parse_rss_cfg(hw, rss_cfg, &addl_hdrs, 85362306a36Sopenharmony_ci &hash_flds)) { 85462306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 85562306a36Sopenharmony_ci goto error_param; 85662306a36Sopenharmony_ci } 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci if (add) { 85962306a36Sopenharmony_ci if (ice_add_rss_cfg(hw, vsi->idx, hash_flds, 86062306a36Sopenharmony_ci addl_hdrs)) { 86162306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 86262306a36Sopenharmony_ci dev_err(dev, "ice_add_rss_cfg failed for vsi = %d, v_ret = %d\n", 86362306a36Sopenharmony_ci vsi->vsi_num, v_ret); 86462306a36Sopenharmony_ci } 86562306a36Sopenharmony_ci } else { 86662306a36Sopenharmony_ci int status; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci status = ice_rem_rss_cfg(hw, vsi->idx, hash_flds, 86962306a36Sopenharmony_ci addl_hdrs); 87062306a36Sopenharmony_ci /* We just ignore -ENOENT, because if two configurations 87162306a36Sopenharmony_ci * share the same profile remove one of them actually 87262306a36Sopenharmony_ci * removes both, since the profile is deleted. 87362306a36Sopenharmony_ci */ 87462306a36Sopenharmony_ci if (status && status != -ENOENT) { 87562306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 87662306a36Sopenharmony_ci dev_err(dev, "ice_rem_rss_cfg failed for VF ID:%d, error:%d\n", 87762306a36Sopenharmony_ci vf->vf_id, status); 87862306a36Sopenharmony_ci } 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci } 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_cierror_param: 88362306a36Sopenharmony_ci return ice_vc_send_msg_to_vf(vf, v_opcode, v_ret, NULL, 0); 88462306a36Sopenharmony_ci} 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci/** 88762306a36Sopenharmony_ci * ice_vc_config_rss_key 88862306a36Sopenharmony_ci * @vf: pointer to the VF info 88962306a36Sopenharmony_ci * @msg: pointer to the msg buffer 89062306a36Sopenharmony_ci * 89162306a36Sopenharmony_ci * Configure the VF's RSS key 89262306a36Sopenharmony_ci */ 89362306a36Sopenharmony_cistatic int ice_vc_config_rss_key(struct ice_vf *vf, u8 *msg) 89462306a36Sopenharmony_ci{ 89562306a36Sopenharmony_ci enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 89662306a36Sopenharmony_ci struct virtchnl_rss_key *vrk = 89762306a36Sopenharmony_ci (struct virtchnl_rss_key *)msg; 89862306a36Sopenharmony_ci struct ice_vsi *vsi; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { 90162306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 90262306a36Sopenharmony_ci goto error_param; 90362306a36Sopenharmony_ci } 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci if (!ice_vc_isvalid_vsi_id(vf, vrk->vsi_id)) { 90662306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 90762306a36Sopenharmony_ci goto error_param; 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci if (vrk->key_len != ICE_VSIQF_HKEY_ARRAY_SIZE) { 91162306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 91262306a36Sopenharmony_ci goto error_param; 91362306a36Sopenharmony_ci } 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci if (!test_bit(ICE_FLAG_RSS_ENA, vf->pf->flags)) { 91662306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 91762306a36Sopenharmony_ci goto error_param; 91862306a36Sopenharmony_ci } 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci vsi = ice_get_vf_vsi(vf); 92162306a36Sopenharmony_ci if (!vsi) { 92262306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 92362306a36Sopenharmony_ci goto error_param; 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci if (ice_set_rss_key(vsi, vrk->key)) 92762306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR; 92862306a36Sopenharmony_cierror_param: 92962306a36Sopenharmony_ci return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_RSS_KEY, v_ret, 93062306a36Sopenharmony_ci NULL, 0); 93162306a36Sopenharmony_ci} 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci/** 93462306a36Sopenharmony_ci * ice_vc_config_rss_lut 93562306a36Sopenharmony_ci * @vf: pointer to the VF info 93662306a36Sopenharmony_ci * @msg: pointer to the msg buffer 93762306a36Sopenharmony_ci * 93862306a36Sopenharmony_ci * Configure the VF's RSS LUT 93962306a36Sopenharmony_ci */ 94062306a36Sopenharmony_cistatic int ice_vc_config_rss_lut(struct ice_vf *vf, u8 *msg) 94162306a36Sopenharmony_ci{ 94262306a36Sopenharmony_ci struct virtchnl_rss_lut *vrl = (struct virtchnl_rss_lut *)msg; 94362306a36Sopenharmony_ci enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 94462306a36Sopenharmony_ci struct ice_vsi *vsi; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { 94762306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 94862306a36Sopenharmony_ci goto error_param; 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci if (!ice_vc_isvalid_vsi_id(vf, vrl->vsi_id)) { 95262306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 95362306a36Sopenharmony_ci goto error_param; 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci if (vrl->lut_entries != ICE_LUT_VSI_SIZE) { 95762306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 95862306a36Sopenharmony_ci goto error_param; 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci if (!test_bit(ICE_FLAG_RSS_ENA, vf->pf->flags)) { 96262306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 96362306a36Sopenharmony_ci goto error_param; 96462306a36Sopenharmony_ci } 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci vsi = ice_get_vf_vsi(vf); 96762306a36Sopenharmony_ci if (!vsi) { 96862306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 96962306a36Sopenharmony_ci goto error_param; 97062306a36Sopenharmony_ci } 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci if (ice_set_rss_lut(vsi, vrl->lut, ICE_LUT_VSI_SIZE)) 97362306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR; 97462306a36Sopenharmony_cierror_param: 97562306a36Sopenharmony_ci return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_RSS_LUT, v_ret, 97662306a36Sopenharmony_ci NULL, 0); 97762306a36Sopenharmony_ci} 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci/** 98062306a36Sopenharmony_ci * ice_vc_cfg_promiscuous_mode_msg 98162306a36Sopenharmony_ci * @vf: pointer to the VF info 98262306a36Sopenharmony_ci * @msg: pointer to the msg buffer 98362306a36Sopenharmony_ci * 98462306a36Sopenharmony_ci * called from the VF to configure VF VSIs promiscuous mode 98562306a36Sopenharmony_ci */ 98662306a36Sopenharmony_cistatic int ice_vc_cfg_promiscuous_mode_msg(struct ice_vf *vf, u8 *msg) 98762306a36Sopenharmony_ci{ 98862306a36Sopenharmony_ci enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 98962306a36Sopenharmony_ci bool rm_promisc, alluni = false, allmulti = false; 99062306a36Sopenharmony_ci struct virtchnl_promisc_info *info = 99162306a36Sopenharmony_ci (struct virtchnl_promisc_info *)msg; 99262306a36Sopenharmony_ci struct ice_vsi_vlan_ops *vlan_ops; 99362306a36Sopenharmony_ci int mcast_err = 0, ucast_err = 0; 99462306a36Sopenharmony_ci struct ice_pf *pf = vf->pf; 99562306a36Sopenharmony_ci struct ice_vsi *vsi; 99662306a36Sopenharmony_ci u8 mcast_m, ucast_m; 99762306a36Sopenharmony_ci struct device *dev; 99862306a36Sopenharmony_ci int ret = 0; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { 100162306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 100262306a36Sopenharmony_ci goto error_param; 100362306a36Sopenharmony_ci } 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci if (!ice_vc_isvalid_vsi_id(vf, info->vsi_id)) { 100662306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 100762306a36Sopenharmony_ci goto error_param; 100862306a36Sopenharmony_ci } 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci vsi = ice_get_vf_vsi(vf); 101162306a36Sopenharmony_ci if (!vsi) { 101262306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 101362306a36Sopenharmony_ci goto error_param; 101462306a36Sopenharmony_ci } 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci dev = ice_pf_to_dev(pf); 101762306a36Sopenharmony_ci if (!ice_is_vf_trusted(vf)) { 101862306a36Sopenharmony_ci dev_err(dev, "Unprivileged VF %d is attempting to configure promiscuous mode\n", 101962306a36Sopenharmony_ci vf->vf_id); 102062306a36Sopenharmony_ci /* Leave v_ret alone, lie to the VF on purpose. */ 102162306a36Sopenharmony_ci goto error_param; 102262306a36Sopenharmony_ci } 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci if (info->flags & FLAG_VF_UNICAST_PROMISC) 102562306a36Sopenharmony_ci alluni = true; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci if (info->flags & FLAG_VF_MULTICAST_PROMISC) 102862306a36Sopenharmony_ci allmulti = true; 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci rm_promisc = !allmulti && !alluni; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci vlan_ops = ice_get_compat_vsi_vlan_ops(vsi); 103362306a36Sopenharmony_ci if (rm_promisc) 103462306a36Sopenharmony_ci ret = vlan_ops->ena_rx_filtering(vsi); 103562306a36Sopenharmony_ci else 103662306a36Sopenharmony_ci ret = vlan_ops->dis_rx_filtering(vsi); 103762306a36Sopenharmony_ci if (ret) { 103862306a36Sopenharmony_ci dev_err(dev, "Failed to configure VLAN pruning in promiscuous mode\n"); 103962306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 104062306a36Sopenharmony_ci goto error_param; 104162306a36Sopenharmony_ci } 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci ice_vf_get_promisc_masks(vf, vsi, &ucast_m, &mcast_m); 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci if (!test_bit(ICE_FLAG_VF_TRUE_PROMISC_ENA, pf->flags)) { 104662306a36Sopenharmony_ci if (alluni) { 104762306a36Sopenharmony_ci /* in this case we're turning on promiscuous mode */ 104862306a36Sopenharmony_ci ret = ice_set_dflt_vsi(vsi); 104962306a36Sopenharmony_ci } else { 105062306a36Sopenharmony_ci /* in this case we're turning off promiscuous mode */ 105162306a36Sopenharmony_ci if (ice_is_dflt_vsi_in_use(vsi->port_info)) 105262306a36Sopenharmony_ci ret = ice_clear_dflt_vsi(vsi); 105362306a36Sopenharmony_ci } 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci /* in this case we're turning on/off only 105662306a36Sopenharmony_ci * allmulticast 105762306a36Sopenharmony_ci */ 105862306a36Sopenharmony_ci if (allmulti) 105962306a36Sopenharmony_ci mcast_err = ice_vf_set_vsi_promisc(vf, vsi, mcast_m); 106062306a36Sopenharmony_ci else 106162306a36Sopenharmony_ci mcast_err = ice_vf_clear_vsi_promisc(vf, vsi, mcast_m); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci if (ret) { 106462306a36Sopenharmony_ci dev_err(dev, "Turning on/off promiscuous mode for VF %d failed, error: %d\n", 106562306a36Sopenharmony_ci vf->vf_id, ret); 106662306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR; 106762306a36Sopenharmony_ci goto error_param; 106862306a36Sopenharmony_ci } 106962306a36Sopenharmony_ci } else { 107062306a36Sopenharmony_ci if (alluni) 107162306a36Sopenharmony_ci ucast_err = ice_vf_set_vsi_promisc(vf, vsi, ucast_m); 107262306a36Sopenharmony_ci else 107362306a36Sopenharmony_ci ucast_err = ice_vf_clear_vsi_promisc(vf, vsi, ucast_m); 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci if (allmulti) 107662306a36Sopenharmony_ci mcast_err = ice_vf_set_vsi_promisc(vf, vsi, mcast_m); 107762306a36Sopenharmony_ci else 107862306a36Sopenharmony_ci mcast_err = ice_vf_clear_vsi_promisc(vf, vsi, mcast_m); 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci if (ucast_err || mcast_err) 108162306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 108262306a36Sopenharmony_ci } 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci if (!mcast_err) { 108562306a36Sopenharmony_ci if (allmulti && 108662306a36Sopenharmony_ci !test_and_set_bit(ICE_VF_STATE_MC_PROMISC, vf->vf_states)) 108762306a36Sopenharmony_ci dev_info(dev, "VF %u successfully set multicast promiscuous mode\n", 108862306a36Sopenharmony_ci vf->vf_id); 108962306a36Sopenharmony_ci else if (!allmulti && 109062306a36Sopenharmony_ci test_and_clear_bit(ICE_VF_STATE_MC_PROMISC, 109162306a36Sopenharmony_ci vf->vf_states)) 109262306a36Sopenharmony_ci dev_info(dev, "VF %u successfully unset multicast promiscuous mode\n", 109362306a36Sopenharmony_ci vf->vf_id); 109462306a36Sopenharmony_ci } else { 109562306a36Sopenharmony_ci dev_err(dev, "Error while modifying multicast promiscuous mode for VF %u, error: %d\n", 109662306a36Sopenharmony_ci vf->vf_id, mcast_err); 109762306a36Sopenharmony_ci } 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci if (!ucast_err) { 110062306a36Sopenharmony_ci if (alluni && 110162306a36Sopenharmony_ci !test_and_set_bit(ICE_VF_STATE_UC_PROMISC, vf->vf_states)) 110262306a36Sopenharmony_ci dev_info(dev, "VF %u successfully set unicast promiscuous mode\n", 110362306a36Sopenharmony_ci vf->vf_id); 110462306a36Sopenharmony_ci else if (!alluni && 110562306a36Sopenharmony_ci test_and_clear_bit(ICE_VF_STATE_UC_PROMISC, 110662306a36Sopenharmony_ci vf->vf_states)) 110762306a36Sopenharmony_ci dev_info(dev, "VF %u successfully unset unicast promiscuous mode\n", 110862306a36Sopenharmony_ci vf->vf_id); 110962306a36Sopenharmony_ci } else { 111062306a36Sopenharmony_ci dev_err(dev, "Error while modifying unicast promiscuous mode for VF %u, error: %d\n", 111162306a36Sopenharmony_ci vf->vf_id, ucast_err); 111262306a36Sopenharmony_ci } 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_cierror_param: 111562306a36Sopenharmony_ci return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, 111662306a36Sopenharmony_ci v_ret, NULL, 0); 111762306a36Sopenharmony_ci} 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci/** 112062306a36Sopenharmony_ci * ice_vc_get_stats_msg 112162306a36Sopenharmony_ci * @vf: pointer to the VF info 112262306a36Sopenharmony_ci * @msg: pointer to the msg buffer 112362306a36Sopenharmony_ci * 112462306a36Sopenharmony_ci * called from the VF to get VSI stats 112562306a36Sopenharmony_ci */ 112662306a36Sopenharmony_cistatic int ice_vc_get_stats_msg(struct ice_vf *vf, u8 *msg) 112762306a36Sopenharmony_ci{ 112862306a36Sopenharmony_ci enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 112962306a36Sopenharmony_ci struct virtchnl_queue_select *vqs = 113062306a36Sopenharmony_ci (struct virtchnl_queue_select *)msg; 113162306a36Sopenharmony_ci struct ice_eth_stats stats = { 0 }; 113262306a36Sopenharmony_ci struct ice_vsi *vsi; 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { 113562306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 113662306a36Sopenharmony_ci goto error_param; 113762306a36Sopenharmony_ci } 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci if (!ice_vc_isvalid_vsi_id(vf, vqs->vsi_id)) { 114062306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 114162306a36Sopenharmony_ci goto error_param; 114262306a36Sopenharmony_ci } 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci vsi = ice_get_vf_vsi(vf); 114562306a36Sopenharmony_ci if (!vsi) { 114662306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 114762306a36Sopenharmony_ci goto error_param; 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci ice_update_eth_stats(vsi); 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci stats = vsi->eth_stats; 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_cierror_param: 115562306a36Sopenharmony_ci /* send the response to the VF */ 115662306a36Sopenharmony_ci return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_STATS, v_ret, 115762306a36Sopenharmony_ci (u8 *)&stats, sizeof(stats)); 115862306a36Sopenharmony_ci} 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci/** 116162306a36Sopenharmony_ci * ice_vc_validate_vqs_bitmaps - validate Rx/Tx queue bitmaps from VIRTCHNL 116262306a36Sopenharmony_ci * @vqs: virtchnl_queue_select structure containing bitmaps to validate 116362306a36Sopenharmony_ci * 116462306a36Sopenharmony_ci * Return true on successful validation, else false 116562306a36Sopenharmony_ci */ 116662306a36Sopenharmony_cistatic bool ice_vc_validate_vqs_bitmaps(struct virtchnl_queue_select *vqs) 116762306a36Sopenharmony_ci{ 116862306a36Sopenharmony_ci if ((!vqs->rx_queues && !vqs->tx_queues) || 116962306a36Sopenharmony_ci vqs->rx_queues >= BIT(ICE_MAX_RSS_QS_PER_VF) || 117062306a36Sopenharmony_ci vqs->tx_queues >= BIT(ICE_MAX_RSS_QS_PER_VF)) 117162306a36Sopenharmony_ci return false; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci return true; 117462306a36Sopenharmony_ci} 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci/** 117762306a36Sopenharmony_ci * ice_vf_ena_txq_interrupt - enable Tx queue interrupt via QINT_TQCTL 117862306a36Sopenharmony_ci * @vsi: VSI of the VF to configure 117962306a36Sopenharmony_ci * @q_idx: VF queue index used to determine the queue in the PF's space 118062306a36Sopenharmony_ci */ 118162306a36Sopenharmony_cistatic void ice_vf_ena_txq_interrupt(struct ice_vsi *vsi, u32 q_idx) 118262306a36Sopenharmony_ci{ 118362306a36Sopenharmony_ci struct ice_hw *hw = &vsi->back->hw; 118462306a36Sopenharmony_ci u32 pfq = vsi->txq_map[q_idx]; 118562306a36Sopenharmony_ci u32 reg; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci reg = rd32(hw, QINT_TQCTL(pfq)); 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci /* MSI-X index 0 in the VF's space is always for the OICR, which means 119062306a36Sopenharmony_ci * this is most likely a poll mode VF driver, so don't enable an 119162306a36Sopenharmony_ci * interrupt that was never configured via VIRTCHNL_OP_CONFIG_IRQ_MAP 119262306a36Sopenharmony_ci */ 119362306a36Sopenharmony_ci if (!(reg & QINT_TQCTL_MSIX_INDX_M)) 119462306a36Sopenharmony_ci return; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci wr32(hw, QINT_TQCTL(pfq), reg | QINT_TQCTL_CAUSE_ENA_M); 119762306a36Sopenharmony_ci} 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci/** 120062306a36Sopenharmony_ci * ice_vf_ena_rxq_interrupt - enable Tx queue interrupt via QINT_RQCTL 120162306a36Sopenharmony_ci * @vsi: VSI of the VF to configure 120262306a36Sopenharmony_ci * @q_idx: VF queue index used to determine the queue in the PF's space 120362306a36Sopenharmony_ci */ 120462306a36Sopenharmony_cistatic void ice_vf_ena_rxq_interrupt(struct ice_vsi *vsi, u32 q_idx) 120562306a36Sopenharmony_ci{ 120662306a36Sopenharmony_ci struct ice_hw *hw = &vsi->back->hw; 120762306a36Sopenharmony_ci u32 pfq = vsi->rxq_map[q_idx]; 120862306a36Sopenharmony_ci u32 reg; 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci reg = rd32(hw, QINT_RQCTL(pfq)); 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci /* MSI-X index 0 in the VF's space is always for the OICR, which means 121362306a36Sopenharmony_ci * this is most likely a poll mode VF driver, so don't enable an 121462306a36Sopenharmony_ci * interrupt that was never configured via VIRTCHNL_OP_CONFIG_IRQ_MAP 121562306a36Sopenharmony_ci */ 121662306a36Sopenharmony_ci if (!(reg & QINT_RQCTL_MSIX_INDX_M)) 121762306a36Sopenharmony_ci return; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci wr32(hw, QINT_RQCTL(pfq), reg | QINT_RQCTL_CAUSE_ENA_M); 122062306a36Sopenharmony_ci} 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci/** 122362306a36Sopenharmony_ci * ice_vc_ena_qs_msg 122462306a36Sopenharmony_ci * @vf: pointer to the VF info 122562306a36Sopenharmony_ci * @msg: pointer to the msg buffer 122662306a36Sopenharmony_ci * 122762306a36Sopenharmony_ci * called from the VF to enable all or specific queue(s) 122862306a36Sopenharmony_ci */ 122962306a36Sopenharmony_cistatic int ice_vc_ena_qs_msg(struct ice_vf *vf, u8 *msg) 123062306a36Sopenharmony_ci{ 123162306a36Sopenharmony_ci enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 123262306a36Sopenharmony_ci struct virtchnl_queue_select *vqs = 123362306a36Sopenharmony_ci (struct virtchnl_queue_select *)msg; 123462306a36Sopenharmony_ci struct ice_vsi *vsi; 123562306a36Sopenharmony_ci unsigned long q_map; 123662306a36Sopenharmony_ci u16 vf_q_id; 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { 123962306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 124062306a36Sopenharmony_ci goto error_param; 124162306a36Sopenharmony_ci } 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci if (!ice_vc_isvalid_vsi_id(vf, vqs->vsi_id)) { 124462306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 124562306a36Sopenharmony_ci goto error_param; 124662306a36Sopenharmony_ci } 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci if (!ice_vc_validate_vqs_bitmaps(vqs)) { 124962306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 125062306a36Sopenharmony_ci goto error_param; 125162306a36Sopenharmony_ci } 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci vsi = ice_get_vf_vsi(vf); 125462306a36Sopenharmony_ci if (!vsi) { 125562306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 125662306a36Sopenharmony_ci goto error_param; 125762306a36Sopenharmony_ci } 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci /* Enable only Rx rings, Tx rings were enabled by the FW when the 126062306a36Sopenharmony_ci * Tx queue group list was configured and the context bits were 126162306a36Sopenharmony_ci * programmed using ice_vsi_cfg_txqs 126262306a36Sopenharmony_ci */ 126362306a36Sopenharmony_ci q_map = vqs->rx_queues; 126462306a36Sopenharmony_ci for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF) { 126562306a36Sopenharmony_ci if (!ice_vc_isvalid_q_id(vf, vqs->vsi_id, vf_q_id)) { 126662306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 126762306a36Sopenharmony_ci goto error_param; 126862306a36Sopenharmony_ci } 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci /* Skip queue if enabled */ 127162306a36Sopenharmony_ci if (test_bit(vf_q_id, vf->rxq_ena)) 127262306a36Sopenharmony_ci continue; 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci if (ice_vsi_ctrl_one_rx_ring(vsi, true, vf_q_id, true)) { 127562306a36Sopenharmony_ci dev_err(ice_pf_to_dev(vsi->back), "Failed to enable Rx ring %d on VSI %d\n", 127662306a36Sopenharmony_ci vf_q_id, vsi->vsi_num); 127762306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 127862306a36Sopenharmony_ci goto error_param; 127962306a36Sopenharmony_ci } 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci ice_vf_ena_rxq_interrupt(vsi, vf_q_id); 128262306a36Sopenharmony_ci set_bit(vf_q_id, vf->rxq_ena); 128362306a36Sopenharmony_ci } 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci q_map = vqs->tx_queues; 128662306a36Sopenharmony_ci for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF) { 128762306a36Sopenharmony_ci if (!ice_vc_isvalid_q_id(vf, vqs->vsi_id, vf_q_id)) { 128862306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 128962306a36Sopenharmony_ci goto error_param; 129062306a36Sopenharmony_ci } 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci /* Skip queue if enabled */ 129362306a36Sopenharmony_ci if (test_bit(vf_q_id, vf->txq_ena)) 129462306a36Sopenharmony_ci continue; 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci ice_vf_ena_txq_interrupt(vsi, vf_q_id); 129762306a36Sopenharmony_ci set_bit(vf_q_id, vf->txq_ena); 129862306a36Sopenharmony_ci } 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci /* Set flag to indicate that queues are enabled */ 130162306a36Sopenharmony_ci if (v_ret == VIRTCHNL_STATUS_SUCCESS) 130262306a36Sopenharmony_ci set_bit(ICE_VF_STATE_QS_ENA, vf->vf_states); 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_cierror_param: 130562306a36Sopenharmony_ci /* send the response to the VF */ 130662306a36Sopenharmony_ci return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ENABLE_QUEUES, v_ret, 130762306a36Sopenharmony_ci NULL, 0); 130862306a36Sopenharmony_ci} 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci/** 131162306a36Sopenharmony_ci * ice_vf_vsi_dis_single_txq - disable a single Tx queue 131262306a36Sopenharmony_ci * @vf: VF to disable queue for 131362306a36Sopenharmony_ci * @vsi: VSI for the VF 131462306a36Sopenharmony_ci * @q_id: VF relative (0-based) queue ID 131562306a36Sopenharmony_ci * 131662306a36Sopenharmony_ci * Attempt to disable the Tx queue passed in. If the Tx queue was successfully 131762306a36Sopenharmony_ci * disabled then clear q_id bit in the enabled queues bitmap and return 131862306a36Sopenharmony_ci * success. Otherwise return error. 131962306a36Sopenharmony_ci */ 132062306a36Sopenharmony_cistatic int 132162306a36Sopenharmony_ciice_vf_vsi_dis_single_txq(struct ice_vf *vf, struct ice_vsi *vsi, u16 q_id) 132262306a36Sopenharmony_ci{ 132362306a36Sopenharmony_ci struct ice_txq_meta txq_meta = { 0 }; 132462306a36Sopenharmony_ci struct ice_tx_ring *ring; 132562306a36Sopenharmony_ci int err; 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci if (!test_bit(q_id, vf->txq_ena)) 132862306a36Sopenharmony_ci dev_dbg(ice_pf_to_dev(vsi->back), "Queue %u on VSI %u is not enabled, but stopping it anyway\n", 132962306a36Sopenharmony_ci q_id, vsi->vsi_num); 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci ring = vsi->tx_rings[q_id]; 133262306a36Sopenharmony_ci if (!ring) 133362306a36Sopenharmony_ci return -EINVAL; 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci ice_fill_txq_meta(vsi, ring, &txq_meta); 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci err = ice_vsi_stop_tx_ring(vsi, ICE_NO_RESET, vf->vf_id, ring, &txq_meta); 133862306a36Sopenharmony_ci if (err) { 133962306a36Sopenharmony_ci dev_err(ice_pf_to_dev(vsi->back), "Failed to stop Tx ring %d on VSI %d\n", 134062306a36Sopenharmony_ci q_id, vsi->vsi_num); 134162306a36Sopenharmony_ci return err; 134262306a36Sopenharmony_ci } 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci /* Clear enabled queues flag */ 134562306a36Sopenharmony_ci clear_bit(q_id, vf->txq_ena); 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci return 0; 134862306a36Sopenharmony_ci} 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci/** 135162306a36Sopenharmony_ci * ice_vc_dis_qs_msg 135262306a36Sopenharmony_ci * @vf: pointer to the VF info 135362306a36Sopenharmony_ci * @msg: pointer to the msg buffer 135462306a36Sopenharmony_ci * 135562306a36Sopenharmony_ci * called from the VF to disable all or specific queue(s) 135662306a36Sopenharmony_ci */ 135762306a36Sopenharmony_cistatic int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg) 135862306a36Sopenharmony_ci{ 135962306a36Sopenharmony_ci enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 136062306a36Sopenharmony_ci struct virtchnl_queue_select *vqs = 136162306a36Sopenharmony_ci (struct virtchnl_queue_select *)msg; 136262306a36Sopenharmony_ci struct ice_vsi *vsi; 136362306a36Sopenharmony_ci unsigned long q_map; 136462306a36Sopenharmony_ci u16 vf_q_id; 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states) && 136762306a36Sopenharmony_ci !test_bit(ICE_VF_STATE_QS_ENA, vf->vf_states)) { 136862306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 136962306a36Sopenharmony_ci goto error_param; 137062306a36Sopenharmony_ci } 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci if (!ice_vc_isvalid_vsi_id(vf, vqs->vsi_id)) { 137362306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 137462306a36Sopenharmony_ci goto error_param; 137562306a36Sopenharmony_ci } 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci if (!ice_vc_validate_vqs_bitmaps(vqs)) { 137862306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 137962306a36Sopenharmony_ci goto error_param; 138062306a36Sopenharmony_ci } 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci vsi = ice_get_vf_vsi(vf); 138362306a36Sopenharmony_ci if (!vsi) { 138462306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 138562306a36Sopenharmony_ci goto error_param; 138662306a36Sopenharmony_ci } 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci if (vqs->tx_queues) { 138962306a36Sopenharmony_ci q_map = vqs->tx_queues; 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF) { 139262306a36Sopenharmony_ci if (!ice_vc_isvalid_q_id(vf, vqs->vsi_id, vf_q_id)) { 139362306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 139462306a36Sopenharmony_ci goto error_param; 139562306a36Sopenharmony_ci } 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci if (ice_vf_vsi_dis_single_txq(vf, vsi, vf_q_id)) { 139862306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 139962306a36Sopenharmony_ci goto error_param; 140062306a36Sopenharmony_ci } 140162306a36Sopenharmony_ci } 140262306a36Sopenharmony_ci } 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci q_map = vqs->rx_queues; 140562306a36Sopenharmony_ci /* speed up Rx queue disable by batching them if possible */ 140662306a36Sopenharmony_ci if (q_map && 140762306a36Sopenharmony_ci bitmap_equal(&q_map, vf->rxq_ena, ICE_MAX_RSS_QS_PER_VF)) { 140862306a36Sopenharmony_ci if (ice_vsi_stop_all_rx_rings(vsi)) { 140962306a36Sopenharmony_ci dev_err(ice_pf_to_dev(vsi->back), "Failed to stop all Rx rings on VSI %d\n", 141062306a36Sopenharmony_ci vsi->vsi_num); 141162306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 141262306a36Sopenharmony_ci goto error_param; 141362306a36Sopenharmony_ci } 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci bitmap_zero(vf->rxq_ena, ICE_MAX_RSS_QS_PER_VF); 141662306a36Sopenharmony_ci } else if (q_map) { 141762306a36Sopenharmony_ci for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF) { 141862306a36Sopenharmony_ci if (!ice_vc_isvalid_q_id(vf, vqs->vsi_id, vf_q_id)) { 141962306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 142062306a36Sopenharmony_ci goto error_param; 142162306a36Sopenharmony_ci } 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci /* Skip queue if not enabled */ 142462306a36Sopenharmony_ci if (!test_bit(vf_q_id, vf->rxq_ena)) 142562306a36Sopenharmony_ci continue; 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci if (ice_vsi_ctrl_one_rx_ring(vsi, false, vf_q_id, 142862306a36Sopenharmony_ci true)) { 142962306a36Sopenharmony_ci dev_err(ice_pf_to_dev(vsi->back), "Failed to stop Rx ring %d on VSI %d\n", 143062306a36Sopenharmony_ci vf_q_id, vsi->vsi_num); 143162306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 143262306a36Sopenharmony_ci goto error_param; 143362306a36Sopenharmony_ci } 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci /* Clear enabled queues flag */ 143662306a36Sopenharmony_ci clear_bit(vf_q_id, vf->rxq_ena); 143762306a36Sopenharmony_ci } 143862306a36Sopenharmony_ci } 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci /* Clear enabled queues flag */ 144162306a36Sopenharmony_ci if (v_ret == VIRTCHNL_STATUS_SUCCESS && ice_vf_has_no_qs_ena(vf)) 144262306a36Sopenharmony_ci clear_bit(ICE_VF_STATE_QS_ENA, vf->vf_states); 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_cierror_param: 144562306a36Sopenharmony_ci /* send the response to the VF */ 144662306a36Sopenharmony_ci return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DISABLE_QUEUES, v_ret, 144762306a36Sopenharmony_ci NULL, 0); 144862306a36Sopenharmony_ci} 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci/** 145162306a36Sopenharmony_ci * ice_cfg_interrupt 145262306a36Sopenharmony_ci * @vf: pointer to the VF info 145362306a36Sopenharmony_ci * @vsi: the VSI being configured 145462306a36Sopenharmony_ci * @vector_id: vector ID 145562306a36Sopenharmony_ci * @map: vector map for mapping vectors to queues 145662306a36Sopenharmony_ci * @q_vector: structure for interrupt vector 145762306a36Sopenharmony_ci * configure the IRQ to queue map 145862306a36Sopenharmony_ci */ 145962306a36Sopenharmony_cistatic int 146062306a36Sopenharmony_ciice_cfg_interrupt(struct ice_vf *vf, struct ice_vsi *vsi, u16 vector_id, 146162306a36Sopenharmony_ci struct virtchnl_vector_map *map, 146262306a36Sopenharmony_ci struct ice_q_vector *q_vector) 146362306a36Sopenharmony_ci{ 146462306a36Sopenharmony_ci u16 vsi_q_id, vsi_q_id_idx; 146562306a36Sopenharmony_ci unsigned long qmap; 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci q_vector->num_ring_rx = 0; 146862306a36Sopenharmony_ci q_vector->num_ring_tx = 0; 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci qmap = map->rxq_map; 147162306a36Sopenharmony_ci for_each_set_bit(vsi_q_id_idx, &qmap, ICE_MAX_RSS_QS_PER_VF) { 147262306a36Sopenharmony_ci vsi_q_id = vsi_q_id_idx; 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci if (!ice_vc_isvalid_q_id(vf, vsi->vsi_num, vsi_q_id)) 147562306a36Sopenharmony_ci return VIRTCHNL_STATUS_ERR_PARAM; 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci q_vector->num_ring_rx++; 147862306a36Sopenharmony_ci q_vector->rx.itr_idx = map->rxitr_idx; 147962306a36Sopenharmony_ci vsi->rx_rings[vsi_q_id]->q_vector = q_vector; 148062306a36Sopenharmony_ci ice_cfg_rxq_interrupt(vsi, vsi_q_id, vector_id, 148162306a36Sopenharmony_ci q_vector->rx.itr_idx); 148262306a36Sopenharmony_ci } 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci qmap = map->txq_map; 148562306a36Sopenharmony_ci for_each_set_bit(vsi_q_id_idx, &qmap, ICE_MAX_RSS_QS_PER_VF) { 148662306a36Sopenharmony_ci vsi_q_id = vsi_q_id_idx; 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci if (!ice_vc_isvalid_q_id(vf, vsi->vsi_num, vsi_q_id)) 148962306a36Sopenharmony_ci return VIRTCHNL_STATUS_ERR_PARAM; 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci q_vector->num_ring_tx++; 149262306a36Sopenharmony_ci q_vector->tx.itr_idx = map->txitr_idx; 149362306a36Sopenharmony_ci vsi->tx_rings[vsi_q_id]->q_vector = q_vector; 149462306a36Sopenharmony_ci ice_cfg_txq_interrupt(vsi, vsi_q_id, vector_id, 149562306a36Sopenharmony_ci q_vector->tx.itr_idx); 149662306a36Sopenharmony_ci } 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci return VIRTCHNL_STATUS_SUCCESS; 149962306a36Sopenharmony_ci} 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci/** 150262306a36Sopenharmony_ci * ice_vc_cfg_irq_map_msg 150362306a36Sopenharmony_ci * @vf: pointer to the VF info 150462306a36Sopenharmony_ci * @msg: pointer to the msg buffer 150562306a36Sopenharmony_ci * 150662306a36Sopenharmony_ci * called from the VF to configure the IRQ to queue map 150762306a36Sopenharmony_ci */ 150862306a36Sopenharmony_cistatic int ice_vc_cfg_irq_map_msg(struct ice_vf *vf, u8 *msg) 150962306a36Sopenharmony_ci{ 151062306a36Sopenharmony_ci enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 151162306a36Sopenharmony_ci u16 num_q_vectors_mapped, vsi_id, vector_id; 151262306a36Sopenharmony_ci struct virtchnl_irq_map_info *irqmap_info; 151362306a36Sopenharmony_ci struct virtchnl_vector_map *map; 151462306a36Sopenharmony_ci struct ice_pf *pf = vf->pf; 151562306a36Sopenharmony_ci struct ice_vsi *vsi; 151662306a36Sopenharmony_ci int i; 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci irqmap_info = (struct virtchnl_irq_map_info *)msg; 151962306a36Sopenharmony_ci num_q_vectors_mapped = irqmap_info->num_vectors; 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci /* Check to make sure number of VF vectors mapped is not greater than 152262306a36Sopenharmony_ci * number of VF vectors originally allocated, and check that 152362306a36Sopenharmony_ci * there is actually at least a single VF queue vector mapped 152462306a36Sopenharmony_ci */ 152562306a36Sopenharmony_ci if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states) || 152662306a36Sopenharmony_ci pf->vfs.num_msix_per < num_q_vectors_mapped || 152762306a36Sopenharmony_ci !num_q_vectors_mapped) { 152862306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 152962306a36Sopenharmony_ci goto error_param; 153062306a36Sopenharmony_ci } 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci vsi = ice_get_vf_vsi(vf); 153362306a36Sopenharmony_ci if (!vsi) { 153462306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 153562306a36Sopenharmony_ci goto error_param; 153662306a36Sopenharmony_ci } 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci for (i = 0; i < num_q_vectors_mapped; i++) { 153962306a36Sopenharmony_ci struct ice_q_vector *q_vector; 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci map = &irqmap_info->vecmap[i]; 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci vector_id = map->vector_id; 154462306a36Sopenharmony_ci vsi_id = map->vsi_id; 154562306a36Sopenharmony_ci /* vector_id is always 0-based for each VF, and can never be 154662306a36Sopenharmony_ci * larger than or equal to the max allowed interrupts per VF 154762306a36Sopenharmony_ci */ 154862306a36Sopenharmony_ci if (!(vector_id < pf->vfs.num_msix_per) || 154962306a36Sopenharmony_ci !ice_vc_isvalid_vsi_id(vf, vsi_id) || 155062306a36Sopenharmony_ci (!vector_id && (map->rxq_map || map->txq_map))) { 155162306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 155262306a36Sopenharmony_ci goto error_param; 155362306a36Sopenharmony_ci } 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci /* No need to map VF miscellaneous or rogue vector */ 155662306a36Sopenharmony_ci if (!vector_id) 155762306a36Sopenharmony_ci continue; 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci /* Subtract non queue vector from vector_id passed by VF 156062306a36Sopenharmony_ci * to get actual number of VSI queue vector array index 156162306a36Sopenharmony_ci */ 156262306a36Sopenharmony_ci q_vector = vsi->q_vectors[vector_id - ICE_NONQ_VECS_VF]; 156362306a36Sopenharmony_ci if (!q_vector) { 156462306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 156562306a36Sopenharmony_ci goto error_param; 156662306a36Sopenharmony_ci } 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci /* lookout for the invalid queue index */ 156962306a36Sopenharmony_ci v_ret = (enum virtchnl_status_code) 157062306a36Sopenharmony_ci ice_cfg_interrupt(vf, vsi, vector_id, map, q_vector); 157162306a36Sopenharmony_ci if (v_ret) 157262306a36Sopenharmony_ci goto error_param; 157362306a36Sopenharmony_ci } 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_cierror_param: 157662306a36Sopenharmony_ci /* send the response to the VF */ 157762306a36Sopenharmony_ci return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_IRQ_MAP, v_ret, 157862306a36Sopenharmony_ci NULL, 0); 157962306a36Sopenharmony_ci} 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci/** 158262306a36Sopenharmony_ci * ice_vc_cfg_qs_msg 158362306a36Sopenharmony_ci * @vf: pointer to the VF info 158462306a36Sopenharmony_ci * @msg: pointer to the msg buffer 158562306a36Sopenharmony_ci * 158662306a36Sopenharmony_ci * called from the VF to configure the Rx/Tx queues 158762306a36Sopenharmony_ci */ 158862306a36Sopenharmony_cistatic int ice_vc_cfg_qs_msg(struct ice_vf *vf, u8 *msg) 158962306a36Sopenharmony_ci{ 159062306a36Sopenharmony_ci struct virtchnl_vsi_queue_config_info *qci = 159162306a36Sopenharmony_ci (struct virtchnl_vsi_queue_config_info *)msg; 159262306a36Sopenharmony_ci struct virtchnl_queue_pair_info *qpi; 159362306a36Sopenharmony_ci struct ice_pf *pf = vf->pf; 159462306a36Sopenharmony_ci struct ice_lag *lag; 159562306a36Sopenharmony_ci struct ice_vsi *vsi; 159662306a36Sopenharmony_ci u8 act_prt, pri_prt; 159762306a36Sopenharmony_ci int i = -1, q_idx; 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci lag = pf->lag; 160062306a36Sopenharmony_ci mutex_lock(&pf->lag_mutex); 160162306a36Sopenharmony_ci act_prt = ICE_LAG_INVALID_PORT; 160262306a36Sopenharmony_ci pri_prt = pf->hw.port_info->lport; 160362306a36Sopenharmony_ci if (lag && lag->bonded && lag->primary) { 160462306a36Sopenharmony_ci act_prt = lag->active_port; 160562306a36Sopenharmony_ci if (act_prt != pri_prt && act_prt != ICE_LAG_INVALID_PORT && 160662306a36Sopenharmony_ci lag->upper_netdev) 160762306a36Sopenharmony_ci ice_lag_move_vf_nodes_cfg(lag, act_prt, pri_prt); 160862306a36Sopenharmony_ci else 160962306a36Sopenharmony_ci act_prt = ICE_LAG_INVALID_PORT; 161062306a36Sopenharmony_ci } 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) 161362306a36Sopenharmony_ci goto error_param; 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci if (!ice_vc_isvalid_vsi_id(vf, qci->vsi_id)) 161662306a36Sopenharmony_ci goto error_param; 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci vsi = ice_get_vf_vsi(vf); 161962306a36Sopenharmony_ci if (!vsi) 162062306a36Sopenharmony_ci goto error_param; 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci if (qci->num_queue_pairs > ICE_MAX_RSS_QS_PER_VF || 162362306a36Sopenharmony_ci qci->num_queue_pairs > min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)) { 162462306a36Sopenharmony_ci dev_err(ice_pf_to_dev(pf), "VF-%d requesting more than supported number of queues: %d\n", 162562306a36Sopenharmony_ci vf->vf_id, min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)); 162662306a36Sopenharmony_ci goto error_param; 162762306a36Sopenharmony_ci } 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci for (i = 0; i < qci->num_queue_pairs; i++) { 163062306a36Sopenharmony_ci qpi = &qci->qpair[i]; 163162306a36Sopenharmony_ci if (qpi->txq.vsi_id != qci->vsi_id || 163262306a36Sopenharmony_ci qpi->rxq.vsi_id != qci->vsi_id || 163362306a36Sopenharmony_ci qpi->rxq.queue_id != qpi->txq.queue_id || 163462306a36Sopenharmony_ci qpi->txq.headwb_enabled || 163562306a36Sopenharmony_ci !ice_vc_isvalid_ring_len(qpi->txq.ring_len) || 163662306a36Sopenharmony_ci !ice_vc_isvalid_ring_len(qpi->rxq.ring_len) || 163762306a36Sopenharmony_ci !ice_vc_isvalid_q_id(vf, qci->vsi_id, qpi->txq.queue_id)) { 163862306a36Sopenharmony_ci goto error_param; 163962306a36Sopenharmony_ci } 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci q_idx = qpi->rxq.queue_id; 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci /* make sure selected "q_idx" is in valid range of queues 164462306a36Sopenharmony_ci * for selected "vsi" 164562306a36Sopenharmony_ci */ 164662306a36Sopenharmony_ci if (q_idx >= vsi->alloc_txq || q_idx >= vsi->alloc_rxq) { 164762306a36Sopenharmony_ci goto error_param; 164862306a36Sopenharmony_ci } 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci /* copy Tx queue info from VF into VSI */ 165162306a36Sopenharmony_ci if (qpi->txq.ring_len > 0) { 165262306a36Sopenharmony_ci vsi->tx_rings[i]->dma = qpi->txq.dma_ring_addr; 165362306a36Sopenharmony_ci vsi->tx_rings[i]->count = qpi->txq.ring_len; 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ci /* Disable any existing queue first */ 165662306a36Sopenharmony_ci if (ice_vf_vsi_dis_single_txq(vf, vsi, q_idx)) 165762306a36Sopenharmony_ci goto error_param; 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci /* Configure a queue with the requested settings */ 166062306a36Sopenharmony_ci if (ice_vsi_cfg_single_txq(vsi, vsi->tx_rings, q_idx)) { 166162306a36Sopenharmony_ci dev_warn(ice_pf_to_dev(pf), "VF-%d failed to configure TX queue %d\n", 166262306a36Sopenharmony_ci vf->vf_id, i); 166362306a36Sopenharmony_ci goto error_param; 166462306a36Sopenharmony_ci } 166562306a36Sopenharmony_ci } 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci /* copy Rx queue info from VF into VSI */ 166862306a36Sopenharmony_ci if (qpi->rxq.ring_len > 0) { 166962306a36Sopenharmony_ci u16 max_frame_size = ice_vc_get_max_frame_size(vf); 167062306a36Sopenharmony_ci u32 rxdid; 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci vsi->rx_rings[i]->dma = qpi->rxq.dma_ring_addr; 167362306a36Sopenharmony_ci vsi->rx_rings[i]->count = qpi->rxq.ring_len; 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci if (qpi->rxq.databuffer_size != 0 && 167662306a36Sopenharmony_ci (qpi->rxq.databuffer_size > ((16 * 1024) - 128) || 167762306a36Sopenharmony_ci qpi->rxq.databuffer_size < 1024)) 167862306a36Sopenharmony_ci goto error_param; 167962306a36Sopenharmony_ci vsi->rx_buf_len = qpi->rxq.databuffer_size; 168062306a36Sopenharmony_ci vsi->rx_rings[i]->rx_buf_len = vsi->rx_buf_len; 168162306a36Sopenharmony_ci if (qpi->rxq.max_pkt_size > max_frame_size || 168262306a36Sopenharmony_ci qpi->rxq.max_pkt_size < 64) 168362306a36Sopenharmony_ci goto error_param; 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci vsi->max_frame = qpi->rxq.max_pkt_size; 168662306a36Sopenharmony_ci /* add space for the port VLAN since the VF driver is 168762306a36Sopenharmony_ci * not expected to account for it in the MTU 168862306a36Sopenharmony_ci * calculation 168962306a36Sopenharmony_ci */ 169062306a36Sopenharmony_ci if (ice_vf_is_port_vlan_ena(vf)) 169162306a36Sopenharmony_ci vsi->max_frame += VLAN_HLEN; 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci if (ice_vsi_cfg_single_rxq(vsi, q_idx)) { 169462306a36Sopenharmony_ci dev_warn(ice_pf_to_dev(pf), "VF-%d failed to configure RX queue %d\n", 169562306a36Sopenharmony_ci vf->vf_id, i); 169662306a36Sopenharmony_ci goto error_param; 169762306a36Sopenharmony_ci } 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci /* If Rx flex desc is supported, select RXDID for Rx 170062306a36Sopenharmony_ci * queues. Otherwise, use legacy 32byte descriptor 170162306a36Sopenharmony_ci * format. Legacy 16byte descriptor is not supported. 170262306a36Sopenharmony_ci * If this RXDID is selected, return error. 170362306a36Sopenharmony_ci */ 170462306a36Sopenharmony_ci if (vf->driver_caps & 170562306a36Sopenharmony_ci VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC) { 170662306a36Sopenharmony_ci rxdid = qpi->rxq.rxdid; 170762306a36Sopenharmony_ci if (!(BIT(rxdid) & pf->supported_rxdids)) 170862306a36Sopenharmony_ci goto error_param; 170962306a36Sopenharmony_ci } else { 171062306a36Sopenharmony_ci rxdid = ICE_RXDID_LEGACY_1; 171162306a36Sopenharmony_ci } 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci ice_write_qrxflxp_cntxt(&vsi->back->hw, 171462306a36Sopenharmony_ci vsi->rxq_map[q_idx], 171562306a36Sopenharmony_ci rxdid, 0x03, false); 171662306a36Sopenharmony_ci } 171762306a36Sopenharmony_ci } 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci if (lag && lag->bonded && lag->primary && 172062306a36Sopenharmony_ci act_prt != ICE_LAG_INVALID_PORT) 172162306a36Sopenharmony_ci ice_lag_move_vf_nodes_cfg(lag, pri_prt, act_prt); 172262306a36Sopenharmony_ci mutex_unlock(&pf->lag_mutex); 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci /* send the response to the VF */ 172562306a36Sopenharmony_ci return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_VSI_QUEUES, 172662306a36Sopenharmony_ci VIRTCHNL_STATUS_SUCCESS, NULL, 0); 172762306a36Sopenharmony_cierror_param: 172862306a36Sopenharmony_ci /* disable whatever we can */ 172962306a36Sopenharmony_ci for (; i >= 0; i--) { 173062306a36Sopenharmony_ci if (ice_vsi_ctrl_one_rx_ring(vsi, false, i, true)) 173162306a36Sopenharmony_ci dev_err(ice_pf_to_dev(pf), "VF-%d could not disable RX queue %d\n", 173262306a36Sopenharmony_ci vf->vf_id, i); 173362306a36Sopenharmony_ci if (ice_vf_vsi_dis_single_txq(vf, vsi, i)) 173462306a36Sopenharmony_ci dev_err(ice_pf_to_dev(pf), "VF-%d could not disable TX queue %d\n", 173562306a36Sopenharmony_ci vf->vf_id, i); 173662306a36Sopenharmony_ci } 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci if (lag && lag->bonded && lag->primary && 173962306a36Sopenharmony_ci act_prt != ICE_LAG_INVALID_PORT) 174062306a36Sopenharmony_ci ice_lag_move_vf_nodes_cfg(lag, pri_prt, act_prt); 174162306a36Sopenharmony_ci mutex_unlock(&pf->lag_mutex); 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci ice_lag_move_new_vf_nodes(vf); 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci /* send the response to the VF */ 174662306a36Sopenharmony_ci return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_VSI_QUEUES, 174762306a36Sopenharmony_ci VIRTCHNL_STATUS_ERR_PARAM, NULL, 0); 174862306a36Sopenharmony_ci} 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci/** 175162306a36Sopenharmony_ci * ice_can_vf_change_mac 175262306a36Sopenharmony_ci * @vf: pointer to the VF info 175362306a36Sopenharmony_ci * 175462306a36Sopenharmony_ci * Return true if the VF is allowed to change its MAC filters, false otherwise 175562306a36Sopenharmony_ci */ 175662306a36Sopenharmony_cistatic bool ice_can_vf_change_mac(struct ice_vf *vf) 175762306a36Sopenharmony_ci{ 175862306a36Sopenharmony_ci /* If the VF MAC address has been set administratively (via the 175962306a36Sopenharmony_ci * ndo_set_vf_mac command), then deny permission to the VF to 176062306a36Sopenharmony_ci * add/delete unicast MAC addresses, unless the VF is trusted 176162306a36Sopenharmony_ci */ 176262306a36Sopenharmony_ci if (vf->pf_set_mac && !ice_is_vf_trusted(vf)) 176362306a36Sopenharmony_ci return false; 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci return true; 176662306a36Sopenharmony_ci} 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_ci/** 176962306a36Sopenharmony_ci * ice_vc_ether_addr_type - get type of virtchnl_ether_addr 177062306a36Sopenharmony_ci * @vc_ether_addr: used to extract the type 177162306a36Sopenharmony_ci */ 177262306a36Sopenharmony_cistatic u8 177362306a36Sopenharmony_ciice_vc_ether_addr_type(struct virtchnl_ether_addr *vc_ether_addr) 177462306a36Sopenharmony_ci{ 177562306a36Sopenharmony_ci return (vc_ether_addr->type & VIRTCHNL_ETHER_ADDR_TYPE_MASK); 177662306a36Sopenharmony_ci} 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci/** 177962306a36Sopenharmony_ci * ice_is_vc_addr_legacy - check if the MAC address is from an older VF 178062306a36Sopenharmony_ci * @vc_ether_addr: VIRTCHNL structure that contains MAC and type 178162306a36Sopenharmony_ci */ 178262306a36Sopenharmony_cistatic bool 178362306a36Sopenharmony_ciice_is_vc_addr_legacy(struct virtchnl_ether_addr *vc_ether_addr) 178462306a36Sopenharmony_ci{ 178562306a36Sopenharmony_ci u8 type = ice_vc_ether_addr_type(vc_ether_addr); 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci return (type == VIRTCHNL_ETHER_ADDR_LEGACY); 178862306a36Sopenharmony_ci} 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci/** 179162306a36Sopenharmony_ci * ice_is_vc_addr_primary - check if the MAC address is the VF's primary MAC 179262306a36Sopenharmony_ci * @vc_ether_addr: VIRTCHNL structure that contains MAC and type 179362306a36Sopenharmony_ci * 179462306a36Sopenharmony_ci * This function should only be called when the MAC address in 179562306a36Sopenharmony_ci * virtchnl_ether_addr is a valid unicast MAC 179662306a36Sopenharmony_ci */ 179762306a36Sopenharmony_cistatic bool 179862306a36Sopenharmony_ciice_is_vc_addr_primary(struct virtchnl_ether_addr __maybe_unused *vc_ether_addr) 179962306a36Sopenharmony_ci{ 180062306a36Sopenharmony_ci u8 type = ice_vc_ether_addr_type(vc_ether_addr); 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ci return (type == VIRTCHNL_ETHER_ADDR_PRIMARY); 180362306a36Sopenharmony_ci} 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci/** 180662306a36Sopenharmony_ci * ice_vfhw_mac_add - update the VF's cached hardware MAC if allowed 180762306a36Sopenharmony_ci * @vf: VF to update 180862306a36Sopenharmony_ci * @vc_ether_addr: structure from VIRTCHNL with MAC to add 180962306a36Sopenharmony_ci */ 181062306a36Sopenharmony_cistatic void 181162306a36Sopenharmony_ciice_vfhw_mac_add(struct ice_vf *vf, struct virtchnl_ether_addr *vc_ether_addr) 181262306a36Sopenharmony_ci{ 181362306a36Sopenharmony_ci u8 *mac_addr = vc_ether_addr->addr; 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci if (!is_valid_ether_addr(mac_addr)) 181662306a36Sopenharmony_ci return; 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci /* only allow legacy VF drivers to set the device and hardware MAC if it 181962306a36Sopenharmony_ci * is zero and allow new VF drivers to set the hardware MAC if the type 182062306a36Sopenharmony_ci * was correctly specified over VIRTCHNL 182162306a36Sopenharmony_ci */ 182262306a36Sopenharmony_ci if ((ice_is_vc_addr_legacy(vc_ether_addr) && 182362306a36Sopenharmony_ci is_zero_ether_addr(vf->hw_lan_addr)) || 182462306a36Sopenharmony_ci ice_is_vc_addr_primary(vc_ether_addr)) { 182562306a36Sopenharmony_ci ether_addr_copy(vf->dev_lan_addr, mac_addr); 182662306a36Sopenharmony_ci ether_addr_copy(vf->hw_lan_addr, mac_addr); 182762306a36Sopenharmony_ci } 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_ci /* hardware and device MACs are already set, but its possible that the 183062306a36Sopenharmony_ci * VF driver sent the VIRTCHNL_OP_ADD_ETH_ADDR message before the 183162306a36Sopenharmony_ci * VIRTCHNL_OP_DEL_ETH_ADDR when trying to update its MAC, so save it 183262306a36Sopenharmony_ci * away for the legacy VF driver case as it will be updated in the 183362306a36Sopenharmony_ci * delete flow for this case 183462306a36Sopenharmony_ci */ 183562306a36Sopenharmony_ci if (ice_is_vc_addr_legacy(vc_ether_addr)) { 183662306a36Sopenharmony_ci ether_addr_copy(vf->legacy_last_added_umac.addr, 183762306a36Sopenharmony_ci mac_addr); 183862306a36Sopenharmony_ci vf->legacy_last_added_umac.time_modified = jiffies; 183962306a36Sopenharmony_ci } 184062306a36Sopenharmony_ci} 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci/** 184362306a36Sopenharmony_ci * ice_vc_add_mac_addr - attempt to add the MAC address passed in 184462306a36Sopenharmony_ci * @vf: pointer to the VF info 184562306a36Sopenharmony_ci * @vsi: pointer to the VF's VSI 184662306a36Sopenharmony_ci * @vc_ether_addr: VIRTCHNL MAC address structure used to add MAC 184762306a36Sopenharmony_ci */ 184862306a36Sopenharmony_cistatic int 184962306a36Sopenharmony_ciice_vc_add_mac_addr(struct ice_vf *vf, struct ice_vsi *vsi, 185062306a36Sopenharmony_ci struct virtchnl_ether_addr *vc_ether_addr) 185162306a36Sopenharmony_ci{ 185262306a36Sopenharmony_ci struct device *dev = ice_pf_to_dev(vf->pf); 185362306a36Sopenharmony_ci u8 *mac_addr = vc_ether_addr->addr; 185462306a36Sopenharmony_ci int ret; 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci /* device MAC already added */ 185762306a36Sopenharmony_ci if (ether_addr_equal(mac_addr, vf->dev_lan_addr)) 185862306a36Sopenharmony_ci return 0; 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci if (is_unicast_ether_addr(mac_addr) && !ice_can_vf_change_mac(vf)) { 186162306a36Sopenharmony_ci dev_err(dev, "VF attempting to override administratively set MAC address, bring down and up the VF interface to resume normal operation\n"); 186262306a36Sopenharmony_ci return -EPERM; 186362306a36Sopenharmony_ci } 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci ret = ice_fltr_add_mac(vsi, mac_addr, ICE_FWD_TO_VSI); 186662306a36Sopenharmony_ci if (ret == -EEXIST) { 186762306a36Sopenharmony_ci dev_dbg(dev, "MAC %pM already exists for VF %d\n", mac_addr, 186862306a36Sopenharmony_ci vf->vf_id); 186962306a36Sopenharmony_ci /* don't return since we might need to update 187062306a36Sopenharmony_ci * the primary MAC in ice_vfhw_mac_add() below 187162306a36Sopenharmony_ci */ 187262306a36Sopenharmony_ci } else if (ret) { 187362306a36Sopenharmony_ci dev_err(dev, "Failed to add MAC %pM for VF %d\n, error %d\n", 187462306a36Sopenharmony_ci mac_addr, vf->vf_id, ret); 187562306a36Sopenharmony_ci return ret; 187662306a36Sopenharmony_ci } else { 187762306a36Sopenharmony_ci vf->num_mac++; 187862306a36Sopenharmony_ci } 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci ice_vfhw_mac_add(vf, vc_ether_addr); 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_ci return ret; 188362306a36Sopenharmony_ci} 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci/** 188662306a36Sopenharmony_ci * ice_is_legacy_umac_expired - check if last added legacy unicast MAC expired 188762306a36Sopenharmony_ci * @last_added_umac: structure used to check expiration 188862306a36Sopenharmony_ci */ 188962306a36Sopenharmony_cistatic bool ice_is_legacy_umac_expired(struct ice_time_mac *last_added_umac) 189062306a36Sopenharmony_ci{ 189162306a36Sopenharmony_ci#define ICE_LEGACY_VF_MAC_CHANGE_EXPIRE_TIME msecs_to_jiffies(3000) 189262306a36Sopenharmony_ci return time_is_before_jiffies(last_added_umac->time_modified + 189362306a36Sopenharmony_ci ICE_LEGACY_VF_MAC_CHANGE_EXPIRE_TIME); 189462306a36Sopenharmony_ci} 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_ci/** 189762306a36Sopenharmony_ci * ice_update_legacy_cached_mac - update cached hardware MAC for legacy VF 189862306a36Sopenharmony_ci * @vf: VF to update 189962306a36Sopenharmony_ci * @vc_ether_addr: structure from VIRTCHNL with MAC to check 190062306a36Sopenharmony_ci * 190162306a36Sopenharmony_ci * only update cached hardware MAC for legacy VF drivers on delete 190262306a36Sopenharmony_ci * because we cannot guarantee order/type of MAC from the VF driver 190362306a36Sopenharmony_ci */ 190462306a36Sopenharmony_cistatic void 190562306a36Sopenharmony_ciice_update_legacy_cached_mac(struct ice_vf *vf, 190662306a36Sopenharmony_ci struct virtchnl_ether_addr *vc_ether_addr) 190762306a36Sopenharmony_ci{ 190862306a36Sopenharmony_ci if (!ice_is_vc_addr_legacy(vc_ether_addr) || 190962306a36Sopenharmony_ci ice_is_legacy_umac_expired(&vf->legacy_last_added_umac)) 191062306a36Sopenharmony_ci return; 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ci ether_addr_copy(vf->dev_lan_addr, vf->legacy_last_added_umac.addr); 191362306a36Sopenharmony_ci ether_addr_copy(vf->hw_lan_addr, vf->legacy_last_added_umac.addr); 191462306a36Sopenharmony_ci} 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci/** 191762306a36Sopenharmony_ci * ice_vfhw_mac_del - update the VF's cached hardware MAC if allowed 191862306a36Sopenharmony_ci * @vf: VF to update 191962306a36Sopenharmony_ci * @vc_ether_addr: structure from VIRTCHNL with MAC to delete 192062306a36Sopenharmony_ci */ 192162306a36Sopenharmony_cistatic void 192262306a36Sopenharmony_ciice_vfhw_mac_del(struct ice_vf *vf, struct virtchnl_ether_addr *vc_ether_addr) 192362306a36Sopenharmony_ci{ 192462306a36Sopenharmony_ci u8 *mac_addr = vc_ether_addr->addr; 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci if (!is_valid_ether_addr(mac_addr) || 192762306a36Sopenharmony_ci !ether_addr_equal(vf->dev_lan_addr, mac_addr)) 192862306a36Sopenharmony_ci return; 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci /* allow the device MAC to be repopulated in the add flow and don't 193162306a36Sopenharmony_ci * clear the hardware MAC (i.e. hw_lan_addr) here as that is meant 193262306a36Sopenharmony_ci * to be persistent on VM reboot and across driver unload/load, which 193362306a36Sopenharmony_ci * won't work if we clear the hardware MAC here 193462306a36Sopenharmony_ci */ 193562306a36Sopenharmony_ci eth_zero_addr(vf->dev_lan_addr); 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ci ice_update_legacy_cached_mac(vf, vc_ether_addr); 193862306a36Sopenharmony_ci} 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_ci/** 194162306a36Sopenharmony_ci * ice_vc_del_mac_addr - attempt to delete the MAC address passed in 194262306a36Sopenharmony_ci * @vf: pointer to the VF info 194362306a36Sopenharmony_ci * @vsi: pointer to the VF's VSI 194462306a36Sopenharmony_ci * @vc_ether_addr: VIRTCHNL MAC address structure used to delete MAC 194562306a36Sopenharmony_ci */ 194662306a36Sopenharmony_cistatic int 194762306a36Sopenharmony_ciice_vc_del_mac_addr(struct ice_vf *vf, struct ice_vsi *vsi, 194862306a36Sopenharmony_ci struct virtchnl_ether_addr *vc_ether_addr) 194962306a36Sopenharmony_ci{ 195062306a36Sopenharmony_ci struct device *dev = ice_pf_to_dev(vf->pf); 195162306a36Sopenharmony_ci u8 *mac_addr = vc_ether_addr->addr; 195262306a36Sopenharmony_ci int status; 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_ci if (!ice_can_vf_change_mac(vf) && 195562306a36Sopenharmony_ci ether_addr_equal(vf->dev_lan_addr, mac_addr)) 195662306a36Sopenharmony_ci return 0; 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci status = ice_fltr_remove_mac(vsi, mac_addr, ICE_FWD_TO_VSI); 195962306a36Sopenharmony_ci if (status == -ENOENT) { 196062306a36Sopenharmony_ci dev_err(dev, "MAC %pM does not exist for VF %d\n", mac_addr, 196162306a36Sopenharmony_ci vf->vf_id); 196262306a36Sopenharmony_ci return -ENOENT; 196362306a36Sopenharmony_ci } else if (status) { 196462306a36Sopenharmony_ci dev_err(dev, "Failed to delete MAC %pM for VF %d, error %d\n", 196562306a36Sopenharmony_ci mac_addr, vf->vf_id, status); 196662306a36Sopenharmony_ci return -EIO; 196762306a36Sopenharmony_ci } 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_ci ice_vfhw_mac_del(vf, vc_ether_addr); 197062306a36Sopenharmony_ci 197162306a36Sopenharmony_ci vf->num_mac--; 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci return 0; 197462306a36Sopenharmony_ci} 197562306a36Sopenharmony_ci 197662306a36Sopenharmony_ci/** 197762306a36Sopenharmony_ci * ice_vc_handle_mac_addr_msg 197862306a36Sopenharmony_ci * @vf: pointer to the VF info 197962306a36Sopenharmony_ci * @msg: pointer to the msg buffer 198062306a36Sopenharmony_ci * @set: true if MAC filters are being set, false otherwise 198162306a36Sopenharmony_ci * 198262306a36Sopenharmony_ci * add guest MAC address filter 198362306a36Sopenharmony_ci */ 198462306a36Sopenharmony_cistatic int 198562306a36Sopenharmony_ciice_vc_handle_mac_addr_msg(struct ice_vf *vf, u8 *msg, bool set) 198662306a36Sopenharmony_ci{ 198762306a36Sopenharmony_ci int (*ice_vc_cfg_mac) 198862306a36Sopenharmony_ci (struct ice_vf *vf, struct ice_vsi *vsi, 198962306a36Sopenharmony_ci struct virtchnl_ether_addr *virtchnl_ether_addr); 199062306a36Sopenharmony_ci enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 199162306a36Sopenharmony_ci struct virtchnl_ether_addr_list *al = 199262306a36Sopenharmony_ci (struct virtchnl_ether_addr_list *)msg; 199362306a36Sopenharmony_ci struct ice_pf *pf = vf->pf; 199462306a36Sopenharmony_ci enum virtchnl_ops vc_op; 199562306a36Sopenharmony_ci struct ice_vsi *vsi; 199662306a36Sopenharmony_ci int i; 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci if (set) { 199962306a36Sopenharmony_ci vc_op = VIRTCHNL_OP_ADD_ETH_ADDR; 200062306a36Sopenharmony_ci ice_vc_cfg_mac = ice_vc_add_mac_addr; 200162306a36Sopenharmony_ci } else { 200262306a36Sopenharmony_ci vc_op = VIRTCHNL_OP_DEL_ETH_ADDR; 200362306a36Sopenharmony_ci ice_vc_cfg_mac = ice_vc_del_mac_addr; 200462306a36Sopenharmony_ci } 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_ci if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states) || 200762306a36Sopenharmony_ci !ice_vc_isvalid_vsi_id(vf, al->vsi_id)) { 200862306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 200962306a36Sopenharmony_ci goto handle_mac_exit; 201062306a36Sopenharmony_ci } 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_ci /* If this VF is not privileged, then we can't add more than a 201362306a36Sopenharmony_ci * limited number of addresses. Check to make sure that the 201462306a36Sopenharmony_ci * additions do not push us over the limit. 201562306a36Sopenharmony_ci */ 201662306a36Sopenharmony_ci if (set && !ice_is_vf_trusted(vf) && 201762306a36Sopenharmony_ci (vf->num_mac + al->num_elements) > ICE_MAX_MACADDR_PER_VF) { 201862306a36Sopenharmony_ci 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", 201962306a36Sopenharmony_ci vf->vf_id); 202062306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 202162306a36Sopenharmony_ci goto handle_mac_exit; 202262306a36Sopenharmony_ci } 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ci vsi = ice_get_vf_vsi(vf); 202562306a36Sopenharmony_ci if (!vsi) { 202662306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 202762306a36Sopenharmony_ci goto handle_mac_exit; 202862306a36Sopenharmony_ci } 202962306a36Sopenharmony_ci 203062306a36Sopenharmony_ci for (i = 0; i < al->num_elements; i++) { 203162306a36Sopenharmony_ci u8 *mac_addr = al->list[i].addr; 203262306a36Sopenharmony_ci int result; 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci if (is_broadcast_ether_addr(mac_addr) || 203562306a36Sopenharmony_ci is_zero_ether_addr(mac_addr)) 203662306a36Sopenharmony_ci continue; 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ci result = ice_vc_cfg_mac(vf, vsi, &al->list[i]); 203962306a36Sopenharmony_ci if (result == -EEXIST || result == -ENOENT) { 204062306a36Sopenharmony_ci continue; 204162306a36Sopenharmony_ci } else if (result) { 204262306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR; 204362306a36Sopenharmony_ci goto handle_mac_exit; 204462306a36Sopenharmony_ci } 204562306a36Sopenharmony_ci } 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_cihandle_mac_exit: 204862306a36Sopenharmony_ci /* send the response to the VF */ 204962306a36Sopenharmony_ci return ice_vc_send_msg_to_vf(vf, vc_op, v_ret, NULL, 0); 205062306a36Sopenharmony_ci} 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci/** 205362306a36Sopenharmony_ci * ice_vc_add_mac_addr_msg 205462306a36Sopenharmony_ci * @vf: pointer to the VF info 205562306a36Sopenharmony_ci * @msg: pointer to the msg buffer 205662306a36Sopenharmony_ci * 205762306a36Sopenharmony_ci * add guest MAC address filter 205862306a36Sopenharmony_ci */ 205962306a36Sopenharmony_cistatic int ice_vc_add_mac_addr_msg(struct ice_vf *vf, u8 *msg) 206062306a36Sopenharmony_ci{ 206162306a36Sopenharmony_ci return ice_vc_handle_mac_addr_msg(vf, msg, true); 206262306a36Sopenharmony_ci} 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ci/** 206562306a36Sopenharmony_ci * ice_vc_del_mac_addr_msg 206662306a36Sopenharmony_ci * @vf: pointer to the VF info 206762306a36Sopenharmony_ci * @msg: pointer to the msg buffer 206862306a36Sopenharmony_ci * 206962306a36Sopenharmony_ci * remove guest MAC address filter 207062306a36Sopenharmony_ci */ 207162306a36Sopenharmony_cistatic int ice_vc_del_mac_addr_msg(struct ice_vf *vf, u8 *msg) 207262306a36Sopenharmony_ci{ 207362306a36Sopenharmony_ci return ice_vc_handle_mac_addr_msg(vf, msg, false); 207462306a36Sopenharmony_ci} 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_ci/** 207762306a36Sopenharmony_ci * ice_vc_request_qs_msg 207862306a36Sopenharmony_ci * @vf: pointer to the VF info 207962306a36Sopenharmony_ci * @msg: pointer to the msg buffer 208062306a36Sopenharmony_ci * 208162306a36Sopenharmony_ci * VFs get a default number of queues but can use this message to request a 208262306a36Sopenharmony_ci * different number. If the request is successful, PF will reset the VF and 208362306a36Sopenharmony_ci * return 0. If unsuccessful, PF will send message informing VF of number of 208462306a36Sopenharmony_ci * available queue pairs via virtchnl message response to VF. 208562306a36Sopenharmony_ci */ 208662306a36Sopenharmony_cistatic int ice_vc_request_qs_msg(struct ice_vf *vf, u8 *msg) 208762306a36Sopenharmony_ci{ 208862306a36Sopenharmony_ci enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 208962306a36Sopenharmony_ci struct virtchnl_vf_res_request *vfres = 209062306a36Sopenharmony_ci (struct virtchnl_vf_res_request *)msg; 209162306a36Sopenharmony_ci u16 req_queues = vfres->num_queue_pairs; 209262306a36Sopenharmony_ci struct ice_pf *pf = vf->pf; 209362306a36Sopenharmony_ci u16 max_allowed_vf_queues; 209462306a36Sopenharmony_ci u16 tx_rx_queue_left; 209562306a36Sopenharmony_ci struct device *dev; 209662306a36Sopenharmony_ci u16 cur_queues; 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_ci dev = ice_pf_to_dev(pf); 209962306a36Sopenharmony_ci if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { 210062306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 210162306a36Sopenharmony_ci goto error_param; 210262306a36Sopenharmony_ci } 210362306a36Sopenharmony_ci 210462306a36Sopenharmony_ci cur_queues = vf->num_vf_qs; 210562306a36Sopenharmony_ci tx_rx_queue_left = min_t(u16, ice_get_avail_txq_count(pf), 210662306a36Sopenharmony_ci ice_get_avail_rxq_count(pf)); 210762306a36Sopenharmony_ci max_allowed_vf_queues = tx_rx_queue_left + cur_queues; 210862306a36Sopenharmony_ci if (!req_queues) { 210962306a36Sopenharmony_ci dev_err(dev, "VF %d tried to request 0 queues. Ignoring.\n", 211062306a36Sopenharmony_ci vf->vf_id); 211162306a36Sopenharmony_ci } else if (req_queues > ICE_MAX_RSS_QS_PER_VF) { 211262306a36Sopenharmony_ci dev_err(dev, "VF %d tried to request more than %d queues.\n", 211362306a36Sopenharmony_ci vf->vf_id, ICE_MAX_RSS_QS_PER_VF); 211462306a36Sopenharmony_ci vfres->num_queue_pairs = ICE_MAX_RSS_QS_PER_VF; 211562306a36Sopenharmony_ci } else if (req_queues > cur_queues && 211662306a36Sopenharmony_ci req_queues - cur_queues > tx_rx_queue_left) { 211762306a36Sopenharmony_ci dev_warn(dev, "VF %d requested %u more queues, but only %u left.\n", 211862306a36Sopenharmony_ci vf->vf_id, req_queues - cur_queues, tx_rx_queue_left); 211962306a36Sopenharmony_ci vfres->num_queue_pairs = min_t(u16, max_allowed_vf_queues, 212062306a36Sopenharmony_ci ICE_MAX_RSS_QS_PER_VF); 212162306a36Sopenharmony_ci } else { 212262306a36Sopenharmony_ci /* request is successful, then reset VF */ 212362306a36Sopenharmony_ci vf->num_req_qs = req_queues; 212462306a36Sopenharmony_ci ice_reset_vf(vf, ICE_VF_RESET_NOTIFY); 212562306a36Sopenharmony_ci dev_info(dev, "VF %d granted request of %u queues.\n", 212662306a36Sopenharmony_ci vf->vf_id, req_queues); 212762306a36Sopenharmony_ci return 0; 212862306a36Sopenharmony_ci } 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_cierror_param: 213162306a36Sopenharmony_ci /* send the response to the VF */ 213262306a36Sopenharmony_ci return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_REQUEST_QUEUES, 213362306a36Sopenharmony_ci v_ret, (u8 *)vfres, sizeof(*vfres)); 213462306a36Sopenharmony_ci} 213562306a36Sopenharmony_ci 213662306a36Sopenharmony_ci/** 213762306a36Sopenharmony_ci * ice_vf_vlan_offload_ena - determine if capabilities support VLAN offloads 213862306a36Sopenharmony_ci * @caps: VF driver negotiated capabilities 213962306a36Sopenharmony_ci * 214062306a36Sopenharmony_ci * Return true if VIRTCHNL_VF_OFFLOAD_VLAN capability is set, else return false 214162306a36Sopenharmony_ci */ 214262306a36Sopenharmony_cistatic bool ice_vf_vlan_offload_ena(u32 caps) 214362306a36Sopenharmony_ci{ 214462306a36Sopenharmony_ci return !!(caps & VIRTCHNL_VF_OFFLOAD_VLAN); 214562306a36Sopenharmony_ci} 214662306a36Sopenharmony_ci 214762306a36Sopenharmony_ci/** 214862306a36Sopenharmony_ci * ice_is_vlan_promisc_allowed - check if VLAN promiscuous config is allowed 214962306a36Sopenharmony_ci * @vf: VF used to determine if VLAN promiscuous config is allowed 215062306a36Sopenharmony_ci */ 215162306a36Sopenharmony_cistatic bool ice_is_vlan_promisc_allowed(struct ice_vf *vf) 215262306a36Sopenharmony_ci{ 215362306a36Sopenharmony_ci if ((test_bit(ICE_VF_STATE_UC_PROMISC, vf->vf_states) || 215462306a36Sopenharmony_ci test_bit(ICE_VF_STATE_MC_PROMISC, vf->vf_states)) && 215562306a36Sopenharmony_ci test_bit(ICE_FLAG_VF_TRUE_PROMISC_ENA, vf->pf->flags)) 215662306a36Sopenharmony_ci return true; 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci return false; 215962306a36Sopenharmony_ci} 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_ci/** 216262306a36Sopenharmony_ci * ice_vf_ena_vlan_promisc - Enable Tx/Rx VLAN promiscuous for the VLAN 216362306a36Sopenharmony_ci * @vsi: VF's VSI used to enable VLAN promiscuous mode 216462306a36Sopenharmony_ci * @vlan: VLAN used to enable VLAN promiscuous 216562306a36Sopenharmony_ci * 216662306a36Sopenharmony_ci * This function should only be called if VLAN promiscuous mode is allowed, 216762306a36Sopenharmony_ci * which can be determined via ice_is_vlan_promisc_allowed(). 216862306a36Sopenharmony_ci */ 216962306a36Sopenharmony_cistatic int ice_vf_ena_vlan_promisc(struct ice_vsi *vsi, struct ice_vlan *vlan) 217062306a36Sopenharmony_ci{ 217162306a36Sopenharmony_ci u8 promisc_m = ICE_PROMISC_VLAN_TX | ICE_PROMISC_VLAN_RX; 217262306a36Sopenharmony_ci int status; 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_ci status = ice_fltr_set_vsi_promisc(&vsi->back->hw, vsi->idx, promisc_m, 217562306a36Sopenharmony_ci vlan->vid); 217662306a36Sopenharmony_ci if (status && status != -EEXIST) 217762306a36Sopenharmony_ci return status; 217862306a36Sopenharmony_ci 217962306a36Sopenharmony_ci return 0; 218062306a36Sopenharmony_ci} 218162306a36Sopenharmony_ci 218262306a36Sopenharmony_ci/** 218362306a36Sopenharmony_ci * ice_vf_dis_vlan_promisc - Disable Tx/Rx VLAN promiscuous for the VLAN 218462306a36Sopenharmony_ci * @vsi: VF's VSI used to disable VLAN promiscuous mode for 218562306a36Sopenharmony_ci * @vlan: VLAN used to disable VLAN promiscuous 218662306a36Sopenharmony_ci * 218762306a36Sopenharmony_ci * This function should only be called if VLAN promiscuous mode is allowed, 218862306a36Sopenharmony_ci * which can be determined via ice_is_vlan_promisc_allowed(). 218962306a36Sopenharmony_ci */ 219062306a36Sopenharmony_cistatic int ice_vf_dis_vlan_promisc(struct ice_vsi *vsi, struct ice_vlan *vlan) 219162306a36Sopenharmony_ci{ 219262306a36Sopenharmony_ci u8 promisc_m = ICE_PROMISC_VLAN_TX | ICE_PROMISC_VLAN_RX; 219362306a36Sopenharmony_ci int status; 219462306a36Sopenharmony_ci 219562306a36Sopenharmony_ci status = ice_fltr_clear_vsi_promisc(&vsi->back->hw, vsi->idx, promisc_m, 219662306a36Sopenharmony_ci vlan->vid); 219762306a36Sopenharmony_ci if (status && status != -ENOENT) 219862306a36Sopenharmony_ci return status; 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci return 0; 220162306a36Sopenharmony_ci} 220262306a36Sopenharmony_ci 220362306a36Sopenharmony_ci/** 220462306a36Sopenharmony_ci * ice_vf_has_max_vlans - check if VF already has the max allowed VLAN filters 220562306a36Sopenharmony_ci * @vf: VF to check against 220662306a36Sopenharmony_ci * @vsi: VF's VSI 220762306a36Sopenharmony_ci * 220862306a36Sopenharmony_ci * If the VF is trusted then the VF is allowed to add as many VLANs as it 220962306a36Sopenharmony_ci * wants to, so return false. 221062306a36Sopenharmony_ci * 221162306a36Sopenharmony_ci * When the VF is untrusted compare the number of non-zero VLANs + 1 to the max 221262306a36Sopenharmony_ci * allowed VLANs for an untrusted VF. Return the result of this comparison. 221362306a36Sopenharmony_ci */ 221462306a36Sopenharmony_cistatic bool ice_vf_has_max_vlans(struct ice_vf *vf, struct ice_vsi *vsi) 221562306a36Sopenharmony_ci{ 221662306a36Sopenharmony_ci if (ice_is_vf_trusted(vf)) 221762306a36Sopenharmony_ci return false; 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci#define ICE_VF_ADDED_VLAN_ZERO_FLTRS 1 222062306a36Sopenharmony_ci return ((ice_vsi_num_non_zero_vlans(vsi) + 222162306a36Sopenharmony_ci ICE_VF_ADDED_VLAN_ZERO_FLTRS) >= ICE_MAX_VLAN_PER_VF); 222262306a36Sopenharmony_ci} 222362306a36Sopenharmony_ci 222462306a36Sopenharmony_ci/** 222562306a36Sopenharmony_ci * ice_vc_process_vlan_msg 222662306a36Sopenharmony_ci * @vf: pointer to the VF info 222762306a36Sopenharmony_ci * @msg: pointer to the msg buffer 222862306a36Sopenharmony_ci * @add_v: Add VLAN if true, otherwise delete VLAN 222962306a36Sopenharmony_ci * 223062306a36Sopenharmony_ci * Process virtchnl op to add or remove programmed guest VLAN ID 223162306a36Sopenharmony_ci */ 223262306a36Sopenharmony_cistatic int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v) 223362306a36Sopenharmony_ci{ 223462306a36Sopenharmony_ci enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 223562306a36Sopenharmony_ci struct virtchnl_vlan_filter_list *vfl = 223662306a36Sopenharmony_ci (struct virtchnl_vlan_filter_list *)msg; 223762306a36Sopenharmony_ci struct ice_pf *pf = vf->pf; 223862306a36Sopenharmony_ci bool vlan_promisc = false; 223962306a36Sopenharmony_ci struct ice_vsi *vsi; 224062306a36Sopenharmony_ci struct device *dev; 224162306a36Sopenharmony_ci int status = 0; 224262306a36Sopenharmony_ci int i; 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ci dev = ice_pf_to_dev(pf); 224562306a36Sopenharmony_ci if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { 224662306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 224762306a36Sopenharmony_ci goto error_param; 224862306a36Sopenharmony_ci } 224962306a36Sopenharmony_ci 225062306a36Sopenharmony_ci if (!ice_vf_vlan_offload_ena(vf->driver_caps)) { 225162306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 225262306a36Sopenharmony_ci goto error_param; 225362306a36Sopenharmony_ci } 225462306a36Sopenharmony_ci 225562306a36Sopenharmony_ci if (!ice_vc_isvalid_vsi_id(vf, vfl->vsi_id)) { 225662306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 225762306a36Sopenharmony_ci goto error_param; 225862306a36Sopenharmony_ci } 225962306a36Sopenharmony_ci 226062306a36Sopenharmony_ci for (i = 0; i < vfl->num_elements; i++) { 226162306a36Sopenharmony_ci if (vfl->vlan_id[i] >= VLAN_N_VID) { 226262306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 226362306a36Sopenharmony_ci dev_err(dev, "invalid VF VLAN id %d\n", 226462306a36Sopenharmony_ci vfl->vlan_id[i]); 226562306a36Sopenharmony_ci goto error_param; 226662306a36Sopenharmony_ci } 226762306a36Sopenharmony_ci } 226862306a36Sopenharmony_ci 226962306a36Sopenharmony_ci vsi = ice_get_vf_vsi(vf); 227062306a36Sopenharmony_ci if (!vsi) { 227162306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 227262306a36Sopenharmony_ci goto error_param; 227362306a36Sopenharmony_ci } 227462306a36Sopenharmony_ci 227562306a36Sopenharmony_ci if (add_v && ice_vf_has_max_vlans(vf, vsi)) { 227662306a36Sopenharmony_ci dev_info(dev, "VF-%d is not trusted, switch the VF to trusted mode, in order to add more VLAN addresses\n", 227762306a36Sopenharmony_ci vf->vf_id); 227862306a36Sopenharmony_ci /* There is no need to let VF know about being not trusted, 227962306a36Sopenharmony_ci * so we can just return success message here 228062306a36Sopenharmony_ci */ 228162306a36Sopenharmony_ci goto error_param; 228262306a36Sopenharmony_ci } 228362306a36Sopenharmony_ci 228462306a36Sopenharmony_ci /* in DVM a VF can add/delete inner VLAN filters when 228562306a36Sopenharmony_ci * VIRTCHNL_VF_OFFLOAD_VLAN is negotiated, so only reject in SVM 228662306a36Sopenharmony_ci */ 228762306a36Sopenharmony_ci if (ice_vf_is_port_vlan_ena(vf) && !ice_is_dvm_ena(&pf->hw)) { 228862306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 228962306a36Sopenharmony_ci goto error_param; 229062306a36Sopenharmony_ci } 229162306a36Sopenharmony_ci 229262306a36Sopenharmony_ci /* in DVM VLAN promiscuous is based on the outer VLAN, which would be 229362306a36Sopenharmony_ci * the port VLAN if VIRTCHNL_VF_OFFLOAD_VLAN was negotiated, so only 229462306a36Sopenharmony_ci * allow vlan_promisc = true in SVM and if no port VLAN is configured 229562306a36Sopenharmony_ci */ 229662306a36Sopenharmony_ci vlan_promisc = ice_is_vlan_promisc_allowed(vf) && 229762306a36Sopenharmony_ci !ice_is_dvm_ena(&pf->hw) && 229862306a36Sopenharmony_ci !ice_vf_is_port_vlan_ena(vf); 229962306a36Sopenharmony_ci 230062306a36Sopenharmony_ci if (add_v) { 230162306a36Sopenharmony_ci for (i = 0; i < vfl->num_elements; i++) { 230262306a36Sopenharmony_ci u16 vid = vfl->vlan_id[i]; 230362306a36Sopenharmony_ci struct ice_vlan vlan; 230462306a36Sopenharmony_ci 230562306a36Sopenharmony_ci if (ice_vf_has_max_vlans(vf, vsi)) { 230662306a36Sopenharmony_ci dev_info(dev, "VF-%d is not trusted, switch the VF to trusted mode, in order to add more VLAN addresses\n", 230762306a36Sopenharmony_ci vf->vf_id); 230862306a36Sopenharmony_ci /* There is no need to let VF know about being 230962306a36Sopenharmony_ci * not trusted, so we can just return success 231062306a36Sopenharmony_ci * message here as well. 231162306a36Sopenharmony_ci */ 231262306a36Sopenharmony_ci goto error_param; 231362306a36Sopenharmony_ci } 231462306a36Sopenharmony_ci 231562306a36Sopenharmony_ci /* we add VLAN 0 by default for each VF so we can enable 231662306a36Sopenharmony_ci * Tx VLAN anti-spoof without triggering MDD events so 231762306a36Sopenharmony_ci * we don't need to add it again here 231862306a36Sopenharmony_ci */ 231962306a36Sopenharmony_ci if (!vid) 232062306a36Sopenharmony_ci continue; 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_ci vlan = ICE_VLAN(ETH_P_8021Q, vid, 0); 232362306a36Sopenharmony_ci status = vsi->inner_vlan_ops.add_vlan(vsi, &vlan); 232462306a36Sopenharmony_ci if (status) { 232562306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 232662306a36Sopenharmony_ci goto error_param; 232762306a36Sopenharmony_ci } 232862306a36Sopenharmony_ci 232962306a36Sopenharmony_ci /* Enable VLAN filtering on first non-zero VLAN */ 233062306a36Sopenharmony_ci if (!vlan_promisc && vid && !ice_is_dvm_ena(&pf->hw)) { 233162306a36Sopenharmony_ci if (vf->spoofchk) { 233262306a36Sopenharmony_ci status = vsi->inner_vlan_ops.ena_tx_filtering(vsi); 233362306a36Sopenharmony_ci if (status) { 233462306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 233562306a36Sopenharmony_ci dev_err(dev, "Enable VLAN anti-spoofing on VLAN ID: %d failed error-%d\n", 233662306a36Sopenharmony_ci vid, status); 233762306a36Sopenharmony_ci goto error_param; 233862306a36Sopenharmony_ci } 233962306a36Sopenharmony_ci } 234062306a36Sopenharmony_ci if (vsi->inner_vlan_ops.ena_rx_filtering(vsi)) { 234162306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 234262306a36Sopenharmony_ci dev_err(dev, "Enable VLAN pruning on VLAN ID: %d failed error-%d\n", 234362306a36Sopenharmony_ci vid, status); 234462306a36Sopenharmony_ci goto error_param; 234562306a36Sopenharmony_ci } 234662306a36Sopenharmony_ci } else if (vlan_promisc) { 234762306a36Sopenharmony_ci status = ice_vf_ena_vlan_promisc(vsi, &vlan); 234862306a36Sopenharmony_ci if (status) { 234962306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 235062306a36Sopenharmony_ci dev_err(dev, "Enable Unicast/multicast promiscuous mode on VLAN ID:%d failed error-%d\n", 235162306a36Sopenharmony_ci vid, status); 235262306a36Sopenharmony_ci } 235362306a36Sopenharmony_ci } 235462306a36Sopenharmony_ci } 235562306a36Sopenharmony_ci } else { 235662306a36Sopenharmony_ci /* In case of non_trusted VF, number of VLAN elements passed 235762306a36Sopenharmony_ci * to PF for removal might be greater than number of VLANs 235862306a36Sopenharmony_ci * filter programmed for that VF - So, use actual number of 235962306a36Sopenharmony_ci * VLANS added earlier with add VLAN opcode. In order to avoid 236062306a36Sopenharmony_ci * removing VLAN that doesn't exist, which result to sending 236162306a36Sopenharmony_ci * erroneous failed message back to the VF 236262306a36Sopenharmony_ci */ 236362306a36Sopenharmony_ci int num_vf_vlan; 236462306a36Sopenharmony_ci 236562306a36Sopenharmony_ci num_vf_vlan = vsi->num_vlan; 236662306a36Sopenharmony_ci for (i = 0; i < vfl->num_elements && i < num_vf_vlan; i++) { 236762306a36Sopenharmony_ci u16 vid = vfl->vlan_id[i]; 236862306a36Sopenharmony_ci struct ice_vlan vlan; 236962306a36Sopenharmony_ci 237062306a36Sopenharmony_ci /* we add VLAN 0 by default for each VF so we can enable 237162306a36Sopenharmony_ci * Tx VLAN anti-spoof without triggering MDD events so 237262306a36Sopenharmony_ci * we don't want a VIRTCHNL request to remove it 237362306a36Sopenharmony_ci */ 237462306a36Sopenharmony_ci if (!vid) 237562306a36Sopenharmony_ci continue; 237662306a36Sopenharmony_ci 237762306a36Sopenharmony_ci vlan = ICE_VLAN(ETH_P_8021Q, vid, 0); 237862306a36Sopenharmony_ci status = vsi->inner_vlan_ops.del_vlan(vsi, &vlan); 237962306a36Sopenharmony_ci if (status) { 238062306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 238162306a36Sopenharmony_ci goto error_param; 238262306a36Sopenharmony_ci } 238362306a36Sopenharmony_ci 238462306a36Sopenharmony_ci /* Disable VLAN filtering when only VLAN 0 is left */ 238562306a36Sopenharmony_ci if (!ice_vsi_has_non_zero_vlans(vsi)) { 238662306a36Sopenharmony_ci vsi->inner_vlan_ops.dis_tx_filtering(vsi); 238762306a36Sopenharmony_ci vsi->inner_vlan_ops.dis_rx_filtering(vsi); 238862306a36Sopenharmony_ci } 238962306a36Sopenharmony_ci 239062306a36Sopenharmony_ci if (vlan_promisc) 239162306a36Sopenharmony_ci ice_vf_dis_vlan_promisc(vsi, &vlan); 239262306a36Sopenharmony_ci } 239362306a36Sopenharmony_ci } 239462306a36Sopenharmony_ci 239562306a36Sopenharmony_cierror_param: 239662306a36Sopenharmony_ci /* send the response to the VF */ 239762306a36Sopenharmony_ci if (add_v) 239862306a36Sopenharmony_ci return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ADD_VLAN, v_ret, 239962306a36Sopenharmony_ci NULL, 0); 240062306a36Sopenharmony_ci else 240162306a36Sopenharmony_ci return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DEL_VLAN, v_ret, 240262306a36Sopenharmony_ci NULL, 0); 240362306a36Sopenharmony_ci} 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_ci/** 240662306a36Sopenharmony_ci * ice_vc_add_vlan_msg 240762306a36Sopenharmony_ci * @vf: pointer to the VF info 240862306a36Sopenharmony_ci * @msg: pointer to the msg buffer 240962306a36Sopenharmony_ci * 241062306a36Sopenharmony_ci * Add and program guest VLAN ID 241162306a36Sopenharmony_ci */ 241262306a36Sopenharmony_cistatic int ice_vc_add_vlan_msg(struct ice_vf *vf, u8 *msg) 241362306a36Sopenharmony_ci{ 241462306a36Sopenharmony_ci return ice_vc_process_vlan_msg(vf, msg, true); 241562306a36Sopenharmony_ci} 241662306a36Sopenharmony_ci 241762306a36Sopenharmony_ci/** 241862306a36Sopenharmony_ci * ice_vc_remove_vlan_msg 241962306a36Sopenharmony_ci * @vf: pointer to the VF info 242062306a36Sopenharmony_ci * @msg: pointer to the msg buffer 242162306a36Sopenharmony_ci * 242262306a36Sopenharmony_ci * remove programmed guest VLAN ID 242362306a36Sopenharmony_ci */ 242462306a36Sopenharmony_cistatic int ice_vc_remove_vlan_msg(struct ice_vf *vf, u8 *msg) 242562306a36Sopenharmony_ci{ 242662306a36Sopenharmony_ci return ice_vc_process_vlan_msg(vf, msg, false); 242762306a36Sopenharmony_ci} 242862306a36Sopenharmony_ci 242962306a36Sopenharmony_ci/** 243062306a36Sopenharmony_ci * ice_vc_ena_vlan_stripping 243162306a36Sopenharmony_ci * @vf: pointer to the VF info 243262306a36Sopenharmony_ci * 243362306a36Sopenharmony_ci * Enable VLAN header stripping for a given VF 243462306a36Sopenharmony_ci */ 243562306a36Sopenharmony_cistatic int ice_vc_ena_vlan_stripping(struct ice_vf *vf) 243662306a36Sopenharmony_ci{ 243762306a36Sopenharmony_ci enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 243862306a36Sopenharmony_ci struct ice_vsi *vsi; 243962306a36Sopenharmony_ci 244062306a36Sopenharmony_ci if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { 244162306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 244262306a36Sopenharmony_ci goto error_param; 244362306a36Sopenharmony_ci } 244462306a36Sopenharmony_ci 244562306a36Sopenharmony_ci if (!ice_vf_vlan_offload_ena(vf->driver_caps)) { 244662306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 244762306a36Sopenharmony_ci goto error_param; 244862306a36Sopenharmony_ci } 244962306a36Sopenharmony_ci 245062306a36Sopenharmony_ci vsi = ice_get_vf_vsi(vf); 245162306a36Sopenharmony_ci if (!vsi) { 245262306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 245362306a36Sopenharmony_ci goto error_param; 245462306a36Sopenharmony_ci } 245562306a36Sopenharmony_ci 245662306a36Sopenharmony_ci if (vsi->inner_vlan_ops.ena_stripping(vsi, ETH_P_8021Q)) 245762306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 245862306a36Sopenharmony_ci 245962306a36Sopenharmony_cierror_param: 246062306a36Sopenharmony_ci return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ENABLE_VLAN_STRIPPING, 246162306a36Sopenharmony_ci v_ret, NULL, 0); 246262306a36Sopenharmony_ci} 246362306a36Sopenharmony_ci 246462306a36Sopenharmony_ci/** 246562306a36Sopenharmony_ci * ice_vc_dis_vlan_stripping 246662306a36Sopenharmony_ci * @vf: pointer to the VF info 246762306a36Sopenharmony_ci * 246862306a36Sopenharmony_ci * Disable VLAN header stripping for a given VF 246962306a36Sopenharmony_ci */ 247062306a36Sopenharmony_cistatic int ice_vc_dis_vlan_stripping(struct ice_vf *vf) 247162306a36Sopenharmony_ci{ 247262306a36Sopenharmony_ci enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 247362306a36Sopenharmony_ci struct ice_vsi *vsi; 247462306a36Sopenharmony_ci 247562306a36Sopenharmony_ci if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { 247662306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 247762306a36Sopenharmony_ci goto error_param; 247862306a36Sopenharmony_ci } 247962306a36Sopenharmony_ci 248062306a36Sopenharmony_ci if (!ice_vf_vlan_offload_ena(vf->driver_caps)) { 248162306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 248262306a36Sopenharmony_ci goto error_param; 248362306a36Sopenharmony_ci } 248462306a36Sopenharmony_ci 248562306a36Sopenharmony_ci vsi = ice_get_vf_vsi(vf); 248662306a36Sopenharmony_ci if (!vsi) { 248762306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 248862306a36Sopenharmony_ci goto error_param; 248962306a36Sopenharmony_ci } 249062306a36Sopenharmony_ci 249162306a36Sopenharmony_ci if (vsi->inner_vlan_ops.dis_stripping(vsi)) 249262306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 249362306a36Sopenharmony_ci 249462306a36Sopenharmony_cierror_param: 249562306a36Sopenharmony_ci return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DISABLE_VLAN_STRIPPING, 249662306a36Sopenharmony_ci v_ret, NULL, 0); 249762306a36Sopenharmony_ci} 249862306a36Sopenharmony_ci 249962306a36Sopenharmony_ci/** 250062306a36Sopenharmony_ci * ice_vc_get_rss_hena - return the RSS HENA bits allowed by the hardware 250162306a36Sopenharmony_ci * @vf: pointer to the VF info 250262306a36Sopenharmony_ci */ 250362306a36Sopenharmony_cistatic int ice_vc_get_rss_hena(struct ice_vf *vf) 250462306a36Sopenharmony_ci{ 250562306a36Sopenharmony_ci enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 250662306a36Sopenharmony_ci struct virtchnl_rss_hena *vrh = NULL; 250762306a36Sopenharmony_ci int len = 0, ret; 250862306a36Sopenharmony_ci 250962306a36Sopenharmony_ci if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { 251062306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 251162306a36Sopenharmony_ci goto err; 251262306a36Sopenharmony_ci } 251362306a36Sopenharmony_ci 251462306a36Sopenharmony_ci if (!test_bit(ICE_FLAG_RSS_ENA, vf->pf->flags)) { 251562306a36Sopenharmony_ci dev_err(ice_pf_to_dev(vf->pf), "RSS not supported by PF\n"); 251662306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 251762306a36Sopenharmony_ci goto err; 251862306a36Sopenharmony_ci } 251962306a36Sopenharmony_ci 252062306a36Sopenharmony_ci len = sizeof(struct virtchnl_rss_hena); 252162306a36Sopenharmony_ci vrh = kzalloc(len, GFP_KERNEL); 252262306a36Sopenharmony_ci if (!vrh) { 252362306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; 252462306a36Sopenharmony_ci len = 0; 252562306a36Sopenharmony_ci goto err; 252662306a36Sopenharmony_ci } 252762306a36Sopenharmony_ci 252862306a36Sopenharmony_ci vrh->hena = ICE_DEFAULT_RSS_HENA; 252962306a36Sopenharmony_cierr: 253062306a36Sopenharmony_ci /* send the response back to the VF */ 253162306a36Sopenharmony_ci ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_RSS_HENA_CAPS, v_ret, 253262306a36Sopenharmony_ci (u8 *)vrh, len); 253362306a36Sopenharmony_ci kfree(vrh); 253462306a36Sopenharmony_ci return ret; 253562306a36Sopenharmony_ci} 253662306a36Sopenharmony_ci 253762306a36Sopenharmony_ci/** 253862306a36Sopenharmony_ci * ice_vc_set_rss_hena - set RSS HENA bits for the VF 253962306a36Sopenharmony_ci * @vf: pointer to the VF info 254062306a36Sopenharmony_ci * @msg: pointer to the msg buffer 254162306a36Sopenharmony_ci */ 254262306a36Sopenharmony_cistatic int ice_vc_set_rss_hena(struct ice_vf *vf, u8 *msg) 254362306a36Sopenharmony_ci{ 254462306a36Sopenharmony_ci struct virtchnl_rss_hena *vrh = (struct virtchnl_rss_hena *)msg; 254562306a36Sopenharmony_ci enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 254662306a36Sopenharmony_ci struct ice_pf *pf = vf->pf; 254762306a36Sopenharmony_ci struct ice_vsi *vsi; 254862306a36Sopenharmony_ci struct device *dev; 254962306a36Sopenharmony_ci int status; 255062306a36Sopenharmony_ci 255162306a36Sopenharmony_ci dev = ice_pf_to_dev(pf); 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_ci if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { 255462306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 255562306a36Sopenharmony_ci goto err; 255662306a36Sopenharmony_ci } 255762306a36Sopenharmony_ci 255862306a36Sopenharmony_ci if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { 255962306a36Sopenharmony_ci dev_err(dev, "RSS not supported by PF\n"); 256062306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 256162306a36Sopenharmony_ci goto err; 256262306a36Sopenharmony_ci } 256362306a36Sopenharmony_ci 256462306a36Sopenharmony_ci vsi = ice_get_vf_vsi(vf); 256562306a36Sopenharmony_ci if (!vsi) { 256662306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 256762306a36Sopenharmony_ci goto err; 256862306a36Sopenharmony_ci } 256962306a36Sopenharmony_ci 257062306a36Sopenharmony_ci /* clear all previously programmed RSS configuration to allow VF drivers 257162306a36Sopenharmony_ci * the ability to customize the RSS configuration and/or completely 257262306a36Sopenharmony_ci * disable RSS 257362306a36Sopenharmony_ci */ 257462306a36Sopenharmony_ci status = ice_rem_vsi_rss_cfg(&pf->hw, vsi->idx); 257562306a36Sopenharmony_ci if (status && !vrh->hena) { 257662306a36Sopenharmony_ci /* only report failure to clear the current RSS configuration if 257762306a36Sopenharmony_ci * that was clearly the VF's intention (i.e. vrh->hena = 0) 257862306a36Sopenharmony_ci */ 257962306a36Sopenharmony_ci v_ret = ice_err_to_virt_err(status); 258062306a36Sopenharmony_ci goto err; 258162306a36Sopenharmony_ci } else if (status) { 258262306a36Sopenharmony_ci /* allow the VF to update the RSS configuration even on failure 258362306a36Sopenharmony_ci * to clear the current RSS confguration in an attempt to keep 258462306a36Sopenharmony_ci * RSS in a working state 258562306a36Sopenharmony_ci */ 258662306a36Sopenharmony_ci dev_warn(dev, "Failed to clear the RSS configuration for VF %u\n", 258762306a36Sopenharmony_ci vf->vf_id); 258862306a36Sopenharmony_ci } 258962306a36Sopenharmony_ci 259062306a36Sopenharmony_ci if (vrh->hena) { 259162306a36Sopenharmony_ci status = ice_add_avf_rss_cfg(&pf->hw, vsi->idx, vrh->hena); 259262306a36Sopenharmony_ci v_ret = ice_err_to_virt_err(status); 259362306a36Sopenharmony_ci } 259462306a36Sopenharmony_ci 259562306a36Sopenharmony_ci /* send the response to the VF */ 259662306a36Sopenharmony_cierr: 259762306a36Sopenharmony_ci return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_SET_RSS_HENA, v_ret, 259862306a36Sopenharmony_ci NULL, 0); 259962306a36Sopenharmony_ci} 260062306a36Sopenharmony_ci 260162306a36Sopenharmony_ci/** 260262306a36Sopenharmony_ci * ice_vc_query_rxdid - query RXDID supported by DDP package 260362306a36Sopenharmony_ci * @vf: pointer to VF info 260462306a36Sopenharmony_ci * 260562306a36Sopenharmony_ci * Called from VF to query a bitmap of supported flexible 260662306a36Sopenharmony_ci * descriptor RXDIDs of a DDP package. 260762306a36Sopenharmony_ci */ 260862306a36Sopenharmony_cistatic int ice_vc_query_rxdid(struct ice_vf *vf) 260962306a36Sopenharmony_ci{ 261062306a36Sopenharmony_ci enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 261162306a36Sopenharmony_ci struct virtchnl_supported_rxdids *rxdid = NULL; 261262306a36Sopenharmony_ci struct ice_hw *hw = &vf->pf->hw; 261362306a36Sopenharmony_ci struct ice_pf *pf = vf->pf; 261462306a36Sopenharmony_ci int len = 0; 261562306a36Sopenharmony_ci int ret, i; 261662306a36Sopenharmony_ci u32 regval; 261762306a36Sopenharmony_ci 261862306a36Sopenharmony_ci if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { 261962306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 262062306a36Sopenharmony_ci goto err; 262162306a36Sopenharmony_ci } 262262306a36Sopenharmony_ci 262362306a36Sopenharmony_ci if (!(vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC)) { 262462306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 262562306a36Sopenharmony_ci goto err; 262662306a36Sopenharmony_ci } 262762306a36Sopenharmony_ci 262862306a36Sopenharmony_ci len = sizeof(struct virtchnl_supported_rxdids); 262962306a36Sopenharmony_ci rxdid = kzalloc(len, GFP_KERNEL); 263062306a36Sopenharmony_ci if (!rxdid) { 263162306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; 263262306a36Sopenharmony_ci len = 0; 263362306a36Sopenharmony_ci goto err; 263462306a36Sopenharmony_ci } 263562306a36Sopenharmony_ci 263662306a36Sopenharmony_ci /* RXDIDs supported by DDP package can be read from the register 263762306a36Sopenharmony_ci * to get the supported RXDID bitmap. But the legacy 32byte RXDID 263862306a36Sopenharmony_ci * is not listed in DDP package, add it in the bitmap manually. 263962306a36Sopenharmony_ci * Legacy 16byte descriptor is not supported. 264062306a36Sopenharmony_ci */ 264162306a36Sopenharmony_ci rxdid->supported_rxdids |= BIT(ICE_RXDID_LEGACY_1); 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_ci for (i = ICE_RXDID_FLEX_NIC; i < ICE_FLEX_DESC_RXDID_MAX_NUM; i++) { 264462306a36Sopenharmony_ci regval = rd32(hw, GLFLXP_RXDID_FLAGS(i, 0)); 264562306a36Sopenharmony_ci if ((regval >> GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_S) 264662306a36Sopenharmony_ci & GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_M) 264762306a36Sopenharmony_ci rxdid->supported_rxdids |= BIT(i); 264862306a36Sopenharmony_ci } 264962306a36Sopenharmony_ci 265062306a36Sopenharmony_ci pf->supported_rxdids = rxdid->supported_rxdids; 265162306a36Sopenharmony_ci 265262306a36Sopenharmony_cierr: 265362306a36Sopenharmony_ci ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_SUPPORTED_RXDIDS, 265462306a36Sopenharmony_ci v_ret, (u8 *)rxdid, len); 265562306a36Sopenharmony_ci kfree(rxdid); 265662306a36Sopenharmony_ci return ret; 265762306a36Sopenharmony_ci} 265862306a36Sopenharmony_ci 265962306a36Sopenharmony_ci/** 266062306a36Sopenharmony_ci * ice_vf_init_vlan_stripping - enable/disable VLAN stripping on initialization 266162306a36Sopenharmony_ci * @vf: VF to enable/disable VLAN stripping for on initialization 266262306a36Sopenharmony_ci * 266362306a36Sopenharmony_ci * Set the default for VLAN stripping based on whether a port VLAN is configured 266462306a36Sopenharmony_ci * and the current VLAN mode of the device. 266562306a36Sopenharmony_ci */ 266662306a36Sopenharmony_cistatic int ice_vf_init_vlan_stripping(struct ice_vf *vf) 266762306a36Sopenharmony_ci{ 266862306a36Sopenharmony_ci struct ice_vsi *vsi = ice_get_vf_vsi(vf); 266962306a36Sopenharmony_ci 267062306a36Sopenharmony_ci if (!vsi) 267162306a36Sopenharmony_ci return -EINVAL; 267262306a36Sopenharmony_ci 267362306a36Sopenharmony_ci /* don't modify stripping if port VLAN is configured in SVM since the 267462306a36Sopenharmony_ci * port VLAN is based on the inner/single VLAN in SVM 267562306a36Sopenharmony_ci */ 267662306a36Sopenharmony_ci if (ice_vf_is_port_vlan_ena(vf) && !ice_is_dvm_ena(&vsi->back->hw)) 267762306a36Sopenharmony_ci return 0; 267862306a36Sopenharmony_ci 267962306a36Sopenharmony_ci if (ice_vf_vlan_offload_ena(vf->driver_caps)) 268062306a36Sopenharmony_ci return vsi->inner_vlan_ops.ena_stripping(vsi, ETH_P_8021Q); 268162306a36Sopenharmony_ci else 268262306a36Sopenharmony_ci return vsi->inner_vlan_ops.dis_stripping(vsi); 268362306a36Sopenharmony_ci} 268462306a36Sopenharmony_ci 268562306a36Sopenharmony_cistatic u16 ice_vc_get_max_vlan_fltrs(struct ice_vf *vf) 268662306a36Sopenharmony_ci{ 268762306a36Sopenharmony_ci if (vf->trusted) 268862306a36Sopenharmony_ci return VLAN_N_VID; 268962306a36Sopenharmony_ci else 269062306a36Sopenharmony_ci return ICE_MAX_VLAN_PER_VF; 269162306a36Sopenharmony_ci} 269262306a36Sopenharmony_ci 269362306a36Sopenharmony_ci/** 269462306a36Sopenharmony_ci * ice_vf_outer_vlan_not_allowed - check if outer VLAN can be used 269562306a36Sopenharmony_ci * @vf: VF that being checked for 269662306a36Sopenharmony_ci * 269762306a36Sopenharmony_ci * When the device is in double VLAN mode, check whether or not the outer VLAN 269862306a36Sopenharmony_ci * is allowed. 269962306a36Sopenharmony_ci */ 270062306a36Sopenharmony_cistatic bool ice_vf_outer_vlan_not_allowed(struct ice_vf *vf) 270162306a36Sopenharmony_ci{ 270262306a36Sopenharmony_ci if (ice_vf_is_port_vlan_ena(vf)) 270362306a36Sopenharmony_ci return true; 270462306a36Sopenharmony_ci 270562306a36Sopenharmony_ci return false; 270662306a36Sopenharmony_ci} 270762306a36Sopenharmony_ci 270862306a36Sopenharmony_ci/** 270962306a36Sopenharmony_ci * ice_vc_set_dvm_caps - set VLAN capabilities when the device is in DVM 271062306a36Sopenharmony_ci * @vf: VF that capabilities are being set for 271162306a36Sopenharmony_ci * @caps: VLAN capabilities to populate 271262306a36Sopenharmony_ci * 271362306a36Sopenharmony_ci * Determine VLAN capabilities support based on whether a port VLAN is 271462306a36Sopenharmony_ci * configured. If a port VLAN is configured then the VF should use the inner 271562306a36Sopenharmony_ci * filtering/offload capabilities since the port VLAN is using the outer VLAN 271662306a36Sopenharmony_ci * capabilies. 271762306a36Sopenharmony_ci */ 271862306a36Sopenharmony_cistatic void 271962306a36Sopenharmony_ciice_vc_set_dvm_caps(struct ice_vf *vf, struct virtchnl_vlan_caps *caps) 272062306a36Sopenharmony_ci{ 272162306a36Sopenharmony_ci struct virtchnl_vlan_supported_caps *supported_caps; 272262306a36Sopenharmony_ci 272362306a36Sopenharmony_ci if (ice_vf_outer_vlan_not_allowed(vf)) { 272462306a36Sopenharmony_ci /* until support for inner VLAN filtering is added when a port 272562306a36Sopenharmony_ci * VLAN is configured, only support software offloaded inner 272662306a36Sopenharmony_ci * VLANs when a port VLAN is confgured in DVM 272762306a36Sopenharmony_ci */ 272862306a36Sopenharmony_ci supported_caps = &caps->filtering.filtering_support; 272962306a36Sopenharmony_ci supported_caps->inner = VIRTCHNL_VLAN_UNSUPPORTED; 273062306a36Sopenharmony_ci 273162306a36Sopenharmony_ci supported_caps = &caps->offloads.stripping_support; 273262306a36Sopenharmony_ci supported_caps->inner = VIRTCHNL_VLAN_ETHERTYPE_8100 | 273362306a36Sopenharmony_ci VIRTCHNL_VLAN_TOGGLE | 273462306a36Sopenharmony_ci VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1; 273562306a36Sopenharmony_ci supported_caps->outer = VIRTCHNL_VLAN_UNSUPPORTED; 273662306a36Sopenharmony_ci 273762306a36Sopenharmony_ci supported_caps = &caps->offloads.insertion_support; 273862306a36Sopenharmony_ci supported_caps->inner = VIRTCHNL_VLAN_ETHERTYPE_8100 | 273962306a36Sopenharmony_ci VIRTCHNL_VLAN_TOGGLE | 274062306a36Sopenharmony_ci VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1; 274162306a36Sopenharmony_ci supported_caps->outer = VIRTCHNL_VLAN_UNSUPPORTED; 274262306a36Sopenharmony_ci 274362306a36Sopenharmony_ci caps->offloads.ethertype_init = VIRTCHNL_VLAN_ETHERTYPE_8100; 274462306a36Sopenharmony_ci caps->offloads.ethertype_match = 274562306a36Sopenharmony_ci VIRTCHNL_ETHERTYPE_STRIPPING_MATCHES_INSERTION; 274662306a36Sopenharmony_ci } else { 274762306a36Sopenharmony_ci supported_caps = &caps->filtering.filtering_support; 274862306a36Sopenharmony_ci supported_caps->inner = VIRTCHNL_VLAN_UNSUPPORTED; 274962306a36Sopenharmony_ci supported_caps->outer = VIRTCHNL_VLAN_ETHERTYPE_8100 | 275062306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_88A8 | 275162306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_9100 | 275262306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_AND; 275362306a36Sopenharmony_ci caps->filtering.ethertype_init = VIRTCHNL_VLAN_ETHERTYPE_8100 | 275462306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_88A8 | 275562306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_9100; 275662306a36Sopenharmony_ci 275762306a36Sopenharmony_ci supported_caps = &caps->offloads.stripping_support; 275862306a36Sopenharmony_ci supported_caps->inner = VIRTCHNL_VLAN_TOGGLE | 275962306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_8100 | 276062306a36Sopenharmony_ci VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1; 276162306a36Sopenharmony_ci supported_caps->outer = VIRTCHNL_VLAN_TOGGLE | 276262306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_8100 | 276362306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_88A8 | 276462306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_9100 | 276562306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_XOR | 276662306a36Sopenharmony_ci VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2_2; 276762306a36Sopenharmony_ci 276862306a36Sopenharmony_ci supported_caps = &caps->offloads.insertion_support; 276962306a36Sopenharmony_ci supported_caps->inner = VIRTCHNL_VLAN_TOGGLE | 277062306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_8100 | 277162306a36Sopenharmony_ci VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1; 277262306a36Sopenharmony_ci supported_caps->outer = VIRTCHNL_VLAN_TOGGLE | 277362306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_8100 | 277462306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_88A8 | 277562306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_9100 | 277662306a36Sopenharmony_ci VIRTCHNL_VLAN_ETHERTYPE_XOR | 277762306a36Sopenharmony_ci VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2; 277862306a36Sopenharmony_ci 277962306a36Sopenharmony_ci caps->offloads.ethertype_init = VIRTCHNL_VLAN_ETHERTYPE_8100; 278062306a36Sopenharmony_ci 278162306a36Sopenharmony_ci caps->offloads.ethertype_match = 278262306a36Sopenharmony_ci VIRTCHNL_ETHERTYPE_STRIPPING_MATCHES_INSERTION; 278362306a36Sopenharmony_ci } 278462306a36Sopenharmony_ci 278562306a36Sopenharmony_ci caps->filtering.max_filters = ice_vc_get_max_vlan_fltrs(vf); 278662306a36Sopenharmony_ci} 278762306a36Sopenharmony_ci 278862306a36Sopenharmony_ci/** 278962306a36Sopenharmony_ci * ice_vc_set_svm_caps - set VLAN capabilities when the device is in SVM 279062306a36Sopenharmony_ci * @vf: VF that capabilities are being set for 279162306a36Sopenharmony_ci * @caps: VLAN capabilities to populate 279262306a36Sopenharmony_ci * 279362306a36Sopenharmony_ci * Determine VLAN capabilities support based on whether a port VLAN is 279462306a36Sopenharmony_ci * configured. If a port VLAN is configured then the VF does not have any VLAN 279562306a36Sopenharmony_ci * filtering or offload capabilities since the port VLAN is using the inner VLAN 279662306a36Sopenharmony_ci * capabilities in single VLAN mode (SVM). Otherwise allow the VF to use inner 279762306a36Sopenharmony_ci * VLAN fitlering and offload capabilities. 279862306a36Sopenharmony_ci */ 279962306a36Sopenharmony_cistatic void 280062306a36Sopenharmony_ciice_vc_set_svm_caps(struct ice_vf *vf, struct virtchnl_vlan_caps *caps) 280162306a36Sopenharmony_ci{ 280262306a36Sopenharmony_ci struct virtchnl_vlan_supported_caps *supported_caps; 280362306a36Sopenharmony_ci 280462306a36Sopenharmony_ci if (ice_vf_is_port_vlan_ena(vf)) { 280562306a36Sopenharmony_ci supported_caps = &caps->filtering.filtering_support; 280662306a36Sopenharmony_ci supported_caps->inner = VIRTCHNL_VLAN_UNSUPPORTED; 280762306a36Sopenharmony_ci supported_caps->outer = VIRTCHNL_VLAN_UNSUPPORTED; 280862306a36Sopenharmony_ci 280962306a36Sopenharmony_ci supported_caps = &caps->offloads.stripping_support; 281062306a36Sopenharmony_ci supported_caps->inner = VIRTCHNL_VLAN_UNSUPPORTED; 281162306a36Sopenharmony_ci supported_caps->outer = VIRTCHNL_VLAN_UNSUPPORTED; 281262306a36Sopenharmony_ci 281362306a36Sopenharmony_ci supported_caps = &caps->offloads.insertion_support; 281462306a36Sopenharmony_ci supported_caps->inner = VIRTCHNL_VLAN_UNSUPPORTED; 281562306a36Sopenharmony_ci supported_caps->outer = VIRTCHNL_VLAN_UNSUPPORTED; 281662306a36Sopenharmony_ci 281762306a36Sopenharmony_ci caps->offloads.ethertype_init = VIRTCHNL_VLAN_UNSUPPORTED; 281862306a36Sopenharmony_ci caps->offloads.ethertype_match = VIRTCHNL_VLAN_UNSUPPORTED; 281962306a36Sopenharmony_ci caps->filtering.max_filters = 0; 282062306a36Sopenharmony_ci } else { 282162306a36Sopenharmony_ci supported_caps = &caps->filtering.filtering_support; 282262306a36Sopenharmony_ci supported_caps->inner = VIRTCHNL_VLAN_ETHERTYPE_8100; 282362306a36Sopenharmony_ci supported_caps->outer = VIRTCHNL_VLAN_UNSUPPORTED; 282462306a36Sopenharmony_ci caps->filtering.ethertype_init = VIRTCHNL_VLAN_ETHERTYPE_8100; 282562306a36Sopenharmony_ci 282662306a36Sopenharmony_ci supported_caps = &caps->offloads.stripping_support; 282762306a36Sopenharmony_ci supported_caps->inner = VIRTCHNL_VLAN_ETHERTYPE_8100 | 282862306a36Sopenharmony_ci VIRTCHNL_VLAN_TOGGLE | 282962306a36Sopenharmony_ci VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1; 283062306a36Sopenharmony_ci supported_caps->outer = VIRTCHNL_VLAN_UNSUPPORTED; 283162306a36Sopenharmony_ci 283262306a36Sopenharmony_ci supported_caps = &caps->offloads.insertion_support; 283362306a36Sopenharmony_ci supported_caps->inner = VIRTCHNL_VLAN_ETHERTYPE_8100 | 283462306a36Sopenharmony_ci VIRTCHNL_VLAN_TOGGLE | 283562306a36Sopenharmony_ci VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1; 283662306a36Sopenharmony_ci supported_caps->outer = VIRTCHNL_VLAN_UNSUPPORTED; 283762306a36Sopenharmony_ci 283862306a36Sopenharmony_ci caps->offloads.ethertype_init = VIRTCHNL_VLAN_ETHERTYPE_8100; 283962306a36Sopenharmony_ci caps->offloads.ethertype_match = 284062306a36Sopenharmony_ci VIRTCHNL_ETHERTYPE_STRIPPING_MATCHES_INSERTION; 284162306a36Sopenharmony_ci caps->filtering.max_filters = ice_vc_get_max_vlan_fltrs(vf); 284262306a36Sopenharmony_ci } 284362306a36Sopenharmony_ci} 284462306a36Sopenharmony_ci 284562306a36Sopenharmony_ci/** 284662306a36Sopenharmony_ci * ice_vc_get_offload_vlan_v2_caps - determine VF's VLAN capabilities 284762306a36Sopenharmony_ci * @vf: VF to determine VLAN capabilities for 284862306a36Sopenharmony_ci * 284962306a36Sopenharmony_ci * This will only be called if the VF and PF successfully negotiated 285062306a36Sopenharmony_ci * VIRTCHNL_VF_OFFLOAD_VLAN_V2. 285162306a36Sopenharmony_ci * 285262306a36Sopenharmony_ci * Set VLAN capabilities based on the current VLAN mode and whether a port VLAN 285362306a36Sopenharmony_ci * is configured or not. 285462306a36Sopenharmony_ci */ 285562306a36Sopenharmony_cistatic int ice_vc_get_offload_vlan_v2_caps(struct ice_vf *vf) 285662306a36Sopenharmony_ci{ 285762306a36Sopenharmony_ci enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 285862306a36Sopenharmony_ci struct virtchnl_vlan_caps *caps = NULL; 285962306a36Sopenharmony_ci int err, len = 0; 286062306a36Sopenharmony_ci 286162306a36Sopenharmony_ci if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { 286262306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 286362306a36Sopenharmony_ci goto out; 286462306a36Sopenharmony_ci } 286562306a36Sopenharmony_ci 286662306a36Sopenharmony_ci caps = kzalloc(sizeof(*caps), GFP_KERNEL); 286762306a36Sopenharmony_ci if (!caps) { 286862306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; 286962306a36Sopenharmony_ci goto out; 287062306a36Sopenharmony_ci } 287162306a36Sopenharmony_ci len = sizeof(*caps); 287262306a36Sopenharmony_ci 287362306a36Sopenharmony_ci if (ice_is_dvm_ena(&vf->pf->hw)) 287462306a36Sopenharmony_ci ice_vc_set_dvm_caps(vf, caps); 287562306a36Sopenharmony_ci else 287662306a36Sopenharmony_ci ice_vc_set_svm_caps(vf, caps); 287762306a36Sopenharmony_ci 287862306a36Sopenharmony_ci /* store negotiated caps to prevent invalid VF messages */ 287962306a36Sopenharmony_ci memcpy(&vf->vlan_v2_caps, caps, sizeof(*caps)); 288062306a36Sopenharmony_ci 288162306a36Sopenharmony_ciout: 288262306a36Sopenharmony_ci err = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS, 288362306a36Sopenharmony_ci v_ret, (u8 *)caps, len); 288462306a36Sopenharmony_ci kfree(caps); 288562306a36Sopenharmony_ci return err; 288662306a36Sopenharmony_ci} 288762306a36Sopenharmony_ci 288862306a36Sopenharmony_ci/** 288962306a36Sopenharmony_ci * ice_vc_validate_vlan_tpid - validate VLAN TPID 289062306a36Sopenharmony_ci * @filtering_caps: negotiated/supported VLAN filtering capabilities 289162306a36Sopenharmony_ci * @tpid: VLAN TPID used for validation 289262306a36Sopenharmony_ci * 289362306a36Sopenharmony_ci * Convert the VLAN TPID to a VIRTCHNL_VLAN_ETHERTYPE_* and then compare against 289462306a36Sopenharmony_ci * the negotiated/supported filtering caps to see if the VLAN TPID is valid. 289562306a36Sopenharmony_ci */ 289662306a36Sopenharmony_cistatic bool ice_vc_validate_vlan_tpid(u16 filtering_caps, u16 tpid) 289762306a36Sopenharmony_ci{ 289862306a36Sopenharmony_ci enum virtchnl_vlan_support vlan_ethertype = VIRTCHNL_VLAN_UNSUPPORTED; 289962306a36Sopenharmony_ci 290062306a36Sopenharmony_ci switch (tpid) { 290162306a36Sopenharmony_ci case ETH_P_8021Q: 290262306a36Sopenharmony_ci vlan_ethertype = VIRTCHNL_VLAN_ETHERTYPE_8100; 290362306a36Sopenharmony_ci break; 290462306a36Sopenharmony_ci case ETH_P_8021AD: 290562306a36Sopenharmony_ci vlan_ethertype = VIRTCHNL_VLAN_ETHERTYPE_88A8; 290662306a36Sopenharmony_ci break; 290762306a36Sopenharmony_ci case ETH_P_QINQ1: 290862306a36Sopenharmony_ci vlan_ethertype = VIRTCHNL_VLAN_ETHERTYPE_9100; 290962306a36Sopenharmony_ci break; 291062306a36Sopenharmony_ci } 291162306a36Sopenharmony_ci 291262306a36Sopenharmony_ci if (!(filtering_caps & vlan_ethertype)) 291362306a36Sopenharmony_ci return false; 291462306a36Sopenharmony_ci 291562306a36Sopenharmony_ci return true; 291662306a36Sopenharmony_ci} 291762306a36Sopenharmony_ci 291862306a36Sopenharmony_ci/** 291962306a36Sopenharmony_ci * ice_vc_is_valid_vlan - validate the virtchnl_vlan 292062306a36Sopenharmony_ci * @vc_vlan: virtchnl_vlan to validate 292162306a36Sopenharmony_ci * 292262306a36Sopenharmony_ci * If the VLAN TCI and VLAN TPID are 0, then this filter is invalid, so return 292362306a36Sopenharmony_ci * false. Otherwise return true. 292462306a36Sopenharmony_ci */ 292562306a36Sopenharmony_cistatic bool ice_vc_is_valid_vlan(struct virtchnl_vlan *vc_vlan) 292662306a36Sopenharmony_ci{ 292762306a36Sopenharmony_ci if (!vc_vlan->tci || !vc_vlan->tpid) 292862306a36Sopenharmony_ci return false; 292962306a36Sopenharmony_ci 293062306a36Sopenharmony_ci return true; 293162306a36Sopenharmony_ci} 293262306a36Sopenharmony_ci 293362306a36Sopenharmony_ci/** 293462306a36Sopenharmony_ci * ice_vc_validate_vlan_filter_list - validate the filter list from the VF 293562306a36Sopenharmony_ci * @vfc: negotiated/supported VLAN filtering capabilities 293662306a36Sopenharmony_ci * @vfl: VLAN filter list from VF to validate 293762306a36Sopenharmony_ci * 293862306a36Sopenharmony_ci * Validate all of the filters in the VLAN filter list from the VF. If any of 293962306a36Sopenharmony_ci * the checks fail then return false. Otherwise return true. 294062306a36Sopenharmony_ci */ 294162306a36Sopenharmony_cistatic bool 294262306a36Sopenharmony_ciice_vc_validate_vlan_filter_list(struct virtchnl_vlan_filtering_caps *vfc, 294362306a36Sopenharmony_ci struct virtchnl_vlan_filter_list_v2 *vfl) 294462306a36Sopenharmony_ci{ 294562306a36Sopenharmony_ci u16 i; 294662306a36Sopenharmony_ci 294762306a36Sopenharmony_ci if (!vfl->num_elements) 294862306a36Sopenharmony_ci return false; 294962306a36Sopenharmony_ci 295062306a36Sopenharmony_ci for (i = 0; i < vfl->num_elements; i++) { 295162306a36Sopenharmony_ci struct virtchnl_vlan_supported_caps *filtering_support = 295262306a36Sopenharmony_ci &vfc->filtering_support; 295362306a36Sopenharmony_ci struct virtchnl_vlan_filter *vlan_fltr = &vfl->filters[i]; 295462306a36Sopenharmony_ci struct virtchnl_vlan *outer = &vlan_fltr->outer; 295562306a36Sopenharmony_ci struct virtchnl_vlan *inner = &vlan_fltr->inner; 295662306a36Sopenharmony_ci 295762306a36Sopenharmony_ci if ((ice_vc_is_valid_vlan(outer) && 295862306a36Sopenharmony_ci filtering_support->outer == VIRTCHNL_VLAN_UNSUPPORTED) || 295962306a36Sopenharmony_ci (ice_vc_is_valid_vlan(inner) && 296062306a36Sopenharmony_ci filtering_support->inner == VIRTCHNL_VLAN_UNSUPPORTED)) 296162306a36Sopenharmony_ci return false; 296262306a36Sopenharmony_ci 296362306a36Sopenharmony_ci if ((outer->tci_mask && 296462306a36Sopenharmony_ci !(filtering_support->outer & VIRTCHNL_VLAN_FILTER_MASK)) || 296562306a36Sopenharmony_ci (inner->tci_mask && 296662306a36Sopenharmony_ci !(filtering_support->inner & VIRTCHNL_VLAN_FILTER_MASK))) 296762306a36Sopenharmony_ci return false; 296862306a36Sopenharmony_ci 296962306a36Sopenharmony_ci if (((outer->tci & VLAN_PRIO_MASK) && 297062306a36Sopenharmony_ci !(filtering_support->outer & VIRTCHNL_VLAN_PRIO)) || 297162306a36Sopenharmony_ci ((inner->tci & VLAN_PRIO_MASK) && 297262306a36Sopenharmony_ci !(filtering_support->inner & VIRTCHNL_VLAN_PRIO))) 297362306a36Sopenharmony_ci return false; 297462306a36Sopenharmony_ci 297562306a36Sopenharmony_ci if ((ice_vc_is_valid_vlan(outer) && 297662306a36Sopenharmony_ci !ice_vc_validate_vlan_tpid(filtering_support->outer, 297762306a36Sopenharmony_ci outer->tpid)) || 297862306a36Sopenharmony_ci (ice_vc_is_valid_vlan(inner) && 297962306a36Sopenharmony_ci !ice_vc_validate_vlan_tpid(filtering_support->inner, 298062306a36Sopenharmony_ci inner->tpid))) 298162306a36Sopenharmony_ci return false; 298262306a36Sopenharmony_ci } 298362306a36Sopenharmony_ci 298462306a36Sopenharmony_ci return true; 298562306a36Sopenharmony_ci} 298662306a36Sopenharmony_ci 298762306a36Sopenharmony_ci/** 298862306a36Sopenharmony_ci * ice_vc_to_vlan - transform from struct virtchnl_vlan to struct ice_vlan 298962306a36Sopenharmony_ci * @vc_vlan: struct virtchnl_vlan to transform 299062306a36Sopenharmony_ci */ 299162306a36Sopenharmony_cistatic struct ice_vlan ice_vc_to_vlan(struct virtchnl_vlan *vc_vlan) 299262306a36Sopenharmony_ci{ 299362306a36Sopenharmony_ci struct ice_vlan vlan = { 0 }; 299462306a36Sopenharmony_ci 299562306a36Sopenharmony_ci vlan.prio = (vc_vlan->tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; 299662306a36Sopenharmony_ci vlan.vid = vc_vlan->tci & VLAN_VID_MASK; 299762306a36Sopenharmony_ci vlan.tpid = vc_vlan->tpid; 299862306a36Sopenharmony_ci 299962306a36Sopenharmony_ci return vlan; 300062306a36Sopenharmony_ci} 300162306a36Sopenharmony_ci 300262306a36Sopenharmony_ci/** 300362306a36Sopenharmony_ci * ice_vc_vlan_action - action to perform on the virthcnl_vlan 300462306a36Sopenharmony_ci * @vsi: VF's VSI used to perform the action 300562306a36Sopenharmony_ci * @vlan_action: function to perform the action with (i.e. add/del) 300662306a36Sopenharmony_ci * @vlan: VLAN filter to perform the action with 300762306a36Sopenharmony_ci */ 300862306a36Sopenharmony_cistatic int 300962306a36Sopenharmony_ciice_vc_vlan_action(struct ice_vsi *vsi, 301062306a36Sopenharmony_ci int (*vlan_action)(struct ice_vsi *, struct ice_vlan *), 301162306a36Sopenharmony_ci struct ice_vlan *vlan) 301262306a36Sopenharmony_ci{ 301362306a36Sopenharmony_ci int err; 301462306a36Sopenharmony_ci 301562306a36Sopenharmony_ci err = vlan_action(vsi, vlan); 301662306a36Sopenharmony_ci if (err) 301762306a36Sopenharmony_ci return err; 301862306a36Sopenharmony_ci 301962306a36Sopenharmony_ci return 0; 302062306a36Sopenharmony_ci} 302162306a36Sopenharmony_ci 302262306a36Sopenharmony_ci/** 302362306a36Sopenharmony_ci * ice_vc_del_vlans - delete VLAN(s) from the virtchnl filter list 302462306a36Sopenharmony_ci * @vf: VF used to delete the VLAN(s) 302562306a36Sopenharmony_ci * @vsi: VF's VSI used to delete the VLAN(s) 302662306a36Sopenharmony_ci * @vfl: virthchnl filter list used to delete the filters 302762306a36Sopenharmony_ci */ 302862306a36Sopenharmony_cistatic int 302962306a36Sopenharmony_ciice_vc_del_vlans(struct ice_vf *vf, struct ice_vsi *vsi, 303062306a36Sopenharmony_ci struct virtchnl_vlan_filter_list_v2 *vfl) 303162306a36Sopenharmony_ci{ 303262306a36Sopenharmony_ci bool vlan_promisc = ice_is_vlan_promisc_allowed(vf); 303362306a36Sopenharmony_ci int err; 303462306a36Sopenharmony_ci u16 i; 303562306a36Sopenharmony_ci 303662306a36Sopenharmony_ci for (i = 0; i < vfl->num_elements; i++) { 303762306a36Sopenharmony_ci struct virtchnl_vlan_filter *vlan_fltr = &vfl->filters[i]; 303862306a36Sopenharmony_ci struct virtchnl_vlan *vc_vlan; 303962306a36Sopenharmony_ci 304062306a36Sopenharmony_ci vc_vlan = &vlan_fltr->outer; 304162306a36Sopenharmony_ci if (ice_vc_is_valid_vlan(vc_vlan)) { 304262306a36Sopenharmony_ci struct ice_vlan vlan = ice_vc_to_vlan(vc_vlan); 304362306a36Sopenharmony_ci 304462306a36Sopenharmony_ci err = ice_vc_vlan_action(vsi, 304562306a36Sopenharmony_ci vsi->outer_vlan_ops.del_vlan, 304662306a36Sopenharmony_ci &vlan); 304762306a36Sopenharmony_ci if (err) 304862306a36Sopenharmony_ci return err; 304962306a36Sopenharmony_ci 305062306a36Sopenharmony_ci if (vlan_promisc) 305162306a36Sopenharmony_ci ice_vf_dis_vlan_promisc(vsi, &vlan); 305262306a36Sopenharmony_ci 305362306a36Sopenharmony_ci /* Disable VLAN filtering when only VLAN 0 is left */ 305462306a36Sopenharmony_ci if (!ice_vsi_has_non_zero_vlans(vsi) && ice_is_dvm_ena(&vsi->back->hw)) { 305562306a36Sopenharmony_ci err = vsi->outer_vlan_ops.dis_tx_filtering(vsi); 305662306a36Sopenharmony_ci if (err) 305762306a36Sopenharmony_ci return err; 305862306a36Sopenharmony_ci } 305962306a36Sopenharmony_ci } 306062306a36Sopenharmony_ci 306162306a36Sopenharmony_ci vc_vlan = &vlan_fltr->inner; 306262306a36Sopenharmony_ci if (ice_vc_is_valid_vlan(vc_vlan)) { 306362306a36Sopenharmony_ci struct ice_vlan vlan = ice_vc_to_vlan(vc_vlan); 306462306a36Sopenharmony_ci 306562306a36Sopenharmony_ci err = ice_vc_vlan_action(vsi, 306662306a36Sopenharmony_ci vsi->inner_vlan_ops.del_vlan, 306762306a36Sopenharmony_ci &vlan); 306862306a36Sopenharmony_ci if (err) 306962306a36Sopenharmony_ci return err; 307062306a36Sopenharmony_ci 307162306a36Sopenharmony_ci /* no support for VLAN promiscuous on inner VLAN unless 307262306a36Sopenharmony_ci * we are in Single VLAN Mode (SVM) 307362306a36Sopenharmony_ci */ 307462306a36Sopenharmony_ci if (!ice_is_dvm_ena(&vsi->back->hw)) { 307562306a36Sopenharmony_ci if (vlan_promisc) 307662306a36Sopenharmony_ci ice_vf_dis_vlan_promisc(vsi, &vlan); 307762306a36Sopenharmony_ci 307862306a36Sopenharmony_ci /* Disable VLAN filtering when only VLAN 0 is left */ 307962306a36Sopenharmony_ci if (!ice_vsi_has_non_zero_vlans(vsi)) { 308062306a36Sopenharmony_ci err = vsi->inner_vlan_ops.dis_tx_filtering(vsi); 308162306a36Sopenharmony_ci if (err) 308262306a36Sopenharmony_ci return err; 308362306a36Sopenharmony_ci } 308462306a36Sopenharmony_ci } 308562306a36Sopenharmony_ci } 308662306a36Sopenharmony_ci } 308762306a36Sopenharmony_ci 308862306a36Sopenharmony_ci return 0; 308962306a36Sopenharmony_ci} 309062306a36Sopenharmony_ci 309162306a36Sopenharmony_ci/** 309262306a36Sopenharmony_ci * ice_vc_remove_vlan_v2_msg - virtchnl handler for VIRTCHNL_OP_DEL_VLAN_V2 309362306a36Sopenharmony_ci * @vf: VF the message was received from 309462306a36Sopenharmony_ci * @msg: message received from the VF 309562306a36Sopenharmony_ci */ 309662306a36Sopenharmony_cistatic int ice_vc_remove_vlan_v2_msg(struct ice_vf *vf, u8 *msg) 309762306a36Sopenharmony_ci{ 309862306a36Sopenharmony_ci struct virtchnl_vlan_filter_list_v2 *vfl = 309962306a36Sopenharmony_ci (struct virtchnl_vlan_filter_list_v2 *)msg; 310062306a36Sopenharmony_ci enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 310162306a36Sopenharmony_ci struct ice_vsi *vsi; 310262306a36Sopenharmony_ci 310362306a36Sopenharmony_ci if (!ice_vc_validate_vlan_filter_list(&vf->vlan_v2_caps.filtering, 310462306a36Sopenharmony_ci vfl)) { 310562306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 310662306a36Sopenharmony_ci goto out; 310762306a36Sopenharmony_ci } 310862306a36Sopenharmony_ci 310962306a36Sopenharmony_ci if (!ice_vc_isvalid_vsi_id(vf, vfl->vport_id)) { 311062306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 311162306a36Sopenharmony_ci goto out; 311262306a36Sopenharmony_ci } 311362306a36Sopenharmony_ci 311462306a36Sopenharmony_ci vsi = ice_get_vf_vsi(vf); 311562306a36Sopenharmony_ci if (!vsi) { 311662306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 311762306a36Sopenharmony_ci goto out; 311862306a36Sopenharmony_ci } 311962306a36Sopenharmony_ci 312062306a36Sopenharmony_ci if (ice_vc_del_vlans(vf, vsi, vfl)) 312162306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 312262306a36Sopenharmony_ci 312362306a36Sopenharmony_ciout: 312462306a36Sopenharmony_ci return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DEL_VLAN_V2, v_ret, NULL, 312562306a36Sopenharmony_ci 0); 312662306a36Sopenharmony_ci} 312762306a36Sopenharmony_ci 312862306a36Sopenharmony_ci/** 312962306a36Sopenharmony_ci * ice_vc_add_vlans - add VLAN(s) from the virtchnl filter list 313062306a36Sopenharmony_ci * @vf: VF used to add the VLAN(s) 313162306a36Sopenharmony_ci * @vsi: VF's VSI used to add the VLAN(s) 313262306a36Sopenharmony_ci * @vfl: virthchnl filter list used to add the filters 313362306a36Sopenharmony_ci */ 313462306a36Sopenharmony_cistatic int 313562306a36Sopenharmony_ciice_vc_add_vlans(struct ice_vf *vf, struct ice_vsi *vsi, 313662306a36Sopenharmony_ci struct virtchnl_vlan_filter_list_v2 *vfl) 313762306a36Sopenharmony_ci{ 313862306a36Sopenharmony_ci bool vlan_promisc = ice_is_vlan_promisc_allowed(vf); 313962306a36Sopenharmony_ci int err; 314062306a36Sopenharmony_ci u16 i; 314162306a36Sopenharmony_ci 314262306a36Sopenharmony_ci for (i = 0; i < vfl->num_elements; i++) { 314362306a36Sopenharmony_ci struct virtchnl_vlan_filter *vlan_fltr = &vfl->filters[i]; 314462306a36Sopenharmony_ci struct virtchnl_vlan *vc_vlan; 314562306a36Sopenharmony_ci 314662306a36Sopenharmony_ci vc_vlan = &vlan_fltr->outer; 314762306a36Sopenharmony_ci if (ice_vc_is_valid_vlan(vc_vlan)) { 314862306a36Sopenharmony_ci struct ice_vlan vlan = ice_vc_to_vlan(vc_vlan); 314962306a36Sopenharmony_ci 315062306a36Sopenharmony_ci err = ice_vc_vlan_action(vsi, 315162306a36Sopenharmony_ci vsi->outer_vlan_ops.add_vlan, 315262306a36Sopenharmony_ci &vlan); 315362306a36Sopenharmony_ci if (err) 315462306a36Sopenharmony_ci return err; 315562306a36Sopenharmony_ci 315662306a36Sopenharmony_ci if (vlan_promisc) { 315762306a36Sopenharmony_ci err = ice_vf_ena_vlan_promisc(vsi, &vlan); 315862306a36Sopenharmony_ci if (err) 315962306a36Sopenharmony_ci return err; 316062306a36Sopenharmony_ci } 316162306a36Sopenharmony_ci 316262306a36Sopenharmony_ci /* Enable VLAN filtering on first non-zero VLAN */ 316362306a36Sopenharmony_ci if (vf->spoofchk && vlan.vid && ice_is_dvm_ena(&vsi->back->hw)) { 316462306a36Sopenharmony_ci err = vsi->outer_vlan_ops.ena_tx_filtering(vsi); 316562306a36Sopenharmony_ci if (err) 316662306a36Sopenharmony_ci return err; 316762306a36Sopenharmony_ci } 316862306a36Sopenharmony_ci } 316962306a36Sopenharmony_ci 317062306a36Sopenharmony_ci vc_vlan = &vlan_fltr->inner; 317162306a36Sopenharmony_ci if (ice_vc_is_valid_vlan(vc_vlan)) { 317262306a36Sopenharmony_ci struct ice_vlan vlan = ice_vc_to_vlan(vc_vlan); 317362306a36Sopenharmony_ci 317462306a36Sopenharmony_ci err = ice_vc_vlan_action(vsi, 317562306a36Sopenharmony_ci vsi->inner_vlan_ops.add_vlan, 317662306a36Sopenharmony_ci &vlan); 317762306a36Sopenharmony_ci if (err) 317862306a36Sopenharmony_ci return err; 317962306a36Sopenharmony_ci 318062306a36Sopenharmony_ci /* no support for VLAN promiscuous on inner VLAN unless 318162306a36Sopenharmony_ci * we are in Single VLAN Mode (SVM) 318262306a36Sopenharmony_ci */ 318362306a36Sopenharmony_ci if (!ice_is_dvm_ena(&vsi->back->hw)) { 318462306a36Sopenharmony_ci if (vlan_promisc) { 318562306a36Sopenharmony_ci err = ice_vf_ena_vlan_promisc(vsi, &vlan); 318662306a36Sopenharmony_ci if (err) 318762306a36Sopenharmony_ci return err; 318862306a36Sopenharmony_ci } 318962306a36Sopenharmony_ci 319062306a36Sopenharmony_ci /* Enable VLAN filtering on first non-zero VLAN */ 319162306a36Sopenharmony_ci if (vf->spoofchk && vlan.vid) { 319262306a36Sopenharmony_ci err = vsi->inner_vlan_ops.ena_tx_filtering(vsi); 319362306a36Sopenharmony_ci if (err) 319462306a36Sopenharmony_ci return err; 319562306a36Sopenharmony_ci } 319662306a36Sopenharmony_ci } 319762306a36Sopenharmony_ci } 319862306a36Sopenharmony_ci } 319962306a36Sopenharmony_ci 320062306a36Sopenharmony_ci return 0; 320162306a36Sopenharmony_ci} 320262306a36Sopenharmony_ci 320362306a36Sopenharmony_ci/** 320462306a36Sopenharmony_ci * ice_vc_validate_add_vlan_filter_list - validate add filter list from the VF 320562306a36Sopenharmony_ci * @vsi: VF VSI used to get number of existing VLAN filters 320662306a36Sopenharmony_ci * @vfc: negotiated/supported VLAN filtering capabilities 320762306a36Sopenharmony_ci * @vfl: VLAN filter list from VF to validate 320862306a36Sopenharmony_ci * 320962306a36Sopenharmony_ci * Validate all of the filters in the VLAN filter list from the VF during the 321062306a36Sopenharmony_ci * VIRTCHNL_OP_ADD_VLAN_V2 opcode. If any of the checks fail then return false. 321162306a36Sopenharmony_ci * Otherwise return true. 321262306a36Sopenharmony_ci */ 321362306a36Sopenharmony_cistatic bool 321462306a36Sopenharmony_ciice_vc_validate_add_vlan_filter_list(struct ice_vsi *vsi, 321562306a36Sopenharmony_ci struct virtchnl_vlan_filtering_caps *vfc, 321662306a36Sopenharmony_ci struct virtchnl_vlan_filter_list_v2 *vfl) 321762306a36Sopenharmony_ci{ 321862306a36Sopenharmony_ci u16 num_requested_filters = ice_vsi_num_non_zero_vlans(vsi) + 321962306a36Sopenharmony_ci vfl->num_elements; 322062306a36Sopenharmony_ci 322162306a36Sopenharmony_ci if (num_requested_filters > vfc->max_filters) 322262306a36Sopenharmony_ci return false; 322362306a36Sopenharmony_ci 322462306a36Sopenharmony_ci return ice_vc_validate_vlan_filter_list(vfc, vfl); 322562306a36Sopenharmony_ci} 322662306a36Sopenharmony_ci 322762306a36Sopenharmony_ci/** 322862306a36Sopenharmony_ci * ice_vc_add_vlan_v2_msg - virtchnl handler for VIRTCHNL_OP_ADD_VLAN_V2 322962306a36Sopenharmony_ci * @vf: VF the message was received from 323062306a36Sopenharmony_ci * @msg: message received from the VF 323162306a36Sopenharmony_ci */ 323262306a36Sopenharmony_cistatic int ice_vc_add_vlan_v2_msg(struct ice_vf *vf, u8 *msg) 323362306a36Sopenharmony_ci{ 323462306a36Sopenharmony_ci enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 323562306a36Sopenharmony_ci struct virtchnl_vlan_filter_list_v2 *vfl = 323662306a36Sopenharmony_ci (struct virtchnl_vlan_filter_list_v2 *)msg; 323762306a36Sopenharmony_ci struct ice_vsi *vsi; 323862306a36Sopenharmony_ci 323962306a36Sopenharmony_ci if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { 324062306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 324162306a36Sopenharmony_ci goto out; 324262306a36Sopenharmony_ci } 324362306a36Sopenharmony_ci 324462306a36Sopenharmony_ci if (!ice_vc_isvalid_vsi_id(vf, vfl->vport_id)) { 324562306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 324662306a36Sopenharmony_ci goto out; 324762306a36Sopenharmony_ci } 324862306a36Sopenharmony_ci 324962306a36Sopenharmony_ci vsi = ice_get_vf_vsi(vf); 325062306a36Sopenharmony_ci if (!vsi) { 325162306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 325262306a36Sopenharmony_ci goto out; 325362306a36Sopenharmony_ci } 325462306a36Sopenharmony_ci 325562306a36Sopenharmony_ci if (!ice_vc_validate_add_vlan_filter_list(vsi, 325662306a36Sopenharmony_ci &vf->vlan_v2_caps.filtering, 325762306a36Sopenharmony_ci vfl)) { 325862306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 325962306a36Sopenharmony_ci goto out; 326062306a36Sopenharmony_ci } 326162306a36Sopenharmony_ci 326262306a36Sopenharmony_ci if (ice_vc_add_vlans(vf, vsi, vfl)) 326362306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 326462306a36Sopenharmony_ci 326562306a36Sopenharmony_ciout: 326662306a36Sopenharmony_ci return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ADD_VLAN_V2, v_ret, NULL, 326762306a36Sopenharmony_ci 0); 326862306a36Sopenharmony_ci} 326962306a36Sopenharmony_ci 327062306a36Sopenharmony_ci/** 327162306a36Sopenharmony_ci * ice_vc_valid_vlan_setting - validate VLAN setting 327262306a36Sopenharmony_ci * @negotiated_settings: negotiated VLAN settings during VF init 327362306a36Sopenharmony_ci * @ethertype_setting: ethertype(s) requested for the VLAN setting 327462306a36Sopenharmony_ci */ 327562306a36Sopenharmony_cistatic bool 327662306a36Sopenharmony_ciice_vc_valid_vlan_setting(u32 negotiated_settings, u32 ethertype_setting) 327762306a36Sopenharmony_ci{ 327862306a36Sopenharmony_ci if (ethertype_setting && !(negotiated_settings & ethertype_setting)) 327962306a36Sopenharmony_ci return false; 328062306a36Sopenharmony_ci 328162306a36Sopenharmony_ci /* only allow a single VIRTCHNL_VLAN_ETHERTYPE if 328262306a36Sopenharmony_ci * VIRTHCNL_VLAN_ETHERTYPE_AND is not negotiated/supported 328362306a36Sopenharmony_ci */ 328462306a36Sopenharmony_ci if (!(negotiated_settings & VIRTCHNL_VLAN_ETHERTYPE_AND) && 328562306a36Sopenharmony_ci hweight32(ethertype_setting) > 1) 328662306a36Sopenharmony_ci return false; 328762306a36Sopenharmony_ci 328862306a36Sopenharmony_ci /* ability to modify the VLAN setting was not negotiated */ 328962306a36Sopenharmony_ci if (!(negotiated_settings & VIRTCHNL_VLAN_TOGGLE)) 329062306a36Sopenharmony_ci return false; 329162306a36Sopenharmony_ci 329262306a36Sopenharmony_ci return true; 329362306a36Sopenharmony_ci} 329462306a36Sopenharmony_ci 329562306a36Sopenharmony_ci/** 329662306a36Sopenharmony_ci * ice_vc_valid_vlan_setting_msg - validate the VLAN setting message 329762306a36Sopenharmony_ci * @caps: negotiated VLAN settings during VF init 329862306a36Sopenharmony_ci * @msg: message to validate 329962306a36Sopenharmony_ci * 330062306a36Sopenharmony_ci * Used to validate any VLAN virtchnl message sent as a 330162306a36Sopenharmony_ci * virtchnl_vlan_setting structure. Validates the message against the 330262306a36Sopenharmony_ci * negotiated/supported caps during VF driver init. 330362306a36Sopenharmony_ci */ 330462306a36Sopenharmony_cistatic bool 330562306a36Sopenharmony_ciice_vc_valid_vlan_setting_msg(struct virtchnl_vlan_supported_caps *caps, 330662306a36Sopenharmony_ci struct virtchnl_vlan_setting *msg) 330762306a36Sopenharmony_ci{ 330862306a36Sopenharmony_ci if ((!msg->outer_ethertype_setting && 330962306a36Sopenharmony_ci !msg->inner_ethertype_setting) || 331062306a36Sopenharmony_ci (!caps->outer && !caps->inner)) 331162306a36Sopenharmony_ci return false; 331262306a36Sopenharmony_ci 331362306a36Sopenharmony_ci if (msg->outer_ethertype_setting && 331462306a36Sopenharmony_ci !ice_vc_valid_vlan_setting(caps->outer, 331562306a36Sopenharmony_ci msg->outer_ethertype_setting)) 331662306a36Sopenharmony_ci return false; 331762306a36Sopenharmony_ci 331862306a36Sopenharmony_ci if (msg->inner_ethertype_setting && 331962306a36Sopenharmony_ci !ice_vc_valid_vlan_setting(caps->inner, 332062306a36Sopenharmony_ci msg->inner_ethertype_setting)) 332162306a36Sopenharmony_ci return false; 332262306a36Sopenharmony_ci 332362306a36Sopenharmony_ci return true; 332462306a36Sopenharmony_ci} 332562306a36Sopenharmony_ci 332662306a36Sopenharmony_ci/** 332762306a36Sopenharmony_ci * ice_vc_get_tpid - transform from VIRTCHNL_VLAN_ETHERTYPE_* to VLAN TPID 332862306a36Sopenharmony_ci * @ethertype_setting: VIRTCHNL_VLAN_ETHERTYPE_* used to get VLAN TPID 332962306a36Sopenharmony_ci * @tpid: VLAN TPID to populate 333062306a36Sopenharmony_ci */ 333162306a36Sopenharmony_cistatic int ice_vc_get_tpid(u32 ethertype_setting, u16 *tpid) 333262306a36Sopenharmony_ci{ 333362306a36Sopenharmony_ci switch (ethertype_setting) { 333462306a36Sopenharmony_ci case VIRTCHNL_VLAN_ETHERTYPE_8100: 333562306a36Sopenharmony_ci *tpid = ETH_P_8021Q; 333662306a36Sopenharmony_ci break; 333762306a36Sopenharmony_ci case VIRTCHNL_VLAN_ETHERTYPE_88A8: 333862306a36Sopenharmony_ci *tpid = ETH_P_8021AD; 333962306a36Sopenharmony_ci break; 334062306a36Sopenharmony_ci case VIRTCHNL_VLAN_ETHERTYPE_9100: 334162306a36Sopenharmony_ci *tpid = ETH_P_QINQ1; 334262306a36Sopenharmony_ci break; 334362306a36Sopenharmony_ci default: 334462306a36Sopenharmony_ci *tpid = 0; 334562306a36Sopenharmony_ci return -EINVAL; 334662306a36Sopenharmony_ci } 334762306a36Sopenharmony_ci 334862306a36Sopenharmony_ci return 0; 334962306a36Sopenharmony_ci} 335062306a36Sopenharmony_ci 335162306a36Sopenharmony_ci/** 335262306a36Sopenharmony_ci * ice_vc_ena_vlan_offload - enable VLAN offload based on the ethertype_setting 335362306a36Sopenharmony_ci * @vsi: VF's VSI used to enable the VLAN offload 335462306a36Sopenharmony_ci * @ena_offload: function used to enable the VLAN offload 335562306a36Sopenharmony_ci * @ethertype_setting: VIRTCHNL_VLAN_ETHERTYPE_* to enable offloads for 335662306a36Sopenharmony_ci */ 335762306a36Sopenharmony_cistatic int 335862306a36Sopenharmony_ciice_vc_ena_vlan_offload(struct ice_vsi *vsi, 335962306a36Sopenharmony_ci int (*ena_offload)(struct ice_vsi *vsi, u16 tpid), 336062306a36Sopenharmony_ci u32 ethertype_setting) 336162306a36Sopenharmony_ci{ 336262306a36Sopenharmony_ci u16 tpid; 336362306a36Sopenharmony_ci int err; 336462306a36Sopenharmony_ci 336562306a36Sopenharmony_ci err = ice_vc_get_tpid(ethertype_setting, &tpid); 336662306a36Sopenharmony_ci if (err) 336762306a36Sopenharmony_ci return err; 336862306a36Sopenharmony_ci 336962306a36Sopenharmony_ci err = ena_offload(vsi, tpid); 337062306a36Sopenharmony_ci if (err) 337162306a36Sopenharmony_ci return err; 337262306a36Sopenharmony_ci 337362306a36Sopenharmony_ci return 0; 337462306a36Sopenharmony_ci} 337562306a36Sopenharmony_ci 337662306a36Sopenharmony_ci#define ICE_L2TSEL_QRX_CONTEXT_REG_IDX 3 337762306a36Sopenharmony_ci#define ICE_L2TSEL_BIT_OFFSET 23 337862306a36Sopenharmony_cienum ice_l2tsel { 337962306a36Sopenharmony_ci ICE_L2TSEL_EXTRACT_FIRST_TAG_L2TAG2_2ND, 338062306a36Sopenharmony_ci ICE_L2TSEL_EXTRACT_FIRST_TAG_L2TAG1, 338162306a36Sopenharmony_ci}; 338262306a36Sopenharmony_ci 338362306a36Sopenharmony_ci/** 338462306a36Sopenharmony_ci * ice_vsi_update_l2tsel - update l2tsel field for all Rx rings on this VSI 338562306a36Sopenharmony_ci * @vsi: VSI used to update l2tsel on 338662306a36Sopenharmony_ci * @l2tsel: l2tsel setting requested 338762306a36Sopenharmony_ci * 338862306a36Sopenharmony_ci * Use the l2tsel setting to update all of the Rx queue context bits for l2tsel. 338962306a36Sopenharmony_ci * This will modify which descriptor field the first offloaded VLAN will be 339062306a36Sopenharmony_ci * stripped into. 339162306a36Sopenharmony_ci */ 339262306a36Sopenharmony_cistatic void ice_vsi_update_l2tsel(struct ice_vsi *vsi, enum ice_l2tsel l2tsel) 339362306a36Sopenharmony_ci{ 339462306a36Sopenharmony_ci struct ice_hw *hw = &vsi->back->hw; 339562306a36Sopenharmony_ci u32 l2tsel_bit; 339662306a36Sopenharmony_ci int i; 339762306a36Sopenharmony_ci 339862306a36Sopenharmony_ci if (l2tsel == ICE_L2TSEL_EXTRACT_FIRST_TAG_L2TAG2_2ND) 339962306a36Sopenharmony_ci l2tsel_bit = 0; 340062306a36Sopenharmony_ci else 340162306a36Sopenharmony_ci l2tsel_bit = BIT(ICE_L2TSEL_BIT_OFFSET); 340262306a36Sopenharmony_ci 340362306a36Sopenharmony_ci for (i = 0; i < vsi->alloc_rxq; i++) { 340462306a36Sopenharmony_ci u16 pfq = vsi->rxq_map[i]; 340562306a36Sopenharmony_ci u32 qrx_context_offset; 340662306a36Sopenharmony_ci u32 regval; 340762306a36Sopenharmony_ci 340862306a36Sopenharmony_ci qrx_context_offset = 340962306a36Sopenharmony_ci QRX_CONTEXT(ICE_L2TSEL_QRX_CONTEXT_REG_IDX, pfq); 341062306a36Sopenharmony_ci 341162306a36Sopenharmony_ci regval = rd32(hw, qrx_context_offset); 341262306a36Sopenharmony_ci regval &= ~BIT(ICE_L2TSEL_BIT_OFFSET); 341362306a36Sopenharmony_ci regval |= l2tsel_bit; 341462306a36Sopenharmony_ci wr32(hw, qrx_context_offset, regval); 341562306a36Sopenharmony_ci } 341662306a36Sopenharmony_ci} 341762306a36Sopenharmony_ci 341862306a36Sopenharmony_ci/** 341962306a36Sopenharmony_ci * ice_vc_ena_vlan_stripping_v2_msg 342062306a36Sopenharmony_ci * @vf: VF the message was received from 342162306a36Sopenharmony_ci * @msg: message received from the VF 342262306a36Sopenharmony_ci * 342362306a36Sopenharmony_ci * virthcnl handler for VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2 342462306a36Sopenharmony_ci */ 342562306a36Sopenharmony_cistatic int ice_vc_ena_vlan_stripping_v2_msg(struct ice_vf *vf, u8 *msg) 342662306a36Sopenharmony_ci{ 342762306a36Sopenharmony_ci enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 342862306a36Sopenharmony_ci struct virtchnl_vlan_supported_caps *stripping_support; 342962306a36Sopenharmony_ci struct virtchnl_vlan_setting *strip_msg = 343062306a36Sopenharmony_ci (struct virtchnl_vlan_setting *)msg; 343162306a36Sopenharmony_ci u32 ethertype_setting; 343262306a36Sopenharmony_ci struct ice_vsi *vsi; 343362306a36Sopenharmony_ci 343462306a36Sopenharmony_ci if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { 343562306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 343662306a36Sopenharmony_ci goto out; 343762306a36Sopenharmony_ci } 343862306a36Sopenharmony_ci 343962306a36Sopenharmony_ci if (!ice_vc_isvalid_vsi_id(vf, strip_msg->vport_id)) { 344062306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 344162306a36Sopenharmony_ci goto out; 344262306a36Sopenharmony_ci } 344362306a36Sopenharmony_ci 344462306a36Sopenharmony_ci vsi = ice_get_vf_vsi(vf); 344562306a36Sopenharmony_ci if (!vsi) { 344662306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 344762306a36Sopenharmony_ci goto out; 344862306a36Sopenharmony_ci } 344962306a36Sopenharmony_ci 345062306a36Sopenharmony_ci stripping_support = &vf->vlan_v2_caps.offloads.stripping_support; 345162306a36Sopenharmony_ci if (!ice_vc_valid_vlan_setting_msg(stripping_support, strip_msg)) { 345262306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 345362306a36Sopenharmony_ci goto out; 345462306a36Sopenharmony_ci } 345562306a36Sopenharmony_ci 345662306a36Sopenharmony_ci ethertype_setting = strip_msg->outer_ethertype_setting; 345762306a36Sopenharmony_ci if (ethertype_setting) { 345862306a36Sopenharmony_ci if (ice_vc_ena_vlan_offload(vsi, 345962306a36Sopenharmony_ci vsi->outer_vlan_ops.ena_stripping, 346062306a36Sopenharmony_ci ethertype_setting)) { 346162306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 346262306a36Sopenharmony_ci goto out; 346362306a36Sopenharmony_ci } else { 346462306a36Sopenharmony_ci enum ice_l2tsel l2tsel = 346562306a36Sopenharmony_ci ICE_L2TSEL_EXTRACT_FIRST_TAG_L2TAG2_2ND; 346662306a36Sopenharmony_ci 346762306a36Sopenharmony_ci /* PF tells the VF that the outer VLAN tag is always 346862306a36Sopenharmony_ci * extracted to VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2_2 and 346962306a36Sopenharmony_ci * inner is always extracted to 347062306a36Sopenharmony_ci * VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1. This is needed to 347162306a36Sopenharmony_ci * support outer stripping so the first tag always ends 347262306a36Sopenharmony_ci * up in L2TAG2_2ND and the second/inner tag, if 347362306a36Sopenharmony_ci * enabled, is extracted in L2TAG1. 347462306a36Sopenharmony_ci */ 347562306a36Sopenharmony_ci ice_vsi_update_l2tsel(vsi, l2tsel); 347662306a36Sopenharmony_ci } 347762306a36Sopenharmony_ci } 347862306a36Sopenharmony_ci 347962306a36Sopenharmony_ci ethertype_setting = strip_msg->inner_ethertype_setting; 348062306a36Sopenharmony_ci if (ethertype_setting && 348162306a36Sopenharmony_ci ice_vc_ena_vlan_offload(vsi, vsi->inner_vlan_ops.ena_stripping, 348262306a36Sopenharmony_ci ethertype_setting)) { 348362306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 348462306a36Sopenharmony_ci goto out; 348562306a36Sopenharmony_ci } 348662306a36Sopenharmony_ci 348762306a36Sopenharmony_ciout: 348862306a36Sopenharmony_ci return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2, 348962306a36Sopenharmony_ci v_ret, NULL, 0); 349062306a36Sopenharmony_ci} 349162306a36Sopenharmony_ci 349262306a36Sopenharmony_ci/** 349362306a36Sopenharmony_ci * ice_vc_dis_vlan_stripping_v2_msg 349462306a36Sopenharmony_ci * @vf: VF the message was received from 349562306a36Sopenharmony_ci * @msg: message received from the VF 349662306a36Sopenharmony_ci * 349762306a36Sopenharmony_ci * virthcnl handler for VIRTCHNL_OP_DISABLE_VLAN_STRIPPING_V2 349862306a36Sopenharmony_ci */ 349962306a36Sopenharmony_cistatic int ice_vc_dis_vlan_stripping_v2_msg(struct ice_vf *vf, u8 *msg) 350062306a36Sopenharmony_ci{ 350162306a36Sopenharmony_ci enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 350262306a36Sopenharmony_ci struct virtchnl_vlan_supported_caps *stripping_support; 350362306a36Sopenharmony_ci struct virtchnl_vlan_setting *strip_msg = 350462306a36Sopenharmony_ci (struct virtchnl_vlan_setting *)msg; 350562306a36Sopenharmony_ci u32 ethertype_setting; 350662306a36Sopenharmony_ci struct ice_vsi *vsi; 350762306a36Sopenharmony_ci 350862306a36Sopenharmony_ci if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { 350962306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 351062306a36Sopenharmony_ci goto out; 351162306a36Sopenharmony_ci } 351262306a36Sopenharmony_ci 351362306a36Sopenharmony_ci if (!ice_vc_isvalid_vsi_id(vf, strip_msg->vport_id)) { 351462306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 351562306a36Sopenharmony_ci goto out; 351662306a36Sopenharmony_ci } 351762306a36Sopenharmony_ci 351862306a36Sopenharmony_ci vsi = ice_get_vf_vsi(vf); 351962306a36Sopenharmony_ci if (!vsi) { 352062306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 352162306a36Sopenharmony_ci goto out; 352262306a36Sopenharmony_ci } 352362306a36Sopenharmony_ci 352462306a36Sopenharmony_ci stripping_support = &vf->vlan_v2_caps.offloads.stripping_support; 352562306a36Sopenharmony_ci if (!ice_vc_valid_vlan_setting_msg(stripping_support, strip_msg)) { 352662306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 352762306a36Sopenharmony_ci goto out; 352862306a36Sopenharmony_ci } 352962306a36Sopenharmony_ci 353062306a36Sopenharmony_ci ethertype_setting = strip_msg->outer_ethertype_setting; 353162306a36Sopenharmony_ci if (ethertype_setting) { 353262306a36Sopenharmony_ci if (vsi->outer_vlan_ops.dis_stripping(vsi)) { 353362306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 353462306a36Sopenharmony_ci goto out; 353562306a36Sopenharmony_ci } else { 353662306a36Sopenharmony_ci enum ice_l2tsel l2tsel = 353762306a36Sopenharmony_ci ICE_L2TSEL_EXTRACT_FIRST_TAG_L2TAG1; 353862306a36Sopenharmony_ci 353962306a36Sopenharmony_ci /* PF tells the VF that the outer VLAN tag is always 354062306a36Sopenharmony_ci * extracted to VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2_2 and 354162306a36Sopenharmony_ci * inner is always extracted to 354262306a36Sopenharmony_ci * VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1. This is needed to 354362306a36Sopenharmony_ci * support inner stripping while outer stripping is 354462306a36Sopenharmony_ci * disabled so that the first and only tag is extracted 354562306a36Sopenharmony_ci * in L2TAG1. 354662306a36Sopenharmony_ci */ 354762306a36Sopenharmony_ci ice_vsi_update_l2tsel(vsi, l2tsel); 354862306a36Sopenharmony_ci } 354962306a36Sopenharmony_ci } 355062306a36Sopenharmony_ci 355162306a36Sopenharmony_ci ethertype_setting = strip_msg->inner_ethertype_setting; 355262306a36Sopenharmony_ci if (ethertype_setting && vsi->inner_vlan_ops.dis_stripping(vsi)) { 355362306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 355462306a36Sopenharmony_ci goto out; 355562306a36Sopenharmony_ci } 355662306a36Sopenharmony_ci 355762306a36Sopenharmony_ciout: 355862306a36Sopenharmony_ci return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DISABLE_VLAN_STRIPPING_V2, 355962306a36Sopenharmony_ci v_ret, NULL, 0); 356062306a36Sopenharmony_ci} 356162306a36Sopenharmony_ci 356262306a36Sopenharmony_ci/** 356362306a36Sopenharmony_ci * ice_vc_ena_vlan_insertion_v2_msg 356462306a36Sopenharmony_ci * @vf: VF the message was received from 356562306a36Sopenharmony_ci * @msg: message received from the VF 356662306a36Sopenharmony_ci * 356762306a36Sopenharmony_ci * virthcnl handler for VIRTCHNL_OP_ENABLE_VLAN_INSERTION_V2 356862306a36Sopenharmony_ci */ 356962306a36Sopenharmony_cistatic int ice_vc_ena_vlan_insertion_v2_msg(struct ice_vf *vf, u8 *msg) 357062306a36Sopenharmony_ci{ 357162306a36Sopenharmony_ci enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 357262306a36Sopenharmony_ci struct virtchnl_vlan_supported_caps *insertion_support; 357362306a36Sopenharmony_ci struct virtchnl_vlan_setting *insertion_msg = 357462306a36Sopenharmony_ci (struct virtchnl_vlan_setting *)msg; 357562306a36Sopenharmony_ci u32 ethertype_setting; 357662306a36Sopenharmony_ci struct ice_vsi *vsi; 357762306a36Sopenharmony_ci 357862306a36Sopenharmony_ci if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { 357962306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 358062306a36Sopenharmony_ci goto out; 358162306a36Sopenharmony_ci } 358262306a36Sopenharmony_ci 358362306a36Sopenharmony_ci if (!ice_vc_isvalid_vsi_id(vf, insertion_msg->vport_id)) { 358462306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 358562306a36Sopenharmony_ci goto out; 358662306a36Sopenharmony_ci } 358762306a36Sopenharmony_ci 358862306a36Sopenharmony_ci vsi = ice_get_vf_vsi(vf); 358962306a36Sopenharmony_ci if (!vsi) { 359062306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 359162306a36Sopenharmony_ci goto out; 359262306a36Sopenharmony_ci } 359362306a36Sopenharmony_ci 359462306a36Sopenharmony_ci insertion_support = &vf->vlan_v2_caps.offloads.insertion_support; 359562306a36Sopenharmony_ci if (!ice_vc_valid_vlan_setting_msg(insertion_support, insertion_msg)) { 359662306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 359762306a36Sopenharmony_ci goto out; 359862306a36Sopenharmony_ci } 359962306a36Sopenharmony_ci 360062306a36Sopenharmony_ci ethertype_setting = insertion_msg->outer_ethertype_setting; 360162306a36Sopenharmony_ci if (ethertype_setting && 360262306a36Sopenharmony_ci ice_vc_ena_vlan_offload(vsi, vsi->outer_vlan_ops.ena_insertion, 360362306a36Sopenharmony_ci ethertype_setting)) { 360462306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 360562306a36Sopenharmony_ci goto out; 360662306a36Sopenharmony_ci } 360762306a36Sopenharmony_ci 360862306a36Sopenharmony_ci ethertype_setting = insertion_msg->inner_ethertype_setting; 360962306a36Sopenharmony_ci if (ethertype_setting && 361062306a36Sopenharmony_ci ice_vc_ena_vlan_offload(vsi, vsi->inner_vlan_ops.ena_insertion, 361162306a36Sopenharmony_ci ethertype_setting)) { 361262306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 361362306a36Sopenharmony_ci goto out; 361462306a36Sopenharmony_ci } 361562306a36Sopenharmony_ci 361662306a36Sopenharmony_ciout: 361762306a36Sopenharmony_ci return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ENABLE_VLAN_INSERTION_V2, 361862306a36Sopenharmony_ci v_ret, NULL, 0); 361962306a36Sopenharmony_ci} 362062306a36Sopenharmony_ci 362162306a36Sopenharmony_ci/** 362262306a36Sopenharmony_ci * ice_vc_dis_vlan_insertion_v2_msg 362362306a36Sopenharmony_ci * @vf: VF the message was received from 362462306a36Sopenharmony_ci * @msg: message received from the VF 362562306a36Sopenharmony_ci * 362662306a36Sopenharmony_ci * virthcnl handler for VIRTCHNL_OP_DISABLE_VLAN_INSERTION_V2 362762306a36Sopenharmony_ci */ 362862306a36Sopenharmony_cistatic int ice_vc_dis_vlan_insertion_v2_msg(struct ice_vf *vf, u8 *msg) 362962306a36Sopenharmony_ci{ 363062306a36Sopenharmony_ci enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 363162306a36Sopenharmony_ci struct virtchnl_vlan_supported_caps *insertion_support; 363262306a36Sopenharmony_ci struct virtchnl_vlan_setting *insertion_msg = 363362306a36Sopenharmony_ci (struct virtchnl_vlan_setting *)msg; 363462306a36Sopenharmony_ci u32 ethertype_setting; 363562306a36Sopenharmony_ci struct ice_vsi *vsi; 363662306a36Sopenharmony_ci 363762306a36Sopenharmony_ci if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { 363862306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 363962306a36Sopenharmony_ci goto out; 364062306a36Sopenharmony_ci } 364162306a36Sopenharmony_ci 364262306a36Sopenharmony_ci if (!ice_vc_isvalid_vsi_id(vf, insertion_msg->vport_id)) { 364362306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 364462306a36Sopenharmony_ci goto out; 364562306a36Sopenharmony_ci } 364662306a36Sopenharmony_ci 364762306a36Sopenharmony_ci vsi = ice_get_vf_vsi(vf); 364862306a36Sopenharmony_ci if (!vsi) { 364962306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 365062306a36Sopenharmony_ci goto out; 365162306a36Sopenharmony_ci } 365262306a36Sopenharmony_ci 365362306a36Sopenharmony_ci insertion_support = &vf->vlan_v2_caps.offloads.insertion_support; 365462306a36Sopenharmony_ci if (!ice_vc_valid_vlan_setting_msg(insertion_support, insertion_msg)) { 365562306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 365662306a36Sopenharmony_ci goto out; 365762306a36Sopenharmony_ci } 365862306a36Sopenharmony_ci 365962306a36Sopenharmony_ci ethertype_setting = insertion_msg->outer_ethertype_setting; 366062306a36Sopenharmony_ci if (ethertype_setting && vsi->outer_vlan_ops.dis_insertion(vsi)) { 366162306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 366262306a36Sopenharmony_ci goto out; 366362306a36Sopenharmony_ci } 366462306a36Sopenharmony_ci 366562306a36Sopenharmony_ci ethertype_setting = insertion_msg->inner_ethertype_setting; 366662306a36Sopenharmony_ci if (ethertype_setting && vsi->inner_vlan_ops.dis_insertion(vsi)) { 366762306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 366862306a36Sopenharmony_ci goto out; 366962306a36Sopenharmony_ci } 367062306a36Sopenharmony_ci 367162306a36Sopenharmony_ciout: 367262306a36Sopenharmony_ci return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DISABLE_VLAN_INSERTION_V2, 367362306a36Sopenharmony_ci v_ret, NULL, 0); 367462306a36Sopenharmony_ci} 367562306a36Sopenharmony_ci 367662306a36Sopenharmony_cistatic const struct ice_virtchnl_ops ice_virtchnl_dflt_ops = { 367762306a36Sopenharmony_ci .get_ver_msg = ice_vc_get_ver_msg, 367862306a36Sopenharmony_ci .get_vf_res_msg = ice_vc_get_vf_res_msg, 367962306a36Sopenharmony_ci .reset_vf = ice_vc_reset_vf_msg, 368062306a36Sopenharmony_ci .add_mac_addr_msg = ice_vc_add_mac_addr_msg, 368162306a36Sopenharmony_ci .del_mac_addr_msg = ice_vc_del_mac_addr_msg, 368262306a36Sopenharmony_ci .cfg_qs_msg = ice_vc_cfg_qs_msg, 368362306a36Sopenharmony_ci .ena_qs_msg = ice_vc_ena_qs_msg, 368462306a36Sopenharmony_ci .dis_qs_msg = ice_vc_dis_qs_msg, 368562306a36Sopenharmony_ci .request_qs_msg = ice_vc_request_qs_msg, 368662306a36Sopenharmony_ci .cfg_irq_map_msg = ice_vc_cfg_irq_map_msg, 368762306a36Sopenharmony_ci .config_rss_key = ice_vc_config_rss_key, 368862306a36Sopenharmony_ci .config_rss_lut = ice_vc_config_rss_lut, 368962306a36Sopenharmony_ci .get_stats_msg = ice_vc_get_stats_msg, 369062306a36Sopenharmony_ci .cfg_promiscuous_mode_msg = ice_vc_cfg_promiscuous_mode_msg, 369162306a36Sopenharmony_ci .add_vlan_msg = ice_vc_add_vlan_msg, 369262306a36Sopenharmony_ci .remove_vlan_msg = ice_vc_remove_vlan_msg, 369362306a36Sopenharmony_ci .query_rxdid = ice_vc_query_rxdid, 369462306a36Sopenharmony_ci .get_rss_hena = ice_vc_get_rss_hena, 369562306a36Sopenharmony_ci .set_rss_hena_msg = ice_vc_set_rss_hena, 369662306a36Sopenharmony_ci .ena_vlan_stripping = ice_vc_ena_vlan_stripping, 369762306a36Sopenharmony_ci .dis_vlan_stripping = ice_vc_dis_vlan_stripping, 369862306a36Sopenharmony_ci .handle_rss_cfg_msg = ice_vc_handle_rss_cfg, 369962306a36Sopenharmony_ci .add_fdir_fltr_msg = ice_vc_add_fdir_fltr, 370062306a36Sopenharmony_ci .del_fdir_fltr_msg = ice_vc_del_fdir_fltr, 370162306a36Sopenharmony_ci .get_offload_vlan_v2_caps = ice_vc_get_offload_vlan_v2_caps, 370262306a36Sopenharmony_ci .add_vlan_v2_msg = ice_vc_add_vlan_v2_msg, 370362306a36Sopenharmony_ci .remove_vlan_v2_msg = ice_vc_remove_vlan_v2_msg, 370462306a36Sopenharmony_ci .ena_vlan_stripping_v2_msg = ice_vc_ena_vlan_stripping_v2_msg, 370562306a36Sopenharmony_ci .dis_vlan_stripping_v2_msg = ice_vc_dis_vlan_stripping_v2_msg, 370662306a36Sopenharmony_ci .ena_vlan_insertion_v2_msg = ice_vc_ena_vlan_insertion_v2_msg, 370762306a36Sopenharmony_ci .dis_vlan_insertion_v2_msg = ice_vc_dis_vlan_insertion_v2_msg, 370862306a36Sopenharmony_ci}; 370962306a36Sopenharmony_ci 371062306a36Sopenharmony_ci/** 371162306a36Sopenharmony_ci * ice_virtchnl_set_dflt_ops - Switch to default virtchnl ops 371262306a36Sopenharmony_ci * @vf: the VF to switch ops 371362306a36Sopenharmony_ci */ 371462306a36Sopenharmony_civoid ice_virtchnl_set_dflt_ops(struct ice_vf *vf) 371562306a36Sopenharmony_ci{ 371662306a36Sopenharmony_ci vf->virtchnl_ops = &ice_virtchnl_dflt_ops; 371762306a36Sopenharmony_ci} 371862306a36Sopenharmony_ci 371962306a36Sopenharmony_ci/** 372062306a36Sopenharmony_ci * ice_vc_repr_add_mac 372162306a36Sopenharmony_ci * @vf: pointer to VF 372262306a36Sopenharmony_ci * @msg: virtchannel message 372362306a36Sopenharmony_ci * 372462306a36Sopenharmony_ci * When port representors are created, we do not add MAC rule 372562306a36Sopenharmony_ci * to firmware, we store it so that PF could report same 372662306a36Sopenharmony_ci * MAC as VF. 372762306a36Sopenharmony_ci */ 372862306a36Sopenharmony_cistatic int ice_vc_repr_add_mac(struct ice_vf *vf, u8 *msg) 372962306a36Sopenharmony_ci{ 373062306a36Sopenharmony_ci enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; 373162306a36Sopenharmony_ci struct virtchnl_ether_addr_list *al = 373262306a36Sopenharmony_ci (struct virtchnl_ether_addr_list *)msg; 373362306a36Sopenharmony_ci struct ice_vsi *vsi; 373462306a36Sopenharmony_ci struct ice_pf *pf; 373562306a36Sopenharmony_ci int i; 373662306a36Sopenharmony_ci 373762306a36Sopenharmony_ci if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states) || 373862306a36Sopenharmony_ci !ice_vc_isvalid_vsi_id(vf, al->vsi_id)) { 373962306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 374062306a36Sopenharmony_ci goto handle_mac_exit; 374162306a36Sopenharmony_ci } 374262306a36Sopenharmony_ci 374362306a36Sopenharmony_ci pf = vf->pf; 374462306a36Sopenharmony_ci 374562306a36Sopenharmony_ci vsi = ice_get_vf_vsi(vf); 374662306a36Sopenharmony_ci if (!vsi) { 374762306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_PARAM; 374862306a36Sopenharmony_ci goto handle_mac_exit; 374962306a36Sopenharmony_ci } 375062306a36Sopenharmony_ci 375162306a36Sopenharmony_ci for (i = 0; i < al->num_elements; i++) { 375262306a36Sopenharmony_ci u8 *mac_addr = al->list[i].addr; 375362306a36Sopenharmony_ci 375462306a36Sopenharmony_ci if (!is_unicast_ether_addr(mac_addr) || 375562306a36Sopenharmony_ci ether_addr_equal(mac_addr, vf->hw_lan_addr)) 375662306a36Sopenharmony_ci continue; 375762306a36Sopenharmony_ci 375862306a36Sopenharmony_ci if (vf->pf_set_mac) { 375962306a36Sopenharmony_ci dev_err(ice_pf_to_dev(pf), "VF attempting to override administratively set MAC address\n"); 376062306a36Sopenharmony_ci v_ret = VIRTCHNL_STATUS_ERR_NOT_SUPPORTED; 376162306a36Sopenharmony_ci goto handle_mac_exit; 376262306a36Sopenharmony_ci } 376362306a36Sopenharmony_ci 376462306a36Sopenharmony_ci ice_vfhw_mac_add(vf, &al->list[i]); 376562306a36Sopenharmony_ci vf->num_mac++; 376662306a36Sopenharmony_ci break; 376762306a36Sopenharmony_ci } 376862306a36Sopenharmony_ci 376962306a36Sopenharmony_cihandle_mac_exit: 377062306a36Sopenharmony_ci return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ADD_ETH_ADDR, 377162306a36Sopenharmony_ci v_ret, NULL, 0); 377262306a36Sopenharmony_ci} 377362306a36Sopenharmony_ci 377462306a36Sopenharmony_ci/** 377562306a36Sopenharmony_ci * ice_vc_repr_del_mac - response with success for deleting MAC 377662306a36Sopenharmony_ci * @vf: pointer to VF 377762306a36Sopenharmony_ci * @msg: virtchannel message 377862306a36Sopenharmony_ci * 377962306a36Sopenharmony_ci * Respond with success to not break normal VF flow. 378062306a36Sopenharmony_ci * For legacy VF driver try to update cached MAC address. 378162306a36Sopenharmony_ci */ 378262306a36Sopenharmony_cistatic int 378362306a36Sopenharmony_ciice_vc_repr_del_mac(struct ice_vf __always_unused *vf, u8 __always_unused *msg) 378462306a36Sopenharmony_ci{ 378562306a36Sopenharmony_ci struct virtchnl_ether_addr_list *al = 378662306a36Sopenharmony_ci (struct virtchnl_ether_addr_list *)msg; 378762306a36Sopenharmony_ci 378862306a36Sopenharmony_ci ice_update_legacy_cached_mac(vf, &al->list[0]); 378962306a36Sopenharmony_ci 379062306a36Sopenharmony_ci return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DEL_ETH_ADDR, 379162306a36Sopenharmony_ci VIRTCHNL_STATUS_SUCCESS, NULL, 0); 379262306a36Sopenharmony_ci} 379362306a36Sopenharmony_ci 379462306a36Sopenharmony_cistatic int 379562306a36Sopenharmony_ciice_vc_repr_cfg_promiscuous_mode(struct ice_vf *vf, u8 __always_unused *msg) 379662306a36Sopenharmony_ci{ 379762306a36Sopenharmony_ci dev_dbg(ice_pf_to_dev(vf->pf), 379862306a36Sopenharmony_ci "Can't config promiscuous mode in switchdev mode for VF %d\n", 379962306a36Sopenharmony_ci vf->vf_id); 380062306a36Sopenharmony_ci return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, 380162306a36Sopenharmony_ci VIRTCHNL_STATUS_ERR_NOT_SUPPORTED, 380262306a36Sopenharmony_ci NULL, 0); 380362306a36Sopenharmony_ci} 380462306a36Sopenharmony_ci 380562306a36Sopenharmony_cistatic const struct ice_virtchnl_ops ice_virtchnl_repr_ops = { 380662306a36Sopenharmony_ci .get_ver_msg = ice_vc_get_ver_msg, 380762306a36Sopenharmony_ci .get_vf_res_msg = ice_vc_get_vf_res_msg, 380862306a36Sopenharmony_ci .reset_vf = ice_vc_reset_vf_msg, 380962306a36Sopenharmony_ci .add_mac_addr_msg = ice_vc_repr_add_mac, 381062306a36Sopenharmony_ci .del_mac_addr_msg = ice_vc_repr_del_mac, 381162306a36Sopenharmony_ci .cfg_qs_msg = ice_vc_cfg_qs_msg, 381262306a36Sopenharmony_ci .ena_qs_msg = ice_vc_ena_qs_msg, 381362306a36Sopenharmony_ci .dis_qs_msg = ice_vc_dis_qs_msg, 381462306a36Sopenharmony_ci .request_qs_msg = ice_vc_request_qs_msg, 381562306a36Sopenharmony_ci .cfg_irq_map_msg = ice_vc_cfg_irq_map_msg, 381662306a36Sopenharmony_ci .config_rss_key = ice_vc_config_rss_key, 381762306a36Sopenharmony_ci .config_rss_lut = ice_vc_config_rss_lut, 381862306a36Sopenharmony_ci .get_stats_msg = ice_vc_get_stats_msg, 381962306a36Sopenharmony_ci .cfg_promiscuous_mode_msg = ice_vc_repr_cfg_promiscuous_mode, 382062306a36Sopenharmony_ci .add_vlan_msg = ice_vc_add_vlan_msg, 382162306a36Sopenharmony_ci .remove_vlan_msg = ice_vc_remove_vlan_msg, 382262306a36Sopenharmony_ci .query_rxdid = ice_vc_query_rxdid, 382362306a36Sopenharmony_ci .get_rss_hena = ice_vc_get_rss_hena, 382462306a36Sopenharmony_ci .set_rss_hena_msg = ice_vc_set_rss_hena, 382562306a36Sopenharmony_ci .ena_vlan_stripping = ice_vc_ena_vlan_stripping, 382662306a36Sopenharmony_ci .dis_vlan_stripping = ice_vc_dis_vlan_stripping, 382762306a36Sopenharmony_ci .handle_rss_cfg_msg = ice_vc_handle_rss_cfg, 382862306a36Sopenharmony_ci .add_fdir_fltr_msg = ice_vc_add_fdir_fltr, 382962306a36Sopenharmony_ci .del_fdir_fltr_msg = ice_vc_del_fdir_fltr, 383062306a36Sopenharmony_ci .get_offload_vlan_v2_caps = ice_vc_get_offload_vlan_v2_caps, 383162306a36Sopenharmony_ci .add_vlan_v2_msg = ice_vc_add_vlan_v2_msg, 383262306a36Sopenharmony_ci .remove_vlan_v2_msg = ice_vc_remove_vlan_v2_msg, 383362306a36Sopenharmony_ci .ena_vlan_stripping_v2_msg = ice_vc_ena_vlan_stripping_v2_msg, 383462306a36Sopenharmony_ci .dis_vlan_stripping_v2_msg = ice_vc_dis_vlan_stripping_v2_msg, 383562306a36Sopenharmony_ci .ena_vlan_insertion_v2_msg = ice_vc_ena_vlan_insertion_v2_msg, 383662306a36Sopenharmony_ci .dis_vlan_insertion_v2_msg = ice_vc_dis_vlan_insertion_v2_msg, 383762306a36Sopenharmony_ci}; 383862306a36Sopenharmony_ci 383962306a36Sopenharmony_ci/** 384062306a36Sopenharmony_ci * ice_virtchnl_set_repr_ops - Switch to representor virtchnl ops 384162306a36Sopenharmony_ci * @vf: the VF to switch ops 384262306a36Sopenharmony_ci */ 384362306a36Sopenharmony_civoid ice_virtchnl_set_repr_ops(struct ice_vf *vf) 384462306a36Sopenharmony_ci{ 384562306a36Sopenharmony_ci vf->virtchnl_ops = &ice_virtchnl_repr_ops; 384662306a36Sopenharmony_ci} 384762306a36Sopenharmony_ci 384862306a36Sopenharmony_ci/** 384962306a36Sopenharmony_ci * ice_is_malicious_vf - check if this vf might be overflowing mailbox 385062306a36Sopenharmony_ci * @vf: the VF to check 385162306a36Sopenharmony_ci * @mbxdata: data about the state of the mailbox 385262306a36Sopenharmony_ci * 385362306a36Sopenharmony_ci * Detect if a given VF might be malicious and attempting to overflow the PF 385462306a36Sopenharmony_ci * mailbox. If so, log a warning message and ignore this event. 385562306a36Sopenharmony_ci */ 385662306a36Sopenharmony_cistatic bool 385762306a36Sopenharmony_ciice_is_malicious_vf(struct ice_vf *vf, struct ice_mbx_data *mbxdata) 385862306a36Sopenharmony_ci{ 385962306a36Sopenharmony_ci bool report_malvf = false; 386062306a36Sopenharmony_ci struct device *dev; 386162306a36Sopenharmony_ci struct ice_pf *pf; 386262306a36Sopenharmony_ci int status; 386362306a36Sopenharmony_ci 386462306a36Sopenharmony_ci pf = vf->pf; 386562306a36Sopenharmony_ci dev = ice_pf_to_dev(pf); 386662306a36Sopenharmony_ci 386762306a36Sopenharmony_ci if (test_bit(ICE_VF_STATE_DIS, vf->vf_states)) 386862306a36Sopenharmony_ci return vf->mbx_info.malicious; 386962306a36Sopenharmony_ci 387062306a36Sopenharmony_ci /* check to see if we have a newly malicious VF */ 387162306a36Sopenharmony_ci status = ice_mbx_vf_state_handler(&pf->hw, mbxdata, &vf->mbx_info, 387262306a36Sopenharmony_ci &report_malvf); 387362306a36Sopenharmony_ci if (status) 387462306a36Sopenharmony_ci dev_warn_ratelimited(dev, "Unable to check status of mailbox overflow for VF %u MAC %pM, status %d\n", 387562306a36Sopenharmony_ci vf->vf_id, vf->dev_lan_addr, status); 387662306a36Sopenharmony_ci 387762306a36Sopenharmony_ci if (report_malvf) { 387862306a36Sopenharmony_ci struct ice_vsi *pf_vsi = ice_get_main_vsi(pf); 387962306a36Sopenharmony_ci u8 zero_addr[ETH_ALEN] = {}; 388062306a36Sopenharmony_ci 388162306a36Sopenharmony_ci dev_warn(dev, "VF MAC %pM on PF MAC %pM is generating asynchronous messages and may be overflowing the PF message queue. Please see the Adapter User Guide for more information\n", 388262306a36Sopenharmony_ci vf->dev_lan_addr, 388362306a36Sopenharmony_ci pf_vsi ? pf_vsi->netdev->dev_addr : zero_addr); 388462306a36Sopenharmony_ci } 388562306a36Sopenharmony_ci 388662306a36Sopenharmony_ci return vf->mbx_info.malicious; 388762306a36Sopenharmony_ci} 388862306a36Sopenharmony_ci 388962306a36Sopenharmony_ci/** 389062306a36Sopenharmony_ci * ice_vc_process_vf_msg - Process request from VF 389162306a36Sopenharmony_ci * @pf: pointer to the PF structure 389262306a36Sopenharmony_ci * @event: pointer to the AQ event 389362306a36Sopenharmony_ci * @mbxdata: information used to detect VF attempting mailbox overflow 389462306a36Sopenharmony_ci * 389562306a36Sopenharmony_ci * called from the common asq/arq handler to 389662306a36Sopenharmony_ci * process request from VF 389762306a36Sopenharmony_ci */ 389862306a36Sopenharmony_civoid ice_vc_process_vf_msg(struct ice_pf *pf, struct ice_rq_event_info *event, 389962306a36Sopenharmony_ci struct ice_mbx_data *mbxdata) 390062306a36Sopenharmony_ci{ 390162306a36Sopenharmony_ci u32 v_opcode = le32_to_cpu(event->desc.cookie_high); 390262306a36Sopenharmony_ci s16 vf_id = le16_to_cpu(event->desc.retval); 390362306a36Sopenharmony_ci const struct ice_virtchnl_ops *ops; 390462306a36Sopenharmony_ci u16 msglen = event->msg_len; 390562306a36Sopenharmony_ci u8 *msg = event->msg_buf; 390662306a36Sopenharmony_ci struct ice_vf *vf = NULL; 390762306a36Sopenharmony_ci struct device *dev; 390862306a36Sopenharmony_ci int err = 0; 390962306a36Sopenharmony_ci 391062306a36Sopenharmony_ci dev = ice_pf_to_dev(pf); 391162306a36Sopenharmony_ci 391262306a36Sopenharmony_ci vf = ice_get_vf_by_id(pf, vf_id); 391362306a36Sopenharmony_ci if (!vf) { 391462306a36Sopenharmony_ci dev_err(dev, "Unable to locate VF for message from VF ID %d, opcode %d, len %d\n", 391562306a36Sopenharmony_ci vf_id, v_opcode, msglen); 391662306a36Sopenharmony_ci return; 391762306a36Sopenharmony_ci } 391862306a36Sopenharmony_ci 391962306a36Sopenharmony_ci mutex_lock(&vf->cfg_lock); 392062306a36Sopenharmony_ci 392162306a36Sopenharmony_ci /* Check if the VF is trying to overflow the mailbox */ 392262306a36Sopenharmony_ci if (ice_is_malicious_vf(vf, mbxdata)) 392362306a36Sopenharmony_ci goto finish; 392462306a36Sopenharmony_ci 392562306a36Sopenharmony_ci /* Check if VF is disabled. */ 392662306a36Sopenharmony_ci if (test_bit(ICE_VF_STATE_DIS, vf->vf_states)) { 392762306a36Sopenharmony_ci err = -EPERM; 392862306a36Sopenharmony_ci goto error_handler; 392962306a36Sopenharmony_ci } 393062306a36Sopenharmony_ci 393162306a36Sopenharmony_ci ops = vf->virtchnl_ops; 393262306a36Sopenharmony_ci 393362306a36Sopenharmony_ci /* Perform basic checks on the msg */ 393462306a36Sopenharmony_ci err = virtchnl_vc_validate_vf_msg(&vf->vf_ver, v_opcode, msg, msglen); 393562306a36Sopenharmony_ci if (err) { 393662306a36Sopenharmony_ci if (err == VIRTCHNL_STATUS_ERR_PARAM) 393762306a36Sopenharmony_ci err = -EPERM; 393862306a36Sopenharmony_ci else 393962306a36Sopenharmony_ci err = -EINVAL; 394062306a36Sopenharmony_ci } 394162306a36Sopenharmony_ci 394262306a36Sopenharmony_cierror_handler: 394362306a36Sopenharmony_ci if (err) { 394462306a36Sopenharmony_ci ice_vc_send_msg_to_vf(vf, v_opcode, VIRTCHNL_STATUS_ERR_PARAM, 394562306a36Sopenharmony_ci NULL, 0); 394662306a36Sopenharmony_ci dev_err(dev, "Invalid message from VF %d, opcode %d, len %d, error %d\n", 394762306a36Sopenharmony_ci vf_id, v_opcode, msglen, err); 394862306a36Sopenharmony_ci goto finish; 394962306a36Sopenharmony_ci } 395062306a36Sopenharmony_ci 395162306a36Sopenharmony_ci if (!ice_vc_is_opcode_allowed(vf, v_opcode)) { 395262306a36Sopenharmony_ci ice_vc_send_msg_to_vf(vf, v_opcode, 395362306a36Sopenharmony_ci VIRTCHNL_STATUS_ERR_NOT_SUPPORTED, NULL, 395462306a36Sopenharmony_ci 0); 395562306a36Sopenharmony_ci goto finish; 395662306a36Sopenharmony_ci } 395762306a36Sopenharmony_ci 395862306a36Sopenharmony_ci switch (v_opcode) { 395962306a36Sopenharmony_ci case VIRTCHNL_OP_VERSION: 396062306a36Sopenharmony_ci err = ops->get_ver_msg(vf, msg); 396162306a36Sopenharmony_ci break; 396262306a36Sopenharmony_ci case VIRTCHNL_OP_GET_VF_RESOURCES: 396362306a36Sopenharmony_ci err = ops->get_vf_res_msg(vf, msg); 396462306a36Sopenharmony_ci if (ice_vf_init_vlan_stripping(vf)) 396562306a36Sopenharmony_ci dev_dbg(dev, "Failed to initialize VLAN stripping for VF %d\n", 396662306a36Sopenharmony_ci vf->vf_id); 396762306a36Sopenharmony_ci ice_vc_notify_vf_link_state(vf); 396862306a36Sopenharmony_ci break; 396962306a36Sopenharmony_ci case VIRTCHNL_OP_RESET_VF: 397062306a36Sopenharmony_ci ops->reset_vf(vf); 397162306a36Sopenharmony_ci break; 397262306a36Sopenharmony_ci case VIRTCHNL_OP_ADD_ETH_ADDR: 397362306a36Sopenharmony_ci err = ops->add_mac_addr_msg(vf, msg); 397462306a36Sopenharmony_ci break; 397562306a36Sopenharmony_ci case VIRTCHNL_OP_DEL_ETH_ADDR: 397662306a36Sopenharmony_ci err = ops->del_mac_addr_msg(vf, msg); 397762306a36Sopenharmony_ci break; 397862306a36Sopenharmony_ci case VIRTCHNL_OP_CONFIG_VSI_QUEUES: 397962306a36Sopenharmony_ci err = ops->cfg_qs_msg(vf, msg); 398062306a36Sopenharmony_ci break; 398162306a36Sopenharmony_ci case VIRTCHNL_OP_ENABLE_QUEUES: 398262306a36Sopenharmony_ci err = ops->ena_qs_msg(vf, msg); 398362306a36Sopenharmony_ci ice_vc_notify_vf_link_state(vf); 398462306a36Sopenharmony_ci break; 398562306a36Sopenharmony_ci case VIRTCHNL_OP_DISABLE_QUEUES: 398662306a36Sopenharmony_ci err = ops->dis_qs_msg(vf, msg); 398762306a36Sopenharmony_ci break; 398862306a36Sopenharmony_ci case VIRTCHNL_OP_REQUEST_QUEUES: 398962306a36Sopenharmony_ci err = ops->request_qs_msg(vf, msg); 399062306a36Sopenharmony_ci break; 399162306a36Sopenharmony_ci case VIRTCHNL_OP_CONFIG_IRQ_MAP: 399262306a36Sopenharmony_ci err = ops->cfg_irq_map_msg(vf, msg); 399362306a36Sopenharmony_ci break; 399462306a36Sopenharmony_ci case VIRTCHNL_OP_CONFIG_RSS_KEY: 399562306a36Sopenharmony_ci err = ops->config_rss_key(vf, msg); 399662306a36Sopenharmony_ci break; 399762306a36Sopenharmony_ci case VIRTCHNL_OP_CONFIG_RSS_LUT: 399862306a36Sopenharmony_ci err = ops->config_rss_lut(vf, msg); 399962306a36Sopenharmony_ci break; 400062306a36Sopenharmony_ci case VIRTCHNL_OP_GET_STATS: 400162306a36Sopenharmony_ci err = ops->get_stats_msg(vf, msg); 400262306a36Sopenharmony_ci break; 400362306a36Sopenharmony_ci case VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE: 400462306a36Sopenharmony_ci err = ops->cfg_promiscuous_mode_msg(vf, msg); 400562306a36Sopenharmony_ci break; 400662306a36Sopenharmony_ci case VIRTCHNL_OP_ADD_VLAN: 400762306a36Sopenharmony_ci err = ops->add_vlan_msg(vf, msg); 400862306a36Sopenharmony_ci break; 400962306a36Sopenharmony_ci case VIRTCHNL_OP_DEL_VLAN: 401062306a36Sopenharmony_ci err = ops->remove_vlan_msg(vf, msg); 401162306a36Sopenharmony_ci break; 401262306a36Sopenharmony_ci case VIRTCHNL_OP_GET_SUPPORTED_RXDIDS: 401362306a36Sopenharmony_ci err = ops->query_rxdid(vf); 401462306a36Sopenharmony_ci break; 401562306a36Sopenharmony_ci case VIRTCHNL_OP_GET_RSS_HENA_CAPS: 401662306a36Sopenharmony_ci err = ops->get_rss_hena(vf); 401762306a36Sopenharmony_ci break; 401862306a36Sopenharmony_ci case VIRTCHNL_OP_SET_RSS_HENA: 401962306a36Sopenharmony_ci err = ops->set_rss_hena_msg(vf, msg); 402062306a36Sopenharmony_ci break; 402162306a36Sopenharmony_ci case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING: 402262306a36Sopenharmony_ci err = ops->ena_vlan_stripping(vf); 402362306a36Sopenharmony_ci break; 402462306a36Sopenharmony_ci case VIRTCHNL_OP_DISABLE_VLAN_STRIPPING: 402562306a36Sopenharmony_ci err = ops->dis_vlan_stripping(vf); 402662306a36Sopenharmony_ci break; 402762306a36Sopenharmony_ci case VIRTCHNL_OP_ADD_FDIR_FILTER: 402862306a36Sopenharmony_ci err = ops->add_fdir_fltr_msg(vf, msg); 402962306a36Sopenharmony_ci break; 403062306a36Sopenharmony_ci case VIRTCHNL_OP_DEL_FDIR_FILTER: 403162306a36Sopenharmony_ci err = ops->del_fdir_fltr_msg(vf, msg); 403262306a36Sopenharmony_ci break; 403362306a36Sopenharmony_ci case VIRTCHNL_OP_ADD_RSS_CFG: 403462306a36Sopenharmony_ci err = ops->handle_rss_cfg_msg(vf, msg, true); 403562306a36Sopenharmony_ci break; 403662306a36Sopenharmony_ci case VIRTCHNL_OP_DEL_RSS_CFG: 403762306a36Sopenharmony_ci err = ops->handle_rss_cfg_msg(vf, msg, false); 403862306a36Sopenharmony_ci break; 403962306a36Sopenharmony_ci case VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS: 404062306a36Sopenharmony_ci err = ops->get_offload_vlan_v2_caps(vf); 404162306a36Sopenharmony_ci break; 404262306a36Sopenharmony_ci case VIRTCHNL_OP_ADD_VLAN_V2: 404362306a36Sopenharmony_ci err = ops->add_vlan_v2_msg(vf, msg); 404462306a36Sopenharmony_ci break; 404562306a36Sopenharmony_ci case VIRTCHNL_OP_DEL_VLAN_V2: 404662306a36Sopenharmony_ci err = ops->remove_vlan_v2_msg(vf, msg); 404762306a36Sopenharmony_ci break; 404862306a36Sopenharmony_ci case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2: 404962306a36Sopenharmony_ci err = ops->ena_vlan_stripping_v2_msg(vf, msg); 405062306a36Sopenharmony_ci break; 405162306a36Sopenharmony_ci case VIRTCHNL_OP_DISABLE_VLAN_STRIPPING_V2: 405262306a36Sopenharmony_ci err = ops->dis_vlan_stripping_v2_msg(vf, msg); 405362306a36Sopenharmony_ci break; 405462306a36Sopenharmony_ci case VIRTCHNL_OP_ENABLE_VLAN_INSERTION_V2: 405562306a36Sopenharmony_ci err = ops->ena_vlan_insertion_v2_msg(vf, msg); 405662306a36Sopenharmony_ci break; 405762306a36Sopenharmony_ci case VIRTCHNL_OP_DISABLE_VLAN_INSERTION_V2: 405862306a36Sopenharmony_ci err = ops->dis_vlan_insertion_v2_msg(vf, msg); 405962306a36Sopenharmony_ci break; 406062306a36Sopenharmony_ci case VIRTCHNL_OP_UNKNOWN: 406162306a36Sopenharmony_ci default: 406262306a36Sopenharmony_ci dev_err(dev, "Unsupported opcode %d from VF %d\n", v_opcode, 406362306a36Sopenharmony_ci vf_id); 406462306a36Sopenharmony_ci err = ice_vc_send_msg_to_vf(vf, v_opcode, 406562306a36Sopenharmony_ci VIRTCHNL_STATUS_ERR_NOT_SUPPORTED, 406662306a36Sopenharmony_ci NULL, 0); 406762306a36Sopenharmony_ci break; 406862306a36Sopenharmony_ci } 406962306a36Sopenharmony_ci if (err) { 407062306a36Sopenharmony_ci /* Helper function cares less about error return values here 407162306a36Sopenharmony_ci * as it is busy with pending work. 407262306a36Sopenharmony_ci */ 407362306a36Sopenharmony_ci dev_info(dev, "PF failed to honor VF %d, opcode %d, error %d\n", 407462306a36Sopenharmony_ci vf_id, v_opcode, err); 407562306a36Sopenharmony_ci } 407662306a36Sopenharmony_ci 407762306a36Sopenharmony_cifinish: 407862306a36Sopenharmony_ci mutex_unlock(&vf->cfg_lock); 407962306a36Sopenharmony_ci ice_put_vf(vf); 408062306a36Sopenharmony_ci} 4081