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

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
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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,
};
+86 −27
Original line number Diff line number Diff line
@@ -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;