Skip to content

Commit

Permalink
ice: Enable writing hardware filtering tables
Browse files Browse the repository at this point in the history
Enable the driver to write the filtering hardware tables to allow for
changing of RSS rules. Upon loading of DDP package, a minimal configuration
should be written to hardware.

Introduce and initialize structures for storing configuration and make
the top level calls to configure the RSS tables to initial values. A packet
segment will be created but nothing is written to hardware yet.

Signed-off-by: Tony Nguyen <[email protected]>
Signed-off-by: Henry Tieman <[email protected]>
Tested-by: Andrew Bowers <[email protected]>
Signed-off-by: Jeff Kirsher <[email protected]>
  • Loading branch information
anguy11 authored and Jeff Kirsher committed Jan 24, 2020
1 parent 08a45c5 commit c90ed40
Show file tree
Hide file tree
Showing 7 changed files with 491 additions and 4 deletions.
3 changes: 2 additions & 1 deletion drivers/net/ethernet/intel/ice/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ ice-y := ice_main.o \
ice_lib.o \
ice_txrx_lib.o \
ice_txrx.o \
ice_flex_pipe.o \
ice_flex_pipe.o \
ice_flow.o \
ice_ethtool.o
ice-$(CONFIG_PCI_IOV) += ice_virtchnl_pf.o ice_sriov.o
ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
Expand Down
6 changes: 5 additions & 1 deletion drivers/net/ethernet/intel/ice/ice_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "ice_common.h"
#include "ice_sched.h"
#include "ice_adminq_cmd.h"
#include "ice_flow.h"

#define ICE_PF_RESET_WAIT_COUNT 200

Expand Down Expand Up @@ -3406,7 +3407,10 @@ enum ice_status ice_replay_vsi(struct ice_hw *hw, u16 vsi_handle)
if (status)
return status;
}

/* Replay per VSI all RSS configurations */
status = ice_replay_rss_cfg(hw, vsi_handle);
if (status)
return status;
/* Replay per VSI all filters */
status = ice_replay_vsi_all_fltr(hw, vsi_handle);
return status;
Expand Down
31 changes: 30 additions & 1 deletion drivers/net/ethernet/intel/ice/ice_flex_pipe.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "ice_common.h"
#include "ice_flex_pipe.h"
#include "ice_flow.h"

/**
* ice_pkg_val_buf
Expand Down Expand Up @@ -1379,11 +1380,18 @@ void ice_fill_blk_tbls(struct ice_hw *hw)
*/
void ice_free_hw_tbls(struct ice_hw *hw)
{
struct ice_rss_cfg *r, *rt;
u8 i;

for (i = 0; i < ICE_BLK_COUNT; i++) {
hw->blk[i].is_list_init = false;
if (hw->blk[i].is_list_init) {
struct ice_es *es = &hw->blk[i].es;

mutex_destroy(&es->prof_map_lock);
mutex_destroy(&hw->fl_profs_locks[i]);

hw->blk[i].is_list_init = false;
}
devm_kfree(ice_hw_to_dev(hw), hw->blk[i].xlt1.ptypes);
devm_kfree(ice_hw_to_dev(hw), hw->blk[i].xlt1.ptg_tbl);
devm_kfree(ice_hw_to_dev(hw), hw->blk[i].xlt1.t);
Expand All @@ -1397,9 +1405,25 @@ void ice_free_hw_tbls(struct ice_hw *hw)
devm_kfree(ice_hw_to_dev(hw), hw->blk[i].es.written);
}

list_for_each_entry_safe(r, rt, &hw->rss_list_head, l_entry) {
list_del(&r->l_entry);
devm_kfree(ice_hw_to_dev(hw), r);
}
mutex_destroy(&hw->rss_locks);
memset(hw->blk, 0, sizeof(hw->blk));
}

/**
* ice_init_flow_profs - init flow profile locks and list heads
* @hw: pointer to the hardware structure
* @blk_idx: HW block index
*/
static void ice_init_flow_profs(struct ice_hw *hw, u8 blk_idx)
{
mutex_init(&hw->fl_profs_locks[blk_idx]);
INIT_LIST_HEAD(&hw->fl_profs[blk_idx]);
}

/**
* ice_clear_hw_tbls - clear HW tables and flow profiles
* @hw: pointer to the hardware structure
Expand Down Expand Up @@ -1443,6 +1467,8 @@ enum ice_status ice_init_hw_tbls(struct ice_hw *hw)
{
u8 i;

mutex_init(&hw->rss_locks);
INIT_LIST_HEAD(&hw->rss_list_head);
for (i = 0; i < ICE_BLK_COUNT; i++) {
struct ice_prof_redir *prof_redir = &hw->blk[i].prof_redir;
struct ice_prof_tcam *prof = &hw->blk[i].prof;
Expand All @@ -1454,6 +1480,9 @@ enum ice_status ice_init_hw_tbls(struct ice_hw *hw)
if (hw->blk[i].is_list_init)
continue;

ice_init_flow_profs(hw, i);
mutex_init(&es->prof_map_lock);
INIT_LIST_HEAD(&es->prof_map);
hw->blk[i].is_list_init = true;

hw->blk[i].overwrite = blk_sizes[i].overwrite;
Expand Down
250 changes: 250 additions & 0 deletions drivers/net/ethernet/intel/ice/ice_flow.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2019, Intel Corporation. */

#include "ice_common.h"
#include "ice_flow.h"

/* Describe properties of a protocol header field */
struct ice_flow_field_info {
enum ice_flow_seg_hdr hdr;
s16 off; /* Offset from start of a protocol header, in bits */
u16 size; /* Size of fields in bits */
};

#define ICE_FLOW_FLD_INFO(_hdr, _offset_bytes, _size_bytes) { \
.hdr = _hdr, \
.off = (_offset_bytes) * BITS_PER_BYTE, \
.size = (_size_bytes) * BITS_PER_BYTE, \
}

/* Table containing properties of supported protocol header fields */
static const
struct ice_flow_field_info ice_flds_info[ICE_FLOW_FIELD_IDX_MAX] = {
/* IPv4 / IPv6 */
/* ICE_FLOW_FIELD_IDX_IPV4_SA */
ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_IPV4, 12, sizeof(struct in_addr)),
/* ICE_FLOW_FIELD_IDX_IPV4_DA */
ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_IPV4, 16, sizeof(struct in_addr)),
/* ICE_FLOW_FIELD_IDX_IPV6_SA */
ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_IPV6, 8, sizeof(struct in6_addr)),
/* ICE_FLOW_FIELD_IDX_IPV6_DA */
ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_IPV6, 24, sizeof(struct in6_addr)),
/* Transport */
/* ICE_FLOW_FIELD_IDX_TCP_SRC_PORT */
ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_TCP, 0, sizeof(__be16)),
/* ICE_FLOW_FIELD_IDX_TCP_DST_PORT */
ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_TCP, 2, sizeof(__be16)),
/* ICE_FLOW_FIELD_IDX_UDP_SRC_PORT */
ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_UDP, 0, sizeof(__be16)),
/* ICE_FLOW_FIELD_IDX_UDP_DST_PORT */
ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_UDP, 2, sizeof(__be16)),
};

/**
* ice_flow_set_fld_ext - specifies locations of field from entry's input buffer
* @seg: packet segment the field being set belongs to
* @fld: field to be set
* @type: type of the field
* @val_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of the value to match from
* entry's input buffer
* @mask_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of mask value from entry's
* input buffer
* @last_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of last/upper value from
* entry's input buffer
*
* This helper function stores information of a field being matched, including
* the type of the field and the locations of the value to match, the mask, and
* and the upper-bound value in the start of the input buffer for a flow entry.
* This function should only be used for fixed-size data structures.
*
* This function also opportunistically determines the protocol headers to be
* present based on the fields being set. Some fields cannot be used alone to
* determine the protocol headers present. Sometimes, fields for particular
* protocol headers are not matched. In those cases, the protocol headers
* must be explicitly set.
*/
static void
ice_flow_set_fld_ext(struct ice_flow_seg_info *seg, enum ice_flow_field fld,
enum ice_flow_fld_match_type type, u16 val_loc,
u16 mask_loc, u16 last_loc)
{
u64 bit = BIT_ULL(fld);

seg->match |= bit;
if (type == ICE_FLOW_FLD_TYPE_RANGE)
seg->range |= bit;

seg->fields[fld].type = type;
seg->fields[fld].src.val = val_loc;
seg->fields[fld].src.mask = mask_loc;
seg->fields[fld].src.last = last_loc;

ICE_FLOW_SET_HDRS(seg, ice_flds_info[fld].hdr);
}

/**
* ice_flow_set_fld - specifies locations of field from entry's input buffer
* @seg: packet segment the field being set belongs to
* @fld: field to be set
* @val_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of the value to match from
* entry's input buffer
* @mask_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of mask value from entry's
* input buffer
* @last_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of last/upper value from
* entry's input buffer
* @range: indicate if field being matched is to be in a range
*
* This function specifies the locations, in the form of byte offsets from the
* start of the input buffer for a flow entry, from where the value to match,
* the mask value, and upper value can be extracted. These locations are then
* stored in the flow profile. When adding a flow entry associated with the
* flow profile, these locations will be used to quickly extract the values and
* create the content of a match entry. This function should only be used for
* fixed-size data structures.
*/
static void
ice_flow_set_fld(struct ice_flow_seg_info *seg, enum ice_flow_field fld,
u16 val_loc, u16 mask_loc, u16 last_loc, bool range)
{
enum ice_flow_fld_match_type t = range ?
ICE_FLOW_FLD_TYPE_RANGE : ICE_FLOW_FLD_TYPE_REG;

ice_flow_set_fld_ext(seg, fld, t, val_loc, mask_loc, last_loc);
}

#define ICE_FLOW_RSS_SEG_HDR_L3_MASKS \
(ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_IPV6)

#define ICE_FLOW_RSS_SEG_HDR_L4_MASKS \
(ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_SCTP)

#define ICE_FLOW_RSS_SEG_HDR_VAL_MASKS \
(ICE_FLOW_RSS_SEG_HDR_L3_MASKS | \
ICE_FLOW_RSS_SEG_HDR_L4_MASKS)

/**
* ice_flow_set_rss_seg_info - setup packet segments for RSS
* @segs: pointer to the flow field segment(s)
* @hash_fields: fields to be hashed on for the segment(s)
* @flow_hdr: protocol header fields within a packet segment
*
* Helper function to extract fields from hash bitmap and use flow
* header value to set flow field segment for further use in flow
* profile entry or removal.
*/
static enum ice_status
ice_flow_set_rss_seg_info(struct ice_flow_seg_info *segs, u64 hash_fields,
u32 flow_hdr)
{
u64 val;
u8 i;

for_each_set_bit(i, (unsigned long *)&hash_fields,
ICE_FLOW_FIELD_IDX_MAX)
ice_flow_set_fld(segs, (enum ice_flow_field)i,
ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,
ICE_FLOW_FLD_OFF_INVAL, false);

ICE_FLOW_SET_HDRS(segs, flow_hdr);

if (segs->hdrs & ~ICE_FLOW_RSS_SEG_HDR_VAL_MASKS)
return ICE_ERR_PARAM;

val = (u64)(segs->hdrs & ICE_FLOW_RSS_SEG_HDR_L3_MASKS);
if (val && !is_power_of_2(val))
return ICE_ERR_CFG;

val = (u64)(segs->hdrs & ICE_FLOW_RSS_SEG_HDR_L4_MASKS);
if (val && !is_power_of_2(val))
return ICE_ERR_CFG;

return 0;
}

#define ICE_RSS_OUTER_HEADERS 1

/**
* ice_add_rss_cfg_sync - add an RSS configuration
* @hashed_flds: hash bit fields (ICE_FLOW_HASH_*) to configure
* @addl_hdrs: protocol header fields
* @segs_cnt: packet segment count
*
* Assumption: lock has already been acquired for RSS list
*/
static enum ice_status
ice_add_rss_cfg_sync(u64 hashed_flds, u32 addl_hdrs, u8 segs_cnt)
{
struct ice_flow_seg_info *segs;
enum ice_status status;

if (!segs_cnt || segs_cnt > ICE_FLOW_SEG_MAX)
return ICE_ERR_PARAM;

segs = kcalloc(segs_cnt, sizeof(*segs), GFP_KERNEL);
if (!segs)
return ICE_ERR_NO_MEMORY;

/* Construct the packet segment info from the hashed fields */
status = ice_flow_set_rss_seg_info(&segs[segs_cnt - 1], hashed_flds,
addl_hdrs);

kfree(segs);
return status;
}

/**
* ice_add_rss_cfg - add an RSS configuration with specified hashed fields
* @hw: pointer to the hardware structure
* @vsi_handle: software VSI handle
* @hashed_flds: hash bit fields (ICE_FLOW_HASH_*) to configure
* @addl_hdrs: protocol header fields
*
* This function will generate a flow profile based on fields associated with
* the input fields to hash on, the flow type and use the VSI number to add
* a flow entry to the profile.
*/
enum ice_status
ice_add_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
u32 addl_hdrs)
{
enum ice_status status;

if (hashed_flds == ICE_HASH_INVALID ||
!ice_is_vsi_valid(hw, vsi_handle))
return ICE_ERR_PARAM;

mutex_lock(&hw->rss_locks);
status = ice_add_rss_cfg_sync(hashed_flds, addl_hdrs,
ICE_RSS_OUTER_HEADERS);
mutex_unlock(&hw->rss_locks);

return status;
}

/**
* ice_replay_rss_cfg - replay RSS configurations associated with VSI
* @hw: pointer to the hardware structure
* @vsi_handle: software VSI handle
*/
enum ice_status ice_replay_rss_cfg(struct ice_hw *hw, u16 vsi_handle)
{
enum ice_status status = 0;
struct ice_rss_cfg *r;

if (!ice_is_vsi_valid(hw, vsi_handle))
return ICE_ERR_PARAM;

mutex_lock(&hw->rss_locks);
list_for_each_entry(r, &hw->rss_list_head, l_entry) {
if (test_bit(vsi_handle, r->vsis)) {
status = ice_add_rss_cfg_sync(r->hashed_flds,
r->packet_hdr,
ICE_RSS_OUTER_HEADERS);
if (status)
break;
}
}
mutex_unlock(&hw->rss_locks);

return status;
}
Loading

0 comments on commit c90ed40

Please sign in to comment.