Commit 40319796 authored by Kiran Patil's avatar Kiran Patil Committed by David S. Miller

ice: Add flow director support for channel mode

Add support to enable flow-director filter when multiple TCs are
configured. Flow director filter can be configured using ethtool
(--config-ntuple option). When multiple TCs are configured, each
TC is mapped to an unique HW VSI. So VSI corresponding to queue
used in filter is identified and flow director context is updated
with correct VSI while configuring ntuple filter in HW.
Signed-off-by: default avatarKiran Patil <kiran.patil@intel.com>
Signed-off-by: default avatarAmritha Nambiar <amritha.nambiar@intel.com>
Signed-off-by: default avatarSudheer Mogilappagari <sudheer.mogilappagari@intel.com>
Tested-by: default avatarBharathi Sreenivas <bharathi.sreenivas@intel.com>
Signed-off-by: default avatarTony Nguyen <anthony.l.nguyen@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a1f18c5f
...@@ -112,7 +112,6 @@ ...@@ -112,7 +112,6 @@
#define ICE_MAX_RXQS_PER_TC 256 /* Used when setting VSI context per TC Rx queues */ #define ICE_MAX_RXQS_PER_TC 256 /* Used when setting VSI context per TC Rx queues */
#define ICE_CHNL_START_TC 1 #define ICE_CHNL_START_TC 1
#define ICE_CHNL_MAX_TC 16
#define ICE_MAX_RESET_WAIT 20 #define ICE_MAX_RESET_WAIT 20
...@@ -201,6 +200,7 @@ struct ice_channel { ...@@ -201,6 +200,7 @@ struct ice_channel {
struct ice_aqc_vsi_props info; struct ice_aqc_vsi_props info;
u64 max_tx_rate; u64 max_tx_rate;
u64 min_tx_rate; u64 min_tx_rate;
atomic_t num_sb_fltr;
struct ice_vsi *ch_vsi; struct ice_vsi *ch_vsi;
}; };
...@@ -792,6 +792,9 @@ static inline void ice_clear_sriov_cap(struct ice_pf *pf) ...@@ -792,6 +792,9 @@ static inline void ice_clear_sriov_cap(struct ice_pf *pf)
#define ICE_FD_STAT_PF_IDX(base_idx) \ #define ICE_FD_STAT_PF_IDX(base_idx) \
((base_idx) * ICE_FD_STAT_CTR_BLOCK_COUNT) ((base_idx) * ICE_FD_STAT_CTR_BLOCK_COUNT)
#define ICE_FD_SB_STAT_IDX(base_idx) ICE_FD_STAT_PF_IDX(base_idx) #define ICE_FD_SB_STAT_IDX(base_idx) ICE_FD_STAT_PF_IDX(base_idx)
#define ICE_FD_STAT_CH 1
#define ICE_FD_CH_STAT_IDX(base_idx) \
(ICE_FD_STAT_PF_IDX(base_idx) + ICE_FD_STAT_CH)
/** /**
* ice_is_adq_active - any active ADQs * ice_is_adq_active - any active ADQs
...@@ -852,6 +855,7 @@ void ice_unplug_aux_dev(struct ice_pf *pf); ...@@ -852,6 +855,7 @@ void ice_unplug_aux_dev(struct ice_pf *pf);
int ice_init_rdma(struct ice_pf *pf); int ice_init_rdma(struct ice_pf *pf);
const char *ice_aq_str(enum ice_aq_err aq_err); const char *ice_aq_str(enum ice_aq_err aq_err);
bool ice_is_wol_supported(struct ice_hw *hw); bool ice_is_wol_supported(struct ice_hw *hw);
void ice_fdir_del_all_fltrs(struct ice_vsi *vsi);
int int
ice_fdir_write_fltr(struct ice_pf *pf, struct ice_fdir_fltr *input, bool add, ice_fdir_write_fltr(struct ice_pf *pf, struct ice_fdir_fltr *input, bool add,
bool is_tun); bool is_tun);
...@@ -862,6 +866,7 @@ int ice_get_ethtool_fdir_entry(struct ice_hw *hw, struct ethtool_rxnfc *cmd); ...@@ -862,6 +866,7 @@ int ice_get_ethtool_fdir_entry(struct ice_hw *hw, struct ethtool_rxnfc *cmd);
int int
ice_get_fdir_fltr_ids(struct ice_hw *hw, struct ethtool_rxnfc *cmd, ice_get_fdir_fltr_ids(struct ice_hw *hw, struct ethtool_rxnfc *cmd,
u32 *rule_locs); u32 *rule_locs);
void ice_fdir_rem_adq_chnl(struct ice_hw *hw, u16 vsi_idx);
void ice_fdir_release_flows(struct ice_hw *hw); void ice_fdir_release_flows(struct ice_hw *hw);
void ice_fdir_replay_flows(struct ice_hw *hw); void ice_fdir_replay_flows(struct ice_hw *hw);
void ice_fdir_replay_fltrs(struct ice_pf *pf); void ice_fdir_replay_fltrs(struct ice_pf *pf);
......
...@@ -182,6 +182,7 @@ struct ice_fdir_fltr { ...@@ -182,6 +182,7 @@ struct ice_fdir_fltr {
/* filter control */ /* filter control */
u16 q_index; u16 q_index;
u16 orig_q_index;
u16 dest_vsi; u16 dest_vsi;
u8 dest_ctl; u8 dest_ctl;
u8 cnt_ena; u8 cnt_ena;
......
...@@ -1806,6 +1806,57 @@ ice_flow_add_fld_raw(struct ice_flow_seg_info *seg, u16 off, u8 len, ...@@ -1806,6 +1806,57 @@ ice_flow_add_fld_raw(struct ice_flow_seg_info *seg, u16 off, u8 len,
seg->raws_cnt++; seg->raws_cnt++;
} }
/**
* ice_flow_rem_vsi_prof - remove VSI from flow profile
* @hw: pointer to the hardware structure
* @vsi_handle: software VSI handle
* @prof_id: unique ID to identify this flow profile
*
* This function removes the flow entries associated to the input
* VSI handle and disassociate the VSI from the flow profile.
*/
int ice_flow_rem_vsi_prof(struct ice_hw *hw, u16 vsi_handle, u64 prof_id)
{
struct ice_flow_prof *prof;
int status = 0;
if (!ice_is_vsi_valid(hw, vsi_handle))
return -EINVAL;
/* find flow profile pointer with input package block and profile ID */
prof = ice_flow_find_prof_id(hw, ICE_BLK_FD, prof_id);
if (!prof) {
ice_debug(hw, ICE_DBG_PKG, "Cannot find flow profile id=%llu\n",
prof_id);
return -ENOENT;
}
/* Remove all remaining flow entries before removing the flow profile */
if (!list_empty(&prof->entries)) {
struct ice_flow_entry *e, *t;
mutex_lock(&prof->entries_lock);
list_for_each_entry_safe(e, t, &prof->entries, l_entry) {
if (e->vsi_handle != vsi_handle)
continue;
status = ice_flow_rem_entry_sync(hw, ICE_BLK_FD, e);
if (status)
break;
}
mutex_unlock(&prof->entries_lock);
}
if (status)
return status;
/* disassociate the flow profile from sw VSI handle */
status = ice_flow_disassoc_prof(hw, ICE_BLK_FD, prof, vsi_handle);
if (status)
ice_debug(hw, ICE_DBG_PKG, "ice_flow_disassoc_prof() failed with status=%d\n",
status);
return status;
}
#define ICE_FLOW_RSS_SEG_HDR_L2_MASKS \ #define ICE_FLOW_RSS_SEG_HDR_L2_MASKS \
(ICE_FLOW_SEG_HDR_ETH | ICE_FLOW_SEG_HDR_VLAN) (ICE_FLOW_SEG_HDR_ETH | ICE_FLOW_SEG_HDR_VLAN)
......
...@@ -399,6 +399,7 @@ ice_flow_set_fld(struct ice_flow_seg_info *seg, enum ice_flow_field fld, ...@@ -399,6 +399,7 @@ ice_flow_set_fld(struct ice_flow_seg_info *seg, enum ice_flow_field fld,
void void
ice_flow_add_fld_raw(struct ice_flow_seg_info *seg, u16 off, u8 len, ice_flow_add_fld_raw(struct ice_flow_seg_info *seg, u16 off, u8 len,
u16 val_loc, u16 mask_loc); u16 val_loc, u16 mask_loc);
int ice_flow_rem_vsi_prof(struct ice_hw *hw, u16 vsi_handle, u64 prof_id);
void ice_rem_vsi_rss_list(struct ice_hw *hw, u16 vsi_handle); void ice_rem_vsi_rss_list(struct ice_hw *hw, u16 vsi_handle);
int ice_replay_rss_cfg(struct ice_hw *hw, u16 vsi_handle); int ice_replay_rss_cfg(struct ice_hw *hw, u16 vsi_handle);
int ice_add_avf_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds); int ice_add_avf_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds);
......
...@@ -570,10 +570,16 @@ static int ice_alloc_fd_res(struct ice_vsi *vsi) ...@@ -570,10 +570,16 @@ static int ice_alloc_fd_res(struct ice_vsi *vsi)
struct ice_pf *pf = vsi->back; struct ice_pf *pf = vsi->back;
u32 g_val, b_val; u32 g_val, b_val;
/* Flow Director filters are only allocated/assigned to the PF VSI which /* Flow Director filters are only allocated/assigned to the PF VSI or
* passes the traffic. The CTRL VSI is only used to add/delete filters * CHNL VSI which passes the traffic. The CTRL VSI is only used to
* so we don't allocate resources to it * add/delete filters so resources are not allocated to it
*/ */
if (!test_bit(ICE_FLAG_FD_ENA, pf->flags))
return -EPERM;
if (!(vsi->type == ICE_VSI_PF || vsi->type == ICE_VSI_VF ||
vsi->type == ICE_VSI_CHNL))
return -EPERM;
/* FD filters from guaranteed pool per VSI */ /* FD filters from guaranteed pool per VSI */
g_val = pf->hw.func_caps.fd_fltr_guar; g_val = pf->hw.func_caps.fd_fltr_guar;
...@@ -585,19 +591,56 @@ static int ice_alloc_fd_res(struct ice_vsi *vsi) ...@@ -585,19 +591,56 @@ static int ice_alloc_fd_res(struct ice_vsi *vsi)
if (!b_val) if (!b_val)
return -EPERM; return -EPERM;
if (!(vsi->type == ICE_VSI_PF || vsi->type == ICE_VSI_VF)) /* PF main VSI gets only 64 FD resources from guaranteed pool
return -EPERM; * when ADQ is configured.
*/
#define ICE_PF_VSI_GFLTR 64
if (!test_bit(ICE_FLAG_FD_ENA, pf->flags)) /* determine FD filter resources per VSI from shared(best effort) and
return -EPERM; * dedicated pool
*/
if (vsi->type == ICE_VSI_PF) {
vsi->num_gfltr = g_val;
/* if MQPRIO is configured, main VSI doesn't get all FD
* resources from guaranteed pool. PF VSI gets 64 FD resources
*/
if (test_bit(ICE_FLAG_TC_MQPRIO, pf->flags)) {
if (g_val < ICE_PF_VSI_GFLTR)
return -EPERM;
/* allow bare minimum entries for PF VSI */
vsi->num_gfltr = ICE_PF_VSI_GFLTR;
}
/* each VSI gets same "best_effort" quota */
vsi->num_bfltr = b_val;
} else if (vsi->type == ICE_VSI_VF) {
vsi->num_gfltr = 0;
/* each VSI gets same "best_effort" quota */
vsi->num_bfltr = b_val;
} else {
struct ice_vsi *main_vsi;
int numtc;
vsi->num_gfltr = g_val / pf->num_alloc_vsi; main_vsi = ice_get_main_vsi(pf);
if (!main_vsi)
return -EPERM;
/* each VSI gets same "best_effort" quota */ if (!main_vsi->all_numtc)
vsi->num_bfltr = b_val; return -EINVAL;
if (vsi->type == ICE_VSI_VF) { /* figure out ADQ numtc */
vsi->num_gfltr = 0; numtc = main_vsi->all_numtc - ICE_CHNL_START_TC;
/* only one TC but still asking resources for channels,
* invalid config
*/
if (numtc < ICE_CHNL_START_TC)
return -EPERM;
g_val -= ICE_PF_VSI_GFLTR;
/* channel VSIs gets equal share from guaranteed pool */
vsi->num_gfltr = g_val / numtc;
/* each VSI gets same "best_effort" quota */ /* each VSI gets same "best_effort" quota */
vsi->num_bfltr = b_val; vsi->num_bfltr = b_val;
...@@ -942,7 +985,7 @@ static void ice_set_fd_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi) ...@@ -942,7 +985,7 @@ static void ice_set_fd_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi)
u16 dflt_q, report_q, val; u16 dflt_q, report_q, val;
if (vsi->type != ICE_VSI_PF && vsi->type != ICE_VSI_CTRL && if (vsi->type != ICE_VSI_PF && vsi->type != ICE_VSI_CTRL &&
vsi->type != ICE_VSI_VF) vsi->type != ICE_VSI_VF && vsi->type != ICE_VSI_CHNL)
return; return;
val = ICE_AQ_VSI_PROP_FLOW_DIR_VALID; val = ICE_AQ_VSI_PROP_FLOW_DIR_VALID;
......
...@@ -7439,6 +7439,67 @@ ice_validate_mqprio_qopt(struct ice_vsi *vsi, ...@@ -7439,6 +7439,67 @@ ice_validate_mqprio_qopt(struct ice_vsi *vsi,
return 0; return 0;
} }
/**
* ice_add_vsi_to_fdir - add a VSI to the flow director group for PF
* @pf: ptr to PF device
* @vsi: ptr to VSI
*/
static int ice_add_vsi_to_fdir(struct ice_pf *pf, struct ice_vsi *vsi)
{
struct device *dev = ice_pf_to_dev(pf);
bool added = false;
struct ice_hw *hw;
int flow;
if (!(vsi->num_gfltr || vsi->num_bfltr))
return -EINVAL;
hw = &pf->hw;
for (flow = 0; flow < ICE_FLTR_PTYPE_MAX; flow++) {
struct ice_fd_hw_prof *prof;
int tun, status;
u64 entry_h;
if (!(hw->fdir_prof && hw->fdir_prof[flow] &&
hw->fdir_prof[flow]->cnt))
continue;
for (tun = 0; tun < ICE_FD_HW_SEG_MAX; tun++) {
enum ice_flow_priority prio;
u64 prof_id;
/* add this VSI to FDir profile for this flow */
prio = ICE_FLOW_PRIO_NORMAL;
prof = hw->fdir_prof[flow];
prof_id = flow + tun * ICE_FLTR_PTYPE_MAX;
status = ice_flow_add_entry(hw, ICE_BLK_FD, prof_id,
prof->vsi_h[0], vsi->idx,
prio, prof->fdir_seg[tun],
&entry_h);
if (status) {
dev_err(dev, "channel VSI idx %d, not able to add to group %d\n",
vsi->idx, flow);
continue;
}
prof->entry_h[prof->cnt][tun] = entry_h;
}
/* store VSI for filter replay and delete */
prof->vsi_h[prof->cnt] = vsi->idx;
prof->cnt++;
added = true;
dev_dbg(dev, "VSI idx %d added to fdir group %d\n", vsi->idx,
flow);
}
if (!added)
dev_dbg(dev, "VSI idx %d not added to fdir groups\n", vsi->idx);
return 0;
}
/** /**
* ice_add_channel - add a channel by adding VSI * ice_add_channel - add a channel by adding VSI
* @pf: ptr to PF device * @pf: ptr to PF device
...@@ -7463,6 +7524,8 @@ static int ice_add_channel(struct ice_pf *pf, u16 sw_id, struct ice_channel *ch) ...@@ -7463,6 +7524,8 @@ static int ice_add_channel(struct ice_pf *pf, u16 sw_id, struct ice_channel *ch)
return -EINVAL; return -EINVAL;
} }
ice_add_vsi_to_fdir(pf, vsi);
ch->sw_id = sw_id; ch->sw_id = sw_id;
ch->vsi_num = vsi->vsi_num; ch->vsi_num = vsi->vsi_num;
ch->info.mapping_flags = vsi->info.mapping_flags; ch->info.mapping_flags = vsi->info.mapping_flags;
...@@ -7763,6 +7826,15 @@ static void ice_remove_q_channels(struct ice_vsi *vsi, bool rem_fltr) ...@@ -7763,6 +7826,15 @@ static void ice_remove_q_channels(struct ice_vsi *vsi, bool rem_fltr)
if (rem_fltr) if (rem_fltr)
ice_rem_all_chnl_fltrs(pf); ice_rem_all_chnl_fltrs(pf);
/* remove ntuple filters since queue configuration is being changed */
if (vsi->netdev->features & NETIF_F_NTUPLE) {
struct ice_hw *hw = &pf->hw;
mutex_lock(&hw->fdir_fltr_lock);
ice_fdir_del_all_fltrs(vsi);
mutex_unlock(&hw->fdir_fltr_lock);
}
/* perform cleanup for channels if they exist */ /* perform cleanup for channels if they exist */
list_for_each_entry_safe(ch, ch_tmp, &vsi->ch_list, list) { list_for_each_entry_safe(ch, ch_tmp, &vsi->ch_list, list) {
struct ice_vsi *ch_vsi; struct ice_vsi *ch_vsi;
...@@ -7793,6 +7865,9 @@ static void ice_remove_q_channels(struct ice_vsi *vsi, bool rem_fltr) ...@@ -7793,6 +7865,9 @@ static void ice_remove_q_channels(struct ice_vsi *vsi, bool rem_fltr)
} }
} }
/* Release FD resources for the channel VSI */
ice_fdir_rem_adq_chnl(&pf->hw, ch->ch_vsi->idx);
/* clear the VSI from scheduler tree */ /* clear the VSI from scheduler tree */
ice_rm_vsi_lan_cfg(ch->ch_vsi->port_info, ch->ch_vsi->idx); ice_rm_vsi_lan_cfg(ch->ch_vsi->port_info, ch->ch_vsi->idx);
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define ICE_BYTES_PER_WORD 2 #define ICE_BYTES_PER_WORD 2
#define ICE_BYTES_PER_DWORD 4 #define ICE_BYTES_PER_DWORD 4
#define ICE_CHNL_MAX_TC 16
#include "ice_hw_autogen.h" #include "ice_hw_autogen.h"
#include "ice_osdep.h" #include "ice_osdep.h"
...@@ -229,8 +230,8 @@ enum ice_fd_hw_seg { ...@@ -229,8 +230,8 @@ enum ice_fd_hw_seg {
ICE_FD_HW_SEG_MAX, ICE_FD_HW_SEG_MAX,
}; };
/* 2 VSI = 1 ICE_VSI_PF + 1 ICE_VSI_CTRL */ /* 1 ICE_VSI_PF + 1 ICE_VSI_CTRL + ICE_CHNL_MAX_TC */
#define ICE_MAX_FDIR_VSI_PER_FILTER 2 #define ICE_MAX_FDIR_VSI_PER_FILTER (2 + ICE_CHNL_MAX_TC)
struct ice_fd_hw_prof { struct ice_fd_hw_prof {
struct ice_flow_seg_info *fdir_seg[ICE_FD_HW_SEG_MAX]; struct ice_flow_seg_info *fdir_seg[ICE_FD_HW_SEG_MAX];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment