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 1161f7ea1cdSQi Zhang if (!pf->vsi[vf->lan_vsi_idx]) 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 4971f7ea1cdSQi Zhang vf_vsi = pf->vsi[vf->lan_vsi_idx]; 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 /** 5451f7ea1cdSQi Zhang * ice_vc_fdir_write_flow_prof 5461f7ea1cdSQi Zhang * @vf: pointer to the VF structure 5471f7ea1cdSQi Zhang * @flow: filter flow type 5481f7ea1cdSQi Zhang * @seg: array of one or more packet segments that describe the flow 5491f7ea1cdSQi Zhang * @tun: 0 implies non-tunnel type filter, 1 implies tunnel type filter 5501f7ea1cdSQi Zhang * 5511f7ea1cdSQi Zhang * Write the flow's profile config and packet segment into the hardware 5521f7ea1cdSQi Zhang * 5531f7ea1cdSQi Zhang * Return: 0 on success, and other on error. 5541f7ea1cdSQi Zhang */ 5551f7ea1cdSQi Zhang static int 5561f7ea1cdSQi Zhang ice_vc_fdir_write_flow_prof(struct ice_vf *vf, enum ice_fltr_ptype flow, 5571f7ea1cdSQi Zhang struct ice_flow_seg_info *seg, int tun) 5581f7ea1cdSQi Zhang { 5591f7ea1cdSQi Zhang struct ice_vf_fdir *fdir = &vf->fdir; 5601f7ea1cdSQi Zhang struct ice_vsi *vf_vsi, *ctrl_vsi; 5611f7ea1cdSQi Zhang struct ice_flow_seg_info *old_seg; 5621f7ea1cdSQi Zhang struct ice_flow_prof *prof = NULL; 5631f7ea1cdSQi Zhang struct ice_fd_hw_prof *vf_prof; 5641f7ea1cdSQi Zhang struct device *dev; 5651f7ea1cdSQi Zhang struct ice_pf *pf; 5661f7ea1cdSQi Zhang struct ice_hw *hw; 5671f7ea1cdSQi Zhang u64 entry1_h = 0; 5681f7ea1cdSQi Zhang u64 entry2_h = 0; 5691f7ea1cdSQi Zhang u64 prof_id; 5701f7ea1cdSQi Zhang int ret; 5711f7ea1cdSQi Zhang 5721f7ea1cdSQi Zhang pf = vf->pf; 5731f7ea1cdSQi Zhang dev = ice_pf_to_dev(pf); 5741f7ea1cdSQi Zhang hw = &pf->hw; 5751f7ea1cdSQi Zhang vf_vsi = pf->vsi[vf->lan_vsi_idx]; 5761f7ea1cdSQi Zhang if (!vf_vsi) 5771f7ea1cdSQi Zhang return -EINVAL; 5781f7ea1cdSQi Zhang 5791f7ea1cdSQi Zhang ctrl_vsi = pf->vsi[vf->ctrl_vsi_idx]; 5801f7ea1cdSQi Zhang if (!ctrl_vsi) 5811f7ea1cdSQi Zhang return -EINVAL; 5821f7ea1cdSQi Zhang 5831f7ea1cdSQi Zhang vf_prof = fdir->fdir_prof[flow]; 5841f7ea1cdSQi Zhang old_seg = vf_prof->fdir_seg[tun]; 5851f7ea1cdSQi Zhang if (old_seg) { 5861f7ea1cdSQi Zhang if (!memcmp(old_seg, seg, sizeof(*seg))) { 5871f7ea1cdSQi Zhang dev_dbg(dev, "Duplicated profile for VF %d!\n", 5881f7ea1cdSQi Zhang vf->vf_id); 5891f7ea1cdSQi Zhang return -EEXIST; 5901f7ea1cdSQi Zhang } 5911f7ea1cdSQi Zhang 5921f7ea1cdSQi Zhang if (fdir->fdir_fltr_cnt[flow][tun]) { 5931f7ea1cdSQi Zhang ret = -EINVAL; 5941f7ea1cdSQi Zhang dev_dbg(dev, "Input set conflicts for VF %d\n", 5951f7ea1cdSQi Zhang vf->vf_id); 5961f7ea1cdSQi Zhang goto err_exit; 5971f7ea1cdSQi Zhang } 5981f7ea1cdSQi Zhang 5991f7ea1cdSQi Zhang /* remove previously allocated profile */ 6001f7ea1cdSQi Zhang ice_vc_fdir_rem_prof(vf, flow, tun); 6011f7ea1cdSQi Zhang } 6021f7ea1cdSQi Zhang 6031f7ea1cdSQi Zhang prof_id = ICE_FLOW_PROF_FD(vf_vsi->vsi_num, flow, 6041f7ea1cdSQi Zhang tun ? ICE_FLTR_PTYPE_MAX : 0); 6051f7ea1cdSQi Zhang 6062ccc1c1cSTony Nguyen ret = ice_flow_add_prof(hw, ICE_BLK_FD, ICE_FLOW_RX, prof_id, seg, 6071f7ea1cdSQi Zhang tun + 1, &prof); 6081f7ea1cdSQi Zhang if (ret) { 6091f7ea1cdSQi Zhang dev_dbg(dev, "Could not add VSI flow 0x%x for VF %d\n", 6101f7ea1cdSQi Zhang flow, vf->vf_id); 6111f7ea1cdSQi Zhang goto err_exit; 6121f7ea1cdSQi Zhang } 6131f7ea1cdSQi Zhang 6142ccc1c1cSTony Nguyen ret = ice_flow_add_entry(hw, ICE_BLK_FD, prof_id, vf_vsi->idx, 6151f7ea1cdSQi Zhang vf_vsi->idx, ICE_FLOW_PRIO_NORMAL, 6161f7ea1cdSQi Zhang seg, &entry1_h); 6171f7ea1cdSQi Zhang if (ret) { 6181f7ea1cdSQi Zhang dev_dbg(dev, "Could not add flow 0x%x VSI entry for VF %d\n", 6191f7ea1cdSQi Zhang flow, vf->vf_id); 6201f7ea1cdSQi Zhang goto err_prof; 6211f7ea1cdSQi Zhang } 6221f7ea1cdSQi Zhang 6232ccc1c1cSTony Nguyen ret = ice_flow_add_entry(hw, ICE_BLK_FD, prof_id, vf_vsi->idx, 6241f7ea1cdSQi Zhang ctrl_vsi->idx, ICE_FLOW_PRIO_NORMAL, 6251f7ea1cdSQi Zhang seg, &entry2_h); 6261f7ea1cdSQi Zhang if (ret) { 6271f7ea1cdSQi Zhang dev_dbg(dev, 6281f7ea1cdSQi Zhang "Could not add flow 0x%x Ctrl VSI entry for VF %d\n", 6291f7ea1cdSQi Zhang flow, vf->vf_id); 6301f7ea1cdSQi Zhang goto err_entry_1; 6311f7ea1cdSQi Zhang } 6321f7ea1cdSQi Zhang 6331f7ea1cdSQi Zhang vf_prof->fdir_seg[tun] = seg; 6341f7ea1cdSQi Zhang vf_prof->cnt = 0; 6351f7ea1cdSQi Zhang fdir->prof_entry_cnt[flow][tun] = 0; 6361f7ea1cdSQi Zhang 6371f7ea1cdSQi Zhang vf_prof->entry_h[vf_prof->cnt][tun] = entry1_h; 6381f7ea1cdSQi Zhang vf_prof->vsi_h[vf_prof->cnt] = vf_vsi->idx; 6391f7ea1cdSQi Zhang vf_prof->cnt++; 6401f7ea1cdSQi Zhang fdir->prof_entry_cnt[flow][tun]++; 6411f7ea1cdSQi Zhang 6421f7ea1cdSQi Zhang vf_prof->entry_h[vf_prof->cnt][tun] = entry2_h; 6431f7ea1cdSQi Zhang vf_prof->vsi_h[vf_prof->cnt] = ctrl_vsi->idx; 6441f7ea1cdSQi Zhang vf_prof->cnt++; 6451f7ea1cdSQi Zhang fdir->prof_entry_cnt[flow][tun]++; 6461f7ea1cdSQi Zhang 6471f7ea1cdSQi Zhang return 0; 6481f7ea1cdSQi Zhang 6491f7ea1cdSQi Zhang err_entry_1: 6501f7ea1cdSQi Zhang ice_rem_prof_id_flow(hw, ICE_BLK_FD, 6511f7ea1cdSQi Zhang ice_get_hw_vsi_num(hw, vf_vsi->idx), prof_id); 6521f7ea1cdSQi Zhang ice_flow_rem_entry(hw, ICE_BLK_FD, entry1_h); 6531f7ea1cdSQi Zhang err_prof: 6541f7ea1cdSQi Zhang ice_flow_rem_prof(hw, ICE_BLK_FD, prof_id); 6551f7ea1cdSQi Zhang err_exit: 6561f7ea1cdSQi Zhang return ret; 6571f7ea1cdSQi Zhang } 6581f7ea1cdSQi Zhang 6591f7ea1cdSQi Zhang /** 6601f7ea1cdSQi Zhang * ice_vc_fdir_config_input_set 6611f7ea1cdSQi Zhang * @vf: pointer to the VF structure 6621f7ea1cdSQi Zhang * @fltr: virtual channel add cmd buffer 6631f7ea1cdSQi Zhang * @conf: FDIR configuration for each filter 6641f7ea1cdSQi Zhang * @tun: 0 implies non-tunnel type filter, 1 implies tunnel type filter 6651f7ea1cdSQi Zhang * 6661f7ea1cdSQi Zhang * Config the input set type and value for virtual channel add msg buffer 6671f7ea1cdSQi Zhang * 6681f7ea1cdSQi Zhang * Return: 0 on success, and other on error. 6691f7ea1cdSQi Zhang */ 6701f7ea1cdSQi Zhang static int 6711f7ea1cdSQi Zhang ice_vc_fdir_config_input_set(struct ice_vf *vf, struct virtchnl_fdir_add *fltr, 6721f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf, int tun) 6731f7ea1cdSQi Zhang { 6741f7ea1cdSQi Zhang struct ice_fdir_fltr *input = &conf->input; 6751f7ea1cdSQi Zhang struct device *dev = ice_pf_to_dev(vf->pf); 6761f7ea1cdSQi Zhang struct ice_flow_seg_info *seg; 6771f7ea1cdSQi Zhang enum ice_fltr_ptype flow; 6781f7ea1cdSQi Zhang int ret; 6791f7ea1cdSQi Zhang 6801f7ea1cdSQi Zhang flow = input->flow_type; 6811f7ea1cdSQi Zhang ret = ice_vc_fdir_alloc_prof(vf, flow); 6821f7ea1cdSQi Zhang if (ret) { 6831f7ea1cdSQi Zhang dev_dbg(dev, "Alloc flow prof for VF %d failed\n", vf->vf_id); 6841f7ea1cdSQi Zhang return ret; 6851f7ea1cdSQi Zhang } 6861f7ea1cdSQi Zhang 6871f7ea1cdSQi Zhang seg = devm_kzalloc(dev, sizeof(*seg), GFP_KERNEL); 6881f7ea1cdSQi Zhang if (!seg) 6891f7ea1cdSQi Zhang return -ENOMEM; 6901f7ea1cdSQi Zhang 6911f7ea1cdSQi Zhang ret = ice_vc_fdir_set_flow_fld(vf, fltr, conf, seg); 6921f7ea1cdSQi Zhang if (ret) { 6931f7ea1cdSQi Zhang dev_dbg(dev, "Set flow field for VF %d failed\n", vf->vf_id); 6941f7ea1cdSQi Zhang goto err_exit; 6951f7ea1cdSQi Zhang } 6961f7ea1cdSQi Zhang 6971f7ea1cdSQi Zhang ret = ice_vc_fdir_set_flow_hdr(vf, conf, seg); 6981f7ea1cdSQi Zhang if (ret) { 6991f7ea1cdSQi Zhang dev_dbg(dev, "Set flow hdr for VF %d failed\n", vf->vf_id); 7001f7ea1cdSQi Zhang goto err_exit; 7011f7ea1cdSQi Zhang } 7021f7ea1cdSQi Zhang 7031f7ea1cdSQi Zhang ret = ice_vc_fdir_write_flow_prof(vf, flow, seg, tun); 7041f7ea1cdSQi Zhang if (ret == -EEXIST) { 7051f7ea1cdSQi Zhang devm_kfree(dev, seg); 7061f7ea1cdSQi Zhang } else if (ret) { 7071f7ea1cdSQi Zhang dev_dbg(dev, "Write flow profile for VF %d failed\n", 7081f7ea1cdSQi Zhang vf->vf_id); 7091f7ea1cdSQi Zhang goto err_exit; 7101f7ea1cdSQi Zhang } 7111f7ea1cdSQi Zhang 7121f7ea1cdSQi Zhang return 0; 7131f7ea1cdSQi Zhang 7141f7ea1cdSQi Zhang err_exit: 7151f7ea1cdSQi Zhang devm_kfree(dev, seg); 7161f7ea1cdSQi Zhang return ret; 7171f7ea1cdSQi Zhang } 7181f7ea1cdSQi Zhang 7191f7ea1cdSQi Zhang /** 7200ce332fdSQi Zhang * ice_vc_fdir_parse_pattern 7210ce332fdSQi Zhang * @vf: pointer to the VF info 7220ce332fdSQi Zhang * @fltr: virtual channel add cmd buffer 7230ce332fdSQi Zhang * @conf: FDIR configuration for each filter 7240ce332fdSQi Zhang * 7250ce332fdSQi Zhang * Parse the virtual channel filter's pattern and store them into conf 7260ce332fdSQi Zhang * 7270ce332fdSQi Zhang * Return: 0 on success, and other on error. 7280ce332fdSQi Zhang */ 7290ce332fdSQi Zhang static int 7300ce332fdSQi Zhang ice_vc_fdir_parse_pattern(struct ice_vf *vf, struct virtchnl_fdir_add *fltr, 7310ce332fdSQi Zhang struct virtchnl_fdir_fltr_conf *conf) 7320ce332fdSQi Zhang { 7330ce332fdSQi Zhang struct virtchnl_proto_hdrs *proto = &fltr->rule_cfg.proto_hdrs; 7340ce332fdSQi Zhang enum virtchnl_proto_hdr_type l3 = VIRTCHNL_PROTO_HDR_NONE; 735213528feSQi Zhang enum virtchnl_proto_hdr_type l4 = VIRTCHNL_PROTO_HDR_NONE; 7360ce332fdSQi Zhang struct device *dev = ice_pf_to_dev(vf->pf); 7370ce332fdSQi Zhang struct ice_fdir_fltr *input = &conf->input; 7380ce332fdSQi Zhang int i; 7390ce332fdSQi Zhang 7400ce332fdSQi Zhang if (proto->count > VIRTCHNL_MAX_NUM_PROTO_HDRS) { 7410ce332fdSQi Zhang dev_dbg(dev, "Invalid protocol count:0x%x for VF %d\n", 7420ce332fdSQi Zhang proto->count, vf->vf_id); 7430ce332fdSQi Zhang return -EINVAL; 7440ce332fdSQi Zhang } 7450ce332fdSQi Zhang 7460ce332fdSQi Zhang for (i = 0; i < proto->count; i++) { 7470ce332fdSQi Zhang struct virtchnl_proto_hdr *hdr = &proto->proto_hdr[i]; 748213528feSQi Zhang struct ip_esp_hdr *esph; 749213528feSQi Zhang struct ip_auth_hdr *ah; 7500ce332fdSQi Zhang struct sctphdr *sctph; 7510ce332fdSQi Zhang struct ipv6hdr *ip6h; 7520ce332fdSQi Zhang struct udphdr *udph; 7530ce332fdSQi Zhang struct tcphdr *tcph; 75421606584SQi Zhang struct ethhdr *eth; 7550ce332fdSQi Zhang struct iphdr *iph; 756213528feSQi Zhang u8 s_field; 757ef9e4cc5SQi Zhang u8 *rawh; 7580ce332fdSQi Zhang 7590ce332fdSQi Zhang switch (hdr->type) { 7600ce332fdSQi Zhang case VIRTCHNL_PROTO_HDR_ETH: 76121606584SQi Zhang eth = (struct ethhdr *)hdr->buffer; 76221606584SQi Zhang input->flow_type = ICE_FLTR_PTYPE_NON_IP_L2; 76321606584SQi Zhang 76421606584SQi Zhang if (hdr->field_selector) 76521606584SQi Zhang input->ext_data.ether_type = eth->h_proto; 7660ce332fdSQi Zhang break; 7670ce332fdSQi Zhang case VIRTCHNL_PROTO_HDR_IPV4: 7680ce332fdSQi Zhang iph = (struct iphdr *)hdr->buffer; 7690ce332fdSQi Zhang l3 = VIRTCHNL_PROTO_HDR_IPV4; 7700ce332fdSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_OTHER; 7710ce332fdSQi Zhang 7720ce332fdSQi Zhang if (hdr->field_selector) { 7730ce332fdSQi Zhang input->ip.v4.src_ip = iph->saddr; 7740ce332fdSQi Zhang input->ip.v4.dst_ip = iph->daddr; 7750ce332fdSQi Zhang input->ip.v4.tos = iph->tos; 7760ce332fdSQi Zhang input->ip.v4.proto = iph->protocol; 7770ce332fdSQi Zhang } 7780ce332fdSQi Zhang break; 7790ce332fdSQi Zhang case VIRTCHNL_PROTO_HDR_IPV6: 7800ce332fdSQi Zhang ip6h = (struct ipv6hdr *)hdr->buffer; 7810ce332fdSQi Zhang l3 = VIRTCHNL_PROTO_HDR_IPV6; 7820ce332fdSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_OTHER; 7830ce332fdSQi Zhang 7840ce332fdSQi Zhang if (hdr->field_selector) { 7850ce332fdSQi Zhang memcpy(input->ip.v6.src_ip, 7860ce332fdSQi Zhang ip6h->saddr.in6_u.u6_addr8, 7870ce332fdSQi Zhang sizeof(ip6h->saddr)); 7880ce332fdSQi Zhang memcpy(input->ip.v6.dst_ip, 7890ce332fdSQi Zhang ip6h->daddr.in6_u.u6_addr8, 7900ce332fdSQi Zhang sizeof(ip6h->daddr)); 7910ce332fdSQi Zhang input->ip.v6.tc = ((u8)(ip6h->priority) << 4) | 7920ce332fdSQi Zhang (ip6h->flow_lbl[0] >> 4); 7930ce332fdSQi Zhang input->ip.v6.proto = ip6h->nexthdr; 7940ce332fdSQi Zhang } 7950ce332fdSQi Zhang break; 7960ce332fdSQi Zhang case VIRTCHNL_PROTO_HDR_TCP: 7970ce332fdSQi Zhang tcph = (struct tcphdr *)hdr->buffer; 7980ce332fdSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4) 7990ce332fdSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_TCP; 8000ce332fdSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) 8010ce332fdSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_TCP; 8020ce332fdSQi Zhang 8030ce332fdSQi Zhang if (hdr->field_selector) { 8040ce332fdSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4) { 8050ce332fdSQi Zhang input->ip.v4.src_port = tcph->source; 8060ce332fdSQi Zhang input->ip.v4.dst_port = tcph->dest; 8070ce332fdSQi Zhang } else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) { 8080ce332fdSQi Zhang input->ip.v6.src_port = tcph->source; 8090ce332fdSQi Zhang input->ip.v6.dst_port = tcph->dest; 8100ce332fdSQi Zhang } 8110ce332fdSQi Zhang } 8120ce332fdSQi Zhang break; 8130ce332fdSQi Zhang case VIRTCHNL_PROTO_HDR_UDP: 8140ce332fdSQi Zhang udph = (struct udphdr *)hdr->buffer; 8150ce332fdSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4) 8160ce332fdSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_UDP; 8170ce332fdSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) 8180ce332fdSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_UDP; 8190ce332fdSQi Zhang 8200ce332fdSQi Zhang if (hdr->field_selector) { 8210ce332fdSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4) { 8220ce332fdSQi Zhang input->ip.v4.src_port = udph->source; 8230ce332fdSQi Zhang input->ip.v4.dst_port = udph->dest; 8240ce332fdSQi Zhang } else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) { 8250ce332fdSQi Zhang input->ip.v6.src_port = udph->source; 8260ce332fdSQi Zhang input->ip.v6.dst_port = udph->dest; 8270ce332fdSQi Zhang } 8280ce332fdSQi Zhang } 8290ce332fdSQi Zhang break; 8300ce332fdSQi Zhang case VIRTCHNL_PROTO_HDR_SCTP: 8310ce332fdSQi Zhang sctph = (struct sctphdr *)hdr->buffer; 8320ce332fdSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4) 8330ce332fdSQi Zhang input->flow_type = 8340ce332fdSQi Zhang ICE_FLTR_PTYPE_NONF_IPV4_SCTP; 8350ce332fdSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) 8360ce332fdSQi Zhang input->flow_type = 8370ce332fdSQi Zhang ICE_FLTR_PTYPE_NONF_IPV6_SCTP; 8380ce332fdSQi Zhang 8390ce332fdSQi Zhang if (hdr->field_selector) { 8400ce332fdSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4) { 8410ce332fdSQi Zhang input->ip.v4.src_port = sctph->source; 8420ce332fdSQi Zhang input->ip.v4.dst_port = sctph->dest; 8430ce332fdSQi Zhang } else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) { 8440ce332fdSQi Zhang input->ip.v6.src_port = sctph->source; 8450ce332fdSQi Zhang input->ip.v6.dst_port = sctph->dest; 8460ce332fdSQi Zhang } 8470ce332fdSQi Zhang } 8480ce332fdSQi Zhang break; 849213528feSQi Zhang case VIRTCHNL_PROTO_HDR_L2TPV3: 850213528feSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4) 851213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_L2TPV3; 852213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) 853213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_L2TPV3; 854213528feSQi Zhang 855213528feSQi Zhang if (hdr->field_selector) 856213528feSQi Zhang input->l2tpv3_data.session_id = *((__be32 *)hdr->buffer); 857213528feSQi Zhang break; 858213528feSQi Zhang case VIRTCHNL_PROTO_HDR_ESP: 859213528feSQi Zhang esph = (struct ip_esp_hdr *)hdr->buffer; 860213528feSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4 && 861213528feSQi Zhang l4 == VIRTCHNL_PROTO_HDR_UDP) 862213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_NAT_T_ESP; 863213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6 && 864213528feSQi Zhang l4 == VIRTCHNL_PROTO_HDR_UDP) 865213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_NAT_T_ESP; 866213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV4 && 867213528feSQi Zhang l4 == VIRTCHNL_PROTO_HDR_NONE) 868213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_ESP; 869213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6 && 870213528feSQi Zhang l4 == VIRTCHNL_PROTO_HDR_NONE) 871213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_ESP; 872213528feSQi Zhang 873213528feSQi Zhang if (l4 == VIRTCHNL_PROTO_HDR_UDP) 874213528feSQi Zhang conf->inset_flag |= FDIR_INSET_FLAG_ESP_UDP; 875213528feSQi Zhang else 876213528feSQi Zhang conf->inset_flag |= FDIR_INSET_FLAG_ESP_IPSEC; 877213528feSQi Zhang 878213528feSQi Zhang if (hdr->field_selector) { 879213528feSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4) 880213528feSQi Zhang input->ip.v4.sec_parm_idx = esph->spi; 881213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) 882213528feSQi Zhang input->ip.v6.sec_parm_idx = esph->spi; 883213528feSQi Zhang } 884213528feSQi Zhang break; 885213528feSQi Zhang case VIRTCHNL_PROTO_HDR_AH: 886213528feSQi Zhang ah = (struct ip_auth_hdr *)hdr->buffer; 887213528feSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4) 888213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_AH; 889213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) 890213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_AH; 891213528feSQi Zhang 892213528feSQi Zhang if (hdr->field_selector) { 893213528feSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4) 894213528feSQi Zhang input->ip.v4.sec_parm_idx = ah->spi; 895213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) 896213528feSQi Zhang input->ip.v6.sec_parm_idx = ah->spi; 897213528feSQi Zhang } 898213528feSQi Zhang break; 899213528feSQi Zhang case VIRTCHNL_PROTO_HDR_PFCP: 900213528feSQi Zhang rawh = (u8 *)hdr->buffer; 901213528feSQi Zhang s_field = (rawh[0] >> PFCP_S_OFFSET) & PFCP_S_MASK; 902213528feSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4 && s_field == 0) 903213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_PFCP_NODE; 904213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV4 && s_field == 1) 905213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_PFCP_SESSION; 906213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6 && s_field == 0) 907213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_PFCP_NODE; 908213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6 && s_field == 1) 909213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_PFCP_SESSION; 910213528feSQi Zhang 911213528feSQi Zhang if (hdr->field_selector) { 912213528feSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4) 913213528feSQi Zhang input->ip.v4.dst_port = cpu_to_be16(PFCP_PORT_NR); 914213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) 915213528feSQi Zhang input->ip.v6.dst_port = cpu_to_be16(PFCP_PORT_NR); 916213528feSQi Zhang } 917213528feSQi Zhang break; 918ef9e4cc5SQi Zhang case VIRTCHNL_PROTO_HDR_GTPU_IP: 919ef9e4cc5SQi Zhang rawh = (u8 *)hdr->buffer; 920ef9e4cc5SQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_OTHER; 921ef9e4cc5SQi Zhang 922ef9e4cc5SQi Zhang if (hdr->field_selector) 923ef9e4cc5SQi Zhang input->gtpu_data.teid = *(__be32 *)(&rawh[GTPU_TEID_OFFSET]); 924ef9e4cc5SQi Zhang conf->ttype = ICE_FDIR_TUNNEL_TYPE_GTPU; 925ef9e4cc5SQi Zhang break; 926ef9e4cc5SQi Zhang case VIRTCHNL_PROTO_HDR_GTPU_EH: 927ef9e4cc5SQi Zhang rawh = (u8 *)hdr->buffer; 928ef9e4cc5SQi Zhang 929ef9e4cc5SQi Zhang if (hdr->field_selector) 930ef9e4cc5SQi Zhang input->gtpu_data.qfi = rawh[GTPU_EH_QFI_OFFSET] & GTPU_EH_QFI_MASK; 931ef9e4cc5SQi Zhang conf->ttype = ICE_FDIR_TUNNEL_TYPE_GTPU_EH; 932ef9e4cc5SQi Zhang break; 9330ce332fdSQi Zhang default: 9340ce332fdSQi Zhang dev_dbg(dev, "Invalid header type 0x:%x for VF %d\n", 9350ce332fdSQi Zhang hdr->type, vf->vf_id); 9360ce332fdSQi Zhang return -EINVAL; 9370ce332fdSQi Zhang } 9380ce332fdSQi Zhang } 9390ce332fdSQi Zhang 9400ce332fdSQi Zhang return 0; 9410ce332fdSQi Zhang } 9420ce332fdSQi Zhang 9430ce332fdSQi Zhang /** 9440ce332fdSQi Zhang * ice_vc_fdir_parse_action 9450ce332fdSQi Zhang * @vf: pointer to the VF info 9460ce332fdSQi Zhang * @fltr: virtual channel add cmd buffer 9470ce332fdSQi Zhang * @conf: FDIR configuration for each filter 9480ce332fdSQi Zhang * 9490ce332fdSQi Zhang * Parse the virtual channel filter's action and store them into conf 9500ce332fdSQi Zhang * 9510ce332fdSQi Zhang * Return: 0 on success, and other on error. 9520ce332fdSQi Zhang */ 9530ce332fdSQi Zhang static int 9540ce332fdSQi Zhang ice_vc_fdir_parse_action(struct ice_vf *vf, struct virtchnl_fdir_add *fltr, 9550ce332fdSQi Zhang struct virtchnl_fdir_fltr_conf *conf) 9560ce332fdSQi Zhang { 9570ce332fdSQi Zhang struct virtchnl_filter_action_set *as = &fltr->rule_cfg.action_set; 9580ce332fdSQi Zhang struct device *dev = ice_pf_to_dev(vf->pf); 9590ce332fdSQi Zhang struct ice_fdir_fltr *input = &conf->input; 9600ce332fdSQi Zhang u32 dest_num = 0; 9610ce332fdSQi Zhang u32 mark_num = 0; 9620ce332fdSQi Zhang int i; 9630ce332fdSQi Zhang 9640ce332fdSQi Zhang if (as->count > VIRTCHNL_MAX_NUM_ACTIONS) { 9650ce332fdSQi Zhang dev_dbg(dev, "Invalid action numbers:0x%x for VF %d\n", 9660ce332fdSQi Zhang as->count, vf->vf_id); 9670ce332fdSQi Zhang return -EINVAL; 9680ce332fdSQi Zhang } 9690ce332fdSQi Zhang 9700ce332fdSQi Zhang for (i = 0; i < as->count; i++) { 9710ce332fdSQi Zhang struct virtchnl_filter_action *action = &as->actions[i]; 9720ce332fdSQi Zhang 9730ce332fdSQi Zhang switch (action->type) { 974346bf250SQi Zhang case VIRTCHNL_ACTION_PASSTHRU: 975346bf250SQi Zhang dest_num++; 976346bf250SQi Zhang input->dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_OTHER; 977346bf250SQi Zhang break; 9780ce332fdSQi Zhang case VIRTCHNL_ACTION_DROP: 9790ce332fdSQi Zhang dest_num++; 9800ce332fdSQi Zhang input->dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DROP_PKT; 9810ce332fdSQi Zhang break; 9820ce332fdSQi Zhang case VIRTCHNL_ACTION_QUEUE: 9830ce332fdSQi Zhang dest_num++; 9840ce332fdSQi Zhang input->dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_QINDEX; 9850ce332fdSQi Zhang input->q_index = action->act_conf.queue.index; 9860ce332fdSQi Zhang break; 987346bf250SQi Zhang case VIRTCHNL_ACTION_Q_REGION: 988346bf250SQi Zhang dest_num++; 989346bf250SQi Zhang input->dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_QGROUP; 990346bf250SQi Zhang input->q_index = action->act_conf.queue.index; 991346bf250SQi Zhang input->q_region = action->act_conf.queue.region; 992346bf250SQi Zhang break; 9930ce332fdSQi Zhang case VIRTCHNL_ACTION_MARK: 9940ce332fdSQi Zhang mark_num++; 9950ce332fdSQi Zhang input->fltr_id = action->act_conf.mark_id; 9960ce332fdSQi Zhang input->fdid_prio = ICE_FXD_FLTR_QW1_FDID_PRI_THREE; 9970ce332fdSQi Zhang break; 9980ce332fdSQi Zhang default: 9990ce332fdSQi Zhang dev_dbg(dev, "Invalid action type:0x%x for VF %d\n", 10000ce332fdSQi Zhang action->type, vf->vf_id); 10010ce332fdSQi Zhang return -EINVAL; 10020ce332fdSQi Zhang } 10030ce332fdSQi Zhang } 10040ce332fdSQi Zhang 10050ce332fdSQi Zhang if (dest_num == 0 || dest_num >= 2) { 10060ce332fdSQi Zhang dev_dbg(dev, "Invalid destination action for VF %d\n", 10070ce332fdSQi Zhang vf->vf_id); 10080ce332fdSQi Zhang return -EINVAL; 10090ce332fdSQi Zhang } 10100ce332fdSQi Zhang 10110ce332fdSQi Zhang if (mark_num >= 2) { 10120ce332fdSQi Zhang dev_dbg(dev, "Too many mark actions for VF %d\n", vf->vf_id); 10130ce332fdSQi Zhang return -EINVAL; 10140ce332fdSQi Zhang } 10150ce332fdSQi Zhang 10160ce332fdSQi Zhang return 0; 10170ce332fdSQi Zhang } 10180ce332fdSQi Zhang 10190ce332fdSQi Zhang /** 10201f7ea1cdSQi Zhang * ice_vc_validate_fdir_fltr - validate the virtual channel filter 10211f7ea1cdSQi Zhang * @vf: pointer to the VF info 10221f7ea1cdSQi Zhang * @fltr: virtual channel add cmd buffer 10231f7ea1cdSQi Zhang * @conf: FDIR configuration for each filter 10241f7ea1cdSQi Zhang * 10251f7ea1cdSQi Zhang * Return: 0 on success, and other on error. 10261f7ea1cdSQi Zhang */ 10271f7ea1cdSQi Zhang static int 10281f7ea1cdSQi Zhang ice_vc_validate_fdir_fltr(struct ice_vf *vf, struct virtchnl_fdir_add *fltr, 10291f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf) 10301f7ea1cdSQi Zhang { 103160f44fe4SJeff Guo struct virtchnl_proto_hdrs *proto = &fltr->rule_cfg.proto_hdrs; 10320ce332fdSQi Zhang int ret; 10330ce332fdSQi Zhang 103460f44fe4SJeff Guo if (!ice_vc_validate_pattern(vf, proto)) 103560f44fe4SJeff Guo return -EINVAL; 10360ce332fdSQi Zhang 10370ce332fdSQi Zhang ret = ice_vc_fdir_parse_pattern(vf, fltr, conf); 10380ce332fdSQi Zhang if (ret) 10390ce332fdSQi Zhang return ret; 10400ce332fdSQi Zhang 10410ce332fdSQi Zhang return ice_vc_fdir_parse_action(vf, fltr, conf); 10421f7ea1cdSQi Zhang } 10431f7ea1cdSQi Zhang 10441f7ea1cdSQi Zhang /** 10451f7ea1cdSQi Zhang * ice_vc_fdir_comp_rules - compare if two filter rules have the same value 10461f7ea1cdSQi Zhang * @conf_a: FDIR configuration for filter a 10471f7ea1cdSQi Zhang * @conf_b: FDIR configuration for filter b 10481f7ea1cdSQi Zhang * 10491f7ea1cdSQi Zhang * Return: 0 on success, and other on error. 10501f7ea1cdSQi Zhang */ 10511f7ea1cdSQi Zhang static bool 10521f7ea1cdSQi Zhang ice_vc_fdir_comp_rules(struct virtchnl_fdir_fltr_conf *conf_a, 10531f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf_b) 10541f7ea1cdSQi Zhang { 10551f7ea1cdSQi Zhang struct ice_fdir_fltr *a = &conf_a->input; 10561f7ea1cdSQi Zhang struct ice_fdir_fltr *b = &conf_b->input; 10571f7ea1cdSQi Zhang 1058ef9e4cc5SQi Zhang if (conf_a->ttype != conf_b->ttype) 1059ef9e4cc5SQi Zhang return false; 10601f7ea1cdSQi Zhang if (a->flow_type != b->flow_type) 10611f7ea1cdSQi Zhang return false; 10621f7ea1cdSQi Zhang if (memcmp(&a->ip, &b->ip, sizeof(a->ip))) 10631f7ea1cdSQi Zhang return false; 10641f7ea1cdSQi Zhang if (memcmp(&a->mask, &b->mask, sizeof(a->mask))) 10651f7ea1cdSQi Zhang return false; 1066ef9e4cc5SQi Zhang if (memcmp(&a->gtpu_data, &b->gtpu_data, sizeof(a->gtpu_data))) 1067ef9e4cc5SQi Zhang return false; 1068ef9e4cc5SQi Zhang if (memcmp(&a->gtpu_mask, &b->gtpu_mask, sizeof(a->gtpu_mask))) 1069ef9e4cc5SQi Zhang return false; 1070213528feSQi Zhang if (memcmp(&a->l2tpv3_data, &b->l2tpv3_data, sizeof(a->l2tpv3_data))) 1071213528feSQi Zhang return false; 1072213528feSQi Zhang if (memcmp(&a->l2tpv3_mask, &b->l2tpv3_mask, sizeof(a->l2tpv3_mask))) 1073213528feSQi Zhang return false; 10741f7ea1cdSQi Zhang if (memcmp(&a->ext_data, &b->ext_data, sizeof(a->ext_data))) 10751f7ea1cdSQi Zhang return false; 10761f7ea1cdSQi Zhang if (memcmp(&a->ext_mask, &b->ext_mask, sizeof(a->ext_mask))) 10771f7ea1cdSQi Zhang return false; 10781f7ea1cdSQi Zhang 10791f7ea1cdSQi Zhang return true; 10801f7ea1cdSQi Zhang } 10811f7ea1cdSQi Zhang 10821f7ea1cdSQi Zhang /** 10831f7ea1cdSQi Zhang * ice_vc_fdir_is_dup_fltr 10841f7ea1cdSQi Zhang * @vf: pointer to the VF info 10851f7ea1cdSQi Zhang * @conf: FDIR configuration for each filter 10861f7ea1cdSQi Zhang * 10871f7ea1cdSQi Zhang * Check if there is duplicated rule with same conf value 10881f7ea1cdSQi Zhang * 10891f7ea1cdSQi Zhang * Return: 0 true success, and false on error. 10901f7ea1cdSQi Zhang */ 10911f7ea1cdSQi Zhang static bool 10921f7ea1cdSQi Zhang ice_vc_fdir_is_dup_fltr(struct ice_vf *vf, struct virtchnl_fdir_fltr_conf *conf) 10931f7ea1cdSQi Zhang { 10941f7ea1cdSQi Zhang struct ice_fdir_fltr *desc; 10951f7ea1cdSQi Zhang bool ret; 10961f7ea1cdSQi Zhang 10971f7ea1cdSQi Zhang list_for_each_entry(desc, &vf->fdir.fdir_rule_list, fltr_node) { 10981f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *node = 10991f7ea1cdSQi Zhang to_fltr_conf_from_desc(desc); 11001f7ea1cdSQi Zhang 11011f7ea1cdSQi Zhang ret = ice_vc_fdir_comp_rules(node, conf); 11021f7ea1cdSQi Zhang if (ret) 11031f7ea1cdSQi Zhang return true; 11041f7ea1cdSQi Zhang } 11051f7ea1cdSQi Zhang 11061f7ea1cdSQi Zhang return false; 11071f7ea1cdSQi Zhang } 11081f7ea1cdSQi Zhang 11091f7ea1cdSQi Zhang /** 11101f7ea1cdSQi Zhang * ice_vc_fdir_insert_entry 11111f7ea1cdSQi Zhang * @vf: pointer to the VF info 11121f7ea1cdSQi Zhang * @conf: FDIR configuration for each filter 11131f7ea1cdSQi Zhang * @id: pointer to ID value allocated by driver 11141f7ea1cdSQi Zhang * 11151f7ea1cdSQi Zhang * Insert FDIR conf entry into list and allocate ID for this filter 11161f7ea1cdSQi Zhang * 11171f7ea1cdSQi Zhang * Return: 0 true success, and other on error. 11181f7ea1cdSQi Zhang */ 11191f7ea1cdSQi Zhang static int 11201f7ea1cdSQi Zhang ice_vc_fdir_insert_entry(struct ice_vf *vf, 11211f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf, u32 *id) 11221f7ea1cdSQi Zhang { 11231f7ea1cdSQi Zhang struct ice_fdir_fltr *input = &conf->input; 11241f7ea1cdSQi Zhang int i; 11251f7ea1cdSQi Zhang 11261f7ea1cdSQi Zhang /* alloc ID corresponding with conf */ 11271f7ea1cdSQi Zhang i = idr_alloc(&vf->fdir.fdir_rule_idr, conf, 0, 11281f7ea1cdSQi Zhang ICE_FDIR_MAX_FLTRS, GFP_KERNEL); 11291f7ea1cdSQi Zhang if (i < 0) 11301f7ea1cdSQi Zhang return -EINVAL; 11311f7ea1cdSQi Zhang *id = i; 11321f7ea1cdSQi Zhang 11331f7ea1cdSQi Zhang list_add(&input->fltr_node, &vf->fdir.fdir_rule_list); 11341f7ea1cdSQi Zhang return 0; 11351f7ea1cdSQi Zhang } 11361f7ea1cdSQi Zhang 11371f7ea1cdSQi Zhang /** 11381f7ea1cdSQi Zhang * ice_vc_fdir_remove_entry - remove FDIR conf entry by ID value 11391f7ea1cdSQi Zhang * @vf: pointer to the VF info 11401f7ea1cdSQi Zhang * @conf: FDIR configuration for each filter 11411f7ea1cdSQi Zhang * @id: filter rule's ID 11421f7ea1cdSQi Zhang */ 11431f7ea1cdSQi Zhang static void 11441f7ea1cdSQi Zhang ice_vc_fdir_remove_entry(struct ice_vf *vf, 11451f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf, u32 id) 11461f7ea1cdSQi Zhang { 11471f7ea1cdSQi Zhang struct ice_fdir_fltr *input = &conf->input; 11481f7ea1cdSQi Zhang 11491f7ea1cdSQi Zhang idr_remove(&vf->fdir.fdir_rule_idr, id); 11501f7ea1cdSQi Zhang list_del(&input->fltr_node); 11511f7ea1cdSQi Zhang } 11521f7ea1cdSQi Zhang 11531f7ea1cdSQi Zhang /** 11541f7ea1cdSQi Zhang * ice_vc_fdir_lookup_entry - lookup FDIR conf entry by ID value 11551f7ea1cdSQi Zhang * @vf: pointer to the VF info 11561f7ea1cdSQi Zhang * @id: filter rule's ID 11571f7ea1cdSQi Zhang * 11581f7ea1cdSQi Zhang * Return: NULL on error, and other on success. 11591f7ea1cdSQi Zhang */ 11601f7ea1cdSQi Zhang static struct virtchnl_fdir_fltr_conf * 11611f7ea1cdSQi Zhang ice_vc_fdir_lookup_entry(struct ice_vf *vf, u32 id) 11621f7ea1cdSQi Zhang { 11631f7ea1cdSQi Zhang return idr_find(&vf->fdir.fdir_rule_idr, id); 11641f7ea1cdSQi Zhang } 11651f7ea1cdSQi Zhang 11661f7ea1cdSQi Zhang /** 11671f7ea1cdSQi Zhang * ice_vc_fdir_flush_entry - remove all FDIR conf entry 11681f7ea1cdSQi Zhang * @vf: pointer to the VF info 11691f7ea1cdSQi Zhang */ 11701f7ea1cdSQi Zhang static void ice_vc_fdir_flush_entry(struct ice_vf *vf) 11711f7ea1cdSQi Zhang { 11721f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf; 11731f7ea1cdSQi Zhang struct ice_fdir_fltr *desc, *temp; 11741f7ea1cdSQi Zhang 11751f7ea1cdSQi Zhang list_for_each_entry_safe(desc, temp, 11761f7ea1cdSQi Zhang &vf->fdir.fdir_rule_list, fltr_node) { 11771f7ea1cdSQi Zhang conf = to_fltr_conf_from_desc(desc); 11781f7ea1cdSQi Zhang list_del(&desc->fltr_node); 11791f7ea1cdSQi Zhang devm_kfree(ice_pf_to_dev(vf->pf), conf); 11801f7ea1cdSQi Zhang } 11811f7ea1cdSQi Zhang } 11821f7ea1cdSQi Zhang 11831f7ea1cdSQi Zhang /** 11841f7ea1cdSQi Zhang * ice_vc_fdir_write_fltr - write filter rule into hardware 11851f7ea1cdSQi Zhang * @vf: pointer to the VF info 11861f7ea1cdSQi Zhang * @conf: FDIR configuration for each filter 11871f7ea1cdSQi Zhang * @add: true implies add rule, false implies del rules 11881f7ea1cdSQi Zhang * @is_tun: false implies non-tunnel type filter, true implies tunnel filter 11891f7ea1cdSQi Zhang * 11901f7ea1cdSQi Zhang * Return: 0 on success, and other on error. 11911f7ea1cdSQi Zhang */ 11921f7ea1cdSQi Zhang static int ice_vc_fdir_write_fltr(struct ice_vf *vf, 11931f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf, 11941f7ea1cdSQi Zhang bool add, bool is_tun) 11951f7ea1cdSQi Zhang { 11961f7ea1cdSQi Zhang struct ice_fdir_fltr *input = &conf->input; 11971f7ea1cdSQi Zhang struct ice_vsi *vsi, *ctrl_vsi; 11981f7ea1cdSQi Zhang struct ice_fltr_desc desc; 11991f7ea1cdSQi Zhang struct device *dev; 12001f7ea1cdSQi Zhang struct ice_pf *pf; 12011f7ea1cdSQi Zhang struct ice_hw *hw; 12021f7ea1cdSQi Zhang int ret; 12031f7ea1cdSQi Zhang u8 *pkt; 12041f7ea1cdSQi Zhang 12051f7ea1cdSQi Zhang pf = vf->pf; 12061f7ea1cdSQi Zhang dev = ice_pf_to_dev(pf); 12071f7ea1cdSQi Zhang hw = &pf->hw; 12081f7ea1cdSQi Zhang vsi = pf->vsi[vf->lan_vsi_idx]; 12091f7ea1cdSQi Zhang if (!vsi) { 12101f7ea1cdSQi Zhang dev_dbg(dev, "Invalid vsi for VF %d\n", vf->vf_id); 12111f7ea1cdSQi Zhang return -EINVAL; 12121f7ea1cdSQi Zhang } 12131f7ea1cdSQi Zhang 12141f7ea1cdSQi Zhang input->dest_vsi = vsi->idx; 1215d6218317SQi Zhang input->comp_report = ICE_FXD_FLTR_QW0_COMP_REPORT_SW; 12161f7ea1cdSQi Zhang 12171f7ea1cdSQi Zhang ctrl_vsi = pf->vsi[vf->ctrl_vsi_idx]; 12181f7ea1cdSQi Zhang if (!ctrl_vsi) { 12191f7ea1cdSQi Zhang dev_dbg(dev, "Invalid ctrl_vsi for VF %d\n", vf->vf_id); 12201f7ea1cdSQi Zhang return -EINVAL; 12211f7ea1cdSQi Zhang } 12221f7ea1cdSQi Zhang 12231f7ea1cdSQi Zhang pkt = devm_kzalloc(dev, ICE_FDIR_MAX_RAW_PKT_SIZE, GFP_KERNEL); 12241f7ea1cdSQi Zhang if (!pkt) 12251f7ea1cdSQi Zhang return -ENOMEM; 12261f7ea1cdSQi Zhang 12271f7ea1cdSQi Zhang ice_fdir_get_prgm_desc(hw, input, &desc, add); 12282ccc1c1cSTony Nguyen ret = ice_fdir_get_gen_prgm_pkt(hw, input, pkt, false, is_tun); 12291f7ea1cdSQi Zhang if (ret) { 12301f7ea1cdSQi Zhang dev_dbg(dev, "Gen training pkt for VF %d ptype %d failed\n", 12311f7ea1cdSQi Zhang vf->vf_id, input->flow_type); 12321f7ea1cdSQi Zhang goto err_free_pkt; 12331f7ea1cdSQi Zhang } 12341f7ea1cdSQi Zhang 12351f7ea1cdSQi Zhang ret = ice_prgm_fdir_fltr(ctrl_vsi, &desc, pkt); 12361f7ea1cdSQi Zhang if (ret) 12371f7ea1cdSQi Zhang goto err_free_pkt; 12381f7ea1cdSQi Zhang 12391f7ea1cdSQi Zhang return 0; 12401f7ea1cdSQi Zhang 12411f7ea1cdSQi Zhang err_free_pkt: 12421f7ea1cdSQi Zhang devm_kfree(dev, pkt); 12431f7ea1cdSQi Zhang return ret; 12441f7ea1cdSQi Zhang } 12451f7ea1cdSQi Zhang 12461f7ea1cdSQi Zhang /** 1247d6218317SQi Zhang * ice_vf_fdir_timer - FDIR program waiting timer interrupt handler 1248d6218317SQi Zhang * @t: pointer to timer_list 1249d6218317SQi Zhang */ 1250d6218317SQi Zhang static void ice_vf_fdir_timer(struct timer_list *t) 1251d6218317SQi Zhang { 1252d6218317SQi Zhang struct ice_vf_fdir_ctx *ctx_irq = from_timer(ctx_irq, t, rx_tmr); 1253d6218317SQi Zhang struct ice_vf_fdir_ctx *ctx_done; 1254d6218317SQi Zhang struct ice_vf_fdir *fdir; 1255d6218317SQi Zhang unsigned long flags; 1256d6218317SQi Zhang struct ice_vf *vf; 1257d6218317SQi Zhang struct ice_pf *pf; 1258d6218317SQi Zhang 1259d6218317SQi Zhang fdir = container_of(ctx_irq, struct ice_vf_fdir, ctx_irq); 1260d6218317SQi Zhang vf = container_of(fdir, struct ice_vf, fdir); 1261d6218317SQi Zhang ctx_done = &fdir->ctx_done; 1262d6218317SQi Zhang pf = vf->pf; 1263d6218317SQi Zhang spin_lock_irqsave(&fdir->ctx_lock, flags); 1264d6218317SQi Zhang if (!(ctx_irq->flags & ICE_VF_FDIR_CTX_VALID)) { 1265d6218317SQi Zhang spin_unlock_irqrestore(&fdir->ctx_lock, flags); 1266d6218317SQi Zhang WARN_ON_ONCE(1); 1267d6218317SQi Zhang return; 1268d6218317SQi Zhang } 1269d6218317SQi Zhang 1270d6218317SQi Zhang ctx_irq->flags &= ~ICE_VF_FDIR_CTX_VALID; 1271d6218317SQi Zhang 1272d6218317SQi Zhang ctx_done->flags |= ICE_VF_FDIR_CTX_VALID; 1273d6218317SQi Zhang ctx_done->conf = ctx_irq->conf; 1274d6218317SQi Zhang ctx_done->stat = ICE_FDIR_CTX_TIMEOUT; 1275d6218317SQi Zhang ctx_done->v_opcode = ctx_irq->v_opcode; 1276d6218317SQi Zhang spin_unlock_irqrestore(&fdir->ctx_lock, flags); 1277d6218317SQi Zhang 12787e408e07SAnirudh Venkataramanan set_bit(ICE_FD_VF_FLUSH_CTX, pf->state); 1279d6218317SQi Zhang ice_service_task_schedule(pf); 1280d6218317SQi Zhang } 1281d6218317SQi Zhang 1282d6218317SQi Zhang /** 1283d6218317SQi Zhang * ice_vc_fdir_irq_handler - ctrl_vsi Rx queue interrupt handler 1284d6218317SQi Zhang * @ctrl_vsi: pointer to a VF's CTRL VSI 1285d6218317SQi Zhang * @rx_desc: pointer to FDIR Rx queue descriptor 1286d6218317SQi Zhang */ 1287d6218317SQi Zhang void 1288d6218317SQi Zhang ice_vc_fdir_irq_handler(struct ice_vsi *ctrl_vsi, 1289d6218317SQi Zhang union ice_32b_rx_flex_desc *rx_desc) 1290d6218317SQi Zhang { 1291d6218317SQi Zhang struct ice_pf *pf = ctrl_vsi->back; 1292b03d519dSJacob Keller struct ice_vf *vf = ctrl_vsi->vf; 1293d6218317SQi Zhang struct ice_vf_fdir_ctx *ctx_done; 1294d6218317SQi Zhang struct ice_vf_fdir_ctx *ctx_irq; 1295d6218317SQi Zhang struct ice_vf_fdir *fdir; 1296d6218317SQi Zhang unsigned long flags; 1297d6218317SQi Zhang struct device *dev; 1298d6218317SQi Zhang int ret; 1299d6218317SQi Zhang 1300b03d519dSJacob Keller if (WARN_ON(!vf)) 1301b03d519dSJacob Keller return; 1302d6218317SQi Zhang 1303d6218317SQi Zhang fdir = &vf->fdir; 1304d6218317SQi Zhang ctx_done = &fdir->ctx_done; 1305d6218317SQi Zhang ctx_irq = &fdir->ctx_irq; 1306d6218317SQi Zhang dev = ice_pf_to_dev(pf); 1307d6218317SQi Zhang spin_lock_irqsave(&fdir->ctx_lock, flags); 1308d6218317SQi Zhang if (!(ctx_irq->flags & ICE_VF_FDIR_CTX_VALID)) { 1309d6218317SQi Zhang spin_unlock_irqrestore(&fdir->ctx_lock, flags); 1310d6218317SQi Zhang WARN_ON_ONCE(1); 1311d6218317SQi Zhang return; 1312d6218317SQi Zhang } 1313d6218317SQi Zhang 1314d6218317SQi Zhang ctx_irq->flags &= ~ICE_VF_FDIR_CTX_VALID; 1315d6218317SQi Zhang 1316d6218317SQi Zhang ctx_done->flags |= ICE_VF_FDIR_CTX_VALID; 1317d6218317SQi Zhang ctx_done->conf = ctx_irq->conf; 1318d6218317SQi Zhang ctx_done->stat = ICE_FDIR_CTX_IRQ; 1319d6218317SQi Zhang ctx_done->v_opcode = ctx_irq->v_opcode; 1320d6218317SQi Zhang memcpy(&ctx_done->rx_desc, rx_desc, sizeof(*rx_desc)); 1321d6218317SQi Zhang spin_unlock_irqrestore(&fdir->ctx_lock, flags); 1322d6218317SQi Zhang 1323d6218317SQi Zhang ret = del_timer(&ctx_irq->rx_tmr); 1324d6218317SQi Zhang if (!ret) 1325d6218317SQi Zhang dev_err(dev, "VF %d: Unexpected inactive timer!\n", vf->vf_id); 1326d6218317SQi Zhang 13277e408e07SAnirudh Venkataramanan set_bit(ICE_FD_VF_FLUSH_CTX, pf->state); 1328d6218317SQi Zhang ice_service_task_schedule(pf); 1329d6218317SQi Zhang } 1330d6218317SQi Zhang 1331d6218317SQi Zhang /** 1332d6218317SQi Zhang * ice_vf_fdir_dump_info - dump FDIR information for diagnosis 1333d6218317SQi Zhang * @vf: pointer to the VF info 1334d6218317SQi Zhang */ 1335d6218317SQi Zhang static void ice_vf_fdir_dump_info(struct ice_vf *vf) 1336d6218317SQi Zhang { 1337d6218317SQi Zhang struct ice_vsi *vf_vsi; 1338d6218317SQi Zhang u32 fd_size, fd_cnt; 1339d6218317SQi Zhang struct device *dev; 1340d6218317SQi Zhang struct ice_pf *pf; 1341d6218317SQi Zhang struct ice_hw *hw; 1342d6218317SQi Zhang u16 vsi_num; 1343d6218317SQi Zhang 1344d6218317SQi Zhang pf = vf->pf; 1345d6218317SQi Zhang hw = &pf->hw; 1346d6218317SQi Zhang dev = ice_pf_to_dev(pf); 1347d6218317SQi Zhang vf_vsi = pf->vsi[vf->lan_vsi_idx]; 1348d6218317SQi Zhang vsi_num = ice_get_hw_vsi_num(hw, vf_vsi->idx); 1349d6218317SQi Zhang 1350d6218317SQi Zhang fd_size = rd32(hw, VSIQF_FD_SIZE(vsi_num)); 1351d6218317SQi Zhang fd_cnt = rd32(hw, VSIQF_FD_CNT(vsi_num)); 1352*9880d3d6SJacob Keller dev_dbg(dev, "VF %d: space allocated: guar:0x%x, be:0x%x, space consumed: guar:0x%x, be:0x%x\n", 1353d6218317SQi Zhang vf->vf_id, 1354d6218317SQi Zhang (fd_size & VSIQF_FD_CNT_FD_GCNT_M) >> VSIQF_FD_CNT_FD_GCNT_S, 1355d6218317SQi Zhang (fd_size & VSIQF_FD_CNT_FD_BCNT_M) >> VSIQF_FD_CNT_FD_BCNT_S, 1356d6218317SQi Zhang (fd_cnt & VSIQF_FD_CNT_FD_GCNT_M) >> VSIQF_FD_CNT_FD_GCNT_S, 1357d6218317SQi Zhang (fd_cnt & VSIQF_FD_CNT_FD_BCNT_M) >> VSIQF_FD_CNT_FD_BCNT_S); 1358d6218317SQi Zhang } 1359d6218317SQi Zhang 1360d6218317SQi Zhang /** 1361d6218317SQi Zhang * ice_vf_verify_rx_desc - verify received FDIR programming status descriptor 1362d6218317SQi Zhang * @vf: pointer to the VF info 1363d6218317SQi Zhang * @ctx: FDIR context info for post processing 1364d6218317SQi Zhang * @status: virtchnl FDIR program status 1365d6218317SQi Zhang * 1366d6218317SQi Zhang * Return: 0 on success, and other on error. 1367d6218317SQi Zhang */ 1368d6218317SQi Zhang static int 1369d6218317SQi Zhang ice_vf_verify_rx_desc(struct ice_vf *vf, struct ice_vf_fdir_ctx *ctx, 1370d6218317SQi Zhang enum virtchnl_fdir_prgm_status *status) 1371d6218317SQi Zhang { 1372d6218317SQi Zhang struct device *dev = ice_pf_to_dev(vf->pf); 1373d6218317SQi Zhang u32 stat_err, error, prog_id; 1374d6218317SQi Zhang int ret; 1375d6218317SQi Zhang 1376d6218317SQi Zhang stat_err = le16_to_cpu(ctx->rx_desc.wb.status_error0); 1377d6218317SQi Zhang if (((stat_err & ICE_FXD_FLTR_WB_QW1_DD_M) >> 1378d6218317SQi Zhang ICE_FXD_FLTR_WB_QW1_DD_S) != ICE_FXD_FLTR_WB_QW1_DD_YES) { 1379d6218317SQi Zhang *status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; 1380d6218317SQi Zhang dev_err(dev, "VF %d: Desc Done not set\n", vf->vf_id); 1381d6218317SQi Zhang ret = -EINVAL; 1382d6218317SQi Zhang goto err_exit; 1383d6218317SQi Zhang } 1384d6218317SQi Zhang 1385d6218317SQi Zhang prog_id = (stat_err & ICE_FXD_FLTR_WB_QW1_PROG_ID_M) >> 1386d6218317SQi Zhang ICE_FXD_FLTR_WB_QW1_PROG_ID_S; 1387d6218317SQi Zhang if (prog_id == ICE_FXD_FLTR_WB_QW1_PROG_ADD && 1388d6218317SQi Zhang ctx->v_opcode != VIRTCHNL_OP_ADD_FDIR_FILTER) { 1389d6218317SQi Zhang dev_err(dev, "VF %d: Desc show add, but ctx not", 1390d6218317SQi Zhang vf->vf_id); 1391d6218317SQi Zhang *status = VIRTCHNL_FDIR_FAILURE_RULE_INVALID; 1392d6218317SQi Zhang ret = -EINVAL; 1393d6218317SQi Zhang goto err_exit; 1394d6218317SQi Zhang } 1395d6218317SQi Zhang 1396d6218317SQi Zhang if (prog_id == ICE_FXD_FLTR_WB_QW1_PROG_DEL && 1397d6218317SQi Zhang ctx->v_opcode != VIRTCHNL_OP_DEL_FDIR_FILTER) { 1398d6218317SQi Zhang dev_err(dev, "VF %d: Desc show del, but ctx not", 1399d6218317SQi Zhang vf->vf_id); 1400d6218317SQi Zhang *status = VIRTCHNL_FDIR_FAILURE_RULE_INVALID; 1401d6218317SQi Zhang ret = -EINVAL; 1402d6218317SQi Zhang goto err_exit; 1403d6218317SQi Zhang } 1404d6218317SQi Zhang 1405d6218317SQi Zhang error = (stat_err & ICE_FXD_FLTR_WB_QW1_FAIL_M) >> 1406d6218317SQi Zhang ICE_FXD_FLTR_WB_QW1_FAIL_S; 1407d6218317SQi Zhang if (error == ICE_FXD_FLTR_WB_QW1_FAIL_YES) { 1408d6218317SQi Zhang if (prog_id == ICE_FXD_FLTR_WB_QW1_PROG_ADD) { 1409d6218317SQi Zhang dev_err(dev, "VF %d, Failed to add FDIR rule due to no space in the table", 1410d6218317SQi Zhang vf->vf_id); 1411d6218317SQi Zhang *status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; 1412d6218317SQi Zhang } else { 1413d6218317SQi Zhang dev_err(dev, "VF %d, Failed to remove FDIR rule, attempt to remove non-existent entry", 1414d6218317SQi Zhang vf->vf_id); 1415d6218317SQi Zhang *status = VIRTCHNL_FDIR_FAILURE_RULE_NONEXIST; 1416d6218317SQi Zhang } 1417d6218317SQi Zhang ret = -EINVAL; 1418d6218317SQi Zhang goto err_exit; 1419d6218317SQi Zhang } 1420d6218317SQi Zhang 1421d6218317SQi Zhang error = (stat_err & ICE_FXD_FLTR_WB_QW1_FAIL_PROF_M) >> 1422d6218317SQi Zhang ICE_FXD_FLTR_WB_QW1_FAIL_PROF_S; 1423d6218317SQi Zhang if (error == ICE_FXD_FLTR_WB_QW1_FAIL_PROF_YES) { 1424d6218317SQi Zhang dev_err(dev, "VF %d: Profile matching error", vf->vf_id); 1425d6218317SQi Zhang *status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; 1426d6218317SQi Zhang ret = -EINVAL; 1427d6218317SQi Zhang goto err_exit; 1428d6218317SQi Zhang } 1429d6218317SQi Zhang 1430d6218317SQi Zhang *status = VIRTCHNL_FDIR_SUCCESS; 1431d6218317SQi Zhang 1432d6218317SQi Zhang return 0; 1433d6218317SQi Zhang 1434d6218317SQi Zhang err_exit: 1435d6218317SQi Zhang ice_vf_fdir_dump_info(vf); 1436d6218317SQi Zhang return ret; 1437d6218317SQi Zhang } 1438d6218317SQi Zhang 1439d6218317SQi Zhang /** 1440d6218317SQi Zhang * ice_vc_add_fdir_fltr_post 1441d6218317SQi Zhang * @vf: pointer to the VF structure 1442d6218317SQi Zhang * @ctx: FDIR context info for post processing 1443d6218317SQi Zhang * @status: virtchnl FDIR program status 1444d6218317SQi Zhang * @success: true implies success, false implies failure 1445d6218317SQi Zhang * 1446d6218317SQi Zhang * Post process for flow director add command. If success, then do post process 1447d6218317SQi Zhang * and send back success msg by virtchnl. Otherwise, do context reversion and 1448d6218317SQi Zhang * send back failure msg by virtchnl. 1449d6218317SQi Zhang * 1450d6218317SQi Zhang * Return: 0 on success, and other on error. 1451d6218317SQi Zhang */ 1452d6218317SQi Zhang static int 1453d6218317SQi Zhang ice_vc_add_fdir_fltr_post(struct ice_vf *vf, struct ice_vf_fdir_ctx *ctx, 1454d6218317SQi Zhang enum virtchnl_fdir_prgm_status status, 1455d6218317SQi Zhang bool success) 1456d6218317SQi Zhang { 1457d6218317SQi Zhang struct virtchnl_fdir_fltr_conf *conf = ctx->conf; 1458d6218317SQi Zhang struct device *dev = ice_pf_to_dev(vf->pf); 1459d6218317SQi Zhang enum virtchnl_status_code v_ret; 1460d6218317SQi Zhang struct virtchnl_fdir_add *resp; 1461d6218317SQi Zhang int ret, len, is_tun; 1462d6218317SQi Zhang 1463d6218317SQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS; 1464d6218317SQi Zhang len = sizeof(*resp); 1465d6218317SQi Zhang resp = kzalloc(len, GFP_KERNEL); 1466d6218317SQi Zhang if (!resp) { 1467d6218317SQi Zhang len = 0; 1468d6218317SQi Zhang v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; 1469d6218317SQi Zhang dev_dbg(dev, "VF %d: Alloc resp buf fail", vf->vf_id); 1470d6218317SQi Zhang goto err_exit; 1471d6218317SQi Zhang } 1472d6218317SQi Zhang 1473d6218317SQi Zhang if (!success) 1474d6218317SQi Zhang goto err_exit; 1475d6218317SQi Zhang 1476d6218317SQi Zhang is_tun = 0; 1477d6218317SQi Zhang resp->status = status; 1478d6218317SQi Zhang resp->flow_id = conf->flow_id; 1479d6218317SQi Zhang vf->fdir.fdir_fltr_cnt[conf->input.flow_type][is_tun]++; 1480d6218317SQi Zhang 1481d6218317SQi Zhang ret = ice_vc_send_msg_to_vf(vf, ctx->v_opcode, v_ret, 1482d6218317SQi Zhang (u8 *)resp, len); 1483d6218317SQi Zhang kfree(resp); 1484d6218317SQi Zhang 1485d6218317SQi Zhang dev_dbg(dev, "VF %d: flow_id:0x%X, FDIR %s success!\n", 1486d6218317SQi Zhang vf->vf_id, conf->flow_id, 1487d6218317SQi Zhang (ctx->v_opcode == VIRTCHNL_OP_ADD_FDIR_FILTER) ? 1488d6218317SQi Zhang "add" : "del"); 1489d6218317SQi Zhang return ret; 1490d6218317SQi Zhang 1491d6218317SQi Zhang err_exit: 1492d6218317SQi Zhang if (resp) 1493d6218317SQi Zhang resp->status = status; 1494d6218317SQi Zhang ice_vc_fdir_remove_entry(vf, conf, conf->flow_id); 1495d6218317SQi Zhang devm_kfree(dev, conf); 1496d6218317SQi Zhang 1497d6218317SQi Zhang ret = ice_vc_send_msg_to_vf(vf, ctx->v_opcode, v_ret, 1498d6218317SQi Zhang (u8 *)resp, len); 1499d6218317SQi Zhang kfree(resp); 1500d6218317SQi Zhang return ret; 1501d6218317SQi Zhang } 1502d6218317SQi Zhang 1503d6218317SQi Zhang /** 1504d6218317SQi Zhang * ice_vc_del_fdir_fltr_post 1505d6218317SQi Zhang * @vf: pointer to the VF structure 1506d6218317SQi Zhang * @ctx: FDIR context info for post processing 1507d6218317SQi Zhang * @status: virtchnl FDIR program status 1508d6218317SQi Zhang * @success: true implies success, false implies failure 1509d6218317SQi Zhang * 1510d6218317SQi Zhang * Post process for flow director del command. If success, then do post process 1511d6218317SQi Zhang * and send back success msg by virtchnl. Otherwise, do context reversion and 1512d6218317SQi Zhang * send back failure msg by virtchnl. 1513d6218317SQi Zhang * 1514d6218317SQi Zhang * Return: 0 on success, and other on error. 1515d6218317SQi Zhang */ 1516d6218317SQi Zhang static int 1517d6218317SQi Zhang ice_vc_del_fdir_fltr_post(struct ice_vf *vf, struct ice_vf_fdir_ctx *ctx, 1518d6218317SQi Zhang enum virtchnl_fdir_prgm_status status, 1519d6218317SQi Zhang bool success) 1520d6218317SQi Zhang { 1521d6218317SQi Zhang struct virtchnl_fdir_fltr_conf *conf = ctx->conf; 1522d6218317SQi Zhang struct device *dev = ice_pf_to_dev(vf->pf); 1523d6218317SQi Zhang enum virtchnl_status_code v_ret; 1524d6218317SQi Zhang struct virtchnl_fdir_del *resp; 1525d6218317SQi Zhang int ret, len, is_tun; 1526d6218317SQi Zhang 1527d6218317SQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS; 1528d6218317SQi Zhang len = sizeof(*resp); 1529d6218317SQi Zhang resp = kzalloc(len, GFP_KERNEL); 1530d6218317SQi Zhang if (!resp) { 1531d6218317SQi Zhang len = 0; 1532d6218317SQi Zhang v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; 1533d6218317SQi Zhang dev_dbg(dev, "VF %d: Alloc resp buf fail", vf->vf_id); 1534d6218317SQi Zhang goto err_exit; 1535d6218317SQi Zhang } 1536d6218317SQi Zhang 1537d6218317SQi Zhang if (!success) 1538d6218317SQi Zhang goto err_exit; 1539d6218317SQi Zhang 1540d6218317SQi Zhang is_tun = 0; 1541d6218317SQi Zhang resp->status = status; 1542d6218317SQi Zhang ice_vc_fdir_remove_entry(vf, conf, conf->flow_id); 1543d6218317SQi Zhang vf->fdir.fdir_fltr_cnt[conf->input.flow_type][is_tun]--; 1544d6218317SQi Zhang 1545d6218317SQi Zhang ret = ice_vc_send_msg_to_vf(vf, ctx->v_opcode, v_ret, 1546d6218317SQi Zhang (u8 *)resp, len); 1547d6218317SQi Zhang kfree(resp); 1548d6218317SQi Zhang 1549d6218317SQi Zhang dev_dbg(dev, "VF %d: flow_id:0x%X, FDIR %s success!\n", 1550d6218317SQi Zhang vf->vf_id, conf->flow_id, 1551d6218317SQi Zhang (ctx->v_opcode == VIRTCHNL_OP_ADD_FDIR_FILTER) ? 1552d6218317SQi Zhang "add" : "del"); 1553d6218317SQi Zhang devm_kfree(dev, conf); 1554d6218317SQi Zhang return ret; 1555d6218317SQi Zhang 1556d6218317SQi Zhang err_exit: 1557d6218317SQi Zhang if (resp) 1558d6218317SQi Zhang resp->status = status; 1559d6218317SQi Zhang if (success) 1560d6218317SQi Zhang devm_kfree(dev, conf); 1561d6218317SQi Zhang 1562d6218317SQi Zhang ret = ice_vc_send_msg_to_vf(vf, ctx->v_opcode, v_ret, 1563d6218317SQi Zhang (u8 *)resp, len); 1564d6218317SQi Zhang kfree(resp); 1565d6218317SQi Zhang return ret; 1566d6218317SQi Zhang } 1567d6218317SQi Zhang 1568d6218317SQi Zhang /** 1569d6218317SQi Zhang * ice_flush_fdir_ctx 1570d6218317SQi Zhang * @pf: pointer to the PF structure 1571d6218317SQi Zhang * 1572d6218317SQi Zhang * Flush all the pending event on ctx_done list and process them. 1573d6218317SQi Zhang */ 1574d6218317SQi Zhang void ice_flush_fdir_ctx(struct ice_pf *pf) 1575d6218317SQi Zhang { 1576c4c2c7dbSJacob Keller struct ice_vf *vf; 1577c4c2c7dbSJacob Keller unsigned int bkt; 1578d6218317SQi Zhang 15797e408e07SAnirudh Venkataramanan if (!test_and_clear_bit(ICE_FD_VF_FLUSH_CTX, pf->state)) 1580d6218317SQi Zhang return; 1581d6218317SQi Zhang 15823d5985a1SJacob Keller mutex_lock(&pf->vfs.table_lock); 1583c4c2c7dbSJacob Keller ice_for_each_vf(pf, bkt, vf) { 1584d6218317SQi Zhang struct device *dev = ice_pf_to_dev(pf); 1585d6218317SQi Zhang enum virtchnl_fdir_prgm_status status; 1586d6218317SQi Zhang struct ice_vf_fdir_ctx *ctx; 1587d6218317SQi Zhang unsigned long flags; 1588d6218317SQi Zhang int ret; 1589d6218317SQi Zhang 1590d6218317SQi Zhang if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) 1591d6218317SQi Zhang continue; 1592d6218317SQi Zhang 1593d6218317SQi Zhang if (vf->ctrl_vsi_idx == ICE_NO_VSI) 1594d6218317SQi Zhang continue; 1595d6218317SQi Zhang 1596d6218317SQi Zhang ctx = &vf->fdir.ctx_done; 1597d6218317SQi Zhang spin_lock_irqsave(&vf->fdir.ctx_lock, flags); 1598d6218317SQi Zhang if (!(ctx->flags & ICE_VF_FDIR_CTX_VALID)) { 1599d6218317SQi Zhang spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags); 1600d6218317SQi Zhang continue; 1601d6218317SQi Zhang } 1602d6218317SQi Zhang spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags); 1603d6218317SQi Zhang 1604d6218317SQi Zhang WARN_ON(ctx->stat == ICE_FDIR_CTX_READY); 1605d6218317SQi Zhang if (ctx->stat == ICE_FDIR_CTX_TIMEOUT) { 1606d6218317SQi Zhang status = VIRTCHNL_FDIR_FAILURE_RULE_TIMEOUT; 1607d6218317SQi Zhang dev_err(dev, "VF %d: ctrl_vsi irq timeout\n", 1608d6218317SQi Zhang vf->vf_id); 1609d6218317SQi Zhang goto err_exit; 1610d6218317SQi Zhang } 1611d6218317SQi Zhang 1612d6218317SQi Zhang ret = ice_vf_verify_rx_desc(vf, ctx, &status); 1613d6218317SQi Zhang if (ret) 1614d6218317SQi Zhang goto err_exit; 1615d6218317SQi Zhang 1616d6218317SQi Zhang if (ctx->v_opcode == VIRTCHNL_OP_ADD_FDIR_FILTER) 1617d6218317SQi Zhang ice_vc_add_fdir_fltr_post(vf, ctx, status, true); 1618d6218317SQi Zhang else if (ctx->v_opcode == VIRTCHNL_OP_DEL_FDIR_FILTER) 1619d6218317SQi Zhang ice_vc_del_fdir_fltr_post(vf, ctx, status, true); 1620d6218317SQi Zhang else 1621d6218317SQi Zhang dev_err(dev, "VF %d: Unsupported opcode\n", vf->vf_id); 1622d6218317SQi Zhang 1623d6218317SQi Zhang spin_lock_irqsave(&vf->fdir.ctx_lock, flags); 1624d6218317SQi Zhang ctx->flags &= ~ICE_VF_FDIR_CTX_VALID; 1625d6218317SQi Zhang spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags); 1626d6218317SQi Zhang continue; 1627d6218317SQi Zhang err_exit: 1628d6218317SQi Zhang if (ctx->v_opcode == VIRTCHNL_OP_ADD_FDIR_FILTER) 1629d6218317SQi Zhang ice_vc_add_fdir_fltr_post(vf, ctx, status, false); 1630d6218317SQi Zhang else if (ctx->v_opcode == VIRTCHNL_OP_DEL_FDIR_FILTER) 1631d6218317SQi Zhang ice_vc_del_fdir_fltr_post(vf, ctx, status, false); 1632d6218317SQi Zhang else 1633d6218317SQi Zhang dev_err(dev, "VF %d: Unsupported opcode\n", vf->vf_id); 1634d6218317SQi Zhang 1635d6218317SQi Zhang spin_lock_irqsave(&vf->fdir.ctx_lock, flags); 1636d6218317SQi Zhang ctx->flags &= ~ICE_VF_FDIR_CTX_VALID; 1637d6218317SQi Zhang spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags); 1638d6218317SQi Zhang } 16393d5985a1SJacob Keller mutex_unlock(&pf->vfs.table_lock); 1640d6218317SQi Zhang } 1641d6218317SQi Zhang 1642d6218317SQi Zhang /** 1643d6218317SQi Zhang * ice_vc_fdir_set_irq_ctx - set FDIR context info for later IRQ handler 1644d6218317SQi Zhang * @vf: pointer to the VF structure 1645d6218317SQi Zhang * @conf: FDIR configuration for each filter 1646d6218317SQi Zhang * @v_opcode: virtual channel operation code 1647d6218317SQi Zhang * 1648d6218317SQi Zhang * Return: 0 on success, and other on error. 1649d6218317SQi Zhang */ 1650d6218317SQi Zhang static int 1651d6218317SQi Zhang ice_vc_fdir_set_irq_ctx(struct ice_vf *vf, struct virtchnl_fdir_fltr_conf *conf, 1652d6218317SQi Zhang enum virtchnl_ops v_opcode) 1653d6218317SQi Zhang { 1654d6218317SQi Zhang struct device *dev = ice_pf_to_dev(vf->pf); 1655d6218317SQi Zhang struct ice_vf_fdir_ctx *ctx; 1656d6218317SQi Zhang unsigned long flags; 1657d6218317SQi Zhang 1658d6218317SQi Zhang ctx = &vf->fdir.ctx_irq; 1659d6218317SQi Zhang spin_lock_irqsave(&vf->fdir.ctx_lock, flags); 1660d6218317SQi Zhang if ((vf->fdir.ctx_irq.flags & ICE_VF_FDIR_CTX_VALID) || 1661d6218317SQi Zhang (vf->fdir.ctx_done.flags & ICE_VF_FDIR_CTX_VALID)) { 1662d6218317SQi Zhang spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags); 1663d6218317SQi Zhang dev_dbg(dev, "VF %d: Last request is still in progress\n", 1664d6218317SQi Zhang vf->vf_id); 1665d6218317SQi Zhang return -EBUSY; 1666d6218317SQi Zhang } 1667d6218317SQi Zhang ctx->flags |= ICE_VF_FDIR_CTX_VALID; 1668d6218317SQi Zhang spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags); 1669d6218317SQi Zhang 1670d6218317SQi Zhang ctx->conf = conf; 1671d6218317SQi Zhang ctx->v_opcode = v_opcode; 1672d6218317SQi Zhang ctx->stat = ICE_FDIR_CTX_READY; 1673d6218317SQi Zhang timer_setup(&ctx->rx_tmr, ice_vf_fdir_timer, 0); 1674d6218317SQi Zhang 1675d6218317SQi Zhang mod_timer(&ctx->rx_tmr, round_jiffies(msecs_to_jiffies(10) + jiffies)); 1676d6218317SQi Zhang 1677d6218317SQi Zhang return 0; 1678d6218317SQi Zhang } 1679d6218317SQi Zhang 1680d6218317SQi Zhang /** 1681d6218317SQi Zhang * ice_vc_fdir_clear_irq_ctx - clear FDIR context info for IRQ handler 1682d6218317SQi Zhang * @vf: pointer to the VF structure 1683d6218317SQi Zhang * 1684d6218317SQi Zhang * Return: 0 on success, and other on error. 1685d6218317SQi Zhang */ 1686d6218317SQi Zhang static void ice_vc_fdir_clear_irq_ctx(struct ice_vf *vf) 1687d6218317SQi Zhang { 1688d6218317SQi Zhang struct ice_vf_fdir_ctx *ctx = &vf->fdir.ctx_irq; 1689d6218317SQi Zhang unsigned long flags; 1690d6218317SQi Zhang 1691d6218317SQi Zhang del_timer(&ctx->rx_tmr); 1692d6218317SQi Zhang spin_lock_irqsave(&vf->fdir.ctx_lock, flags); 1693d6218317SQi Zhang ctx->flags &= ~ICE_VF_FDIR_CTX_VALID; 1694d6218317SQi Zhang spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags); 1695d6218317SQi Zhang } 1696d6218317SQi Zhang 1697d6218317SQi Zhang /** 16981f7ea1cdSQi Zhang * ice_vc_add_fdir_fltr - add a FDIR filter for VF by the msg buffer 16991f7ea1cdSQi Zhang * @vf: pointer to the VF info 17001f7ea1cdSQi Zhang * @msg: pointer to the msg buffer 17011f7ea1cdSQi Zhang * 17021f7ea1cdSQi Zhang * Return: 0 on success, and other on error. 17031f7ea1cdSQi Zhang */ 17041f7ea1cdSQi Zhang int ice_vc_add_fdir_fltr(struct ice_vf *vf, u8 *msg) 17051f7ea1cdSQi Zhang { 17061f7ea1cdSQi Zhang struct virtchnl_fdir_add *fltr = (struct virtchnl_fdir_add *)msg; 17071f7ea1cdSQi Zhang struct virtchnl_fdir_add *stat = NULL; 17081f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf; 17091f7ea1cdSQi Zhang enum virtchnl_status_code v_ret; 17101f7ea1cdSQi Zhang struct device *dev; 17111f7ea1cdSQi Zhang struct ice_pf *pf; 17121f7ea1cdSQi Zhang int is_tun = 0; 17131f7ea1cdSQi Zhang int len = 0; 17141f7ea1cdSQi Zhang int ret; 17151f7ea1cdSQi Zhang 17161f7ea1cdSQi Zhang pf = vf->pf; 17171f7ea1cdSQi Zhang dev = ice_pf_to_dev(pf); 17181f7ea1cdSQi Zhang ret = ice_vc_fdir_param_check(vf, fltr->vsi_id); 17191f7ea1cdSQi Zhang if (ret) { 17201f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_ERR_PARAM; 17211f7ea1cdSQi Zhang dev_dbg(dev, "Parameter check for VF %d failed\n", vf->vf_id); 17221f7ea1cdSQi Zhang goto err_exit; 17231f7ea1cdSQi Zhang } 17241f7ea1cdSQi Zhang 17251f7ea1cdSQi Zhang ret = ice_vf_start_ctrl_vsi(vf); 17261f7ea1cdSQi Zhang if (ret && (ret != -EEXIST)) { 17271f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_ERR_PARAM; 17281f7ea1cdSQi Zhang dev_err(dev, "Init FDIR for VF %d failed, ret:%d\n", 17291f7ea1cdSQi Zhang vf->vf_id, ret); 17301f7ea1cdSQi Zhang goto err_exit; 17311f7ea1cdSQi Zhang } 17321f7ea1cdSQi Zhang 17331f7ea1cdSQi Zhang stat = kzalloc(sizeof(*stat), GFP_KERNEL); 17341f7ea1cdSQi Zhang if (!stat) { 17351f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; 17361f7ea1cdSQi Zhang dev_dbg(dev, "Alloc stat for VF %d failed\n", vf->vf_id); 17371f7ea1cdSQi Zhang goto err_exit; 17381f7ea1cdSQi Zhang } 17391f7ea1cdSQi Zhang 17401f7ea1cdSQi Zhang conf = devm_kzalloc(dev, sizeof(*conf), GFP_KERNEL); 17411f7ea1cdSQi Zhang if (!conf) { 17421f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; 17431f7ea1cdSQi Zhang dev_dbg(dev, "Alloc conf for VF %d failed\n", vf->vf_id); 17441f7ea1cdSQi Zhang goto err_exit; 17451f7ea1cdSQi Zhang } 17461f7ea1cdSQi Zhang 17471f7ea1cdSQi Zhang len = sizeof(*stat); 17481f7ea1cdSQi Zhang ret = ice_vc_validate_fdir_fltr(vf, fltr, conf); 17491f7ea1cdSQi Zhang if (ret) { 17501f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS; 17511f7ea1cdSQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_INVALID; 17521f7ea1cdSQi Zhang dev_dbg(dev, "Invalid FDIR filter from VF %d\n", vf->vf_id); 17531f7ea1cdSQi Zhang goto err_free_conf; 17541f7ea1cdSQi Zhang } 17551f7ea1cdSQi Zhang 17561f7ea1cdSQi Zhang if (fltr->validate_only) { 17571f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS; 17581f7ea1cdSQi Zhang stat->status = VIRTCHNL_FDIR_SUCCESS; 17591f7ea1cdSQi Zhang devm_kfree(dev, conf); 17601f7ea1cdSQi Zhang ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ADD_FDIR_FILTER, 17611f7ea1cdSQi Zhang v_ret, (u8 *)stat, len); 17621f7ea1cdSQi Zhang goto exit; 17631f7ea1cdSQi Zhang } 17641f7ea1cdSQi Zhang 17651f7ea1cdSQi Zhang ret = ice_vc_fdir_config_input_set(vf, fltr, conf, is_tun); 17661f7ea1cdSQi Zhang if (ret) { 17671f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS; 17681f7ea1cdSQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_CONFLICT; 17691f7ea1cdSQi Zhang dev_err(dev, "VF %d: FDIR input set configure failed, ret:%d\n", 17701f7ea1cdSQi Zhang vf->vf_id, ret); 17711f7ea1cdSQi Zhang goto err_free_conf; 17721f7ea1cdSQi Zhang } 17731f7ea1cdSQi Zhang 17741f7ea1cdSQi Zhang ret = ice_vc_fdir_is_dup_fltr(vf, conf); 17751f7ea1cdSQi Zhang if (ret) { 17761f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS; 17771f7ea1cdSQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_EXIST; 17781f7ea1cdSQi Zhang dev_dbg(dev, "VF %d: duplicated FDIR rule detected\n", 17791f7ea1cdSQi Zhang vf->vf_id); 17801f7ea1cdSQi Zhang goto err_free_conf; 17811f7ea1cdSQi Zhang } 17821f7ea1cdSQi Zhang 1783d6218317SQi Zhang ret = ice_vc_fdir_insert_entry(vf, conf, &conf->flow_id); 17841f7ea1cdSQi Zhang if (ret) { 17851f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS; 17861f7ea1cdSQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; 17871f7ea1cdSQi Zhang dev_dbg(dev, "VF %d: insert FDIR list failed\n", vf->vf_id); 17881f7ea1cdSQi Zhang goto err_free_conf; 17891f7ea1cdSQi Zhang } 17901f7ea1cdSQi Zhang 1791d6218317SQi Zhang ret = ice_vc_fdir_set_irq_ctx(vf, conf, VIRTCHNL_OP_ADD_FDIR_FILTER); 1792d6218317SQi Zhang if (ret) { 1793d6218317SQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS; 1794d6218317SQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; 1795d6218317SQi Zhang dev_dbg(dev, "VF %d: set FDIR context failed\n", vf->vf_id); 1796d6218317SQi Zhang goto err_free_conf; 1797d6218317SQi Zhang } 1798d6218317SQi Zhang 17991f7ea1cdSQi Zhang ret = ice_vc_fdir_write_fltr(vf, conf, true, is_tun); 18001f7ea1cdSQi Zhang if (ret) { 18011f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS; 18021f7ea1cdSQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; 18031f7ea1cdSQi Zhang dev_err(dev, "VF %d: writing FDIR rule failed, ret:%d\n", 18041f7ea1cdSQi Zhang vf->vf_id, ret); 18051f7ea1cdSQi Zhang goto err_rem_entry; 18061f7ea1cdSQi Zhang } 18071f7ea1cdSQi Zhang 18081f7ea1cdSQi Zhang exit: 18091f7ea1cdSQi Zhang kfree(stat); 18101f7ea1cdSQi Zhang return ret; 18111f7ea1cdSQi Zhang 18121f7ea1cdSQi Zhang err_rem_entry: 1813d6218317SQi Zhang ice_vc_fdir_clear_irq_ctx(vf); 1814d6218317SQi Zhang ice_vc_fdir_remove_entry(vf, conf, conf->flow_id); 18151f7ea1cdSQi Zhang err_free_conf: 18161f7ea1cdSQi Zhang devm_kfree(dev, conf); 18171f7ea1cdSQi Zhang err_exit: 18181f7ea1cdSQi Zhang ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ADD_FDIR_FILTER, v_ret, 18191f7ea1cdSQi Zhang (u8 *)stat, len); 18201f7ea1cdSQi Zhang kfree(stat); 18211f7ea1cdSQi Zhang return ret; 18221f7ea1cdSQi Zhang } 18231f7ea1cdSQi Zhang 18241f7ea1cdSQi Zhang /** 18251f7ea1cdSQi Zhang * ice_vc_del_fdir_fltr - delete a FDIR filter for VF by the msg buffer 18261f7ea1cdSQi Zhang * @vf: pointer to the VF info 18271f7ea1cdSQi Zhang * @msg: pointer to the msg buffer 18281f7ea1cdSQi Zhang * 18291f7ea1cdSQi Zhang * Return: 0 on success, and other on error. 18301f7ea1cdSQi Zhang */ 18311f7ea1cdSQi Zhang int ice_vc_del_fdir_fltr(struct ice_vf *vf, u8 *msg) 18321f7ea1cdSQi Zhang { 18331f7ea1cdSQi Zhang struct virtchnl_fdir_del *fltr = (struct virtchnl_fdir_del *)msg; 18341f7ea1cdSQi Zhang struct virtchnl_fdir_del *stat = NULL; 18351f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf; 18361f7ea1cdSQi Zhang enum virtchnl_status_code v_ret; 18371f7ea1cdSQi Zhang struct device *dev; 18381f7ea1cdSQi Zhang struct ice_pf *pf; 18391f7ea1cdSQi Zhang int is_tun = 0; 18401f7ea1cdSQi Zhang int len = 0; 18411f7ea1cdSQi Zhang int ret; 18421f7ea1cdSQi Zhang 18431f7ea1cdSQi Zhang pf = vf->pf; 18441f7ea1cdSQi Zhang dev = ice_pf_to_dev(pf); 18451f7ea1cdSQi Zhang ret = ice_vc_fdir_param_check(vf, fltr->vsi_id); 18461f7ea1cdSQi Zhang if (ret) { 18471f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_ERR_PARAM; 18481f7ea1cdSQi Zhang dev_dbg(dev, "Parameter check for VF %d failed\n", vf->vf_id); 18491f7ea1cdSQi Zhang goto err_exit; 18501f7ea1cdSQi Zhang } 18511f7ea1cdSQi Zhang 18521f7ea1cdSQi Zhang stat = kzalloc(sizeof(*stat), GFP_KERNEL); 18531f7ea1cdSQi Zhang if (!stat) { 18541f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; 18551f7ea1cdSQi Zhang dev_dbg(dev, "Alloc stat for VF %d failed\n", vf->vf_id); 18561f7ea1cdSQi Zhang goto err_exit; 18571f7ea1cdSQi Zhang } 18581f7ea1cdSQi Zhang 18591f7ea1cdSQi Zhang len = sizeof(*stat); 18601f7ea1cdSQi Zhang 18611f7ea1cdSQi Zhang conf = ice_vc_fdir_lookup_entry(vf, fltr->flow_id); 18621f7ea1cdSQi Zhang if (!conf) { 18631f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS; 18641f7ea1cdSQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NONEXIST; 18651f7ea1cdSQi Zhang dev_dbg(dev, "VF %d: FDIR invalid flow_id:0x%X\n", 18661f7ea1cdSQi Zhang vf->vf_id, fltr->flow_id); 18671f7ea1cdSQi Zhang goto err_exit; 18681f7ea1cdSQi Zhang } 18691f7ea1cdSQi Zhang 18701f7ea1cdSQi Zhang /* Just return failure when ctrl_vsi idx is invalid */ 18711f7ea1cdSQi Zhang if (vf->ctrl_vsi_idx == ICE_NO_VSI) { 18721f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS; 18731f7ea1cdSQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; 18741f7ea1cdSQi Zhang dev_err(dev, "Invalid FDIR ctrl_vsi for VF %d\n", vf->vf_id); 18751f7ea1cdSQi Zhang goto err_exit; 18761f7ea1cdSQi Zhang } 18771f7ea1cdSQi Zhang 1878d6218317SQi Zhang ret = ice_vc_fdir_set_irq_ctx(vf, conf, VIRTCHNL_OP_DEL_FDIR_FILTER); 1879d6218317SQi Zhang if (ret) { 1880d6218317SQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS; 1881d6218317SQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; 1882d6218317SQi Zhang dev_dbg(dev, "VF %d: set FDIR context failed\n", vf->vf_id); 1883d6218317SQi Zhang goto err_exit; 1884d6218317SQi Zhang } 1885d6218317SQi Zhang 18861f7ea1cdSQi Zhang ret = ice_vc_fdir_write_fltr(vf, conf, false, is_tun); 18871f7ea1cdSQi Zhang if (ret) { 18881f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS; 18891f7ea1cdSQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; 18901f7ea1cdSQi Zhang dev_err(dev, "VF %d: writing FDIR rule failed, ret:%d\n", 18911f7ea1cdSQi Zhang vf->vf_id, ret); 1892d6218317SQi Zhang goto err_del_tmr; 18931f7ea1cdSQi Zhang } 18941f7ea1cdSQi Zhang 1895d6218317SQi Zhang kfree(stat); 18961f7ea1cdSQi Zhang 1897d6218317SQi Zhang return ret; 18981f7ea1cdSQi Zhang 1899d6218317SQi Zhang err_del_tmr: 1900d6218317SQi Zhang ice_vc_fdir_clear_irq_ctx(vf); 19011f7ea1cdSQi Zhang err_exit: 19021f7ea1cdSQi Zhang ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DEL_FDIR_FILTER, v_ret, 19031f7ea1cdSQi Zhang (u8 *)stat, len); 19041f7ea1cdSQi Zhang kfree(stat); 19051f7ea1cdSQi Zhang return ret; 19061f7ea1cdSQi Zhang } 19071f7ea1cdSQi Zhang 19081f7ea1cdSQi Zhang /** 19091f7ea1cdSQi Zhang * ice_vf_fdir_init - init FDIR resource for VF 19101f7ea1cdSQi Zhang * @vf: pointer to the VF info 19111f7ea1cdSQi Zhang */ 19121f7ea1cdSQi Zhang void ice_vf_fdir_init(struct ice_vf *vf) 19131f7ea1cdSQi Zhang { 19141f7ea1cdSQi Zhang struct ice_vf_fdir *fdir = &vf->fdir; 19151f7ea1cdSQi Zhang 19161f7ea1cdSQi Zhang idr_init(&fdir->fdir_rule_idr); 19171f7ea1cdSQi Zhang INIT_LIST_HEAD(&fdir->fdir_rule_list); 1918d6218317SQi Zhang 1919d6218317SQi Zhang spin_lock_init(&fdir->ctx_lock); 1920d6218317SQi Zhang fdir->ctx_irq.flags = 0; 1921d6218317SQi Zhang fdir->ctx_done.flags = 0; 19221f7ea1cdSQi Zhang } 19231f7ea1cdSQi Zhang 19241f7ea1cdSQi Zhang /** 19251f7ea1cdSQi Zhang * ice_vf_fdir_exit - destroy FDIR resource for VF 19261f7ea1cdSQi Zhang * @vf: pointer to the VF info 19271f7ea1cdSQi Zhang */ 19281f7ea1cdSQi Zhang void ice_vf_fdir_exit(struct ice_vf *vf) 19291f7ea1cdSQi Zhang { 19301f7ea1cdSQi Zhang ice_vc_fdir_flush_entry(vf); 19311f7ea1cdSQi Zhang idr_destroy(&vf->fdir.fdir_rule_idr); 19321f7ea1cdSQi Zhang ice_vc_fdir_rem_prof_all(vf); 19331f7ea1cdSQi Zhang ice_vc_fdir_free_prof_all(vf); 19341f7ea1cdSQi Zhang } 1935