18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (C) 2018-2020, Intel Corporation. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include "ice.h" 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci/** 78c2ecf20Sopenharmony_ci * ice_is_arfs_active - helper to check is aRFS is active 88c2ecf20Sopenharmony_ci * @vsi: VSI to check 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_cistatic bool ice_is_arfs_active(struct ice_vsi *vsi) 118c2ecf20Sopenharmony_ci{ 128c2ecf20Sopenharmony_ci return !!vsi->arfs_fltr_list; 138c2ecf20Sopenharmony_ci} 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/** 168c2ecf20Sopenharmony_ci * ice_is_arfs_using_perfect_flow - check if aRFS has active perfect filters 178c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 188c2ecf20Sopenharmony_ci * @flow_type: flow type as Flow Director understands it 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * Flow Director will query this function to see if aRFS is currently using 218c2ecf20Sopenharmony_ci * the specified flow_type for perfect (4-tuple) filters. 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_cibool 248c2ecf20Sopenharmony_ciice_is_arfs_using_perfect_flow(struct ice_hw *hw, enum ice_fltr_ptype flow_type) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci struct ice_arfs_active_fltr_cntrs *arfs_fltr_cntrs; 278c2ecf20Sopenharmony_ci struct ice_pf *pf = hw->back; 288c2ecf20Sopenharmony_ci struct ice_vsi *vsi; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci vsi = ice_get_main_vsi(pf); 318c2ecf20Sopenharmony_ci if (!vsi) 328c2ecf20Sopenharmony_ci return false; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci arfs_fltr_cntrs = vsi->arfs_fltr_cntrs; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci /* active counters can be updated by multiple CPUs */ 378c2ecf20Sopenharmony_ci smp_mb__before_atomic(); 388c2ecf20Sopenharmony_ci switch (flow_type) { 398c2ecf20Sopenharmony_ci case ICE_FLTR_PTYPE_NONF_IPV4_UDP: 408c2ecf20Sopenharmony_ci return atomic_read(&arfs_fltr_cntrs->active_udpv4_cnt) > 0; 418c2ecf20Sopenharmony_ci case ICE_FLTR_PTYPE_NONF_IPV6_UDP: 428c2ecf20Sopenharmony_ci return atomic_read(&arfs_fltr_cntrs->active_udpv6_cnt) > 0; 438c2ecf20Sopenharmony_ci case ICE_FLTR_PTYPE_NONF_IPV4_TCP: 448c2ecf20Sopenharmony_ci return atomic_read(&arfs_fltr_cntrs->active_tcpv4_cnt) > 0; 458c2ecf20Sopenharmony_ci case ICE_FLTR_PTYPE_NONF_IPV6_TCP: 468c2ecf20Sopenharmony_ci return atomic_read(&arfs_fltr_cntrs->active_tcpv6_cnt) > 0; 478c2ecf20Sopenharmony_ci default: 488c2ecf20Sopenharmony_ci return false; 498c2ecf20Sopenharmony_ci } 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/** 538c2ecf20Sopenharmony_ci * ice_arfs_update_active_fltr_cntrs - update active filter counters for aRFS 548c2ecf20Sopenharmony_ci * @vsi: VSI that aRFS is active on 558c2ecf20Sopenharmony_ci * @entry: aRFS entry used to change counters 568c2ecf20Sopenharmony_ci * @add: true to increment counter, false to decrement 578c2ecf20Sopenharmony_ci */ 588c2ecf20Sopenharmony_cistatic void 598c2ecf20Sopenharmony_ciice_arfs_update_active_fltr_cntrs(struct ice_vsi *vsi, 608c2ecf20Sopenharmony_ci struct ice_arfs_entry *entry, bool add) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci struct ice_arfs_active_fltr_cntrs *fltr_cntrs = vsi->arfs_fltr_cntrs; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci switch (entry->fltr_info.flow_type) { 658c2ecf20Sopenharmony_ci case ICE_FLTR_PTYPE_NONF_IPV4_TCP: 668c2ecf20Sopenharmony_ci if (add) 678c2ecf20Sopenharmony_ci atomic_inc(&fltr_cntrs->active_tcpv4_cnt); 688c2ecf20Sopenharmony_ci else 698c2ecf20Sopenharmony_ci atomic_dec(&fltr_cntrs->active_tcpv4_cnt); 708c2ecf20Sopenharmony_ci break; 718c2ecf20Sopenharmony_ci case ICE_FLTR_PTYPE_NONF_IPV6_TCP: 728c2ecf20Sopenharmony_ci if (add) 738c2ecf20Sopenharmony_ci atomic_inc(&fltr_cntrs->active_tcpv6_cnt); 748c2ecf20Sopenharmony_ci else 758c2ecf20Sopenharmony_ci atomic_dec(&fltr_cntrs->active_tcpv6_cnt); 768c2ecf20Sopenharmony_ci break; 778c2ecf20Sopenharmony_ci case ICE_FLTR_PTYPE_NONF_IPV4_UDP: 788c2ecf20Sopenharmony_ci if (add) 798c2ecf20Sopenharmony_ci atomic_inc(&fltr_cntrs->active_udpv4_cnt); 808c2ecf20Sopenharmony_ci else 818c2ecf20Sopenharmony_ci atomic_dec(&fltr_cntrs->active_udpv4_cnt); 828c2ecf20Sopenharmony_ci break; 838c2ecf20Sopenharmony_ci case ICE_FLTR_PTYPE_NONF_IPV6_UDP: 848c2ecf20Sopenharmony_ci if (add) 858c2ecf20Sopenharmony_ci atomic_inc(&fltr_cntrs->active_udpv6_cnt); 868c2ecf20Sopenharmony_ci else 878c2ecf20Sopenharmony_ci atomic_dec(&fltr_cntrs->active_udpv6_cnt); 888c2ecf20Sopenharmony_ci break; 898c2ecf20Sopenharmony_ci default: 908c2ecf20Sopenharmony_ci dev_err(ice_pf_to_dev(vsi->back), "aRFS: Failed to update filter counters, invalid filter type %d\n", 918c2ecf20Sopenharmony_ci entry->fltr_info.flow_type); 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci/** 968c2ecf20Sopenharmony_ci * ice_arfs_del_flow_rules - delete the rules passed in from HW 978c2ecf20Sopenharmony_ci * @vsi: VSI for the flow rules that need to be deleted 988c2ecf20Sopenharmony_ci * @del_list_head: head of the list of ice_arfs_entry(s) for rule deletion 998c2ecf20Sopenharmony_ci * 1008c2ecf20Sopenharmony_ci * Loop through the delete list passed in and remove the rules from HW. After 1018c2ecf20Sopenharmony_ci * each rule is deleted, disconnect and free the ice_arfs_entry because it is no 1028c2ecf20Sopenharmony_ci * longer being referenced by the aRFS hash table. 1038c2ecf20Sopenharmony_ci */ 1048c2ecf20Sopenharmony_cistatic void 1058c2ecf20Sopenharmony_ciice_arfs_del_flow_rules(struct ice_vsi *vsi, struct hlist_head *del_list_head) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct ice_arfs_entry *e; 1088c2ecf20Sopenharmony_ci struct hlist_node *n; 1098c2ecf20Sopenharmony_ci struct device *dev; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(vsi->back); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci hlist_for_each_entry_safe(e, n, del_list_head, list_entry) { 1148c2ecf20Sopenharmony_ci int result; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci result = ice_fdir_write_fltr(vsi->back, &e->fltr_info, false, 1178c2ecf20Sopenharmony_ci false); 1188c2ecf20Sopenharmony_ci if (!result) 1198c2ecf20Sopenharmony_ci ice_arfs_update_active_fltr_cntrs(vsi, e, false); 1208c2ecf20Sopenharmony_ci else 1218c2ecf20Sopenharmony_ci dev_dbg(dev, "Unable to delete aRFS entry, err %d fltr_state %d fltr_id %d flow_id %d Q %d\n", 1228c2ecf20Sopenharmony_ci result, e->fltr_state, e->fltr_info.fltr_id, 1238c2ecf20Sopenharmony_ci e->flow_id, e->fltr_info.q_index); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci /* The aRFS hash table is no longer referencing this entry */ 1268c2ecf20Sopenharmony_ci hlist_del(&e->list_entry); 1278c2ecf20Sopenharmony_ci devm_kfree(dev, e); 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci/** 1328c2ecf20Sopenharmony_ci * ice_arfs_add_flow_rules - add the rules passed in from HW 1338c2ecf20Sopenharmony_ci * @vsi: VSI for the flow rules that need to be added 1348c2ecf20Sopenharmony_ci * @add_list_head: head of the list of ice_arfs_entry_ptr(s) for rule addition 1358c2ecf20Sopenharmony_ci * 1368c2ecf20Sopenharmony_ci * Loop through the add list passed in and remove the rules from HW. After each 1378c2ecf20Sopenharmony_ci * rule is added, disconnect and free the ice_arfs_entry_ptr node. Don't free 1388c2ecf20Sopenharmony_ci * the ice_arfs_entry(s) because they are still being referenced in the aRFS 1398c2ecf20Sopenharmony_ci * hash table. 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_cistatic void 1428c2ecf20Sopenharmony_ciice_arfs_add_flow_rules(struct ice_vsi *vsi, struct hlist_head *add_list_head) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci struct ice_arfs_entry_ptr *ep; 1458c2ecf20Sopenharmony_ci struct hlist_node *n; 1468c2ecf20Sopenharmony_ci struct device *dev; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(vsi->back); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci hlist_for_each_entry_safe(ep, n, add_list_head, list_entry) { 1518c2ecf20Sopenharmony_ci int result; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci result = ice_fdir_write_fltr(vsi->back, 1548c2ecf20Sopenharmony_ci &ep->arfs_entry->fltr_info, true, 1558c2ecf20Sopenharmony_ci false); 1568c2ecf20Sopenharmony_ci if (!result) 1578c2ecf20Sopenharmony_ci ice_arfs_update_active_fltr_cntrs(vsi, ep->arfs_entry, 1588c2ecf20Sopenharmony_ci true); 1598c2ecf20Sopenharmony_ci else 1608c2ecf20Sopenharmony_ci dev_dbg(dev, "Unable to add aRFS entry, err %d fltr_state %d fltr_id %d flow_id %d Q %d\n", 1618c2ecf20Sopenharmony_ci result, ep->arfs_entry->fltr_state, 1628c2ecf20Sopenharmony_ci ep->arfs_entry->fltr_info.fltr_id, 1638c2ecf20Sopenharmony_ci ep->arfs_entry->flow_id, 1648c2ecf20Sopenharmony_ci ep->arfs_entry->fltr_info.q_index); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci hlist_del(&ep->list_entry); 1678c2ecf20Sopenharmony_ci devm_kfree(dev, ep); 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci/** 1728c2ecf20Sopenharmony_ci * ice_arfs_is_flow_expired - check if the aRFS entry has expired 1738c2ecf20Sopenharmony_ci * @vsi: VSI containing the aRFS entry 1748c2ecf20Sopenharmony_ci * @arfs_entry: aRFS entry that's being checked for expiration 1758c2ecf20Sopenharmony_ci * 1768c2ecf20Sopenharmony_ci * Return true if the flow has expired, else false. This function should be used 1778c2ecf20Sopenharmony_ci * to determine whether or not an aRFS entry should be removed from the hardware 1788c2ecf20Sopenharmony_ci * and software structures. 1798c2ecf20Sopenharmony_ci */ 1808c2ecf20Sopenharmony_cistatic bool 1818c2ecf20Sopenharmony_ciice_arfs_is_flow_expired(struct ice_vsi *vsi, struct ice_arfs_entry *arfs_entry) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci#define ICE_ARFS_TIME_DELTA_EXPIRATION msecs_to_jiffies(5000) 1848c2ecf20Sopenharmony_ci if (rps_may_expire_flow(vsi->netdev, arfs_entry->fltr_info.q_index, 1858c2ecf20Sopenharmony_ci arfs_entry->flow_id, 1868c2ecf20Sopenharmony_ci arfs_entry->fltr_info.fltr_id)) 1878c2ecf20Sopenharmony_ci return true; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci /* expiration timer only used for UDP filters */ 1908c2ecf20Sopenharmony_ci if (arfs_entry->fltr_info.flow_type != ICE_FLTR_PTYPE_NONF_IPV4_UDP && 1918c2ecf20Sopenharmony_ci arfs_entry->fltr_info.flow_type != ICE_FLTR_PTYPE_NONF_IPV6_UDP) 1928c2ecf20Sopenharmony_ci return false; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci return time_in_range64(arfs_entry->time_activated + 1958c2ecf20Sopenharmony_ci ICE_ARFS_TIME_DELTA_EXPIRATION, 1968c2ecf20Sopenharmony_ci arfs_entry->time_activated, get_jiffies_64()); 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci/** 2008c2ecf20Sopenharmony_ci * ice_arfs_update_flow_rules - add/delete aRFS rules in HW 2018c2ecf20Sopenharmony_ci * @vsi: the VSI to be forwarded to 2028c2ecf20Sopenharmony_ci * @idx: index into the table of aRFS filter lists. Obtained from skb->hash 2038c2ecf20Sopenharmony_ci * @add_list: list to populate with filters to be added to Flow Director 2048c2ecf20Sopenharmony_ci * @del_list: list to populate with filters to be deleted from Flow Director 2058c2ecf20Sopenharmony_ci * 2068c2ecf20Sopenharmony_ci * Iterate over the hlist at the index given in the aRFS hash table and 2078c2ecf20Sopenharmony_ci * determine if there are any aRFS entries that need to be either added or 2088c2ecf20Sopenharmony_ci * deleted in the HW. If the aRFS entry is marked as ICE_ARFS_INACTIVE the 2098c2ecf20Sopenharmony_ci * filter needs to be added to HW, else if it's marked as ICE_ARFS_ACTIVE and 2108c2ecf20Sopenharmony_ci * the flow has expired delete the filter from HW. The caller of this function 2118c2ecf20Sopenharmony_ci * is expected to add/delete rules on the add_list/del_list respectively. 2128c2ecf20Sopenharmony_ci */ 2138c2ecf20Sopenharmony_cistatic void 2148c2ecf20Sopenharmony_ciice_arfs_update_flow_rules(struct ice_vsi *vsi, u16 idx, 2158c2ecf20Sopenharmony_ci struct hlist_head *add_list, 2168c2ecf20Sopenharmony_ci struct hlist_head *del_list) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci struct ice_arfs_entry *e; 2198c2ecf20Sopenharmony_ci struct hlist_node *n; 2208c2ecf20Sopenharmony_ci struct device *dev; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(vsi->back); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci /* go through the aRFS hlist at this idx and check for needed updates */ 2258c2ecf20Sopenharmony_ci hlist_for_each_entry_safe(e, n, &vsi->arfs_fltr_list[idx], list_entry) 2268c2ecf20Sopenharmony_ci /* check if filter needs to be added to HW */ 2278c2ecf20Sopenharmony_ci if (e->fltr_state == ICE_ARFS_INACTIVE) { 2288c2ecf20Sopenharmony_ci enum ice_fltr_ptype flow_type = e->fltr_info.flow_type; 2298c2ecf20Sopenharmony_ci struct ice_arfs_entry_ptr *ep = 2308c2ecf20Sopenharmony_ci devm_kzalloc(dev, sizeof(*ep), GFP_ATOMIC); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci if (!ep) 2338c2ecf20Sopenharmony_ci continue; 2348c2ecf20Sopenharmony_ci INIT_HLIST_NODE(&ep->list_entry); 2358c2ecf20Sopenharmony_ci /* reference aRFS entry to add HW filter */ 2368c2ecf20Sopenharmony_ci ep->arfs_entry = e; 2378c2ecf20Sopenharmony_ci hlist_add_head(&ep->list_entry, add_list); 2388c2ecf20Sopenharmony_ci e->fltr_state = ICE_ARFS_ACTIVE; 2398c2ecf20Sopenharmony_ci /* expiration timer only used for UDP flows */ 2408c2ecf20Sopenharmony_ci if (flow_type == ICE_FLTR_PTYPE_NONF_IPV4_UDP || 2418c2ecf20Sopenharmony_ci flow_type == ICE_FLTR_PTYPE_NONF_IPV6_UDP) 2428c2ecf20Sopenharmony_ci e->time_activated = get_jiffies_64(); 2438c2ecf20Sopenharmony_ci } else if (e->fltr_state == ICE_ARFS_ACTIVE) { 2448c2ecf20Sopenharmony_ci /* check if filter needs to be removed from HW */ 2458c2ecf20Sopenharmony_ci if (ice_arfs_is_flow_expired(vsi, e)) { 2468c2ecf20Sopenharmony_ci /* remove aRFS entry from hash table for delete 2478c2ecf20Sopenharmony_ci * and to prevent referencing it the next time 2488c2ecf20Sopenharmony_ci * through this hlist index 2498c2ecf20Sopenharmony_ci */ 2508c2ecf20Sopenharmony_ci hlist_del(&e->list_entry); 2518c2ecf20Sopenharmony_ci e->fltr_state = ICE_ARFS_TODEL; 2528c2ecf20Sopenharmony_ci /* save reference to aRFS entry for delete */ 2538c2ecf20Sopenharmony_ci hlist_add_head(&e->list_entry, del_list); 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci/** 2598c2ecf20Sopenharmony_ci * ice_sync_arfs_fltrs - update all aRFS filters 2608c2ecf20Sopenharmony_ci * @pf: board private structure 2618c2ecf20Sopenharmony_ci */ 2628c2ecf20Sopenharmony_civoid ice_sync_arfs_fltrs(struct ice_pf *pf) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci HLIST_HEAD(tmp_del_list); 2658c2ecf20Sopenharmony_ci HLIST_HEAD(tmp_add_list); 2668c2ecf20Sopenharmony_ci struct ice_vsi *pf_vsi; 2678c2ecf20Sopenharmony_ci unsigned int i; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci pf_vsi = ice_get_main_vsi(pf); 2708c2ecf20Sopenharmony_ci if (!pf_vsi) 2718c2ecf20Sopenharmony_ci return; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (!ice_is_arfs_active(pf_vsi)) 2748c2ecf20Sopenharmony_ci return; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci spin_lock_bh(&pf_vsi->arfs_lock); 2778c2ecf20Sopenharmony_ci /* Once we process aRFS for the PF VSI get out */ 2788c2ecf20Sopenharmony_ci for (i = 0; i < ICE_MAX_ARFS_LIST; i++) 2798c2ecf20Sopenharmony_ci ice_arfs_update_flow_rules(pf_vsi, i, &tmp_add_list, 2808c2ecf20Sopenharmony_ci &tmp_del_list); 2818c2ecf20Sopenharmony_ci spin_unlock_bh(&pf_vsi->arfs_lock); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* use list of ice_arfs_entry(s) for delete */ 2848c2ecf20Sopenharmony_ci ice_arfs_del_flow_rules(pf_vsi, &tmp_del_list); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci /* use list of ice_arfs_entry_ptr(s) for add */ 2878c2ecf20Sopenharmony_ci ice_arfs_add_flow_rules(pf_vsi, &tmp_add_list); 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci/** 2918c2ecf20Sopenharmony_ci * ice_arfs_build_entry - builds an aRFS entry based on input 2928c2ecf20Sopenharmony_ci * @vsi: destination VSI for this flow 2938c2ecf20Sopenharmony_ci * @fk: flow dissector keys for creating the tuple 2948c2ecf20Sopenharmony_ci * @rxq_idx: Rx queue to steer this flow to 2958c2ecf20Sopenharmony_ci * @flow_id: passed down from the stack and saved for flow expiration 2968c2ecf20Sopenharmony_ci * 2978c2ecf20Sopenharmony_ci * returns an aRFS entry on success and NULL on failure 2988c2ecf20Sopenharmony_ci */ 2998c2ecf20Sopenharmony_cistatic struct ice_arfs_entry * 3008c2ecf20Sopenharmony_ciice_arfs_build_entry(struct ice_vsi *vsi, const struct flow_keys *fk, 3018c2ecf20Sopenharmony_ci u16 rxq_idx, u32 flow_id) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci struct ice_arfs_entry *arfs_entry; 3048c2ecf20Sopenharmony_ci struct ice_fdir_fltr *fltr_info; 3058c2ecf20Sopenharmony_ci u8 ip_proto; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci arfs_entry = devm_kzalloc(ice_pf_to_dev(vsi->back), 3088c2ecf20Sopenharmony_ci sizeof(*arfs_entry), 3098c2ecf20Sopenharmony_ci GFP_ATOMIC | __GFP_NOWARN); 3108c2ecf20Sopenharmony_ci if (!arfs_entry) 3118c2ecf20Sopenharmony_ci return NULL; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci fltr_info = &arfs_entry->fltr_info; 3148c2ecf20Sopenharmony_ci fltr_info->q_index = rxq_idx; 3158c2ecf20Sopenharmony_ci fltr_info->dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_QINDEX; 3168c2ecf20Sopenharmony_ci fltr_info->dest_vsi = vsi->idx; 3178c2ecf20Sopenharmony_ci ip_proto = fk->basic.ip_proto; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if (fk->basic.n_proto == htons(ETH_P_IP)) { 3208c2ecf20Sopenharmony_ci fltr_info->ip.v4.proto = ip_proto; 3218c2ecf20Sopenharmony_ci fltr_info->flow_type = (ip_proto == IPPROTO_TCP) ? 3228c2ecf20Sopenharmony_ci ICE_FLTR_PTYPE_NONF_IPV4_TCP : 3238c2ecf20Sopenharmony_ci ICE_FLTR_PTYPE_NONF_IPV4_UDP; 3248c2ecf20Sopenharmony_ci fltr_info->ip.v4.src_ip = fk->addrs.v4addrs.src; 3258c2ecf20Sopenharmony_ci fltr_info->ip.v4.dst_ip = fk->addrs.v4addrs.dst; 3268c2ecf20Sopenharmony_ci fltr_info->ip.v4.src_port = fk->ports.src; 3278c2ecf20Sopenharmony_ci fltr_info->ip.v4.dst_port = fk->ports.dst; 3288c2ecf20Sopenharmony_ci } else { /* ETH_P_IPV6 */ 3298c2ecf20Sopenharmony_ci fltr_info->ip.v6.proto = ip_proto; 3308c2ecf20Sopenharmony_ci fltr_info->flow_type = (ip_proto == IPPROTO_TCP) ? 3318c2ecf20Sopenharmony_ci ICE_FLTR_PTYPE_NONF_IPV6_TCP : 3328c2ecf20Sopenharmony_ci ICE_FLTR_PTYPE_NONF_IPV6_UDP; 3338c2ecf20Sopenharmony_ci memcpy(&fltr_info->ip.v6.src_ip, &fk->addrs.v6addrs.src, 3348c2ecf20Sopenharmony_ci sizeof(struct in6_addr)); 3358c2ecf20Sopenharmony_ci memcpy(&fltr_info->ip.v6.dst_ip, &fk->addrs.v6addrs.dst, 3368c2ecf20Sopenharmony_ci sizeof(struct in6_addr)); 3378c2ecf20Sopenharmony_ci fltr_info->ip.v6.src_port = fk->ports.src; 3388c2ecf20Sopenharmony_ci fltr_info->ip.v6.dst_port = fk->ports.dst; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci arfs_entry->flow_id = flow_id; 3428c2ecf20Sopenharmony_ci fltr_info->fltr_id = 3438c2ecf20Sopenharmony_ci atomic_inc_return(vsi->arfs_last_fltr_id) % RPS_NO_FILTER; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci return arfs_entry; 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci/** 3498c2ecf20Sopenharmony_ci * ice_arfs_is_perfect_flow_set - Check to see if perfect flow is set 3508c2ecf20Sopenharmony_ci * @hw: pointer to HW structure 3518c2ecf20Sopenharmony_ci * @l3_proto: ETH_P_IP or ETH_P_IPV6 in network order 3528c2ecf20Sopenharmony_ci * @l4_proto: IPPROTO_UDP or IPPROTO_TCP 3538c2ecf20Sopenharmony_ci * 3548c2ecf20Sopenharmony_ci * We only support perfect (4-tuple) filters for aRFS. This function allows aRFS 3558c2ecf20Sopenharmony_ci * to check if perfect (4-tuple) flow rules are currently in place by Flow 3568c2ecf20Sopenharmony_ci * Director. 3578c2ecf20Sopenharmony_ci */ 3588c2ecf20Sopenharmony_cistatic bool 3598c2ecf20Sopenharmony_ciice_arfs_is_perfect_flow_set(struct ice_hw *hw, __be16 l3_proto, u8 l4_proto) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci unsigned long *perfect_fltr = hw->fdir_perfect_fltr; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci /* advanced Flow Director disabled, perfect filters always supported */ 3648c2ecf20Sopenharmony_ci if (!perfect_fltr) 3658c2ecf20Sopenharmony_ci return true; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci if (l3_proto == htons(ETH_P_IP) && l4_proto == IPPROTO_UDP) 3688c2ecf20Sopenharmony_ci return test_bit(ICE_FLTR_PTYPE_NONF_IPV4_UDP, perfect_fltr); 3698c2ecf20Sopenharmony_ci else if (l3_proto == htons(ETH_P_IP) && l4_proto == IPPROTO_TCP) 3708c2ecf20Sopenharmony_ci return test_bit(ICE_FLTR_PTYPE_NONF_IPV4_TCP, perfect_fltr); 3718c2ecf20Sopenharmony_ci else if (l3_proto == htons(ETH_P_IPV6) && l4_proto == IPPROTO_UDP) 3728c2ecf20Sopenharmony_ci return test_bit(ICE_FLTR_PTYPE_NONF_IPV6_UDP, perfect_fltr); 3738c2ecf20Sopenharmony_ci else if (l3_proto == htons(ETH_P_IPV6) && l4_proto == IPPROTO_TCP) 3748c2ecf20Sopenharmony_ci return test_bit(ICE_FLTR_PTYPE_NONF_IPV6_TCP, perfect_fltr); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci return false; 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci/** 3808c2ecf20Sopenharmony_ci * ice_rx_flow_steer - steer the Rx flow to where application is being run 3818c2ecf20Sopenharmony_ci * @netdev: ptr to the netdev being adjusted 3828c2ecf20Sopenharmony_ci * @skb: buffer with required header information 3838c2ecf20Sopenharmony_ci * @rxq_idx: queue to which the flow needs to move 3848c2ecf20Sopenharmony_ci * @flow_id: flow identifier provided by the netdev 3858c2ecf20Sopenharmony_ci * 3868c2ecf20Sopenharmony_ci * Based on the skb, rxq_idx, and flow_id passed in add/update an entry in the 3878c2ecf20Sopenharmony_ci * aRFS hash table. Iterate over one of the hlists in the aRFS hash table and 3888c2ecf20Sopenharmony_ci * if the flow_id already exists in the hash table but the rxq_idx has changed 3898c2ecf20Sopenharmony_ci * mark the entry as ICE_ARFS_INACTIVE so it can get updated in HW, else 3908c2ecf20Sopenharmony_ci * if the entry is marked as ICE_ARFS_TODEL delete it from the aRFS hash table. 3918c2ecf20Sopenharmony_ci * If neither of the previous conditions are true then add a new entry in the 3928c2ecf20Sopenharmony_ci * aRFS hash table, which gets set to ICE_ARFS_INACTIVE by default so it can be 3938c2ecf20Sopenharmony_ci * added to HW. 3948c2ecf20Sopenharmony_ci */ 3958c2ecf20Sopenharmony_ciint 3968c2ecf20Sopenharmony_ciice_rx_flow_steer(struct net_device *netdev, const struct sk_buff *skb, 3978c2ecf20Sopenharmony_ci u16 rxq_idx, u32 flow_id) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 4008c2ecf20Sopenharmony_ci struct ice_arfs_entry *arfs_entry; 4018c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 4028c2ecf20Sopenharmony_ci struct flow_keys fk; 4038c2ecf20Sopenharmony_ci struct ice_pf *pf; 4048c2ecf20Sopenharmony_ci __be16 n_proto; 4058c2ecf20Sopenharmony_ci u8 ip_proto; 4068c2ecf20Sopenharmony_ci u16 idx; 4078c2ecf20Sopenharmony_ci int ret; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci /* failed to allocate memory for aRFS so don't crash */ 4108c2ecf20Sopenharmony_ci if (unlikely(!vsi->arfs_fltr_list)) 4118c2ecf20Sopenharmony_ci return -ENODEV; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci pf = vsi->back; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci if (skb->encapsulation) 4168c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (!skb_flow_dissect_flow_keys(skb, &fk, 0)) 4198c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci n_proto = fk.basic.n_proto; 4228c2ecf20Sopenharmony_ci /* Support only IPV4 and IPV6 */ 4238c2ecf20Sopenharmony_ci if ((n_proto == htons(ETH_P_IP) && !ip_is_fragment(ip_hdr(skb))) || 4248c2ecf20Sopenharmony_ci n_proto == htons(ETH_P_IPV6)) 4258c2ecf20Sopenharmony_ci ip_proto = fk.basic.ip_proto; 4268c2ecf20Sopenharmony_ci else 4278c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci /* Support only TCP and UDP */ 4308c2ecf20Sopenharmony_ci if (ip_proto != IPPROTO_TCP && ip_proto != IPPROTO_UDP) 4318c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci /* only support 4-tuple filters for aRFS */ 4348c2ecf20Sopenharmony_ci if (!ice_arfs_is_perfect_flow_set(&pf->hw, n_proto, ip_proto)) 4358c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci /* choose the aRFS list bucket based on skb hash */ 4388c2ecf20Sopenharmony_ci idx = skb_get_hash_raw(skb) & ICE_ARFS_LST_MASK; 4398c2ecf20Sopenharmony_ci /* search for entry in the bucket */ 4408c2ecf20Sopenharmony_ci spin_lock_bh(&vsi->arfs_lock); 4418c2ecf20Sopenharmony_ci hlist_for_each_entry(arfs_entry, &vsi->arfs_fltr_list[idx], 4428c2ecf20Sopenharmony_ci list_entry) { 4438c2ecf20Sopenharmony_ci struct ice_fdir_fltr *fltr_info; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci /* keep searching for the already existing arfs_entry flow */ 4468c2ecf20Sopenharmony_ci if (arfs_entry->flow_id != flow_id) 4478c2ecf20Sopenharmony_ci continue; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci fltr_info = &arfs_entry->fltr_info; 4508c2ecf20Sopenharmony_ci ret = fltr_info->fltr_id; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (fltr_info->q_index == rxq_idx || 4538c2ecf20Sopenharmony_ci arfs_entry->fltr_state != ICE_ARFS_ACTIVE) 4548c2ecf20Sopenharmony_ci goto out; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci /* update the queue to forward to on an already existing flow */ 4578c2ecf20Sopenharmony_ci fltr_info->q_index = rxq_idx; 4588c2ecf20Sopenharmony_ci arfs_entry->fltr_state = ICE_ARFS_INACTIVE; 4598c2ecf20Sopenharmony_ci ice_arfs_update_active_fltr_cntrs(vsi, arfs_entry, false); 4608c2ecf20Sopenharmony_ci goto out_schedule_service_task; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci arfs_entry = ice_arfs_build_entry(vsi, &fk, rxq_idx, flow_id); 4648c2ecf20Sopenharmony_ci if (!arfs_entry) { 4658c2ecf20Sopenharmony_ci ret = -ENOMEM; 4668c2ecf20Sopenharmony_ci goto out; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci ret = arfs_entry->fltr_info.fltr_id; 4708c2ecf20Sopenharmony_ci INIT_HLIST_NODE(&arfs_entry->list_entry); 4718c2ecf20Sopenharmony_ci hlist_add_head(&arfs_entry->list_entry, &vsi->arfs_fltr_list[idx]); 4728c2ecf20Sopenharmony_ciout_schedule_service_task: 4738c2ecf20Sopenharmony_ci ice_service_task_schedule(pf); 4748c2ecf20Sopenharmony_ciout: 4758c2ecf20Sopenharmony_ci spin_unlock_bh(&vsi->arfs_lock); 4768c2ecf20Sopenharmony_ci return ret; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci/** 4808c2ecf20Sopenharmony_ci * ice_init_arfs_cntrs - initialize aRFS counter values 4818c2ecf20Sopenharmony_ci * @vsi: VSI that aRFS counters need to be initialized on 4828c2ecf20Sopenharmony_ci */ 4838c2ecf20Sopenharmony_cistatic int ice_init_arfs_cntrs(struct ice_vsi *vsi) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci if (!vsi || vsi->type != ICE_VSI_PF) 4868c2ecf20Sopenharmony_ci return -EINVAL; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci vsi->arfs_fltr_cntrs = kzalloc(sizeof(*vsi->arfs_fltr_cntrs), 4898c2ecf20Sopenharmony_ci GFP_KERNEL); 4908c2ecf20Sopenharmony_ci if (!vsi->arfs_fltr_cntrs) 4918c2ecf20Sopenharmony_ci return -ENOMEM; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci vsi->arfs_last_fltr_id = kzalloc(sizeof(*vsi->arfs_last_fltr_id), 4948c2ecf20Sopenharmony_ci GFP_KERNEL); 4958c2ecf20Sopenharmony_ci if (!vsi->arfs_last_fltr_id) { 4968c2ecf20Sopenharmony_ci kfree(vsi->arfs_fltr_cntrs); 4978c2ecf20Sopenharmony_ci vsi->arfs_fltr_cntrs = NULL; 4988c2ecf20Sopenharmony_ci return -ENOMEM; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci return 0; 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci/** 5058c2ecf20Sopenharmony_ci * ice_init_arfs - initialize aRFS resources 5068c2ecf20Sopenharmony_ci * @vsi: the VSI to be forwarded to 5078c2ecf20Sopenharmony_ci */ 5088c2ecf20Sopenharmony_civoid ice_init_arfs(struct ice_vsi *vsi) 5098c2ecf20Sopenharmony_ci{ 5108c2ecf20Sopenharmony_ci struct hlist_head *arfs_fltr_list; 5118c2ecf20Sopenharmony_ci unsigned int i; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci if (!vsi || vsi->type != ICE_VSI_PF) 5148c2ecf20Sopenharmony_ci return; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci arfs_fltr_list = kzalloc(sizeof(*arfs_fltr_list) * ICE_MAX_ARFS_LIST, 5178c2ecf20Sopenharmony_ci GFP_KERNEL); 5188c2ecf20Sopenharmony_ci if (!arfs_fltr_list) 5198c2ecf20Sopenharmony_ci return; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci if (ice_init_arfs_cntrs(vsi)) 5228c2ecf20Sopenharmony_ci goto free_arfs_fltr_list; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci for (i = 0; i < ICE_MAX_ARFS_LIST; i++) 5258c2ecf20Sopenharmony_ci INIT_HLIST_HEAD(&arfs_fltr_list[i]); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci spin_lock_init(&vsi->arfs_lock); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci vsi->arfs_fltr_list = arfs_fltr_list; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci return; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_cifree_arfs_fltr_list: 5348c2ecf20Sopenharmony_ci kfree(arfs_fltr_list); 5358c2ecf20Sopenharmony_ci} 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci/** 5388c2ecf20Sopenharmony_ci * ice_clear_arfs - clear the aRFS hash table and any memory used for aRFS 5398c2ecf20Sopenharmony_ci * @vsi: the VSI to be forwarded to 5408c2ecf20Sopenharmony_ci */ 5418c2ecf20Sopenharmony_civoid ice_clear_arfs(struct ice_vsi *vsi) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci struct device *dev; 5448c2ecf20Sopenharmony_ci unsigned int i; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci if (!vsi || vsi->type != ICE_VSI_PF || !vsi->back || 5478c2ecf20Sopenharmony_ci !vsi->arfs_fltr_list) 5488c2ecf20Sopenharmony_ci return; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(vsi->back); 5518c2ecf20Sopenharmony_ci for (i = 0; i < ICE_MAX_ARFS_LIST; i++) { 5528c2ecf20Sopenharmony_ci struct ice_arfs_entry *r; 5538c2ecf20Sopenharmony_ci struct hlist_node *n; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci spin_lock_bh(&vsi->arfs_lock); 5568c2ecf20Sopenharmony_ci hlist_for_each_entry_safe(r, n, &vsi->arfs_fltr_list[i], 5578c2ecf20Sopenharmony_ci list_entry) { 5588c2ecf20Sopenharmony_ci hlist_del(&r->list_entry); 5598c2ecf20Sopenharmony_ci devm_kfree(dev, r); 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci spin_unlock_bh(&vsi->arfs_lock); 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci kfree(vsi->arfs_fltr_list); 5658c2ecf20Sopenharmony_ci vsi->arfs_fltr_list = NULL; 5668c2ecf20Sopenharmony_ci kfree(vsi->arfs_last_fltr_id); 5678c2ecf20Sopenharmony_ci vsi->arfs_last_fltr_id = NULL; 5688c2ecf20Sopenharmony_ci kfree(vsi->arfs_fltr_cntrs); 5698c2ecf20Sopenharmony_ci vsi->arfs_fltr_cntrs = NULL; 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci/** 5738c2ecf20Sopenharmony_ci * ice_free_cpu_rx_rmap - free setup CPU reverse map 5748c2ecf20Sopenharmony_ci * @vsi: the VSI to be forwarded to 5758c2ecf20Sopenharmony_ci */ 5768c2ecf20Sopenharmony_civoid ice_free_cpu_rx_rmap(struct ice_vsi *vsi) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci struct net_device *netdev; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci if (!vsi || vsi->type != ICE_VSI_PF || !vsi->arfs_fltr_list) 5818c2ecf20Sopenharmony_ci return; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci netdev = vsi->netdev; 5848c2ecf20Sopenharmony_ci if (!netdev || !netdev->rx_cpu_rmap || 5858c2ecf20Sopenharmony_ci netdev->reg_state != NETREG_REGISTERED) 5868c2ecf20Sopenharmony_ci return; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci free_irq_cpu_rmap(netdev->rx_cpu_rmap); 5898c2ecf20Sopenharmony_ci netdev->rx_cpu_rmap = NULL; 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci/** 5938c2ecf20Sopenharmony_ci * ice_set_cpu_rx_rmap - setup CPU reverse map for each queue 5948c2ecf20Sopenharmony_ci * @vsi: the VSI to be forwarded to 5958c2ecf20Sopenharmony_ci */ 5968c2ecf20Sopenharmony_ciint ice_set_cpu_rx_rmap(struct ice_vsi *vsi) 5978c2ecf20Sopenharmony_ci{ 5988c2ecf20Sopenharmony_ci struct net_device *netdev; 5998c2ecf20Sopenharmony_ci struct ice_pf *pf; 6008c2ecf20Sopenharmony_ci int base_idx, i; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci if (!vsi || vsi->type != ICE_VSI_PF) 6038c2ecf20Sopenharmony_ci return -EINVAL; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci pf = vsi->back; 6068c2ecf20Sopenharmony_ci netdev = vsi->netdev; 6078c2ecf20Sopenharmony_ci if (!pf || !netdev || !vsi->num_q_vectors || 6088c2ecf20Sopenharmony_ci vsi->netdev->reg_state != NETREG_REGISTERED) 6098c2ecf20Sopenharmony_ci return -EINVAL; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci netdev_dbg(netdev, "Setup CPU RMAP: vsi type 0x%x, ifname %s, q_vectors %d\n", 6128c2ecf20Sopenharmony_ci vsi->type, netdev->name, vsi->num_q_vectors); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci netdev->rx_cpu_rmap = alloc_irq_cpu_rmap(vsi->num_q_vectors); 6158c2ecf20Sopenharmony_ci if (unlikely(!netdev->rx_cpu_rmap)) 6168c2ecf20Sopenharmony_ci return -EINVAL; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci base_idx = vsi->base_vector; 6198c2ecf20Sopenharmony_ci for (i = 0; i < vsi->num_q_vectors; i++) 6208c2ecf20Sopenharmony_ci if (irq_cpu_rmap_add(netdev->rx_cpu_rmap, 6218c2ecf20Sopenharmony_ci pf->msix_entries[base_idx + i].vector)) { 6228c2ecf20Sopenharmony_ci ice_free_cpu_rx_rmap(vsi); 6238c2ecf20Sopenharmony_ci return -EINVAL; 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci return 0; 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci/** 6308c2ecf20Sopenharmony_ci * ice_remove_arfs - remove/clear all aRFS resources 6318c2ecf20Sopenharmony_ci * @pf: device private structure 6328c2ecf20Sopenharmony_ci */ 6338c2ecf20Sopenharmony_civoid ice_remove_arfs(struct ice_pf *pf) 6348c2ecf20Sopenharmony_ci{ 6358c2ecf20Sopenharmony_ci struct ice_vsi *pf_vsi; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci pf_vsi = ice_get_main_vsi(pf); 6388c2ecf20Sopenharmony_ci if (!pf_vsi) 6398c2ecf20Sopenharmony_ci return; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci ice_free_cpu_rx_rmap(pf_vsi); 6428c2ecf20Sopenharmony_ci ice_clear_arfs(pf_vsi); 6438c2ecf20Sopenharmony_ci} 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci/** 6468c2ecf20Sopenharmony_ci * ice_rebuild_arfs - remove/clear all aRFS resources and rebuild after reset 6478c2ecf20Sopenharmony_ci * @pf: device private structure 6488c2ecf20Sopenharmony_ci */ 6498c2ecf20Sopenharmony_civoid ice_rebuild_arfs(struct ice_pf *pf) 6508c2ecf20Sopenharmony_ci{ 6518c2ecf20Sopenharmony_ci struct ice_vsi *pf_vsi; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci pf_vsi = ice_get_main_vsi(pf); 6548c2ecf20Sopenharmony_ci if (!pf_vsi) 6558c2ecf20Sopenharmony_ci return; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci ice_remove_arfs(pf); 6588c2ecf20Sopenharmony_ci if (ice_set_cpu_rx_rmap(pf_vsi)) { 6598c2ecf20Sopenharmony_ci dev_err(ice_pf_to_dev(pf), "Failed to rebuild aRFS\n"); 6608c2ecf20Sopenharmony_ci return; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci ice_init_arfs(pf_vsi); 6638c2ecf20Sopenharmony_ci} 664