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:
Pete Spreadborough 2020-04-15 13:48:49 +05:30 committed by Ferruh Yigit
parent dba3ca8b30
commit 69c410b844
13 changed files with 3788 additions and 7 deletions

View File

@ -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

View 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_ */

View 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");
}
}

View 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_ */

View File

@ -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.

View File

@ -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_ */

View 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;
}

View 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_ */

View 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_ */

View File

@ -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,

View File

@ -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

View File

@ -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