Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ice: Optimize table usage

Attempt to optimize TCAM entries and reduce table resource usage by
searching for profiles that can be reused. Provide resource cleanup
of both hardware and software structures.

Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
Signed-off-by: Henry Tieman <henry.w.tieman@intel.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>

authored by

Tony Nguyen and committed by
Jeff Kirsher
2c61054c 43dbfc7b

+773 -1
+394
drivers/net/ethernet/intel/ice/ice_flex_pipe.c
··· 1922 1922 } 1923 1923 1924 1924 /** 1925 + * ice_free_prof_id - free profile ID 1926 + * @hw: pointer to the HW struct 1927 + * @blk: the block from which to free the profile ID 1928 + * @prof_id: the profile ID to free 1929 + * 1930 + * This function frees a profile ID, which also corresponds to a Field Vector. 1931 + */ 1932 + static enum ice_status 1933 + ice_free_prof_id(struct ice_hw *hw, enum ice_block blk, u8 prof_id) 1934 + { 1935 + u16 tmp_prof_id = (u16)prof_id; 1936 + u16 res_type; 1937 + 1938 + if (!ice_prof_id_rsrc_type(blk, &res_type)) 1939 + return ICE_ERR_PARAM; 1940 + 1941 + return ice_free_hw_res(hw, res_type, 1, &tmp_prof_id); 1942 + } 1943 + 1944 + /** 1925 1945 * ice_prof_inc_ref - increment reference count for profile 1926 1946 * @hw: pointer to the HW struct 1927 1947 * @blk: the block from which to free the profile ID ··· 1980 1960 memcpy(&hw->blk[blk].es.t[off], fv, 1981 1961 hw->blk[blk].es.fvw * sizeof(*fv)); 1982 1962 } 1963 + } 1964 + 1965 + /** 1966 + * ice_prof_dec_ref - decrement reference count for profile 1967 + * @hw: pointer to the HW struct 1968 + * @blk: the block from which to free the profile ID 1969 + * @prof_id: the profile ID for which to decrement the reference count 1970 + */ 1971 + static enum ice_status 1972 + ice_prof_dec_ref(struct ice_hw *hw, enum ice_block blk, u8 prof_id) 1973 + { 1974 + if (prof_id > hw->blk[blk].es.count) 1975 + return ICE_ERR_PARAM; 1976 + 1977 + if (hw->blk[blk].es.ref_count[prof_id] > 0) { 1978 + if (!--hw->blk[blk].es.ref_count[prof_id]) { 1979 + ice_write_es(hw, blk, prof_id, NULL); 1980 + return ice_free_prof_id(hw, blk, prof_id); 1981 + } 1982 + } 1983 + 1984 + return 0; 1983 1985 } 1984 1986 1985 1987 /* Block / table section IDs */ ··· 2261 2219 } 2262 2220 2263 2221 /** 2222 + * ice_free_prof_map - free profile map 2223 + * @hw: pointer to the hardware structure 2224 + * @blk_idx: HW block index 2225 + */ 2226 + static void ice_free_prof_map(struct ice_hw *hw, u8 blk_idx) 2227 + { 2228 + struct ice_es *es = &hw->blk[blk_idx].es; 2229 + struct ice_prof_map *del, *tmp; 2230 + 2231 + mutex_lock(&es->prof_map_lock); 2232 + list_for_each_entry_safe(del, tmp, &es->prof_map, list) { 2233 + list_del(&del->list); 2234 + devm_kfree(ice_hw_to_dev(hw), del); 2235 + } 2236 + INIT_LIST_HEAD(&es->prof_map); 2237 + mutex_unlock(&es->prof_map_lock); 2238 + } 2239 + 2240 + /** 2241 + * ice_free_flow_profs - free flow profile entries 2242 + * @hw: pointer to the hardware structure 2243 + * @blk_idx: HW block index 2244 + */ 2245 + static void ice_free_flow_profs(struct ice_hw *hw, u8 blk_idx) 2246 + { 2247 + struct ice_flow_prof *p, *tmp; 2248 + 2249 + mutex_lock(&hw->fl_profs_locks[blk_idx]); 2250 + list_for_each_entry_safe(p, tmp, &hw->fl_profs[blk_idx], l_entry) { 2251 + list_del(&p->l_entry); 2252 + devm_kfree(ice_hw_to_dev(hw), p); 2253 + } 2254 + mutex_unlock(&hw->fl_profs_locks[blk_idx]); 2255 + 2256 + /* if driver is in reset and tables are being cleared 2257 + * re-initialize the flow profile list heads 2258 + */ 2259 + INIT_LIST_HEAD(&hw->fl_profs[blk_idx]); 2260 + } 2261 + 2262 + /** 2263 + * ice_free_vsig_tbl - free complete VSIG table entries 2264 + * @hw: pointer to the hardware structure 2265 + * @blk: the HW block on which to free the VSIG table entries 2266 + */ 2267 + static void ice_free_vsig_tbl(struct ice_hw *hw, enum ice_block blk) 2268 + { 2269 + u16 i; 2270 + 2271 + if (!hw->blk[blk].xlt2.vsig_tbl) 2272 + return; 2273 + 2274 + for (i = 1; i < ICE_MAX_VSIGS; i++) 2275 + if (hw->blk[blk].xlt2.vsig_tbl[i].in_use) 2276 + ice_vsig_free(hw, blk, i); 2277 + } 2278 + 2279 + /** 2264 2280 * ice_free_hw_tbls - free hardware table memory 2265 2281 * @hw: pointer to the hardware structure 2266 2282 */ ··· 2331 2231 if (hw->blk[i].is_list_init) { 2332 2232 struct ice_es *es = &hw->blk[i].es; 2333 2233 2234 + ice_free_prof_map(hw, i); 2334 2235 mutex_destroy(&es->prof_map_lock); 2236 + 2237 + ice_free_flow_profs(hw, i); 2335 2238 mutex_destroy(&hw->fl_profs_locks[i]); 2336 2239 2337 2240 hw->blk[i].is_list_init = false; 2338 2241 } 2242 + ice_free_vsig_tbl(hw, (enum ice_block)i); 2339 2243 devm_kfree(ice_hw_to_dev(hw), hw->blk[i].xlt1.ptypes); 2340 2244 devm_kfree(ice_hw_to_dev(hw), hw->blk[i].xlt1.ptg_tbl); 2341 2245 devm_kfree(ice_hw_to_dev(hw), hw->blk[i].xlt1.t); ··· 2386 2282 struct ice_xlt1 *xlt1 = &hw->blk[i].xlt1; 2387 2283 struct ice_xlt2 *xlt2 = &hw->blk[i].xlt2; 2388 2284 struct ice_es *es = &hw->blk[i].es; 2285 + 2286 + if (hw->blk[i].is_list_init) { 2287 + ice_free_prof_map(hw, i); 2288 + ice_free_flow_profs(hw, i); 2289 + } 2290 + 2291 + ice_free_vsig_tbl(hw, (enum ice_block)i); 2389 2292 2390 2293 memset(xlt1->ptypes, 0, xlt1->count * sizeof(*xlt1->ptypes)); 2391 2294 memset(xlt1->ptg_tbl, 0, ··· 3068 2957 } 3069 2958 3070 2959 /** 2960 + * ice_vsig_prof_id_count - count profiles in a VSIG 2961 + * @hw: pointer to the HW struct 2962 + * @blk: hardware block 2963 + * @vsig: VSIG to remove the profile from 2964 + */ 2965 + static u16 2966 + ice_vsig_prof_id_count(struct ice_hw *hw, enum ice_block blk, u16 vsig) 2967 + { 2968 + u16 idx = vsig & ICE_VSIG_IDX_M, count = 0; 2969 + struct ice_vsig_prof *p; 2970 + 2971 + list_for_each_entry(p, &hw->blk[blk].xlt2.vsig_tbl[idx].prop_lst, 2972 + list) 2973 + count++; 2974 + 2975 + return count; 2976 + } 2977 + 2978 + /** 3071 2979 * ice_rel_tcam_idx - release a TCAM index 3072 2980 * @hw: pointer to the HW struct 3073 2981 * @blk: hardware block ··· 3192 3062 } while (vsi_cur); 3193 3063 3194 3064 return ice_vsig_free(hw, blk, vsig); 3065 + } 3066 + 3067 + /** 3068 + * ice_rem_prof_id_vsig - remove a specific profile from a VSIG 3069 + * @hw: pointer to the HW struct 3070 + * @blk: hardware block 3071 + * @vsig: VSIG to remove the profile from 3072 + * @hdl: profile handle indicating which profile to remove 3073 + * @chg: list to receive a record of changes 3074 + */ 3075 + static enum ice_status 3076 + ice_rem_prof_id_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig, u64 hdl, 3077 + struct list_head *chg) 3078 + { 3079 + u16 idx = vsig & ICE_VSIG_IDX_M; 3080 + struct ice_vsig_prof *p, *t; 3081 + enum ice_status status; 3082 + 3083 + list_for_each_entry_safe(p, t, 3084 + &hw->blk[blk].xlt2.vsig_tbl[idx].prop_lst, 3085 + list) 3086 + if (p->profile_cookie == hdl) { 3087 + if (ice_vsig_prof_id_count(hw, blk, vsig) == 1) 3088 + /* this is the last profile, remove the VSIG */ 3089 + return ice_rem_vsig(hw, blk, vsig, chg); 3090 + 3091 + status = ice_rem_prof_id(hw, blk, p); 3092 + if (!status) { 3093 + list_del(&p->list); 3094 + devm_kfree(ice_hw_to_dev(hw), p); 3095 + } 3096 + return status; 3097 + } 3098 + 3099 + return ICE_ERR_DOES_NOT_EXIST; 3100 + } 3101 + 3102 + /** 3103 + * ice_rem_flow_all - remove all flows with a particular profile 3104 + * @hw: pointer to the HW struct 3105 + * @blk: hardware block 3106 + * @id: profile tracking ID 3107 + */ 3108 + static enum ice_status 3109 + ice_rem_flow_all(struct ice_hw *hw, enum ice_block blk, u64 id) 3110 + { 3111 + struct ice_chs_chg *del, *tmp; 3112 + enum ice_status status; 3113 + struct list_head chg; 3114 + u16 i; 3115 + 3116 + INIT_LIST_HEAD(&chg); 3117 + 3118 + for (i = 1; i < ICE_MAX_VSIGS; i++) 3119 + if (hw->blk[blk].xlt2.vsig_tbl[i].in_use) { 3120 + if (ice_has_prof_vsig(hw, blk, i, id)) { 3121 + status = ice_rem_prof_id_vsig(hw, blk, i, id, 3122 + &chg); 3123 + if (status) 3124 + goto err_ice_rem_flow_all; 3125 + } 3126 + } 3127 + 3128 + status = ice_upd_prof_hw(hw, blk, &chg); 3129 + 3130 + err_ice_rem_flow_all: 3131 + list_for_each_entry_safe(del, tmp, &chg, list_entry) { 3132 + list_del(&del->list_entry); 3133 + devm_kfree(ice_hw_to_dev(hw), del); 3134 + } 3135 + 3136 + return status; 3137 + } 3138 + 3139 + /** 3140 + * ice_rem_prof - remove profile 3141 + * @hw: pointer to the HW struct 3142 + * @blk: hardware block 3143 + * @id: profile tracking ID 3144 + * 3145 + * This will remove the profile specified by the ID parameter, which was 3146 + * previously created through ice_add_prof. If any existing entries 3147 + * are associated with this profile, they will be removed as well. 3148 + */ 3149 + enum ice_status ice_rem_prof(struct ice_hw *hw, enum ice_block blk, u64 id) 3150 + { 3151 + struct ice_prof_map *pmap; 3152 + enum ice_status status; 3153 + 3154 + mutex_lock(&hw->blk[blk].es.prof_map_lock); 3155 + 3156 + pmap = ice_search_prof_id_low(hw, blk, id); 3157 + if (!pmap) { 3158 + status = ICE_ERR_DOES_NOT_EXIST; 3159 + goto err_ice_rem_prof; 3160 + } 3161 + 3162 + /* remove all flows with this profile */ 3163 + status = ice_rem_flow_all(hw, blk, pmap->profile_cookie); 3164 + if (status) 3165 + goto err_ice_rem_prof; 3166 + 3167 + /* dereference profile, and possibly remove */ 3168 + ice_prof_dec_ref(hw, blk, pmap->prof_id); 3169 + 3170 + list_del(&pmap->list); 3171 + devm_kfree(ice_hw_to_dev(hw), pmap); 3172 + 3173 + err_ice_rem_prof: 3174 + mutex_unlock(&hw->blk[blk].es.prof_map_lock); 3175 + return status; 3195 3176 } 3196 3177 3197 3178 /** ··· 3949 3708 } 3950 3709 3951 3710 list_for_each_entry_safe(del1, tmp1, &union_lst, list) { 3711 + list_del(&del1->list); 3712 + devm_kfree(ice_hw_to_dev(hw), del1); 3713 + } 3714 + 3715 + return status; 3716 + } 3717 + 3718 + /** 3719 + * ice_rem_prof_from_list - remove a profile from list 3720 + * @hw: pointer to the HW struct 3721 + * @lst: list to remove the profile from 3722 + * @hdl: the profile handle indicating the profile to remove 3723 + */ 3724 + static enum ice_status 3725 + ice_rem_prof_from_list(struct ice_hw *hw, struct list_head *lst, u64 hdl) 3726 + { 3727 + struct ice_vsig_prof *ent, *tmp; 3728 + 3729 + list_for_each_entry_safe(ent, tmp, lst, list) 3730 + if (ent->profile_cookie == hdl) { 3731 + list_del(&ent->list); 3732 + devm_kfree(ice_hw_to_dev(hw), ent); 3733 + return 0; 3734 + } 3735 + 3736 + return ICE_ERR_DOES_NOT_EXIST; 3737 + } 3738 + 3739 + /** 3740 + * ice_rem_prof_id_flow - remove flow 3741 + * @hw: pointer to the HW struct 3742 + * @blk: hardware block 3743 + * @vsi: the VSI from which to remove the profile specified by ID 3744 + * @hdl: profile tracking handle 3745 + * 3746 + * Calling this function will update the hardware tables to remove the 3747 + * profile indicated by the ID parameter for the VSIs specified in the VSI 3748 + * array. Once successfully called, the flow will be disabled. 3749 + */ 3750 + enum ice_status 3751 + ice_rem_prof_id_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl) 3752 + { 3753 + struct ice_vsig_prof *tmp1, *del1; 3754 + struct ice_chs_chg *tmp, *del; 3755 + struct list_head chg, copy; 3756 + enum ice_status status; 3757 + u16 vsig; 3758 + 3759 + INIT_LIST_HEAD(&copy); 3760 + INIT_LIST_HEAD(&chg); 3761 + 3762 + /* determine if VSI is already part of a VSIG */ 3763 + status = ice_vsig_find_vsi(hw, blk, vsi, &vsig); 3764 + if (!status && vsig) { 3765 + bool last_profile; 3766 + bool only_vsi; 3767 + u16 ref; 3768 + 3769 + /* found in VSIG */ 3770 + last_profile = ice_vsig_prof_id_count(hw, blk, vsig) == 1; 3771 + status = ice_vsig_get_ref(hw, blk, vsig, &ref); 3772 + if (status) 3773 + goto err_ice_rem_prof_id_flow; 3774 + only_vsi = (ref == 1); 3775 + 3776 + if (only_vsi) { 3777 + /* If the original VSIG only contains one reference, 3778 + * which will be the requesting VSI, then the VSI is not 3779 + * sharing entries and we can simply remove the specific 3780 + * characteristics from the VSIG. 3781 + */ 3782 + 3783 + if (last_profile) { 3784 + /* If there are no profiles left for this VSIG, 3785 + * then simply remove the the VSIG. 3786 + */ 3787 + status = ice_rem_vsig(hw, blk, vsig, &chg); 3788 + if (status) 3789 + goto err_ice_rem_prof_id_flow; 3790 + } else { 3791 + status = ice_rem_prof_id_vsig(hw, blk, vsig, 3792 + hdl, &chg); 3793 + if (status) 3794 + goto err_ice_rem_prof_id_flow; 3795 + 3796 + /* Adjust priorities */ 3797 + status = ice_adj_prof_priorities(hw, blk, vsig, 3798 + &chg); 3799 + if (status) 3800 + goto err_ice_rem_prof_id_flow; 3801 + } 3802 + 3803 + } else { 3804 + /* Make a copy of the VSIG's list of Profiles */ 3805 + status = ice_get_profs_vsig(hw, blk, vsig, &copy); 3806 + if (status) 3807 + goto err_ice_rem_prof_id_flow; 3808 + 3809 + /* Remove specified profile entry from the list */ 3810 + status = ice_rem_prof_from_list(hw, &copy, hdl); 3811 + if (status) 3812 + goto err_ice_rem_prof_id_flow; 3813 + 3814 + if (list_empty(&copy)) { 3815 + status = ice_move_vsi(hw, blk, vsi, 3816 + ICE_DEFAULT_VSIG, &chg); 3817 + if (status) 3818 + goto err_ice_rem_prof_id_flow; 3819 + 3820 + } else if (!ice_find_dup_props_vsig(hw, blk, &copy, 3821 + &vsig)) { 3822 + /* found an exact match */ 3823 + /* add or move VSI to the VSIG that matches */ 3824 + /* Search for a VSIG with a matching profile 3825 + * list 3826 + */ 3827 + 3828 + /* Found match, move VSI to the matching VSIG */ 3829 + status = ice_move_vsi(hw, blk, vsi, vsig, &chg); 3830 + if (status) 3831 + goto err_ice_rem_prof_id_flow; 3832 + } else { 3833 + /* since no existing VSIG supports this 3834 + * characteristic pattern, we need to create a 3835 + * new VSIG and TCAM entries 3836 + */ 3837 + status = ice_create_vsig_from_lst(hw, blk, vsi, 3838 + &copy, &chg); 3839 + if (status) 3840 + goto err_ice_rem_prof_id_flow; 3841 + 3842 + /* Adjust priorities */ 3843 + status = ice_adj_prof_priorities(hw, blk, vsig, 3844 + &chg); 3845 + if (status) 3846 + goto err_ice_rem_prof_id_flow; 3847 + } 3848 + } 3849 + } else { 3850 + status = ICE_ERR_DOES_NOT_EXIST; 3851 + } 3852 + 3853 + /* update hardware tables */ 3854 + if (!status) 3855 + status = ice_upd_prof_hw(hw, blk, &chg); 3856 + 3857 + err_ice_rem_prof_id_flow: 3858 + list_for_each_entry_safe(del, tmp, &chg, list_entry) { 3859 + list_del(&del->list_entry); 3860 + devm_kfree(ice_hw_to_dev(hw), del); 3861 + } 3862 + 3863 + list_for_each_entry_safe(del1, tmp1, &copy, list) { 3952 3864 list_del(&del1->list); 3953 3865 devm_kfree(ice_hw_to_dev(hw), del1); 3954 3866 }
+4
drivers/net/ethernet/intel/ice/ice_flex_pipe.h
··· 23 23 struct ice_fv_word *es); 24 24 enum ice_status 25 25 ice_add_prof_id_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl); 26 + enum ice_status 27 + ice_rem_prof_id_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl); 26 28 enum ice_status ice_init_pkg(struct ice_hw *hw, u8 *buff, u32 len); 27 29 enum ice_status 28 30 ice_copy_and_init_pkg(struct ice_hw *hw, const u8 *buf, u32 len); ··· 33 31 void ice_fill_blk_tbls(struct ice_hw *hw); 34 32 void ice_clear_hw_tbls(struct ice_hw *hw); 35 33 void ice_free_hw_tbls(struct ice_hw *hw); 34 + enum ice_status 35 + ice_rem_prof(struct ice_hw *hw, enum ice_block blk, u64 id); 36 36 #endif /* _ICE_FLEX_PIPE_H_ */
+338
drivers/net/ethernet/intel/ice/ice_flow.c
··· 377 377 return status; 378 378 } 379 379 380 + #define ICE_FLOW_FIND_PROF_CHK_FLDS 0x00000001 381 + #define ICE_FLOW_FIND_PROF_CHK_VSI 0x00000002 382 + #define ICE_FLOW_FIND_PROF_NOT_CHK_DIR 0x00000004 383 + 384 + /** 385 + * ice_flow_find_prof_conds - Find a profile matching headers and conditions 386 + * @hw: pointer to the HW struct 387 + * @blk: classification stage 388 + * @dir: flow direction 389 + * @segs: array of one or more packet segments that describe the flow 390 + * @segs_cnt: number of packet segments provided 391 + * @vsi_handle: software VSI handle to check VSI (ICE_FLOW_FIND_PROF_CHK_VSI) 392 + * @conds: additional conditions to be checked (ICE_FLOW_FIND_PROF_CHK_*) 393 + */ 394 + static struct ice_flow_prof * 395 + ice_flow_find_prof_conds(struct ice_hw *hw, enum ice_block blk, 396 + enum ice_flow_dir dir, struct ice_flow_seg_info *segs, 397 + u8 segs_cnt, u16 vsi_handle, u32 conds) 398 + { 399 + struct ice_flow_prof *p, *prof = NULL; 400 + 401 + mutex_lock(&hw->fl_profs_locks[blk]); 402 + list_for_each_entry(p, &hw->fl_profs[blk], l_entry) 403 + if ((p->dir == dir || conds & ICE_FLOW_FIND_PROF_NOT_CHK_DIR) && 404 + segs_cnt && segs_cnt == p->segs_cnt) { 405 + u8 i; 406 + 407 + /* Check for profile-VSI association if specified */ 408 + if ((conds & ICE_FLOW_FIND_PROF_CHK_VSI) && 409 + ice_is_vsi_valid(hw, vsi_handle) && 410 + !test_bit(vsi_handle, p->vsis)) 411 + continue; 412 + 413 + /* Protocol headers must be checked. Matched fields are 414 + * checked if specified. 415 + */ 416 + for (i = 0; i < segs_cnt; i++) 417 + if (segs[i].hdrs != p->segs[i].hdrs || 418 + ((conds & ICE_FLOW_FIND_PROF_CHK_FLDS) && 419 + segs[i].match != p->segs[i].match)) 420 + break; 421 + 422 + /* A match is found if all segments are matched */ 423 + if (i == segs_cnt) { 424 + prof = p; 425 + break; 426 + } 427 + } 428 + mutex_unlock(&hw->fl_profs_locks[blk]); 429 + 430 + return prof; 431 + } 432 + 433 + /** 434 + * ice_flow_find_prof_id - Look up a profile with given profile ID 435 + * @hw: pointer to the HW struct 436 + * @blk: classification stage 437 + * @prof_id: unique ID to identify this flow profile 438 + */ 439 + static struct ice_flow_prof * 440 + ice_flow_find_prof_id(struct ice_hw *hw, enum ice_block blk, u64 prof_id) 441 + { 442 + struct ice_flow_prof *p; 443 + 444 + list_for_each_entry(p, &hw->fl_profs[blk], l_entry) 445 + if (p->id == prof_id) 446 + return p; 447 + 448 + return NULL; 449 + } 450 + 380 451 /** 381 452 * ice_flow_add_prof_sync - Add a flow profile for packet segments and fields 382 453 * @hw: pointer to the HW struct ··· 522 451 } 523 452 524 453 /** 454 + * ice_flow_rem_prof_sync - remove a flow profile 455 + * @hw: pointer to the hardware structure 456 + * @blk: classification stage 457 + * @prof: pointer to flow profile to remove 458 + * 459 + * Assumption: the caller has acquired the lock to the profile list 460 + */ 461 + static enum ice_status 462 + ice_flow_rem_prof_sync(struct ice_hw *hw, enum ice_block blk, 463 + struct ice_flow_prof *prof) 464 + { 465 + enum ice_status status; 466 + 467 + /* Remove all hardware profiles associated with this flow profile */ 468 + status = ice_rem_prof(hw, blk, prof->id); 469 + if (!status) { 470 + list_del(&prof->l_entry); 471 + mutex_destroy(&prof->entries_lock); 472 + devm_kfree(ice_hw_to_dev(hw), prof); 473 + } 474 + 475 + return status; 476 + } 477 + 478 + /** 525 479 * ice_flow_assoc_prof - associate a VSI with a flow profile 526 480 * @hw: pointer to the hardware structure 527 481 * @blk: classification stage ··· 572 476 else 573 477 ice_debug(hw, ICE_DBG_FLOW, 574 478 "HW profile add failed, %d\n", 479 + status); 480 + } 481 + 482 + return status; 483 + } 484 + 485 + /** 486 + * ice_flow_disassoc_prof - disassociate a VSI from a flow profile 487 + * @hw: pointer to the hardware structure 488 + * @blk: classification stage 489 + * @prof: pointer to flow profile 490 + * @vsi_handle: software VSI handle 491 + * 492 + * Assumption: the caller has acquired the lock to the profile list 493 + * and the software VSI handle has been validated 494 + */ 495 + static enum ice_status 496 + ice_flow_disassoc_prof(struct ice_hw *hw, enum ice_block blk, 497 + struct ice_flow_prof *prof, u16 vsi_handle) 498 + { 499 + enum ice_status status = 0; 500 + 501 + if (test_bit(vsi_handle, prof->vsis)) { 502 + status = ice_rem_prof_id_flow(hw, blk, 503 + ice_get_hw_vsi_num(hw, 504 + vsi_handle), 505 + prof->id); 506 + if (!status) 507 + clear_bit(vsi_handle, prof->vsis); 508 + else 509 + ice_debug(hw, ICE_DBG_FLOW, 510 + "HW profile remove failed, %d\n", 575 511 status); 576 512 } 577 513 ··· 647 519 if (!status) 648 520 list_add(&(*prof)->l_entry, &hw->fl_profs[blk]); 649 521 522 + mutex_unlock(&hw->fl_profs_locks[blk]); 523 + 524 + return status; 525 + } 526 + 527 + /** 528 + * ice_flow_rem_prof - Remove a flow profile and all entries associated with it 529 + * @hw: pointer to the HW struct 530 + * @blk: the block for which the flow profile is to be removed 531 + * @prof_id: unique ID of the flow profile to be removed 532 + */ 533 + static enum ice_status 534 + ice_flow_rem_prof(struct ice_hw *hw, enum ice_block blk, u64 prof_id) 535 + { 536 + struct ice_flow_prof *prof; 537 + enum ice_status status; 538 + 539 + mutex_lock(&hw->fl_profs_locks[blk]); 540 + 541 + prof = ice_flow_find_prof_id(hw, blk, prof_id); 542 + if (!prof) { 543 + status = ICE_ERR_DOES_NOT_EXIST; 544 + goto out; 545 + } 546 + 547 + /* prof becomes invalid after the call */ 548 + status = ice_flow_rem_prof_sync(hw, blk, prof); 549 + 550 + out: 650 551 mutex_unlock(&hw->fl_profs_locks[blk]); 651 552 652 553 return status; ··· 802 645 return 0; 803 646 } 804 647 648 + /** 649 + * ice_rem_vsi_rss_list - remove VSI from RSS list 650 + * @hw: pointer to the hardware structure 651 + * @vsi_handle: software VSI handle 652 + * 653 + * Remove the VSI from all RSS configurations in the list. 654 + */ 655 + void ice_rem_vsi_rss_list(struct ice_hw *hw, u16 vsi_handle) 656 + { 657 + struct ice_rss_cfg *r, *tmp; 658 + 659 + if (list_empty(&hw->rss_list_head)) 660 + return; 661 + 662 + mutex_lock(&hw->rss_locks); 663 + list_for_each_entry_safe(r, tmp, &hw->rss_list_head, l_entry) 664 + if (test_and_clear_bit(vsi_handle, r->vsis)) 665 + if (bitmap_empty(r->vsis, ICE_MAX_VSI)) { 666 + list_del(&r->l_entry); 667 + devm_kfree(ice_hw_to_dev(hw), r); 668 + } 669 + mutex_unlock(&hw->rss_locks); 670 + } 671 + 672 + /** 673 + * ice_rem_vsi_rss_cfg - remove RSS configurations associated with VSI 674 + * @hw: pointer to the hardware structure 675 + * @vsi_handle: software VSI handle 676 + * 677 + * This function will iterate through all flow profiles and disassociate 678 + * the VSI from that profile. If the flow profile has no VSIs it will 679 + * be removed. 680 + */ 681 + enum ice_status ice_rem_vsi_rss_cfg(struct ice_hw *hw, u16 vsi_handle) 682 + { 683 + const enum ice_block blk = ICE_BLK_RSS; 684 + struct ice_flow_prof *p, *t; 685 + enum ice_status status = 0; 686 + 687 + if (!ice_is_vsi_valid(hw, vsi_handle)) 688 + return ICE_ERR_PARAM; 689 + 690 + if (list_empty(&hw->fl_profs[blk])) 691 + return 0; 692 + 693 + mutex_lock(&hw->fl_profs_locks[blk]); 694 + list_for_each_entry_safe(p, t, &hw->fl_profs[blk], l_entry) 695 + if (test_bit(vsi_handle, p->vsis)) { 696 + status = ice_flow_disassoc_prof(hw, blk, p, vsi_handle); 697 + if (status) 698 + break; 699 + 700 + if (bitmap_empty(p->vsis, ICE_MAX_VSI)) { 701 + status = ice_flow_rem_prof_sync(hw, blk, p); 702 + if (status) 703 + break; 704 + } 705 + } 706 + mutex_unlock(&hw->fl_profs_locks[blk]); 707 + 708 + return status; 709 + } 710 + 711 + /** 712 + * ice_rem_rss_list - remove RSS configuration from list 713 + * @hw: pointer to the hardware structure 714 + * @vsi_handle: software VSI handle 715 + * @prof: pointer to flow profile 716 + * 717 + * Assumption: lock has already been acquired for RSS list 718 + */ 719 + static void 720 + ice_rem_rss_list(struct ice_hw *hw, u16 vsi_handle, struct ice_flow_prof *prof) 721 + { 722 + struct ice_rss_cfg *r, *tmp; 723 + 724 + /* Search for RSS hash fields associated to the VSI that match the 725 + * hash configurations associated to the flow profile. If found 726 + * remove from the RSS entry list of the VSI context and delete entry. 727 + */ 728 + list_for_each_entry_safe(r, tmp, &hw->rss_list_head, l_entry) 729 + if (r->hashed_flds == prof->segs[prof->segs_cnt - 1].match && 730 + r->packet_hdr == prof->segs[prof->segs_cnt - 1].hdrs) { 731 + clear_bit(vsi_handle, r->vsis); 732 + if (bitmap_empty(r->vsis, ICE_MAX_VSI)) { 733 + list_del(&r->l_entry); 734 + devm_kfree(ice_hw_to_dev(hw), r); 735 + } 736 + return; 737 + } 738 + } 739 + 740 + /** 741 + * ice_add_rss_list - add RSS configuration to list 742 + * @hw: pointer to the hardware structure 743 + * @vsi_handle: software VSI handle 744 + * @prof: pointer to flow profile 745 + * 746 + * Assumption: lock has already been acquired for RSS list 747 + */ 748 + static enum ice_status 749 + ice_add_rss_list(struct ice_hw *hw, u16 vsi_handle, struct ice_flow_prof *prof) 750 + { 751 + struct ice_rss_cfg *r, *rss_cfg; 752 + 753 + list_for_each_entry(r, &hw->rss_list_head, l_entry) 754 + if (r->hashed_flds == prof->segs[prof->segs_cnt - 1].match && 755 + r->packet_hdr == prof->segs[prof->segs_cnt - 1].hdrs) { 756 + set_bit(vsi_handle, r->vsis); 757 + return 0; 758 + } 759 + 760 + rss_cfg = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*rss_cfg), 761 + GFP_KERNEL); 762 + if (!rss_cfg) 763 + return ICE_ERR_NO_MEMORY; 764 + 765 + rss_cfg->hashed_flds = prof->segs[prof->segs_cnt - 1].match; 766 + rss_cfg->packet_hdr = prof->segs[prof->segs_cnt - 1].hdrs; 767 + set_bit(vsi_handle, rss_cfg->vsis); 768 + 769 + list_add_tail(&rss_cfg->l_entry, &hw->rss_list_head); 770 + 771 + return 0; 772 + } 773 + 805 774 #define ICE_FLOW_PROF_HASH_S 0 806 775 #define ICE_FLOW_PROF_HASH_M (0xFFFFFFFFULL << ICE_FLOW_PROF_HASH_S) 807 776 #define ICE_FLOW_PROF_HDR_S 32 ··· 979 696 if (status) 980 697 goto exit; 981 698 699 + /* Search for a flow profile that has matching headers, hash fields 700 + * and has the input VSI associated to it. If found, no further 701 + * operations required and exit. 702 + */ 703 + prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, segs_cnt, 704 + vsi_handle, 705 + ICE_FLOW_FIND_PROF_CHK_FLDS | 706 + ICE_FLOW_FIND_PROF_CHK_VSI); 707 + if (prof) 708 + goto exit; 709 + 710 + /* Check if a flow profile exists with the same protocol headers and 711 + * associated with the input VSI. If so disassociate the VSI from 712 + * this profile. The VSI will be added to a new profile created with 713 + * the protocol header and new hash field configuration. 714 + */ 715 + prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, segs_cnt, 716 + vsi_handle, ICE_FLOW_FIND_PROF_CHK_VSI); 717 + if (prof) { 718 + status = ice_flow_disassoc_prof(hw, blk, prof, vsi_handle); 719 + if (!status) 720 + ice_rem_rss_list(hw, vsi_handle, prof); 721 + else 722 + goto exit; 723 + 724 + /* Remove profile if it has no VSIs associated */ 725 + if (bitmap_empty(prof->vsis, ICE_MAX_VSI)) { 726 + status = ice_flow_rem_prof(hw, blk, prof->id); 727 + if (status) 728 + goto exit; 729 + } 730 + } 731 + 732 + /* Search for a profile that has same match fields only. If this 733 + * exists then associate the VSI to this profile. 734 + */ 735 + prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, segs_cnt, 736 + vsi_handle, 737 + ICE_FLOW_FIND_PROF_CHK_FLDS); 738 + if (prof) { 739 + status = ice_flow_assoc_prof(hw, blk, prof, vsi_handle); 740 + if (!status) 741 + status = ice_add_rss_list(hw, vsi_handle, prof); 742 + goto exit; 743 + } 744 + 982 745 /* Create a new flow profile with generated profile and packet 983 746 * segment information. 984 747 */ ··· 1037 708 goto exit; 1038 709 1039 710 status = ice_flow_assoc_prof(hw, blk, prof, vsi_handle); 711 + /* If association to a new flow profile failed then this profile can 712 + * be removed. 713 + */ 714 + if (status) { 715 + ice_flow_rem_prof(hw, blk, prof->id); 716 + goto exit; 717 + } 718 + 719 + status = ice_add_rss_list(hw, vsi_handle, prof); 1040 720 1041 721 exit: 1042 722 kfree(segs);
+10
drivers/net/ethernet/intel/ice/ice_flow.h
··· 4 4 #ifndef _ICE_FLOW_H_ 5 5 #define _ICE_FLOW_H_ 6 6 7 + #define ICE_FLOW_ENTRY_HANDLE_INVAL 0 7 8 #define ICE_FLOW_FLD_OFF_INVAL 0xffff 8 9 9 10 /* Generate flow hash field from flow field type(s) */ ··· 59 58 60 59 enum ice_flow_dir { 61 60 ICE_FLOW_RX = 0x02, 61 + }; 62 + 63 + enum ice_flow_priority { 64 + ICE_FLOW_PRIO_LOW, 65 + ICE_FLOW_PRIO_NORMAL, 66 + ICE_FLOW_PRIO_HIGH 62 67 }; 63 68 64 69 #define ICE_FLOW_SEG_MAX 2 ··· 137 130 u32 packet_hdr; 138 131 }; 139 132 133 + enum ice_status ice_flow_rem_entry(struct ice_hw *hw, u64 entry_h); 134 + void ice_rem_vsi_rss_list(struct ice_hw *hw, u16 vsi_handle); 140 135 enum ice_status ice_replay_rss_cfg(struct ice_hw *hw, u16 vsi_handle); 136 + enum ice_status ice_rem_vsi_rss_cfg(struct ice_hw *hw, u16 vsi_handle); 141 137 enum ice_status 142 138 ice_add_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds, 143 139 u32 addl_hdrs);
+27 -1
drivers/net/ethernet/intel/ice/ice_lib.c
··· 494 494 } 495 495 496 496 /** 497 - * ice_rss_clean - Delete RSS related VSI structures that hold user inputs 497 + * ice_vsi_clean_rss_flow_fld - Delete RSS configuration 498 + * @vsi: the VSI being cleaned up 499 + * 500 + * This function deletes RSS input set for all flows that were configured 501 + * for this VSI 502 + */ 503 + static void ice_vsi_clean_rss_flow_fld(struct ice_vsi *vsi) 504 + { 505 + struct ice_pf *pf = vsi->back; 506 + enum ice_status status; 507 + 508 + if (ice_is_safe_mode(pf)) 509 + return; 510 + 511 + status = ice_rem_vsi_rss_cfg(&pf->hw, vsi->idx); 512 + if (status) 513 + dev_dbg(ice_pf_to_dev(pf), "ice_rem_vsi_rss_cfg failed for vsi = %d, error = %d\n", 514 + vsi->vsi_num, status); 515 + } 516 + 517 + /** 518 + * ice_rss_clean - Delete RSS related VSI structures and configuration 498 519 * @vsi: the VSI being removed 499 520 */ 500 521 static void ice_rss_clean(struct ice_vsi *vsi) ··· 529 508 devm_kfree(dev, vsi->rss_hkey_user); 530 509 if (vsi->rss_lut_user) 531 510 devm_kfree(dev, vsi->rss_lut_user); 511 + 512 + ice_vsi_clean_rss_flow_fld(vsi); 513 + /* remove RSS replay list */ 514 + if (!ice_is_safe_mode(pf)) 515 + ice_rem_vsi_rss_list(&pf->hw, vsi->idx); 532 516 } 533 517 534 518 /**