Commit 311c13dd authored by David S. Miller's avatar David S. Miller

Merge branch '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/nex

t-queue

Tony Nguyen says:

====================
100GbE Intel Wired LAN Driver Updates 2021-10-11

Wojciech Drewek says:

This series adds support for adding/removing advanced switch filters
in ice driver. Advanced filters are building blocks for HW acceleration
of TC orchestration. Add ndo_setup_tc callback implementation for PF and
VF port representors (when device is configured in switchdev mode).

Define dummy packet headers to allow adding advanced rules in HW.
Supported headers, and thus filters, are:
- MAC + IPv4 + UDP
- MAC + VLAN + IPv4 + UDP
- MAC + IPv4 + TCP
- MAC + VLAN + IPv4 + TCP
- MAC + IPv6 + UDP
- MAC + VLAN + IPv6 + UDP
- MAC + IPv6 + TCP
- MAC + VLAN + IPv6 + TCP
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents e679198b 7fde6d8b
......@@ -27,7 +27,8 @@ ice-y := ice_main.o \
ice_fw_update.o \
ice_lag.o \
ice_ethtool.o \
ice_repr.o
ice_repr.o \
ice_tc_lib.o
ice-$(CONFIG_PCI_IOV) += ice_virtchnl_allowlist.o
ice-$(CONFIG_PCI_IOV) += ice_virtchnl_pf.o ice_sriov.o ice_virtchnl_fdir.o
ice-$(CONFIG_PTP_1588_CLOCK) += ice_ptp.o ice_ptp_hw.o
......
......@@ -64,6 +64,7 @@
#include "ice_xsk.h"
#include "ice_arfs.h"
#include "ice_repr.h"
#include "ice_eswitch.h"
#include "ice_lag.h"
#define ICE_BAR0 0
......@@ -400,6 +401,7 @@ enum ice_pf_flags {
ICE_FLAG_PTP, /* PTP is enabled by software */
ICE_FLAG_AUX_ENA,
ICE_FLAG_ADV_FEATURES,
ICE_FLAG_CLS_FLOWER,
ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA,
ICE_FLAG_TOTAL_PORT_SHUTDOWN_ENA,
ICE_FLAG_NO_MEDIA,
......@@ -512,6 +514,8 @@ struct ice_pf {
int aux_idx;
u32 sw_int_count;
struct hlist_head tc_flower_fltr_list;
__le64 nvm_phy_type_lo; /* NVM PHY type low */
__le64 nvm_phy_type_hi; /* NVM PHY type high */
struct ice_link_default_override_tlv link_dflt_override;
......
......@@ -233,6 +233,7 @@ struct ice_aqc_get_sw_cfg_resp_elem {
*/
#define ICE_AQC_RES_TYPE_VSI_LIST_REP 0x03
#define ICE_AQC_RES_TYPE_VSI_LIST_PRUNE 0x04
#define ICE_AQC_RES_TYPE_RECIPE 0x05
#define ICE_AQC_RES_TYPE_FDIR_COUNTER_BLOCK 0x21
#define ICE_AQC_RES_TYPE_FDIR_GUARANTEED_ENTRIES 0x22
#define ICE_AQC_RES_TYPE_FDIR_SHARED_ENTRIES 0x23
......@@ -241,6 +242,7 @@ struct ice_aqc_get_sw_cfg_resp_elem {
#define ICE_AQC_RES_TYPE_HASH_PROF_BLDR_PROFID 0x60
#define ICE_AQC_RES_TYPE_HASH_PROF_BLDR_TCAM 0x61
#define ICE_AQC_RES_TYPE_FLAG_SHARED BIT(7)
#define ICE_AQC_RES_TYPE_FLAG_SCAN_BOTTOM BIT(12)
#define ICE_AQC_RES_TYPE_FLAG_IGNORE_INDEX BIT(13)
......@@ -474,6 +476,53 @@ struct ice_aqc_vsi_props {
#define ICE_MAX_NUM_RECIPES 64
/* Add/Get Recipe (indirect 0x0290/0x0292) */
struct ice_aqc_add_get_recipe {
__le16 num_sub_recipes; /* Input in Add cmd, Output in Get cmd */
__le16 return_index; /* Input, used for Get cmd only */
u8 reserved[4];
__le32 addr_high;
__le32 addr_low;
};
struct ice_aqc_recipe_content {
u8 rid;
#define ICE_AQ_RECIPE_ID_IS_ROOT BIT(7)
#define ICE_AQ_SW_ID_LKUP_IDX 0
u8 lkup_indx[5];
#define ICE_AQ_RECIPE_LKUP_IGNORE BIT(7)
#define ICE_AQ_SW_ID_LKUP_MASK 0x00FF
__le16 mask[5];
u8 result_indx;
#define ICE_AQ_RECIPE_RESULT_DATA_S 0
#define ICE_AQ_RECIPE_RESULT_DATA_M (0x3F << ICE_AQ_RECIPE_RESULT_DATA_S)
#define ICE_AQ_RECIPE_RESULT_EN BIT(7)
u8 rsvd0[3];
u8 act_ctrl_join_priority;
u8 act_ctrl_fwd_priority;
u8 act_ctrl;
#define ICE_AQ_RECIPE_ACT_INV_ACT BIT(2)
u8 rsvd1;
__le32 dflt_act;
};
struct ice_aqc_recipe_data_elem {
u8 recipe_indx;
u8 resp_bits;
u8 rsvd0[2];
u8 recipe_bitmap[8];
u8 rsvd1[4];
struct ice_aqc_recipe_content content;
u8 rsvd2[20];
};
/* Set/Get Recipes to Profile Association (direct 0x0291/0x0293) */
struct ice_aqc_recipe_to_profile {
__le16 profile_id;
u8 rsvd[6];
DECLARE_BITMAP(recipe_assoc, ICE_MAX_NUM_RECIPES);
};
/* Add/Update/Remove/Get switch rules (indirect 0x02A0, 0x02A1, 0x02A2, 0x02A3)
*/
struct ice_aqc_sw_rules {
......@@ -1936,6 +1985,8 @@ struct ice_aq_desc {
struct ice_aqc_set_port_id_led set_port_id_led;
struct ice_aqc_get_sw_cfg get_sw_conf;
struct ice_aqc_sw_rules sw_rules;
struct ice_aqc_add_get_recipe add_get_recipe;
struct ice_aqc_recipe_to_profile recipe_to_profile;
struct ice_aqc_get_topo get_topo;
struct ice_aqc_sched_elem_cmd sched_elem_cmd;
struct ice_aqc_query_txsched_res query_sched_res;
......@@ -2044,6 +2095,12 @@ enum ice_adminq_opc {
ice_aqc_opc_update_vsi = 0x0211,
ice_aqc_opc_free_vsi = 0x0213,
/* recipe commands */
ice_aqc_opc_add_recipe = 0x0290,
ice_aqc_opc_recipe_to_profile = 0x0291,
ice_aqc_opc_get_recipe = 0x0292,
ice_aqc_opc_get_recipe_to_profile = 0x0293,
/* switch rules population commands */
ice_aqc_opc_add_sw_rules = 0x02A0,
ice_aqc_opc_update_sw_rules = 0x02A1,
......
......@@ -568,6 +568,7 @@ static enum ice_status ice_init_fltr_mgmt_struct(struct ice_hw *hw)
return ICE_ERR_NO_MEMORY;
INIT_LIST_HEAD(&sw->vsi_list_map_head);
sw->prof_res_bm_init = 0;
status = ice_init_def_sw_recp(hw);
if (status) {
......@@ -594,17 +595,42 @@ static void ice_cleanup_fltr_mgmt_struct(struct ice_hw *hw)
list_del(&v_pos_map->list_entry);
devm_kfree(ice_hw_to_dev(hw), v_pos_map);
}
recps = hw->switch_info->recp_list;
for (i = 0; i < ICE_SW_LKUP_LAST; i++) {
struct ice_fltr_mgmt_list_entry *lst_itr, *tmp_entry;
recps = sw->recp_list;
for (i = 0; i < ICE_MAX_NUM_RECIPES; i++) {
struct ice_recp_grp_entry *rg_entry, *tmprg_entry;
recps[i].root_rid = i;
list_for_each_entry_safe(rg_entry, tmprg_entry,
&recps[i].rg_list, l_entry) {
list_del(&rg_entry->l_entry);
devm_kfree(ice_hw_to_dev(hw), rg_entry);
}
if (recps[i].adv_rule) {
struct ice_adv_fltr_mgmt_list_entry *tmp_entry;
struct ice_adv_fltr_mgmt_list_entry *lst_itr;
mutex_destroy(&recps[i].filt_rule_lock);
list_for_each_entry_safe(lst_itr, tmp_entry,
&recps[i].filt_rules, list_entry) {
&recps[i].filt_rules,
list_entry) {
list_del(&lst_itr->list_entry);
devm_kfree(ice_hw_to_dev(hw), lst_itr->lkups);
devm_kfree(ice_hw_to_dev(hw), lst_itr);
}
} else {
struct ice_fltr_mgmt_list_entry *lst_itr, *tmp_entry;
mutex_destroy(&recps[i].filt_rule_lock);
list_for_each_entry_safe(lst_itr, tmp_entry,
&recps[i].filt_rules,
list_entry) {
list_del(&lst_itr->list_entry);
devm_kfree(ice_hw_to_dev(hw), lst_itr);
}
}
if (recps[i].root_buf)
devm_kfree(ice_hw_to_dev(hw), recps[i].root_buf);
}
ice_rm_all_sw_replay_rule_info(hw);
devm_kfree(ice_hw_to_dev(hw), sw->recp_list);
......
......@@ -7,6 +7,7 @@
#include "ice_fltr.h"
#include "ice_repr.h"
#include "ice_devlink.h"
#include "ice_tc_lib.h"
/**
* ice_eswitch_setup_env - configure switchdev HW filters
......@@ -645,6 +646,8 @@ int ice_eswitch_rebuild(struct ice_pf *pf)
ice_eswitch_remap_rings_to_vectors(pf);
ice_replay_tc_fltrs(pf);
status = ice_vsi_open(ctrl_vsi);
if (status)
return status;
......
......@@ -735,7 +735,7 @@ static void ice_release_global_cfg_lock(struct ice_hw *hw)
*
* This function will request ownership of the change lock.
*/
static enum ice_status
enum ice_status
ice_acquire_change_lock(struct ice_hw *hw, enum ice_aq_res_access_type access)
{
return ice_acquire_res(hw, ICE_CHANGE_LOCK_RES_ID, access,
......@@ -748,7 +748,7 @@ ice_acquire_change_lock(struct ice_hw *hw, enum ice_aq_res_access_type access)
*
* This function will release the change lock using the proper Admin Command.
*/
static void ice_release_change_lock(struct ice_hw *hw)
void ice_release_change_lock(struct ice_hw *hw)
{
ice_release_res(hw, ICE_CHANGE_LOCK_RES_ID);
}
......@@ -1329,6 +1329,86 @@ ice_chk_pkg_compat(struct ice_hw *hw, struct ice_pkg_hdr *ospkg,
return status;
}
/**
* ice_sw_fv_handler
* @sect_type: section type
* @section: pointer to section
* @index: index of the field vector entry to be returned
* @offset: ptr to variable that receives the offset in the field vector table
*
* This is a callback function that can be passed to ice_pkg_enum_entry.
* This function treats the given section as of type ice_sw_fv_section and
* enumerates offset field. "offset" is an index into the field vector table.
*/
static void *
ice_sw_fv_handler(u32 sect_type, void *section, u32 index, u32 *offset)
{
struct ice_sw_fv_section *fv_section = section;
if (!section || sect_type != ICE_SID_FLD_VEC_SW)
return NULL;
if (index >= le16_to_cpu(fv_section->count))
return NULL;
if (offset)
/* "index" passed in to this function is relative to a given
* 4k block. To get to the true index into the field vector
* table need to add the relative index to the base_offset
* field of this section
*/
*offset = le16_to_cpu(fv_section->base_offset) + index;
return fv_section->fv + index;
}
/**
* ice_get_prof_index_max - get the max profile index for used profile
* @hw: pointer to the HW struct
*
* Calling this function will get the max profile index for used profile
* and store the index number in struct ice_switch_info *switch_info
* in HW for following use.
*/
static enum ice_status ice_get_prof_index_max(struct ice_hw *hw)
{
u16 prof_index = 0, j, max_prof_index = 0;
struct ice_pkg_enum state;
struct ice_seg *ice_seg;
bool flag = false;
struct ice_fv *fv;
u32 offset;
memset(&state, 0, sizeof(state));
if (!hw->seg)
return ICE_ERR_PARAM;
ice_seg = hw->seg;
do {
fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW,
&offset, ice_sw_fv_handler);
if (!fv)
break;
ice_seg = NULL;
/* in the profile that not be used, the prot_id is set to 0xff
* and the off is set to 0x1ff for all the field vectors.
*/
for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++)
if (fv->ew[j].prot_id != ICE_PROT_INVALID ||
fv->ew[j].off != ICE_FV_OFFSET_INVAL)
flag = true;
if (flag && prof_index > max_prof_index)
max_prof_index = prof_index;
prof_index++;
flag = false;
} while (fv);
hw->switch_info->max_used_prof_index = max_prof_index;
return 0;
}
/**
* ice_init_pkg - initialize/download package
* @hw: pointer to the hardware structure
......@@ -1408,6 +1488,7 @@ enum ice_status ice_init_pkg(struct ice_hw *hw, u8 *buf, u32 len)
*/
ice_init_pkg_regs(hw);
ice_fill_blk_tbls(hw);
ice_get_prof_index_max(hw);
} else {
ice_debug(hw, ICE_DBG_INIT, "package load failed, %d\n",
status);
......@@ -1484,6 +1565,167 @@ static struct ice_buf_build *ice_pkg_buf_alloc(struct ice_hw *hw)
return bld;
}
/**
* ice_get_sw_fv_bitmap - Get switch field vector bitmap based on profile type
* @hw: pointer to hardware structure
* @req_profs: type of profiles requested
* @bm: pointer to memory for returning the bitmap of field vectors
*/
void
ice_get_sw_fv_bitmap(struct ice_hw *hw, enum ice_prof_type req_profs,
unsigned long *bm)
{
struct ice_pkg_enum state;
struct ice_seg *ice_seg;
struct ice_fv *fv;
if (req_profs == ICE_PROF_ALL) {
bitmap_set(bm, 0, ICE_MAX_NUM_PROFILES);
return;
}
memset(&state, 0, sizeof(state));
bitmap_zero(bm, ICE_MAX_NUM_PROFILES);
ice_seg = hw->seg;
do {
u32 offset;
fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW,
&offset, ice_sw_fv_handler);
ice_seg = NULL;
if (fv) {
if (req_profs & ICE_PROF_NON_TUN)
set_bit((u16)offset, bm);
}
} while (fv);
}
/**
* ice_get_sw_fv_list
* @hw: pointer to the HW structure
* @prot_ids: field vector to search for with a given protocol ID
* @ids_cnt: lookup/protocol count
* @bm: bitmap of field vectors to consider
* @fv_list: Head of a list
*
* Finds all the field vector entries from switch block that contain
* a given protocol ID and returns a list of structures of type
* "ice_sw_fv_list_entry". Every structure in the list has a field vector
* definition and profile ID information
* NOTE: The caller of the function is responsible for freeing the memory
* allocated for every list entry.
*/
enum ice_status
ice_get_sw_fv_list(struct ice_hw *hw, u8 *prot_ids, u16 ids_cnt,
unsigned long *bm, struct list_head *fv_list)
{
struct ice_sw_fv_list_entry *fvl;
struct ice_sw_fv_list_entry *tmp;
struct ice_pkg_enum state;
struct ice_seg *ice_seg;
struct ice_fv *fv;
u32 offset;
memset(&state, 0, sizeof(state));
if (!ids_cnt || !hw->seg)
return ICE_ERR_PARAM;
ice_seg = hw->seg;
do {
u16 i;
fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW,
&offset, ice_sw_fv_handler);
if (!fv)
break;
ice_seg = NULL;
/* If field vector is not in the bitmap list, then skip this
* profile.
*/
if (!test_bit((u16)offset, bm))
continue;
for (i = 0; i < ids_cnt; i++) {
int j;
/* This code assumes that if a switch field vector line
* has a matching protocol, then this line will contain
* the entries necessary to represent every field in
* that protocol header.
*/
for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++)
if (fv->ew[j].prot_id == prot_ids[i])
break;
if (j >= hw->blk[ICE_BLK_SW].es.fvw)
break;
if (i + 1 == ids_cnt) {
fvl = devm_kzalloc(ice_hw_to_dev(hw),
sizeof(*fvl), GFP_KERNEL);
if (!fvl)
goto err;
fvl->fv_ptr = fv;
fvl->profile_id = offset;
list_add(&fvl->list_entry, fv_list);
break;
}
}
} while (fv);
if (list_empty(fv_list))
return ICE_ERR_CFG;
return 0;
err:
list_for_each_entry_safe(fvl, tmp, fv_list, list_entry) {
list_del(&fvl->list_entry);
devm_kfree(ice_hw_to_dev(hw), fvl);
}
return ICE_ERR_NO_MEMORY;
}
/**
* ice_init_prof_result_bm - Initialize the profile result index bitmap
* @hw: pointer to hardware structure
*/
void ice_init_prof_result_bm(struct ice_hw *hw)
{
struct ice_pkg_enum state;
struct ice_seg *ice_seg;
struct ice_fv *fv;
memset(&state, 0, sizeof(state));
if (!hw->seg)
return;
ice_seg = hw->seg;
do {
u32 off;
u16 i;
fv = ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW,
&off, ice_sw_fv_handler);
ice_seg = NULL;
if (!fv)
break;
bitmap_zero(hw->switch_info->prof_res_bm[off],
ICE_MAX_FV_WORDS);
/* Determine empty field vector indices, these can be
* used for recipe results. Skip index 0, since it is
* always used for Switch ID.
*/
for (i = 1; i < ICE_MAX_FV_WORDS; i++)
if (fv->ew[i].prot_id == ICE_PROT_INVALID &&
fv->ew[i].off == ICE_FV_OFFSET_INVAL)
set_bit(i, hw->switch_info->prof_res_bm[off]);
} while (fv);
}
/**
* ice_pkg_buf_free
* @hw: pointer to the HW structure
......@@ -1863,6 +2105,35 @@ int ice_udp_tunnel_unset_port(struct net_device *netdev, unsigned int table,
return 0;
}
/**
* ice_find_prot_off - find prot ID and offset pair, based on prof and FV index
* @hw: pointer to the hardware structure
* @blk: hardware block
* @prof: profile ID
* @fv_idx: field vector word index
* @prot: variable to receive the protocol ID
* @off: variable to receive the protocol offset
*/
enum ice_status
ice_find_prot_off(struct ice_hw *hw, enum ice_block blk, u8 prof, u16 fv_idx,
u8 *prot, u16 *off)
{
struct ice_fv_word *fv_ext;
if (prof >= hw->blk[blk].es.count)
return ICE_ERR_PARAM;
if (fv_idx >= hw->blk[blk].es.fvw)
return ICE_ERR_PARAM;
fv_ext = hw->blk[blk].es.t + (prof * hw->blk[blk].es.fvw);
*prot = fv_ext[fv_idx].prot_id;
*off = fv_ext[fv_idx].off;
return 0;
}
/* PTG Management */
/**
......
......@@ -18,6 +18,20 @@
#define ICE_PKG_CNT 4
enum ice_status
ice_acquire_change_lock(struct ice_hw *hw, enum ice_aq_res_access_type access);
void ice_release_change_lock(struct ice_hw *hw);
enum ice_status
ice_find_prot_off(struct ice_hw *hw, enum ice_block blk, u8 prof, u16 fv_idx,
u8 *prot, u16 *off);
void
ice_get_sw_fv_bitmap(struct ice_hw *hw, enum ice_prof_type type,
unsigned long *bm);
void
ice_init_prof_result_bm(struct ice_hw *hw);
enum ice_status
ice_get_sw_fv_list(struct ice_hw *hw, u8 *prot_ids, u16 ids_cnt,
unsigned long *bm, struct list_head *fv_list);
bool
ice_get_open_tunnel_port(struct ice_hw *hw, u16 *port);
int ice_udp_tunnel_set_port(struct net_device *netdev, unsigned int table,
......
......@@ -13,6 +13,8 @@ struct ice_fv_word {
u8 resvrd;
} __packed;
#define ICE_MAX_NUM_PROFILES 256
#define ICE_MAX_FV_WORDS 48
struct ice_fv {
struct ice_fv_word ew[ICE_MAX_FV_WORDS];
......@@ -279,6 +281,12 @@ struct ice_sw_fv_section {
struct ice_fv fv[];
};
struct ice_sw_fv_list_entry {
struct list_head list_entry;
u32 profile_id;
struct ice_fv *fv_ptr;
};
/* The BOOST TCAM stores the match packet header in reverse order, meaning
* the fields are reversed; in addition, this means that the normally big endian
* fields of the packet are now little endian.
......@@ -603,4 +611,9 @@ struct ice_chs_chg {
};
#define ICE_FLOW_PTYPE_MAX ICE_XLT1_CNT
enum ice_prof_type {
ICE_PROF_NON_TUN = 0x1,
ICE_PROF_ALL = 0xFF,
};
#endif /* _ICE_FLEX_TYPE_H_ */
......@@ -453,6 +453,133 @@ static u32 ice_fltr_build_action(u16 vsi_id)
ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_VALID_BIT;
}
/**
* ice_fltr_find_adv_entry - find advanced rule
* @rules: list of rules
* @rule_id: id of wanted rule
*/
static struct ice_adv_fltr_mgmt_list_entry *
ice_fltr_find_adv_entry(struct list_head *rules, u16 rule_id)
{
struct ice_adv_fltr_mgmt_list_entry *entry;
list_for_each_entry(entry, rules, list_entry) {
if (entry->rule_info.fltr_rule_id == rule_id)
return entry;
}
return NULL;
}
/**
* ice_fltr_update_adv_rule_flags - update flags on advanced rule
* @vsi: pointer to VSI
* @recipe_id: id of recipe
* @entry: advanced rule entry
* @new_flags: flags to update
*/
static enum ice_status
ice_fltr_update_adv_rule_flags(struct ice_vsi *vsi, u16 recipe_id,
struct ice_adv_fltr_mgmt_list_entry *entry,
u32 new_flags)
{
struct ice_adv_rule_info *info = &entry->rule_info;
struct ice_sw_act_ctrl *act = &info->sw_act;
u32 action;
if (act->fltr_act != ICE_FWD_TO_VSI)
return ICE_ERR_NOT_SUPPORTED;
action = ice_fltr_build_action(act->fwd_id.hw_vsi_id);
return ice_fltr_update_rule_flags(&vsi->back->hw, info->fltr_rule_id,
recipe_id, action, info->sw_act.flag,
act->src, new_flags);
}
/**
* ice_fltr_find_regular_entry - find regular rule
* @rules: list of rules
* @rule_id: id of wanted rule
*/
static struct ice_fltr_mgmt_list_entry *
ice_fltr_find_regular_entry(struct list_head *rules, u16 rule_id)
{
struct ice_fltr_mgmt_list_entry *entry;
list_for_each_entry(entry, rules, list_entry) {
if (entry->fltr_info.fltr_rule_id == rule_id)
return entry;
}
return NULL;
}
/**
* ice_fltr_update_regular_rule - update flags on regular rule
* @vsi: pointer to VSI
* @recipe_id: id of recipe
* @entry: regular rule entry
* @new_flags: flags to update
*/
static enum ice_status
ice_fltr_update_regular_rule(struct ice_vsi *vsi, u16 recipe_id,
struct ice_fltr_mgmt_list_entry *entry,
u32 new_flags)
{
struct ice_fltr_info *info = &entry->fltr_info;
u32 action;
if (info->fltr_act != ICE_FWD_TO_VSI)
return ICE_ERR_NOT_SUPPORTED;
action = ice_fltr_build_action(info->fwd_id.hw_vsi_id);
return ice_fltr_update_rule_flags(&vsi->back->hw, info->fltr_rule_id,
recipe_id, action, info->flag,
info->src, new_flags);
}
/**
* ice_fltr_update_flags - update flags on rule
* @vsi: pointer to VSI
* @rule_id: id of rule
* @recipe_id: id of recipe
* @new_flags: flags to update
*
* Function updates flags on regular and advance rule.
*
* Flags should be a combination of ICE_SINGLE_ACT_LB_ENABLE and
* ICE_SINGLE_ACT_LAN_ENABLE.
*/
enum ice_status
ice_fltr_update_flags(struct ice_vsi *vsi, u16 rule_id, u16 recipe_id,
u32 new_flags)
{
struct ice_adv_fltr_mgmt_list_entry *adv_entry;
struct ice_fltr_mgmt_list_entry *regular_entry;
struct ice_hw *hw = &vsi->back->hw;
struct ice_sw_recipe *recp_list;
struct list_head *fltr_rules;
recp_list = &hw->switch_info->recp_list[recipe_id];
if (!recp_list)
return ICE_ERR_DOES_NOT_EXIST;
fltr_rules = &recp_list->filt_rules;
regular_entry = ice_fltr_find_regular_entry(fltr_rules, rule_id);
if (regular_entry)
return ice_fltr_update_regular_rule(vsi, recipe_id,
regular_entry, new_flags);
adv_entry = ice_fltr_find_adv_entry(fltr_rules, rule_id);
if (adv_entry)
return ice_fltr_update_adv_rule_flags(vsi, recipe_id,
adv_entry, new_flags);
return ICE_ERR_DOES_NOT_EXIST;
}
/**
* ice_fltr_update_flags_dflt_rule - update flags on default rule
* @vsi: pointer to VSI
......
......@@ -20,6 +20,7 @@
#define CREATE_TRACE_POINTS
#include "ice_trace.h"
#include "ice_eswitch.h"
#include "ice_tc_lib.h"
#define DRV_SUMMARY "Intel(R) Ethernet Connection E800 Series Linux Driver"
static const char ice_driver_string[] = DRV_SUMMARY;
......@@ -3107,6 +3108,9 @@ static void ice_set_netdev_features(struct net_device *netdev)
/* enable features */
netdev->features |= netdev->hw_features;
netdev->hw_features |= NETIF_F_HW_TC;
/* encap and VLAN devices inherit default, csumo and tso features */
netdev->hw_enc_features |= dflt_features | csumo_features |
tso_features;
......@@ -7069,6 +7073,72 @@ static void ice_tx_timeout(struct net_device *netdev, unsigned int txqueue)
pf->tx_timeout_recovery_level++;
}
/**
* ice_setup_tc_cls_flower - flower classifier offloads
* @np: net device to configure
* @filter_dev: device on which filter is added
* @cls_flower: offload data
*/
static int
ice_setup_tc_cls_flower(struct ice_netdev_priv *np,
struct net_device *filter_dev,
struct flow_cls_offload *cls_flower)
{
struct ice_vsi *vsi = np->vsi;
if (cls_flower->common.chain_index)
return -EOPNOTSUPP;
switch (cls_flower->command) {
case FLOW_CLS_REPLACE:
return ice_add_cls_flower(filter_dev, vsi, cls_flower);
case FLOW_CLS_DESTROY:
return ice_del_cls_flower(vsi, cls_flower);
default:
return -EINVAL;
}
}
/**
* ice_setup_tc_block_cb - callback handler registered for TC block
* @type: TC SETUP type
* @type_data: TC flower offload data that contains user input
* @cb_priv: netdev private data
*/
static int
ice_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv)
{
struct ice_netdev_priv *np = cb_priv;
switch (type) {
case TC_SETUP_CLSFLOWER:
return ice_setup_tc_cls_flower(np, np->vsi->netdev,
type_data);
default:
return -EOPNOTSUPP;
}
}
static LIST_HEAD(ice_block_cb_list);
static int
ice_setup_tc(struct net_device *netdev, enum tc_setup_type type,
void *type_data)
{
struct ice_netdev_priv *np = netdev_priv(netdev);
switch (type) {
case TC_SETUP_BLOCK:
return flow_block_cb_setup_simple(type_data,
&ice_block_cb_list,
ice_setup_tc_block_cb,
np, np, true);
default:
return -EOPNOTSUPP;
}
return -EOPNOTSUPP;
}
/**
* ice_open - Called when a network interface becomes active
* @netdev: network interface device structure
......@@ -7273,6 +7343,7 @@ static const struct net_device_ops ice_netdev_ops = {
.ndo_get_vf_stats = ice_get_vf_stats,
.ndo_vlan_rx_add_vid = ice_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = ice_vlan_rx_kill_vid,
.ndo_setup_tc = ice_setup_tc,
.ndo_set_features = ice_set_features,
.ndo_bridge_getlink = ice_bridge_getlink,
.ndo_bridge_setlink = ice_bridge_setlink,
......
......@@ -3,6 +3,44 @@
#ifndef _ICE_PROTOCOL_TYPE_H_
#define _ICE_PROTOCOL_TYPE_H_
#define ICE_IPV6_ADDR_LENGTH 16
/* Each recipe can match up to 5 different fields. Fields to match can be meta-
* data, values extracted from packet headers, or results from other recipes.
* One of the 5 fields is reserved for matching the switch ID. So, up to 4
* recipes can provide intermediate results to another one through chaining,
* e.g. recipes 0, 1, 2, and 3 can provide intermediate results to recipe 4.
*/
#define ICE_NUM_WORDS_RECIPE 4
/* Max recipes that can be chained */
#define ICE_MAX_CHAIN_RECIPE 5
/* 1 word reserved for switch ID from allowed 5 words.
* So a recipe can have max 4 words. And you can chain 5 such recipes
* together. So maximum words that can be programmed for look up is 5 * 4.
*/
#define ICE_MAX_CHAIN_WORDS (ICE_NUM_WORDS_RECIPE * ICE_MAX_CHAIN_RECIPE)
/* Field vector index corresponding to chaining */
#define ICE_CHAIN_FV_INDEX_START 47
enum ice_protocol_type {
ICE_MAC_OFOS = 0,
ICE_MAC_IL,
ICE_ETYPE_OL,
ICE_VLAN_OFOS,
ICE_IPV4_OFOS,
ICE_IPV4_IL,
ICE_IPV6_OFOS,
ICE_IPV6_IL,
ICE_TCP_IL,
ICE_UDP_OF,
ICE_UDP_ILOS,
ICE_SCTP_IL,
ICE_PROTOCOL_LAST
};
/* Decoders for ice_prot_id:
* - F: First
* - I: Inner
......@@ -35,4 +73,135 @@ enum ice_prot_id {
ICE_PROT_META_ID = 255, /* when offset == metadata */
ICE_PROT_INVALID = 255 /* when offset == ICE_FV_OFFSET_INVAL */
};
#define ICE_MAC_OFOS_HW 1
#define ICE_MAC_IL_HW 4
#define ICE_ETYPE_OL_HW 9
#define ICE_VLAN_OF_HW 16
#define ICE_VLAN_OL_HW 17
#define ICE_IPV4_OFOS_HW 32
#define ICE_IPV4_IL_HW 33
#define ICE_IPV6_OFOS_HW 40
#define ICE_IPV6_IL_HW 41
#define ICE_TCP_IL_HW 49
#define ICE_UDP_ILOS_HW 53
#define ICE_UDP_OF_HW 52 /* UDP Tunnels */
#define ICE_TUN_FLAG_FV_IND 2
/* Mapping of software defined protocol ID to hardware defined protocol ID */
struct ice_protocol_entry {
enum ice_protocol_type type;
u8 protocol_id;
};
struct ice_ether_hdr {
u8 dst_addr[ETH_ALEN];
u8 src_addr[ETH_ALEN];
};
struct ice_ethtype_hdr {
__be16 ethtype_id;
};
struct ice_ether_vlan_hdr {
u8 dst_addr[ETH_ALEN];
u8 src_addr[ETH_ALEN];
__be32 vlan_id;
};
struct ice_vlan_hdr {
__be16 type;
__be16 vlan;
};
struct ice_ipv4_hdr {
u8 version;
u8 tos;
__be16 total_length;
__be16 id;
__be16 frag_off;
u8 time_to_live;
u8 protocol;
__be16 check;
__be32 src_addr;
__be32 dst_addr;
};
struct ice_ipv6_hdr {
__be32 be_ver_tc_flow;
__be16 payload_len;
u8 next_hdr;
u8 hop_limit;
u8 src_addr[ICE_IPV6_ADDR_LENGTH];
u8 dst_addr[ICE_IPV6_ADDR_LENGTH];
};
struct ice_sctp_hdr {
__be16 src_port;
__be16 dst_port;
__be32 verification_tag;
__be32 check;
};
struct ice_l4_hdr {
__be16 src_port;
__be16 dst_port;
__be16 len;
__be16 check;
};
union ice_prot_hdr {
struct ice_ether_hdr eth_hdr;
struct ice_ethtype_hdr ethertype;
struct ice_vlan_hdr vlan_hdr;
struct ice_ipv4_hdr ipv4_hdr;
struct ice_ipv6_hdr ipv6_hdr;
struct ice_l4_hdr l4_hdr;
struct ice_sctp_hdr sctp_hdr;
};
/* This is mapping table entry that maps every word within a given protocol
* structure to the real byte offset as per the specification of that
* protocol header.
* for e.g. dst address is 3 words in ethertype header and corresponding bytes
* are 0, 2, 3 in the actual packet header and src address is at 4, 6, 8
*/
struct ice_prot_ext_tbl_entry {
enum ice_protocol_type prot_type;
/* Byte offset into header of given protocol type */
u8 offs[sizeof(union ice_prot_hdr)];
};
/* Extractions to be looked up for a given recipe */
struct ice_prot_lkup_ext {
u16 prot_type;
u8 n_val_words;
/* create a buffer to hold max words per recipe */
u16 field_off[ICE_MAX_CHAIN_WORDS];
u16 field_mask[ICE_MAX_CHAIN_WORDS];
struct ice_fv_word fv_words[ICE_MAX_CHAIN_WORDS];
/* Indicate field offsets that have field vector indices assigned */
DECLARE_BITMAP(done, ICE_MAX_CHAIN_WORDS);
};
struct ice_pref_recipe_group {
u8 n_val_pairs; /* Number of valid pairs */
struct ice_fv_word pairs[ICE_NUM_WORDS_RECIPE];
u16 mask[ICE_NUM_WORDS_RECIPE];
};
struct ice_recp_grp_entry {
struct list_head l_entry;
#define ICE_INVAL_CHAIN_IND 0xFF
u16 rid;
u8 chain_idx;
u16 fv_idx[ICE_NUM_WORDS_RECIPE];
u16 fv_mask[ICE_NUM_WORDS_RECIPE];
struct ice_pref_recipe_group r_group;
};
#endif /* _ICE_PROTOCOL_TYPE_H_ */
......@@ -5,6 +5,7 @@
#include "ice_eswitch.h"
#include "ice_devlink.h"
#include "ice_virtchnl_pf.h"
#include "ice_tc_lib.h"
/**
* ice_repr_get_sw_port_id - get port ID associated with representor
......@@ -141,6 +142,55 @@ ice_repr_get_devlink_port(struct net_device *netdev)
return &repr->vf->devlink_port;
}
static int
ice_repr_setup_tc_cls_flower(struct ice_repr *repr,
struct flow_cls_offload *flower)
{
switch (flower->command) {
case FLOW_CLS_REPLACE:
return ice_add_cls_flower(repr->netdev, repr->src_vsi, flower);
case FLOW_CLS_DESTROY:
return ice_del_cls_flower(repr->src_vsi, flower);
default:
return -EINVAL;
}
}
static int
ice_repr_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
void *cb_priv)
{
struct flow_cls_offload *flower = (struct flow_cls_offload *)type_data;
struct ice_netdev_priv *np = (struct ice_netdev_priv *)cb_priv;
switch (type) {
case TC_SETUP_CLSFLOWER:
return ice_repr_setup_tc_cls_flower(np->repr, flower);
default:
return -EOPNOTSUPP;
}
}
static LIST_HEAD(ice_repr_block_cb_list);
static int
ice_repr_setup_tc(struct net_device *netdev, enum tc_setup_type type,
void *type_data)
{
struct ice_netdev_priv *np = netdev_priv(netdev);
switch (type) {
case TC_SETUP_BLOCK:
return flow_block_cb_setup_simple((struct flow_block_offload *)
type_data,
&ice_repr_block_cb_list,
ice_repr_setup_tc_block_cb,
np, np, true);
default:
return -EOPNOTSUPP;
}
}
static const struct net_device_ops ice_repr_netdev_ops = {
.ndo_get_phys_port_name = ice_repr_get_phys_port_name,
.ndo_get_stats64 = ice_repr_get_stats64,
......@@ -148,6 +198,7 @@ static const struct net_device_ops ice_repr_netdev_ops = {
.ndo_stop = ice_repr_stop,
.ndo_start_xmit = ice_eswitch_port_start_xmit,
.ndo_get_devlink_port = ice_repr_get_devlink_port,
.ndo_setup_tc = ice_repr_setup_tc,
};
/**
......@@ -170,6 +221,8 @@ ice_repr_reg_netdev(struct net_device *netdev)
netdev->netdev_ops = &ice_repr_netdev_ops;
ice_set_ethtool_repr_ops(netdev);
netdev->hw_features |= NETIF_F_HW_TC;
netif_carrier_off(netdev);
netif_tx_stop_all_queues(netdev);
......
This diff is collapsed.
......@@ -125,30 +125,110 @@ struct ice_fltr_info {
u8 lan_en; /* Indicate if packet can be forwarded to the uplink */
};
struct ice_adv_lkup_elem {
enum ice_protocol_type type;
union ice_prot_hdr h_u; /* Header values */
union ice_prot_hdr m_u; /* Mask of header values to match */
};
struct ice_sw_act_ctrl {
/* Source VSI for LOOKUP_TX or source port for LOOKUP_RX */
u16 src;
u16 flag;
enum ice_sw_fwd_act_type fltr_act;
/* Depending on filter action */
union {
/* This is a queue ID in case of ICE_FWD_TO_Q and starting
* queue ID in case of ICE_FWD_TO_QGRP.
*/
u16 q_id:11;
u16 vsi_id:10;
u16 hw_vsi_id:10;
u16 vsi_list_id:10;
} fwd_id;
/* software VSI handle */
u16 vsi_handle;
u8 qgrp_size;
};
struct ice_rule_query_data {
/* Recipe ID for which the requested rule was added */
u16 rid;
/* Rule ID that was added or is supposed to be removed */
u16 rule_id;
/* vsi_handle for which Rule was added or is supposed to be removed */
u16 vsi_handle;
};
struct ice_adv_rule_info {
struct ice_sw_act_ctrl sw_act;
u32 priority;
u8 rx; /* true means LOOKUP_RX otherwise LOOKUP_TX */
u16 fltr_rule_id;
};
/* A collection of one or more four word recipe */
struct ice_sw_recipe {
struct list_head l_entry;
/* For a chained recipe the root recipe is what should be used for
* programming rules
*/
u8 is_root;
u8 root_rid;
u8 recp_created;
/* To protect modification of filt_rule list
* defined below
/* Number of extraction words */
u8 n_ext_words;
/* Protocol ID and Offset pair (extraction word) to describe the
* recipe
*/
struct mutex filt_rule_lock;
struct ice_fv_word ext_words[ICE_MAX_CHAIN_WORDS];
u16 word_masks[ICE_MAX_CHAIN_WORDS];
/* if this recipe is a collection of other recipe */
u8 big_recp;
/* List of type ice_fltr_mgmt_list_entry */
/* if this recipe is part of another bigger recipe then chain index
* corresponding to this recipe
*/
u8 chain_idx;
/* if this recipe is a collection of other recipe then count of other
* recipes and recipe IDs of those recipes
*/
u8 n_grp_count;
/* Bit map specifying the IDs associated with this group of recipe */
DECLARE_BITMAP(r_bitmap, ICE_MAX_NUM_RECIPES);
/* List of type ice_fltr_mgmt_list_entry or adv_rule */
u8 adv_rule;
struct list_head filt_rules;
struct list_head filt_replay_rules;
/* linked list of type recipe_list_entry */
struct list_head rg_list;
/* linked list of type ice_sw_fv_list_entry*/
struct mutex filt_rule_lock; /* protect filter rule structure */
/* Profiles this recipe should be associated with */
struct list_head fv_list;
struct ice_aqc_recipe_data_elem *r_buf;
u8 recp_count;
u8 root_rid;
u8 num_profs;
u8 *prof_ids;
/* recipe bitmap: what all recipes makes this recipe */
DECLARE_BITMAP(r_bitmap, ICE_MAX_NUM_RECIPES);
/* Profiles this recipe is associated with */
u8 num_profs, *prof_ids;
/* Bit map for possible result indexes */
DECLARE_BITMAP(res_idxs, ICE_MAX_FV_WORDS);
/* This allows user to specify the recipe priority.
* For now, this becomes 'fwd_priority' when recipe
* is created, usually recipes can have 'fwd' and 'join'
* priority.
*/
u8 priority;
struct list_head rg_list;
/* AQ buffer associated with this recipe */
struct ice_aqc_recipe_data_elem *root_buf;
/* This struct saves the fv_words for a given lookup */
struct ice_prot_lkup_ext lkup_exts;
};
/* Bookkeeping structure to hold bitmap of VSIs corresponding to VSI list ID */
......@@ -186,6 +266,16 @@ struct ice_fltr_mgmt_list_entry {
u8 counter_index;
};
struct ice_adv_fltr_mgmt_list_entry {
struct list_head list_entry;
struct ice_adv_lkup_elem *lkups;
struct ice_adv_rule_info rule_info;
u16 lkups_cnt;
struct ice_vsi_list_map_info *vsi_list_info;
u16 vsi_count;
};
enum ice_promisc_flags {
ICE_PROMISC_UCAST_RX = 0x1,
ICE_PROMISC_UCAST_TX = 0x2,
......@@ -221,6 +311,10 @@ ice_free_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,
u16 counter_id);
/* Switch/bridge related commands */
enum ice_status
ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
u16 lkups_cnt, struct ice_adv_rule_info *rinfo,
struct ice_rule_query_data *added_entry);
enum ice_status ice_update_sw_rule_bridge_mode(struct ice_hw *hw);
enum ice_status ice_add_mac(struct ice_hw *hw, struct list_head *m_lst);
enum ice_status ice_remove_mac(struct ice_hw *hw, struct list_head *m_lst);
......@@ -248,6 +342,12 @@ enum ice_status
ice_set_vlan_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask,
bool rm_vlan_promisc);
enum ice_status
ice_rem_adv_rule_for_vsi(struct ice_hw *hw, u16 vsi_handle);
enum ice_status
ice_rem_adv_rule_by_id(struct ice_hw *hw,
struct ice_rule_query_data *remove_entry);
enum ice_status ice_init_def_sw_recp(struct ice_hw *hw);
u16 ice_get_hw_vsi_num(struct ice_hw *hw, u16 vsi_handle);
......
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2019-2021, Intel Corporation. */
#ifndef _ICE_TC_LIB_H_
#define _ICE_TC_LIB_H_
#define ICE_TC_FLWR_FIELD_DST_MAC BIT(0)
#define ICE_TC_FLWR_FIELD_SRC_MAC BIT(1)
#define ICE_TC_FLWR_FIELD_VLAN BIT(2)
#define ICE_TC_FLWR_FIELD_DEST_IPV4 BIT(3)
#define ICE_TC_FLWR_FIELD_SRC_IPV4 BIT(4)
#define ICE_TC_FLWR_FIELD_DEST_IPV6 BIT(5)
#define ICE_TC_FLWR_FIELD_SRC_IPV6 BIT(6)
#define ICE_TC_FLWR_FIELD_DEST_L4_PORT BIT(7)
#define ICE_TC_FLWR_FIELD_SRC_L4_PORT BIT(8)
#define ICE_TC_FLWR_FIELD_TENANT_ID BIT(9)
#define ICE_TC_FLWR_FIELD_ENC_DEST_IPV4 BIT(10)
#define ICE_TC_FLWR_FIELD_ENC_SRC_IPV4 BIT(11)
#define ICE_TC_FLWR_FIELD_ENC_DEST_IPV6 BIT(12)
#define ICE_TC_FLWR_FIELD_ENC_SRC_IPV6 BIT(13)
#define ICE_TC_FLWR_FIELD_ENC_DEST_L4_PORT BIT(14)
#define ICE_TC_FLWR_FIELD_ENC_SRC_L4_PORT BIT(15)
#define ICE_TC_FLWR_FIELD_ENC_DST_MAC BIT(16)
#define ICE_TC_FLWR_FIELD_ETH_TYPE_ID BIT(17)
struct ice_tc_flower_action {
u32 tc_class;
enum ice_sw_fwd_act_type fltr_act;
};
struct ice_tc_vlan_hdr {
__be16 vlan_id; /* Only last 12 bits valid */
u16 vlan_prio; /* Only last 3 bits valid (valid values: 0..7) */
};
struct ice_tc_l2_hdr {
u8 dst_mac[ETH_ALEN];
u8 src_mac[ETH_ALEN];
__be16 n_proto; /* Ethernet Protocol */
};
struct ice_tc_l3_hdr {
u8 ip_proto; /* IPPROTO value */
union {
struct {
struct in_addr dst_ip;
struct in_addr src_ip;
} v4;
struct {
struct in6_addr dst_ip6;
struct in6_addr src_ip6;
} v6;
} ip;
#define dst_ipv6 ip.v6.dst_ip6.s6_addr32
#define dst_ipv6_addr ip.v6.dst_ip6.s6_addr
#define src_ipv6 ip.v6.src_ip6.s6_addr32
#define src_ipv6_addr ip.v6.src_ip6.s6_addr
#define dst_ipv4 ip.v4.dst_ip.s_addr
#define src_ipv4 ip.v4.src_ip.s_addr
u8 tos;
u8 ttl;
};
struct ice_tc_l4_hdr {
__be16 dst_port;
__be16 src_port;
};
struct ice_tc_flower_lyr_2_4_hdrs {
/* L2 layer fields with their mask */
struct ice_tc_l2_hdr l2_key;
struct ice_tc_l2_hdr l2_mask;
struct ice_tc_vlan_hdr vlan_hdr;
/* L3 (IPv4[6]) layer fields with their mask */
struct ice_tc_l3_hdr l3_key;
struct ice_tc_l3_hdr l3_mask;
/* L4 layer fields with their mask */
struct ice_tc_l4_hdr l4_key;
struct ice_tc_l4_hdr l4_mask;
};
enum ice_eswitch_fltr_direction {
ICE_ESWITCH_FLTR_INGRESS,
ICE_ESWITCH_FLTR_EGRESS,
};
struct ice_tc_flower_fltr {
struct hlist_node tc_flower_node;
/* cookie becomes filter_rule_id if rule is added successfully */
unsigned long cookie;
/* add_adv_rule returns information like recipe ID, rule_id. Store
* those values since they are needed to remove advanced rule
*/
u16 rid;
u16 rule_id;
/* this could be queue/vsi_idx (sw handle)/queue_group, depending upon
* destination type
*/
u16 dest_id;
/* if dest_id is vsi_idx, then need to store destination VSI ptr */
struct ice_vsi *dest_vsi;
/* direction of fltr for eswitch use case */
enum ice_eswitch_fltr_direction direction;
/* Parsed TC flower configuration params */
struct ice_tc_flower_lyr_2_4_hdrs outer_headers;
struct ice_tc_flower_lyr_2_4_hdrs inner_headers;
struct ice_vsi *src_vsi;
__be32 tenant_id;
u32 flags;
struct ice_tc_flower_action action;
/* cache ptr which is used wherever needed to communicate netlink
* messages
*/
struct netlink_ext_ack *extack;
};
int
ice_add_cls_flower(struct net_device *netdev, struct ice_vsi *vsi,
struct flow_cls_offload *cls_flower);
int
ice_del_cls_flower(struct ice_vsi *vsi, struct flow_cls_offload *cls_flower);
void ice_replay_tc_fltrs(struct ice_pf *pf);
#endif /* _ICE_TC_LIB_H_ */
......@@ -677,6 +677,10 @@ struct ice_port_info {
struct ice_switch_info {
struct list_head vsi_list_map_head;
struct ice_sw_recipe *recp_list;
u16 prof_res_bm_init;
u16 max_used_prof_index;
DECLARE_BITMAP(prof_res_bm[ICE_MAX_NUM_PROFILES], ICE_MAX_FV_WORDS);
};
/* FW logging configuration */
......
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