11f7ea1cdSQi Zhang // SPDX-License-Identifier: GPL-2.0 21f7ea1cdSQi Zhang /* Copyright (C) 2021, Intel Corporation. */ 31f7ea1cdSQi Zhang 41f7ea1cdSQi Zhang #include "ice.h" 51f7ea1cdSQi Zhang #include "ice_base.h" 61f7ea1cdSQi Zhang #include "ice_lib.h" 71f7ea1cdSQi Zhang #include "ice_flow.h" 8109aba47SJacob Keller #include "ice_vf_lib_private.h" 91f7ea1cdSQi Zhang 101f7ea1cdSQi Zhang #define to_fltr_conf_from_desc(p) \ 111f7ea1cdSQi Zhang container_of(p, struct virtchnl_fdir_fltr_conf, input) 121f7ea1cdSQi Zhang 131f7ea1cdSQi Zhang #define ICE_FLOW_PROF_TYPE_S 0 141f7ea1cdSQi Zhang #define ICE_FLOW_PROF_TYPE_M (0xFFFFFFFFULL << ICE_FLOW_PROF_TYPE_S) 151f7ea1cdSQi Zhang #define ICE_FLOW_PROF_VSI_S 32 161f7ea1cdSQi Zhang #define ICE_FLOW_PROF_VSI_M (0xFFFFFFFFULL << ICE_FLOW_PROF_VSI_S) 171f7ea1cdSQi Zhang 181f7ea1cdSQi Zhang /* Flow profile ID format: 191f7ea1cdSQi Zhang * [0:31] - flow type, flow + tun_offs 201f7ea1cdSQi Zhang * [32:63] - VSI index 211f7ea1cdSQi Zhang */ 221f7ea1cdSQi Zhang #define ICE_FLOW_PROF_FD(vsi, flow, tun_offs) \ 231f7ea1cdSQi Zhang ((u64)(((((flow) + (tun_offs)) & ICE_FLOW_PROF_TYPE_M)) | \ 241f7ea1cdSQi Zhang (((u64)(vsi) << ICE_FLOW_PROF_VSI_S) & ICE_FLOW_PROF_VSI_M))) 251f7ea1cdSQi Zhang 26ef9e4cc5SQi Zhang #define GTPU_TEID_OFFSET 4 27ef9e4cc5SQi Zhang #define GTPU_EH_QFI_OFFSET 1 28ef9e4cc5SQi Zhang #define GTPU_EH_QFI_MASK 0x3F 29213528feSQi Zhang #define PFCP_S_OFFSET 0 30213528feSQi Zhang #define PFCP_S_MASK 0x1 31213528feSQi Zhang #define PFCP_PORT_NR 8805 32213528feSQi Zhang 33213528feSQi Zhang #define FDIR_INSET_FLAG_ESP_S 0 34213528feSQi Zhang #define FDIR_INSET_FLAG_ESP_M BIT_ULL(FDIR_INSET_FLAG_ESP_S) 35213528feSQi Zhang #define FDIR_INSET_FLAG_ESP_UDP BIT_ULL(FDIR_INSET_FLAG_ESP_S) 36213528feSQi Zhang #define FDIR_INSET_FLAG_ESP_IPSEC (0ULL << FDIR_INSET_FLAG_ESP_S) 37ef9e4cc5SQi Zhang 38ef9e4cc5SQi Zhang enum ice_fdir_tunnel_type { 39ef9e4cc5SQi Zhang ICE_FDIR_TUNNEL_TYPE_NONE = 0, 40ef9e4cc5SQi Zhang ICE_FDIR_TUNNEL_TYPE_GTPU, 41ef9e4cc5SQi Zhang ICE_FDIR_TUNNEL_TYPE_GTPU_EH, 42ef9e4cc5SQi Zhang }; 43ef9e4cc5SQi Zhang 441f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf { 451f7ea1cdSQi Zhang struct ice_fdir_fltr input; 46ef9e4cc5SQi Zhang enum ice_fdir_tunnel_type ttype; 47213528feSQi Zhang u64 inset_flag; 48d6218317SQi Zhang u32 flow_id; 491f7ea1cdSQi Zhang }; 501f7ea1cdSQi Zhang 511f7ea1cdSQi Zhang struct virtchnl_fdir_inset_map { 521f7ea1cdSQi Zhang enum virtchnl_proto_hdr_field field; 531f7ea1cdSQi Zhang enum ice_flow_field fld; 54213528feSQi Zhang u64 flag; 55213528feSQi Zhang u64 mask; 561f7ea1cdSQi Zhang }; 571f7ea1cdSQi Zhang 581f7ea1cdSQi Zhang static const struct virtchnl_fdir_inset_map fdir_inset_map[] = { 59213528feSQi Zhang {VIRTCHNL_PROTO_HDR_ETH_ETHERTYPE, ICE_FLOW_FIELD_IDX_ETH_TYPE, 0, 0}, 60213528feSQi Zhang {VIRTCHNL_PROTO_HDR_IPV4_SRC, ICE_FLOW_FIELD_IDX_IPV4_SA, 0, 0}, 61213528feSQi Zhang {VIRTCHNL_PROTO_HDR_IPV4_DST, ICE_FLOW_FIELD_IDX_IPV4_DA, 0, 0}, 62213528feSQi Zhang {VIRTCHNL_PROTO_HDR_IPV4_DSCP, ICE_FLOW_FIELD_IDX_IPV4_DSCP, 0, 0}, 63213528feSQi Zhang {VIRTCHNL_PROTO_HDR_IPV4_TTL, ICE_FLOW_FIELD_IDX_IPV4_TTL, 0, 0}, 64213528feSQi Zhang {VIRTCHNL_PROTO_HDR_IPV4_PROT, ICE_FLOW_FIELD_IDX_IPV4_PROT, 0, 0}, 65213528feSQi Zhang {VIRTCHNL_PROTO_HDR_IPV6_SRC, ICE_FLOW_FIELD_IDX_IPV6_SA, 0, 0}, 66213528feSQi Zhang {VIRTCHNL_PROTO_HDR_IPV6_DST, ICE_FLOW_FIELD_IDX_IPV6_DA, 0, 0}, 67213528feSQi Zhang {VIRTCHNL_PROTO_HDR_IPV6_TC, ICE_FLOW_FIELD_IDX_IPV6_DSCP, 0, 0}, 68213528feSQi Zhang {VIRTCHNL_PROTO_HDR_IPV6_HOP_LIMIT, ICE_FLOW_FIELD_IDX_IPV6_TTL, 0, 0}, 69213528feSQi Zhang {VIRTCHNL_PROTO_HDR_IPV6_PROT, ICE_FLOW_FIELD_IDX_IPV6_PROT, 0, 0}, 70213528feSQi Zhang {VIRTCHNL_PROTO_HDR_UDP_SRC_PORT, ICE_FLOW_FIELD_IDX_UDP_SRC_PORT, 0, 0}, 71213528feSQi Zhang {VIRTCHNL_PROTO_HDR_UDP_DST_PORT, ICE_FLOW_FIELD_IDX_UDP_DST_PORT, 0, 0}, 72213528feSQi Zhang {VIRTCHNL_PROTO_HDR_TCP_SRC_PORT, ICE_FLOW_FIELD_IDX_TCP_SRC_PORT, 0, 0}, 73213528feSQi Zhang {VIRTCHNL_PROTO_HDR_TCP_DST_PORT, ICE_FLOW_FIELD_IDX_TCP_DST_PORT, 0, 0}, 74213528feSQi Zhang {VIRTCHNL_PROTO_HDR_SCTP_SRC_PORT, ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT, 0, 0}, 75213528feSQi Zhang {VIRTCHNL_PROTO_HDR_SCTP_DST_PORT, ICE_FLOW_FIELD_IDX_SCTP_DST_PORT, 0, 0}, 76213528feSQi Zhang {VIRTCHNL_PROTO_HDR_GTPU_IP_TEID, ICE_FLOW_FIELD_IDX_GTPU_IP_TEID, 0, 0}, 77213528feSQi Zhang {VIRTCHNL_PROTO_HDR_GTPU_EH_QFI, ICE_FLOW_FIELD_IDX_GTPU_EH_QFI, 0, 0}, 78213528feSQi Zhang {VIRTCHNL_PROTO_HDR_ESP_SPI, ICE_FLOW_FIELD_IDX_ESP_SPI, 79213528feSQi Zhang FDIR_INSET_FLAG_ESP_IPSEC, FDIR_INSET_FLAG_ESP_M}, 80213528feSQi Zhang {VIRTCHNL_PROTO_HDR_ESP_SPI, ICE_FLOW_FIELD_IDX_NAT_T_ESP_SPI, 81213528feSQi Zhang FDIR_INSET_FLAG_ESP_UDP, FDIR_INSET_FLAG_ESP_M}, 82213528feSQi Zhang {VIRTCHNL_PROTO_HDR_AH_SPI, ICE_FLOW_FIELD_IDX_AH_SPI, 0, 0}, 83213528feSQi Zhang {VIRTCHNL_PROTO_HDR_L2TPV3_SESS_ID, ICE_FLOW_FIELD_IDX_L2TPV3_SESS_ID, 0, 0}, 84213528feSQi Zhang {VIRTCHNL_PROTO_HDR_PFCP_S_FIELD, ICE_FLOW_FIELD_IDX_UDP_DST_PORT, 0, 0}, 851f7ea1cdSQi Zhang }; 861f7ea1cdSQi Zhang 871f7ea1cdSQi Zhang /** 881f7ea1cdSQi Zhang * ice_vc_fdir_param_check 891f7ea1cdSQi Zhang * @vf: pointer to the VF structure 901f7ea1cdSQi Zhang * @vsi_id: VF relative VSI ID 911f7ea1cdSQi Zhang * 921f7ea1cdSQi Zhang * Check for the valid VSI ID, PF's state and VF's state 931f7ea1cdSQi Zhang * 941f7ea1cdSQi Zhang * Return: 0 on success, and -EINVAL on error. 951f7ea1cdSQi Zhang */ 961f7ea1cdSQi Zhang static int 971f7ea1cdSQi Zhang ice_vc_fdir_param_check(struct ice_vf *vf, u16 vsi_id) 981f7ea1cdSQi Zhang { 991f7ea1cdSQi Zhang struct ice_pf *pf = vf->pf; 1001f7ea1cdSQi Zhang 1011f7ea1cdSQi Zhang if (!test_bit(ICE_FLAG_FD_ENA, pf->flags)) 1021f7ea1cdSQi Zhang return -EINVAL; 1031f7ea1cdSQi Zhang 1041f7ea1cdSQi Zhang if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) 1051f7ea1cdSQi Zhang return -EINVAL; 1061f7ea1cdSQi Zhang 1071f7ea1cdSQi Zhang if (!(vf->driver_caps & VIRTCHNL_VF_OFFLOAD_FDIR_PF)) 1081f7ea1cdSQi Zhang return -EINVAL; 1091f7ea1cdSQi Zhang 1101f7ea1cdSQi Zhang if (vsi_id != vf->lan_vsi_num) 1111f7ea1cdSQi Zhang return -EINVAL; 1121f7ea1cdSQi Zhang 1131f7ea1cdSQi Zhang if (!ice_vc_isvalid_vsi_id(vf, vsi_id)) 1141f7ea1cdSQi Zhang return -EINVAL; 1151f7ea1cdSQi Zhang 116772dec64SBrett Creeley if (!ice_get_vf_vsi(vf)) 1171f7ea1cdSQi Zhang return -EINVAL; 1181f7ea1cdSQi Zhang 1191f7ea1cdSQi Zhang return 0; 1201f7ea1cdSQi Zhang } 1211f7ea1cdSQi Zhang 1221f7ea1cdSQi Zhang /** 1231f7ea1cdSQi Zhang * ice_vf_start_ctrl_vsi 1241f7ea1cdSQi Zhang * @vf: pointer to the VF structure 1251f7ea1cdSQi Zhang * 1261f7ea1cdSQi Zhang * Allocate ctrl_vsi for the first time and open the ctrl_vsi port for VF 1271f7ea1cdSQi Zhang * 1281f7ea1cdSQi Zhang * Return: 0 on success, and other on error. 1291f7ea1cdSQi Zhang */ 1301f7ea1cdSQi Zhang static int ice_vf_start_ctrl_vsi(struct ice_vf *vf) 1311f7ea1cdSQi Zhang { 1321f7ea1cdSQi Zhang struct ice_pf *pf = vf->pf; 1331f7ea1cdSQi Zhang struct ice_vsi *ctrl_vsi; 1341f7ea1cdSQi Zhang struct device *dev; 1351f7ea1cdSQi Zhang int err; 1361f7ea1cdSQi Zhang 1371f7ea1cdSQi Zhang dev = ice_pf_to_dev(pf); 1381f7ea1cdSQi Zhang if (vf->ctrl_vsi_idx != ICE_NO_VSI) 1391f7ea1cdSQi Zhang return -EEXIST; 1401f7ea1cdSQi Zhang 1411f7ea1cdSQi Zhang ctrl_vsi = ice_vf_ctrl_vsi_setup(vf); 1421f7ea1cdSQi Zhang if (!ctrl_vsi) { 1431f7ea1cdSQi Zhang dev_dbg(dev, "Could not setup control VSI for VF %d\n", 1441f7ea1cdSQi Zhang vf->vf_id); 1451f7ea1cdSQi Zhang return -ENOMEM; 1461f7ea1cdSQi Zhang } 1471f7ea1cdSQi Zhang 1481f7ea1cdSQi Zhang err = ice_vsi_open_ctrl(ctrl_vsi); 1491f7ea1cdSQi Zhang if (err) { 1501f7ea1cdSQi Zhang dev_dbg(dev, "Could not open control VSI for VF %d\n", 1511f7ea1cdSQi Zhang vf->vf_id); 1521f7ea1cdSQi Zhang goto err_vsi_open; 1531f7ea1cdSQi Zhang } 1541f7ea1cdSQi Zhang 1551f7ea1cdSQi Zhang return 0; 1561f7ea1cdSQi Zhang 1571f7ea1cdSQi Zhang err_vsi_open: 1581f7ea1cdSQi Zhang ice_vsi_release(ctrl_vsi); 1591f7ea1cdSQi Zhang if (vf->ctrl_vsi_idx != ICE_NO_VSI) { 1601f7ea1cdSQi Zhang pf->vsi[vf->ctrl_vsi_idx] = NULL; 1611f7ea1cdSQi Zhang vf->ctrl_vsi_idx = ICE_NO_VSI; 1621f7ea1cdSQi Zhang } 1631f7ea1cdSQi Zhang return err; 1641f7ea1cdSQi Zhang } 1651f7ea1cdSQi Zhang 1661f7ea1cdSQi Zhang /** 1671f7ea1cdSQi Zhang * ice_vc_fdir_alloc_prof - allocate profile for this filter flow type 1681f7ea1cdSQi Zhang * @vf: pointer to the VF structure 1691f7ea1cdSQi Zhang * @flow: filter flow type 1701f7ea1cdSQi Zhang * 1711f7ea1cdSQi Zhang * Return: 0 on success, and other on error. 1721f7ea1cdSQi Zhang */ 1731f7ea1cdSQi Zhang static int 1741f7ea1cdSQi Zhang ice_vc_fdir_alloc_prof(struct ice_vf *vf, enum ice_fltr_ptype flow) 1751f7ea1cdSQi Zhang { 1761f7ea1cdSQi Zhang struct ice_vf_fdir *fdir = &vf->fdir; 1771f7ea1cdSQi Zhang 1781f7ea1cdSQi Zhang if (!fdir->fdir_prof) { 1791f7ea1cdSQi Zhang fdir->fdir_prof = devm_kcalloc(ice_pf_to_dev(vf->pf), 1801f7ea1cdSQi Zhang ICE_FLTR_PTYPE_MAX, 1811f7ea1cdSQi Zhang sizeof(*fdir->fdir_prof), 1821f7ea1cdSQi Zhang GFP_KERNEL); 1831f7ea1cdSQi Zhang if (!fdir->fdir_prof) 1841f7ea1cdSQi Zhang return -ENOMEM; 1851f7ea1cdSQi Zhang } 1861f7ea1cdSQi Zhang 1871f7ea1cdSQi Zhang if (!fdir->fdir_prof[flow]) { 1881f7ea1cdSQi Zhang fdir->fdir_prof[flow] = devm_kzalloc(ice_pf_to_dev(vf->pf), 1891f7ea1cdSQi Zhang sizeof(**fdir->fdir_prof), 1901f7ea1cdSQi Zhang GFP_KERNEL); 1911f7ea1cdSQi Zhang if (!fdir->fdir_prof[flow]) 1921f7ea1cdSQi Zhang return -ENOMEM; 1931f7ea1cdSQi Zhang } 1941f7ea1cdSQi Zhang 1951f7ea1cdSQi Zhang return 0; 1961f7ea1cdSQi Zhang } 1971f7ea1cdSQi Zhang 1981f7ea1cdSQi Zhang /** 1991f7ea1cdSQi Zhang * ice_vc_fdir_free_prof - free profile for this filter flow type 2001f7ea1cdSQi Zhang * @vf: pointer to the VF structure 2011f7ea1cdSQi Zhang * @flow: filter flow type 2021f7ea1cdSQi Zhang */ 2031f7ea1cdSQi Zhang static void 2041f7ea1cdSQi Zhang ice_vc_fdir_free_prof(struct ice_vf *vf, enum ice_fltr_ptype flow) 2051f7ea1cdSQi Zhang { 2061f7ea1cdSQi Zhang struct ice_vf_fdir *fdir = &vf->fdir; 2071f7ea1cdSQi Zhang 2081f7ea1cdSQi Zhang if (!fdir->fdir_prof) 2091f7ea1cdSQi Zhang return; 2101f7ea1cdSQi Zhang 2111f7ea1cdSQi Zhang if (!fdir->fdir_prof[flow]) 2121f7ea1cdSQi Zhang return; 2131f7ea1cdSQi Zhang 2141f7ea1cdSQi Zhang devm_kfree(ice_pf_to_dev(vf->pf), fdir->fdir_prof[flow]); 2151f7ea1cdSQi Zhang fdir->fdir_prof[flow] = NULL; 2161f7ea1cdSQi Zhang } 2171f7ea1cdSQi Zhang 2181f7ea1cdSQi Zhang /** 2191f7ea1cdSQi Zhang * ice_vc_fdir_free_prof_all - free all the profile for this VF 2201f7ea1cdSQi Zhang * @vf: pointer to the VF structure 2211f7ea1cdSQi Zhang */ 2221f7ea1cdSQi Zhang static void ice_vc_fdir_free_prof_all(struct ice_vf *vf) 2231f7ea1cdSQi Zhang { 2241f7ea1cdSQi Zhang struct ice_vf_fdir *fdir = &vf->fdir; 2251f7ea1cdSQi Zhang enum ice_fltr_ptype flow; 2261f7ea1cdSQi Zhang 2271f7ea1cdSQi Zhang if (!fdir->fdir_prof) 2281f7ea1cdSQi Zhang return; 2291f7ea1cdSQi Zhang 2301f7ea1cdSQi Zhang for (flow = ICE_FLTR_PTYPE_NONF_NONE; flow < ICE_FLTR_PTYPE_MAX; flow++) 2311f7ea1cdSQi Zhang ice_vc_fdir_free_prof(vf, flow); 2321f7ea1cdSQi Zhang 2331f7ea1cdSQi Zhang devm_kfree(ice_pf_to_dev(vf->pf), fdir->fdir_prof); 2341f7ea1cdSQi Zhang fdir->fdir_prof = NULL; 2351f7ea1cdSQi Zhang } 2361f7ea1cdSQi Zhang 2371f7ea1cdSQi Zhang /** 2381f7ea1cdSQi Zhang * ice_vc_fdir_parse_flow_fld 2391f7ea1cdSQi Zhang * @proto_hdr: virtual channel protocol filter header 2401f7ea1cdSQi Zhang * @conf: FDIR configuration for each filter 2411f7ea1cdSQi Zhang * @fld: field type array 2421f7ea1cdSQi Zhang * @fld_cnt: field counter 2431f7ea1cdSQi Zhang * 2441f7ea1cdSQi Zhang * Parse the virtual channel filter header and store them into field type array 2451f7ea1cdSQi Zhang * 2461f7ea1cdSQi Zhang * Return: 0 on success, and other on error. 2471f7ea1cdSQi Zhang */ 2481f7ea1cdSQi Zhang static int 2491f7ea1cdSQi Zhang ice_vc_fdir_parse_flow_fld(struct virtchnl_proto_hdr *proto_hdr, 2501f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf, 2511f7ea1cdSQi Zhang enum ice_flow_field *fld, int *fld_cnt) 2521f7ea1cdSQi Zhang { 2531f7ea1cdSQi Zhang struct virtchnl_proto_hdr hdr; 2541f7ea1cdSQi Zhang u32 i; 2551f7ea1cdSQi Zhang 2561f7ea1cdSQi Zhang memcpy(&hdr, proto_hdr, sizeof(hdr)); 2571f7ea1cdSQi Zhang 2581f7ea1cdSQi Zhang for (i = 0; (i < ARRAY_SIZE(fdir_inset_map)) && 2591f7ea1cdSQi Zhang VIRTCHNL_GET_PROTO_HDR_FIELD(&hdr); i++) 2601f7ea1cdSQi Zhang if (VIRTCHNL_TEST_PROTO_HDR(&hdr, fdir_inset_map[i].field)) { 261213528feSQi Zhang if (fdir_inset_map[i].mask && 262213528feSQi Zhang ((fdir_inset_map[i].mask & conf->inset_flag) != 263213528feSQi Zhang fdir_inset_map[i].flag)) 264213528feSQi Zhang continue; 265213528feSQi Zhang 2661f7ea1cdSQi Zhang fld[*fld_cnt] = fdir_inset_map[i].fld; 2671f7ea1cdSQi Zhang *fld_cnt += 1; 2681f7ea1cdSQi Zhang if (*fld_cnt >= ICE_FLOW_FIELD_IDX_MAX) 2691f7ea1cdSQi Zhang return -EINVAL; 2701f7ea1cdSQi Zhang VIRTCHNL_DEL_PROTO_HDR_FIELD(&hdr, 2711f7ea1cdSQi Zhang fdir_inset_map[i].field); 2721f7ea1cdSQi Zhang } 2731f7ea1cdSQi Zhang 2741f7ea1cdSQi Zhang return 0; 2751f7ea1cdSQi Zhang } 2761f7ea1cdSQi Zhang 2771f7ea1cdSQi Zhang /** 2781f7ea1cdSQi Zhang * ice_vc_fdir_set_flow_fld 2791f7ea1cdSQi Zhang * @vf: pointer to the VF structure 2801f7ea1cdSQi Zhang * @fltr: virtual channel add cmd buffer 2811f7ea1cdSQi Zhang * @conf: FDIR configuration for each filter 2821f7ea1cdSQi Zhang * @seg: array of one or more packet segments that describe the flow 2831f7ea1cdSQi Zhang * 2841f7ea1cdSQi Zhang * Parse the virtual channel add msg buffer's field vector and store them into 2851f7ea1cdSQi Zhang * flow's packet segment field 2861f7ea1cdSQi Zhang * 2871f7ea1cdSQi Zhang * Return: 0 on success, and other on error. 2881f7ea1cdSQi Zhang */ 2891f7ea1cdSQi Zhang static int 2901f7ea1cdSQi Zhang ice_vc_fdir_set_flow_fld(struct ice_vf *vf, struct virtchnl_fdir_add *fltr, 2911f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf, 2921f7ea1cdSQi Zhang struct ice_flow_seg_info *seg) 2931f7ea1cdSQi Zhang { 2941f7ea1cdSQi Zhang struct virtchnl_fdir_rule *rule = &fltr->rule_cfg; 2951f7ea1cdSQi Zhang enum ice_flow_field fld[ICE_FLOW_FIELD_IDX_MAX]; 2961f7ea1cdSQi Zhang struct device *dev = ice_pf_to_dev(vf->pf); 2971f7ea1cdSQi Zhang struct virtchnl_proto_hdrs *proto; 2981f7ea1cdSQi Zhang int fld_cnt = 0; 2991f7ea1cdSQi Zhang int i; 3001f7ea1cdSQi Zhang 3011f7ea1cdSQi Zhang proto = &rule->proto_hdrs; 3021f7ea1cdSQi Zhang for (i = 0; i < proto->count; i++) { 3031f7ea1cdSQi Zhang struct virtchnl_proto_hdr *hdr = &proto->proto_hdr[i]; 3041f7ea1cdSQi Zhang int ret; 3051f7ea1cdSQi Zhang 3061f7ea1cdSQi Zhang ret = ice_vc_fdir_parse_flow_fld(hdr, conf, fld, &fld_cnt); 3071f7ea1cdSQi Zhang if (ret) 3081f7ea1cdSQi Zhang return ret; 3091f7ea1cdSQi Zhang } 3101f7ea1cdSQi Zhang 3111f7ea1cdSQi Zhang if (fld_cnt == 0) { 3121f7ea1cdSQi Zhang dev_dbg(dev, "Empty input set for VF %d\n", vf->vf_id); 3131f7ea1cdSQi Zhang return -EINVAL; 3141f7ea1cdSQi Zhang } 3151f7ea1cdSQi Zhang 3161f7ea1cdSQi Zhang for (i = 0; i < fld_cnt; i++) 3171f7ea1cdSQi Zhang ice_flow_set_fld(seg, fld[i], 3181f7ea1cdSQi Zhang ICE_FLOW_FLD_OFF_INVAL, 3191f7ea1cdSQi Zhang ICE_FLOW_FLD_OFF_INVAL, 3201f7ea1cdSQi Zhang ICE_FLOW_FLD_OFF_INVAL, false); 3211f7ea1cdSQi Zhang 3221f7ea1cdSQi Zhang return 0; 3231f7ea1cdSQi Zhang } 3241f7ea1cdSQi Zhang 3251f7ea1cdSQi Zhang /** 3261f7ea1cdSQi Zhang * ice_vc_fdir_set_flow_hdr - config the flow's packet segment header 3271f7ea1cdSQi Zhang * @vf: pointer to the VF structure 3281f7ea1cdSQi Zhang * @conf: FDIR configuration for each filter 3291f7ea1cdSQi Zhang * @seg: array of one or more packet segments that describe the flow 3301f7ea1cdSQi Zhang * 3311f7ea1cdSQi Zhang * Return: 0 on success, and other on error. 3321f7ea1cdSQi Zhang */ 3331f7ea1cdSQi Zhang static int 3341f7ea1cdSQi Zhang ice_vc_fdir_set_flow_hdr(struct ice_vf *vf, 3351f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf, 3361f7ea1cdSQi Zhang struct ice_flow_seg_info *seg) 3371f7ea1cdSQi Zhang { 3381f7ea1cdSQi Zhang enum ice_fltr_ptype flow = conf->input.flow_type; 339ef9e4cc5SQi Zhang enum ice_fdir_tunnel_type ttype = conf->ttype; 3401f7ea1cdSQi Zhang struct device *dev = ice_pf_to_dev(vf->pf); 3411f7ea1cdSQi Zhang 3421f7ea1cdSQi Zhang switch (flow) { 34321606584SQi Zhang case ICE_FLTR_PTYPE_NON_IP_L2: 34421606584SQi Zhang ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_ETH_NON_IP); 34521606584SQi Zhang break; 346213528feSQi Zhang case ICE_FLTR_PTYPE_NONF_IPV4_L2TPV3: 347213528feSQi Zhang ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_L2TPV3 | 348213528feSQi Zhang ICE_FLOW_SEG_HDR_IPV4 | 349213528feSQi Zhang ICE_FLOW_SEG_HDR_IPV_OTHER); 350213528feSQi Zhang break; 351213528feSQi Zhang case ICE_FLTR_PTYPE_NONF_IPV4_ESP: 352213528feSQi Zhang ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_ESP | 353213528feSQi Zhang ICE_FLOW_SEG_HDR_IPV4 | 354213528feSQi Zhang ICE_FLOW_SEG_HDR_IPV_OTHER); 355213528feSQi Zhang break; 356213528feSQi Zhang case ICE_FLTR_PTYPE_NONF_IPV4_AH: 357213528feSQi Zhang ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_AH | 358213528feSQi Zhang ICE_FLOW_SEG_HDR_IPV4 | 359213528feSQi Zhang ICE_FLOW_SEG_HDR_IPV_OTHER); 360213528feSQi Zhang break; 361213528feSQi Zhang case ICE_FLTR_PTYPE_NONF_IPV4_NAT_T_ESP: 362213528feSQi Zhang ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_NAT_T_ESP | 363213528feSQi Zhang ICE_FLOW_SEG_HDR_IPV4 | 364213528feSQi Zhang ICE_FLOW_SEG_HDR_IPV_OTHER); 365213528feSQi Zhang break; 366213528feSQi Zhang case ICE_FLTR_PTYPE_NONF_IPV4_PFCP_NODE: 367213528feSQi Zhang ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_PFCP_NODE | 368213528feSQi Zhang ICE_FLOW_SEG_HDR_IPV4 | 369213528feSQi Zhang ICE_FLOW_SEG_HDR_IPV_OTHER); 370213528feSQi Zhang break; 371213528feSQi Zhang case ICE_FLTR_PTYPE_NONF_IPV4_PFCP_SESSION: 372213528feSQi Zhang ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_PFCP_SESSION | 373213528feSQi Zhang ICE_FLOW_SEG_HDR_IPV4 | 374213528feSQi Zhang ICE_FLOW_SEG_HDR_IPV_OTHER); 375213528feSQi Zhang break; 3761f7ea1cdSQi Zhang case ICE_FLTR_PTYPE_NONF_IPV4_OTHER: 3771f7ea1cdSQi Zhang ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV4 | 3781f7ea1cdSQi Zhang ICE_FLOW_SEG_HDR_IPV_OTHER); 3791f7ea1cdSQi Zhang break; 3801f7ea1cdSQi Zhang case ICE_FLTR_PTYPE_NONF_IPV4_TCP: 3811f7ea1cdSQi Zhang ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_TCP | 3821f7ea1cdSQi Zhang ICE_FLOW_SEG_HDR_IPV4 | 3831f7ea1cdSQi Zhang ICE_FLOW_SEG_HDR_IPV_OTHER); 3841f7ea1cdSQi Zhang break; 3851f7ea1cdSQi Zhang case ICE_FLTR_PTYPE_NONF_IPV4_UDP: 3861f7ea1cdSQi Zhang ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_UDP | 3871f7ea1cdSQi Zhang ICE_FLOW_SEG_HDR_IPV4 | 3881f7ea1cdSQi Zhang ICE_FLOW_SEG_HDR_IPV_OTHER); 3891f7ea1cdSQi Zhang break; 390ef9e4cc5SQi Zhang case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_UDP: 391ef9e4cc5SQi Zhang case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_TCP: 392ef9e4cc5SQi Zhang case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_ICMP: 393ef9e4cc5SQi Zhang case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_OTHER: 394ef9e4cc5SQi Zhang if (ttype == ICE_FDIR_TUNNEL_TYPE_GTPU) { 395ef9e4cc5SQi Zhang ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_GTPU_IP | 396ef9e4cc5SQi Zhang ICE_FLOW_SEG_HDR_IPV4 | 397ef9e4cc5SQi Zhang ICE_FLOW_SEG_HDR_IPV_OTHER); 398ef9e4cc5SQi Zhang } else if (ttype == ICE_FDIR_TUNNEL_TYPE_GTPU_EH) { 399ef9e4cc5SQi Zhang ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_GTPU_EH | 400ef9e4cc5SQi Zhang ICE_FLOW_SEG_HDR_GTPU_IP | 401ef9e4cc5SQi Zhang ICE_FLOW_SEG_HDR_IPV4 | 402ef9e4cc5SQi Zhang ICE_FLOW_SEG_HDR_IPV_OTHER); 403ef9e4cc5SQi Zhang } else { 404ef9e4cc5SQi Zhang dev_dbg(dev, "Invalid tunnel type 0x%x for VF %d\n", 405ef9e4cc5SQi Zhang flow, vf->vf_id); 406ef9e4cc5SQi Zhang return -EINVAL; 407ef9e4cc5SQi Zhang } 408ef9e4cc5SQi Zhang break; 4091f7ea1cdSQi Zhang case ICE_FLTR_PTYPE_NONF_IPV4_SCTP: 4101f7ea1cdSQi Zhang ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_SCTP | 4111f7ea1cdSQi Zhang ICE_FLOW_SEG_HDR_IPV4 | 4121f7ea1cdSQi Zhang ICE_FLOW_SEG_HDR_IPV_OTHER); 4131f7ea1cdSQi Zhang break; 414213528feSQi Zhang case ICE_FLTR_PTYPE_NONF_IPV6_L2TPV3: 415213528feSQi Zhang ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_L2TPV3 | 416213528feSQi Zhang ICE_FLOW_SEG_HDR_IPV6 | 417213528feSQi Zhang ICE_FLOW_SEG_HDR_IPV_OTHER); 418213528feSQi Zhang break; 419213528feSQi Zhang case ICE_FLTR_PTYPE_NONF_IPV6_ESP: 420213528feSQi Zhang ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_ESP | 421213528feSQi Zhang ICE_FLOW_SEG_HDR_IPV6 | 422213528feSQi Zhang ICE_FLOW_SEG_HDR_IPV_OTHER); 423213528feSQi Zhang break; 424213528feSQi Zhang case ICE_FLTR_PTYPE_NONF_IPV6_AH: 425213528feSQi Zhang ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_AH | 426213528feSQi Zhang ICE_FLOW_SEG_HDR_IPV6 | 427213528feSQi Zhang ICE_FLOW_SEG_HDR_IPV_OTHER); 428213528feSQi Zhang break; 429213528feSQi Zhang case ICE_FLTR_PTYPE_NONF_IPV6_NAT_T_ESP: 430213528feSQi Zhang ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_NAT_T_ESP | 431213528feSQi Zhang ICE_FLOW_SEG_HDR_IPV6 | 432213528feSQi Zhang ICE_FLOW_SEG_HDR_IPV_OTHER); 433213528feSQi Zhang break; 434213528feSQi Zhang case ICE_FLTR_PTYPE_NONF_IPV6_PFCP_NODE: 435213528feSQi Zhang ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_PFCP_NODE | 436213528feSQi Zhang ICE_FLOW_SEG_HDR_IPV6 | 437213528feSQi Zhang ICE_FLOW_SEG_HDR_IPV_OTHER); 438213528feSQi Zhang break; 439213528feSQi Zhang case ICE_FLTR_PTYPE_NONF_IPV6_PFCP_SESSION: 440213528feSQi Zhang ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_PFCP_SESSION | 441213528feSQi Zhang ICE_FLOW_SEG_HDR_IPV6 | 442213528feSQi Zhang ICE_FLOW_SEG_HDR_IPV_OTHER); 443213528feSQi Zhang break; 4441f7ea1cdSQi Zhang case ICE_FLTR_PTYPE_NONF_IPV6_OTHER: 4451f7ea1cdSQi Zhang ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV6 | 4461f7ea1cdSQi Zhang ICE_FLOW_SEG_HDR_IPV_OTHER); 4471f7ea1cdSQi Zhang break; 4481f7ea1cdSQi Zhang case ICE_FLTR_PTYPE_NONF_IPV6_TCP: 4491f7ea1cdSQi Zhang ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_TCP | 4501f7ea1cdSQi Zhang ICE_FLOW_SEG_HDR_IPV6 | 4511f7ea1cdSQi Zhang ICE_FLOW_SEG_HDR_IPV_OTHER); 4521f7ea1cdSQi Zhang break; 4531f7ea1cdSQi Zhang case ICE_FLTR_PTYPE_NONF_IPV6_UDP: 4541f7ea1cdSQi Zhang ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_UDP | 4551f7ea1cdSQi Zhang ICE_FLOW_SEG_HDR_IPV6 | 4561f7ea1cdSQi Zhang ICE_FLOW_SEG_HDR_IPV_OTHER); 4571f7ea1cdSQi Zhang break; 4581f7ea1cdSQi Zhang case ICE_FLTR_PTYPE_NONF_IPV6_SCTP: 4591f7ea1cdSQi Zhang ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_SCTP | 4601f7ea1cdSQi Zhang ICE_FLOW_SEG_HDR_IPV6 | 4611f7ea1cdSQi Zhang ICE_FLOW_SEG_HDR_IPV_OTHER); 4621f7ea1cdSQi Zhang break; 4631f7ea1cdSQi Zhang default: 4641f7ea1cdSQi Zhang dev_dbg(dev, "Invalid flow type 0x%x for VF %d failed\n", 4651f7ea1cdSQi Zhang flow, vf->vf_id); 4661f7ea1cdSQi Zhang return -EINVAL; 4671f7ea1cdSQi Zhang } 4681f7ea1cdSQi Zhang 4691f7ea1cdSQi Zhang return 0; 4701f7ea1cdSQi Zhang } 4711f7ea1cdSQi Zhang 4721f7ea1cdSQi Zhang /** 4731f7ea1cdSQi Zhang * ice_vc_fdir_rem_prof - remove profile for this filter flow type 4741f7ea1cdSQi Zhang * @vf: pointer to the VF structure 4751f7ea1cdSQi Zhang * @flow: filter flow type 4761f7ea1cdSQi Zhang * @tun: 0 implies non-tunnel type filter, 1 implies tunnel type filter 4771f7ea1cdSQi Zhang */ 4781f7ea1cdSQi Zhang static void 4791f7ea1cdSQi Zhang ice_vc_fdir_rem_prof(struct ice_vf *vf, enum ice_fltr_ptype flow, int tun) 4801f7ea1cdSQi Zhang { 4811f7ea1cdSQi Zhang struct ice_vf_fdir *fdir = &vf->fdir; 4821f7ea1cdSQi Zhang struct ice_fd_hw_prof *vf_prof; 4831f7ea1cdSQi Zhang struct ice_pf *pf = vf->pf; 4841f7ea1cdSQi Zhang struct ice_vsi *vf_vsi; 4851f7ea1cdSQi Zhang struct device *dev; 4861f7ea1cdSQi Zhang struct ice_hw *hw; 4871f7ea1cdSQi Zhang u64 prof_id; 4881f7ea1cdSQi Zhang int i; 4891f7ea1cdSQi Zhang 4901f7ea1cdSQi Zhang dev = ice_pf_to_dev(pf); 4911f7ea1cdSQi Zhang hw = &pf->hw; 4921f7ea1cdSQi Zhang if (!fdir->fdir_prof || !fdir->fdir_prof[flow]) 4931f7ea1cdSQi Zhang return; 4941f7ea1cdSQi Zhang 4951f7ea1cdSQi Zhang vf_prof = fdir->fdir_prof[flow]; 4961f7ea1cdSQi Zhang 497772dec64SBrett Creeley vf_vsi = ice_get_vf_vsi(vf); 4981f7ea1cdSQi Zhang if (!vf_vsi) { 4991f7ea1cdSQi Zhang dev_dbg(dev, "NULL vf %d vsi pointer\n", vf->vf_id); 5001f7ea1cdSQi Zhang return; 5011f7ea1cdSQi Zhang } 5021f7ea1cdSQi Zhang 5031f7ea1cdSQi Zhang if (!fdir->prof_entry_cnt[flow][tun]) 5041f7ea1cdSQi Zhang return; 5051f7ea1cdSQi Zhang 5061f7ea1cdSQi Zhang prof_id = ICE_FLOW_PROF_FD(vf_vsi->vsi_num, 5071f7ea1cdSQi Zhang flow, tun ? ICE_FLTR_PTYPE_MAX : 0); 5081f7ea1cdSQi Zhang 5091f7ea1cdSQi Zhang for (i = 0; i < fdir->prof_entry_cnt[flow][tun]; i++) 5101f7ea1cdSQi Zhang if (vf_prof->entry_h[i][tun]) { 5111f7ea1cdSQi Zhang u16 vsi_num = ice_get_hw_vsi_num(hw, vf_prof->vsi_h[i]); 5121f7ea1cdSQi Zhang 5131f7ea1cdSQi Zhang ice_rem_prof_id_flow(hw, ICE_BLK_FD, vsi_num, prof_id); 5141f7ea1cdSQi Zhang ice_flow_rem_entry(hw, ICE_BLK_FD, 5151f7ea1cdSQi Zhang vf_prof->entry_h[i][tun]); 5161f7ea1cdSQi Zhang vf_prof->entry_h[i][tun] = 0; 5171f7ea1cdSQi Zhang } 5181f7ea1cdSQi Zhang 5191f7ea1cdSQi Zhang ice_flow_rem_prof(hw, ICE_BLK_FD, prof_id); 5201f7ea1cdSQi Zhang devm_kfree(dev, vf_prof->fdir_seg[tun]); 5211f7ea1cdSQi Zhang vf_prof->fdir_seg[tun] = NULL; 5221f7ea1cdSQi Zhang 5231f7ea1cdSQi Zhang for (i = 0; i < vf_prof->cnt; i++) 5241f7ea1cdSQi Zhang vf_prof->vsi_h[i] = 0; 5251f7ea1cdSQi Zhang 5261f7ea1cdSQi Zhang fdir->prof_entry_cnt[flow][tun] = 0; 5271f7ea1cdSQi Zhang } 5281f7ea1cdSQi Zhang 5291f7ea1cdSQi Zhang /** 5301f7ea1cdSQi Zhang * ice_vc_fdir_rem_prof_all - remove profile for this VF 5311f7ea1cdSQi Zhang * @vf: pointer to the VF structure 5321f7ea1cdSQi Zhang */ 5331f7ea1cdSQi Zhang static void ice_vc_fdir_rem_prof_all(struct ice_vf *vf) 5341f7ea1cdSQi Zhang { 5351f7ea1cdSQi Zhang enum ice_fltr_ptype flow; 5361f7ea1cdSQi Zhang 5371f7ea1cdSQi Zhang for (flow = ICE_FLTR_PTYPE_NONF_NONE; 5381f7ea1cdSQi Zhang flow < ICE_FLTR_PTYPE_MAX; flow++) { 5391f7ea1cdSQi Zhang ice_vc_fdir_rem_prof(vf, flow, 0); 5401f7ea1cdSQi Zhang ice_vc_fdir_rem_prof(vf, flow, 1); 5411f7ea1cdSQi Zhang } 5421f7ea1cdSQi Zhang } 5431f7ea1cdSQi Zhang 5441f7ea1cdSQi Zhang /** 54529486b6dSJunfeng Guo * ice_vc_fdir_has_prof_conflict 54629486b6dSJunfeng Guo * @vf: pointer to the VF structure 54729486b6dSJunfeng Guo * @conf: FDIR configuration for each filter 54829486b6dSJunfeng Guo * 54929486b6dSJunfeng Guo * Check if @conf has conflicting profile with existing profiles 55029486b6dSJunfeng Guo * 55129486b6dSJunfeng Guo * Return: true on success, and false on error. 55229486b6dSJunfeng Guo */ 55329486b6dSJunfeng Guo static bool 55429486b6dSJunfeng Guo ice_vc_fdir_has_prof_conflict(struct ice_vf *vf, 55529486b6dSJunfeng Guo struct virtchnl_fdir_fltr_conf *conf) 55629486b6dSJunfeng Guo { 55729486b6dSJunfeng Guo struct ice_fdir_fltr *desc; 55829486b6dSJunfeng Guo 55929486b6dSJunfeng Guo list_for_each_entry(desc, &vf->fdir.fdir_rule_list, fltr_node) { 56029486b6dSJunfeng Guo struct virtchnl_fdir_fltr_conf *existing_conf; 56129486b6dSJunfeng Guo enum ice_fltr_ptype flow_type_a, flow_type_b; 56229486b6dSJunfeng Guo struct ice_fdir_fltr *a, *b; 56329486b6dSJunfeng Guo 56429486b6dSJunfeng Guo existing_conf = to_fltr_conf_from_desc(desc); 56529486b6dSJunfeng Guo a = &existing_conf->input; 56629486b6dSJunfeng Guo b = &conf->input; 56729486b6dSJunfeng Guo flow_type_a = a->flow_type; 56829486b6dSJunfeng Guo flow_type_b = b->flow_type; 56929486b6dSJunfeng Guo 57029486b6dSJunfeng Guo /* No need to compare two rules with different tunnel types or 57129486b6dSJunfeng Guo * with the same protocol type. 57229486b6dSJunfeng Guo */ 57329486b6dSJunfeng Guo if (existing_conf->ttype != conf->ttype || 57429486b6dSJunfeng Guo flow_type_a == flow_type_b) 57529486b6dSJunfeng Guo continue; 57629486b6dSJunfeng Guo 57729486b6dSJunfeng Guo switch (flow_type_a) { 57829486b6dSJunfeng Guo case ICE_FLTR_PTYPE_NONF_IPV4_UDP: 57929486b6dSJunfeng Guo case ICE_FLTR_PTYPE_NONF_IPV4_TCP: 58029486b6dSJunfeng Guo case ICE_FLTR_PTYPE_NONF_IPV4_SCTP: 58129486b6dSJunfeng Guo if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_OTHER) 58229486b6dSJunfeng Guo return true; 58329486b6dSJunfeng Guo break; 58429486b6dSJunfeng Guo case ICE_FLTR_PTYPE_NONF_IPV4_OTHER: 58529486b6dSJunfeng Guo if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_UDP || 58629486b6dSJunfeng Guo flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_TCP || 58729486b6dSJunfeng Guo flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_SCTP) 58829486b6dSJunfeng Guo return true; 58929486b6dSJunfeng Guo break; 59029486b6dSJunfeng Guo case ICE_FLTR_PTYPE_NONF_IPV6_UDP: 59129486b6dSJunfeng Guo case ICE_FLTR_PTYPE_NONF_IPV6_TCP: 59229486b6dSJunfeng Guo case ICE_FLTR_PTYPE_NONF_IPV6_SCTP: 59329486b6dSJunfeng Guo if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_OTHER) 59429486b6dSJunfeng Guo return true; 59529486b6dSJunfeng Guo break; 59629486b6dSJunfeng Guo case ICE_FLTR_PTYPE_NONF_IPV6_OTHER: 59729486b6dSJunfeng Guo if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_UDP || 59829486b6dSJunfeng Guo flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_TCP || 59929486b6dSJunfeng Guo flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_SCTP) 60029486b6dSJunfeng Guo return true; 60129486b6dSJunfeng Guo break; 60229486b6dSJunfeng Guo default: 60329486b6dSJunfeng Guo break; 60429486b6dSJunfeng Guo } 60529486b6dSJunfeng Guo } 60629486b6dSJunfeng Guo 60729486b6dSJunfeng Guo return false; 60829486b6dSJunfeng Guo } 60929486b6dSJunfeng Guo 61029486b6dSJunfeng Guo /** 6111f7ea1cdSQi Zhang * ice_vc_fdir_write_flow_prof 6121f7ea1cdSQi Zhang * @vf: pointer to the VF structure 6131f7ea1cdSQi Zhang * @flow: filter flow type 6141f7ea1cdSQi Zhang * @seg: array of one or more packet segments that describe the flow 6151f7ea1cdSQi Zhang * @tun: 0 implies non-tunnel type filter, 1 implies tunnel type filter 6161f7ea1cdSQi Zhang * 6171f7ea1cdSQi Zhang * Write the flow's profile config and packet segment into the hardware 6181f7ea1cdSQi Zhang * 6191f7ea1cdSQi Zhang * Return: 0 on success, and other on error. 6201f7ea1cdSQi Zhang */ 6211f7ea1cdSQi Zhang static int 6221f7ea1cdSQi Zhang ice_vc_fdir_write_flow_prof(struct ice_vf *vf, enum ice_fltr_ptype flow, 6231f7ea1cdSQi Zhang struct ice_flow_seg_info *seg, int tun) 6241f7ea1cdSQi Zhang { 6251f7ea1cdSQi Zhang struct ice_vf_fdir *fdir = &vf->fdir; 6261f7ea1cdSQi Zhang struct ice_vsi *vf_vsi, *ctrl_vsi; 6271f7ea1cdSQi Zhang struct ice_flow_seg_info *old_seg; 6281f7ea1cdSQi Zhang struct ice_flow_prof *prof = NULL; 6291f7ea1cdSQi Zhang struct ice_fd_hw_prof *vf_prof; 6301f7ea1cdSQi Zhang struct device *dev; 6311f7ea1cdSQi Zhang struct ice_pf *pf; 6321f7ea1cdSQi Zhang struct ice_hw *hw; 6331f7ea1cdSQi Zhang u64 entry1_h = 0; 6341f7ea1cdSQi Zhang u64 entry2_h = 0; 6351f7ea1cdSQi Zhang u64 prof_id; 6361f7ea1cdSQi Zhang int ret; 6371f7ea1cdSQi Zhang 6381f7ea1cdSQi Zhang pf = vf->pf; 6391f7ea1cdSQi Zhang dev = ice_pf_to_dev(pf); 6401f7ea1cdSQi Zhang hw = &pf->hw; 641772dec64SBrett Creeley vf_vsi = ice_get_vf_vsi(vf); 6421f7ea1cdSQi Zhang if (!vf_vsi) 6431f7ea1cdSQi Zhang return -EINVAL; 6441f7ea1cdSQi Zhang 6451f7ea1cdSQi Zhang ctrl_vsi = pf->vsi[vf->ctrl_vsi_idx]; 6461f7ea1cdSQi Zhang if (!ctrl_vsi) 6471f7ea1cdSQi Zhang return -EINVAL; 6481f7ea1cdSQi Zhang 6491f7ea1cdSQi Zhang vf_prof = fdir->fdir_prof[flow]; 6501f7ea1cdSQi Zhang old_seg = vf_prof->fdir_seg[tun]; 6511f7ea1cdSQi Zhang if (old_seg) { 6521f7ea1cdSQi Zhang if (!memcmp(old_seg, seg, sizeof(*seg))) { 6531f7ea1cdSQi Zhang dev_dbg(dev, "Duplicated profile for VF %d!\n", 6541f7ea1cdSQi Zhang vf->vf_id); 6551f7ea1cdSQi Zhang return -EEXIST; 6561f7ea1cdSQi Zhang } 6571f7ea1cdSQi Zhang 6581f7ea1cdSQi Zhang if (fdir->fdir_fltr_cnt[flow][tun]) { 6591f7ea1cdSQi Zhang ret = -EINVAL; 6601f7ea1cdSQi Zhang dev_dbg(dev, "Input set conflicts for VF %d\n", 6611f7ea1cdSQi Zhang vf->vf_id); 6621f7ea1cdSQi Zhang goto err_exit; 6631f7ea1cdSQi Zhang } 6641f7ea1cdSQi Zhang 6651f7ea1cdSQi Zhang /* remove previously allocated profile */ 6661f7ea1cdSQi Zhang ice_vc_fdir_rem_prof(vf, flow, tun); 6671f7ea1cdSQi Zhang } 6681f7ea1cdSQi Zhang 6691f7ea1cdSQi Zhang prof_id = ICE_FLOW_PROF_FD(vf_vsi->vsi_num, flow, 6701f7ea1cdSQi Zhang tun ? ICE_FLTR_PTYPE_MAX : 0); 6711f7ea1cdSQi Zhang 6722ccc1c1cSTony Nguyen ret = ice_flow_add_prof(hw, ICE_BLK_FD, ICE_FLOW_RX, prof_id, seg, 6731f7ea1cdSQi Zhang tun + 1, &prof); 6741f7ea1cdSQi Zhang if (ret) { 6751f7ea1cdSQi Zhang dev_dbg(dev, "Could not add VSI flow 0x%x for VF %d\n", 6761f7ea1cdSQi Zhang flow, vf->vf_id); 6771f7ea1cdSQi Zhang goto err_exit; 6781f7ea1cdSQi Zhang } 6791f7ea1cdSQi Zhang 6802ccc1c1cSTony Nguyen ret = ice_flow_add_entry(hw, ICE_BLK_FD, prof_id, vf_vsi->idx, 6811f7ea1cdSQi Zhang vf_vsi->idx, ICE_FLOW_PRIO_NORMAL, 6821f7ea1cdSQi Zhang seg, &entry1_h); 6831f7ea1cdSQi Zhang if (ret) { 6841f7ea1cdSQi Zhang dev_dbg(dev, "Could not add flow 0x%x VSI entry for VF %d\n", 6851f7ea1cdSQi Zhang flow, vf->vf_id); 6861f7ea1cdSQi Zhang goto err_prof; 6871f7ea1cdSQi Zhang } 6881f7ea1cdSQi Zhang 6892ccc1c1cSTony Nguyen ret = ice_flow_add_entry(hw, ICE_BLK_FD, prof_id, vf_vsi->idx, 6901f7ea1cdSQi Zhang ctrl_vsi->idx, ICE_FLOW_PRIO_NORMAL, 6911f7ea1cdSQi Zhang seg, &entry2_h); 6921f7ea1cdSQi Zhang if (ret) { 6931f7ea1cdSQi Zhang dev_dbg(dev, 6941f7ea1cdSQi Zhang "Could not add flow 0x%x Ctrl VSI entry for VF %d\n", 6951f7ea1cdSQi Zhang flow, vf->vf_id); 6961f7ea1cdSQi Zhang goto err_entry_1; 6971f7ea1cdSQi Zhang } 6981f7ea1cdSQi Zhang 6991f7ea1cdSQi Zhang vf_prof->fdir_seg[tun] = seg; 7001f7ea1cdSQi Zhang vf_prof->cnt = 0; 7011f7ea1cdSQi Zhang fdir->prof_entry_cnt[flow][tun] = 0; 7021f7ea1cdSQi Zhang 7031f7ea1cdSQi Zhang vf_prof->entry_h[vf_prof->cnt][tun] = entry1_h; 7041f7ea1cdSQi Zhang vf_prof->vsi_h[vf_prof->cnt] = vf_vsi->idx; 7051f7ea1cdSQi Zhang vf_prof->cnt++; 7061f7ea1cdSQi Zhang fdir->prof_entry_cnt[flow][tun]++; 7071f7ea1cdSQi Zhang 7081f7ea1cdSQi Zhang vf_prof->entry_h[vf_prof->cnt][tun] = entry2_h; 7091f7ea1cdSQi Zhang vf_prof->vsi_h[vf_prof->cnt] = ctrl_vsi->idx; 7101f7ea1cdSQi Zhang vf_prof->cnt++; 7111f7ea1cdSQi Zhang fdir->prof_entry_cnt[flow][tun]++; 7121f7ea1cdSQi Zhang 7131f7ea1cdSQi Zhang return 0; 7141f7ea1cdSQi Zhang 7151f7ea1cdSQi Zhang err_entry_1: 7161f7ea1cdSQi Zhang ice_rem_prof_id_flow(hw, ICE_BLK_FD, 7171f7ea1cdSQi Zhang ice_get_hw_vsi_num(hw, vf_vsi->idx), prof_id); 7181f7ea1cdSQi Zhang ice_flow_rem_entry(hw, ICE_BLK_FD, entry1_h); 7191f7ea1cdSQi Zhang err_prof: 7201f7ea1cdSQi Zhang ice_flow_rem_prof(hw, ICE_BLK_FD, prof_id); 7211f7ea1cdSQi Zhang err_exit: 7221f7ea1cdSQi Zhang return ret; 7231f7ea1cdSQi Zhang } 7241f7ea1cdSQi Zhang 7251f7ea1cdSQi Zhang /** 7261f7ea1cdSQi Zhang * ice_vc_fdir_config_input_set 7271f7ea1cdSQi Zhang * @vf: pointer to the VF structure 7281f7ea1cdSQi Zhang * @fltr: virtual channel add cmd buffer 7291f7ea1cdSQi Zhang * @conf: FDIR configuration for each filter 7301f7ea1cdSQi Zhang * @tun: 0 implies non-tunnel type filter, 1 implies tunnel type filter 7311f7ea1cdSQi Zhang * 7321f7ea1cdSQi Zhang * Config the input set type and value for virtual channel add msg buffer 7331f7ea1cdSQi Zhang * 7341f7ea1cdSQi Zhang * Return: 0 on success, and other on error. 7351f7ea1cdSQi Zhang */ 7361f7ea1cdSQi Zhang static int 7371f7ea1cdSQi Zhang ice_vc_fdir_config_input_set(struct ice_vf *vf, struct virtchnl_fdir_add *fltr, 7381f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf, int tun) 7391f7ea1cdSQi Zhang { 7401f7ea1cdSQi Zhang struct ice_fdir_fltr *input = &conf->input; 7411f7ea1cdSQi Zhang struct device *dev = ice_pf_to_dev(vf->pf); 7421f7ea1cdSQi Zhang struct ice_flow_seg_info *seg; 7431f7ea1cdSQi Zhang enum ice_fltr_ptype flow; 7441f7ea1cdSQi Zhang int ret; 7451f7ea1cdSQi Zhang 74629486b6dSJunfeng Guo ret = ice_vc_fdir_has_prof_conflict(vf, conf); 74729486b6dSJunfeng Guo if (ret) { 74829486b6dSJunfeng Guo dev_dbg(dev, "Found flow profile conflict for VF %d\n", 74929486b6dSJunfeng Guo vf->vf_id); 75029486b6dSJunfeng Guo return ret; 75129486b6dSJunfeng Guo } 75229486b6dSJunfeng Guo 7531f7ea1cdSQi Zhang flow = input->flow_type; 7541f7ea1cdSQi Zhang ret = ice_vc_fdir_alloc_prof(vf, flow); 7551f7ea1cdSQi Zhang if (ret) { 7561f7ea1cdSQi Zhang dev_dbg(dev, "Alloc flow prof for VF %d failed\n", vf->vf_id); 7571f7ea1cdSQi Zhang return ret; 7581f7ea1cdSQi Zhang } 7591f7ea1cdSQi Zhang 7601f7ea1cdSQi Zhang seg = devm_kzalloc(dev, sizeof(*seg), GFP_KERNEL); 7611f7ea1cdSQi Zhang if (!seg) 7621f7ea1cdSQi Zhang return -ENOMEM; 7631f7ea1cdSQi Zhang 7641f7ea1cdSQi Zhang ret = ice_vc_fdir_set_flow_fld(vf, fltr, conf, seg); 7651f7ea1cdSQi Zhang if (ret) { 7661f7ea1cdSQi Zhang dev_dbg(dev, "Set flow field for VF %d failed\n", vf->vf_id); 7671f7ea1cdSQi Zhang goto err_exit; 7681f7ea1cdSQi Zhang } 7691f7ea1cdSQi Zhang 7701f7ea1cdSQi Zhang ret = ice_vc_fdir_set_flow_hdr(vf, conf, seg); 7711f7ea1cdSQi Zhang if (ret) { 7721f7ea1cdSQi Zhang dev_dbg(dev, "Set flow hdr for VF %d failed\n", vf->vf_id); 7731f7ea1cdSQi Zhang goto err_exit; 7741f7ea1cdSQi Zhang } 7751f7ea1cdSQi Zhang 7761f7ea1cdSQi Zhang ret = ice_vc_fdir_write_flow_prof(vf, flow, seg, tun); 7771f7ea1cdSQi Zhang if (ret == -EEXIST) { 7781f7ea1cdSQi Zhang devm_kfree(dev, seg); 7791f7ea1cdSQi Zhang } else if (ret) { 7801f7ea1cdSQi Zhang dev_dbg(dev, "Write flow profile for VF %d failed\n", 7811f7ea1cdSQi Zhang vf->vf_id); 7821f7ea1cdSQi Zhang goto err_exit; 7831f7ea1cdSQi Zhang } 7841f7ea1cdSQi Zhang 7851f7ea1cdSQi Zhang return 0; 7861f7ea1cdSQi Zhang 7871f7ea1cdSQi Zhang err_exit: 7881f7ea1cdSQi Zhang devm_kfree(dev, seg); 7891f7ea1cdSQi Zhang return ret; 7901f7ea1cdSQi Zhang } 7911f7ea1cdSQi Zhang 7921f7ea1cdSQi Zhang /** 7930ce332fdSQi Zhang * ice_vc_fdir_parse_pattern 7940ce332fdSQi Zhang * @vf: pointer to the VF info 7950ce332fdSQi Zhang * @fltr: virtual channel add cmd buffer 7960ce332fdSQi Zhang * @conf: FDIR configuration for each filter 7970ce332fdSQi Zhang * 7980ce332fdSQi Zhang * Parse the virtual channel filter's pattern and store them into conf 7990ce332fdSQi Zhang * 8000ce332fdSQi Zhang * Return: 0 on success, and other on error. 8010ce332fdSQi Zhang */ 8020ce332fdSQi Zhang static int 8030ce332fdSQi Zhang ice_vc_fdir_parse_pattern(struct ice_vf *vf, struct virtchnl_fdir_add *fltr, 8040ce332fdSQi Zhang struct virtchnl_fdir_fltr_conf *conf) 8050ce332fdSQi Zhang { 8060ce332fdSQi Zhang struct virtchnl_proto_hdrs *proto = &fltr->rule_cfg.proto_hdrs; 8070ce332fdSQi Zhang enum virtchnl_proto_hdr_type l3 = VIRTCHNL_PROTO_HDR_NONE; 808213528feSQi Zhang enum virtchnl_proto_hdr_type l4 = VIRTCHNL_PROTO_HDR_NONE; 8090ce332fdSQi Zhang struct device *dev = ice_pf_to_dev(vf->pf); 8100ce332fdSQi Zhang struct ice_fdir_fltr *input = &conf->input; 8110ce332fdSQi Zhang int i; 8120ce332fdSQi Zhang 8130ce332fdSQi Zhang if (proto->count > VIRTCHNL_MAX_NUM_PROTO_HDRS) { 8140ce332fdSQi Zhang dev_dbg(dev, "Invalid protocol count:0x%x for VF %d\n", 8150ce332fdSQi Zhang proto->count, vf->vf_id); 8160ce332fdSQi Zhang return -EINVAL; 8170ce332fdSQi Zhang } 8180ce332fdSQi Zhang 8190ce332fdSQi Zhang for (i = 0; i < proto->count; i++) { 8200ce332fdSQi Zhang struct virtchnl_proto_hdr *hdr = &proto->proto_hdr[i]; 821213528feSQi Zhang struct ip_esp_hdr *esph; 822213528feSQi Zhang struct ip_auth_hdr *ah; 8230ce332fdSQi Zhang struct sctphdr *sctph; 8240ce332fdSQi Zhang struct ipv6hdr *ip6h; 8250ce332fdSQi Zhang struct udphdr *udph; 8260ce332fdSQi Zhang struct tcphdr *tcph; 82721606584SQi Zhang struct ethhdr *eth; 8280ce332fdSQi Zhang struct iphdr *iph; 829213528feSQi Zhang u8 s_field; 830ef9e4cc5SQi Zhang u8 *rawh; 8310ce332fdSQi Zhang 8320ce332fdSQi Zhang switch (hdr->type) { 8330ce332fdSQi Zhang case VIRTCHNL_PROTO_HDR_ETH: 83421606584SQi Zhang eth = (struct ethhdr *)hdr->buffer; 83521606584SQi Zhang input->flow_type = ICE_FLTR_PTYPE_NON_IP_L2; 83621606584SQi Zhang 83721606584SQi Zhang if (hdr->field_selector) 83821606584SQi Zhang input->ext_data.ether_type = eth->h_proto; 8390ce332fdSQi Zhang break; 8400ce332fdSQi Zhang case VIRTCHNL_PROTO_HDR_IPV4: 8410ce332fdSQi Zhang iph = (struct iphdr *)hdr->buffer; 8420ce332fdSQi Zhang l3 = VIRTCHNL_PROTO_HDR_IPV4; 8430ce332fdSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_OTHER; 8440ce332fdSQi Zhang 8450ce332fdSQi Zhang if (hdr->field_selector) { 8460ce332fdSQi Zhang input->ip.v4.src_ip = iph->saddr; 8470ce332fdSQi Zhang input->ip.v4.dst_ip = iph->daddr; 8480ce332fdSQi Zhang input->ip.v4.tos = iph->tos; 8490ce332fdSQi Zhang input->ip.v4.proto = iph->protocol; 8500ce332fdSQi Zhang } 8510ce332fdSQi Zhang break; 8520ce332fdSQi Zhang case VIRTCHNL_PROTO_HDR_IPV6: 8530ce332fdSQi Zhang ip6h = (struct ipv6hdr *)hdr->buffer; 8540ce332fdSQi Zhang l3 = VIRTCHNL_PROTO_HDR_IPV6; 8550ce332fdSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_OTHER; 8560ce332fdSQi Zhang 8570ce332fdSQi Zhang if (hdr->field_selector) { 8580ce332fdSQi Zhang memcpy(input->ip.v6.src_ip, 8590ce332fdSQi Zhang ip6h->saddr.in6_u.u6_addr8, 8600ce332fdSQi Zhang sizeof(ip6h->saddr)); 8610ce332fdSQi Zhang memcpy(input->ip.v6.dst_ip, 8620ce332fdSQi Zhang ip6h->daddr.in6_u.u6_addr8, 8630ce332fdSQi Zhang sizeof(ip6h->daddr)); 8640ce332fdSQi Zhang input->ip.v6.tc = ((u8)(ip6h->priority) << 4) | 8650ce332fdSQi Zhang (ip6h->flow_lbl[0] >> 4); 8660ce332fdSQi Zhang input->ip.v6.proto = ip6h->nexthdr; 8670ce332fdSQi Zhang } 8680ce332fdSQi Zhang break; 8690ce332fdSQi Zhang case VIRTCHNL_PROTO_HDR_TCP: 8700ce332fdSQi Zhang tcph = (struct tcphdr *)hdr->buffer; 8710ce332fdSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4) 8720ce332fdSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_TCP; 8730ce332fdSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) 8740ce332fdSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_TCP; 8750ce332fdSQi Zhang 8760ce332fdSQi Zhang if (hdr->field_selector) { 8770ce332fdSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4) { 8780ce332fdSQi Zhang input->ip.v4.src_port = tcph->source; 8790ce332fdSQi Zhang input->ip.v4.dst_port = tcph->dest; 8800ce332fdSQi Zhang } else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) { 8810ce332fdSQi Zhang input->ip.v6.src_port = tcph->source; 8820ce332fdSQi Zhang input->ip.v6.dst_port = tcph->dest; 8830ce332fdSQi Zhang } 8840ce332fdSQi Zhang } 8850ce332fdSQi Zhang break; 8860ce332fdSQi Zhang case VIRTCHNL_PROTO_HDR_UDP: 8870ce332fdSQi Zhang udph = (struct udphdr *)hdr->buffer; 8880ce332fdSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4) 8890ce332fdSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_UDP; 8900ce332fdSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) 8910ce332fdSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_UDP; 8920ce332fdSQi Zhang 8930ce332fdSQi Zhang if (hdr->field_selector) { 8940ce332fdSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4) { 8950ce332fdSQi Zhang input->ip.v4.src_port = udph->source; 8960ce332fdSQi Zhang input->ip.v4.dst_port = udph->dest; 8970ce332fdSQi Zhang } else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) { 8980ce332fdSQi Zhang input->ip.v6.src_port = udph->source; 8990ce332fdSQi Zhang input->ip.v6.dst_port = udph->dest; 9000ce332fdSQi Zhang } 9010ce332fdSQi Zhang } 9020ce332fdSQi Zhang break; 9030ce332fdSQi Zhang case VIRTCHNL_PROTO_HDR_SCTP: 9040ce332fdSQi Zhang sctph = (struct sctphdr *)hdr->buffer; 9050ce332fdSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4) 9060ce332fdSQi Zhang input->flow_type = 9070ce332fdSQi Zhang ICE_FLTR_PTYPE_NONF_IPV4_SCTP; 9080ce332fdSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) 9090ce332fdSQi Zhang input->flow_type = 9100ce332fdSQi Zhang ICE_FLTR_PTYPE_NONF_IPV6_SCTP; 9110ce332fdSQi Zhang 9120ce332fdSQi Zhang if (hdr->field_selector) { 9130ce332fdSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4) { 9140ce332fdSQi Zhang input->ip.v4.src_port = sctph->source; 9150ce332fdSQi Zhang input->ip.v4.dst_port = sctph->dest; 9160ce332fdSQi Zhang } else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) { 9170ce332fdSQi Zhang input->ip.v6.src_port = sctph->source; 9180ce332fdSQi Zhang input->ip.v6.dst_port = sctph->dest; 9190ce332fdSQi Zhang } 9200ce332fdSQi Zhang } 9210ce332fdSQi Zhang break; 922213528feSQi Zhang case VIRTCHNL_PROTO_HDR_L2TPV3: 923213528feSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4) 924213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_L2TPV3; 925213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) 926213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_L2TPV3; 927213528feSQi Zhang 928213528feSQi Zhang if (hdr->field_selector) 929213528feSQi Zhang input->l2tpv3_data.session_id = *((__be32 *)hdr->buffer); 930213528feSQi Zhang break; 931213528feSQi Zhang case VIRTCHNL_PROTO_HDR_ESP: 932213528feSQi Zhang esph = (struct ip_esp_hdr *)hdr->buffer; 933213528feSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4 && 934213528feSQi Zhang l4 == VIRTCHNL_PROTO_HDR_UDP) 935213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_NAT_T_ESP; 936213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6 && 937213528feSQi Zhang l4 == VIRTCHNL_PROTO_HDR_UDP) 938213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_NAT_T_ESP; 939213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV4 && 940213528feSQi Zhang l4 == VIRTCHNL_PROTO_HDR_NONE) 941213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_ESP; 942213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6 && 943213528feSQi Zhang l4 == VIRTCHNL_PROTO_HDR_NONE) 944213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_ESP; 945213528feSQi Zhang 946213528feSQi Zhang if (l4 == VIRTCHNL_PROTO_HDR_UDP) 947213528feSQi Zhang conf->inset_flag |= FDIR_INSET_FLAG_ESP_UDP; 948213528feSQi Zhang else 949213528feSQi Zhang conf->inset_flag |= FDIR_INSET_FLAG_ESP_IPSEC; 950213528feSQi Zhang 951213528feSQi Zhang if (hdr->field_selector) { 952213528feSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4) 953213528feSQi Zhang input->ip.v4.sec_parm_idx = esph->spi; 954213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) 955213528feSQi Zhang input->ip.v6.sec_parm_idx = esph->spi; 956213528feSQi Zhang } 957213528feSQi Zhang break; 958213528feSQi Zhang case VIRTCHNL_PROTO_HDR_AH: 959213528feSQi Zhang ah = (struct ip_auth_hdr *)hdr->buffer; 960213528feSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4) 961213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_AH; 962213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) 963213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_AH; 964213528feSQi Zhang 965213528feSQi Zhang if (hdr->field_selector) { 966213528feSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4) 967213528feSQi Zhang input->ip.v4.sec_parm_idx = ah->spi; 968213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) 969213528feSQi Zhang input->ip.v6.sec_parm_idx = ah->spi; 970213528feSQi Zhang } 971213528feSQi Zhang break; 972213528feSQi Zhang case VIRTCHNL_PROTO_HDR_PFCP: 973213528feSQi Zhang rawh = (u8 *)hdr->buffer; 974213528feSQi Zhang s_field = (rawh[0] >> PFCP_S_OFFSET) & PFCP_S_MASK; 975213528feSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4 && s_field == 0) 976213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_PFCP_NODE; 977213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV4 && s_field == 1) 978213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_PFCP_SESSION; 979213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6 && s_field == 0) 980213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_PFCP_NODE; 981213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6 && s_field == 1) 982213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_PFCP_SESSION; 983213528feSQi Zhang 984213528feSQi Zhang if (hdr->field_selector) { 985213528feSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4) 986213528feSQi Zhang input->ip.v4.dst_port = cpu_to_be16(PFCP_PORT_NR); 987213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) 988213528feSQi Zhang input->ip.v6.dst_port = cpu_to_be16(PFCP_PORT_NR); 989213528feSQi Zhang } 990213528feSQi Zhang break; 991ef9e4cc5SQi Zhang case VIRTCHNL_PROTO_HDR_GTPU_IP: 992ef9e4cc5SQi Zhang rawh = (u8 *)hdr->buffer; 993ef9e4cc5SQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_OTHER; 994ef9e4cc5SQi Zhang 995ef9e4cc5SQi Zhang if (hdr->field_selector) 996ef9e4cc5SQi Zhang input->gtpu_data.teid = *(__be32 *)(&rawh[GTPU_TEID_OFFSET]); 997ef9e4cc5SQi Zhang conf->ttype = ICE_FDIR_TUNNEL_TYPE_GTPU; 998ef9e4cc5SQi Zhang break; 999ef9e4cc5SQi Zhang case VIRTCHNL_PROTO_HDR_GTPU_EH: 1000ef9e4cc5SQi Zhang rawh = (u8 *)hdr->buffer; 1001ef9e4cc5SQi Zhang 1002ef9e4cc5SQi Zhang if (hdr->field_selector) 1003ef9e4cc5SQi Zhang input->gtpu_data.qfi = rawh[GTPU_EH_QFI_OFFSET] & GTPU_EH_QFI_MASK; 1004ef9e4cc5SQi Zhang conf->ttype = ICE_FDIR_TUNNEL_TYPE_GTPU_EH; 1005ef9e4cc5SQi Zhang break; 10060ce332fdSQi Zhang default: 10070ce332fdSQi Zhang dev_dbg(dev, "Invalid header type 0x:%x for VF %d\n", 10080ce332fdSQi Zhang hdr->type, vf->vf_id); 10090ce332fdSQi Zhang return -EINVAL; 10100ce332fdSQi Zhang } 10110ce332fdSQi Zhang } 10120ce332fdSQi Zhang 10130ce332fdSQi Zhang return 0; 10140ce332fdSQi Zhang } 10150ce332fdSQi Zhang 10160ce332fdSQi Zhang /** 10170ce332fdSQi Zhang * ice_vc_fdir_parse_action 10180ce332fdSQi Zhang * @vf: pointer to the VF info 10190ce332fdSQi Zhang * @fltr: virtual channel add cmd buffer 10200ce332fdSQi Zhang * @conf: FDIR configuration for each filter 10210ce332fdSQi Zhang * 10220ce332fdSQi Zhang * Parse the virtual channel filter's action and store them into conf 10230ce332fdSQi Zhang * 10240ce332fdSQi Zhang * Return: 0 on success, and other on error. 10250ce332fdSQi Zhang */ 10260ce332fdSQi Zhang static int 10270ce332fdSQi Zhang ice_vc_fdir_parse_action(struct ice_vf *vf, struct virtchnl_fdir_add *fltr, 10280ce332fdSQi Zhang struct virtchnl_fdir_fltr_conf *conf) 10290ce332fdSQi Zhang { 10300ce332fdSQi Zhang struct virtchnl_filter_action_set *as = &fltr->rule_cfg.action_set; 10310ce332fdSQi Zhang struct device *dev = ice_pf_to_dev(vf->pf); 10320ce332fdSQi Zhang struct ice_fdir_fltr *input = &conf->input; 10330ce332fdSQi Zhang u32 dest_num = 0; 10340ce332fdSQi Zhang u32 mark_num = 0; 10350ce332fdSQi Zhang int i; 10360ce332fdSQi Zhang 10370ce332fdSQi Zhang if (as->count > VIRTCHNL_MAX_NUM_ACTIONS) { 10380ce332fdSQi Zhang dev_dbg(dev, "Invalid action numbers:0x%x for VF %d\n", 10390ce332fdSQi Zhang as->count, vf->vf_id); 10400ce332fdSQi Zhang return -EINVAL; 10410ce332fdSQi Zhang } 10420ce332fdSQi Zhang 10430ce332fdSQi Zhang for (i = 0; i < as->count; i++) { 10440ce332fdSQi Zhang struct virtchnl_filter_action *action = &as->actions[i]; 10450ce332fdSQi Zhang 10460ce332fdSQi Zhang switch (action->type) { 1047346bf250SQi Zhang case VIRTCHNL_ACTION_PASSTHRU: 1048346bf250SQi Zhang dest_num++; 1049346bf250SQi Zhang input->dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_OTHER; 1050346bf250SQi Zhang break; 10510ce332fdSQi Zhang case VIRTCHNL_ACTION_DROP: 10520ce332fdSQi Zhang dest_num++; 10530ce332fdSQi Zhang input->dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DROP_PKT; 10540ce332fdSQi Zhang break; 10550ce332fdSQi Zhang case VIRTCHNL_ACTION_QUEUE: 10560ce332fdSQi Zhang dest_num++; 10570ce332fdSQi Zhang input->dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_QINDEX; 10580ce332fdSQi Zhang input->q_index = action->act_conf.queue.index; 10590ce332fdSQi Zhang break; 1060346bf250SQi Zhang case VIRTCHNL_ACTION_Q_REGION: 1061346bf250SQi Zhang dest_num++; 1062346bf250SQi Zhang input->dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_QGROUP; 1063346bf250SQi Zhang input->q_index = action->act_conf.queue.index; 1064346bf250SQi Zhang input->q_region = action->act_conf.queue.region; 1065346bf250SQi Zhang break; 10660ce332fdSQi Zhang case VIRTCHNL_ACTION_MARK: 10670ce332fdSQi Zhang mark_num++; 10680ce332fdSQi Zhang input->fltr_id = action->act_conf.mark_id; 10690ce332fdSQi Zhang input->fdid_prio = ICE_FXD_FLTR_QW1_FDID_PRI_THREE; 10700ce332fdSQi Zhang break; 10710ce332fdSQi Zhang default: 10720ce332fdSQi Zhang dev_dbg(dev, "Invalid action type:0x%x for VF %d\n", 10730ce332fdSQi Zhang action->type, vf->vf_id); 10740ce332fdSQi Zhang return -EINVAL; 10750ce332fdSQi Zhang } 10760ce332fdSQi Zhang } 10770ce332fdSQi Zhang 10780ce332fdSQi Zhang if (dest_num == 0 || dest_num >= 2) { 10790ce332fdSQi Zhang dev_dbg(dev, "Invalid destination action for VF %d\n", 10800ce332fdSQi Zhang vf->vf_id); 10810ce332fdSQi Zhang return -EINVAL; 10820ce332fdSQi Zhang } 10830ce332fdSQi Zhang 10840ce332fdSQi Zhang if (mark_num >= 2) { 10850ce332fdSQi Zhang dev_dbg(dev, "Too many mark actions for VF %d\n", vf->vf_id); 10860ce332fdSQi Zhang return -EINVAL; 10870ce332fdSQi Zhang } 10880ce332fdSQi Zhang 10890ce332fdSQi Zhang return 0; 10900ce332fdSQi Zhang } 10910ce332fdSQi Zhang 10920ce332fdSQi Zhang /** 10931f7ea1cdSQi Zhang * ice_vc_validate_fdir_fltr - validate the virtual channel filter 10941f7ea1cdSQi Zhang * @vf: pointer to the VF info 10951f7ea1cdSQi Zhang * @fltr: virtual channel add cmd buffer 10961f7ea1cdSQi Zhang * @conf: FDIR configuration for each filter 10971f7ea1cdSQi Zhang * 10981f7ea1cdSQi Zhang * Return: 0 on success, and other on error. 10991f7ea1cdSQi Zhang */ 11001f7ea1cdSQi Zhang static int 11011f7ea1cdSQi Zhang ice_vc_validate_fdir_fltr(struct ice_vf *vf, struct virtchnl_fdir_add *fltr, 11021f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf) 11031f7ea1cdSQi Zhang { 110460f44fe4SJeff Guo struct virtchnl_proto_hdrs *proto = &fltr->rule_cfg.proto_hdrs; 11050ce332fdSQi Zhang int ret; 11060ce332fdSQi Zhang 110760f44fe4SJeff Guo if (!ice_vc_validate_pattern(vf, proto)) 110860f44fe4SJeff Guo return -EINVAL; 11090ce332fdSQi Zhang 11100ce332fdSQi Zhang ret = ice_vc_fdir_parse_pattern(vf, fltr, conf); 11110ce332fdSQi Zhang if (ret) 11120ce332fdSQi Zhang return ret; 11130ce332fdSQi Zhang 11140ce332fdSQi Zhang return ice_vc_fdir_parse_action(vf, fltr, conf); 11151f7ea1cdSQi Zhang } 11161f7ea1cdSQi Zhang 11171f7ea1cdSQi Zhang /** 11181f7ea1cdSQi Zhang * ice_vc_fdir_comp_rules - compare if two filter rules have the same value 11191f7ea1cdSQi Zhang * @conf_a: FDIR configuration for filter a 11201f7ea1cdSQi Zhang * @conf_b: FDIR configuration for filter b 11211f7ea1cdSQi Zhang * 11221f7ea1cdSQi Zhang * Return: 0 on success, and other on error. 11231f7ea1cdSQi Zhang */ 11241f7ea1cdSQi Zhang static bool 11251f7ea1cdSQi Zhang ice_vc_fdir_comp_rules(struct virtchnl_fdir_fltr_conf *conf_a, 11261f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf_b) 11271f7ea1cdSQi Zhang { 11281f7ea1cdSQi Zhang struct ice_fdir_fltr *a = &conf_a->input; 11291f7ea1cdSQi Zhang struct ice_fdir_fltr *b = &conf_b->input; 11301f7ea1cdSQi Zhang 1131ef9e4cc5SQi Zhang if (conf_a->ttype != conf_b->ttype) 1132ef9e4cc5SQi Zhang return false; 11331f7ea1cdSQi Zhang if (a->flow_type != b->flow_type) 11341f7ea1cdSQi Zhang return false; 11351f7ea1cdSQi Zhang if (memcmp(&a->ip, &b->ip, sizeof(a->ip))) 11361f7ea1cdSQi Zhang return false; 11371f7ea1cdSQi Zhang if (memcmp(&a->mask, &b->mask, sizeof(a->mask))) 11381f7ea1cdSQi Zhang return false; 1139ef9e4cc5SQi Zhang if (memcmp(&a->gtpu_data, &b->gtpu_data, sizeof(a->gtpu_data))) 1140ef9e4cc5SQi Zhang return false; 1141ef9e4cc5SQi Zhang if (memcmp(&a->gtpu_mask, &b->gtpu_mask, sizeof(a->gtpu_mask))) 1142ef9e4cc5SQi Zhang return false; 1143213528feSQi Zhang if (memcmp(&a->l2tpv3_data, &b->l2tpv3_data, sizeof(a->l2tpv3_data))) 1144213528feSQi Zhang return false; 1145213528feSQi Zhang if (memcmp(&a->l2tpv3_mask, &b->l2tpv3_mask, sizeof(a->l2tpv3_mask))) 1146213528feSQi Zhang return false; 11471f7ea1cdSQi Zhang if (memcmp(&a->ext_data, &b->ext_data, sizeof(a->ext_data))) 11481f7ea1cdSQi Zhang return false; 11491f7ea1cdSQi Zhang if (memcmp(&a->ext_mask, &b->ext_mask, sizeof(a->ext_mask))) 11501f7ea1cdSQi Zhang return false; 11511f7ea1cdSQi Zhang 11521f7ea1cdSQi Zhang return true; 11531f7ea1cdSQi Zhang } 11541f7ea1cdSQi Zhang 11551f7ea1cdSQi Zhang /** 11561f7ea1cdSQi Zhang * ice_vc_fdir_is_dup_fltr 11571f7ea1cdSQi Zhang * @vf: pointer to the VF info 11581f7ea1cdSQi Zhang * @conf: FDIR configuration for each filter 11591f7ea1cdSQi Zhang * 11601f7ea1cdSQi Zhang * Check if there is duplicated rule with same conf value 11611f7ea1cdSQi Zhang * 11621f7ea1cdSQi Zhang * Return: 0 true success, and false on error. 11631f7ea1cdSQi Zhang */ 11641f7ea1cdSQi Zhang static bool 11651f7ea1cdSQi Zhang ice_vc_fdir_is_dup_fltr(struct ice_vf *vf, struct virtchnl_fdir_fltr_conf *conf) 11661f7ea1cdSQi Zhang { 11671f7ea1cdSQi Zhang struct ice_fdir_fltr *desc; 11681f7ea1cdSQi Zhang bool ret; 11691f7ea1cdSQi Zhang 11701f7ea1cdSQi Zhang list_for_each_entry(desc, &vf->fdir.fdir_rule_list, fltr_node) { 11711f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *node = 11721f7ea1cdSQi Zhang to_fltr_conf_from_desc(desc); 11731f7ea1cdSQi Zhang 11741f7ea1cdSQi Zhang ret = ice_vc_fdir_comp_rules(node, conf); 11751f7ea1cdSQi Zhang if (ret) 11761f7ea1cdSQi Zhang return true; 11771f7ea1cdSQi Zhang } 11781f7ea1cdSQi Zhang 11791f7ea1cdSQi Zhang return false; 11801f7ea1cdSQi Zhang } 11811f7ea1cdSQi Zhang 11821f7ea1cdSQi Zhang /** 11831f7ea1cdSQi Zhang * ice_vc_fdir_insert_entry 11841f7ea1cdSQi Zhang * @vf: pointer to the VF info 11851f7ea1cdSQi Zhang * @conf: FDIR configuration for each filter 11861f7ea1cdSQi Zhang * @id: pointer to ID value allocated by driver 11871f7ea1cdSQi Zhang * 11881f7ea1cdSQi Zhang * Insert FDIR conf entry into list and allocate ID for this filter 11891f7ea1cdSQi Zhang * 11901f7ea1cdSQi Zhang * Return: 0 true success, and other on error. 11911f7ea1cdSQi Zhang */ 11921f7ea1cdSQi Zhang static int 11931f7ea1cdSQi Zhang ice_vc_fdir_insert_entry(struct ice_vf *vf, 11941f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf, u32 *id) 11951f7ea1cdSQi Zhang { 11961f7ea1cdSQi Zhang struct ice_fdir_fltr *input = &conf->input; 11971f7ea1cdSQi Zhang int i; 11981f7ea1cdSQi Zhang 11991f7ea1cdSQi Zhang /* alloc ID corresponding with conf */ 12001f7ea1cdSQi Zhang i = idr_alloc(&vf->fdir.fdir_rule_idr, conf, 0, 12011f7ea1cdSQi Zhang ICE_FDIR_MAX_FLTRS, GFP_KERNEL); 12021f7ea1cdSQi Zhang if (i < 0) 12031f7ea1cdSQi Zhang return -EINVAL; 12041f7ea1cdSQi Zhang *id = i; 12051f7ea1cdSQi Zhang 12061f7ea1cdSQi Zhang list_add(&input->fltr_node, &vf->fdir.fdir_rule_list); 12071f7ea1cdSQi Zhang return 0; 12081f7ea1cdSQi Zhang } 12091f7ea1cdSQi Zhang 12101f7ea1cdSQi Zhang /** 12111f7ea1cdSQi Zhang * ice_vc_fdir_remove_entry - remove FDIR conf entry by ID value 12121f7ea1cdSQi Zhang * @vf: pointer to the VF info 12131f7ea1cdSQi Zhang * @conf: FDIR configuration for each filter 12141f7ea1cdSQi Zhang * @id: filter rule's ID 12151f7ea1cdSQi Zhang */ 12161f7ea1cdSQi Zhang static void 12171f7ea1cdSQi Zhang ice_vc_fdir_remove_entry(struct ice_vf *vf, 12181f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf, u32 id) 12191f7ea1cdSQi Zhang { 12201f7ea1cdSQi Zhang struct ice_fdir_fltr *input = &conf->input; 12211f7ea1cdSQi Zhang 12221f7ea1cdSQi Zhang idr_remove(&vf->fdir.fdir_rule_idr, id); 12231f7ea1cdSQi Zhang list_del(&input->fltr_node); 12241f7ea1cdSQi Zhang } 12251f7ea1cdSQi Zhang 12261f7ea1cdSQi Zhang /** 12271f7ea1cdSQi Zhang * ice_vc_fdir_lookup_entry - lookup FDIR conf entry by ID value 12281f7ea1cdSQi Zhang * @vf: pointer to the VF info 12291f7ea1cdSQi Zhang * @id: filter rule's ID 12301f7ea1cdSQi Zhang * 12311f7ea1cdSQi Zhang * Return: NULL on error, and other on success. 12321f7ea1cdSQi Zhang */ 12331f7ea1cdSQi Zhang static struct virtchnl_fdir_fltr_conf * 12341f7ea1cdSQi Zhang ice_vc_fdir_lookup_entry(struct ice_vf *vf, u32 id) 12351f7ea1cdSQi Zhang { 12361f7ea1cdSQi Zhang return idr_find(&vf->fdir.fdir_rule_idr, id); 12371f7ea1cdSQi Zhang } 12381f7ea1cdSQi Zhang 12391f7ea1cdSQi Zhang /** 12401f7ea1cdSQi Zhang * ice_vc_fdir_flush_entry - remove all FDIR conf entry 12411f7ea1cdSQi Zhang * @vf: pointer to the VF info 12421f7ea1cdSQi Zhang */ 12431f7ea1cdSQi Zhang static void ice_vc_fdir_flush_entry(struct ice_vf *vf) 12441f7ea1cdSQi Zhang { 12451f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf; 12461f7ea1cdSQi Zhang struct ice_fdir_fltr *desc, *temp; 12471f7ea1cdSQi Zhang 12481f7ea1cdSQi Zhang list_for_each_entry_safe(desc, temp, 12491f7ea1cdSQi Zhang &vf->fdir.fdir_rule_list, fltr_node) { 12501f7ea1cdSQi Zhang conf = to_fltr_conf_from_desc(desc); 12511f7ea1cdSQi Zhang list_del(&desc->fltr_node); 12521f7ea1cdSQi Zhang devm_kfree(ice_pf_to_dev(vf->pf), conf); 12531f7ea1cdSQi Zhang } 12541f7ea1cdSQi Zhang } 12551f7ea1cdSQi Zhang 12561f7ea1cdSQi Zhang /** 12571f7ea1cdSQi Zhang * ice_vc_fdir_write_fltr - write filter rule into hardware 12581f7ea1cdSQi Zhang * @vf: pointer to the VF info 12591f7ea1cdSQi Zhang * @conf: FDIR configuration for each filter 12601f7ea1cdSQi Zhang * @add: true implies add rule, false implies del rules 12611f7ea1cdSQi Zhang * @is_tun: false implies non-tunnel type filter, true implies tunnel filter 12621f7ea1cdSQi Zhang * 12631f7ea1cdSQi Zhang * Return: 0 on success, and other on error. 12641f7ea1cdSQi Zhang */ 12651f7ea1cdSQi Zhang static int ice_vc_fdir_write_fltr(struct ice_vf *vf, 12661f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf, 12671f7ea1cdSQi Zhang bool add, bool is_tun) 12681f7ea1cdSQi Zhang { 12691f7ea1cdSQi Zhang struct ice_fdir_fltr *input = &conf->input; 12701f7ea1cdSQi Zhang struct ice_vsi *vsi, *ctrl_vsi; 12711f7ea1cdSQi Zhang struct ice_fltr_desc desc; 12721f7ea1cdSQi Zhang struct device *dev; 12731f7ea1cdSQi Zhang struct ice_pf *pf; 12741f7ea1cdSQi Zhang struct ice_hw *hw; 12751f7ea1cdSQi Zhang int ret; 12761f7ea1cdSQi Zhang u8 *pkt; 12771f7ea1cdSQi Zhang 12781f7ea1cdSQi Zhang pf = vf->pf; 12791f7ea1cdSQi Zhang dev = ice_pf_to_dev(pf); 12801f7ea1cdSQi Zhang hw = &pf->hw; 1281772dec64SBrett Creeley vsi = ice_get_vf_vsi(vf); 12821f7ea1cdSQi Zhang if (!vsi) { 12831f7ea1cdSQi Zhang dev_dbg(dev, "Invalid vsi for VF %d\n", vf->vf_id); 12841f7ea1cdSQi Zhang return -EINVAL; 12851f7ea1cdSQi Zhang } 12861f7ea1cdSQi Zhang 12871f7ea1cdSQi Zhang input->dest_vsi = vsi->idx; 1288d6218317SQi Zhang input->comp_report = ICE_FXD_FLTR_QW0_COMP_REPORT_SW; 12891f7ea1cdSQi Zhang 12901f7ea1cdSQi Zhang ctrl_vsi = pf->vsi[vf->ctrl_vsi_idx]; 12911f7ea1cdSQi Zhang if (!ctrl_vsi) { 12921f7ea1cdSQi Zhang dev_dbg(dev, "Invalid ctrl_vsi for VF %d\n", vf->vf_id); 12931f7ea1cdSQi Zhang return -EINVAL; 12941f7ea1cdSQi Zhang } 12951f7ea1cdSQi Zhang 12961f7ea1cdSQi Zhang pkt = devm_kzalloc(dev, ICE_FDIR_MAX_RAW_PKT_SIZE, GFP_KERNEL); 12971f7ea1cdSQi Zhang if (!pkt) 12981f7ea1cdSQi Zhang return -ENOMEM; 12991f7ea1cdSQi Zhang 13001f7ea1cdSQi Zhang ice_fdir_get_prgm_desc(hw, input, &desc, add); 13012ccc1c1cSTony Nguyen ret = ice_fdir_get_gen_prgm_pkt(hw, input, pkt, false, is_tun); 13021f7ea1cdSQi Zhang if (ret) { 13031f7ea1cdSQi Zhang dev_dbg(dev, "Gen training pkt for VF %d ptype %d failed\n", 13041f7ea1cdSQi Zhang vf->vf_id, input->flow_type); 13051f7ea1cdSQi Zhang goto err_free_pkt; 13061f7ea1cdSQi Zhang } 13071f7ea1cdSQi Zhang 13081f7ea1cdSQi Zhang ret = ice_prgm_fdir_fltr(ctrl_vsi, &desc, pkt); 13091f7ea1cdSQi Zhang if (ret) 13101f7ea1cdSQi Zhang goto err_free_pkt; 13111f7ea1cdSQi Zhang 13121f7ea1cdSQi Zhang return 0; 13131f7ea1cdSQi Zhang 13141f7ea1cdSQi Zhang err_free_pkt: 13151f7ea1cdSQi Zhang devm_kfree(dev, pkt); 13161f7ea1cdSQi Zhang return ret; 13171f7ea1cdSQi Zhang } 13181f7ea1cdSQi Zhang 13191f7ea1cdSQi Zhang /** 1320d6218317SQi Zhang * ice_vf_fdir_timer - FDIR program waiting timer interrupt handler 1321d6218317SQi Zhang * @t: pointer to timer_list 1322d6218317SQi Zhang */ 1323d6218317SQi Zhang static void ice_vf_fdir_timer(struct timer_list *t) 1324d6218317SQi Zhang { 1325d6218317SQi Zhang struct ice_vf_fdir_ctx *ctx_irq = from_timer(ctx_irq, t, rx_tmr); 1326d6218317SQi Zhang struct ice_vf_fdir_ctx *ctx_done; 1327d6218317SQi Zhang struct ice_vf_fdir *fdir; 1328d6218317SQi Zhang unsigned long flags; 1329d6218317SQi Zhang struct ice_vf *vf; 1330d6218317SQi Zhang struct ice_pf *pf; 1331d6218317SQi Zhang 1332d6218317SQi Zhang fdir = container_of(ctx_irq, struct ice_vf_fdir, ctx_irq); 1333d6218317SQi Zhang vf = container_of(fdir, struct ice_vf, fdir); 1334d6218317SQi Zhang ctx_done = &fdir->ctx_done; 1335d6218317SQi Zhang pf = vf->pf; 1336d6218317SQi Zhang spin_lock_irqsave(&fdir->ctx_lock, flags); 1337d6218317SQi Zhang if (!(ctx_irq->flags & ICE_VF_FDIR_CTX_VALID)) { 1338d6218317SQi Zhang spin_unlock_irqrestore(&fdir->ctx_lock, flags); 1339d6218317SQi Zhang WARN_ON_ONCE(1); 1340d6218317SQi Zhang return; 1341d6218317SQi Zhang } 1342d6218317SQi Zhang 1343d6218317SQi Zhang ctx_irq->flags &= ~ICE_VF_FDIR_CTX_VALID; 1344d6218317SQi Zhang 1345d6218317SQi Zhang ctx_done->flags |= ICE_VF_FDIR_CTX_VALID; 1346d6218317SQi Zhang ctx_done->conf = ctx_irq->conf; 1347d6218317SQi Zhang ctx_done->stat = ICE_FDIR_CTX_TIMEOUT; 1348d6218317SQi Zhang ctx_done->v_opcode = ctx_irq->v_opcode; 1349d6218317SQi Zhang spin_unlock_irqrestore(&fdir->ctx_lock, flags); 1350d6218317SQi Zhang 13517e408e07SAnirudh Venkataramanan set_bit(ICE_FD_VF_FLUSH_CTX, pf->state); 1352d6218317SQi Zhang ice_service_task_schedule(pf); 1353d6218317SQi Zhang } 1354d6218317SQi Zhang 1355d6218317SQi Zhang /** 1356d6218317SQi Zhang * ice_vc_fdir_irq_handler - ctrl_vsi Rx queue interrupt handler 1357d6218317SQi Zhang * @ctrl_vsi: pointer to a VF's CTRL VSI 1358d6218317SQi Zhang * @rx_desc: pointer to FDIR Rx queue descriptor 1359d6218317SQi Zhang */ 1360d6218317SQi Zhang void 1361d6218317SQi Zhang ice_vc_fdir_irq_handler(struct ice_vsi *ctrl_vsi, 1362d6218317SQi Zhang union ice_32b_rx_flex_desc *rx_desc) 1363d6218317SQi Zhang { 1364d6218317SQi Zhang struct ice_pf *pf = ctrl_vsi->back; 1365b03d519dSJacob Keller struct ice_vf *vf = ctrl_vsi->vf; 1366d6218317SQi Zhang struct ice_vf_fdir_ctx *ctx_done; 1367d6218317SQi Zhang struct ice_vf_fdir_ctx *ctx_irq; 1368d6218317SQi Zhang struct ice_vf_fdir *fdir; 1369d6218317SQi Zhang unsigned long flags; 1370d6218317SQi Zhang struct device *dev; 1371d6218317SQi Zhang int ret; 1372d6218317SQi Zhang 1373b03d519dSJacob Keller if (WARN_ON(!vf)) 1374b03d519dSJacob Keller return; 1375d6218317SQi Zhang 1376d6218317SQi Zhang fdir = &vf->fdir; 1377d6218317SQi Zhang ctx_done = &fdir->ctx_done; 1378d6218317SQi Zhang ctx_irq = &fdir->ctx_irq; 1379d6218317SQi Zhang dev = ice_pf_to_dev(pf); 1380d6218317SQi Zhang spin_lock_irqsave(&fdir->ctx_lock, flags); 1381d6218317SQi Zhang if (!(ctx_irq->flags & ICE_VF_FDIR_CTX_VALID)) { 1382d6218317SQi Zhang spin_unlock_irqrestore(&fdir->ctx_lock, flags); 1383d6218317SQi Zhang WARN_ON_ONCE(1); 1384d6218317SQi Zhang return; 1385d6218317SQi Zhang } 1386d6218317SQi Zhang 1387d6218317SQi Zhang ctx_irq->flags &= ~ICE_VF_FDIR_CTX_VALID; 1388d6218317SQi Zhang 1389d6218317SQi Zhang ctx_done->flags |= ICE_VF_FDIR_CTX_VALID; 1390d6218317SQi Zhang ctx_done->conf = ctx_irq->conf; 1391d6218317SQi Zhang ctx_done->stat = ICE_FDIR_CTX_IRQ; 1392d6218317SQi Zhang ctx_done->v_opcode = ctx_irq->v_opcode; 1393d6218317SQi Zhang memcpy(&ctx_done->rx_desc, rx_desc, sizeof(*rx_desc)); 1394d6218317SQi Zhang spin_unlock_irqrestore(&fdir->ctx_lock, flags); 1395d6218317SQi Zhang 1396d6218317SQi Zhang ret = del_timer(&ctx_irq->rx_tmr); 1397d6218317SQi Zhang if (!ret) 1398d6218317SQi Zhang dev_err(dev, "VF %d: Unexpected inactive timer!\n", vf->vf_id); 1399d6218317SQi Zhang 14007e408e07SAnirudh Venkataramanan set_bit(ICE_FD_VF_FLUSH_CTX, pf->state); 1401d6218317SQi Zhang ice_service_task_schedule(pf); 1402d6218317SQi Zhang } 1403d6218317SQi Zhang 1404d6218317SQi Zhang /** 1405d6218317SQi Zhang * ice_vf_fdir_dump_info - dump FDIR information for diagnosis 1406d6218317SQi Zhang * @vf: pointer to the VF info 1407d6218317SQi Zhang */ 1408d6218317SQi Zhang static void ice_vf_fdir_dump_info(struct ice_vf *vf) 1409d6218317SQi Zhang { 1410d6218317SQi Zhang struct ice_vsi *vf_vsi; 1411d6218317SQi Zhang u32 fd_size, fd_cnt; 1412d6218317SQi Zhang struct device *dev; 1413d6218317SQi Zhang struct ice_pf *pf; 1414d6218317SQi Zhang struct ice_hw *hw; 1415d6218317SQi Zhang u16 vsi_num; 1416d6218317SQi Zhang 1417d6218317SQi Zhang pf = vf->pf; 1418d6218317SQi Zhang hw = &pf->hw; 1419d6218317SQi Zhang dev = ice_pf_to_dev(pf); 1420baeb705fSJacob Keller vf_vsi = ice_get_vf_vsi(vf); 1421baeb705fSJacob Keller if (!vf_vsi) { 1422baeb705fSJacob Keller dev_dbg(dev, "VF %d: invalid VSI pointer\n", vf->vf_id); 1423baeb705fSJacob Keller return; 1424baeb705fSJacob Keller } 1425baeb705fSJacob Keller 1426d6218317SQi Zhang vsi_num = ice_get_hw_vsi_num(hw, vf_vsi->idx); 1427d6218317SQi Zhang 1428d6218317SQi Zhang fd_size = rd32(hw, VSIQF_FD_SIZE(vsi_num)); 1429d6218317SQi Zhang fd_cnt = rd32(hw, VSIQF_FD_CNT(vsi_num)); 14309880d3d6SJacob Keller dev_dbg(dev, "VF %d: space allocated: guar:0x%x, be:0x%x, space consumed: guar:0x%x, be:0x%x\n", 1431d6218317SQi Zhang vf->vf_id, 1432d6218317SQi Zhang (fd_size & VSIQF_FD_CNT_FD_GCNT_M) >> VSIQF_FD_CNT_FD_GCNT_S, 1433d6218317SQi Zhang (fd_size & VSIQF_FD_CNT_FD_BCNT_M) >> VSIQF_FD_CNT_FD_BCNT_S, 1434d6218317SQi Zhang (fd_cnt & VSIQF_FD_CNT_FD_GCNT_M) >> VSIQF_FD_CNT_FD_GCNT_S, 1435d6218317SQi Zhang (fd_cnt & VSIQF_FD_CNT_FD_BCNT_M) >> VSIQF_FD_CNT_FD_BCNT_S); 1436d6218317SQi Zhang } 1437d6218317SQi Zhang 1438d6218317SQi Zhang /** 1439d6218317SQi Zhang * ice_vf_verify_rx_desc - verify received FDIR programming status descriptor 1440d6218317SQi Zhang * @vf: pointer to the VF info 1441d6218317SQi Zhang * @ctx: FDIR context info for post processing 1442d6218317SQi Zhang * @status: virtchnl FDIR program status 1443d6218317SQi Zhang * 1444d6218317SQi Zhang * Return: 0 on success, and other on error. 1445d6218317SQi Zhang */ 1446d6218317SQi Zhang static int 1447d6218317SQi Zhang ice_vf_verify_rx_desc(struct ice_vf *vf, struct ice_vf_fdir_ctx *ctx, 1448d6218317SQi Zhang enum virtchnl_fdir_prgm_status *status) 1449d6218317SQi Zhang { 1450d6218317SQi Zhang struct device *dev = ice_pf_to_dev(vf->pf); 1451d6218317SQi Zhang u32 stat_err, error, prog_id; 1452d6218317SQi Zhang int ret; 1453d6218317SQi Zhang 1454d6218317SQi Zhang stat_err = le16_to_cpu(ctx->rx_desc.wb.status_error0); 1455d6218317SQi Zhang if (((stat_err & ICE_FXD_FLTR_WB_QW1_DD_M) >> 1456d6218317SQi Zhang ICE_FXD_FLTR_WB_QW1_DD_S) != ICE_FXD_FLTR_WB_QW1_DD_YES) { 1457d6218317SQi Zhang *status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; 1458d6218317SQi Zhang dev_err(dev, "VF %d: Desc Done not set\n", vf->vf_id); 1459d6218317SQi Zhang ret = -EINVAL; 1460d6218317SQi Zhang goto err_exit; 1461d6218317SQi Zhang } 1462d6218317SQi Zhang 1463d6218317SQi Zhang prog_id = (stat_err & ICE_FXD_FLTR_WB_QW1_PROG_ID_M) >> 1464d6218317SQi Zhang ICE_FXD_FLTR_WB_QW1_PROG_ID_S; 1465d6218317SQi Zhang if (prog_id == ICE_FXD_FLTR_WB_QW1_PROG_ADD && 1466d6218317SQi Zhang ctx->v_opcode != VIRTCHNL_OP_ADD_FDIR_FILTER) { 1467d6218317SQi Zhang dev_err(dev, "VF %d: Desc show add, but ctx not", 1468d6218317SQi Zhang vf->vf_id); 1469d6218317SQi Zhang *status = VIRTCHNL_FDIR_FAILURE_RULE_INVALID; 1470d6218317SQi Zhang ret = -EINVAL; 1471d6218317SQi Zhang goto err_exit; 1472d6218317SQi Zhang } 1473d6218317SQi Zhang 1474d6218317SQi Zhang if (prog_id == ICE_FXD_FLTR_WB_QW1_PROG_DEL && 1475d6218317SQi Zhang ctx->v_opcode != VIRTCHNL_OP_DEL_FDIR_FILTER) { 1476d6218317SQi Zhang dev_err(dev, "VF %d: Desc show del, but ctx not", 1477d6218317SQi Zhang vf->vf_id); 1478d6218317SQi Zhang *status = VIRTCHNL_FDIR_FAILURE_RULE_INVALID; 1479d6218317SQi Zhang ret = -EINVAL; 1480d6218317SQi Zhang goto err_exit; 1481d6218317SQi Zhang } 1482d6218317SQi Zhang 1483d6218317SQi Zhang error = (stat_err & ICE_FXD_FLTR_WB_QW1_FAIL_M) >> 1484d6218317SQi Zhang ICE_FXD_FLTR_WB_QW1_FAIL_S; 1485d6218317SQi Zhang if (error == ICE_FXD_FLTR_WB_QW1_FAIL_YES) { 1486d6218317SQi Zhang if (prog_id == ICE_FXD_FLTR_WB_QW1_PROG_ADD) { 1487d6218317SQi Zhang dev_err(dev, "VF %d, Failed to add FDIR rule due to no space in the table", 1488d6218317SQi Zhang vf->vf_id); 1489d6218317SQi Zhang *status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; 1490d6218317SQi Zhang } else { 1491d6218317SQi Zhang dev_err(dev, "VF %d, Failed to remove FDIR rule, attempt to remove non-existent entry", 1492d6218317SQi Zhang vf->vf_id); 1493d6218317SQi Zhang *status = VIRTCHNL_FDIR_FAILURE_RULE_NONEXIST; 1494d6218317SQi Zhang } 1495d6218317SQi Zhang ret = -EINVAL; 1496d6218317SQi Zhang goto err_exit; 1497d6218317SQi Zhang } 1498d6218317SQi Zhang 1499d6218317SQi Zhang error = (stat_err & ICE_FXD_FLTR_WB_QW1_FAIL_PROF_M) >> 1500d6218317SQi Zhang ICE_FXD_FLTR_WB_QW1_FAIL_PROF_S; 1501d6218317SQi Zhang if (error == ICE_FXD_FLTR_WB_QW1_FAIL_PROF_YES) { 1502d6218317SQi Zhang dev_err(dev, "VF %d: Profile matching error", vf->vf_id); 1503d6218317SQi Zhang *status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; 1504d6218317SQi Zhang ret = -EINVAL; 1505d6218317SQi Zhang goto err_exit; 1506d6218317SQi Zhang } 1507d6218317SQi Zhang 1508d6218317SQi Zhang *status = VIRTCHNL_FDIR_SUCCESS; 1509d6218317SQi Zhang 1510d6218317SQi Zhang return 0; 1511d6218317SQi Zhang 1512d6218317SQi Zhang err_exit: 1513d6218317SQi Zhang ice_vf_fdir_dump_info(vf); 1514d6218317SQi Zhang return ret; 1515d6218317SQi Zhang } 1516d6218317SQi Zhang 1517d6218317SQi Zhang /** 1518d6218317SQi Zhang * ice_vc_add_fdir_fltr_post 1519d6218317SQi Zhang * @vf: pointer to the VF structure 1520d6218317SQi Zhang * @ctx: FDIR context info for post processing 1521d6218317SQi Zhang * @status: virtchnl FDIR program status 1522d6218317SQi Zhang * @success: true implies success, false implies failure 1523d6218317SQi Zhang * 1524d6218317SQi Zhang * Post process for flow director add command. If success, then do post process 1525d6218317SQi Zhang * and send back success msg by virtchnl. Otherwise, do context reversion and 1526d6218317SQi Zhang * send back failure msg by virtchnl. 1527d6218317SQi Zhang * 1528d6218317SQi Zhang * Return: 0 on success, and other on error. 1529d6218317SQi Zhang */ 1530d6218317SQi Zhang static int 1531d6218317SQi Zhang ice_vc_add_fdir_fltr_post(struct ice_vf *vf, struct ice_vf_fdir_ctx *ctx, 1532d6218317SQi Zhang enum virtchnl_fdir_prgm_status status, 1533d6218317SQi Zhang bool success) 1534d6218317SQi Zhang { 1535d6218317SQi Zhang struct virtchnl_fdir_fltr_conf *conf = ctx->conf; 1536d6218317SQi Zhang struct device *dev = ice_pf_to_dev(vf->pf); 1537d6218317SQi Zhang enum virtchnl_status_code v_ret; 1538d6218317SQi Zhang struct virtchnl_fdir_add *resp; 1539d6218317SQi Zhang int ret, len, is_tun; 1540d6218317SQi Zhang 1541d6218317SQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS; 1542d6218317SQi Zhang len = sizeof(*resp); 1543d6218317SQi Zhang resp = kzalloc(len, GFP_KERNEL); 1544d6218317SQi Zhang if (!resp) { 1545d6218317SQi Zhang len = 0; 1546d6218317SQi Zhang v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; 1547d6218317SQi Zhang dev_dbg(dev, "VF %d: Alloc resp buf fail", vf->vf_id); 1548d6218317SQi Zhang goto err_exit; 1549d6218317SQi Zhang } 1550d6218317SQi Zhang 1551d6218317SQi Zhang if (!success) 1552d6218317SQi Zhang goto err_exit; 1553d6218317SQi Zhang 1554d6218317SQi Zhang is_tun = 0; 1555d6218317SQi Zhang resp->status = status; 1556d6218317SQi Zhang resp->flow_id = conf->flow_id; 1557d6218317SQi Zhang vf->fdir.fdir_fltr_cnt[conf->input.flow_type][is_tun]++; 1558d6218317SQi Zhang 1559d6218317SQi Zhang ret = ice_vc_send_msg_to_vf(vf, ctx->v_opcode, v_ret, 1560d6218317SQi Zhang (u8 *)resp, len); 1561d6218317SQi Zhang kfree(resp); 1562d6218317SQi Zhang 1563d6218317SQi Zhang dev_dbg(dev, "VF %d: flow_id:0x%X, FDIR %s success!\n", 1564d6218317SQi Zhang vf->vf_id, conf->flow_id, 1565d6218317SQi Zhang (ctx->v_opcode == VIRTCHNL_OP_ADD_FDIR_FILTER) ? 1566d6218317SQi Zhang "add" : "del"); 1567d6218317SQi Zhang return ret; 1568d6218317SQi Zhang 1569d6218317SQi Zhang err_exit: 1570d6218317SQi Zhang if (resp) 1571d6218317SQi Zhang resp->status = status; 1572d6218317SQi Zhang ice_vc_fdir_remove_entry(vf, conf, conf->flow_id); 1573d6218317SQi Zhang devm_kfree(dev, conf); 1574d6218317SQi Zhang 1575d6218317SQi Zhang ret = ice_vc_send_msg_to_vf(vf, ctx->v_opcode, v_ret, 1576d6218317SQi Zhang (u8 *)resp, len); 1577d6218317SQi Zhang kfree(resp); 1578d6218317SQi Zhang return ret; 1579d6218317SQi Zhang } 1580d6218317SQi Zhang 1581d6218317SQi Zhang /** 1582d6218317SQi Zhang * ice_vc_del_fdir_fltr_post 1583d6218317SQi Zhang * @vf: pointer to the VF structure 1584d6218317SQi Zhang * @ctx: FDIR context info for post processing 1585d6218317SQi Zhang * @status: virtchnl FDIR program status 1586d6218317SQi Zhang * @success: true implies success, false implies failure 1587d6218317SQi Zhang * 1588d6218317SQi Zhang * Post process for flow director del command. If success, then do post process 1589d6218317SQi Zhang * and send back success msg by virtchnl. Otherwise, do context reversion and 1590d6218317SQi Zhang * send back failure msg by virtchnl. 1591d6218317SQi Zhang * 1592d6218317SQi Zhang * Return: 0 on success, and other on error. 1593d6218317SQi Zhang */ 1594d6218317SQi Zhang static int 1595d6218317SQi Zhang ice_vc_del_fdir_fltr_post(struct ice_vf *vf, struct ice_vf_fdir_ctx *ctx, 1596d6218317SQi Zhang enum virtchnl_fdir_prgm_status status, 1597d6218317SQi Zhang bool success) 1598d6218317SQi Zhang { 1599d6218317SQi Zhang struct virtchnl_fdir_fltr_conf *conf = ctx->conf; 1600d6218317SQi Zhang struct device *dev = ice_pf_to_dev(vf->pf); 1601d6218317SQi Zhang enum virtchnl_status_code v_ret; 1602d6218317SQi Zhang struct virtchnl_fdir_del *resp; 1603d6218317SQi Zhang int ret, len, is_tun; 1604d6218317SQi Zhang 1605d6218317SQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS; 1606d6218317SQi Zhang len = sizeof(*resp); 1607d6218317SQi Zhang resp = kzalloc(len, GFP_KERNEL); 1608d6218317SQi Zhang if (!resp) { 1609d6218317SQi Zhang len = 0; 1610d6218317SQi Zhang v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; 1611d6218317SQi Zhang dev_dbg(dev, "VF %d: Alloc resp buf fail", vf->vf_id); 1612d6218317SQi Zhang goto err_exit; 1613d6218317SQi Zhang } 1614d6218317SQi Zhang 1615d6218317SQi Zhang if (!success) 1616d6218317SQi Zhang goto err_exit; 1617d6218317SQi Zhang 1618d6218317SQi Zhang is_tun = 0; 1619d6218317SQi Zhang resp->status = status; 1620d6218317SQi Zhang ice_vc_fdir_remove_entry(vf, conf, conf->flow_id); 1621d6218317SQi Zhang vf->fdir.fdir_fltr_cnt[conf->input.flow_type][is_tun]--; 1622d6218317SQi Zhang 1623d6218317SQi Zhang ret = ice_vc_send_msg_to_vf(vf, ctx->v_opcode, v_ret, 1624d6218317SQi Zhang (u8 *)resp, len); 1625d6218317SQi Zhang kfree(resp); 1626d6218317SQi Zhang 1627d6218317SQi Zhang dev_dbg(dev, "VF %d: flow_id:0x%X, FDIR %s success!\n", 1628d6218317SQi Zhang vf->vf_id, conf->flow_id, 1629d6218317SQi Zhang (ctx->v_opcode == VIRTCHNL_OP_ADD_FDIR_FILTER) ? 1630d6218317SQi Zhang "add" : "del"); 1631d6218317SQi Zhang devm_kfree(dev, conf); 1632d6218317SQi Zhang return ret; 1633d6218317SQi Zhang 1634d6218317SQi Zhang err_exit: 1635d6218317SQi Zhang if (resp) 1636d6218317SQi Zhang resp->status = status; 1637d6218317SQi Zhang if (success) 1638d6218317SQi Zhang devm_kfree(dev, conf); 1639d6218317SQi Zhang 1640d6218317SQi Zhang ret = ice_vc_send_msg_to_vf(vf, ctx->v_opcode, v_ret, 1641d6218317SQi Zhang (u8 *)resp, len); 1642d6218317SQi Zhang kfree(resp); 1643d6218317SQi Zhang return ret; 1644d6218317SQi Zhang } 1645d6218317SQi Zhang 1646d6218317SQi Zhang /** 1647d6218317SQi Zhang * ice_flush_fdir_ctx 1648d6218317SQi Zhang * @pf: pointer to the PF structure 1649d6218317SQi Zhang * 1650d6218317SQi Zhang * Flush all the pending event on ctx_done list and process them. 1651d6218317SQi Zhang */ 1652d6218317SQi Zhang void ice_flush_fdir_ctx(struct ice_pf *pf) 1653d6218317SQi Zhang { 1654c4c2c7dbSJacob Keller struct ice_vf *vf; 1655c4c2c7dbSJacob Keller unsigned int bkt; 1656d6218317SQi Zhang 16577e408e07SAnirudh Venkataramanan if (!test_and_clear_bit(ICE_FD_VF_FLUSH_CTX, pf->state)) 1658d6218317SQi Zhang return; 1659d6218317SQi Zhang 16603d5985a1SJacob Keller mutex_lock(&pf->vfs.table_lock); 1661c4c2c7dbSJacob Keller ice_for_each_vf(pf, bkt, vf) { 1662d6218317SQi Zhang struct device *dev = ice_pf_to_dev(pf); 1663d6218317SQi Zhang enum virtchnl_fdir_prgm_status status; 1664d6218317SQi Zhang struct ice_vf_fdir_ctx *ctx; 1665d6218317SQi Zhang unsigned long flags; 1666d6218317SQi Zhang int ret; 1667d6218317SQi Zhang 1668d6218317SQi Zhang if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) 1669d6218317SQi Zhang continue; 1670d6218317SQi Zhang 1671d6218317SQi Zhang if (vf->ctrl_vsi_idx == ICE_NO_VSI) 1672d6218317SQi Zhang continue; 1673d6218317SQi Zhang 1674d6218317SQi Zhang ctx = &vf->fdir.ctx_done; 1675d6218317SQi Zhang spin_lock_irqsave(&vf->fdir.ctx_lock, flags); 1676d6218317SQi Zhang if (!(ctx->flags & ICE_VF_FDIR_CTX_VALID)) { 1677d6218317SQi Zhang spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags); 1678d6218317SQi Zhang continue; 1679d6218317SQi Zhang } 1680d6218317SQi Zhang spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags); 1681d6218317SQi Zhang 1682d6218317SQi Zhang WARN_ON(ctx->stat == ICE_FDIR_CTX_READY); 1683d6218317SQi Zhang if (ctx->stat == ICE_FDIR_CTX_TIMEOUT) { 1684d6218317SQi Zhang status = VIRTCHNL_FDIR_FAILURE_RULE_TIMEOUT; 1685d6218317SQi Zhang dev_err(dev, "VF %d: ctrl_vsi irq timeout\n", 1686d6218317SQi Zhang vf->vf_id); 1687d6218317SQi Zhang goto err_exit; 1688d6218317SQi Zhang } 1689d6218317SQi Zhang 1690d6218317SQi Zhang ret = ice_vf_verify_rx_desc(vf, ctx, &status); 1691d6218317SQi Zhang if (ret) 1692d6218317SQi Zhang goto err_exit; 1693d6218317SQi Zhang 1694d6218317SQi Zhang if (ctx->v_opcode == VIRTCHNL_OP_ADD_FDIR_FILTER) 1695d6218317SQi Zhang ice_vc_add_fdir_fltr_post(vf, ctx, status, true); 1696d6218317SQi Zhang else if (ctx->v_opcode == VIRTCHNL_OP_DEL_FDIR_FILTER) 1697d6218317SQi Zhang ice_vc_del_fdir_fltr_post(vf, ctx, status, true); 1698d6218317SQi Zhang else 1699d6218317SQi Zhang dev_err(dev, "VF %d: Unsupported opcode\n", vf->vf_id); 1700d6218317SQi Zhang 1701d6218317SQi Zhang spin_lock_irqsave(&vf->fdir.ctx_lock, flags); 1702d6218317SQi Zhang ctx->flags &= ~ICE_VF_FDIR_CTX_VALID; 1703d6218317SQi Zhang spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags); 1704d6218317SQi Zhang continue; 1705d6218317SQi Zhang err_exit: 1706d6218317SQi Zhang if (ctx->v_opcode == VIRTCHNL_OP_ADD_FDIR_FILTER) 1707d6218317SQi Zhang ice_vc_add_fdir_fltr_post(vf, ctx, status, false); 1708d6218317SQi Zhang else if (ctx->v_opcode == VIRTCHNL_OP_DEL_FDIR_FILTER) 1709d6218317SQi Zhang ice_vc_del_fdir_fltr_post(vf, ctx, status, false); 1710d6218317SQi Zhang else 1711d6218317SQi Zhang dev_err(dev, "VF %d: Unsupported opcode\n", vf->vf_id); 1712d6218317SQi Zhang 1713d6218317SQi Zhang spin_lock_irqsave(&vf->fdir.ctx_lock, flags); 1714d6218317SQi Zhang ctx->flags &= ~ICE_VF_FDIR_CTX_VALID; 1715d6218317SQi Zhang spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags); 1716d6218317SQi Zhang } 17173d5985a1SJacob Keller mutex_unlock(&pf->vfs.table_lock); 1718d6218317SQi Zhang } 1719d6218317SQi Zhang 1720d6218317SQi Zhang /** 1721d6218317SQi Zhang * ice_vc_fdir_set_irq_ctx - set FDIR context info for later IRQ handler 1722d6218317SQi Zhang * @vf: pointer to the VF structure 1723d6218317SQi Zhang * @conf: FDIR configuration for each filter 1724d6218317SQi Zhang * @v_opcode: virtual channel operation code 1725d6218317SQi Zhang * 1726d6218317SQi Zhang * Return: 0 on success, and other on error. 1727d6218317SQi Zhang */ 1728d6218317SQi Zhang static int 1729d6218317SQi Zhang ice_vc_fdir_set_irq_ctx(struct ice_vf *vf, struct virtchnl_fdir_fltr_conf *conf, 1730d6218317SQi Zhang enum virtchnl_ops v_opcode) 1731d6218317SQi Zhang { 1732d6218317SQi Zhang struct device *dev = ice_pf_to_dev(vf->pf); 1733d6218317SQi Zhang struct ice_vf_fdir_ctx *ctx; 1734d6218317SQi Zhang unsigned long flags; 1735d6218317SQi Zhang 1736d6218317SQi Zhang ctx = &vf->fdir.ctx_irq; 1737d6218317SQi Zhang spin_lock_irqsave(&vf->fdir.ctx_lock, flags); 1738d6218317SQi Zhang if ((vf->fdir.ctx_irq.flags & ICE_VF_FDIR_CTX_VALID) || 1739d6218317SQi Zhang (vf->fdir.ctx_done.flags & ICE_VF_FDIR_CTX_VALID)) { 1740d6218317SQi Zhang spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags); 1741d6218317SQi Zhang dev_dbg(dev, "VF %d: Last request is still in progress\n", 1742d6218317SQi Zhang vf->vf_id); 1743d6218317SQi Zhang return -EBUSY; 1744d6218317SQi Zhang } 1745d6218317SQi Zhang ctx->flags |= ICE_VF_FDIR_CTX_VALID; 1746d6218317SQi Zhang spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags); 1747d6218317SQi Zhang 1748d6218317SQi Zhang ctx->conf = conf; 1749d6218317SQi Zhang ctx->v_opcode = v_opcode; 1750d6218317SQi Zhang ctx->stat = ICE_FDIR_CTX_READY; 1751d6218317SQi Zhang timer_setup(&ctx->rx_tmr, ice_vf_fdir_timer, 0); 1752d6218317SQi Zhang 1753d6218317SQi Zhang mod_timer(&ctx->rx_tmr, round_jiffies(msecs_to_jiffies(10) + jiffies)); 1754d6218317SQi Zhang 1755d6218317SQi Zhang return 0; 1756d6218317SQi Zhang } 1757d6218317SQi Zhang 1758d6218317SQi Zhang /** 1759d6218317SQi Zhang * ice_vc_fdir_clear_irq_ctx - clear FDIR context info for IRQ handler 1760d6218317SQi Zhang * @vf: pointer to the VF structure 1761d6218317SQi Zhang * 1762d6218317SQi Zhang * Return: 0 on success, and other on error. 1763d6218317SQi Zhang */ 1764d6218317SQi Zhang static void ice_vc_fdir_clear_irq_ctx(struct ice_vf *vf) 1765d6218317SQi Zhang { 1766d6218317SQi Zhang struct ice_vf_fdir_ctx *ctx = &vf->fdir.ctx_irq; 1767d6218317SQi Zhang unsigned long flags; 1768d6218317SQi Zhang 1769d6218317SQi Zhang del_timer(&ctx->rx_tmr); 1770d6218317SQi Zhang spin_lock_irqsave(&vf->fdir.ctx_lock, flags); 1771d6218317SQi Zhang ctx->flags &= ~ICE_VF_FDIR_CTX_VALID; 1772d6218317SQi Zhang spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags); 1773d6218317SQi Zhang } 1774d6218317SQi Zhang 1775d6218317SQi Zhang /** 17761f7ea1cdSQi Zhang * ice_vc_add_fdir_fltr - add a FDIR filter for VF by the msg buffer 17771f7ea1cdSQi Zhang * @vf: pointer to the VF info 17781f7ea1cdSQi Zhang * @msg: pointer to the msg buffer 17791f7ea1cdSQi Zhang * 17801f7ea1cdSQi Zhang * Return: 0 on success, and other on error. 17811f7ea1cdSQi Zhang */ 17821f7ea1cdSQi Zhang int ice_vc_add_fdir_fltr(struct ice_vf *vf, u8 *msg) 17831f7ea1cdSQi Zhang { 17841f7ea1cdSQi Zhang struct virtchnl_fdir_add *fltr = (struct virtchnl_fdir_add *)msg; 17851f7ea1cdSQi Zhang struct virtchnl_fdir_add *stat = NULL; 17861f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf; 17871f7ea1cdSQi Zhang enum virtchnl_status_code v_ret; 17881f7ea1cdSQi Zhang struct device *dev; 17891f7ea1cdSQi Zhang struct ice_pf *pf; 17901f7ea1cdSQi Zhang int is_tun = 0; 17911f7ea1cdSQi Zhang int len = 0; 17921f7ea1cdSQi Zhang int ret; 17931f7ea1cdSQi Zhang 17941f7ea1cdSQi Zhang pf = vf->pf; 17951f7ea1cdSQi Zhang dev = ice_pf_to_dev(pf); 17961f7ea1cdSQi Zhang ret = ice_vc_fdir_param_check(vf, fltr->vsi_id); 17971f7ea1cdSQi Zhang if (ret) { 17981f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_ERR_PARAM; 17991f7ea1cdSQi Zhang dev_dbg(dev, "Parameter check for VF %d failed\n", vf->vf_id); 18001f7ea1cdSQi Zhang goto err_exit; 18011f7ea1cdSQi Zhang } 18021f7ea1cdSQi Zhang 18031f7ea1cdSQi Zhang ret = ice_vf_start_ctrl_vsi(vf); 18041f7ea1cdSQi Zhang if (ret && (ret != -EEXIST)) { 18051f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_ERR_PARAM; 18061f7ea1cdSQi Zhang dev_err(dev, "Init FDIR for VF %d failed, ret:%d\n", 18071f7ea1cdSQi Zhang vf->vf_id, ret); 18081f7ea1cdSQi Zhang goto err_exit; 18091f7ea1cdSQi Zhang } 18101f7ea1cdSQi Zhang 18111f7ea1cdSQi Zhang stat = kzalloc(sizeof(*stat), GFP_KERNEL); 18121f7ea1cdSQi Zhang if (!stat) { 18131f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; 18141f7ea1cdSQi Zhang dev_dbg(dev, "Alloc stat for VF %d failed\n", vf->vf_id); 18151f7ea1cdSQi Zhang goto err_exit; 18161f7ea1cdSQi Zhang } 18171f7ea1cdSQi Zhang 18181f7ea1cdSQi Zhang conf = devm_kzalloc(dev, sizeof(*conf), GFP_KERNEL); 18191f7ea1cdSQi Zhang if (!conf) { 18201f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; 18211f7ea1cdSQi Zhang dev_dbg(dev, "Alloc conf for VF %d failed\n", vf->vf_id); 18221f7ea1cdSQi Zhang goto err_exit; 18231f7ea1cdSQi Zhang } 18241f7ea1cdSQi Zhang 18251f7ea1cdSQi Zhang len = sizeof(*stat); 18261f7ea1cdSQi Zhang ret = ice_vc_validate_fdir_fltr(vf, fltr, conf); 18271f7ea1cdSQi Zhang if (ret) { 18281f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS; 18291f7ea1cdSQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_INVALID; 18301f7ea1cdSQi Zhang dev_dbg(dev, "Invalid FDIR filter from VF %d\n", vf->vf_id); 18311f7ea1cdSQi Zhang goto err_free_conf; 18321f7ea1cdSQi Zhang } 18331f7ea1cdSQi Zhang 18341f7ea1cdSQi Zhang if (fltr->validate_only) { 18351f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS; 18361f7ea1cdSQi Zhang stat->status = VIRTCHNL_FDIR_SUCCESS; 18371f7ea1cdSQi Zhang devm_kfree(dev, conf); 18381f7ea1cdSQi Zhang ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ADD_FDIR_FILTER, 18391f7ea1cdSQi Zhang v_ret, (u8 *)stat, len); 18401f7ea1cdSQi Zhang goto exit; 18411f7ea1cdSQi Zhang } 18421f7ea1cdSQi Zhang 18431f7ea1cdSQi Zhang ret = ice_vc_fdir_config_input_set(vf, fltr, conf, is_tun); 18441f7ea1cdSQi Zhang if (ret) { 18451f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS; 18461f7ea1cdSQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_CONFLICT; 18471f7ea1cdSQi Zhang dev_err(dev, "VF %d: FDIR input set configure failed, ret:%d\n", 18481f7ea1cdSQi Zhang vf->vf_id, ret); 18491f7ea1cdSQi Zhang goto err_free_conf; 18501f7ea1cdSQi Zhang } 18511f7ea1cdSQi Zhang 18521f7ea1cdSQi Zhang ret = ice_vc_fdir_is_dup_fltr(vf, conf); 18531f7ea1cdSQi Zhang if (ret) { 18541f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS; 18551f7ea1cdSQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_EXIST; 18561f7ea1cdSQi Zhang dev_dbg(dev, "VF %d: duplicated FDIR rule detected\n", 18571f7ea1cdSQi Zhang vf->vf_id); 18581f7ea1cdSQi Zhang goto err_free_conf; 18591f7ea1cdSQi Zhang } 18601f7ea1cdSQi Zhang 1861d6218317SQi Zhang ret = ice_vc_fdir_insert_entry(vf, conf, &conf->flow_id); 18621f7ea1cdSQi Zhang if (ret) { 18631f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS; 18641f7ea1cdSQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; 18651f7ea1cdSQi Zhang dev_dbg(dev, "VF %d: insert FDIR list failed\n", vf->vf_id); 18661f7ea1cdSQi Zhang goto err_free_conf; 18671f7ea1cdSQi Zhang } 18681f7ea1cdSQi Zhang 1869d6218317SQi Zhang ret = ice_vc_fdir_set_irq_ctx(vf, conf, VIRTCHNL_OP_ADD_FDIR_FILTER); 1870d6218317SQi Zhang if (ret) { 1871d6218317SQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS; 1872d6218317SQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; 1873d6218317SQi Zhang dev_dbg(dev, "VF %d: set FDIR context failed\n", vf->vf_id); 1874*b4a01aceSSimei Su goto err_rem_entry; 1875d6218317SQi Zhang } 1876d6218317SQi Zhang 18771f7ea1cdSQi Zhang ret = ice_vc_fdir_write_fltr(vf, conf, true, is_tun); 18781f7ea1cdSQi Zhang if (ret) { 18791f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS; 18801f7ea1cdSQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; 18811f7ea1cdSQi Zhang dev_err(dev, "VF %d: writing FDIR rule failed, ret:%d\n", 18821f7ea1cdSQi Zhang vf->vf_id, ret); 1883*b4a01aceSSimei Su goto err_clr_irq; 18841f7ea1cdSQi Zhang } 18851f7ea1cdSQi Zhang 18861f7ea1cdSQi Zhang exit: 18871f7ea1cdSQi Zhang kfree(stat); 18881f7ea1cdSQi Zhang return ret; 18891f7ea1cdSQi Zhang 1890*b4a01aceSSimei Su err_clr_irq: 1891d6218317SQi Zhang ice_vc_fdir_clear_irq_ctx(vf); 1892*b4a01aceSSimei Su err_rem_entry: 1893d6218317SQi Zhang ice_vc_fdir_remove_entry(vf, conf, conf->flow_id); 18941f7ea1cdSQi Zhang err_free_conf: 18951f7ea1cdSQi Zhang devm_kfree(dev, conf); 18961f7ea1cdSQi Zhang err_exit: 18971f7ea1cdSQi Zhang ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ADD_FDIR_FILTER, v_ret, 18981f7ea1cdSQi Zhang (u8 *)stat, len); 18991f7ea1cdSQi Zhang kfree(stat); 19001f7ea1cdSQi Zhang return ret; 19011f7ea1cdSQi Zhang } 19021f7ea1cdSQi Zhang 19031f7ea1cdSQi Zhang /** 19041f7ea1cdSQi Zhang * ice_vc_del_fdir_fltr - delete a FDIR filter for VF by the msg buffer 19051f7ea1cdSQi Zhang * @vf: pointer to the VF info 19061f7ea1cdSQi Zhang * @msg: pointer to the msg buffer 19071f7ea1cdSQi Zhang * 19081f7ea1cdSQi Zhang * Return: 0 on success, and other on error. 19091f7ea1cdSQi Zhang */ 19101f7ea1cdSQi Zhang int ice_vc_del_fdir_fltr(struct ice_vf *vf, u8 *msg) 19111f7ea1cdSQi Zhang { 19121f7ea1cdSQi Zhang struct virtchnl_fdir_del *fltr = (struct virtchnl_fdir_del *)msg; 19131f7ea1cdSQi Zhang struct virtchnl_fdir_del *stat = NULL; 19141f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf; 19151f7ea1cdSQi Zhang enum virtchnl_status_code v_ret; 19161f7ea1cdSQi Zhang struct device *dev; 19171f7ea1cdSQi Zhang struct ice_pf *pf; 19181f7ea1cdSQi Zhang int is_tun = 0; 19191f7ea1cdSQi Zhang int len = 0; 19201f7ea1cdSQi Zhang int ret; 19211f7ea1cdSQi Zhang 19221f7ea1cdSQi Zhang pf = vf->pf; 19231f7ea1cdSQi Zhang dev = ice_pf_to_dev(pf); 19241f7ea1cdSQi Zhang ret = ice_vc_fdir_param_check(vf, fltr->vsi_id); 19251f7ea1cdSQi Zhang if (ret) { 19261f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_ERR_PARAM; 19271f7ea1cdSQi Zhang dev_dbg(dev, "Parameter check for VF %d failed\n", vf->vf_id); 19281f7ea1cdSQi Zhang goto err_exit; 19291f7ea1cdSQi Zhang } 19301f7ea1cdSQi Zhang 19311f7ea1cdSQi Zhang stat = kzalloc(sizeof(*stat), GFP_KERNEL); 19321f7ea1cdSQi Zhang if (!stat) { 19331f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; 19341f7ea1cdSQi Zhang dev_dbg(dev, "Alloc stat for VF %d failed\n", vf->vf_id); 19351f7ea1cdSQi Zhang goto err_exit; 19361f7ea1cdSQi Zhang } 19371f7ea1cdSQi Zhang 19381f7ea1cdSQi Zhang len = sizeof(*stat); 19391f7ea1cdSQi Zhang 19401f7ea1cdSQi Zhang conf = ice_vc_fdir_lookup_entry(vf, fltr->flow_id); 19411f7ea1cdSQi Zhang if (!conf) { 19421f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS; 19431f7ea1cdSQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NONEXIST; 19441f7ea1cdSQi Zhang dev_dbg(dev, "VF %d: FDIR invalid flow_id:0x%X\n", 19451f7ea1cdSQi Zhang vf->vf_id, fltr->flow_id); 19461f7ea1cdSQi Zhang goto err_exit; 19471f7ea1cdSQi Zhang } 19481f7ea1cdSQi Zhang 19491f7ea1cdSQi Zhang /* Just return failure when ctrl_vsi idx is invalid */ 19501f7ea1cdSQi Zhang if (vf->ctrl_vsi_idx == ICE_NO_VSI) { 19511f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS; 19521f7ea1cdSQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; 19531f7ea1cdSQi Zhang dev_err(dev, "Invalid FDIR ctrl_vsi for VF %d\n", vf->vf_id); 19541f7ea1cdSQi Zhang goto err_exit; 19551f7ea1cdSQi Zhang } 19561f7ea1cdSQi Zhang 1957d6218317SQi Zhang ret = ice_vc_fdir_set_irq_ctx(vf, conf, VIRTCHNL_OP_DEL_FDIR_FILTER); 1958d6218317SQi Zhang if (ret) { 1959d6218317SQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS; 1960d6218317SQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; 1961d6218317SQi Zhang dev_dbg(dev, "VF %d: set FDIR context failed\n", vf->vf_id); 1962d6218317SQi Zhang goto err_exit; 1963d6218317SQi Zhang } 1964d6218317SQi Zhang 19651f7ea1cdSQi Zhang ret = ice_vc_fdir_write_fltr(vf, conf, false, is_tun); 19661f7ea1cdSQi Zhang if (ret) { 19671f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS; 19681f7ea1cdSQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; 19691f7ea1cdSQi Zhang dev_err(dev, "VF %d: writing FDIR rule failed, ret:%d\n", 19701f7ea1cdSQi Zhang vf->vf_id, ret); 1971d6218317SQi Zhang goto err_del_tmr; 19721f7ea1cdSQi Zhang } 19731f7ea1cdSQi Zhang 1974d6218317SQi Zhang kfree(stat); 19751f7ea1cdSQi Zhang 1976d6218317SQi Zhang return ret; 19771f7ea1cdSQi Zhang 1978d6218317SQi Zhang err_del_tmr: 1979d6218317SQi Zhang ice_vc_fdir_clear_irq_ctx(vf); 19801f7ea1cdSQi Zhang err_exit: 19811f7ea1cdSQi Zhang ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DEL_FDIR_FILTER, v_ret, 19821f7ea1cdSQi Zhang (u8 *)stat, len); 19831f7ea1cdSQi Zhang kfree(stat); 19841f7ea1cdSQi Zhang return ret; 19851f7ea1cdSQi Zhang } 19861f7ea1cdSQi Zhang 19871f7ea1cdSQi Zhang /** 19881f7ea1cdSQi Zhang * ice_vf_fdir_init - init FDIR resource for VF 19891f7ea1cdSQi Zhang * @vf: pointer to the VF info 19901f7ea1cdSQi Zhang */ 19911f7ea1cdSQi Zhang void ice_vf_fdir_init(struct ice_vf *vf) 19921f7ea1cdSQi Zhang { 19931f7ea1cdSQi Zhang struct ice_vf_fdir *fdir = &vf->fdir; 19941f7ea1cdSQi Zhang 19951f7ea1cdSQi Zhang idr_init(&fdir->fdir_rule_idr); 19961f7ea1cdSQi Zhang INIT_LIST_HEAD(&fdir->fdir_rule_list); 1997d6218317SQi Zhang 1998d6218317SQi Zhang spin_lock_init(&fdir->ctx_lock); 1999d6218317SQi Zhang fdir->ctx_irq.flags = 0; 2000d6218317SQi Zhang fdir->ctx_done.flags = 0; 20011f7ea1cdSQi Zhang } 20021f7ea1cdSQi Zhang 20031f7ea1cdSQi Zhang /** 20041f7ea1cdSQi Zhang * ice_vf_fdir_exit - destroy FDIR resource for VF 20051f7ea1cdSQi Zhang * @vf: pointer to the VF info 20061f7ea1cdSQi Zhang */ 20071f7ea1cdSQi Zhang void ice_vf_fdir_exit(struct ice_vf *vf) 20081f7ea1cdSQi Zhang { 20091f7ea1cdSQi Zhang ice_vc_fdir_flush_entry(vf); 20101f7ea1cdSQi Zhang idr_destroy(&vf->fdir.fdir_rule_idr); 20111f7ea1cdSQi Zhang ice_vc_fdir_rem_prof_all(vf); 20121f7ea1cdSQi Zhang ice_vc_fdir_free_prof_all(vf); 20131f7ea1cdSQi Zhang } 2014