Commit 31ad4e4e authored by Tony Nguyen's avatar Tony Nguyen Committed by Jeff Kirsher

ice: Allocate flow profile

Create an extraction sequence based on the packet header protocols to be
programmed and allocate a flow profile for the extraction sequence.
Signed-off-by: default avatarTony Nguyen <anthony.l.nguyen@intel.com>
Signed-off-by: default avatarHenry Tieman <henry.w.tieman@intel.com>
Tested-by: default avatarAndrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent c90ed40c
......@@ -232,6 +232,12 @@ struct ice_aqc_get_sw_cfg_resp {
*/
#define ICE_AQC_RES_TYPE_VSI_LIST_REP 0x03
#define ICE_AQC_RES_TYPE_VSI_LIST_PRUNE 0x04
#define ICE_AQC_RES_TYPE_HASH_PROF_BLDR_PROFID 0x60
#define ICE_AQC_RES_TYPE_FLAG_SCAN_BOTTOM BIT(12)
#define ICE_AQC_RES_TYPE_FLAG_IGNORE_INDEX BIT(13)
#define ICE_AQC_RES_TYPE_FLAG_DEDICATED 0x00
/* Allocate Resources command (indirect 0x0208)
* Free Resources command (indirect 0x0209)
......
......@@ -1497,6 +1497,81 @@ void ice_release_res(struct ice_hw *hw, enum ice_aq_res_ids res)
}
}
/**
* ice_aq_alloc_free_res - command to allocate/free resources
* @hw: pointer to the HW struct
* @num_entries: number of resource entries in buffer
* @buf: Indirect buffer to hold data parameters and response
* @buf_size: size of buffer for indirect commands
* @opc: pass in the command opcode
* @cd: pointer to command details structure or NULL
*
* Helper function to allocate/free resources using the admin queue commands
*/
enum ice_status
ice_aq_alloc_free_res(struct ice_hw *hw, u16 num_entries,
struct ice_aqc_alloc_free_res_elem *buf, u16 buf_size,
enum ice_adminq_opc opc, struct ice_sq_cd *cd)
{
struct ice_aqc_alloc_free_res_cmd *cmd;
struct ice_aq_desc desc;
cmd = &desc.params.sw_res_ctrl;
if (!buf)
return ICE_ERR_PARAM;
if (buf_size < (num_entries * sizeof(buf->elem[0])))
return ICE_ERR_PARAM;
ice_fill_dflt_direct_cmd_desc(&desc, opc);
desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
cmd->num_entries = cpu_to_le16(num_entries);
return ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
}
/**
* ice_alloc_hw_res - allocate resource
* @hw: pointer to the HW struct
* @type: type of resource
* @num: number of resources to allocate
* @btm: allocate from bottom
* @res: pointer to array that will receive the resources
*/
enum ice_status
ice_alloc_hw_res(struct ice_hw *hw, u16 type, u16 num, bool btm, u16 *res)
{
struct ice_aqc_alloc_free_res_elem *buf;
enum ice_status status;
u16 buf_len;
buf_len = struct_size(buf, elem, num - 1);
buf = kzalloc(buf_len, GFP_KERNEL);
if (!buf)
return ICE_ERR_NO_MEMORY;
/* Prepare buffer to allocate resource. */
buf->num_elems = cpu_to_le16(num);
buf->res_type = cpu_to_le16(type | ICE_AQC_RES_TYPE_FLAG_DEDICATED |
ICE_AQC_RES_TYPE_FLAG_IGNORE_INDEX);
if (btm)
buf->res_type |= cpu_to_le16(ICE_AQC_RES_TYPE_FLAG_SCAN_BOTTOM);
status = ice_aq_alloc_free_res(hw, 1, buf, buf_len,
ice_aqc_opc_alloc_res, NULL);
if (status)
goto ice_alloc_res_exit;
memcpy(res, buf->elem, sizeof(buf->elem) * num);
ice_alloc_res_exit:
kfree(buf);
return status;
}
/**
* ice_get_num_per_func - determine number of resources per PF
* @hw: pointer to the HW structure
......
......@@ -34,10 +34,16 @@ enum ice_status
ice_acquire_res(struct ice_hw *hw, enum ice_aq_res_ids res,
enum ice_aq_res_access_type access, u32 timeout);
void ice_release_res(struct ice_hw *hw, enum ice_aq_res_ids res);
enum ice_status
ice_alloc_hw_res(struct ice_hw *hw, u16 type, u16 num, bool btm, u16 *res);
enum ice_status ice_init_nvm(struct ice_hw *hw);
enum ice_status
ice_read_sr_buf(struct ice_hw *hw, u16 offset, u16 *words, u16 *data);
enum ice_status
ice_aq_alloc_free_res(struct ice_hw *hw, u16 num_entries,
struct ice_aqc_alloc_free_res_elem *buf, u16 buf_size,
enum ice_adminq_opc opc, struct ice_sq_cd *cd);
enum ice_status
ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq,
struct ice_aq_desc *desc, void *buf, u16 buf_size,
struct ice_sq_cd *cd);
......
......@@ -1118,6 +1118,117 @@ ice_vsig_add_mv_vsi(struct ice_hw *hw, enum ice_block blk, u16 vsi, u16 vsig)
return 0;
}
/**
* ice_find_prof_id - find profile ID for a given field vector
* @hw: pointer to the hardware structure
* @blk: HW block
* @fv: field vector to search for
* @prof_id: receives the profile ID
*/
static enum ice_status
ice_find_prof_id(struct ice_hw *hw, enum ice_block blk,
struct ice_fv_word *fv, u8 *prof_id)
{
struct ice_es *es = &hw->blk[blk].es;
u16 off, i;
for (i = 0; i < es->count; i++) {
off = i * es->fvw;
if (memcmp(&es->t[off], fv, es->fvw * sizeof(*fv)))
continue;
*prof_id = i;
return 0;
}
return ICE_ERR_DOES_NOT_EXIST;
}
/**
* ice_prof_id_rsrc_type - get profile ID resource type for a block type
* @blk: the block type
* @rsrc_type: pointer to variable to receive the resource type
*/
static bool ice_prof_id_rsrc_type(enum ice_block blk, u16 *rsrc_type)
{
switch (blk) {
case ICE_BLK_RSS:
*rsrc_type = ICE_AQC_RES_TYPE_HASH_PROF_BLDR_PROFID;
break;
default:
return false;
}
return true;
}
/**
* ice_alloc_prof_id - allocate profile ID
* @hw: pointer to the HW struct
* @blk: the block to allocate the profile ID for
* @prof_id: pointer to variable to receive the profile ID
*
* This function allocates a new profile ID, which also corresponds to a Field
* Vector (Extraction Sequence) entry.
*/
static enum ice_status
ice_alloc_prof_id(struct ice_hw *hw, enum ice_block blk, u8 *prof_id)
{
enum ice_status status;
u16 res_type;
u16 get_prof;
if (!ice_prof_id_rsrc_type(blk, &res_type))
return ICE_ERR_PARAM;
status = ice_alloc_hw_res(hw, res_type, 1, false, &get_prof);
if (!status)
*prof_id = (u8)get_prof;
return status;
}
/**
* ice_prof_inc_ref - increment reference count for profile
* @hw: pointer to the HW struct
* @blk: the block from which to free the profile ID
* @prof_id: the profile ID for which to increment the reference count
*/
static enum ice_status
ice_prof_inc_ref(struct ice_hw *hw, enum ice_block blk, u8 prof_id)
{
if (prof_id > hw->blk[blk].es.count)
return ICE_ERR_PARAM;
hw->blk[blk].es.ref_count[prof_id]++;
return 0;
}
/**
* ice_write_es - write an extraction sequence to hardware
* @hw: pointer to the HW struct
* @blk: the block in which to write the extraction sequence
* @prof_id: the profile ID to write
* @fv: pointer to the extraction sequence to write - NULL to clear extraction
*/
static void
ice_write_es(struct ice_hw *hw, enum ice_block blk, u8 prof_id,
struct ice_fv_word *fv)
{
u16 off;
off = prof_id * hw->blk[blk].es.fvw;
if (!fv) {
memset(&hw->blk[blk].es.t[off], 0,
hw->blk[blk].es.fvw * sizeof(*fv));
hw->blk[blk].es.written[prof_id] = false;
} else {
memcpy(&hw->blk[blk].es.t[off], fv,
hw->blk[blk].es.fvw * sizeof(*fv));
}
}
/* Block / table section IDs */
static const u32 ice_blk_sids[ICE_BLK_COUNT][ICE_SID_OFF_COUNT] = {
/* SWITCH */
......@@ -1576,3 +1687,108 @@ enum ice_status ice_init_hw_tbls(struct ice_hw *hw)
ice_free_hw_tbls(hw);
return ICE_ERR_NO_MEMORY;
}
/**
* ice_add_prof - add profile
* @hw: pointer to the HW struct
* @blk: hardware block
* @id: profile tracking ID
* @ptypes: array of bitmaps indicating ptypes (ICE_FLOW_PTYPE_MAX bits)
* @es: extraction sequence (length of array is determined by the block)
*
* This function registers a profile, which matches a set of PTGs with a
* particular extraction sequence. While the hardware profile is allocated
* it will not be written until the first call to ice_add_flow that specifies
* the ID value used here.
*/
enum ice_status
ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[],
struct ice_fv_word *es)
{
u32 bytes = DIV_ROUND_UP(ICE_FLOW_PTYPE_MAX, BITS_PER_BYTE);
DECLARE_BITMAP(ptgs_used, ICE_XLT1_CNT);
struct ice_prof_map *prof;
enum ice_status status;
u32 byte = 0;
u8 prof_id;
bitmap_zero(ptgs_used, ICE_XLT1_CNT);
mutex_lock(&hw->blk[blk].es.prof_map_lock);
/* search for existing profile */
status = ice_find_prof_id(hw, blk, es, &prof_id);
if (status) {
/* allocate profile ID */
status = ice_alloc_prof_id(hw, blk, &prof_id);
if (status)
goto err_ice_add_prof;
/* and write new es */
ice_write_es(hw, blk, prof_id, es);
}
ice_prof_inc_ref(hw, blk, prof_id);
/* add profile info */
prof = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*prof), GFP_KERNEL);
if (!prof)
goto err_ice_add_prof;
prof->profile_cookie = id;
prof->prof_id = prof_id;
prof->ptg_cnt = 0;
prof->context = 0;
/* build list of ptgs */
while (bytes && prof->ptg_cnt < ICE_MAX_PTG_PER_PROFILE) {
u32 bit;
if (!ptypes[byte]) {
bytes--;
byte++;
continue;
}
/* Examine 8 bits per byte */
for_each_set_bit(bit, (unsigned long *)&ptypes[byte],
BITS_PER_BYTE) {
u16 ptype;
u8 ptg;
u8 m;
ptype = byte * BITS_PER_BYTE + bit;
/* The package should place all ptypes in a non-zero
* PTG, so the following call should never fail.
*/
if (ice_ptg_find_ptype(hw, blk, ptype, &ptg))
continue;
/* If PTG is already added, skip and continue */
if (test_bit(ptg, ptgs_used))
continue;
set_bit(ptg, ptgs_used);
prof->ptg[prof->ptg_cnt] = ptg;
if (++prof->ptg_cnt >= ICE_MAX_PTG_PER_PROFILE)
break;
/* nothing left in byte, then exit */
m = ~((1 << (bit + 1)) - 1);
if (!(ptypes[byte] & m))
break;
}
bytes--;
byte++;
}
list_add(&prof->list, &hw->blk[blk].es.prof_map);
status = 0;
err_ice_add_prof:
mutex_unlock(&hw->blk[blk].es.prof_map_lock);
return status;
}
......@@ -18,6 +18,9 @@
#define ICE_PKG_CNT 4
enum ice_status
ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[],
struct ice_fv_word *es);
enum ice_status ice_init_pkg(struct ice_hw *hw, u8 *buff, u32 len);
enum ice_status
ice_copy_and_init_pkg(struct ice_hw *hw, const u8 *buf, u32 len);
......
......@@ -3,6 +3,9 @@
#ifndef _ICE_FLEX_TYPE_H_
#define _ICE_FLEX_TYPE_H_
#define ICE_FV_OFFSET_INVAL 0x1FF
/* Extraction Sequence (Field Vector) Table */
struct ice_fv_word {
u8 prot_id;
......@@ -280,6 +283,17 @@ struct ice_ptg_ptype {
u8 ptg;
};
#define ICE_MAX_PTG_PER_PROFILE 32
struct ice_prof_map {
struct list_head list;
u64 profile_cookie;
u64 context;
u8 prof_id;
u8 ptg_cnt;
u8 ptg[ICE_MAX_PTG_PER_PROFILE];
};
struct ice_vsig_entry {
struct list_head prop_lst;
struct ice_vsig_vsi *first_vsi;
......@@ -371,4 +385,5 @@ struct ice_blk_info {
u8 is_list_init;
};
#define ICE_FLOW_PTYPE_MAX ICE_XLT1_CNT
#endif /* _ICE_FLEX_TYPE_H_ */
This diff is collapsed.
......@@ -56,7 +56,13 @@ enum ice_flow_field {
ICE_FLOW_FIELD_IDX_MAX
};
enum ice_flow_dir {
ICE_FLOW_RX = 0x02,
};
#define ICE_FLOW_SEG_MAX 2
#define ICE_FLOW_FV_EXTRACT_SZ 2
#define ICE_FLOW_SET_HDRS(seg, val) ((seg)->hdrs |= (u32)(val))
struct ice_flow_seg_xtrct {
......@@ -99,6 +105,23 @@ struct ice_flow_seg_info {
struct ice_flow_fld_info fields[ICE_FLOW_FIELD_IDX_MAX];
};
struct ice_flow_prof {
struct list_head l_entry;
u64 id;
enum ice_flow_dir dir;
u8 segs_cnt;
/* Keep track of flow entries associated with this flow profile */
struct mutex entries_lock;
struct list_head entries;
struct ice_flow_seg_info segs[ICE_FLOW_SEG_MAX];
/* software VSI handles referenced by this flow profile */
DECLARE_BITMAP(vsis, ICE_MAX_VSI);
};
struct ice_rss_cfg {
struct list_head l_entry;
/* bitmap of VSIs added to the RSS entry */
......
......@@ -199,6 +199,14 @@ enum ice_rxdid {
/* Receive Flex Descriptor Rx opcode values */
#define ICE_RX_OPC_MDID 0x01
/* Receive Descriptor MDID values that access packet flags */
enum ice_flex_mdid_pkt_flags {
ICE_RX_MDID_PKT_FLAGS_15_0 = 20,
ICE_RX_MDID_PKT_FLAGS_31_16,
ICE_RX_MDID_PKT_FLAGS_47_32,
ICE_RX_MDID_PKT_FLAGS_63_48,
};
/* Receive Descriptor MDID values */
enum ice_flex_rx_mdid {
ICE_RX_MDID_FLOW_ID_LOWER = 5,
......
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2019, Intel Corporation. */
#ifndef _ICE_PROTOCOL_TYPE_H_
#define _ICE_PROTOCOL_TYPE_H_
/* Decoders for ice_prot_id:
* - F: First
* - I: Inner
* - L: Last
* - O: Outer
* - S: Single
*/
enum ice_prot_id {
ICE_PROT_ID_INVAL = 0,
ICE_PROT_IPV4_OF_OR_S = 32,
ICE_PROT_IPV4_IL = 33,
ICE_PROT_IPV6_OF_OR_S = 40,
ICE_PROT_IPV6_IL = 41,
ICE_PROT_TCP_IL = 49,
ICE_PROT_UDP_IL_OR_S = 53,
ICE_PROT_META_ID = 255, /* when offset == metadata */
ICE_PROT_INVALID = 255 /* when offset == ICE_FV_OFFSET_INVAL */
};
#endif /* _ICE_PROTOCOL_TYPE_H_ */
......@@ -49,42 +49,6 @@ static const u8 dummy_eth_header[DUMMY_ETH_HDR_LEN] = { 0x2, 0, 0, 0, 0, 0,
sizeof(((struct ice_sw_rule_vsi_list *)0)->vsi) + \
((n) * sizeof(((struct ice_sw_rule_vsi_list *)0)->vsi)))
/**
* ice_aq_alloc_free_res - command to allocate/free resources
* @hw: pointer to the HW struct
* @num_entries: number of resource entries in buffer
* @buf: Indirect buffer to hold data parameters and response
* @buf_size: size of buffer for indirect commands
* @opc: pass in the command opcode
* @cd: pointer to command details structure or NULL
*
* Helper function to allocate/free resources using the admin queue commands
*/
static enum ice_status
ice_aq_alloc_free_res(struct ice_hw *hw, u16 num_entries,
struct ice_aqc_alloc_free_res_elem *buf, u16 buf_size,
enum ice_adminq_opc opc, struct ice_sq_cd *cd)
{
struct ice_aqc_alloc_free_res_cmd *cmd;
struct ice_aq_desc desc;
cmd = &desc.params.sw_res_ctrl;
if (!buf)
return ICE_ERR_PARAM;
if (buf_size < (num_entries * sizeof(buf->elem[0])))
return ICE_ERR_PARAM;
ice_fill_dflt_direct_cmd_desc(&desc, opc);
desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
cmd->num_entries = cpu_to_le16(num_entries);
return ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
}
/**
* ice_init_def_sw_recp - initialize the recipe book keeping tables
* @hw: pointer to the HW struct
......
......@@ -13,6 +13,7 @@
#include "ice_controlq.h"
#include "ice_lan_tx_rx.h"
#include "ice_flex_type.h"
#include "ice_protocol_type.h"
static inline bool ice_is_tc_ena(unsigned long bitmap, u8 tc)
{
......@@ -41,6 +42,7 @@ static inline u32 ice_round_to_num(u32 N, u32 R)
#define ICE_DBG_QCTX BIT_ULL(6)
#define ICE_DBG_NVM BIT_ULL(7)
#define ICE_DBG_LAN BIT_ULL(8)
#define ICE_DBG_FLOW BIT_ULL(9)
#define ICE_DBG_SW BIT_ULL(13)
#define ICE_DBG_SCHED BIT_ULL(14)
#define ICE_DBG_PKG BIT_ULL(16)
......
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