Commit b648366c authored by Jerin Jacob's avatar Jerin Jacob Committed by David S. Miller

octeontx2-af: Add support for dynamic flow cfg to RSS field generation

Introduce state-based algorithm to convert the flow_key value
to RSS algo field used by NIX_AF_RX_FLOW_KEY_ALGX_FIELDX register.

The outer `for loop` goes over _all_ protocol field and the following
variables depict the state machine forward progress logic.

a) keyoff_marker - Enabled when hash byte length needs to be accounted
in field->key_offset update.
b) field_marker - Enabled when a new field needs to be selected.
c) group_member - Enabled when a protocol is part of a group.

This would remove the existing hard coding and enable to add
new protocol support seamlessly.
Signed-off-by: default avatarJerin Jacob <jerinj@marvell.com>
Signed-off-by: default avatarNithin Dabilpuram <ndabilpuram@marvell.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent bd522d68
......@@ -414,6 +414,7 @@ enum nix_af_status {
NIX_AF_INVAL_TXSCHQ_CFG = -412,
NIX_AF_SMQ_FLUSH_FAILED = -413,
NIX_AF_ERR_LF_RESET = -414,
NIX_AF_ERR_RSS_NOSPC_FIELD = -415,
NIX_AF_INVAL_NPA_PF_FUNC = -419,
NIX_AF_INVAL_SSO_PF_FUNC = -420,
};
......
......@@ -1650,80 +1650,139 @@ int rvu_mbox_handler_nix_rss_flowkey_cfg(struct rvu *rvu,
return 0;
}
static void set_flowkey_fields(struct nix_rx_flowkey_alg *alg, u32 flow_cfg)
static int set_flowkey_fields(struct nix_rx_flowkey_alg *alg, u32 flow_cfg)
{
struct nix_rx_flowkey_alg *field = NULL;
int idx, key_type;
int idx, nr_field, key_off, field_marker, keyoff_marker;
int max_key_off, max_bit_pos, group_member;
struct nix_rx_flowkey_alg *field;
struct nix_rx_flowkey_alg tmp;
u32 key_type, valid_key;
if (!alg)
return;
return -EINVAL;
/* FIELD0: IPv4
* FIELD1: IPv6
* FIELD2: TCP/UDP/SCTP/ALL
* FIELD3: Unused
* FIELD4: Unused
*
* Each of the 32 possible flow key algorithm definitions should
#define FIELDS_PER_ALG 5
#define MAX_KEY_OFF 40
/* Clear all fields */
memset(alg, 0, sizeof(uint64_t) * FIELDS_PER_ALG);
/* Each of the 32 possible flow key algorithm definitions should
* fall into above incremental config (except ALG0). Otherwise a
* single NPC MCAM entry is not sufficient for supporting RSS.
*
* If a different definition or combination needed then NPC MCAM
* has to be programmed to filter such pkts and it's action should
* point to this definition to calculate flowtag or hash.
*
* The `for loop` goes over _all_ protocol field and the following
* variables depicts the state machine forward progress logic.
*
* keyoff_marker - Enabled when hash byte length needs to be accounted
* in field->key_offset update.
* field_marker - Enabled when a new field needs to be selected.
* group_member - Enabled when protocol is part of a group.
*/
for (idx = 0; idx < 32; idx++) {
key_type = flow_cfg & BIT_ULL(idx);
if (!key_type)
continue;
keyoff_marker = 0; max_key_off = 0; group_member = 0;
nr_field = 0; key_off = 0; field_marker = 1;
field = &tmp; max_bit_pos = fls(flow_cfg);
for (idx = 0;
idx < max_bit_pos && nr_field < FIELDS_PER_ALG &&
key_off < MAX_KEY_OFF; idx++) {
key_type = BIT(idx);
valid_key = flow_cfg & key_type;
/* Found a field marker, reset the field values */
if (field_marker)
memset(&tmp, 0, sizeof(tmp));
switch (key_type) {
case NIX_FLOW_KEY_TYPE_PORT:
field = &alg[0];
field->sel_chan = true;
/* This should be set to 1, when SEL_CHAN is set */
field->bytesm1 = 1;
field_marker = true;
keyoff_marker = true;
break;
case NIX_FLOW_KEY_TYPE_IPV4:
field = &alg[0];
field->lid = NPC_LID_LC;
field->ltype_match = NPC_LT_LC_IP;
field->hdr_offset = 12; /* SIP offset */
field->bytesm1 = 7; /* SIP + DIP, 8 bytes */
field->ltype_mask = 0xF; /* Match only IPv4 */
field_marker = true;
keyoff_marker = false;
break;
case NIX_FLOW_KEY_TYPE_IPV6:
field = &alg[1];
field->lid = NPC_LID_LC;
field->ltype_match = NPC_LT_LC_IP6;
field->hdr_offset = 8; /* SIP offset */
field->bytesm1 = 31; /* SIP + DIP, 32 bytes */
field->ltype_mask = 0xF; /* Match only IPv6 */
field_marker = true;
keyoff_marker = true;
break;
case NIX_FLOW_KEY_TYPE_TCP:
case NIX_FLOW_KEY_TYPE_UDP:
case NIX_FLOW_KEY_TYPE_SCTP:
field = &alg[2];
field->lid = NPC_LID_LD;
field->bytesm1 = 3; /* Sport + Dport, 4 bytes */
if (key_type == NIX_FLOW_KEY_TYPE_TCP)
if (key_type == NIX_FLOW_KEY_TYPE_TCP && valid_key) {
field->ltype_match |= NPC_LT_LD_TCP;
else if (key_type == NIX_FLOW_KEY_TYPE_UDP)
group_member = true;
} else if (key_type == NIX_FLOW_KEY_TYPE_UDP &&
valid_key) {
field->ltype_match |= NPC_LT_LD_UDP;
else if (key_type == NIX_FLOW_KEY_TYPE_SCTP)
group_member = true;
} else if (key_type == NIX_FLOW_KEY_TYPE_SCTP &&
valid_key) {
field->ltype_match |= NPC_LT_LD_SCTP;
field->key_offset = 32; /* After IPv4/v6 SIP, DIP */
group_member = true;
}
field->ltype_mask = ~field->ltype_match;
if (key_type == NIX_FLOW_KEY_TYPE_SCTP) {
/* Handle the case where any of the group item
* is enabled in the group but not the final one
*/
if (group_member) {
valid_key = true;
group_member = false;
}
field_marker = true;
keyoff_marker = true;
} else {
field_marker = false;
keyoff_marker = false;
}
break;
}
if (field)
field->ena = 1;
field = NULL;
/* Found a valid flow key type */
if (valid_key) {
field->key_offset = key_off;
memcpy(&alg[nr_field], field, sizeof(*field));
max_key_off = max(max_key_off, field->bytesm1 + 1);
/* Found a field marker, get the next field */
if (field_marker)
nr_field++;
}
/* Found a keyoff marker, update the new key_off */
if (keyoff_marker) {
key_off += max_key_off;
max_key_off = 0;
}
}
/* Processed all the flow key types */
if (idx == max_bit_pos && key_off <= MAX_KEY_OFF)
return 0;
else
return NIX_AF_ERR_RSS_NOSPC_FIELD;
}
static void nix_rx_flowkey_alg_cfg(struct rvu *rvu, int blkaddr)
{
#define FIELDS_PER_ALG 5
u64 field[NIX_FLOW_KEY_ALG_MAX][FIELDS_PER_ALG];
u32 flowkey_cfg, minkey_cfg;
int alg, fid;
......
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