2084 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (C) 2018-2023, Intel Corporation. */3 4/* flow director ethtool support for ice */5 6#include "ice.h"7#include "ice_lib.h"8#include "ice_fdir.h"9#include "ice_flow.h"10 11static struct in6_addr full_ipv6_addr_mask = {12 .in6_u = {13 .u6_addr8 = {14 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,15 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,16 }17 }18};19 20static struct in6_addr zero_ipv6_addr_mask = {21 .in6_u = {22 .u6_addr8 = {23 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,24 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,25 }26 }27};28 29/* calls to ice_flow_add_prof require the number of segments in the array30 * for segs_cnt. In this code that is one more than the index.31 */32#define TNL_SEG_CNT(_TNL_) ((_TNL_) + 1)33 34/**35 * ice_fltr_to_ethtool_flow - convert filter type values to ethtool36 * flow type values37 * @flow: filter type to be converted38 *39 * Returns the corresponding ethtool flow type.40 */41static int ice_fltr_to_ethtool_flow(enum ice_fltr_ptype flow)42{43 switch (flow) {44 case ICE_FLTR_PTYPE_NONF_ETH:45 return ETHER_FLOW;46 case ICE_FLTR_PTYPE_NONF_IPV4_TCP:47 return TCP_V4_FLOW;48 case ICE_FLTR_PTYPE_NONF_IPV4_UDP:49 return UDP_V4_FLOW;50 case ICE_FLTR_PTYPE_NONF_IPV4_SCTP:51 return SCTP_V4_FLOW;52 case ICE_FLTR_PTYPE_NONF_IPV4_OTHER:53 return IPV4_USER_FLOW;54 case ICE_FLTR_PTYPE_NONF_IPV6_TCP:55 return TCP_V6_FLOW;56 case ICE_FLTR_PTYPE_NONF_IPV6_UDP:57 return UDP_V6_FLOW;58 case ICE_FLTR_PTYPE_NONF_IPV6_SCTP:59 return SCTP_V6_FLOW;60 case ICE_FLTR_PTYPE_NONF_IPV6_OTHER:61 return IPV6_USER_FLOW;62 default:63 /* 0 is undefined ethtool flow */64 return 0;65 }66}67 68/**69 * ice_ethtool_flow_to_fltr - convert ethtool flow type to filter enum70 * @eth: Ethtool flow type to be converted71 *72 * Returns flow enum73 */74static enum ice_fltr_ptype ice_ethtool_flow_to_fltr(int eth)75{76 switch (eth) {77 case ETHER_FLOW:78 return ICE_FLTR_PTYPE_NONF_ETH;79 case TCP_V4_FLOW:80 return ICE_FLTR_PTYPE_NONF_IPV4_TCP;81 case UDP_V4_FLOW:82 return ICE_FLTR_PTYPE_NONF_IPV4_UDP;83 case SCTP_V4_FLOW:84 return ICE_FLTR_PTYPE_NONF_IPV4_SCTP;85 case IPV4_USER_FLOW:86 return ICE_FLTR_PTYPE_NONF_IPV4_OTHER;87 case TCP_V6_FLOW:88 return ICE_FLTR_PTYPE_NONF_IPV6_TCP;89 case UDP_V6_FLOW:90 return ICE_FLTR_PTYPE_NONF_IPV6_UDP;91 case SCTP_V6_FLOW:92 return ICE_FLTR_PTYPE_NONF_IPV6_SCTP;93 case IPV6_USER_FLOW:94 return ICE_FLTR_PTYPE_NONF_IPV6_OTHER;95 default:96 return ICE_FLTR_PTYPE_NONF_NONE;97 }98}99 100/**101 * ice_is_mask_valid - check mask field set102 * @mask: full mask to check103 * @field: field for which mask should be valid104 *105 * If the mask is fully set return true. If it is not valid for field return106 * false.107 */108static bool ice_is_mask_valid(u64 mask, u64 field)109{110 return (mask & field) == field;111}112 113/**114 * ice_get_ethtool_fdir_entry - fill ethtool structure with fdir filter data115 * @hw: hardware structure that contains filter list116 * @cmd: ethtool command data structure to receive the filter data117 *118 * Returns 0 on success and -EINVAL on failure119 */120int ice_get_ethtool_fdir_entry(struct ice_hw *hw, struct ethtool_rxnfc *cmd)121{122 struct ethtool_rx_flow_spec *fsp;123 struct ice_fdir_fltr *rule;124 int ret = 0;125 u16 idx;126 127 fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;128 129 mutex_lock(&hw->fdir_fltr_lock);130 131 rule = ice_fdir_find_fltr_by_idx(hw, fsp->location);132 133 if (!rule || fsp->location != rule->fltr_id) {134 ret = -EINVAL;135 goto release_lock;136 }137 138 fsp->flow_type = ice_fltr_to_ethtool_flow(rule->flow_type);139 140 memset(&fsp->m_u, 0, sizeof(fsp->m_u));141 memset(&fsp->m_ext, 0, sizeof(fsp->m_ext));142 143 switch (fsp->flow_type) {144 case ETHER_FLOW:145 fsp->h_u.ether_spec = rule->eth;146 fsp->m_u.ether_spec = rule->eth_mask;147 break;148 case IPV4_USER_FLOW:149 fsp->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4;150 fsp->h_u.usr_ip4_spec.proto = 0;151 fsp->h_u.usr_ip4_spec.l4_4_bytes = rule->ip.v4.l4_header;152 fsp->h_u.usr_ip4_spec.tos = rule->ip.v4.tos;153 fsp->h_u.usr_ip4_spec.ip4src = rule->ip.v4.src_ip;154 fsp->h_u.usr_ip4_spec.ip4dst = rule->ip.v4.dst_ip;155 fsp->m_u.usr_ip4_spec.ip4src = rule->mask.v4.src_ip;156 fsp->m_u.usr_ip4_spec.ip4dst = rule->mask.v4.dst_ip;157 fsp->m_u.usr_ip4_spec.ip_ver = 0xFF;158 fsp->m_u.usr_ip4_spec.proto = 0;159 fsp->m_u.usr_ip4_spec.l4_4_bytes = rule->mask.v4.l4_header;160 fsp->m_u.usr_ip4_spec.tos = rule->mask.v4.tos;161 break;162 case TCP_V4_FLOW:163 case UDP_V4_FLOW:164 case SCTP_V4_FLOW:165 fsp->h_u.tcp_ip4_spec.psrc = rule->ip.v4.src_port;166 fsp->h_u.tcp_ip4_spec.pdst = rule->ip.v4.dst_port;167 fsp->h_u.tcp_ip4_spec.ip4src = rule->ip.v4.src_ip;168 fsp->h_u.tcp_ip4_spec.ip4dst = rule->ip.v4.dst_ip;169 fsp->m_u.tcp_ip4_spec.psrc = rule->mask.v4.src_port;170 fsp->m_u.tcp_ip4_spec.pdst = rule->mask.v4.dst_port;171 fsp->m_u.tcp_ip4_spec.ip4src = rule->mask.v4.src_ip;172 fsp->m_u.tcp_ip4_spec.ip4dst = rule->mask.v4.dst_ip;173 break;174 case IPV6_USER_FLOW:175 fsp->h_u.usr_ip6_spec.l4_4_bytes = rule->ip.v6.l4_header;176 fsp->h_u.usr_ip6_spec.tclass = rule->ip.v6.tc;177 fsp->h_u.usr_ip6_spec.l4_proto = rule->ip.v6.proto;178 memcpy(fsp->h_u.tcp_ip6_spec.ip6src, rule->ip.v6.src_ip,179 sizeof(struct in6_addr));180 memcpy(fsp->h_u.tcp_ip6_spec.ip6dst, rule->ip.v6.dst_ip,181 sizeof(struct in6_addr));182 memcpy(fsp->m_u.tcp_ip6_spec.ip6src, rule->mask.v6.src_ip,183 sizeof(struct in6_addr));184 memcpy(fsp->m_u.tcp_ip6_spec.ip6dst, rule->mask.v6.dst_ip,185 sizeof(struct in6_addr));186 fsp->m_u.usr_ip6_spec.l4_4_bytes = rule->mask.v6.l4_header;187 fsp->m_u.usr_ip6_spec.tclass = rule->mask.v6.tc;188 fsp->m_u.usr_ip6_spec.l4_proto = rule->mask.v6.proto;189 break;190 case TCP_V6_FLOW:191 case UDP_V6_FLOW:192 case SCTP_V6_FLOW:193 memcpy(fsp->h_u.tcp_ip6_spec.ip6src, rule->ip.v6.src_ip,194 sizeof(struct in6_addr));195 memcpy(fsp->h_u.tcp_ip6_spec.ip6dst, rule->ip.v6.dst_ip,196 sizeof(struct in6_addr));197 fsp->h_u.tcp_ip6_spec.psrc = rule->ip.v6.src_port;198 fsp->h_u.tcp_ip6_spec.pdst = rule->ip.v6.dst_port;199 memcpy(fsp->m_u.tcp_ip6_spec.ip6src,200 rule->mask.v6.src_ip,201 sizeof(struct in6_addr));202 memcpy(fsp->m_u.tcp_ip6_spec.ip6dst,203 rule->mask.v6.dst_ip,204 sizeof(struct in6_addr));205 fsp->m_u.tcp_ip6_spec.psrc = rule->mask.v6.src_port;206 fsp->m_u.tcp_ip6_spec.pdst = rule->mask.v6.dst_port;207 fsp->h_u.tcp_ip6_spec.tclass = rule->ip.v6.tc;208 fsp->m_u.tcp_ip6_spec.tclass = rule->mask.v6.tc;209 break;210 default:211 break;212 }213 214 if (rule->dest_ctl == ICE_FLTR_PRGM_DESC_DEST_DROP_PKT)215 fsp->ring_cookie = RX_CLS_FLOW_DISC;216 else217 fsp->ring_cookie = rule->orig_q_index;218 219 idx = ice_ethtool_flow_to_fltr(fsp->flow_type);220 if (idx == ICE_FLTR_PTYPE_NONF_NONE) {221 dev_err(ice_hw_to_dev(hw), "Missing input index for flow_type %d\n",222 rule->flow_type);223 ret = -EINVAL;224 }225 226release_lock:227 mutex_unlock(&hw->fdir_fltr_lock);228 return ret;229}230 231/**232 * ice_get_fdir_fltr_ids - fill buffer with filter IDs of active filters233 * @hw: hardware structure containing the filter list234 * @cmd: ethtool command data structure235 * @rule_locs: ethtool array passed in from OS to receive filter IDs236 *237 * Returns 0 as expected for success by ethtool238 */239int240ice_get_fdir_fltr_ids(struct ice_hw *hw, struct ethtool_rxnfc *cmd,241 u32 *rule_locs)242{243 struct ice_fdir_fltr *f_rule;244 unsigned int cnt = 0;245 int val = 0;246 247 /* report total rule count */248 cmd->data = ice_get_fdir_cnt_all(hw);249 250 mutex_lock(&hw->fdir_fltr_lock);251 252 list_for_each_entry(f_rule, &hw->fdir_list_head, fltr_node) {253 if (cnt == cmd->rule_cnt) {254 val = -EMSGSIZE;255 goto release_lock;256 }257 rule_locs[cnt] = f_rule->fltr_id;258 cnt++;259 }260 261release_lock:262 mutex_unlock(&hw->fdir_fltr_lock);263 if (!val)264 cmd->rule_cnt = cnt;265 return val;266}267 268/**269 * ice_fdir_remap_entries - update the FDir entries in profile270 * @prof: FDir structure pointer271 * @tun: tunneled or non-tunneled packet272 * @idx: FDir entry index273 */274static void275ice_fdir_remap_entries(struct ice_fd_hw_prof *prof, int tun, int idx)276{277 if (idx != prof->cnt && tun < ICE_FD_HW_SEG_MAX) {278 int i;279 280 for (i = idx; i < (prof->cnt - 1); i++) {281 u64 old_entry_h;282 283 old_entry_h = prof->entry_h[i + 1][tun];284 prof->entry_h[i][tun] = old_entry_h;285 prof->vsi_h[i] = prof->vsi_h[i + 1];286 }287 288 prof->entry_h[i][tun] = 0;289 prof->vsi_h[i] = 0;290 }291}292 293/**294 * ice_fdir_rem_adq_chnl - remove an ADQ channel from HW filter rules295 * @hw: hardware structure containing filter list296 * @vsi_idx: VSI handle297 */298void ice_fdir_rem_adq_chnl(struct ice_hw *hw, u16 vsi_idx)299{300 int status, flow;301 302 if (!hw->fdir_prof)303 return;304 305 for (flow = 0; flow < ICE_FLTR_PTYPE_MAX; flow++) {306 struct ice_fd_hw_prof *prof = hw->fdir_prof[flow];307 int tun, i;308 309 if (!prof || !prof->cnt)310 continue;311 312 for (tun = 0; tun < ICE_FD_HW_SEG_MAX; tun++) {313 u64 prof_id = prof->prof_id[tun];314 315 for (i = 0; i < prof->cnt; i++) {316 if (prof->vsi_h[i] != vsi_idx)317 continue;318 319 prof->entry_h[i][tun] = 0;320 prof->vsi_h[i] = 0;321 break;322 }323 324 /* after clearing FDir entries update the remaining */325 ice_fdir_remap_entries(prof, tun, i);326 327 /* find flow profile corresponding to prof_id and clear328 * vsi_idx from bitmap.329 */330 status = ice_flow_rem_vsi_prof(hw, vsi_idx, prof_id);331 if (status) {332 dev_err(ice_hw_to_dev(hw), "ice_flow_rem_vsi_prof() failed status=%d\n",333 status);334 }335 }336 prof->cnt--;337 }338}339 340/**341 * ice_fdir_get_hw_prof - return the ice_fd_hw_proc associated with a flow342 * @hw: hardware structure containing the filter list343 * @blk: hardware block344 * @flow: FDir flow type to release345 */346static struct ice_fd_hw_prof *347ice_fdir_get_hw_prof(struct ice_hw *hw, enum ice_block blk, int flow)348{349 if (blk == ICE_BLK_FD && hw->fdir_prof)350 return hw->fdir_prof[flow];351 352 return NULL;353}354 355/**356 * ice_fdir_erase_flow_from_hw - remove a flow from the HW profile tables357 * @hw: hardware structure containing the filter list358 * @blk: hardware block359 * @flow: FDir flow type to release360 */361static void362ice_fdir_erase_flow_from_hw(struct ice_hw *hw, enum ice_block blk, int flow)363{364 struct ice_fd_hw_prof *prof = ice_fdir_get_hw_prof(hw, blk, flow);365 int tun;366 367 if (!prof)368 return;369 370 for (tun = 0; tun < ICE_FD_HW_SEG_MAX; tun++) {371 u64 prof_id = prof->prof_id[tun];372 int j;373 374 for (j = 0; j < prof->cnt; j++) {375 u16 vsi_num;376 377 if (!prof->entry_h[j][tun] || !prof->vsi_h[j])378 continue;379 vsi_num = ice_get_hw_vsi_num(hw, prof->vsi_h[j]);380 ice_rem_prof_id_flow(hw, blk, vsi_num, prof_id);381 ice_flow_rem_entry(hw, blk, prof->entry_h[j][tun]);382 prof->entry_h[j][tun] = 0;383 }384 ice_flow_rem_prof(hw, blk, prof_id);385 }386}387 388/**389 * ice_fdir_rem_flow - release the ice_flow structures for a filter type390 * @hw: hardware structure containing the filter list391 * @blk: hardware block392 * @flow_type: FDir flow type to release393 */394static void395ice_fdir_rem_flow(struct ice_hw *hw, enum ice_block blk,396 enum ice_fltr_ptype flow_type)397{398 int flow = (int)flow_type & ~FLOW_EXT;399 struct ice_fd_hw_prof *prof;400 int tun, i;401 402 prof = ice_fdir_get_hw_prof(hw, blk, flow);403 if (!prof)404 return;405 406 ice_fdir_erase_flow_from_hw(hw, blk, flow);407 for (i = 0; i < prof->cnt; i++)408 prof->vsi_h[i] = 0;409 for (tun = 0; tun < ICE_FD_HW_SEG_MAX; tun++) {410 if (!prof->fdir_seg[tun])411 continue;412 devm_kfree(ice_hw_to_dev(hw), prof->fdir_seg[tun]);413 prof->fdir_seg[tun] = NULL;414 }415 prof->cnt = 0;416}417 418/**419 * ice_fdir_release_flows - release all flows in use for later replay420 * @hw: pointer to HW instance421 */422void ice_fdir_release_flows(struct ice_hw *hw)423{424 int flow;425 426 /* release Flow Director HW table entries */427 for (flow = 0; flow < ICE_FLTR_PTYPE_MAX; flow++)428 ice_fdir_erase_flow_from_hw(hw, ICE_BLK_FD, flow);429}430 431/**432 * ice_fdir_replay_flows - replay HW Flow Director filter info433 * @hw: pointer to HW instance434 */435void ice_fdir_replay_flows(struct ice_hw *hw)436{437 int flow;438 439 for (flow = 0; flow < ICE_FLTR_PTYPE_MAX; flow++) {440 int tun;441 442 if (!hw->fdir_prof[flow] || !hw->fdir_prof[flow]->cnt)443 continue;444 for (tun = 0; tun < ICE_FD_HW_SEG_MAX; tun++) {445 struct ice_flow_prof *hw_prof;446 struct ice_fd_hw_prof *prof;447 int j;448 449 prof = hw->fdir_prof[flow];450 ice_flow_add_prof(hw, ICE_BLK_FD, ICE_FLOW_RX,451 prof->fdir_seg[tun], TNL_SEG_CNT(tun),452 false, &hw_prof);453 for (j = 0; j < prof->cnt; j++) {454 enum ice_flow_priority prio;455 u64 entry_h = 0;456 int err;457 458 prio = ICE_FLOW_PRIO_NORMAL;459 err = ice_flow_add_entry(hw, ICE_BLK_FD,460 hw_prof->id,461 prof->vsi_h[0],462 prof->vsi_h[j],463 prio, prof->fdir_seg,464 &entry_h);465 if (err) {466 dev_err(ice_hw_to_dev(hw), "Could not replay Flow Director, flow type %d\n",467 flow);468 continue;469 }470 prof->prof_id[tun] = hw_prof->id;471 prof->entry_h[j][tun] = entry_h;472 }473 }474 }475}476 477/**478 * ice_parse_rx_flow_user_data - deconstruct user-defined data479 * @fsp: pointer to ethtool Rx flow specification480 * @data: pointer to userdef data structure for storage481 *482 * Returns 0 on success, negative error value on failure483 */484static int485ice_parse_rx_flow_user_data(struct ethtool_rx_flow_spec *fsp,486 struct ice_rx_flow_userdef *data)487{488 u64 value, mask;489 490 memset(data, 0, sizeof(*data));491 if (!(fsp->flow_type & FLOW_EXT))492 return 0;493 494 value = be64_to_cpu(*((__force __be64 *)fsp->h_ext.data));495 mask = be64_to_cpu(*((__force __be64 *)fsp->m_ext.data));496 if (!mask)497 return 0;498 499#define ICE_USERDEF_FLEX_WORD_M GENMASK_ULL(15, 0)500#define ICE_USERDEF_FLEX_OFFS_S 16501#define ICE_USERDEF_FLEX_OFFS_M GENMASK_ULL(31, ICE_USERDEF_FLEX_OFFS_S)502#define ICE_USERDEF_FLEX_FLTR_M GENMASK_ULL(31, 0)503 504 /* 0x1fe is the maximum value for offsets stored in the internal505 * filtering tables.506 */507#define ICE_USERDEF_FLEX_MAX_OFFS_VAL 0x1fe508 509 if (!ice_is_mask_valid(mask, ICE_USERDEF_FLEX_FLTR_M) ||510 value > ICE_USERDEF_FLEX_FLTR_M)511 return -EINVAL;512 513 data->flex_word = value & ICE_USERDEF_FLEX_WORD_M;514 data->flex_offset = FIELD_GET(ICE_USERDEF_FLEX_OFFS_M, value);515 if (data->flex_offset > ICE_USERDEF_FLEX_MAX_OFFS_VAL)516 return -EINVAL;517 518 data->flex_fltr = true;519 520 return 0;521}522 523/**524 * ice_fdir_num_avail_fltr - return the number of unused flow director filters525 * @hw: pointer to hardware structure526 * @vsi: software VSI structure527 *528 * There are 2 filter pools: guaranteed and best effort(shared). Each VSI can529 * use filters from either pool. The guaranteed pool is divided between VSIs.530 * The best effort filter pool is common to all VSIs and is a device shared531 * resource pool. The number of filters available to this VSI is the sum of532 * the VSIs guaranteed filter pool and the global available best effort533 * filter pool.534 *535 * Returns the number of available flow director filters to this VSI536 */537int ice_fdir_num_avail_fltr(struct ice_hw *hw, struct ice_vsi *vsi)538{539 u16 vsi_num = ice_get_hw_vsi_num(hw, vsi->idx);540 u16 num_guar;541 u16 num_be;542 543 /* total guaranteed filters assigned to this VSI */544 num_guar = vsi->num_gfltr;545 546 /* total global best effort filters */547 num_be = hw->func_caps.fd_fltr_best_effort;548 549 /* Subtract the number of programmed filters from the global values */550 switch (hw->mac_type) {551 case ICE_MAC_E830:552 num_guar -= FIELD_GET(E830_VSIQF_FD_CNT_FD_GCNT_M,553 rd32(hw, VSIQF_FD_CNT(vsi_num)));554 num_be -= FIELD_GET(E830_GLQF_FD_CNT_FD_BCNT_M,555 rd32(hw, GLQF_FD_CNT));556 break;557 case ICE_MAC_E810:558 default:559 num_guar -= FIELD_GET(E800_VSIQF_FD_CNT_FD_GCNT_M,560 rd32(hw, VSIQF_FD_CNT(vsi_num)));561 num_be -= FIELD_GET(E800_GLQF_FD_CNT_FD_BCNT_M,562 rd32(hw, GLQF_FD_CNT));563 }564 565 return num_guar + num_be;566}567 568/**569 * ice_fdir_alloc_flow_prof - allocate FDir flow profile structure(s)570 * @hw: HW structure containing the FDir flow profile structure(s)571 * @flow: flow type to allocate the flow profile for572 *573 * Allocate the fdir_prof and fdir_prof[flow] if not already created. Return 0574 * on success and negative on error.575 */576static int577ice_fdir_alloc_flow_prof(struct ice_hw *hw, enum ice_fltr_ptype flow)578{579 if (!hw)580 return -EINVAL;581 582 if (!hw->fdir_prof) {583 hw->fdir_prof = devm_kcalloc(ice_hw_to_dev(hw),584 ICE_FLTR_PTYPE_MAX,585 sizeof(*hw->fdir_prof),586 GFP_KERNEL);587 if (!hw->fdir_prof)588 return -ENOMEM;589 }590 591 if (!hw->fdir_prof[flow]) {592 hw->fdir_prof[flow] = devm_kzalloc(ice_hw_to_dev(hw),593 sizeof(**hw->fdir_prof),594 GFP_KERNEL);595 if (!hw->fdir_prof[flow])596 return -ENOMEM;597 }598 599 return 0;600}601 602/**603 * ice_fdir_prof_vsi_idx - find or insert a vsi_idx in structure604 * @prof: pointer to flow director HW profile605 * @vsi_idx: vsi_idx to locate606 *607 * return the index of the vsi_idx. if vsi_idx is not found insert it608 * into the vsi_h table.609 */610static u16611ice_fdir_prof_vsi_idx(struct ice_fd_hw_prof *prof, int vsi_idx)612{613 u16 idx = 0;614 615 for (idx = 0; idx < prof->cnt; idx++)616 if (prof->vsi_h[idx] == vsi_idx)617 return idx;618 619 if (idx == prof->cnt)620 prof->vsi_h[prof->cnt++] = vsi_idx;621 return idx;622}623 624/**625 * ice_fdir_set_hw_fltr_rule - Configure HW tables to generate a FDir rule626 * @pf: pointer to the PF structure627 * @seg: protocol header description pointer628 * @flow: filter enum629 * @tun: FDir segment to program630 */631static int632ice_fdir_set_hw_fltr_rule(struct ice_pf *pf, struct ice_flow_seg_info *seg,633 enum ice_fltr_ptype flow, enum ice_fd_hw_seg tun)634{635 struct device *dev = ice_pf_to_dev(pf);636 struct ice_vsi *main_vsi, *ctrl_vsi;637 struct ice_flow_seg_info *old_seg;638 struct ice_flow_prof *prof = NULL;639 struct ice_fd_hw_prof *hw_prof;640 struct ice_hw *hw = &pf->hw;641 u64 entry1_h = 0;642 u64 entry2_h = 0;643 bool del_last;644 int err;645 int idx;646 647 main_vsi = ice_get_main_vsi(pf);648 if (!main_vsi)649 return -EINVAL;650 651 ctrl_vsi = ice_get_ctrl_vsi(pf);652 if (!ctrl_vsi)653 return -EINVAL;654 655 err = ice_fdir_alloc_flow_prof(hw, flow);656 if (err)657 return err;658 659 hw_prof = hw->fdir_prof[flow];660 old_seg = hw_prof->fdir_seg[tun];661 if (old_seg) {662 /* This flow_type already has a changed input set.663 * If it matches the requested input set then we are664 * done. Or, if it's different then it's an error.665 */666 if (!memcmp(old_seg, seg, sizeof(*seg)))667 return -EEXIST;668 669 /* if there are FDir filters using this flow,670 * then return error.671 */672 if (hw->fdir_fltr_cnt[flow]) {673 dev_err(dev, "Failed to add filter. Flow director filters on each port must have the same input set.\n");674 return -EINVAL;675 }676 677 if (ice_is_arfs_using_perfect_flow(hw, flow)) {678 dev_err(dev, "aRFS using perfect flow type %d, cannot change input set\n",679 flow);680 return -EINVAL;681 }682 683 /* remove HW filter definition */684 ice_fdir_rem_flow(hw, ICE_BLK_FD, flow);685 }686 687 /* Adding a profile, but there is only one header supported.688 * That is the final parameters are 1 header (segment), no689 * actions (NULL) and zero actions 0.690 */691 err = ice_flow_add_prof(hw, ICE_BLK_FD, ICE_FLOW_RX, seg,692 TNL_SEG_CNT(tun), false, &prof);693 if (err)694 return err;695 err = ice_flow_add_entry(hw, ICE_BLK_FD, prof->id, main_vsi->idx,696 main_vsi->idx, ICE_FLOW_PRIO_NORMAL,697 seg, &entry1_h);698 if (err)699 goto err_prof;700 err = ice_flow_add_entry(hw, ICE_BLK_FD, prof->id, main_vsi->idx,701 ctrl_vsi->idx, ICE_FLOW_PRIO_NORMAL,702 seg, &entry2_h);703 if (err)704 goto err_entry;705 706 hw_prof->fdir_seg[tun] = seg;707 hw_prof->prof_id[tun] = prof->id;708 hw_prof->entry_h[0][tun] = entry1_h;709 hw_prof->entry_h[1][tun] = entry2_h;710 hw_prof->vsi_h[0] = main_vsi->idx;711 hw_prof->vsi_h[1] = ctrl_vsi->idx;712 if (!hw_prof->cnt)713 hw_prof->cnt = 2;714 715 for (idx = 1; idx < ICE_CHNL_MAX_TC; idx++) {716 u16 vsi_idx;717 u16 vsi_h;718 719 if (!ice_is_adq_active(pf) || !main_vsi->tc_map_vsi[idx])720 continue;721 722 entry1_h = 0;723 vsi_h = main_vsi->tc_map_vsi[idx]->idx;724 err = ice_flow_add_entry(hw, ICE_BLK_FD, prof->id,725 main_vsi->idx, vsi_h,726 ICE_FLOW_PRIO_NORMAL, seg,727 &entry1_h);728 if (err) {729 dev_err(dev, "Could not add Channel VSI %d to flow group\n",730 idx);731 goto err_unroll;732 }733 734 vsi_idx = ice_fdir_prof_vsi_idx(hw_prof,735 main_vsi->tc_map_vsi[idx]->idx);736 hw_prof->entry_h[vsi_idx][tun] = entry1_h;737 }738 739 return 0;740 741err_unroll:742 entry1_h = 0;743 hw_prof->fdir_seg[tun] = NULL;744 745 /* The variable del_last will be used to determine when to clean up746 * the VSI group data. The VSI data is not needed if there are no747 * segments.748 */749 del_last = true;750 for (idx = 0; idx < ICE_FD_HW_SEG_MAX; idx++)751 if (hw_prof->fdir_seg[idx]) {752 del_last = false;753 break;754 }755 756 for (idx = 0; idx < hw_prof->cnt; idx++) {757 u16 vsi_num = ice_get_hw_vsi_num(hw, hw_prof->vsi_h[idx]);758 759 if (!hw_prof->entry_h[idx][tun])760 continue;761 ice_rem_prof_id_flow(hw, ICE_BLK_FD, vsi_num, prof->id);762 ice_flow_rem_entry(hw, ICE_BLK_FD, hw_prof->entry_h[idx][tun]);763 hw_prof->entry_h[idx][tun] = 0;764 if (del_last)765 hw_prof->vsi_h[idx] = 0;766 }767 if (del_last)768 hw_prof->cnt = 0;769err_entry:770 ice_rem_prof_id_flow(hw, ICE_BLK_FD,771 ice_get_hw_vsi_num(hw, main_vsi->idx), prof->id);772 ice_flow_rem_entry(hw, ICE_BLK_FD, entry1_h);773err_prof:774 ice_flow_rem_prof(hw, ICE_BLK_FD, prof->id);775 dev_err(dev, "Failed to add filter. Flow director filters on each port must have the same input set.\n");776 777 return err;778}779 780/**781 * ice_set_init_fdir_seg782 * @seg: flow segment for programming783 * @l3_proto: ICE_FLOW_SEG_HDR_IPV4 or ICE_FLOW_SEG_HDR_IPV6784 * @l4_proto: ICE_FLOW_SEG_HDR_TCP or ICE_FLOW_SEG_HDR_UDP785 *786 * Set the configuration for perfect filters to the provided flow segment for787 * programming the HW filter. This is to be called only when initializing788 * filters as this function it assumes no filters exist.789 */790static int791ice_set_init_fdir_seg(struct ice_flow_seg_info *seg,792 enum ice_flow_seg_hdr l3_proto,793 enum ice_flow_seg_hdr l4_proto)794{795 enum ice_flow_field src_addr, dst_addr, src_port, dst_port;796 797 if (!seg)798 return -EINVAL;799 800 if (l3_proto == ICE_FLOW_SEG_HDR_IPV4) {801 src_addr = ICE_FLOW_FIELD_IDX_IPV4_SA;802 dst_addr = ICE_FLOW_FIELD_IDX_IPV4_DA;803 } else if (l3_proto == ICE_FLOW_SEG_HDR_IPV6) {804 src_addr = ICE_FLOW_FIELD_IDX_IPV6_SA;805 dst_addr = ICE_FLOW_FIELD_IDX_IPV6_DA;806 } else {807 return -EINVAL;808 }809 810 if (l4_proto == ICE_FLOW_SEG_HDR_TCP) {811 src_port = ICE_FLOW_FIELD_IDX_TCP_SRC_PORT;812 dst_port = ICE_FLOW_FIELD_IDX_TCP_DST_PORT;813 } else if (l4_proto == ICE_FLOW_SEG_HDR_UDP) {814 src_port = ICE_FLOW_FIELD_IDX_UDP_SRC_PORT;815 dst_port = ICE_FLOW_FIELD_IDX_UDP_DST_PORT;816 } else {817 return -EINVAL;818 }819 820 ICE_FLOW_SET_HDRS(seg, l3_proto | l4_proto);821 822 /* IP source address */823 ice_flow_set_fld(seg, src_addr, ICE_FLOW_FLD_OFF_INVAL,824 ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL, false);825 826 /* IP destination address */827 ice_flow_set_fld(seg, dst_addr, ICE_FLOW_FLD_OFF_INVAL,828 ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL, false);829 830 /* Layer 4 source port */831 ice_flow_set_fld(seg, src_port, ICE_FLOW_FLD_OFF_INVAL,832 ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL, false);833 834 /* Layer 4 destination port */835 ice_flow_set_fld(seg, dst_port, ICE_FLOW_FLD_OFF_INVAL,836 ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL, false);837 838 return 0;839}840 841/**842 * ice_create_init_fdir_rule843 * @pf: PF structure844 * @flow: filter enum845 *846 * Return error value or 0 on success.847 */848static int849ice_create_init_fdir_rule(struct ice_pf *pf, enum ice_fltr_ptype flow)850{851 struct ice_flow_seg_info *seg, *tun_seg;852 struct device *dev = ice_pf_to_dev(pf);853 struct ice_hw *hw = &pf->hw;854 int ret;855 856 /* if there is already a filter rule for kind return -EINVAL */857 if (hw->fdir_prof && hw->fdir_prof[flow] &&858 hw->fdir_prof[flow]->fdir_seg[0])859 return -EINVAL;860 861 seg = devm_kzalloc(dev, sizeof(*seg), GFP_KERNEL);862 if (!seg)863 return -ENOMEM;864 865 tun_seg = devm_kcalloc(dev, ICE_FD_HW_SEG_MAX, sizeof(*tun_seg),866 GFP_KERNEL);867 if (!tun_seg) {868 devm_kfree(dev, seg);869 return -ENOMEM;870 }871 872 if (flow == ICE_FLTR_PTYPE_NONF_IPV4_TCP)873 ret = ice_set_init_fdir_seg(seg, ICE_FLOW_SEG_HDR_IPV4,874 ICE_FLOW_SEG_HDR_TCP);875 else if (flow == ICE_FLTR_PTYPE_NONF_IPV4_UDP)876 ret = ice_set_init_fdir_seg(seg, ICE_FLOW_SEG_HDR_IPV4,877 ICE_FLOW_SEG_HDR_UDP);878 else if (flow == ICE_FLTR_PTYPE_NONF_IPV6_TCP)879 ret = ice_set_init_fdir_seg(seg, ICE_FLOW_SEG_HDR_IPV6,880 ICE_FLOW_SEG_HDR_TCP);881 else if (flow == ICE_FLTR_PTYPE_NONF_IPV6_UDP)882 ret = ice_set_init_fdir_seg(seg, ICE_FLOW_SEG_HDR_IPV6,883 ICE_FLOW_SEG_HDR_UDP);884 else885 ret = -EINVAL;886 if (ret)887 goto err_exit;888 889 /* add filter for outer headers */890 ret = ice_fdir_set_hw_fltr_rule(pf, seg, flow, ICE_FD_HW_SEG_NON_TUN);891 if (ret)892 /* could not write filter, free memory */893 goto err_exit;894 895 /* make tunneled filter HW entries if possible */896 memcpy(&tun_seg[1], seg, sizeof(*seg));897 ret = ice_fdir_set_hw_fltr_rule(pf, tun_seg, flow, ICE_FD_HW_SEG_TUN);898 if (ret)899 /* could not write tunnel filter, but outer header filter900 * exists901 */902 devm_kfree(dev, tun_seg);903 904 set_bit(flow, hw->fdir_perfect_fltr);905 return ret;906err_exit:907 devm_kfree(dev, tun_seg);908 devm_kfree(dev, seg);909 910 return -EOPNOTSUPP;911}912 913/**914 * ice_set_fdir_ip4_seg915 * @seg: flow segment for programming916 * @tcp_ip4_spec: mask data from ethtool917 * @l4_proto: Layer 4 protocol to program918 * @perfect_fltr: only valid on success; returns true if perfect filter,919 * false if not920 *921 * Set the mask data into the flow segment to be used to program HW922 * table based on provided L4 protocol for IPv4923 */924static int925ice_set_fdir_ip4_seg(struct ice_flow_seg_info *seg,926 struct ethtool_tcpip4_spec *tcp_ip4_spec,927 enum ice_flow_seg_hdr l4_proto, bool *perfect_fltr)928{929 enum ice_flow_field src_port, dst_port;930 931 /* make sure we don't have any empty rule */932 if (!tcp_ip4_spec->psrc && !tcp_ip4_spec->ip4src &&933 !tcp_ip4_spec->pdst && !tcp_ip4_spec->ip4dst)934 return -EINVAL;935 936 /* filtering on TOS not supported */937 if (tcp_ip4_spec->tos)938 return -EOPNOTSUPP;939 940 if (l4_proto == ICE_FLOW_SEG_HDR_TCP) {941 src_port = ICE_FLOW_FIELD_IDX_TCP_SRC_PORT;942 dst_port = ICE_FLOW_FIELD_IDX_TCP_DST_PORT;943 } else if (l4_proto == ICE_FLOW_SEG_HDR_UDP) {944 src_port = ICE_FLOW_FIELD_IDX_UDP_SRC_PORT;945 dst_port = ICE_FLOW_FIELD_IDX_UDP_DST_PORT;946 } else if (l4_proto == ICE_FLOW_SEG_HDR_SCTP) {947 src_port = ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT;948 dst_port = ICE_FLOW_FIELD_IDX_SCTP_DST_PORT;949 } else {950 return -EOPNOTSUPP;951 }952 953 *perfect_fltr = true;954 ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV4 | l4_proto);955 956 /* IP source address */957 if (tcp_ip4_spec->ip4src == htonl(0xFFFFFFFF))958 ice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_IPV4_SA,959 ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,960 ICE_FLOW_FLD_OFF_INVAL, false);961 else if (!tcp_ip4_spec->ip4src)962 *perfect_fltr = false;963 else964 return -EOPNOTSUPP;965 966 /* IP destination address */967 if (tcp_ip4_spec->ip4dst == htonl(0xFFFFFFFF))968 ice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_IPV4_DA,969 ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,970 ICE_FLOW_FLD_OFF_INVAL, false);971 else if (!tcp_ip4_spec->ip4dst)972 *perfect_fltr = false;973 else974 return -EOPNOTSUPP;975 976 /* Layer 4 source port */977 if (tcp_ip4_spec->psrc == htons(0xFFFF))978 ice_flow_set_fld(seg, src_port, ICE_FLOW_FLD_OFF_INVAL,979 ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,980 false);981 else if (!tcp_ip4_spec->psrc)982 *perfect_fltr = false;983 else984 return -EOPNOTSUPP;985 986 /* Layer 4 destination port */987 if (tcp_ip4_spec->pdst == htons(0xFFFF))988 ice_flow_set_fld(seg, dst_port, ICE_FLOW_FLD_OFF_INVAL,989 ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,990 false);991 else if (!tcp_ip4_spec->pdst)992 *perfect_fltr = false;993 else994 return -EOPNOTSUPP;995 996 return 0;997}998 999/**1000 * ice_set_fdir_ip4_usr_seg1001 * @seg: flow segment for programming1002 * @usr_ip4_spec: ethtool userdef packet offset1003 * @perfect_fltr: only valid on success; returns true if perfect filter,1004 * false if not1005 *1006 * Set the offset data into the flow segment to be used to program HW1007 * table for IPv41008 */1009static int1010ice_set_fdir_ip4_usr_seg(struct ice_flow_seg_info *seg,1011 struct ethtool_usrip4_spec *usr_ip4_spec,1012 bool *perfect_fltr)1013{1014 /* first 4 bytes of Layer 4 header */1015 if (usr_ip4_spec->l4_4_bytes)1016 return -EINVAL;1017 if (usr_ip4_spec->tos)1018 return -EINVAL;1019 if (usr_ip4_spec->ip_ver)1020 return -EINVAL;1021 /* Filtering on Layer 4 protocol not supported */1022 if (usr_ip4_spec->proto)1023 return -EOPNOTSUPP;1024 /* empty rules are not valid */1025 if (!usr_ip4_spec->ip4src && !usr_ip4_spec->ip4dst)1026 return -EINVAL;1027 1028 *perfect_fltr = true;1029 ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV4);1030 1031 /* IP source address */1032 if (usr_ip4_spec->ip4src == htonl(0xFFFFFFFF))1033 ice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_IPV4_SA,1034 ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,1035 ICE_FLOW_FLD_OFF_INVAL, false);1036 else if (!usr_ip4_spec->ip4src)1037 *perfect_fltr = false;1038 else1039 return -EOPNOTSUPP;1040 1041 /* IP destination address */1042 if (usr_ip4_spec->ip4dst == htonl(0xFFFFFFFF))1043 ice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_IPV4_DA,1044 ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,1045 ICE_FLOW_FLD_OFF_INVAL, false);1046 else if (!usr_ip4_spec->ip4dst)1047 *perfect_fltr = false;1048 else1049 return -EOPNOTSUPP;1050 1051 return 0;1052}1053 1054/**1055 * ice_set_fdir_ip6_seg1056 * @seg: flow segment for programming1057 * @tcp_ip6_spec: mask data from ethtool1058 * @l4_proto: Layer 4 protocol to program1059 * @perfect_fltr: only valid on success; returns true if perfect filter,1060 * false if not1061 *1062 * Set the mask data into the flow segment to be used to program HW1063 * table based on provided L4 protocol for IPv61064 */1065static int1066ice_set_fdir_ip6_seg(struct ice_flow_seg_info *seg,1067 struct ethtool_tcpip6_spec *tcp_ip6_spec,1068 enum ice_flow_seg_hdr l4_proto, bool *perfect_fltr)1069{1070 enum ice_flow_field src_port, dst_port;1071 1072 /* make sure we don't have any empty rule */1073 if (!memcmp(tcp_ip6_spec->ip6src, &zero_ipv6_addr_mask,1074 sizeof(struct in6_addr)) &&1075 !memcmp(tcp_ip6_spec->ip6dst, &zero_ipv6_addr_mask,1076 sizeof(struct in6_addr)) &&1077 !tcp_ip6_spec->psrc && !tcp_ip6_spec->pdst)1078 return -EINVAL;1079 1080 /* filtering on TC not supported */1081 if (tcp_ip6_spec->tclass)1082 return -EOPNOTSUPP;1083 1084 if (l4_proto == ICE_FLOW_SEG_HDR_TCP) {1085 src_port = ICE_FLOW_FIELD_IDX_TCP_SRC_PORT;1086 dst_port = ICE_FLOW_FIELD_IDX_TCP_DST_PORT;1087 } else if (l4_proto == ICE_FLOW_SEG_HDR_UDP) {1088 src_port = ICE_FLOW_FIELD_IDX_UDP_SRC_PORT;1089 dst_port = ICE_FLOW_FIELD_IDX_UDP_DST_PORT;1090 } else if (l4_proto == ICE_FLOW_SEG_HDR_SCTP) {1091 src_port = ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT;1092 dst_port = ICE_FLOW_FIELD_IDX_SCTP_DST_PORT;1093 } else {1094 return -EINVAL;1095 }1096 1097 *perfect_fltr = true;1098 ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV6 | l4_proto);1099 1100 if (!memcmp(tcp_ip6_spec->ip6src, &full_ipv6_addr_mask,1101 sizeof(struct in6_addr)))1102 ice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_IPV6_SA,1103 ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,1104 ICE_FLOW_FLD_OFF_INVAL, false);1105 else if (!memcmp(tcp_ip6_spec->ip6src, &zero_ipv6_addr_mask,1106 sizeof(struct in6_addr)))1107 *perfect_fltr = false;1108 else1109 return -EOPNOTSUPP;1110 1111 if (!memcmp(tcp_ip6_spec->ip6dst, &full_ipv6_addr_mask,1112 sizeof(struct in6_addr)))1113 ice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_IPV6_DA,1114 ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,1115 ICE_FLOW_FLD_OFF_INVAL, false);1116 else if (!memcmp(tcp_ip6_spec->ip6dst, &zero_ipv6_addr_mask,1117 sizeof(struct in6_addr)))1118 *perfect_fltr = false;1119 else1120 return -EOPNOTSUPP;1121 1122 /* Layer 4 source port */1123 if (tcp_ip6_spec->psrc == htons(0xFFFF))1124 ice_flow_set_fld(seg, src_port, ICE_FLOW_FLD_OFF_INVAL,1125 ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,1126 false);1127 else if (!tcp_ip6_spec->psrc)1128 *perfect_fltr = false;1129 else1130 return -EOPNOTSUPP;1131 1132 /* Layer 4 destination port */1133 if (tcp_ip6_spec->pdst == htons(0xFFFF))1134 ice_flow_set_fld(seg, dst_port, ICE_FLOW_FLD_OFF_INVAL,1135 ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,1136 false);1137 else if (!tcp_ip6_spec->pdst)1138 *perfect_fltr = false;1139 else1140 return -EOPNOTSUPP;1141 1142 return 0;1143}1144 1145/**1146 * ice_set_fdir_ip6_usr_seg1147 * @seg: flow segment for programming1148 * @usr_ip6_spec: ethtool userdef packet offset1149 * @perfect_fltr: only valid on success; returns true if perfect filter,1150 * false if not1151 *1152 * Set the offset data into the flow segment to be used to program HW1153 * table for IPv61154 */1155static int1156ice_set_fdir_ip6_usr_seg(struct ice_flow_seg_info *seg,1157 struct ethtool_usrip6_spec *usr_ip6_spec,1158 bool *perfect_fltr)1159{1160 /* filtering on Layer 4 bytes not supported */1161 if (usr_ip6_spec->l4_4_bytes)1162 return -EOPNOTSUPP;1163 /* filtering on TC not supported */1164 if (usr_ip6_spec->tclass)1165 return -EOPNOTSUPP;1166 /* filtering on Layer 4 protocol not supported */1167 if (usr_ip6_spec->l4_proto)1168 return -EOPNOTSUPP;1169 /* empty rules are not valid */1170 if (!memcmp(usr_ip6_spec->ip6src, &zero_ipv6_addr_mask,1171 sizeof(struct in6_addr)) &&1172 !memcmp(usr_ip6_spec->ip6dst, &zero_ipv6_addr_mask,1173 sizeof(struct in6_addr)))1174 return -EINVAL;1175 1176 *perfect_fltr = true;1177 ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV6);1178 1179 if (!memcmp(usr_ip6_spec->ip6src, &full_ipv6_addr_mask,1180 sizeof(struct in6_addr)))1181 ice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_IPV6_SA,1182 ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,1183 ICE_FLOW_FLD_OFF_INVAL, false);1184 else if (!memcmp(usr_ip6_spec->ip6src, &zero_ipv6_addr_mask,1185 sizeof(struct in6_addr)))1186 *perfect_fltr = false;1187 else1188 return -EOPNOTSUPP;1189 1190 if (!memcmp(usr_ip6_spec->ip6dst, &full_ipv6_addr_mask,1191 sizeof(struct in6_addr)))1192 ice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_IPV6_DA,1193 ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,1194 ICE_FLOW_FLD_OFF_INVAL, false);1195 else if (!memcmp(usr_ip6_spec->ip6dst, &zero_ipv6_addr_mask,1196 sizeof(struct in6_addr)))1197 *perfect_fltr = false;1198 else1199 return -EOPNOTSUPP;1200 1201 return 0;1202}1203 1204/**1205 * ice_fdir_vlan_valid - validate VLAN data for Flow Director rule1206 * @dev: network interface device structure1207 * @fsp: pointer to ethtool Rx flow specification1208 *1209 * Return: true if vlan data is valid, false otherwise1210 */1211static bool ice_fdir_vlan_valid(struct device *dev,1212 struct ethtool_rx_flow_spec *fsp)1213{1214 if (fsp->m_ext.vlan_etype && !eth_type_vlan(fsp->h_ext.vlan_etype))1215 return false;1216 1217 if (fsp->m_ext.vlan_tci && ntohs(fsp->h_ext.vlan_tci) >= VLAN_N_VID)1218 return false;1219 1220 /* proto and vlan must have vlan-etype defined */1221 if (fsp->m_u.ether_spec.h_proto && fsp->m_ext.vlan_tci &&1222 !fsp->m_ext.vlan_etype) {1223 dev_warn(dev, "Filter with proto and vlan require also vlan-etype");1224 return false;1225 }1226 1227 return true;1228}1229 1230/**1231 * ice_set_ether_flow_seg - set address and protocol segments for ether flow1232 * @dev: network interface device structure1233 * @seg: flow segment for programming1234 * @eth_spec: mask data from ethtool1235 *1236 * Return: 0 on success and errno in case of error.1237 */1238static int ice_set_ether_flow_seg(struct device *dev,1239 struct ice_flow_seg_info *seg,1240 struct ethhdr *eth_spec)1241{1242 ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_ETH);1243 1244 /* empty rules are not valid */1245 if (is_zero_ether_addr(eth_spec->h_source) &&1246 is_zero_ether_addr(eth_spec->h_dest) &&1247 !eth_spec->h_proto)1248 return -EINVAL;1249 1250 /* Ethertype */1251 if (eth_spec->h_proto == htons(0xFFFF)) {1252 ice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_ETH_TYPE,1253 ICE_FLOW_FLD_OFF_INVAL,1254 ICE_FLOW_FLD_OFF_INVAL,1255 ICE_FLOW_FLD_OFF_INVAL, false);1256 } else if (eth_spec->h_proto) {1257 dev_warn(dev, "Only 0x0000 or 0xffff proto mask is allowed for flow-type ether");1258 return -EOPNOTSUPP;1259 }1260 1261 /* Source MAC address */1262 if (is_broadcast_ether_addr(eth_spec->h_source))1263 ice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_ETH_SA,1264 ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,1265 ICE_FLOW_FLD_OFF_INVAL, false);1266 else if (!is_zero_ether_addr(eth_spec->h_source))1267 goto err_mask;1268 1269 /* Destination MAC address */1270 if (is_broadcast_ether_addr(eth_spec->h_dest))1271 ice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_ETH_DA,1272 ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,1273 ICE_FLOW_FLD_OFF_INVAL, false);1274 else if (!is_zero_ether_addr(eth_spec->h_dest))1275 goto err_mask;1276 1277 return 0;1278 1279err_mask:1280 dev_warn(dev, "Only 00:00:00:00:00:00 or ff:ff:ff:ff:ff:ff MAC address mask is allowed for flow-type ether");1281 return -EOPNOTSUPP;1282}1283 1284/**1285 * ice_set_fdir_vlan_seg - set vlan segments for ether flow1286 * @seg: flow segment for programming1287 * @ext_masks: masks for additional RX flow fields1288 *1289 * Return: 0 on success and errno in case of error.1290 */1291static int1292ice_set_fdir_vlan_seg(struct ice_flow_seg_info *seg,1293 struct ethtool_flow_ext *ext_masks)1294{1295 ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_VLAN);1296 1297 if (ext_masks->vlan_etype) {1298 if (ext_masks->vlan_etype != htons(0xFFFF))1299 return -EOPNOTSUPP;1300 1301 ice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_S_VLAN,1302 ICE_FLOW_FLD_OFF_INVAL,1303 ICE_FLOW_FLD_OFF_INVAL,1304 ICE_FLOW_FLD_OFF_INVAL, false);1305 }1306 1307 if (ext_masks->vlan_tci) {1308 if (ext_masks->vlan_tci != htons(0xFFFF))1309 return -EOPNOTSUPP;1310 1311 ice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_C_VLAN,1312 ICE_FLOW_FLD_OFF_INVAL,1313 ICE_FLOW_FLD_OFF_INVAL,1314 ICE_FLOW_FLD_OFF_INVAL, false);1315 }1316 1317 return 0;1318}1319 1320/**1321 * ice_cfg_fdir_xtrct_seq - Configure extraction sequence for the given filter1322 * @pf: PF structure1323 * @fsp: pointer to ethtool Rx flow specification1324 * @user: user defined data from flow specification1325 *1326 * Returns 0 on success.1327 */1328static int1329ice_cfg_fdir_xtrct_seq(struct ice_pf *pf, struct ethtool_rx_flow_spec *fsp,1330 struct ice_rx_flow_userdef *user)1331{1332 struct ice_flow_seg_info *seg, *tun_seg;1333 struct device *dev = ice_pf_to_dev(pf);1334 enum ice_fltr_ptype fltr_idx;1335 struct ice_hw *hw = &pf->hw;1336 bool perfect_filter = false;1337 int ret;1338 1339 seg = devm_kzalloc(dev, sizeof(*seg), GFP_KERNEL);1340 if (!seg)1341 return -ENOMEM;1342 1343 tun_seg = devm_kcalloc(dev, ICE_FD_HW_SEG_MAX, sizeof(*tun_seg),1344 GFP_KERNEL);1345 if (!tun_seg) {1346 devm_kfree(dev, seg);1347 return -ENOMEM;1348 }1349 1350 switch (fsp->flow_type & ~FLOW_EXT) {1351 case TCP_V4_FLOW:1352 ret = ice_set_fdir_ip4_seg(seg, &fsp->m_u.tcp_ip4_spec,1353 ICE_FLOW_SEG_HDR_TCP,1354 &perfect_filter);1355 break;1356 case UDP_V4_FLOW:1357 ret = ice_set_fdir_ip4_seg(seg, &fsp->m_u.tcp_ip4_spec,1358 ICE_FLOW_SEG_HDR_UDP,1359 &perfect_filter);1360 break;1361 case SCTP_V4_FLOW:1362 ret = ice_set_fdir_ip4_seg(seg, &fsp->m_u.tcp_ip4_spec,1363 ICE_FLOW_SEG_HDR_SCTP,1364 &perfect_filter);1365 break;1366 case IPV4_USER_FLOW:1367 ret = ice_set_fdir_ip4_usr_seg(seg, &fsp->m_u.usr_ip4_spec,1368 &perfect_filter);1369 break;1370 case TCP_V6_FLOW:1371 ret = ice_set_fdir_ip6_seg(seg, &fsp->m_u.tcp_ip6_spec,1372 ICE_FLOW_SEG_HDR_TCP,1373 &perfect_filter);1374 break;1375 case UDP_V6_FLOW:1376 ret = ice_set_fdir_ip6_seg(seg, &fsp->m_u.tcp_ip6_spec,1377 ICE_FLOW_SEG_HDR_UDP,1378 &perfect_filter);1379 break;1380 case SCTP_V6_FLOW:1381 ret = ice_set_fdir_ip6_seg(seg, &fsp->m_u.tcp_ip6_spec,1382 ICE_FLOW_SEG_HDR_SCTP,1383 &perfect_filter);1384 break;1385 case IPV6_USER_FLOW:1386 ret = ice_set_fdir_ip6_usr_seg(seg, &fsp->m_u.usr_ip6_spec,1387 &perfect_filter);1388 break;1389 case ETHER_FLOW:1390 ret = ice_set_ether_flow_seg(dev, seg, &fsp->m_u.ether_spec);1391 if (!ret && (fsp->m_ext.vlan_etype || fsp->m_ext.vlan_tci)) {1392 if (!ice_fdir_vlan_valid(dev, fsp)) {1393 ret = -EINVAL;1394 break;1395 }1396 ret = ice_set_fdir_vlan_seg(seg, &fsp->m_ext);1397 }1398 break;1399 default:1400 ret = -EINVAL;1401 }1402 if (ret)1403 goto err_exit;1404 1405 /* tunnel segments are shifted up one. */1406 memcpy(&tun_seg[1], seg, sizeof(*seg));1407 1408 if (user && user->flex_fltr) {1409 perfect_filter = false;1410 ice_flow_add_fld_raw(seg, user->flex_offset,1411 ICE_FLTR_PRGM_FLEX_WORD_SIZE,1412 ICE_FLOW_FLD_OFF_INVAL,1413 ICE_FLOW_FLD_OFF_INVAL);1414 ice_flow_add_fld_raw(&tun_seg[1], user->flex_offset,1415 ICE_FLTR_PRGM_FLEX_WORD_SIZE,1416 ICE_FLOW_FLD_OFF_INVAL,1417 ICE_FLOW_FLD_OFF_INVAL);1418 }1419 1420 fltr_idx = ice_ethtool_flow_to_fltr(fsp->flow_type & ~FLOW_EXT);1421 1422 assign_bit(fltr_idx, hw->fdir_perfect_fltr, perfect_filter);1423 1424 /* add filter for outer headers */1425 ret = ice_fdir_set_hw_fltr_rule(pf, seg, fltr_idx,1426 ICE_FD_HW_SEG_NON_TUN);1427 if (ret == -EEXIST) {1428 /* Rule already exists, free memory and count as success */1429 ret = 0;1430 goto err_exit;1431 } else if (ret) {1432 /* could not write filter, free memory */1433 goto err_exit;1434 }1435 1436 /* make tunneled filter HW entries if possible */1437 memcpy(&tun_seg[1], seg, sizeof(*seg));1438 ret = ice_fdir_set_hw_fltr_rule(pf, tun_seg, fltr_idx,1439 ICE_FD_HW_SEG_TUN);1440 if (ret == -EEXIST) {1441 /* Rule already exists, free memory and count as success */1442 devm_kfree(dev, tun_seg);1443 ret = 0;1444 } else if (ret) {1445 /* could not write tunnel filter, but outer filter exists */1446 devm_kfree(dev, tun_seg);1447 }1448 1449 return ret;1450 1451err_exit:1452 devm_kfree(dev, tun_seg);1453 devm_kfree(dev, seg);1454 1455 return ret;1456}1457 1458/**1459 * ice_update_per_q_fltr1460 * @vsi: ptr to VSI1461 * @q_index: queue index1462 * @inc: true to increment or false to decrement per queue filter count1463 *1464 * This function is used to keep track of per queue sideband filters1465 */1466static void ice_update_per_q_fltr(struct ice_vsi *vsi, u32 q_index, bool inc)1467{1468 struct ice_rx_ring *rx_ring;1469 1470 if (!vsi->num_rxq || q_index >= vsi->num_rxq)1471 return;1472 1473 rx_ring = vsi->rx_rings[q_index];1474 if (!rx_ring || !rx_ring->ch)1475 return;1476 1477 if (inc)1478 atomic_inc(&rx_ring->ch->num_sb_fltr);1479 else1480 atomic_dec_if_positive(&rx_ring->ch->num_sb_fltr);1481}1482 1483/**1484 * ice_fdir_write_fltr - send a flow director filter to the hardware1485 * @pf: PF data structure1486 * @input: filter structure1487 * @add: true adds filter and false removed filter1488 * @is_tun: true adds inner filter on tunnel and false outer headers1489 *1490 * returns 0 on success and negative value on error1491 */1492int1493ice_fdir_write_fltr(struct ice_pf *pf, struct ice_fdir_fltr *input, bool add,1494 bool is_tun)1495{1496 struct device *dev = ice_pf_to_dev(pf);1497 struct ice_hw *hw = &pf->hw;1498 struct ice_fltr_desc desc;1499 struct ice_vsi *ctrl_vsi;1500 u8 *pkt, *frag_pkt;1501 bool has_frag;1502 int err;1503 1504 ctrl_vsi = ice_get_ctrl_vsi(pf);1505 if (!ctrl_vsi)1506 return -EINVAL;1507 1508 pkt = devm_kzalloc(dev, ICE_FDIR_MAX_RAW_PKT_SIZE, GFP_KERNEL);1509 if (!pkt)1510 return -ENOMEM;1511 frag_pkt = devm_kzalloc(dev, ICE_FDIR_MAX_RAW_PKT_SIZE, GFP_KERNEL);1512 if (!frag_pkt) {1513 err = -ENOMEM;1514 goto err_free;1515 }1516 1517 ice_fdir_get_prgm_desc(hw, input, &desc, add);1518 err = ice_fdir_get_gen_prgm_pkt(hw, input, pkt, false, is_tun);1519 if (err)1520 goto err_free_all;1521 err = ice_prgm_fdir_fltr(ctrl_vsi, &desc, pkt);1522 if (err)1523 goto err_free_all;1524 1525 /* repeat for fragment packet */1526 has_frag = ice_fdir_has_frag(input->flow_type);1527 if (has_frag) {1528 /* does not return error */1529 ice_fdir_get_prgm_desc(hw, input, &desc, add);1530 err = ice_fdir_get_gen_prgm_pkt(hw, input, frag_pkt, true,1531 is_tun);1532 if (err)1533 goto err_frag;1534 err = ice_prgm_fdir_fltr(ctrl_vsi, &desc, frag_pkt);1535 if (err)1536 goto err_frag;1537 } else {1538 devm_kfree(dev, frag_pkt);1539 }1540 1541 return 0;1542 1543err_free_all:1544 devm_kfree(dev, frag_pkt);1545err_free:1546 devm_kfree(dev, pkt);1547 return err;1548 1549err_frag:1550 devm_kfree(dev, frag_pkt);1551 return err;1552}1553 1554/**1555 * ice_fdir_write_all_fltr - send a flow director filter to the hardware1556 * @pf: PF data structure1557 * @input: filter structure1558 * @add: true adds filter and false removed filter1559 *1560 * returns 0 on success and negative value on error1561 */1562static int1563ice_fdir_write_all_fltr(struct ice_pf *pf, struct ice_fdir_fltr *input,1564 bool add)1565{1566 u16 port_num;1567 int tun;1568 1569 for (tun = 0; tun < ICE_FD_HW_SEG_MAX; tun++) {1570 bool is_tun = tun == ICE_FD_HW_SEG_TUN;1571 int err;1572 1573 if (is_tun && !ice_get_open_tunnel_port(&pf->hw, &port_num, TNL_ALL))1574 continue;1575 err = ice_fdir_write_fltr(pf, input, add, is_tun);1576 if (err)1577 return err;1578 }1579 return 0;1580}1581 1582/**1583 * ice_fdir_replay_fltrs - replay filters from the HW filter list1584 * @pf: board private structure1585 */1586void ice_fdir_replay_fltrs(struct ice_pf *pf)1587{1588 struct ice_fdir_fltr *f_rule;1589 struct ice_hw *hw = &pf->hw;1590 1591 list_for_each_entry(f_rule, &hw->fdir_list_head, fltr_node) {1592 int err = ice_fdir_write_all_fltr(pf, f_rule, true);1593 1594 if (err)1595 dev_dbg(ice_pf_to_dev(pf), "Flow Director error %d, could not reprogram filter %d\n",1596 err, f_rule->fltr_id);1597 }1598}1599 1600/**1601 * ice_fdir_create_dflt_rules - create default perfect filters1602 * @pf: PF data structure1603 *1604 * Returns 0 for success or error.1605 */1606int ice_fdir_create_dflt_rules(struct ice_pf *pf)1607{1608 int err;1609 1610 /* Create perfect TCP and UDP rules in hardware. */1611 err = ice_create_init_fdir_rule(pf, ICE_FLTR_PTYPE_NONF_IPV4_TCP);1612 if (err)1613 return err;1614 1615 err = ice_create_init_fdir_rule(pf, ICE_FLTR_PTYPE_NONF_IPV4_UDP);1616 if (err)1617 return err;1618 1619 err = ice_create_init_fdir_rule(pf, ICE_FLTR_PTYPE_NONF_IPV6_TCP);1620 if (err)1621 return err;1622 1623 err = ice_create_init_fdir_rule(pf, ICE_FLTR_PTYPE_NONF_IPV6_UDP);1624 1625 return err;1626}1627 1628/**1629 * ice_fdir_del_all_fltrs - Delete all flow director filters1630 * @vsi: the VSI being changed1631 *1632 * This function needs to be called while holding hw->fdir_fltr_lock1633 */1634void ice_fdir_del_all_fltrs(struct ice_vsi *vsi)1635{1636 struct ice_fdir_fltr *f_rule, *tmp;1637 struct ice_pf *pf = vsi->back;1638 struct ice_hw *hw = &pf->hw;1639 1640 list_for_each_entry_safe(f_rule, tmp, &hw->fdir_list_head, fltr_node) {1641 ice_fdir_write_all_fltr(pf, f_rule, false);1642 ice_fdir_update_cntrs(hw, f_rule->flow_type, false);1643 list_del(&f_rule->fltr_node);1644 devm_kfree(ice_pf_to_dev(pf), f_rule);1645 }1646}1647 1648/**1649 * ice_vsi_manage_fdir - turn on/off flow director1650 * @vsi: the VSI being changed1651 * @ena: boolean value indicating if this is an enable or disable request1652 */1653void ice_vsi_manage_fdir(struct ice_vsi *vsi, bool ena)1654{1655 struct ice_pf *pf = vsi->back;1656 struct ice_hw *hw = &pf->hw;1657 enum ice_fltr_ptype flow;1658 1659 if (ena) {1660 set_bit(ICE_FLAG_FD_ENA, pf->flags);1661 ice_fdir_create_dflt_rules(pf);1662 return;1663 }1664 1665 mutex_lock(&hw->fdir_fltr_lock);1666 if (!test_and_clear_bit(ICE_FLAG_FD_ENA, pf->flags))1667 goto release_lock;1668 1669 ice_fdir_del_all_fltrs(vsi);1670 1671 if (hw->fdir_prof)1672 for (flow = ICE_FLTR_PTYPE_NONF_NONE; flow < ICE_FLTR_PTYPE_MAX;1673 flow++)1674 if (hw->fdir_prof[flow])1675 ice_fdir_rem_flow(hw, ICE_BLK_FD, flow);1676 1677release_lock:1678 mutex_unlock(&hw->fdir_fltr_lock);1679}1680 1681/**1682 * ice_fdir_do_rem_flow - delete flow and possibly add perfect flow1683 * @pf: PF structure1684 * @flow_type: FDir flow type to release1685 */1686static void1687ice_fdir_do_rem_flow(struct ice_pf *pf, enum ice_fltr_ptype flow_type)1688{1689 struct ice_hw *hw = &pf->hw;1690 bool need_perfect = false;1691 1692 if (flow_type == ICE_FLTR_PTYPE_NONF_IPV4_TCP ||1693 flow_type == ICE_FLTR_PTYPE_NONF_IPV4_UDP ||1694 flow_type == ICE_FLTR_PTYPE_NONF_IPV6_TCP ||1695 flow_type == ICE_FLTR_PTYPE_NONF_IPV6_UDP)1696 need_perfect = true;1697 1698 if (need_perfect && test_bit(flow_type, hw->fdir_perfect_fltr))1699 return;1700 1701 ice_fdir_rem_flow(hw, ICE_BLK_FD, flow_type);1702 if (need_perfect)1703 ice_create_init_fdir_rule(pf, flow_type);1704}1705 1706/**1707 * ice_fdir_update_list_entry - add or delete a filter from the filter list1708 * @pf: PF structure1709 * @input: filter structure1710 * @fltr_idx: ethtool index of filter to modify1711 *1712 * returns 0 on success and negative on errors1713 */1714static int1715ice_fdir_update_list_entry(struct ice_pf *pf, struct ice_fdir_fltr *input,1716 int fltr_idx)1717{1718 struct ice_fdir_fltr *old_fltr;1719 struct ice_hw *hw = &pf->hw;1720 struct ice_vsi *vsi;1721 int err = -ENOENT;1722 1723 /* Do not update filters during reset */1724 if (ice_is_reset_in_progress(pf->state))1725 return -EBUSY;1726 1727 vsi = ice_get_main_vsi(pf);1728 if (!vsi)1729 return -EINVAL;1730 1731 old_fltr = ice_fdir_find_fltr_by_idx(hw, fltr_idx);1732 if (old_fltr) {1733 err = ice_fdir_write_all_fltr(pf, old_fltr, false);1734 if (err)1735 return err;1736 ice_fdir_update_cntrs(hw, old_fltr->flow_type, false);1737 /* update sb-filters count, specific to ring->channel */1738 ice_update_per_q_fltr(vsi, old_fltr->orig_q_index, false);1739 if (!input && !hw->fdir_fltr_cnt[old_fltr->flow_type])1740 /* we just deleted the last filter of flow_type so we1741 * should also delete the HW filter info.1742 */1743 ice_fdir_do_rem_flow(pf, old_fltr->flow_type);1744 list_del(&old_fltr->fltr_node);1745 devm_kfree(ice_hw_to_dev(hw), old_fltr);1746 }1747 if (!input)1748 return err;1749 ice_fdir_list_add_fltr(hw, input);1750 /* update sb-filters count, specific to ring->channel */1751 ice_update_per_q_fltr(vsi, input->orig_q_index, true);1752 ice_fdir_update_cntrs(hw, input->flow_type, true);1753 return 0;1754}1755 1756/**1757 * ice_del_fdir_ethtool - delete Flow Director filter1758 * @vsi: pointer to target VSI1759 * @cmd: command to add or delete Flow Director filter1760 *1761 * Returns 0 on success and negative values for failure1762 */1763int ice_del_fdir_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd)1764{1765 struct ethtool_rx_flow_spec *fsp =1766 (struct ethtool_rx_flow_spec *)&cmd->fs;1767 struct ice_pf *pf = vsi->back;1768 struct ice_hw *hw = &pf->hw;1769 int val;1770 1771 if (!test_bit(ICE_FLAG_FD_ENA, pf->flags))1772 return -EOPNOTSUPP;1773 1774 /* Do not delete filters during reset */1775 if (ice_is_reset_in_progress(pf->state)) {1776 dev_err(ice_pf_to_dev(pf), "Device is resetting - deleting Flow Director filters not supported during reset\n");1777 return -EBUSY;1778 }1779 1780 if (test_bit(ICE_FD_FLUSH_REQ, pf->state))1781 return -EBUSY;1782 1783 mutex_lock(&hw->fdir_fltr_lock);1784 val = ice_fdir_update_list_entry(pf, NULL, fsp->location);1785 mutex_unlock(&hw->fdir_fltr_lock);1786 1787 return val;1788}1789 1790/**1791 * ice_update_ring_dest_vsi - update dest ring and dest VSI1792 * @vsi: pointer to target VSI1793 * @dest_vsi: ptr to dest VSI index1794 * @ring: ptr to dest ring1795 *1796 * This function updates destination VSI and queue if user specifies1797 * target queue which falls in channel's (aka ADQ) queue region1798 */1799static void1800ice_update_ring_dest_vsi(struct ice_vsi *vsi, u16 *dest_vsi, u32 *ring)1801{1802 struct ice_channel *ch;1803 1804 list_for_each_entry(ch, &vsi->ch_list, list) {1805 if (!ch->ch_vsi)1806 continue;1807 1808 /* make sure to locate corresponding channel based on "queue"1809 * specified1810 */1811 if ((*ring < ch->base_q) ||1812 (*ring >= (ch->base_q + ch->num_rxq)))1813 continue;1814 1815 /* update the dest_vsi based on channel */1816 *dest_vsi = ch->ch_vsi->idx;1817 1818 /* update the "ring" to be correct based on channel */1819 *ring -= ch->base_q;1820 }1821}1822 1823/**1824 * ice_set_fdir_input_set - Set the input set for Flow Director1825 * @vsi: pointer to target VSI1826 * @fsp: pointer to ethtool Rx flow specification1827 * @input: filter structure1828 */1829static int1830ice_set_fdir_input_set(struct ice_vsi *vsi, struct ethtool_rx_flow_spec *fsp,1831 struct ice_fdir_fltr *input)1832{1833 s16 q_index = ICE_FDIR_NO_QUEUE_IDX;1834 u16 orig_q_index = 0;1835 struct ice_pf *pf;1836 struct ice_hw *hw;1837 int flow_type;1838 u16 dest_vsi;1839 u8 dest_ctl;1840 1841 if (!vsi || !fsp || !input)1842 return -EINVAL;1843 1844 pf = vsi->back;1845 hw = &pf->hw;1846 1847 dest_vsi = vsi->idx;1848 if (fsp->ring_cookie == RX_CLS_FLOW_DISC) {1849 dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DROP_PKT;1850 } else {1851 u32 ring = ethtool_get_flow_spec_ring(fsp->ring_cookie);1852 u8 vf = ethtool_get_flow_spec_ring_vf(fsp->ring_cookie);1853 1854 if (vf) {1855 dev_err(ice_pf_to_dev(pf), "Failed to add filter. Flow director filters are not supported on VF queues.\n");1856 return -EINVAL;1857 }1858 1859 if (ring >= vsi->num_rxq)1860 return -EINVAL;1861 1862 orig_q_index = ring;1863 ice_update_ring_dest_vsi(vsi, &dest_vsi, &ring);1864 dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_QINDEX;1865 q_index = ring;1866 }1867 1868 input->fltr_id = fsp->location;1869 input->q_index = q_index;1870 flow_type = fsp->flow_type & ~FLOW_EXT;1871 1872 /* Record the original queue index as specified by user.1873 * with channel configuration 'q_index' becomes relative1874 * to TC (channel).1875 */1876 input->orig_q_index = orig_q_index;1877 input->dest_vsi = dest_vsi;1878 input->dest_ctl = dest_ctl;1879 input->fltr_status = ICE_FLTR_PRGM_DESC_FD_STATUS_FD_ID;1880 input->cnt_index = ICE_FD_SB_STAT_IDX(hw->fd_ctr_base);1881 input->flow_type = ice_ethtool_flow_to_fltr(flow_type);1882 1883 if (fsp->flow_type & FLOW_EXT) {1884 memcpy(input->ext_data.usr_def, fsp->h_ext.data,1885 sizeof(input->ext_data.usr_def));1886 input->ext_data.vlan_type = fsp->h_ext.vlan_etype;1887 input->ext_data.vlan_tag = fsp->h_ext.vlan_tci;1888 memcpy(input->ext_mask.usr_def, fsp->m_ext.data,1889 sizeof(input->ext_mask.usr_def));1890 input->ext_mask.vlan_type = fsp->m_ext.vlan_etype;1891 input->ext_mask.vlan_tag = fsp->m_ext.vlan_tci;1892 }1893 1894 switch (flow_type) {1895 case TCP_V4_FLOW:1896 case UDP_V4_FLOW:1897 case SCTP_V4_FLOW:1898 input->ip.v4.dst_port = fsp->h_u.tcp_ip4_spec.pdst;1899 input->ip.v4.src_port = fsp->h_u.tcp_ip4_spec.psrc;1900 input->ip.v4.dst_ip = fsp->h_u.tcp_ip4_spec.ip4dst;1901 input->ip.v4.src_ip = fsp->h_u.tcp_ip4_spec.ip4src;1902 input->mask.v4.dst_port = fsp->m_u.tcp_ip4_spec.pdst;1903 input->mask.v4.src_port = fsp->m_u.tcp_ip4_spec.psrc;1904 input->mask.v4.dst_ip = fsp->m_u.tcp_ip4_spec.ip4dst;1905 input->mask.v4.src_ip = fsp->m_u.tcp_ip4_spec.ip4src;1906 break;1907 case IPV4_USER_FLOW:1908 input->ip.v4.dst_ip = fsp->h_u.usr_ip4_spec.ip4dst;1909 input->ip.v4.src_ip = fsp->h_u.usr_ip4_spec.ip4src;1910 input->ip.v4.l4_header = fsp->h_u.usr_ip4_spec.l4_4_bytes;1911 input->ip.v4.proto = fsp->h_u.usr_ip4_spec.proto;1912 input->ip.v4.ip_ver = fsp->h_u.usr_ip4_spec.ip_ver;1913 input->ip.v4.tos = fsp->h_u.usr_ip4_spec.tos;1914 input->mask.v4.dst_ip = fsp->m_u.usr_ip4_spec.ip4dst;1915 input->mask.v4.src_ip = fsp->m_u.usr_ip4_spec.ip4src;1916 input->mask.v4.l4_header = fsp->m_u.usr_ip4_spec.l4_4_bytes;1917 input->mask.v4.proto = fsp->m_u.usr_ip4_spec.proto;1918 input->mask.v4.ip_ver = fsp->m_u.usr_ip4_spec.ip_ver;1919 input->mask.v4.tos = fsp->m_u.usr_ip4_spec.tos;1920 break;1921 case TCP_V6_FLOW:1922 case UDP_V6_FLOW:1923 case SCTP_V6_FLOW:1924 memcpy(input->ip.v6.dst_ip, fsp->h_u.usr_ip6_spec.ip6dst,1925 sizeof(struct in6_addr));1926 memcpy(input->ip.v6.src_ip, fsp->h_u.usr_ip6_spec.ip6src,1927 sizeof(struct in6_addr));1928 input->ip.v6.dst_port = fsp->h_u.tcp_ip6_spec.pdst;1929 input->ip.v6.src_port = fsp->h_u.tcp_ip6_spec.psrc;1930 input->ip.v6.tc = fsp->h_u.tcp_ip6_spec.tclass;1931 memcpy(input->mask.v6.dst_ip, fsp->m_u.tcp_ip6_spec.ip6dst,1932 sizeof(struct in6_addr));1933 memcpy(input->mask.v6.src_ip, fsp->m_u.tcp_ip6_spec.ip6src,1934 sizeof(struct in6_addr));1935 input->mask.v6.dst_port = fsp->m_u.tcp_ip6_spec.pdst;1936 input->mask.v6.src_port = fsp->m_u.tcp_ip6_spec.psrc;1937 input->mask.v6.tc = fsp->m_u.tcp_ip6_spec.tclass;1938 break;1939 case IPV6_USER_FLOW:1940 memcpy(input->ip.v6.dst_ip, fsp->h_u.usr_ip6_spec.ip6dst,1941 sizeof(struct in6_addr));1942 memcpy(input->ip.v6.src_ip, fsp->h_u.usr_ip6_spec.ip6src,1943 sizeof(struct in6_addr));1944 input->ip.v6.l4_header = fsp->h_u.usr_ip6_spec.l4_4_bytes;1945 input->ip.v6.tc = fsp->h_u.usr_ip6_spec.tclass;1946 1947 /* if no protocol requested, use IPPROTO_NONE */1948 if (!fsp->m_u.usr_ip6_spec.l4_proto)1949 input->ip.v6.proto = IPPROTO_NONE;1950 else1951 input->ip.v6.proto = fsp->h_u.usr_ip6_spec.l4_proto;1952 1953 memcpy(input->mask.v6.dst_ip, fsp->m_u.usr_ip6_spec.ip6dst,1954 sizeof(struct in6_addr));1955 memcpy(input->mask.v6.src_ip, fsp->m_u.usr_ip6_spec.ip6src,1956 sizeof(struct in6_addr));1957 input->mask.v6.l4_header = fsp->m_u.usr_ip6_spec.l4_4_bytes;1958 input->mask.v6.tc = fsp->m_u.usr_ip6_spec.tclass;1959 input->mask.v6.proto = fsp->m_u.usr_ip6_spec.l4_proto;1960 break;1961 case ETHER_FLOW:1962 input->eth = fsp->h_u.ether_spec;1963 input->eth_mask = fsp->m_u.ether_spec;1964 break;1965 default:1966 /* not doing un-parsed flow types */1967 return -EINVAL;1968 }1969 1970 return 0;1971}1972 1973/**1974 * ice_add_fdir_ethtool - Add/Remove Flow Director filter1975 * @vsi: pointer to target VSI1976 * @cmd: command to add or delete Flow Director filter1977 *1978 * Returns 0 on success and negative values for failure1979 */1980int ice_add_fdir_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd)1981{1982 struct ice_rx_flow_userdef userdata;1983 struct ethtool_rx_flow_spec *fsp;1984 struct ice_fdir_fltr *input;1985 struct device *dev;1986 struct ice_pf *pf;1987 struct ice_hw *hw;1988 int fltrs_needed;1989 u32 max_location;1990 u16 tunnel_port;1991 int ret;1992 1993 if (!vsi)1994 return -EINVAL;1995 1996 pf = vsi->back;1997 hw = &pf->hw;1998 dev = ice_pf_to_dev(pf);1999 2000 if (!test_bit(ICE_FLAG_FD_ENA, pf->flags))2001 return -EOPNOTSUPP;2002 2003 /* Do not program filters during reset */2004 if (ice_is_reset_in_progress(pf->state)) {2005 dev_err(dev, "Device is resetting - adding Flow Director filters not supported during reset\n");2006 return -EBUSY;2007 }2008 2009 fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;2010 2011 if (ice_parse_rx_flow_user_data(fsp, &userdata))2012 return -EINVAL;2013 2014 if (fsp->flow_type & FLOW_MAC_EXT)2015 return -EINVAL;2016 2017 ret = ice_cfg_fdir_xtrct_seq(pf, fsp, &userdata);2018 if (ret)2019 return ret;2020 2021 max_location = ice_get_fdir_cnt_all(hw);2022 if (fsp->location >= max_location) {2023 dev_err(dev, "Failed to add filter. The number of ntuple filters or provided location exceed max %d.\n",2024 max_location);2025 return -ENOSPC;2026 }2027 2028 /* return error if not an update and no available filters */2029 fltrs_needed = ice_get_open_tunnel_port(hw, &tunnel_port, TNL_ALL) ? 2 : 1;2030 if (!ice_fdir_find_fltr_by_idx(hw, fsp->location) &&2031 ice_fdir_num_avail_fltr(hw, pf->vsi[vsi->idx]) < fltrs_needed) {2032 dev_err(dev, "Failed to add filter. The maximum number of flow director filters has been reached.\n");2033 return -ENOSPC;2034 }2035 2036 input = devm_kzalloc(dev, sizeof(*input), GFP_KERNEL);2037 if (!input)2038 return -ENOMEM;2039 2040 ret = ice_set_fdir_input_set(vsi, fsp, input);2041 if (ret)2042 goto free_input;2043 2044 mutex_lock(&hw->fdir_fltr_lock);2045 if (ice_fdir_is_dup_fltr(hw, input)) {2046 ret = -EINVAL;2047 goto release_lock;2048 }2049 2050 if (userdata.flex_fltr) {2051 input->flex_fltr = true;2052 input->flex_word = cpu_to_be16(userdata.flex_word);2053 input->flex_offset = userdata.flex_offset;2054 }2055 2056 input->cnt_ena = ICE_FXD_FLTR_QW0_STAT_ENA_PKTS;2057 input->fdid_prio = ICE_FXD_FLTR_QW1_FDID_PRI_THREE;2058 input->comp_report = ICE_FXD_FLTR_QW0_COMP_REPORT_SW_FAIL;2059 2060 /* input struct is added to the HW filter list */2061 ret = ice_fdir_update_list_entry(pf, input, fsp->location);2062 if (ret)2063 goto release_lock;2064 2065 ret = ice_fdir_write_all_fltr(pf, input, true);2066 if (ret)2067 goto remove_sw_rule;2068 2069 goto release_lock;2070 2071remove_sw_rule:2072 ice_fdir_update_cntrs(hw, input->flow_type, false);2073 /* update sb-filters count, specific to ring->channel */2074 ice_update_per_q_fltr(vsi, input->orig_q_index, false);2075 list_del(&input->fltr_node);2076release_lock:2077 mutex_unlock(&hw->fdir_fltr_lock);2078free_input:2079 if (ret)2080 devm_kfree(dev, input);2081 2082 return ret;2083}2084