net/bnxt: support EM/EEM
- Add TruFlow flow memory support - Exact Match (EM) adds the capability to manage and manipulate data flows using on chip memory. - Extended Exact Match (EEM) behaves similarly to EM, but at a vastly increased scale by using host DDR, with performance trade-off due to the need to access off-chip memory. Signed-off-by: Pete Spreadborough <peter.spreadborough@broadcom.com> Reviewed-by: Randy Schacher <stuart.schacher@broadcom.com> Reviewed-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
This commit is contained in:
parent
dba3ca8b30
commit
69c410b844
@ -51,6 +51,8 @@ SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += tf_core/tf_core.c
|
||||
SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += tf_core/bitalloc.c
|
||||
SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += tf_core/tf_msg.c
|
||||
SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += tf_core/rand.c
|
||||
SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += tf_core/stack.c
|
||||
SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += tf_core/tf_em.c
|
||||
SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += tf_core/tf_rm.c
|
||||
SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += tf_core/tf_tbl.c
|
||||
SRCS-$(CONFIG_RTE_LIBRTE_BNXT_PMD) += tf_core/tfp.c
|
||||
|
162
drivers/net/bnxt/tf_core/lookup3.h
Normal file
162
drivers/net/bnxt/tf_core/lookup3.h
Normal file
@ -0,0 +1,162 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Based on lookup3.c, by Bob Jenkins, May 2006, Public Domain.
|
||||
* http://www.burtleburtle.net/bob/c/lookup3.c
|
||||
*
|
||||
* These functions for producing 32-bit hashes for has table lookup.
|
||||
* hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
|
||||
* are externally useful functions. Routines to test the hash are included
|
||||
* if SELF_TEST is defined. You can use this free for any purpose. It is in
|
||||
* the public domain. It has no warranty.
|
||||
*/
|
||||
|
||||
#ifndef _LOOKUP3_H_
|
||||
#define _LOOKUP3_H_
|
||||
|
||||
#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
|
||||
|
||||
/** -------------------------------------------------------------------------
|
||||
* This is reversible, so any information in (a,b,c) before mix() is
|
||||
* still in (a,b,c) after mix().
|
||||
*
|
||||
* If four pairs of (a,b,c) inputs are run through mix(), or through
|
||||
* mix() in reverse, there are at least 32 bits of the output that
|
||||
* are sometimes the same for one pair and different for another pair.
|
||||
* This was tested for:
|
||||
* pairs that differed by one bit, by two bits, in any combination
|
||||
* of top bits of (a,b,c), or in any combination of bottom bits of
|
||||
* (a,b,c).
|
||||
* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
|
||||
* the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
|
||||
* is commonly produced by subtraction) look like a single 1-bit
|
||||
* difference.
|
||||
* the base values were pseudorandom, all zero but one bit set, or
|
||||
* all zero plus a counter that starts at zero.
|
||||
*
|
||||
* Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
|
||||
* satisfy this are
|
||||
* 4 6 8 16 19 4
|
||||
* 9 15 3 18 27 15
|
||||
* 14 9 3 7 17 3
|
||||
* Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
|
||||
* for "differ" defined as + with a one-bit base and a two-bit delta. I
|
||||
* used http://burtleburtle.net/bob/hash/avalanche.html to choose
|
||||
* the operations, constants, and arrangements of the variables.
|
||||
*
|
||||
* This does not achieve avalanche. There are input bits of (a,b,c)
|
||||
* that fail to affect some output bits of (a,b,c), especially of a. The
|
||||
* most thoroughly mixed value is c, but it doesn't really even achieve
|
||||
* avalanche in c.
|
||||
*
|
||||
* This allows some parallelism. Read-after-writes are good at doubling
|
||||
* the number of bits affected, so the goal of mixing pulls in the opposite
|
||||
* direction as the goal of parallelism. I did what I could. Rotates
|
||||
* seem to cost as much as shifts on every machine I could lay my hands
|
||||
* on, and rotates are much kinder to the top and bottom bits, so I used
|
||||
* rotates.
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
#define mix(a, b, c) \
|
||||
{ \
|
||||
(a) -= (c); (a) ^= rot((c), 4); (c) += b; \
|
||||
(b) -= (a); (b) ^= rot((a), 6); (a) += c; \
|
||||
(c) -= (b); (c) ^= rot((b), 8); (b) += a; \
|
||||
(a) -= (c); (a) ^= rot((c), 16); (c) += b; \
|
||||
(b) -= (a); (b) ^= rot((a), 19); (a) += c; \
|
||||
(c) -= (b); (c) ^= rot((b), 4); (b) += a; \
|
||||
}
|
||||
|
||||
/** --------------------------------------------------------------------------
|
||||
* final -- final mixing of 3 32-bit values (a,b,c) into c
|
||||
*
|
||||
* Pairs of (a,b,c) values differing in only a few bits will usually
|
||||
* produce values of c that look totally different. This was tested for
|
||||
* pairs that differed by one bit, by two bits, in any combination
|
||||
* of top bits of (a,b,c), or in any combination of bottom bits of
|
||||
* (a,b,c).
|
||||
* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
|
||||
* the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
|
||||
* is commonly produced by subtraction) look like a single 1-bit
|
||||
* difference.
|
||||
* the base values were pseudorandom, all zero but one bit set, or
|
||||
* all zero plus a counter that starts at zero.
|
||||
*
|
||||
* These constants passed:
|
||||
* 14 11 25 16 4 14 24
|
||||
* 12 14 25 16 4 14 24
|
||||
* and these came close:
|
||||
* 4 8 15 26 3 22 24
|
||||
* 10 8 15 26 3 22 24
|
||||
* 11 8 15 26 3 22 24
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
#define final(a, b, c) \
|
||||
{ \
|
||||
(c) ^= (b); (c) -= rot((b), 14); \
|
||||
(a) ^= (c); (a) -= rot((c), 11); \
|
||||
(b) ^= (a); (b) -= rot((a), 25); \
|
||||
(c) ^= (b); (c) -= rot((b), 16); \
|
||||
(a) ^= (c); (a) -= rot((c), 4); \
|
||||
(b) ^= (a); (b) -= rot((a), 14); \
|
||||
(c) ^= (b); (c) -= rot((b), 24); \
|
||||
}
|
||||
|
||||
/** --------------------------------------------------------------------
|
||||
* This works on all machines. To be useful, it requires
|
||||
* -- that the key be an array of uint32_t's, and
|
||||
* -- that the length be the number of uint32_t's in the key
|
||||
|
||||
* The function hashword() is identical to hashlittle() on little-endian
|
||||
* machines, and identical to hashbig() on big-endian machines,
|
||||
* except that the length has to be measured in uint32_ts rather than in
|
||||
* bytes. hashlittle() is more complicated than hashword() only because
|
||||
* hashlittle() has to dance around fitting the key bytes into registers.
|
||||
*
|
||||
* Input Parameters:
|
||||
* key: an array of uint32_t values
|
||||
* length: the length of the key, in uint32_ts
|
||||
* initval: the previous hash, or an arbitrary value
|
||||
* --------------------------------------------------------------------
|
||||
*/
|
||||
static inline uint32_t hashword(const uint32_t *k,
|
||||
size_t length,
|
||||
uint32_t initval) {
|
||||
uint32_t a, b, c;
|
||||
int index = 12;
|
||||
|
||||
/* Set up the internal state */
|
||||
a = 0xdeadbeef + (((uint32_t)length) << 2) + initval;
|
||||
b = a;
|
||||
c = a;
|
||||
|
||||
/*-------------------------------------------- handle most of the key */
|
||||
while (length > 3) {
|
||||
a += k[index];
|
||||
b += k[index - 1];
|
||||
c += k[index - 2];
|
||||
mix(a, b, c);
|
||||
length -= 3;
|
||||
index -= 3;
|
||||
}
|
||||
|
||||
/*-------------------------------------- handle the last 3 uint32_t's */
|
||||
switch (length) { /* all the case statements fall through */
|
||||
case 3:
|
||||
c += k[index - 2];
|
||||
/* Falls through. */
|
||||
case 2:
|
||||
b += k[index - 1];
|
||||
/* Falls through. */
|
||||
case 1:
|
||||
a += k[index];
|
||||
final(a, b, c);
|
||||
/* Falls through. */
|
||||
case 0: /* case 0: nothing left to add */
|
||||
/* FALLTHROUGH */
|
||||
break;
|
||||
}
|
||||
/*------------------------------------------------- report the result */
|
||||
return c;
|
||||
}
|
||||
|
||||
#endif /* _LOOKUP3_H_ */
|
107
drivers/net/bnxt/tf_core/stack.c
Normal file
107
drivers/net/bnxt/tf_core/stack.c
Normal file
@ -0,0 +1,107 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright(c) 2019-2020 Broadcom
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include "stack.h"
|
||||
|
||||
#define STACK_EMPTY -1
|
||||
|
||||
/* Initialize stack
|
||||
*/
|
||||
int
|
||||
stack_init(int num_entries, uint32_t *items, struct stack *st)
|
||||
{
|
||||
if (items == NULL || st == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
st->max = num_entries;
|
||||
st->top = STACK_EMPTY;
|
||||
st->items = items;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return the size of the stack
|
||||
*/
|
||||
int32_t
|
||||
stack_size(struct stack *st)
|
||||
{
|
||||
return st->top + 1;
|
||||
}
|
||||
|
||||
/* Check if the stack is empty
|
||||
*/
|
||||
bool
|
||||
stack_is_empty(struct stack *st)
|
||||
{
|
||||
return st->top == STACK_EMPTY;
|
||||
}
|
||||
|
||||
/* Check if the stack is full
|
||||
*/
|
||||
bool
|
||||
stack_is_full(struct stack *st)
|
||||
{
|
||||
return st->top == st->max - 1;
|
||||
}
|
||||
|
||||
/* Add element x to the stack
|
||||
*/
|
||||
int
|
||||
stack_push(struct stack *st, uint32_t x)
|
||||
{
|
||||
if (stack_is_full(st))
|
||||
return -EOVERFLOW;
|
||||
|
||||
/* add an element and increments the top index
|
||||
*/
|
||||
st->items[++st->top] = x;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Pop top element x from the stack and return
|
||||
* in user provided location.
|
||||
*/
|
||||
int
|
||||
stack_pop(struct stack *st, uint32_t *x)
|
||||
{
|
||||
if (stack_is_empty(st))
|
||||
return -ENODATA;
|
||||
|
||||
*x = st->items[st->top];
|
||||
st->top--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Dump the stack
|
||||
*/
|
||||
void stack_dump(struct stack *st)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
printf("top=%d\n", st->top);
|
||||
printf("max=%d\n", st->max);
|
||||
|
||||
if (st->top == -1) {
|
||||
printf("stack is empty\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < st->max + 7 / 8; i++) {
|
||||
printf("item[%d] 0x%08x", i, st->items[i]);
|
||||
|
||||
for (j = 0; j < 7; j++) {
|
||||
if (i++ < st->max - 1)
|
||||
printf(" 0x%08x", st->items[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
107
drivers/net/bnxt/tf_core/stack.h
Normal file
107
drivers/net/bnxt/tf_core/stack.h
Normal file
@ -0,0 +1,107 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright(c) 2019-2020 Broadcom
|
||||
* All rights reserved.
|
||||
*/
|
||||
#ifndef _STACK_H_
|
||||
#define _STACK_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/** Stack data structure
|
||||
*/
|
||||
struct stack {
|
||||
int max; /**< Maximum number of entries */
|
||||
int top; /**< maximum value in stack */
|
||||
uint32_t *items; /**< items in the stack */
|
||||
};
|
||||
|
||||
/** Initialize stack of uint32_t elements
|
||||
*
|
||||
* [in] num_entries
|
||||
* maximum number of elements in the stack
|
||||
*
|
||||
* [in] items
|
||||
* pointer to items (must be sized to (uint32_t * num_entries)
|
||||
*
|
||||
* s[in] st
|
||||
* pointer to the stack structure
|
||||
*
|
||||
* return
|
||||
* 0 for success
|
||||
*/
|
||||
int stack_init(int num_entries,
|
||||
uint32_t *items,
|
||||
struct stack *st);
|
||||
|
||||
/** Return the size of the stack
|
||||
*
|
||||
* [in] st
|
||||
* pointer to the stack
|
||||
*
|
||||
* return
|
||||
* number of elements
|
||||
*/
|
||||
int32_t stack_size(struct stack *st);
|
||||
|
||||
/** Check if the stack is empty
|
||||
*
|
||||
* [in] st
|
||||
* pointer to the stack
|
||||
*
|
||||
* return
|
||||
* true or false
|
||||
*/
|
||||
bool stack_is_empty(struct stack *st);
|
||||
|
||||
/** Check if the stack is full
|
||||
*
|
||||
* [in] st
|
||||
* pointer to the stack
|
||||
*
|
||||
* return
|
||||
* true or false
|
||||
*/
|
||||
bool stack_is_full(struct stack *st);
|
||||
|
||||
/** Add element x to the stack
|
||||
*
|
||||
* [in] st
|
||||
* pointer to the stack
|
||||
*
|
||||
* [in] x
|
||||
* value to push on the stack
|
||||
* return
|
||||
* 0 for success
|
||||
*/
|
||||
int stack_push(struct stack *st, uint32_t x);
|
||||
|
||||
/** Pop top element x from the stack and return
|
||||
* in user provided location.
|
||||
*
|
||||
* [in] st
|
||||
* pointer to the stack
|
||||
*
|
||||
* [in, out] x
|
||||
* pointer to where the value popped will be written
|
||||
*
|
||||
* return
|
||||
* 0 for success
|
||||
*/
|
||||
int stack_pop(struct stack *st, uint32_t *x);
|
||||
|
||||
/** Dump stack information
|
||||
*
|
||||
* Warning: Don't use for large stacks due to prints
|
||||
*
|
||||
* [in] st
|
||||
* pointer to the stack
|
||||
*
|
||||
* return
|
||||
* none
|
||||
*/
|
||||
void stack_dump(struct stack *st);
|
||||
|
||||
#endif /* _STACK_H_ */
|
@ -8,6 +8,7 @@
|
||||
#include "tf_core.h"
|
||||
#include "tf_session.h"
|
||||
#include "tf_tbl.h"
|
||||
#include "tf_em.h"
|
||||
#include "tf_rm.h"
|
||||
#include "tf_msg.h"
|
||||
#include "tfp.h"
|
||||
@ -289,6 +290,55 @@ tf_close_session(struct tf *tfp)
|
||||
return rc_close;
|
||||
}
|
||||
|
||||
/** insert EM hash entry API
|
||||
*
|
||||
* returns:
|
||||
* 0 - Success
|
||||
* -EINVAL - Error
|
||||
*/
|
||||
int tf_insert_em_entry(struct tf *tfp,
|
||||
struct tf_insert_em_entry_parms *parms)
|
||||
{
|
||||
struct tf_tbl_scope_cb *tbl_scope_cb;
|
||||
|
||||
if (tfp == NULL || parms == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
tbl_scope_cb =
|
||||
tbl_scope_cb_find((struct tf_session *)tfp->session->core_data,
|
||||
parms->tbl_scope_id);
|
||||
if (tbl_scope_cb == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
/* Process the EM entry per Table Scope type */
|
||||
return tf_insert_eem_entry((struct tf_session *)tfp->session->core_data,
|
||||
tbl_scope_cb,
|
||||
parms);
|
||||
}
|
||||
|
||||
/** Delete EM hash entry API
|
||||
*
|
||||
* returns:
|
||||
* 0 - Success
|
||||
* -EINVAL - Error
|
||||
*/
|
||||
int tf_delete_em_entry(struct tf *tfp,
|
||||
struct tf_delete_em_entry_parms *parms)
|
||||
{
|
||||
struct tf_tbl_scope_cb *tbl_scope_cb;
|
||||
|
||||
if (tfp == NULL || parms == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
tbl_scope_cb =
|
||||
tbl_scope_cb_find((struct tf_session *)tfp->session->core_data,
|
||||
parms->tbl_scope_id);
|
||||
if (tbl_scope_cb == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
return tf_delete_eem_entry(tfp, parms);
|
||||
}
|
||||
|
||||
/** allocate identifier resource
|
||||
*
|
||||
* Returns success or failure code.
|
||||
|
@ -21,6 +21,10 @@
|
||||
|
||||
/********** BEGIN Truflow Core DEFINITIONS **********/
|
||||
|
||||
|
||||
#define TF_KILOBYTE 1024
|
||||
#define TF_MEGABYTE (1024 * 1024)
|
||||
|
||||
/**
|
||||
* direction
|
||||
*/
|
||||
@ -30,6 +34,27 @@ enum tf_dir {
|
||||
TF_DIR_MAX
|
||||
};
|
||||
|
||||
/**
|
||||
* memory choice
|
||||
*/
|
||||
enum tf_mem {
|
||||
TF_MEM_INTERNAL, /**< Internal */
|
||||
TF_MEM_EXTERNAL, /**< External */
|
||||
TF_MEM_MAX
|
||||
};
|
||||
|
||||
/**
|
||||
* The size of the external action record (Wh+/Brd2)
|
||||
*
|
||||
* Currently set to 512.
|
||||
*
|
||||
* AR (16B) + encap (256B) + stats_ptrs (8) + resvd (8)
|
||||
* + stats (16) = 304 aligned on a 16B boundary
|
||||
*
|
||||
* Theoretically, the size should be smaller. ~304B
|
||||
*/
|
||||
#define TF_ACTION_RECORD_SZ 512
|
||||
|
||||
/**
|
||||
* External pool size
|
||||
*
|
||||
@ -56,6 +81,23 @@ enum tf_dir {
|
||||
#define TF_EXT_POOL_0 0 /**< matches TF_TBL_TYPE_EXT */
|
||||
#define TF_EXT_POOL_1 1 /**< matches TF_TBL_TYPE_EXT_0 */
|
||||
|
||||
/** EEM record AR helper
|
||||
*
|
||||
* Helpers to handle the Action Record Pointer in the EEM Record Entry.
|
||||
*
|
||||
* Convert absolute offset to action record pointer in EEM record entry
|
||||
* Convert action record pointer in EEM record entry to absolute offset
|
||||
*/
|
||||
#define TF_ACT_REC_OFFSET_2_PTR(offset) ((offset) >> 4)
|
||||
#define TF_ACT_REC_PTR_2_OFFSET(offset) ((offset) << 4)
|
||||
|
||||
#define TF_ACT_REC_INDEX_2_OFFSET(idx) ((idx) << 9)
|
||||
|
||||
/*
|
||||
* Helper Macros
|
||||
*/
|
||||
#define TF_BITS_2_BYTES(num_bits) (((num_bits) + 7) / 8)
|
||||
|
||||
/********** BEGIN API FUNCTION PROTOTYPES/PARAMETERS **********/
|
||||
|
||||
/**
|
||||
@ -495,7 +537,7 @@ struct tf_alloc_tbl_scope_parms {
|
||||
*/
|
||||
uint32_t rx_num_flows_in_k;
|
||||
/**
|
||||
* [in] SR2 only receive table access interface id
|
||||
* [in] Brd4 only receive table access interface id
|
||||
*/
|
||||
uint32_t rx_tbl_if_id;
|
||||
/**
|
||||
@ -517,7 +559,7 @@ struct tf_alloc_tbl_scope_parms {
|
||||
*/
|
||||
uint32_t tx_num_flows_in_k;
|
||||
/**
|
||||
* [in] SR2 only receive table access interface id
|
||||
* [in] Brd4 only receive table access interface id
|
||||
*/
|
||||
uint32_t tx_tbl_if_id;
|
||||
/**
|
||||
@ -536,7 +578,7 @@ struct tf_free_tbl_scope_parms {
|
||||
/**
|
||||
* allocate a table scope
|
||||
*
|
||||
* On SR2 Firmware will allocate a scope ID. On other devices, the scope
|
||||
* On Brd4 Firmware will allocate a scope ID. On other devices, the scope
|
||||
* is a software construct to identify an EEM table. This function will
|
||||
* divide the hash memory/buckets and records according to the device
|
||||
* device constraints based upon calculations using either the number of flows
|
||||
@ -546,7 +588,7 @@ struct tf_free_tbl_scope_parms {
|
||||
*
|
||||
* This API will allocate the table region in
|
||||
* DRAM, program the PTU page table entries, and program the number of static
|
||||
* buckets (if SR2) in the RX and TX CFAs. Buckets are assumed to start at
|
||||
* buckets (if Brd4) in the RX and TX CFAs. Buckets are assumed to start at
|
||||
* 0 in the EM memory for the scope. Upon successful completion of this API,
|
||||
* hash tables are fully initialized and ready for entries to be inserted.
|
||||
*
|
||||
@ -563,7 +605,7 @@ struct tf_free_tbl_scope_parms {
|
||||
* memory allocated based on the rx_em_hash_mb/tx_em_hash_mb parameters. The
|
||||
* hash table buckets are stored at the beginning of that memory.
|
||||
*
|
||||
* NOTES: No EM internal setup is done here. On chip EM records are managed
|
||||
* NOTE: No EM internal setup is done here. On chip EM records are managed
|
||||
* internally by TruFlow core.
|
||||
*
|
||||
* Returns success or failure code.
|
||||
@ -577,7 +619,7 @@ int tf_alloc_tbl_scope(struct tf *tfp,
|
||||
*
|
||||
* Firmware checks that the table scope ID is owned by the TruFlow
|
||||
* session, verifies that no references to this table scope remains
|
||||
* (SR2 ILT) or Profile TCAM entries for either CFA (RX/TX) direction,
|
||||
* (Brd4 ILT) or Profile TCAM entries for either CFA (RX/TX) direction,
|
||||
* then frees the table scope ID.
|
||||
*
|
||||
* Returns success or failure code.
|
||||
@ -905,4 +947,430 @@ enum tf_tbl_type {
|
||||
TF_TBL_TYPE_EXT_0,
|
||||
TF_TBL_TYPE_MAX
|
||||
};
|
||||
|
||||
/** tf_alloc_tbl_entry parameter definition
|
||||
*/
|
||||
struct tf_alloc_tbl_entry_parms {
|
||||
/**
|
||||
* [in] Receive or transmit direction
|
||||
*/
|
||||
enum tf_dir dir;
|
||||
/**
|
||||
* [in] Type of the allocation
|
||||
*/
|
||||
enum tf_tbl_type type;
|
||||
/**
|
||||
* [in] Enable search for matching entry. If the table type is
|
||||
* internal the shadow copy will be searched before
|
||||
* alloc. Session must be configured with shadow copy enabled.
|
||||
*/
|
||||
uint8_t search_enable;
|
||||
/**
|
||||
* [in] Result data to search for (if search_enable)
|
||||
*/
|
||||
uint8_t *result;
|
||||
/**
|
||||
* [in] Result data size in bytes (if search_enable)
|
||||
*/
|
||||
uint16_t result_sz_in_bytes;
|
||||
/**
|
||||
* [out] If search_enable, set if matching entry found
|
||||
*/
|
||||
uint8_t hit;
|
||||
/**
|
||||
* [out] Current ref count after allocation (if search_enable)
|
||||
*/
|
||||
uint16_t ref_cnt;
|
||||
/**
|
||||
* [out] Idx of allocated entry or found entry (if search_enable)
|
||||
*/
|
||||
uint32_t idx;
|
||||
};
|
||||
|
||||
/** allocate index table entries
|
||||
*
|
||||
* Internal types:
|
||||
*
|
||||
* Allocate an on chip index table entry or search for a matching
|
||||
* entry of the indicated type for this TruFlow session.
|
||||
*
|
||||
* Allocates an index table record. This function will attempt to
|
||||
* allocate an entry or search an index table for a matching entry if
|
||||
* search is enabled (only the shadow copy of the table is accessed).
|
||||
*
|
||||
* If search is not enabled, the first available free entry is
|
||||
* returned. If search is enabled and a matching entry to entry_data
|
||||
* is found hit is set to TRUE and success is returned.
|
||||
*
|
||||
* External types:
|
||||
*
|
||||
* These are used to allocate inlined action record memory.
|
||||
*
|
||||
* Allocates an external index table action record.
|
||||
*
|
||||
* NOTE:
|
||||
* Implementation of the internals of this function will be a stack with push
|
||||
* and pop.
|
||||
*
|
||||
* Returns success or failure code.
|
||||
*/
|
||||
int tf_alloc_tbl_entry(struct tf *tfp,
|
||||
struct tf_alloc_tbl_entry_parms *parms);
|
||||
|
||||
/** tf_free_tbl_entry parameter definition
|
||||
*/
|
||||
struct tf_free_tbl_entry_parms {
|
||||
/**
|
||||
* [in] Receive or transmit direction
|
||||
*/
|
||||
enum tf_dir dir;
|
||||
/**
|
||||
* [in] Type of the allocation type
|
||||
*/
|
||||
enum tf_tbl_type type;
|
||||
/**
|
||||
* [in] Index to free
|
||||
*/
|
||||
uint32_t idx;
|
||||
/**
|
||||
* [out] Reference count after free, only valid if session has been
|
||||
* created with shadow_copy.
|
||||
*/
|
||||
uint16_t ref_cnt;
|
||||
};
|
||||
|
||||
/** free index table entry
|
||||
*
|
||||
* Used to free a previously allocated table entry.
|
||||
*
|
||||
* Internal types:
|
||||
*
|
||||
* If session has shadow_copy enabled the shadow DB is searched and if
|
||||
* found the element ref_cnt is decremented. If ref_cnt goes to
|
||||
* zero then the element is returned to the session pool.
|
||||
*
|
||||
* If the session does not have a shadow DB the element is free'ed and
|
||||
* given back to the session pool.
|
||||
*
|
||||
* External types:
|
||||
*
|
||||
* Free's an external index table action record.
|
||||
*
|
||||
* NOTE:
|
||||
* Implementation of the internals of this function will be a stack with push
|
||||
* and pop.
|
||||
*
|
||||
* Returns success or failure code.
|
||||
*/
|
||||
int tf_free_tbl_entry(struct tf *tfp,
|
||||
struct tf_free_tbl_entry_parms *parms);
|
||||
|
||||
/** tf_set_tbl_entry parameter definition
|
||||
*/
|
||||
struct tf_set_tbl_entry_parms {
|
||||
/**
|
||||
* [in] Table scope identifier
|
||||
*
|
||||
*/
|
||||
uint32_t tbl_scope_id;
|
||||
/**
|
||||
* [in] Receive or transmit direction
|
||||
*/
|
||||
enum tf_dir dir;
|
||||
/**
|
||||
* [in] Type of object to set
|
||||
*/
|
||||
enum tf_tbl_type type;
|
||||
/**
|
||||
* [in] Entry data
|
||||
*/
|
||||
uint8_t *data;
|
||||
/**
|
||||
* [in] Entry size
|
||||
*/
|
||||
uint16_t data_sz_in_bytes;
|
||||
/**
|
||||
* [in] Entry index to write to
|
||||
*/
|
||||
uint32_t idx;
|
||||
};
|
||||
|
||||
/** set index table entry
|
||||
*
|
||||
* Used to insert an application programmed index table entry into a
|
||||
* previous allocated table location. A shadow copy of the table
|
||||
* is maintained (if enabled) (only for internal objects)
|
||||
*
|
||||
* Returns success or failure code.
|
||||
*/
|
||||
int tf_set_tbl_entry(struct tf *tfp,
|
||||
struct tf_set_tbl_entry_parms *parms);
|
||||
|
||||
/** tf_get_tbl_entry parameter definition
|
||||
*/
|
||||
struct tf_get_tbl_entry_parms {
|
||||
/**
|
||||
* [in] Receive or transmit direction
|
||||
*/
|
||||
enum tf_dir dir;
|
||||
/**
|
||||
* [in] Type of object to get
|
||||
*/
|
||||
enum tf_tbl_type type;
|
||||
/**
|
||||
* [out] Entry data
|
||||
*/
|
||||
uint8_t *data;
|
||||
/**
|
||||
* [out] Entry size
|
||||
*/
|
||||
uint16_t data_sz_in_bytes;
|
||||
/**
|
||||
* [in] Entry index to read
|
||||
*/
|
||||
uint32_t idx;
|
||||
};
|
||||
|
||||
/** get index table entry
|
||||
*
|
||||
* Used to retrieve a previous set index table entry.
|
||||
*
|
||||
* Reads and compares with the shadow table copy (if enabled) (only
|
||||
* for internal objects).
|
||||
*
|
||||
* Returns success or failure code. Failure will be returned if the
|
||||
* provided data buffer is too small for the data type requested.
|
||||
*/
|
||||
int tf_get_tbl_entry(struct tf *tfp,
|
||||
struct tf_get_tbl_entry_parms *parms);
|
||||
|
||||
/**
|
||||
* @page exact_match Exact Match Table
|
||||
*
|
||||
* @ref tf_insert_em_entry
|
||||
*
|
||||
* @ref tf_delete_em_entry
|
||||
*
|
||||
* @ref tf_search_em_entry
|
||||
*
|
||||
*/
|
||||
/** tf_insert_em_entry parameter definition
|
||||
*/
|
||||
struct tf_insert_em_entry_parms {
|
||||
/**
|
||||
* [in] receive or transmit direction
|
||||
*/
|
||||
enum tf_dir dir;
|
||||
/**
|
||||
* [in] internal or external
|
||||
*/
|
||||
enum tf_mem mem;
|
||||
/**
|
||||
* [in] ID of table scope to use (external only)
|
||||
*/
|
||||
uint32_t tbl_scope_id;
|
||||
/**
|
||||
* [in] ID of table interface to use (Brd4 only)
|
||||
*/
|
||||
uint32_t tbl_if_id;
|
||||
/**
|
||||
* [in] ptr to structure containing key fields
|
||||
*/
|
||||
uint8_t *key;
|
||||
/**
|
||||
* [in] key bit length
|
||||
*/
|
||||
uint16_t key_sz_in_bits;
|
||||
/**
|
||||
* [in] ptr to structure containing result field
|
||||
*/
|
||||
uint8_t *em_record;
|
||||
/**
|
||||
* [out] result size in bits
|
||||
*/
|
||||
uint16_t em_record_sz_in_bits;
|
||||
/**
|
||||
* [in] duplicate check flag
|
||||
*/
|
||||
uint8_t dup_check;
|
||||
/**
|
||||
* [out] Flow handle value for the inserted entry. This is encoded
|
||||
* as the entries[4]:bucket[2]:hashId[1]:hash[14]
|
||||
*/
|
||||
uint64_t flow_handle;
|
||||
/**
|
||||
* [out] Flow id is returned as null (internal)
|
||||
* Flow id is the GFID value for the inserted entry (external)
|
||||
* This is the value written to the BD and useful information for mark.
|
||||
*/
|
||||
uint64_t flow_id;
|
||||
};
|
||||
/**
|
||||
* tf_delete_em_entry parameter definition
|
||||
*/
|
||||
struct tf_delete_em_entry_parms {
|
||||
/**
|
||||
* [in] receive or transmit direction
|
||||
*/
|
||||
enum tf_dir dir;
|
||||
/**
|
||||
* [in] internal or external
|
||||
*/
|
||||
enum tf_mem mem;
|
||||
/**
|
||||
* [in] ID of table scope to use (external only)
|
||||
*/
|
||||
uint32_t tbl_scope_id;
|
||||
/**
|
||||
* [in] ID of table interface to use (Brd4 only)
|
||||
*/
|
||||
uint32_t tbl_if_id;
|
||||
/**
|
||||
* [in] epoch group IDs of entry to delete
|
||||
* 2 element array with 2 ids. (Brd4 only)
|
||||
*/
|
||||
uint16_t *epochs;
|
||||
/**
|
||||
* [in] structure containing flow delete handle information
|
||||
*/
|
||||
uint64_t flow_handle;
|
||||
};
|
||||
/**
|
||||
* tf_search_em_entry parameter definition
|
||||
*/
|
||||
struct tf_search_em_entry_parms {
|
||||
/**
|
||||
* [in] receive or transmit direction
|
||||
*/
|
||||
enum tf_dir dir;
|
||||
/**
|
||||
* [in] internal or external
|
||||
*/
|
||||
enum tf_mem mem;
|
||||
/**
|
||||
* [in] ID of table scope to use (external only)
|
||||
*/
|
||||
uint32_t tbl_scope_id;
|
||||
/**
|
||||
* [in] ID of table interface to use (Brd4 only)
|
||||
*/
|
||||
uint32_t tbl_if_id;
|
||||
/**
|
||||
* [in] ptr to structure containing key fields
|
||||
*/
|
||||
uint8_t *key;
|
||||
/**
|
||||
* [in] key bit length
|
||||
*/
|
||||
uint16_t key_sz_in_bits;
|
||||
/**
|
||||
* [in/out] ptr to structure containing EM record fields
|
||||
*/
|
||||
uint8_t *em_record;
|
||||
/**
|
||||
* [out] result size in bits
|
||||
*/
|
||||
uint16_t em_record_sz_in_bits;
|
||||
/**
|
||||
* [in] epoch group IDs of entry to lookup
|
||||
* 2 element array with 2 ids. (Brd4 only)
|
||||
*/
|
||||
uint16_t *epochs;
|
||||
/**
|
||||
* [in] ptr to structure containing flow delete handle
|
||||
*/
|
||||
uint64_t flow_handle;
|
||||
};
|
||||
|
||||
/** insert em hash entry in internal table memory
|
||||
*
|
||||
* Internal:
|
||||
*
|
||||
* This API inserts an exact match entry into internal EM table memory
|
||||
* of the specified direction.
|
||||
*
|
||||
* Note: The EM record is managed within the TruFlow core and not the
|
||||
* application.
|
||||
*
|
||||
* Shadow copy of internal record table an association with hash and 1,2, or 4
|
||||
* associated buckets
|
||||
*
|
||||
* External:
|
||||
* This API inserts an exact match entry into DRAM EM table memory of the
|
||||
* specified direction and table scope.
|
||||
*
|
||||
* When inserting an entry into an exact match table, the TruFlow library may
|
||||
* need to allocate a dynamic bucket for the entry (Brd4 only).
|
||||
*
|
||||
* The insertion of duplicate entries in an EM table is not permitted. If a
|
||||
* TruFlow application can guarantee that it will never insert duplicates, it
|
||||
* can disable duplicate checking by passing a zero value in the dup_check
|
||||
* parameter to this API. This will optimize performance. Otherwise, the
|
||||
* TruFlow library will enforce protection against inserting duplicate entries.
|
||||
*
|
||||
* Flow handle is defined in this document:
|
||||
*
|
||||
* https://docs.google.com
|
||||
* /document/d/1NESu7RpTN3jwxbokaPfYORQyChYRmJgs40wMIRe8_-Q/edit
|
||||
*
|
||||
* Returns success or busy code.
|
||||
*
|
||||
*/
|
||||
int tf_insert_em_entry(struct tf *tfp,
|
||||
struct tf_insert_em_entry_parms *parms);
|
||||
|
||||
/** delete em hash entry table memory
|
||||
*
|
||||
* Internal:
|
||||
*
|
||||
* This API deletes an exact match entry from internal EM table memory of the
|
||||
* specified direction. If a valid flow ptr is passed in then that takes
|
||||
* precedence over the pointer to the complete key passed in.
|
||||
*
|
||||
*
|
||||
* External:
|
||||
*
|
||||
* This API deletes an exact match entry from EM table memory of the specified
|
||||
* direction and table scope. If a valid flow handle is passed in then that
|
||||
* takes precedence over the pointer to the complete key passed in.
|
||||
*
|
||||
* The TruFlow library may release a dynamic bucket when an entry is deleted.
|
||||
*
|
||||
*
|
||||
* Returns success or not found code
|
||||
*
|
||||
*
|
||||
*/
|
||||
int tf_delete_em_entry(struct tf *tfp,
|
||||
struct tf_delete_em_entry_parms *parms);
|
||||
|
||||
/** search em hash entry table memory
|
||||
*
|
||||
* Internal:
|
||||
|
||||
* This API looks up an EM entry in table memory with the specified EM
|
||||
* key or flow (flow takes precedence) and direction.
|
||||
*
|
||||
* The status will be one of: success or entry not found. If the lookup
|
||||
* succeeds, a pointer to the matching entry and the result record associated
|
||||
* with the matching entry will be provided.
|
||||
*
|
||||
* If flow_handle is set, search shadow copy.
|
||||
*
|
||||
* Otherwise, query the fw with key to get result.
|
||||
*
|
||||
* External:
|
||||
*
|
||||
* This API looks up an EM entry in table memory with the specified EM
|
||||
* key or flow_handle (flow takes precedence), direction and table scope.
|
||||
*
|
||||
* The status will be one of: success or entry not found. If the lookup
|
||||
* succeeds, a pointer to the matching entry and the result record associated
|
||||
* with the matching entry will be provided.
|
||||
*
|
||||
* Returns success or not found code
|
||||
*
|
||||
*/
|
||||
int tf_search_em_entry(struct tf *tfp,
|
||||
struct tf_search_em_entry_parms *parms);
|
||||
#endif /* _TF_CORE_H_ */
|
||||
|
515
drivers/net/bnxt/tf_core/tf_em.c
Normal file
515
drivers/net/bnxt/tf_core/tf_em.c
Normal file
@ -0,0 +1,515 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright(c) 2019-2020 Broadcom
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <rte_common.h>
|
||||
#include <rte_errno.h>
|
||||
#include <rte_log.h>
|
||||
|
||||
#include "tf_core.h"
|
||||
#include "tf_em.h"
|
||||
#include "tf_msg.h"
|
||||
#include "tfp.h"
|
||||
#include "lookup3.h"
|
||||
#include "tf_ext_flow_handle.h"
|
||||
|
||||
#include "bnxt.h"
|
||||
|
||||
/* Enable EEM table dump
|
||||
*/
|
||||
#define TF_EEM_DUMP
|
||||
|
||||
static struct tf_eem_64b_entry zero_key_entry;
|
||||
|
||||
static uint32_t tf_em_get_key_mask(int num_entries)
|
||||
{
|
||||
uint32_t mask = num_entries - 1;
|
||||
|
||||
if (num_entries & 0x7FFF)
|
||||
return 0;
|
||||
|
||||
if (num_entries > (128 * 1024 * 1024))
|
||||
return 0;
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
/* CRC32i support for Key0 hash */
|
||||
#define ucrc32(ch, crc) (crc32tbl[((crc) ^ (ch)) & 0xff] ^ ((crc) >> 8))
|
||||
#define crc32(x, y) crc32i(~0, x, y)
|
||||
|
||||
static const uint32_t crc32tbl[] = { /* CRC polynomial 0xedb88320 */
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
|
||||
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
||||
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
|
||||
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
|
||||
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
|
||||
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
|
||||
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
|
||||
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
|
||||
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
|
||||
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
|
||||
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
|
||||
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
|
||||
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
|
||||
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
|
||||
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
|
||||
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
|
||||
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
|
||||
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
|
||||
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
|
||||
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
|
||||
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
|
||||
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
|
||||
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
|
||||
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
|
||||
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
|
||||
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
|
||||
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
|
||||
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
|
||||
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
|
||||
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
|
||||
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
|
||||
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
|
||||
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
|
||||
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
|
||||
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
|
||||
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
|
||||
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
|
||||
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
|
||||
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
|
||||
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
|
||||
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
|
||||
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
|
||||
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||
};
|
||||
|
||||
static uint32_t crc32i(uint32_t crc, const uint8_t *buf, size_t len)
|
||||
{
|
||||
int l;
|
||||
|
||||
for (l = (len - 1); l >= 0; l--)
|
||||
crc = ucrc32(buf[l], crc);
|
||||
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
static uint32_t tf_em_lkup_get_crc32_hash(struct tf_session *session,
|
||||
uint8_t *key,
|
||||
enum tf_dir dir)
|
||||
{
|
||||
int i;
|
||||
uint32_t index;
|
||||
uint32_t val1, val2;
|
||||
uint8_t temp[4];
|
||||
uint8_t *kptr = key;
|
||||
|
||||
/* Do byte-wise XOR of the 52-byte HASH key first. */
|
||||
index = *key;
|
||||
kptr--;
|
||||
|
||||
for (i = TF_HW_EM_KEY_MAX_SIZE - 2; i >= 0; i--) {
|
||||
index = index ^ *kptr;
|
||||
kptr--;
|
||||
}
|
||||
|
||||
/* Get seeds */
|
||||
val1 = session->lkup_em_seed_mem[dir][index * 2];
|
||||
val2 = session->lkup_em_seed_mem[dir][index * 2 + 1];
|
||||
|
||||
temp[3] = (uint8_t)(val1 >> 24);
|
||||
temp[2] = (uint8_t)(val1 >> 16);
|
||||
temp[1] = (uint8_t)(val1 >> 8);
|
||||
temp[0] = (uint8_t)(val1 & 0xff);
|
||||
val1 = 0;
|
||||
|
||||
/* Start with seed */
|
||||
if (!(val2 & 0x1))
|
||||
val1 = crc32i(~val1, temp, 4);
|
||||
|
||||
val1 = crc32i(~val1,
|
||||
(key - (TF_HW_EM_KEY_MAX_SIZE - 1)),
|
||||
TF_HW_EM_KEY_MAX_SIZE);
|
||||
|
||||
/* End with seed */
|
||||
if (val2 & 0x1)
|
||||
val1 = crc32i(~val1, temp, 4);
|
||||
|
||||
return val1;
|
||||
}
|
||||
|
||||
static uint32_t tf_em_lkup_get_lookup3_hash(uint32_t lookup3_init_value,
|
||||
uint8_t *in_key)
|
||||
{
|
||||
uint32_t val1;
|
||||
|
||||
val1 = hashword(((uint32_t *)in_key) + 1,
|
||||
TF_HW_EM_KEY_MAX_SIZE / (sizeof(uint32_t)),
|
||||
lookup3_init_value);
|
||||
|
||||
return val1;
|
||||
}
|
||||
|
||||
void *tf_em_get_table_page(struct tf_tbl_scope_cb *tbl_scope_cb,
|
||||
enum tf_dir dir,
|
||||
uint32_t offset,
|
||||
enum tf_em_table_type table_type)
|
||||
{
|
||||
int level = 0;
|
||||
int page = offset / TF_EM_PAGE_SIZE;
|
||||
void *addr = NULL;
|
||||
struct tf_em_ctx_mem_info *ctx = &tbl_scope_cb->em_ctx_info[dir];
|
||||
|
||||
if (ctx == NULL)
|
||||
return NULL;
|
||||
|
||||
if (dir != TF_DIR_RX && dir != TF_DIR_TX)
|
||||
return NULL;
|
||||
|
||||
if (table_type < KEY0_TABLE || table_type > EFC_TABLE)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Use the level according to the num_level of page table
|
||||
*/
|
||||
level = ctx->em_tables[table_type].num_lvl - 1;
|
||||
|
||||
addr = (void *)ctx->em_tables[table_type].pg_tbl[level].pg_va_tbl[page];
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
/** Read Key table entry
|
||||
*
|
||||
* Entry is read in to entry
|
||||
*/
|
||||
static int tf_em_read_entry(struct tf_tbl_scope_cb *tbl_scope_cb,
|
||||
struct tf_eem_64b_entry *entry,
|
||||
uint32_t entry_size,
|
||||
uint32_t index,
|
||||
enum tf_em_table_type table_type,
|
||||
enum tf_dir dir)
|
||||
{
|
||||
void *page;
|
||||
uint32_t entry_offset = (index * entry_size) % TF_EM_PAGE_SIZE;
|
||||
|
||||
page = tf_em_get_table_page(tbl_scope_cb,
|
||||
dir,
|
||||
(index * entry_size),
|
||||
table_type);
|
||||
|
||||
if (page == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy((uint8_t *)entry, (uint8_t *)page + entry_offset, entry_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tf_em_write_entry(struct tf_tbl_scope_cb *tbl_scope_cb,
|
||||
struct tf_eem_64b_entry *entry,
|
||||
uint32_t entry_size,
|
||||
uint32_t index,
|
||||
enum tf_em_table_type table_type,
|
||||
enum tf_dir dir)
|
||||
{
|
||||
void *page;
|
||||
uint32_t entry_offset = (index * entry_size) % TF_EM_PAGE_SIZE;
|
||||
|
||||
page = tf_em_get_table_page(tbl_scope_cb,
|
||||
dir,
|
||||
(index * entry_size),
|
||||
table_type);
|
||||
|
||||
if (page == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy((uint8_t *)page + entry_offset, entry, entry_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tf_em_entry_exists(struct tf_tbl_scope_cb *tbl_scope_cb,
|
||||
struct tf_eem_64b_entry *entry,
|
||||
uint32_t index,
|
||||
enum tf_em_table_type table_type,
|
||||
enum tf_dir dir)
|
||||
{
|
||||
int rc;
|
||||
struct tf_eem_64b_entry table_entry;
|
||||
|
||||
rc = tf_em_read_entry(tbl_scope_cb,
|
||||
&table_entry,
|
||||
TF_EM_KEY_RECORD_SIZE,
|
||||
index,
|
||||
table_type,
|
||||
dir);
|
||||
|
||||
if (rc != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (table_entry.hdr.word1 & (1 << TF_LKUP_RECORD_VALID_SHIFT)) {
|
||||
if (entry != NULL) {
|
||||
if (memcmp(&table_entry,
|
||||
entry,
|
||||
TF_EM_KEY_RECORD_SIZE) == 0)
|
||||
return -EEXIST;
|
||||
} else {
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tf_em_create_key_entry(struct tf_eem_entry_hdr *result,
|
||||
uint8_t *in_key,
|
||||
struct tf_eem_64b_entry *key_entry)
|
||||
{
|
||||
key_entry->hdr.word1 = result->word1;
|
||||
|
||||
if (result->word1 & TF_LKUP_RECORD_ACT_REC_INT_MASK)
|
||||
key_entry->hdr.pointer = result->pointer;
|
||||
else
|
||||
key_entry->hdr.pointer = result->pointer;
|
||||
|
||||
memcpy(key_entry->key, in_key, TF_HW_EM_KEY_MAX_SIZE + 4);
|
||||
}
|
||||
|
||||
/* tf_em_select_inject_table
|
||||
*
|
||||
* Returns:
|
||||
* 0 - Key does not exist in either table and can be inserted
|
||||
* at "index" in table "table".
|
||||
* EEXIST - Key does exist in table at "index" in table "table".
|
||||
* TF_ERR - Something went horribly wrong.
|
||||
*/
|
||||
static int tf_em_select_inject_table(struct tf_tbl_scope_cb *tbl_scope_cb,
|
||||
enum tf_dir dir,
|
||||
struct tf_eem_64b_entry *entry,
|
||||
uint32_t key0_hash,
|
||||
uint32_t key1_hash,
|
||||
uint32_t *index,
|
||||
enum tf_em_table_type *table)
|
||||
{
|
||||
int key0_entry;
|
||||
int key1_entry;
|
||||
|
||||
/*
|
||||
* Check KEY0 table.
|
||||
*/
|
||||
key0_entry = tf_em_entry_exists(tbl_scope_cb,
|
||||
entry,
|
||||
key0_hash,
|
||||
KEY0_TABLE,
|
||||
dir);
|
||||
|
||||
/*
|
||||
* Check KEY1 table.
|
||||
*/
|
||||
key1_entry = tf_em_entry_exists(tbl_scope_cb,
|
||||
entry,
|
||||
key1_hash,
|
||||
KEY1_TABLE,
|
||||
dir);
|
||||
|
||||
if (key0_entry == -EEXIST) {
|
||||
*table = KEY0_TABLE;
|
||||
*index = key0_hash;
|
||||
return -EEXIST;
|
||||
} else if (key1_entry == -EEXIST) {
|
||||
*table = KEY1_TABLE;
|
||||
*index = key1_hash;
|
||||
return -EEXIST;
|
||||
} else if (key0_entry == 0) {
|
||||
*table = KEY0_TABLE;
|
||||
*index = key0_hash;
|
||||
return 0;
|
||||
} else if (key1_entry == 0) {
|
||||
*table = KEY1_TABLE;
|
||||
*index = key1_hash;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/** insert EEM entry API
|
||||
*
|
||||
* returns:
|
||||
* 0
|
||||
* TF_ERR - unable to get lock
|
||||
*
|
||||
* insert callback returns:
|
||||
* 0
|
||||
* TF_ERR_EM_DUP - key is already in table
|
||||
*/
|
||||
int tf_insert_eem_entry(struct tf_session *session,
|
||||
struct tf_tbl_scope_cb *tbl_scope_cb,
|
||||
struct tf_insert_em_entry_parms *parms)
|
||||
{
|
||||
uint32_t mask;
|
||||
uint32_t key0_hash;
|
||||
uint32_t key1_hash;
|
||||
uint32_t key0_index;
|
||||
uint32_t key1_index;
|
||||
struct tf_eem_64b_entry key_entry;
|
||||
uint32_t index;
|
||||
enum tf_em_table_type table_type;
|
||||
uint32_t gfid;
|
||||
int num_of_entry;
|
||||
|
||||
/* Get mask to use on hash */
|
||||
mask = tf_em_get_key_mask(tbl_scope_cb->em_ctx_info[parms->dir].em_tables[KEY0_TABLE].num_entries);
|
||||
|
||||
if (!mask)
|
||||
return -EINVAL;
|
||||
|
||||
num_of_entry = TF_HW_EM_KEY_MAX_SIZE + 4;
|
||||
|
||||
key0_hash = tf_em_lkup_get_crc32_hash(session,
|
||||
&parms->key[num_of_entry] - 1,
|
||||
parms->dir);
|
||||
key0_index = key0_hash & mask;
|
||||
|
||||
key1_hash =
|
||||
tf_em_lkup_get_lookup3_hash(session->lkup_lkup3_init_cfg[parms->dir],
|
||||
parms->key);
|
||||
key1_index = key1_hash & mask;
|
||||
|
||||
/*
|
||||
* Use the "result" arg to populate all of the key entry then
|
||||
* store the byte swapped "raw" entry in a local copy ready
|
||||
* for insertion in to the table.
|
||||
*/
|
||||
tf_em_create_key_entry((struct tf_eem_entry_hdr *)parms->em_record,
|
||||
((uint8_t *)parms->key),
|
||||
&key_entry);
|
||||
|
||||
/*
|
||||
* Find which table to use
|
||||
*/
|
||||
if (tf_em_select_inject_table(tbl_scope_cb,
|
||||
parms->dir,
|
||||
&key_entry,
|
||||
key0_index,
|
||||
key1_index,
|
||||
&index,
|
||||
&table_type) == 0) {
|
||||
if (table_type == KEY0_TABLE) {
|
||||
TF_SET_GFID(gfid,
|
||||
key0_index,
|
||||
KEY0_TABLE);
|
||||
} else {
|
||||
TF_SET_GFID(gfid,
|
||||
key1_index,
|
||||
KEY1_TABLE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Inject
|
||||
*/
|
||||
if (tf_em_write_entry(tbl_scope_cb,
|
||||
&key_entry,
|
||||
TF_EM_KEY_RECORD_SIZE,
|
||||
index,
|
||||
table_type,
|
||||
parms->dir) == 0) {
|
||||
TF_SET_FLOW_ID(parms->flow_id,
|
||||
gfid,
|
||||
TF_GFID_TABLE_EXTERNAL,
|
||||
parms->dir);
|
||||
TF_SET_FIELDS_IN_FLOW_HANDLE(parms->flow_handle,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
index,
|
||||
0,
|
||||
table_type);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/** delete EEM hash entry API
|
||||
*
|
||||
* returns:
|
||||
* 0
|
||||
* -EINVAL - parameter error
|
||||
* TF_NO_SESSION - bad session ID
|
||||
* TF_ERR_TBL_SCOPE - invalid table scope
|
||||
* TF_ERR_TBL_IF - invalid table interface
|
||||
*
|
||||
* insert callback returns
|
||||
* 0
|
||||
* TF_NO_EM_MATCH - entry not found
|
||||
*/
|
||||
int tf_delete_eem_entry(struct tf *tfp,
|
||||
struct tf_delete_em_entry_parms *parms)
|
||||
{
|
||||
struct tf_session *session;
|
||||
struct tf_tbl_scope_cb *tbl_scope_cb;
|
||||
enum tf_em_table_type hash_type;
|
||||
uint32_t index;
|
||||
|
||||
if (parms == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
session = (struct tf_session *)tfp->session->core_data;
|
||||
if (session == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
tbl_scope_cb = tbl_scope_cb_find(session,
|
||||
parms->tbl_scope_id);
|
||||
if (tbl_scope_cb == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (parms->flow_handle == 0)
|
||||
return -EINVAL;
|
||||
|
||||
TF_GET_HASH_TYPE_FROM_FLOW_HANDLE(parms->flow_handle, hash_type);
|
||||
TF_GET_INDEX_FROM_FLOW_HANDLE(parms->flow_handle, index);
|
||||
|
||||
if (tf_em_entry_exists(tbl_scope_cb,
|
||||
NULL,
|
||||
index,
|
||||
hash_type,
|
||||
parms->dir) == -EEXIST) {
|
||||
tf_em_write_entry(tbl_scope_cb,
|
||||
&zero_key_entry,
|
||||
TF_EM_KEY_RECORD_SIZE,
|
||||
index,
|
||||
hash_type,
|
||||
parms->dir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
117
drivers/net/bnxt/tf_core/tf_em.h
Normal file
117
drivers/net/bnxt/tf_core/tf_em.h
Normal file
@ -0,0 +1,117 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright(c) 2019-2020 Broadcom
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _TF_EM_H_
|
||||
#define _TF_EM_H_
|
||||
|
||||
#include "tf_core.h"
|
||||
#include "tf_session.h"
|
||||
|
||||
#define TF_HW_EM_KEY_MAX_SIZE 52
|
||||
#define TF_EM_KEY_RECORD_SIZE 64
|
||||
|
||||
/** EEM Entry header
|
||||
*
|
||||
*/
|
||||
struct tf_eem_entry_hdr {
|
||||
uint32_t pointer;
|
||||
uint32_t word1; /*
|
||||
* The header is made up of two words,
|
||||
* this is the first word. This field has multiple
|
||||
* subfields, there is no suitable single name for
|
||||
* it so just going with word1.
|
||||
*/
|
||||
#define TF_LKUP_RECORD_VALID_SHIFT 31
|
||||
#define TF_LKUP_RECORD_VALID_MASK 0x80000000
|
||||
#define TF_LKUP_RECORD_L1_CACHEABLE_SHIFT 30
|
||||
#define TF_LKUP_RECORD_L1_CACHEABLE_MASK 0x40000000
|
||||
#define TF_LKUP_RECORD_STRENGTH_SHIFT 28
|
||||
#define TF_LKUP_RECORD_STRENGTH_MASK 0x30000000
|
||||
#define TF_LKUP_RECORD_RESERVED_SHIFT 17
|
||||
#define TF_LKUP_RECORD_RESERVED_MASK 0x0FFE0000
|
||||
#define TF_LKUP_RECORD_KEY_SIZE_SHIFT 8
|
||||
#define TF_LKUP_RECORD_KEY_SIZE_MASK 0x0001FF00
|
||||
#define TF_LKUP_RECORD_ACT_REC_SIZE_SHIFT 3
|
||||
#define TF_LKUP_RECORD_ACT_REC_SIZE_MASK 0x000000F8
|
||||
#define TF_LKUP_RECORD_ACT_REC_INT_SHIFT 2
|
||||
#define TF_LKUP_RECORD_ACT_REC_INT_MASK 0x00000004
|
||||
#define TF_LKUP_RECORD_EXT_FLOW_CTR_SHIFT 1
|
||||
#define TF_LKUP_RECORD_EXT_FLOW_CTR_MASK 0x00000002
|
||||
#define TF_LKUP_RECORD_ACT_PTR_MSB_SHIFT 0
|
||||
#define TF_LKUP_RECORD_ACT_PTR_MSB_MASK 0x00000001
|
||||
};
|
||||
|
||||
/** EEM Entry
|
||||
* Each EEM entry is 512-bit (64-bytes)
|
||||
*/
|
||||
struct tf_eem_64b_entry {
|
||||
/** Key is 448 bits - 56 bytes */
|
||||
uint8_t key[TF_EM_KEY_RECORD_SIZE - sizeof(struct tf_eem_entry_hdr)];
|
||||
/** Header is 8 bytes long */
|
||||
struct tf_eem_entry_hdr hdr;
|
||||
};
|
||||
|
||||
/**
|
||||
* Allocates EEM Table scope
|
||||
*
|
||||
* [in] tfp
|
||||
* Pointer to TruFlow handle
|
||||
*
|
||||
* [in] parms
|
||||
* Pointer to input parameters
|
||||
*
|
||||
* Returns:
|
||||
* 0 - Success
|
||||
* -EINVAL - Parameter error
|
||||
* -ENOMEM - Out of memory
|
||||
*/
|
||||
int tf_alloc_eem_tbl_scope(struct tf *tfp,
|
||||
struct tf_alloc_tbl_scope_parms *parms);
|
||||
|
||||
/**
|
||||
* Free's EEM Table scope control block
|
||||
*
|
||||
* [in] tfp
|
||||
* Pointer to TruFlow handle
|
||||
*
|
||||
* [in] parms
|
||||
* Pointer to input parameters
|
||||
*
|
||||
* Returns:
|
||||
* 0 - Success
|
||||
* -EINVAL - Parameter error
|
||||
*/
|
||||
int tf_free_eem_tbl_scope_cb(struct tf *tfp,
|
||||
struct tf_free_tbl_scope_parms *parms);
|
||||
|
||||
/**
|
||||
* Function to search for table scope control block structure
|
||||
* with specified table scope ID.
|
||||
*
|
||||
* [in] session
|
||||
* Session to use for the search of the table scope control block
|
||||
* [in] tbl_scope_id
|
||||
* Table scope ID to search for
|
||||
*
|
||||
* Returns:
|
||||
* Pointer to the found table scope control block struct or NULL if
|
||||
* table scope control block struct not found
|
||||
*/
|
||||
struct tf_tbl_scope_cb *tbl_scope_cb_find(struct tf_session *session,
|
||||
uint32_t tbl_scope_id);
|
||||
|
||||
int tf_insert_eem_entry(struct tf_session *session,
|
||||
struct tf_tbl_scope_cb *tbl_scope_cb,
|
||||
struct tf_insert_em_entry_parms *parms);
|
||||
|
||||
int tf_delete_eem_entry(struct tf *tfp,
|
||||
struct tf_delete_em_entry_parms *parms);
|
||||
|
||||
void *tf_em_get_table_page(struct tf_tbl_scope_cb *tbl_scope_cb,
|
||||
enum tf_dir dir,
|
||||
uint32_t offset,
|
||||
enum tf_em_table_type table_type);
|
||||
|
||||
#endif /* _TF_EM_H_ */
|
166
drivers/net/bnxt/tf_core/tf_ext_flow_handle.h
Normal file
166
drivers/net/bnxt/tf_core/tf_ext_flow_handle.h
Normal file
@ -0,0 +1,166 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright(c) 2019-2020 Broadcom
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _TF_EXT_FLOW_HANDLE_H_
|
||||
#define _TF_EXT_FLOW_HANDLE_H_
|
||||
|
||||
#define TF_NUM_KEY_ENTRIES_FLOW_HANDLE_MASK 0x00000000F0000000ULL
|
||||
#define TF_NUM_KEY_ENTRIES_FLOW_HANDLE_SFT 28
|
||||
#define TF_FLOW_TYPE_FLOW_HANDLE_MASK 0x00000000000000F0ULL
|
||||
#define TF_FLOW_TYPE_FLOW_HANDLE_SFT 4
|
||||
#define TF_FLAGS_FLOW_HANDLE_MASK 0x000000000000000FULL
|
||||
#define TF_FLAGS_FLOW_HANDLE_SFT 0
|
||||
#define TF_INDEX_FLOW_HANDLE_MASK 0xFFFFFFF000000000ULL
|
||||
#define TF_INDEX_FLOW_HANDLE_SFT 36
|
||||
#define TF_ENTRY_NUM_FLOW_HANDLE_MASK 0x0000000E00000000ULL
|
||||
#define TF_ENTRY_NUM_FLOW_HANDLE_SFT 33
|
||||
#define TF_HASH_TYPE_FLOW_HANDLE_MASK 0x0000000100000000ULL
|
||||
#define TF_HASH_TYPE_FLOW_HANDLE_SFT 32
|
||||
|
||||
#define TF_FLOW_HANDLE_MASK (TF_NUM_KEY_ENTRIES_FLOW_HANDLE_MASK | \
|
||||
TF_FLOW_TYPE_FLOW_HANDLE_MASK | \
|
||||
TF_FLAGS_FLOW_HANDLE_MASK | \
|
||||
TF_INDEX_FLOW_HANDLE_MASK | \
|
||||
TF_ENTRY_NUM_FLOW_HANDLE_MASK | \
|
||||
TF_HASH_TYPE_FLOW_HANDLE_MASK)
|
||||
|
||||
#define TF_GET_FIELDS_FROM_FLOW_HANDLE(flow_handle, \
|
||||
num_key_entries, \
|
||||
flow_type, \
|
||||
flags, \
|
||||
index, \
|
||||
entry_num, \
|
||||
hash_type) \
|
||||
do { \
|
||||
(num_key_entries) = \
|
||||
(((flow_handle) & TF_NUM_KEY_ENTRIES_FLOW_HANDLE_MASK) >> \
|
||||
TF_NUM_KEY_ENTRIES_FLOW_HANDLE_SFT); \
|
||||
(flow_type) = (((flow_handle) & TF_FLOW_TYPE_FLOW_HANDLE_MASK) >> \
|
||||
TF_FLOW_TYPE_FLOW_HANDLE_SFT); \
|
||||
(flags) = (((flow_handle) & TF_FLAGS_FLOW_HANDLE_MASK) >> \
|
||||
TF_FLAGS_FLOW_HANDLE_SFT); \
|
||||
(index) = (((flow_handle) & TF_INDEX_FLOW_HANDLE_MASK) >> \
|
||||
TF_INDEX_FLOW_HANDLE_SFT); \
|
||||
(entry_num) = (((flow_handle) & TF_ENTRY_NUM_FLOW_HANDLE_MASK) >> \
|
||||
TF_ENTRY_NUM_FLOW_HANDLE_SFT); \
|
||||
(hash_type) = (((flow_handle) & TF_HASH_TYPE_FLOW_HANDLE_MASK) >> \
|
||||
TF_HASH_TYPE_FLOW_HANDLE_SFT); \
|
||||
} while (0)
|
||||
|
||||
#define TF_SET_FIELDS_IN_FLOW_HANDLE(flow_handle, \
|
||||
num_key_entries, \
|
||||
flow_type, \
|
||||
flags, \
|
||||
index, \
|
||||
entry_num, \
|
||||
hash_type) \
|
||||
do { \
|
||||
(flow_handle) &= ~TF_FLOW_HANDLE_MASK; \
|
||||
(flow_handle) |= \
|
||||
(((num_key_entries) << TF_NUM_KEY_ENTRIES_FLOW_HANDLE_SFT) & \
|
||||
TF_NUM_KEY_ENTRIES_FLOW_HANDLE_MASK); \
|
||||
(flow_handle) |= (((flow_type) << TF_FLOW_TYPE_FLOW_HANDLE_SFT) & \
|
||||
TF_FLOW_TYPE_FLOW_HANDLE_MASK); \
|
||||
(flow_handle) |= (((flags) << TF_FLAGS_FLOW_HANDLE_SFT) & \
|
||||
TF_FLAGS_FLOW_HANDLE_MASK); \
|
||||
(flow_handle) |= ((((uint64_t)index) << TF_INDEX_FLOW_HANDLE_SFT) & \
|
||||
TF_INDEX_FLOW_HANDLE_MASK); \
|
||||
(flow_handle) |= \
|
||||
((((uint64_t)entry_num) << TF_ENTRY_NUM_FLOW_HANDLE_SFT) & \
|
||||
TF_ENTRY_NUM_FLOW_HANDLE_MASK); \
|
||||
(flow_handle) |= \
|
||||
((((uint64_t)hash_type) << TF_HASH_TYPE_FLOW_HANDLE_SFT) & \
|
||||
TF_HASH_TYPE_FLOW_HANDLE_MASK); \
|
||||
} while (0)
|
||||
#define TF_SET_FIELDS_IN_WH_FLOW_HANDLE TF_SET_FIELDS_IN_FLOW_HANDLE
|
||||
|
||||
#define TF_GET_INDEX_FROM_FLOW_HANDLE(flow_handle, \
|
||||
index) \
|
||||
do { \
|
||||
index = (((flow_handle) & TF_INDEX_FLOW_HANDLE_MASK) >> \
|
||||
TF_INDEX_FLOW_HANDLE_SFT); \
|
||||
} while (0)
|
||||
|
||||
#define TF_GET_HASH_TYPE_FROM_FLOW_HANDLE(flow_handle, \
|
||||
hash_type) \
|
||||
do { \
|
||||
hash_type = (((flow_handle) & TF_HASH_TYPE_FLOW_HANDLE_MASK) >> \
|
||||
TF_HASH_TYPE_FLOW_HANDLE_SFT); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* 32 bit Flow ID handlers
|
||||
*/
|
||||
#define TF_GFID_FLOW_ID_MASK 0xFFFFFFF0UL
|
||||
#define TF_GFID_FLOW_ID_SFT 4
|
||||
#define TF_FLAG_FLOW_ID_MASK 0x00000002UL
|
||||
#define TF_FLAG_FLOW_ID_SFT 1
|
||||
#define TF_DIR_FLOW_ID_MASK 0x00000001UL
|
||||
#define TF_DIR_FLOW_ID_SFT 0
|
||||
|
||||
#define TF_SET_FLOW_ID(flow_id, gfid, flag, dir) \
|
||||
do { \
|
||||
(flow_id) &= ~(TF_GFID_FLOW_ID_MASK | \
|
||||
TF_FLAG_FLOW_ID_MASK | \
|
||||
TF_DIR_FLOW_ID_MASK); \
|
||||
(flow_id) |= (((gfid) << TF_GFID_FLOW_ID_SFT) & \
|
||||
TF_GFID_FLOW_ID_MASK) | \
|
||||
(((flag) << TF_FLAG_FLOW_ID_SFT) & \
|
||||
TF_FLAG_FLOW_ID_MASK) | \
|
||||
(((dir) << TF_DIR_FLOW_ID_SFT) & \
|
||||
TF_DIR_FLOW_ID_MASK); \
|
||||
} while (0)
|
||||
|
||||
#define TF_GET_GFID_FROM_FLOW_ID(flow_id, gfid) \
|
||||
do { \
|
||||
gfid = (((flow_id) & TF_GFID_FLOW_ID_MASK) >> \
|
||||
TF_GFID_FLOW_ID_SFT); \
|
||||
} while (0)
|
||||
|
||||
#define TF_GET_DIR_FROM_FLOW_ID(flow_id, dir) \
|
||||
do { \
|
||||
dir = (((flow_id) & TF_DIR_FLOW_ID_MASK) >> \
|
||||
TF_DIR_FLOW_ID_SFT); \
|
||||
} while (0)
|
||||
|
||||
#define TF_GET_FLAG_FROM_FLOW_ID(flow_id, flag) \
|
||||
do { \
|
||||
flag = (((flow_id) & TF_FLAG_FLOW_ID_MASK) >> \
|
||||
TF_FLAG_FLOW_ID_SFT); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* 32 bit GFID handlers
|
||||
*/
|
||||
#define TF_HASH_INDEX_GFID_MASK 0x07FFFFFFUL
|
||||
#define TF_HASH_INDEX_GFID_SFT 0
|
||||
#define TF_HASH_TYPE_GFID_MASK 0x08000000UL
|
||||
#define TF_HASH_TYPE_GFID_SFT 27
|
||||
|
||||
#define TF_GFID_TABLE_INTERNAL 0
|
||||
#define TF_GFID_TABLE_EXTERNAL 1
|
||||
|
||||
#define TF_SET_GFID(gfid, index, type) \
|
||||
do { \
|
||||
gfid = (((index) << TF_HASH_INDEX_GFID_SFT) & \
|
||||
TF_HASH_INDEX_GFID_MASK) | \
|
||||
(((type) << TF_HASH_TYPE_GFID_SFT) & \
|
||||
TF_HASH_TYPE_GFID_MASK); \
|
||||
} while (0)
|
||||
|
||||
#define TF_GET_HASH_INDEX_FROM_GFID(gfid, index) \
|
||||
do { \
|
||||
index = (((gfid) & TF_HASH_INDEX_GFID_MASK) >> \
|
||||
TF_HASH_INDEX_GFID_SFT); \
|
||||
} while (0)
|
||||
|
||||
#define TF_GET_HASH_TYPE_FROM_GFID(gfid, type) \
|
||||
do { \
|
||||
type = (((gfid) & TF_HASH_TYPE_GFID_MASK) >> \
|
||||
TF_HASH_TYPE_GFID_SFT); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#endif /* _TF_EXT_FLOW_HANDLE_H_ */
|
@ -869,6 +869,177 @@ tf_msg_session_sram_resc_flush(struct tf *tfp,
|
||||
return tfp_le_to_cpu_32(parms.tf_resp_code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends EM mem register request to Firmware
|
||||
*/
|
||||
int tf_msg_em_mem_rgtr(struct tf *tfp,
|
||||
int page_lvl,
|
||||
int page_size,
|
||||
uint64_t dma_addr,
|
||||
uint16_t *ctx_id)
|
||||
{
|
||||
int rc;
|
||||
struct hwrm_tf_ctxt_mem_rgtr_input req = { 0 };
|
||||
struct hwrm_tf_ctxt_mem_rgtr_output resp = { 0 };
|
||||
struct tfp_send_msg_parms parms = { 0 };
|
||||
|
||||
req.page_level = page_lvl;
|
||||
req.page_size = page_size;
|
||||
req.page_dir = tfp_cpu_to_le_64(dma_addr);
|
||||
|
||||
parms.tf_type = HWRM_TF_CTXT_MEM_RGTR;
|
||||
parms.req_data = (uint32_t *)&req;
|
||||
parms.req_size = sizeof(req);
|
||||
parms.resp_data = (uint32_t *)&resp;
|
||||
parms.resp_size = sizeof(resp);
|
||||
parms.mailbox = TF_KONG_MB;
|
||||
|
||||
rc = tfp_send_msg_direct(tfp,
|
||||
&parms);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
*ctx_id = tfp_le_to_cpu_16(resp.ctx_id);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends EM mem unregister request to Firmware
|
||||
*/
|
||||
int tf_msg_em_mem_unrgtr(struct tf *tfp,
|
||||
uint16_t *ctx_id)
|
||||
{
|
||||
int rc;
|
||||
struct hwrm_tf_ctxt_mem_unrgtr_input req = {0};
|
||||
struct hwrm_tf_ctxt_mem_unrgtr_output resp = {0};
|
||||
struct tfp_send_msg_parms parms = { 0 };
|
||||
|
||||
req.ctx_id = tfp_cpu_to_le_32(*ctx_id);
|
||||
|
||||
parms.tf_type = HWRM_TF_CTXT_MEM_UNRGTR;
|
||||
parms.req_data = (uint32_t *)&req;
|
||||
parms.req_size = sizeof(req);
|
||||
parms.resp_data = (uint32_t *)&resp;
|
||||
parms.resp_size = sizeof(resp);
|
||||
parms.mailbox = TF_KONG_MB;
|
||||
|
||||
rc = tfp_send_msg_direct(tfp,
|
||||
&parms);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends EM qcaps request to Firmware
|
||||
*/
|
||||
int tf_msg_em_qcaps(struct tf *tfp,
|
||||
int dir,
|
||||
struct tf_em_caps *em_caps)
|
||||
{
|
||||
int rc;
|
||||
struct hwrm_tf_ext_em_qcaps_input req = {0};
|
||||
struct hwrm_tf_ext_em_qcaps_output resp = { 0 };
|
||||
uint32_t flags;
|
||||
struct tfp_send_msg_parms parms = { 0 };
|
||||
|
||||
flags = (dir == TF_DIR_TX ? HWRM_TF_EXT_EM_QCAPS_INPUT_FLAGS_DIR_TX :
|
||||
HWRM_TF_EXT_EM_QCAPS_INPUT_FLAGS_DIR_RX);
|
||||
req.flags = tfp_cpu_to_le_32(flags);
|
||||
|
||||
parms.tf_type = HWRM_TF_EXT_EM_QCAPS;
|
||||
parms.req_data = (uint32_t *)&req;
|
||||
parms.req_size = sizeof(req);
|
||||
parms.resp_data = (uint32_t *)&resp;
|
||||
parms.resp_size = sizeof(resp);
|
||||
parms.mailbox = TF_KONG_MB;
|
||||
|
||||
rc = tfp_send_msg_direct(tfp,
|
||||
&parms);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
em_caps->supported = tfp_le_to_cpu_32(resp.supported);
|
||||
em_caps->max_entries_supported =
|
||||
tfp_le_to_cpu_32(resp.max_entries_supported);
|
||||
em_caps->key_entry_size = tfp_le_to_cpu_16(resp.key_entry_size);
|
||||
em_caps->record_entry_size =
|
||||
tfp_le_to_cpu_16(resp.record_entry_size);
|
||||
em_caps->efc_entry_size = tfp_le_to_cpu_16(resp.efc_entry_size);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends EM config request to Firmware
|
||||
*/
|
||||
int tf_msg_em_cfg(struct tf *tfp,
|
||||
uint32_t num_entries,
|
||||
uint16_t key0_ctx_id,
|
||||
uint16_t key1_ctx_id,
|
||||
uint16_t record_ctx_id,
|
||||
uint16_t efc_ctx_id,
|
||||
int dir)
|
||||
{
|
||||
int rc;
|
||||
struct hwrm_tf_ext_em_cfg_input req = {0};
|
||||
struct hwrm_tf_ext_em_cfg_output resp = {0};
|
||||
uint32_t flags;
|
||||
struct tfp_send_msg_parms parms = { 0 };
|
||||
|
||||
flags = (dir == TF_DIR_TX ? HWRM_TF_EXT_EM_CFG_INPUT_FLAGS_DIR_TX :
|
||||
HWRM_TF_EXT_EM_CFG_INPUT_FLAGS_DIR_RX);
|
||||
flags |= HWRM_TF_EXT_EM_QCAPS_INPUT_FLAGS_PREFERRED_OFFLOAD;
|
||||
|
||||
req.flags = tfp_cpu_to_le_32(flags);
|
||||
req.num_entries = tfp_cpu_to_le_32(num_entries);
|
||||
|
||||
req.key0_ctx_id = tfp_cpu_to_le_16(key0_ctx_id);
|
||||
req.key1_ctx_id = tfp_cpu_to_le_16(key1_ctx_id);
|
||||
req.record_ctx_id = tfp_cpu_to_le_16(record_ctx_id);
|
||||
req.efc_ctx_id = tfp_cpu_to_le_16(efc_ctx_id);
|
||||
|
||||
parms.tf_type = HWRM_TF_EXT_EM_CFG;
|
||||
parms.req_data = (uint32_t *)&req;
|
||||
parms.req_size = sizeof(req);
|
||||
parms.resp_data = (uint32_t *)&resp;
|
||||
parms.resp_size = sizeof(resp);
|
||||
parms.mailbox = TF_KONG_MB;
|
||||
|
||||
rc = tfp_send_msg_direct(tfp,
|
||||
&parms);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends EM operation request to Firmware
|
||||
*/
|
||||
int tf_msg_em_op(struct tf *tfp,
|
||||
int dir,
|
||||
uint16_t op)
|
||||
{
|
||||
int rc;
|
||||
struct hwrm_tf_ext_em_op_input req = {0};
|
||||
struct hwrm_tf_ext_em_op_output resp = {0};
|
||||
uint32_t flags;
|
||||
struct tfp_send_msg_parms parms = { 0 };
|
||||
|
||||
flags = (dir == TF_DIR_TX ? HWRM_TF_EXT_EM_CFG_INPUT_FLAGS_DIR_TX :
|
||||
HWRM_TF_EXT_EM_CFG_INPUT_FLAGS_DIR_RX);
|
||||
req.flags = tfp_cpu_to_le_32(flags);
|
||||
req.op = tfp_cpu_to_le_16(op);
|
||||
|
||||
parms.tf_type = HWRM_TF_EXT_EM_OP;
|
||||
parms.req_data = (uint32_t *)&req;
|
||||
parms.req_size = sizeof(req);
|
||||
parms.resp_data = (uint32_t *)&resp;
|
||||
parms.resp_size = sizeof(resp);
|
||||
parms.mailbox = TF_KONG_MB;
|
||||
|
||||
rc = tfp_send_msg_direct(tfp,
|
||||
&parms);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
tf_msg_set_tbl_entry(struct tf *tfp,
|
||||
enum tf_dir dir,
|
||||
|
@ -121,6 +121,46 @@ int tf_msg_session_sram_resc_flush(struct tf *tfp,
|
||||
enum tf_dir dir,
|
||||
struct tf_rm_entry *sram_entry);
|
||||
|
||||
/**
|
||||
* Sends EM mem register request to Firmware
|
||||
*/
|
||||
int tf_msg_em_mem_rgtr(struct tf *tfp,
|
||||
int page_lvl,
|
||||
int page_size,
|
||||
uint64_t dma_addr,
|
||||
uint16_t *ctx_id);
|
||||
|
||||
/**
|
||||
* Sends EM mem unregister request to Firmware
|
||||
*/
|
||||
int tf_msg_em_mem_unrgtr(struct tf *tfp,
|
||||
uint16_t *ctx_id);
|
||||
|
||||
/**
|
||||
* Sends EM qcaps request to Firmware
|
||||
*/
|
||||
int tf_msg_em_qcaps(struct tf *tfp,
|
||||
int dir,
|
||||
struct tf_em_caps *em_caps);
|
||||
|
||||
/**
|
||||
* Sends EM config request to Firmware
|
||||
*/
|
||||
int tf_msg_em_cfg(struct tf *tfp,
|
||||
uint32_t num_entries,
|
||||
uint16_t key0_ctx_id,
|
||||
uint16_t key1_ctx_id,
|
||||
uint16_t record_ctx_id,
|
||||
uint16_t efc_ctx_id,
|
||||
int dir);
|
||||
|
||||
/**
|
||||
* Sends EM operation request to Firmware
|
||||
*/
|
||||
int tf_msg_em_op(struct tf *tfp,
|
||||
int dir,
|
||||
uint16_t op);
|
||||
|
||||
/**
|
||||
* Sends tcam entry 'set' to the Firmware.
|
||||
*
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -7,6 +7,7 @@
|
||||
#define _TF_TBL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "stack.h"
|
||||
|
||||
enum tf_pg_tbl_lvl {
|
||||
PT_LVL_0,
|
||||
@ -15,6 +16,48 @@ enum tf_pg_tbl_lvl {
|
||||
PT_LVL_MAX
|
||||
};
|
||||
|
||||
enum tf_em_table_type {
|
||||
KEY0_TABLE,
|
||||
KEY1_TABLE,
|
||||
RECORD_TABLE,
|
||||
EFC_TABLE,
|
||||
MAX_TABLE
|
||||
};
|
||||
|
||||
struct tf_em_page_tbl {
|
||||
uint32_t pg_count;
|
||||
uint32_t pg_size;
|
||||
void **pg_va_tbl;
|
||||
uint64_t *pg_pa_tbl;
|
||||
};
|
||||
|
||||
struct tf_em_table {
|
||||
int type;
|
||||
uint32_t num_entries;
|
||||
uint16_t ctx_id;
|
||||
uint32_t entry_size;
|
||||
int num_lvl;
|
||||
uint32_t page_cnt[PT_LVL_MAX];
|
||||
uint64_t num_data_pages;
|
||||
void *l0_addr;
|
||||
uint64_t l0_dma_addr;
|
||||
struct tf_em_page_tbl pg_tbl[PT_LVL_MAX];
|
||||
};
|
||||
|
||||
struct tf_em_ctx_mem_info {
|
||||
struct tf_em_table em_tables[MAX_TABLE];
|
||||
};
|
||||
|
||||
/** table scope control block content */
|
||||
struct tf_em_caps {
|
||||
uint32_t flags;
|
||||
uint32_t supported;
|
||||
uint32_t max_entries_supported;
|
||||
uint16_t key_entry_size;
|
||||
uint16_t record_entry_size;
|
||||
uint16_t efc_entry_size;
|
||||
};
|
||||
|
||||
/** Invalid table scope id */
|
||||
#define TF_TBL_SCOPE_INVALID 0xffffffff
|
||||
|
||||
@ -27,9 +70,49 @@ enum tf_pg_tbl_lvl {
|
||||
struct tf_tbl_scope_cb {
|
||||
uint32_t tbl_scope_id;
|
||||
int index;
|
||||
struct tf_em_ctx_mem_info em_ctx_info[TF_DIR_MAX];
|
||||
struct tf_em_caps em_caps[TF_DIR_MAX];
|
||||
struct stack ext_pool[TF_DIR_MAX][TF_EXT_POOL_CNT_MAX];
|
||||
uint32_t *ext_pool_mem[TF_DIR_MAX][TF_EXT_POOL_CNT_MAX];
|
||||
};
|
||||
|
||||
/** Hardware Page sizes supported for EEM: 4K, 8K, 64K, 256K, 1M, 2M, 4M, 1G.
|
||||
* Round-down other page sizes to the lower hardware page size supported.
|
||||
*/
|
||||
#define PAGE_SHIFT 22 /** 2M */
|
||||
|
||||
#if (PAGE_SHIFT < 12) /** < 4K >> 4K */
|
||||
#define TF_EM_PAGE_SHIFT 12
|
||||
#define TF_EM_PAGE_SIZE_ENUM HWRM_TF_CTXT_MEM_RGTR_INPUT_PAGE_SIZE_4K
|
||||
#elif (PAGE_SHIFT <= 13) /** 4K, 8K */
|
||||
#define TF_EM_PAGE_SHIFT 13
|
||||
#define TF_EM_PAGE_SIZE_ENUM HWRM_TF_CTXT_MEM_RGTR_INPUT_PAGE_SIZE_8K
|
||||
#elif (PAGE_SHIFT < 16) /** 16K, 32K >> 8K */
|
||||
#define TF_EM_PAGE_SHIFT 15
|
||||
#define TF_EM_PAGE_SIZE_ENUM HWRM_TF_CTXT_MEM_RGTR_INPUT_PAGE_SIZE_32K
|
||||
#elif (PAGE_SHIFT <= 17) /** 64K, 128K >> 64K */
|
||||
#define TF_EM_PAGE_SHIFT 16
|
||||
#define TF_EM_PAGE_SIZE_ENUM HWRM_TF_CTXT_MEM_RGTR_INPUT_PAGE_SIZE_64K
|
||||
#elif (PAGE_SHIFT <= 19) /** 256K, 512K >> 256K */
|
||||
#define TF_EM_PAGE_SHIFT 18
|
||||
#define TF_EM_PAGE_SIZE_ENUM HWRM_TF_CTXT_MEM_RGTR_INPUT_PAGE_SIZE_256K
|
||||
#elif (PAGE_SHIFT <= 21) /** 1M */
|
||||
#define TF_EM_PAGE_SHIFT 20
|
||||
#define TF_EM_PAGE_SIZE_ENUM HWRM_TF_CTXT_MEM_RGTR_INPUT_PAGE_SIZE_1M
|
||||
#elif (PAGE_SHIFT <= 22) /** 2M, 4M */
|
||||
#define TF_EM_PAGE_SHIFT 21
|
||||
#define TF_EM_PAGE_SIZE_ENUM HWRM_TF_CTXT_MEM_RGTR_INPUT_PAGE_SIZE_2M
|
||||
#elif (PAGE_SHIFT <= 29) /** 8M ... 512M >> 4M */
|
||||
#define TF_EM_PAGE_SHIFT 22
|
||||
#define TF_EM_PAGE_SIZE_ENUM HWRM_TF_CTXT_MEM_RGTR_INPUT_PAGE_SIZE_4M
|
||||
#else /** >= 1G >> 1G */
|
||||
#define TF_EM_PAGE_SHIFT 30
|
||||
#define TF_EM_PAGE_SIZE_ENUM HWRM_TF_CTXT_MEM_RGTR_INPUT_PAGE_SIZE_1G
|
||||
#endif
|
||||
|
||||
#define TF_EM_PAGE_SIZE (1 << TF_EM_PAGE_SHIFT)
|
||||
#define TF_EM_PAGE_ALIGNMENT (1 << TF_EM_PAGE_SHIFT)
|
||||
|
||||
/**
|
||||
* Initialize table pool structure to indicate
|
||||
* no table scope has been associated with the
|
||||
|
Loading…
x
Reference in New Issue
Block a user