// SPDX-License-Identifier: GPL-2.0 /* Copyright (C) 2018-2023, Intel Corporation. */ /* flow director ethtool support for ice */ #include "ice.h" #include "ice_lib.h" #include "ice_fdir.h" #include "ice_flow.h" static struct in6_addr full_ipv6_addr_mask = …; static struct in6_addr zero_ipv6_addr_mask = …; /* calls to ice_flow_add_prof require the number of segments in the array * for segs_cnt. In this code that is one more than the index. */ #define TNL_SEG_CNT(_TNL_) … /** * ice_fltr_to_ethtool_flow - convert filter type values to ethtool * flow type values * @flow: filter type to be converted * * Returns the corresponding ethtool flow type. */ static int ice_fltr_to_ethtool_flow(enum ice_fltr_ptype flow) { … } /** * ice_ethtool_flow_to_fltr - convert ethtool flow type to filter enum * @eth: Ethtool flow type to be converted * * Returns flow enum */ static enum ice_fltr_ptype ice_ethtool_flow_to_fltr(int eth) { … } /** * ice_is_mask_valid - check mask field set * @mask: full mask to check * @field: field for which mask should be valid * * If the mask is fully set return true. If it is not valid for field return * false. */ static bool ice_is_mask_valid(u64 mask, u64 field) { … } /** * ice_get_ethtool_fdir_entry - fill ethtool structure with fdir filter data * @hw: hardware structure that contains filter list * @cmd: ethtool command data structure to receive the filter data * * Returns 0 on success and -EINVAL on failure */ int ice_get_ethtool_fdir_entry(struct ice_hw *hw, struct ethtool_rxnfc *cmd) { … } /** * ice_get_fdir_fltr_ids - fill buffer with filter IDs of active filters * @hw: hardware structure containing the filter list * @cmd: ethtool command data structure * @rule_locs: ethtool array passed in from OS to receive filter IDs * * Returns 0 as expected for success by ethtool */ int ice_get_fdir_fltr_ids(struct ice_hw *hw, struct ethtool_rxnfc *cmd, u32 *rule_locs) { … } /** * ice_fdir_remap_entries - update the FDir entries in profile * @prof: FDir structure pointer * @tun: tunneled or non-tunneled packet * @idx: FDir entry index */ static void ice_fdir_remap_entries(struct ice_fd_hw_prof *prof, int tun, int idx) { … } /** * ice_fdir_rem_adq_chnl - remove an ADQ channel from HW filter rules * @hw: hardware structure containing filter list * @vsi_idx: VSI handle */ void ice_fdir_rem_adq_chnl(struct ice_hw *hw, u16 vsi_idx) { … } /** * ice_fdir_get_hw_prof - return the ice_fd_hw_proc associated with a flow * @hw: hardware structure containing the filter list * @blk: hardware block * @flow: FDir flow type to release */ static struct ice_fd_hw_prof * ice_fdir_get_hw_prof(struct ice_hw *hw, enum ice_block blk, int flow) { … } /** * ice_fdir_erase_flow_from_hw - remove a flow from the HW profile tables * @hw: hardware structure containing the filter list * @blk: hardware block * @flow: FDir flow type to release */ static void ice_fdir_erase_flow_from_hw(struct ice_hw *hw, enum ice_block blk, int flow) { … } /** * ice_fdir_rem_flow - release the ice_flow structures for a filter type * @hw: hardware structure containing the filter list * @blk: hardware block * @flow_type: FDir flow type to release */ static void ice_fdir_rem_flow(struct ice_hw *hw, enum ice_block blk, enum ice_fltr_ptype flow_type) { … } /** * ice_fdir_release_flows - release all flows in use for later replay * @hw: pointer to HW instance */ void ice_fdir_release_flows(struct ice_hw *hw) { … } /** * ice_fdir_replay_flows - replay HW Flow Director filter info * @hw: pointer to HW instance */ void ice_fdir_replay_flows(struct ice_hw *hw) { … } /** * ice_parse_rx_flow_user_data - deconstruct user-defined data * @fsp: pointer to ethtool Rx flow specification * @data: pointer to userdef data structure for storage * * Returns 0 on success, negative error value on failure */ static int ice_parse_rx_flow_user_data(struct ethtool_rx_flow_spec *fsp, struct ice_rx_flow_userdef *data) { … } /** * ice_fdir_num_avail_fltr - return the number of unused flow director filters * @hw: pointer to hardware structure * @vsi: software VSI structure * * There are 2 filter pools: guaranteed and best effort(shared). Each VSI can * use filters from either pool. The guaranteed pool is divided between VSIs. * The best effort filter pool is common to all VSIs and is a device shared * resource pool. The number of filters available to this VSI is the sum of * the VSIs guaranteed filter pool and the global available best effort * filter pool. * * Returns the number of available flow director filters to this VSI */ int ice_fdir_num_avail_fltr(struct ice_hw *hw, struct ice_vsi *vsi) { … } /** * ice_fdir_alloc_flow_prof - allocate FDir flow profile structure(s) * @hw: HW structure containing the FDir flow profile structure(s) * @flow: flow type to allocate the flow profile for * * Allocate the fdir_prof and fdir_prof[flow] if not already created. Return 0 * on success and negative on error. */ static int ice_fdir_alloc_flow_prof(struct ice_hw *hw, enum ice_fltr_ptype flow) { … } /** * ice_fdir_prof_vsi_idx - find or insert a vsi_idx in structure * @prof: pointer to flow director HW profile * @vsi_idx: vsi_idx to locate * * return the index of the vsi_idx. if vsi_idx is not found insert it * into the vsi_h table. */ static u16 ice_fdir_prof_vsi_idx(struct ice_fd_hw_prof *prof, int vsi_idx) { … } /** * ice_fdir_set_hw_fltr_rule - Configure HW tables to generate a FDir rule * @pf: pointer to the PF structure * @seg: protocol header description pointer * @flow: filter enum * @tun: FDir segment to program */ static int ice_fdir_set_hw_fltr_rule(struct ice_pf *pf, struct ice_flow_seg_info *seg, enum ice_fltr_ptype flow, enum ice_fd_hw_seg tun) { … } /** * ice_set_init_fdir_seg * @seg: flow segment for programming * @l3_proto: ICE_FLOW_SEG_HDR_IPV4 or ICE_FLOW_SEG_HDR_IPV6 * @l4_proto: ICE_FLOW_SEG_HDR_TCP or ICE_FLOW_SEG_HDR_UDP * * Set the configuration for perfect filters to the provided flow segment for * programming the HW filter. This is to be called only when initializing * filters as this function it assumes no filters exist. */ static int ice_set_init_fdir_seg(struct ice_flow_seg_info *seg, enum ice_flow_seg_hdr l3_proto, enum ice_flow_seg_hdr l4_proto) { … } /** * ice_create_init_fdir_rule * @pf: PF structure * @flow: filter enum * * Return error value or 0 on success. */ static int ice_create_init_fdir_rule(struct ice_pf *pf, enum ice_fltr_ptype flow) { … } /** * ice_set_fdir_ip4_seg * @seg: flow segment for programming * @tcp_ip4_spec: mask data from ethtool * @l4_proto: Layer 4 protocol to program * @perfect_fltr: only valid on success; returns true if perfect filter, * false if not * * Set the mask data into the flow segment to be used to program HW * table based on provided L4 protocol for IPv4 */ static int ice_set_fdir_ip4_seg(struct ice_flow_seg_info *seg, struct ethtool_tcpip4_spec *tcp_ip4_spec, enum ice_flow_seg_hdr l4_proto, bool *perfect_fltr) { … } /** * ice_set_fdir_ip4_usr_seg * @seg: flow segment for programming * @usr_ip4_spec: ethtool userdef packet offset * @perfect_fltr: only valid on success; returns true if perfect filter, * false if not * * Set the offset data into the flow segment to be used to program HW * table for IPv4 */ static int ice_set_fdir_ip4_usr_seg(struct ice_flow_seg_info *seg, struct ethtool_usrip4_spec *usr_ip4_spec, bool *perfect_fltr) { … } /** * ice_set_fdir_ip6_seg * @seg: flow segment for programming * @tcp_ip6_spec: mask data from ethtool * @l4_proto: Layer 4 protocol to program * @perfect_fltr: only valid on success; returns true if perfect filter, * false if not * * Set the mask data into the flow segment to be used to program HW * table based on provided L4 protocol for IPv6 */ static int ice_set_fdir_ip6_seg(struct ice_flow_seg_info *seg, struct ethtool_tcpip6_spec *tcp_ip6_spec, enum ice_flow_seg_hdr l4_proto, bool *perfect_fltr) { … } /** * ice_set_fdir_ip6_usr_seg * @seg: flow segment for programming * @usr_ip6_spec: ethtool userdef packet offset * @perfect_fltr: only valid on success; returns true if perfect filter, * false if not * * Set the offset data into the flow segment to be used to program HW * table for IPv6 */ static int ice_set_fdir_ip6_usr_seg(struct ice_flow_seg_info *seg, struct ethtool_usrip6_spec *usr_ip6_spec, bool *perfect_fltr) { … } /** * ice_fdir_vlan_valid - validate VLAN data for Flow Director rule * @dev: network interface device structure * @fsp: pointer to ethtool Rx flow specification * * Return: true if vlan data is valid, false otherwise */ static bool ice_fdir_vlan_valid(struct device *dev, struct ethtool_rx_flow_spec *fsp) { … } /** * ice_set_ether_flow_seg - set address and protocol segments for ether flow * @dev: network interface device structure * @seg: flow segment for programming * @eth_spec: mask data from ethtool * * Return: 0 on success and errno in case of error. */ static int ice_set_ether_flow_seg(struct device *dev, struct ice_flow_seg_info *seg, struct ethhdr *eth_spec) { … } /** * ice_set_fdir_vlan_seg - set vlan segments for ether flow * @seg: flow segment for programming * @ext_masks: masks for additional RX flow fields * * Return: 0 on success and errno in case of error. */ static int ice_set_fdir_vlan_seg(struct ice_flow_seg_info *seg, struct ethtool_flow_ext *ext_masks) { … } /** * ice_cfg_fdir_xtrct_seq - Configure extraction sequence for the given filter * @pf: PF structure * @fsp: pointer to ethtool Rx flow specification * @user: user defined data from flow specification * * Returns 0 on success. */ static int ice_cfg_fdir_xtrct_seq(struct ice_pf *pf, struct ethtool_rx_flow_spec *fsp, struct ice_rx_flow_userdef *user) { … } /** * ice_update_per_q_fltr * @vsi: ptr to VSI * @q_index: queue index * @inc: true to increment or false to decrement per queue filter count * * This function is used to keep track of per queue sideband filters */ static void ice_update_per_q_fltr(struct ice_vsi *vsi, u32 q_index, bool inc) { … } /** * ice_fdir_write_fltr - send a flow director filter to the hardware * @pf: PF data structure * @input: filter structure * @add: true adds filter and false removed filter * @is_tun: true adds inner filter on tunnel and false outer headers * * returns 0 on success and negative value on error */ int ice_fdir_write_fltr(struct ice_pf *pf, struct ice_fdir_fltr *input, bool add, bool is_tun) { … } /** * ice_fdir_write_all_fltr - send a flow director filter to the hardware * @pf: PF data structure * @input: filter structure * @add: true adds filter and false removed filter * * returns 0 on success and negative value on error */ static int ice_fdir_write_all_fltr(struct ice_pf *pf, struct ice_fdir_fltr *input, bool add) { … } /** * ice_fdir_replay_fltrs - replay filters from the HW filter list * @pf: board private structure */ void ice_fdir_replay_fltrs(struct ice_pf *pf) { … } /** * ice_fdir_create_dflt_rules - create default perfect filters * @pf: PF data structure * * Returns 0 for success or error. */ int ice_fdir_create_dflt_rules(struct ice_pf *pf) { … } /** * ice_fdir_del_all_fltrs - Delete all flow director filters * @vsi: the VSI being changed * * This function needs to be called while holding hw->fdir_fltr_lock */ void ice_fdir_del_all_fltrs(struct ice_vsi *vsi) { … } /** * ice_vsi_manage_fdir - turn on/off flow director * @vsi: the VSI being changed * @ena: boolean value indicating if this is an enable or disable request */ void ice_vsi_manage_fdir(struct ice_vsi *vsi, bool ena) { … } /** * ice_fdir_do_rem_flow - delete flow and possibly add perfect flow * @pf: PF structure * @flow_type: FDir flow type to release */ static void ice_fdir_do_rem_flow(struct ice_pf *pf, enum ice_fltr_ptype flow_type) { … } /** * ice_fdir_update_list_entry - add or delete a filter from the filter list * @pf: PF structure * @input: filter structure * @fltr_idx: ethtool index of filter to modify * * returns 0 on success and negative on errors */ static int ice_fdir_update_list_entry(struct ice_pf *pf, struct ice_fdir_fltr *input, int fltr_idx) { … } /** * ice_del_fdir_ethtool - delete Flow Director filter * @vsi: pointer to target VSI * @cmd: command to add or delete Flow Director filter * * Returns 0 on success and negative values for failure */ int ice_del_fdir_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd) { … } /** * ice_update_ring_dest_vsi - update dest ring and dest VSI * @vsi: pointer to target VSI * @dest_vsi: ptr to dest VSI index * @ring: ptr to dest ring * * This function updates destination VSI and queue if user specifies * target queue which falls in channel's (aka ADQ) queue region */ static void ice_update_ring_dest_vsi(struct ice_vsi *vsi, u16 *dest_vsi, u32 *ring) { … } /** * ice_set_fdir_input_set - Set the input set for Flow Director * @vsi: pointer to target VSI * @fsp: pointer to ethtool Rx flow specification * @input: filter structure */ static int ice_set_fdir_input_set(struct ice_vsi *vsi, struct ethtool_rx_flow_spec *fsp, struct ice_fdir_fltr *input) { … } /** * ice_add_fdir_ethtool - Add/Remove Flow Director filter * @vsi: pointer to target VSI * @cmd: command to add or delete Flow Director filter * * Returns 0 on success and negative values for failure */ int ice_add_fdir_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd) { … }