net/bnxt: add shadow table capability with search
- Added Index Table shadow tables for searching - Added Search API to allow reuse of Table entries Signed-off-by: Mike Baucom <michael.baucom@broadcom.com> Reviewed-by: Farah Smith <farah.smith@broadcom.com>
This commit is contained in:
parent
b389a7888e
commit
0a80226921
@ -75,7 +75,6 @@ tf_open_session(struct tf *tfp,
|
||||
/* Session vs session client is decided in
|
||||
* tf_session_open_session()
|
||||
*/
|
||||
printf("TF_OPEN, %s\n", parms->ctrl_chan_name);
|
||||
rc = tf_session_open_session(tfp, &oparms);
|
||||
/* Logging handled by tf_session_open_session */
|
||||
if (rc)
|
||||
@ -953,6 +952,71 @@ tf_alloc_tbl_entry(struct tf *tfp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
tf_search_tbl_entry(struct tf *tfp,
|
||||
struct tf_search_tbl_entry_parms *parms)
|
||||
{
|
||||
int rc;
|
||||
struct tf_session *tfs;
|
||||
struct tf_dev_info *dev;
|
||||
struct tf_tbl_alloc_search_parms sparms;
|
||||
|
||||
TF_CHECK_PARMS2(tfp, parms);
|
||||
|
||||
/* Retrieve the session information */
|
||||
rc = tf_session_get_session(tfp, &tfs);
|
||||
if (rc) {
|
||||
TFP_DRV_LOG(ERR,
|
||||
"%s: Failed to lookup session, rc:%s\n",
|
||||
tf_dir_2_str(parms->dir),
|
||||
strerror(-rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Retrieve the device information */
|
||||
rc = tf_session_get_device(tfs, &dev);
|
||||
if (rc) {
|
||||
TFP_DRV_LOG(ERR,
|
||||
"%s: Failed to lookup device, rc:%s\n",
|
||||
tf_dir_2_str(parms->dir),
|
||||
strerror(-rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (dev->ops->tf_dev_alloc_search_tbl == NULL) {
|
||||
rc = -EOPNOTSUPP;
|
||||
TFP_DRV_LOG(ERR,
|
||||
"%s: Operation not supported, rc:%s\n",
|
||||
tf_dir_2_str(parms->dir),
|
||||
strerror(-rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
memset(&sparms, 0, sizeof(struct tf_tbl_alloc_search_parms));
|
||||
sparms.dir = parms->dir;
|
||||
sparms.type = parms->type;
|
||||
sparms.result = parms->result;
|
||||
sparms.result_sz_in_bytes = parms->result_sz_in_bytes;
|
||||
sparms.alloc = parms->alloc;
|
||||
sparms.tbl_scope_id = parms->tbl_scope_id;
|
||||
rc = dev->ops->tf_dev_alloc_search_tbl(tfp, &sparms);
|
||||
if (rc) {
|
||||
TFP_DRV_LOG(ERR,
|
||||
"%s: TBL allocation failed, rc:%s\n",
|
||||
tf_dir_2_str(parms->dir),
|
||||
strerror(-rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Return the outputs from the search */
|
||||
parms->hit = sparms.hit;
|
||||
parms->search_status = sparms.search_status;
|
||||
parms->ref_cnt = sparms.ref_cnt;
|
||||
parms->idx = sparms.idx;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
tf_free_tbl_entry(struct tf *tfp,
|
||||
struct tf_free_tbl_entry_parms *parms)
|
||||
|
@ -291,9 +291,9 @@ enum tf_tcam_tbl_type {
|
||||
};
|
||||
|
||||
/**
|
||||
* TCAM SEARCH STATUS
|
||||
* SEARCH STATUS
|
||||
*/
|
||||
enum tf_tcam_search_status {
|
||||
enum tf_search_status {
|
||||
/** The entry was not found, but an idx was allocated if requested. */
|
||||
MISS,
|
||||
/** The entry was found, and the result/idx are valid */
|
||||
@ -1011,7 +1011,7 @@ struct tf_search_tcam_entry_parms {
|
||||
/**
|
||||
* [out] Search result status (hit, miss, reject)
|
||||
*/
|
||||
enum tf_tcam_search_status search_status;
|
||||
enum tf_search_status search_status;
|
||||
/**
|
||||
* [out] Current refcnt after allocation
|
||||
*/
|
||||
@ -1285,6 +1285,79 @@ int tf_free_tcam_entry(struct tf *tfp,
|
||||
* @ref tf_bulk_get_tbl_entry
|
||||
*/
|
||||
|
||||
/**
|
||||
* tf_alloc_tbl_entry parameter definition
|
||||
*/
|
||||
struct tf_search_tbl_entry_parms {
|
||||
/**
|
||||
* [in] Receive or transmit direction
|
||||
*/
|
||||
enum tf_dir dir;
|
||||
/**
|
||||
* [in] Type of the allocation
|
||||
*/
|
||||
enum tf_tbl_type type;
|
||||
/**
|
||||
* [in] Table scope identifier (ignored unless TF_TBL_TYPE_EXT)
|
||||
*/
|
||||
uint32_t tbl_scope_id;
|
||||
/**
|
||||
* [in] Result data to search for
|
||||
*/
|
||||
uint8_t *result;
|
||||
/**
|
||||
* [in] Result data size in bytes
|
||||
*/
|
||||
uint16_t result_sz_in_bytes;
|
||||
/**
|
||||
* [in] Allocate on miss.
|
||||
*/
|
||||
uint8_t alloc;
|
||||
/**
|
||||
* [out] Set if matching entry found
|
||||
*/
|
||||
uint8_t hit;
|
||||
/**
|
||||
* [out] Search result status (hit, miss, reject)
|
||||
*/
|
||||
enum tf_search_status search_status;
|
||||
/**
|
||||
* [out] Current ref count after allocation
|
||||
*/
|
||||
uint16_t ref_cnt;
|
||||
/**
|
||||
* [out] Idx of allocated entry or found entry
|
||||
*/
|
||||
uint32_t idx;
|
||||
};
|
||||
|
||||
/**
|
||||
* search Table Entry (experimental)
|
||||
*
|
||||
* This function searches the shadow copy of an index table for a matching
|
||||
* entry. The result data must match for hit to be set. Only TruFlow core
|
||||
* data is accessed. If shadow_copy is not enabled, an error is returned.
|
||||
*
|
||||
* Implementation:
|
||||
*
|
||||
* A hash is performed on the result data and mappe3d to a shadow copy entry
|
||||
* where the result is populated. If the result matches the entry, hit is set,
|
||||
* ref_cnt is incremented (if alloc), and the search status indicates what
|
||||
* action the caller can take regarding setting the entry.
|
||||
*
|
||||
* search status should be used as follows:
|
||||
* - On MISS, the caller should set the result into the returned index.
|
||||
*
|
||||
* - On REJECT, the caller should reject the flow since there are no resources.
|
||||
*
|
||||
* - On Hit, the matching index is returned to the caller. Additionally, the
|
||||
* ref_cnt is updated.
|
||||
*
|
||||
* Also returns success or failure code.
|
||||
*/
|
||||
int tf_search_tbl_entry(struct tf *tfp,
|
||||
struct tf_search_tbl_entry_parms *parms);
|
||||
|
||||
/**
|
||||
* tf_alloc_tbl_entry parameter definition
|
||||
*/
|
||||
|
@ -126,7 +126,7 @@ const struct tf_dev_ops tf_dev_ops_p4 = {
|
||||
.tf_dev_alloc_ext_tbl = tf_tbl_ext_alloc,
|
||||
.tf_dev_free_tbl = tf_tbl_free,
|
||||
.tf_dev_free_ext_tbl = tf_tbl_ext_free,
|
||||
.tf_dev_alloc_search_tbl = NULL,
|
||||
.tf_dev_alloc_search_tbl = tf_tbl_alloc_search,
|
||||
.tf_dev_set_tbl = tf_tbl_set,
|
||||
.tf_dev_set_ext_tbl = tf_tbl_ext_common_set,
|
||||
.tf_dev_get_tbl = tf_tbl_get,
|
||||
|
@ -3,61 +3,783 @@
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#include <rte_common.h>
|
||||
|
||||
#include "tf_common.h"
|
||||
#include "tf_util.h"
|
||||
#include "tfp.h"
|
||||
#include "tf_core.h"
|
||||
#include "tf_shadow_tbl.h"
|
||||
#include "tf_hash.h"
|
||||
|
||||
/**
|
||||
* Shadow table DB element
|
||||
* The implementation includes 3 tables per table table type.
|
||||
* - hash table
|
||||
* - sized so that a minimum of 4 slots per shadow entry are available to
|
||||
* minimize the likelihood of collisions.
|
||||
* - shadow key table
|
||||
* - sized to the number of entries requested and is directly indexed
|
||||
* - the index is zero based and is the table index - the base address
|
||||
* - the data associated with the entry is stored in the key table.
|
||||
* - The stored key is actually the data associated with the entry.
|
||||
* - shadow result table
|
||||
* - the result table is stored separately since it only needs to be accessed
|
||||
* when the key matches.
|
||||
* - the result has a back pointer to the hash table via the hb handle. The
|
||||
* hb handle is a 32 bit represention of the hash with a valid bit, bucket
|
||||
* element index, and the hash index. It is necessary to store the hb handle
|
||||
* with the result since subsequent removes only provide the table index.
|
||||
*
|
||||
* - Max entries is limited in the current implementation since bit 15 is the
|
||||
* valid bit in the hash table.
|
||||
* - A 16bit hash is calculated and masked based on the number of entries
|
||||
* - 64b wide bucket is used and broken into 4x16bit elements.
|
||||
* This decision is based on quicker bucket scanning to determine if any
|
||||
* elements are in use.
|
||||
* - bit 15 of each bucket element is the valid, this is done to prevent having
|
||||
* to read the larger key/result data for determining VALID. It also aids
|
||||
* in the more efficient scanning of the bucket for slot usage.
|
||||
*/
|
||||
struct tf_shadow_tbl_element {
|
||||
/**
|
||||
* Hash table
|
||||
*/
|
||||
void *hash;
|
||||
|
||||
/**
|
||||
* Reference count, array of number of table type entries
|
||||
*/
|
||||
uint16_t *ref_count;
|
||||
/*
|
||||
* The maximum number of shadow entries supported. The value also doubles as
|
||||
* the maximum number of hash buckets. There are only 15 bits of data per
|
||||
* bucket to point to the shadow tables.
|
||||
*/
|
||||
#define TF_SHADOW_ENTRIES_MAX (1 << 15)
|
||||
|
||||
/* The number of elements(BE) per hash bucket (HB) */
|
||||
#define TF_SHADOW_HB_NUM_ELEM (4)
|
||||
#define TF_SHADOW_BE_VALID (1 << 15)
|
||||
#define TF_SHADOW_BE_IS_VALID(be) (((be) & TF_SHADOW_BE_VALID) != 0)
|
||||
|
||||
/**
|
||||
* The hash bucket handle is 32b
|
||||
* - bit 31, the Valid bit
|
||||
* - bit 29-30, the element
|
||||
* - bits 0-15, the hash idx (is masked based on the allocated size)
|
||||
*/
|
||||
#define TF_SHADOW_HB_HANDLE_IS_VALID(hndl) (((hndl) & (1 << 31)) != 0)
|
||||
#define TF_SHADOW_HB_HANDLE_CREATE(idx, be) ((1 << 31) | \
|
||||
((be) << 29) | (idx))
|
||||
|
||||
#define TF_SHADOW_HB_HANDLE_BE_GET(hdl) (((hdl) >> 29) & \
|
||||
(TF_SHADOW_HB_NUM_ELEM - 1))
|
||||
|
||||
#define TF_SHADOW_HB_HANDLE_HASH_GET(ctxt, hdl)((hdl) & \
|
||||
(ctxt)->hash_ctxt.hid_mask)
|
||||
|
||||
/**
|
||||
* The idx provided by the caller is within a region, so currently the base is
|
||||
* either added or subtracted from the idx to ensure it can be used as a
|
||||
* compressed index
|
||||
*/
|
||||
|
||||
/* Convert the table index to a shadow index */
|
||||
#define TF_SHADOW_IDX_TO_SHIDX(ctxt, idx) ((idx) - \
|
||||
(ctxt)->shadow_ctxt.base_addr)
|
||||
|
||||
/* Convert the shadow index to a tbl index */
|
||||
#define TF_SHADOW_SHIDX_TO_IDX(ctxt, idx) ((idx) + \
|
||||
(ctxt)->shadow_ctxt.base_addr)
|
||||
|
||||
/* Simple helper masks for clearing en element from the bucket */
|
||||
#define TF_SHADOW_BE0_MASK_CLEAR(hb) ((hb) & 0xffffffffffff0000ull)
|
||||
#define TF_SHADOW_BE1_MASK_CLEAR(hb) ((hb) & 0xffffffff0000ffffull)
|
||||
#define TF_SHADOW_BE2_MASK_CLEAR(hb) ((hb) & 0xffff0000ffffffffull)
|
||||
#define TF_SHADOW_BE3_MASK_CLEAR(hb) ((hb) & 0x0000ffffffffffffull)
|
||||
|
||||
/**
|
||||
* This should be coming from external, but for now it is assumed that no key
|
||||
* is greater than 512 bits (64B). This makes allocation of the key table
|
||||
* easier without having to allocate on the fly.
|
||||
*/
|
||||
#define TF_SHADOW_MAX_KEY_SZ 64
|
||||
|
||||
/*
|
||||
* Local only defines for the internal data.
|
||||
*/
|
||||
|
||||
/**
|
||||
* tf_shadow_tbl_shadow_key_entry is the key entry of the key table.
|
||||
* The key stored in the table is the result data of the index table.
|
||||
*/
|
||||
struct tf_shadow_tbl_shadow_key_entry {
|
||||
uint8_t key[TF_SHADOW_MAX_KEY_SZ];
|
||||
};
|
||||
|
||||
/**
|
||||
* Shadow table DB definition
|
||||
* tf_shadow_tbl_shadow_result_entry is the result table entry.
|
||||
* The result table writes are broken into two phases:
|
||||
* - The search phase, which stores the hb_handle and key size and
|
||||
* - The set phase, which writes the refcnt
|
||||
*/
|
||||
struct tf_shadow_tbl_shadow_result_entry {
|
||||
uint16_t key_size;
|
||||
uint32_t refcnt;
|
||||
uint32_t hb_handle;
|
||||
};
|
||||
|
||||
/**
|
||||
* tf_shadow_tbl_shadow_ctxt holds all information for accessing the key and
|
||||
* result tables.
|
||||
*/
|
||||
struct tf_shadow_tbl_shadow_ctxt {
|
||||
struct tf_shadow_tbl_shadow_key_entry *sh_key_tbl;
|
||||
struct tf_shadow_tbl_shadow_result_entry *sh_res_tbl;
|
||||
uint32_t base_addr;
|
||||
uint16_t num_entries;
|
||||
uint16_t alloc_idx;
|
||||
};
|
||||
|
||||
/**
|
||||
* tf_shadow_tbl_hash_ctxt holds all information related to accessing the hash
|
||||
* table.
|
||||
*/
|
||||
struct tf_shadow_tbl_hash_ctxt {
|
||||
uint64_t *hashtbl;
|
||||
uint16_t hid_mask;
|
||||
uint16_t hash_entries;
|
||||
};
|
||||
|
||||
/**
|
||||
* tf_shadow_tbl_ctxt holds the hash and shadow tables for the current shadow
|
||||
* table db. This structure is per table table type as each table table has
|
||||
* it's own shadow and hash table.
|
||||
*/
|
||||
struct tf_shadow_tbl_ctxt {
|
||||
struct tf_shadow_tbl_shadow_ctxt shadow_ctxt;
|
||||
struct tf_shadow_tbl_hash_ctxt hash_ctxt;
|
||||
};
|
||||
|
||||
/**
|
||||
* tf_shadow_tbl_db is the allocated db structure returned as an opaque
|
||||
* void * pointer to the caller during create db. It holds the pointers for
|
||||
* each table associated with the db.
|
||||
*/
|
||||
struct tf_shadow_tbl_db {
|
||||
/**
|
||||
* The DB consists of an array of elements
|
||||
*/
|
||||
struct tf_shadow_tbl_element *db;
|
||||
/* Each context holds the shadow and hash table information */
|
||||
struct tf_shadow_tbl_ctxt *ctxt[TF_TBL_TYPE_MAX];
|
||||
};
|
||||
|
||||
int
|
||||
tf_shadow_tbl_create_db(struct tf_shadow_tbl_create_db_parms *parms __rte_unused)
|
||||
/**
|
||||
* Simple routine that decides what table types can be searchable.
|
||||
*
|
||||
*/
|
||||
static int tf_shadow_tbl_is_searchable(enum tf_tbl_type type)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
switch (type) {
|
||||
case TF_TBL_TYPE_ACT_ENCAP_8B:
|
||||
case TF_TBL_TYPE_ACT_ENCAP_16B:
|
||||
case TF_TBL_TYPE_ACT_ENCAP_32B:
|
||||
case TF_TBL_TYPE_ACT_ENCAP_64B:
|
||||
case TF_TBL_TYPE_ACT_SP_SMAC:
|
||||
case TF_TBL_TYPE_ACT_SP_SMAC_IPV4:
|
||||
case TF_TBL_TYPE_ACT_SP_SMAC_IPV6:
|
||||
case TF_TBL_TYPE_ACT_MODIFY_IPV4:
|
||||
case TF_TBL_TYPE_ACT_MODIFY_SPORT:
|
||||
case TF_TBL_TYPE_ACT_MODIFY_DPORT:
|
||||
rc = 1;
|
||||
break;
|
||||
default:
|
||||
rc = 0;
|
||||
break;
|
||||
};
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of entries in the contexts shadow table.
|
||||
*/
|
||||
static inline uint16_t
|
||||
tf_shadow_tbl_sh_num_entries_get(struct tf_shadow_tbl_ctxt *ctxt)
|
||||
{
|
||||
return ctxt->shadow_ctxt.num_entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the give key with the key in the shadow table.
|
||||
*
|
||||
* Returns 0 if the keys match
|
||||
*/
|
||||
static int
|
||||
tf_shadow_tbl_key_cmp(struct tf_shadow_tbl_ctxt *ctxt,
|
||||
uint8_t *key,
|
||||
uint16_t sh_idx,
|
||||
uint16_t size)
|
||||
{
|
||||
if (size != ctxt->shadow_ctxt.sh_res_tbl[sh_idx].key_size ||
|
||||
sh_idx >= tf_shadow_tbl_sh_num_entries_get(ctxt) || !key)
|
||||
return -1;
|
||||
|
||||
return memcmp(key, ctxt->shadow_ctxt.sh_key_tbl[sh_idx].key, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the memory associated with the context.
|
||||
*/
|
||||
static void
|
||||
tf_shadow_tbl_ctxt_delete(struct tf_shadow_tbl_ctxt *ctxt)
|
||||
{
|
||||
if (!ctxt)
|
||||
return;
|
||||
|
||||
tfp_free(ctxt->hash_ctxt.hashtbl);
|
||||
tfp_free(ctxt->shadow_ctxt.sh_key_tbl);
|
||||
tfp_free(ctxt->shadow_ctxt.sh_res_tbl);
|
||||
}
|
||||
|
||||
/**
|
||||
* The TF Shadow TBL context is per TBL and holds all information relating to
|
||||
* managing the shadow and search capability. This routine allocated data that
|
||||
* needs to be deallocated by the tf_shadow_tbl_ctxt_delete prior when deleting
|
||||
* the shadow db.
|
||||
*/
|
||||
static int
|
||||
tf_shadow_tbl_ctxt_create(struct tf_shadow_tbl_ctxt *ctxt,
|
||||
uint16_t num_entries,
|
||||
uint16_t base_addr)
|
||||
{
|
||||
struct tfp_calloc_parms cparms;
|
||||
uint16_t hash_size = 1;
|
||||
uint16_t hash_mask;
|
||||
int rc;
|
||||
|
||||
/* Hash table is a power of two that holds the number of entries */
|
||||
if (num_entries > TF_SHADOW_ENTRIES_MAX) {
|
||||
TFP_DRV_LOG(ERR, "Too many entries for shadow %d > %d\n",
|
||||
num_entries,
|
||||
TF_SHADOW_ENTRIES_MAX);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
while (hash_size < num_entries)
|
||||
hash_size = hash_size << 1;
|
||||
|
||||
hash_mask = hash_size - 1;
|
||||
|
||||
/* Allocate the hash table */
|
||||
cparms.nitems = hash_size;
|
||||
cparms.size = sizeof(uint64_t);
|
||||
cparms.alignment = 0;
|
||||
rc = tfp_calloc(&cparms);
|
||||
if (rc)
|
||||
goto error;
|
||||
ctxt->hash_ctxt.hashtbl = cparms.mem_va;
|
||||
ctxt->hash_ctxt.hid_mask = hash_mask;
|
||||
ctxt->hash_ctxt.hash_entries = hash_size;
|
||||
|
||||
/* allocate the shadow tables */
|
||||
/* allocate the shadow key table */
|
||||
cparms.nitems = num_entries;
|
||||
cparms.size = sizeof(struct tf_shadow_tbl_shadow_key_entry);
|
||||
cparms.alignment = 0;
|
||||
rc = tfp_calloc(&cparms);
|
||||
if (rc)
|
||||
goto error;
|
||||
ctxt->shadow_ctxt.sh_key_tbl = cparms.mem_va;
|
||||
|
||||
/* allocate the shadow result table */
|
||||
cparms.nitems = num_entries;
|
||||
cparms.size = sizeof(struct tf_shadow_tbl_shadow_result_entry);
|
||||
cparms.alignment = 0;
|
||||
rc = tfp_calloc(&cparms);
|
||||
if (rc)
|
||||
goto error;
|
||||
ctxt->shadow_ctxt.sh_res_tbl = cparms.mem_va;
|
||||
|
||||
ctxt->shadow_ctxt.num_entries = num_entries;
|
||||
ctxt->shadow_ctxt.base_addr = base_addr;
|
||||
|
||||
return 0;
|
||||
error:
|
||||
tf_shadow_tbl_ctxt_delete(ctxt);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a shadow table context given the db and the table type
|
||||
*/
|
||||
static struct tf_shadow_tbl_ctxt *
|
||||
tf_shadow_tbl_ctxt_get(struct tf_shadow_tbl_db *shadow_db,
|
||||
enum tf_tbl_type type)
|
||||
{
|
||||
if (type >= TF_TBL_TYPE_MAX ||
|
||||
!shadow_db ||
|
||||
!shadow_db->ctxt[type])
|
||||
return NULL;
|
||||
|
||||
return shadow_db->ctxt[type];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the hash entry into the table given the table context, hash bucket
|
||||
* handle, and shadow index.
|
||||
*/
|
||||
static inline int
|
||||
tf_shadow_tbl_set_hash_entry(struct tf_shadow_tbl_ctxt *ctxt,
|
||||
uint32_t hb_handle,
|
||||
uint16_t sh_idx)
|
||||
{
|
||||
uint16_t hid = TF_SHADOW_HB_HANDLE_HASH_GET(ctxt, hb_handle);
|
||||
uint16_t be = TF_SHADOW_HB_HANDLE_BE_GET(hb_handle);
|
||||
uint64_t entry = sh_idx | TF_SHADOW_BE_VALID;
|
||||
|
||||
if (hid >= ctxt->hash_ctxt.hash_entries)
|
||||
return -EINVAL;
|
||||
|
||||
ctxt->hash_ctxt.hashtbl[hid] |= entry << (be * 16);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the hash entry given the TBL context and hash bucket handle.
|
||||
*/
|
||||
static inline void
|
||||
tf_shadow_tbl_clear_hash_entry(struct tf_shadow_tbl_ctxt *ctxt,
|
||||
uint32_t hb_handle)
|
||||
{
|
||||
uint16_t hid, be;
|
||||
uint64_t *bucket;
|
||||
|
||||
if (!TF_SHADOW_HB_HANDLE_IS_VALID(hb_handle))
|
||||
return;
|
||||
|
||||
hid = TF_SHADOW_HB_HANDLE_HASH_GET(ctxt, hb_handle);
|
||||
be = TF_SHADOW_HB_HANDLE_BE_GET(hb_handle);
|
||||
bucket = &ctxt->hash_ctxt.hashtbl[hid];
|
||||
|
||||
switch (be) {
|
||||
case 0:
|
||||
*bucket = TF_SHADOW_BE0_MASK_CLEAR(*bucket);
|
||||
break;
|
||||
case 1:
|
||||
*bucket = TF_SHADOW_BE1_MASK_CLEAR(*bucket);
|
||||
break;
|
||||
case 2:
|
||||
*bucket = TF_SHADOW_BE2_MASK_CLEAR(*bucket);
|
||||
break;
|
||||
case 3:
|
||||
*bucket = TF_SHADOW_BE2_MASK_CLEAR(*bucket);
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* Since the BE_GET masks non-inclusive bits, this will not
|
||||
* happen.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the shadow key and result entries given the table context and
|
||||
* shadow index.
|
||||
*/
|
||||
static void
|
||||
tf_shadow_tbl_clear_sh_entry(struct tf_shadow_tbl_ctxt *ctxt,
|
||||
uint16_t sh_idx)
|
||||
{
|
||||
struct tf_shadow_tbl_shadow_key_entry *sk_entry;
|
||||
struct tf_shadow_tbl_shadow_result_entry *sr_entry;
|
||||
|
||||
if (sh_idx >= tf_shadow_tbl_sh_num_entries_get(ctxt))
|
||||
return;
|
||||
|
||||
sk_entry = &ctxt->shadow_ctxt.sh_key_tbl[sh_idx];
|
||||
sr_entry = &ctxt->shadow_ctxt.sh_res_tbl[sh_idx];
|
||||
|
||||
/*
|
||||
* memset key/result to zero for now, possibly leave the data alone
|
||||
* in the future and rely on the valid bit in the hash table.
|
||||
*/
|
||||
memset(sk_entry, 0, sizeof(struct tf_shadow_tbl_shadow_key_entry));
|
||||
memset(sr_entry, 0, sizeof(struct tf_shadow_tbl_shadow_result_entry));
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the allocated tbl index with the hash and shadow tables.
|
||||
* The entry will be incomplete until the set has happened with the result
|
||||
* data.
|
||||
*/
|
||||
int
|
||||
tf_shadow_tbl_bind_index(struct tf_shadow_tbl_bind_index_parms *parms)
|
||||
{
|
||||
int rc;
|
||||
uint16_t idx, len;
|
||||
struct tf_shadow_tbl_ctxt *ctxt;
|
||||
struct tf_shadow_tbl_db *shadow_db;
|
||||
struct tf_shadow_tbl_shadow_key_entry *sk_entry;
|
||||
struct tf_shadow_tbl_shadow_result_entry *sr_entry;
|
||||
|
||||
if (!parms || !TF_SHADOW_HB_HANDLE_IS_VALID(parms->hb_handle) ||
|
||||
!parms->data) {
|
||||
TFP_DRV_LOG(ERR, "Invalid parms\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
shadow_db = (struct tf_shadow_tbl_db *)parms->shadow_db;
|
||||
ctxt = tf_shadow_tbl_ctxt_get(shadow_db, parms->type);
|
||||
if (!ctxt) {
|
||||
TFP_DRV_LOG(DEBUG, "%s no ctxt for table\n",
|
||||
tf_tbl_type_2_str(parms->type));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
idx = TF_SHADOW_IDX_TO_SHIDX(ctxt, parms->idx);
|
||||
len = parms->data_sz_in_bytes;
|
||||
if (idx >= tf_shadow_tbl_sh_num_entries_get(ctxt) ||
|
||||
len > TF_SHADOW_MAX_KEY_SZ) {
|
||||
TFP_DRV_LOG(ERR, "%s:%s Invalid len (%d) > %d || oob idx %d\n",
|
||||
tf_dir_2_str(parms->dir),
|
||||
tf_tbl_type_2_str(parms->type),
|
||||
len,
|
||||
TF_SHADOW_MAX_KEY_SZ, idx);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = tf_shadow_tbl_set_hash_entry(ctxt, parms->hb_handle, idx);
|
||||
if (rc)
|
||||
return -EINVAL;
|
||||
|
||||
sk_entry = &ctxt->shadow_ctxt.sh_key_tbl[idx];
|
||||
sr_entry = &ctxt->shadow_ctxt.sh_res_tbl[idx];
|
||||
|
||||
/* For tables, the data is the key */
|
||||
memcpy(sk_entry->key, parms->data, len);
|
||||
|
||||
/* Write the result table */
|
||||
sr_entry->key_size = len;
|
||||
sr_entry->hb_handle = parms->hb_handle;
|
||||
sr_entry->refcnt = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes hash/shadow information if no more references.
|
||||
*
|
||||
* Returns 0 - The caller should delete the table entry in hardware.
|
||||
* Returns non-zero - The number of references to the entry
|
||||
*/
|
||||
int
|
||||
tf_shadow_tbl_remove(struct tf_shadow_tbl_remove_parms *parms)
|
||||
{
|
||||
uint16_t idx;
|
||||
uint32_t hb_handle;
|
||||
struct tf_shadow_tbl_ctxt *ctxt;
|
||||
struct tf_shadow_tbl_db *shadow_db;
|
||||
struct tf_tbl_free_parms *fparms;
|
||||
struct tf_shadow_tbl_shadow_result_entry *sr_entry;
|
||||
|
||||
if (!parms || !parms->fparms) {
|
||||
TFP_DRV_LOG(ERR, "Invalid parms\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fparms = parms->fparms;
|
||||
if (!tf_shadow_tbl_is_searchable(fparms->type))
|
||||
return 0;
|
||||
/*
|
||||
* Initialize the ref count to zero. The default would be to remove
|
||||
* the entry.
|
||||
*/
|
||||
fparms->ref_cnt = 0;
|
||||
|
||||
shadow_db = (struct tf_shadow_tbl_db *)parms->shadow_db;
|
||||
ctxt = tf_shadow_tbl_ctxt_get(shadow_db, fparms->type);
|
||||
if (!ctxt) {
|
||||
TFP_DRV_LOG(DEBUG, "%s no ctxt for table\n",
|
||||
tf_tbl_type_2_str(fparms->type));
|
||||
return 0;
|
||||
}
|
||||
|
||||
idx = TF_SHADOW_IDX_TO_SHIDX(ctxt, fparms->idx);
|
||||
if (idx >= tf_shadow_tbl_sh_num_entries_get(ctxt)) {
|
||||
TFP_DRV_LOG(DEBUG, "%s %d >= %d\n",
|
||||
tf_tbl_type_2_str(fparms->type),
|
||||
fparms->idx,
|
||||
tf_shadow_tbl_sh_num_entries_get(ctxt));
|
||||
return 0;
|
||||
}
|
||||
|
||||
sr_entry = &ctxt->shadow_ctxt.sh_res_tbl[idx];
|
||||
if (sr_entry->refcnt <= 1) {
|
||||
hb_handle = sr_entry->hb_handle;
|
||||
tf_shadow_tbl_clear_hash_entry(ctxt, hb_handle);
|
||||
tf_shadow_tbl_clear_sh_entry(ctxt, idx);
|
||||
} else {
|
||||
sr_entry->refcnt--;
|
||||
fparms->ref_cnt = sr_entry->refcnt;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
tf_shadow_tbl_free_db(struct tf_shadow_tbl_free_db_parms *parms __rte_unused)
|
||||
tf_shadow_tbl_search(struct tf_shadow_tbl_search_parms *parms)
|
||||
{
|
||||
uint16_t len;
|
||||
uint64_t bucket;
|
||||
uint32_t i, hid32;
|
||||
struct tf_shadow_tbl_ctxt *ctxt;
|
||||
struct tf_shadow_tbl_db *shadow_db;
|
||||
uint16_t hid16, hb_idx, hid_mask, shtbl_idx, shtbl_key, be_valid;
|
||||
struct tf_tbl_alloc_search_parms *sparms;
|
||||
uint32_t be_avail = TF_SHADOW_HB_NUM_ELEM;
|
||||
|
||||
if (!parms || !parms->sparms) {
|
||||
TFP_DRV_LOG(ERR, "tbl search with invalid parms\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sparms = parms->sparms;
|
||||
/* Check that caller was supposed to call search */
|
||||
if (!tf_shadow_tbl_is_searchable(sparms->type))
|
||||
return -EINVAL;
|
||||
|
||||
/* Initialize return values to invalid */
|
||||
sparms->hit = 0;
|
||||
sparms->search_status = REJECT;
|
||||
parms->hb_handle = 0;
|
||||
sparms->ref_cnt = 0;
|
||||
|
||||
shadow_db = (struct tf_shadow_tbl_db *)parms->shadow_db;
|
||||
ctxt = tf_shadow_tbl_ctxt_get(shadow_db, sparms->type);
|
||||
if (!ctxt) {
|
||||
TFP_DRV_LOG(ERR, "%s Unable to get tbl mgr context\n",
|
||||
tf_tbl_type_2_str(sparms->type));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
len = sparms->result_sz_in_bytes;
|
||||
if (len > TF_SHADOW_MAX_KEY_SZ || !sparms->result || !len) {
|
||||
TFP_DRV_LOG(ERR, "%s:%s Invalid parms %d : %p\n",
|
||||
tf_dir_2_str(sparms->dir),
|
||||
tf_tbl_type_2_str(sparms->type),
|
||||
len,
|
||||
sparms->result);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the crc32
|
||||
* Fold it to create a 16b value
|
||||
* Reduce it to fit the table
|
||||
*/
|
||||
hid32 = tf_hash_calc_crc32(sparms->result, len);
|
||||
hid16 = (uint16_t)(((hid32 >> 16) & 0xffff) ^ (hid32 & 0xffff));
|
||||
hid_mask = ctxt->hash_ctxt.hid_mask;
|
||||
hb_idx = hid16 & hid_mask;
|
||||
|
||||
bucket = ctxt->hash_ctxt.hashtbl[hb_idx];
|
||||
if (!bucket) {
|
||||
/* empty bucket means a miss and available entry */
|
||||
sparms->search_status = MISS;
|
||||
parms->hb_handle = TF_SHADOW_HB_HANDLE_CREATE(hb_idx, 0);
|
||||
sparms->idx = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set the avail to max so we can detect when there is an avail entry */
|
||||
be_avail = TF_SHADOW_HB_NUM_ELEM;
|
||||
for (i = 0; i < TF_SHADOW_HB_NUM_ELEM; i++) {
|
||||
shtbl_idx = (uint16_t)((bucket >> (i * 16)) & 0xffff);
|
||||
be_valid = TF_SHADOW_BE_IS_VALID(shtbl_idx);
|
||||
if (!be_valid) {
|
||||
/* The element is avail, keep going */
|
||||
be_avail = i;
|
||||
continue;
|
||||
}
|
||||
/* There is a valid entry, compare it */
|
||||
shtbl_key = shtbl_idx & ~TF_SHADOW_BE_VALID;
|
||||
if (!tf_shadow_tbl_key_cmp(ctxt,
|
||||
sparms->result,
|
||||
shtbl_key,
|
||||
len)) {
|
||||
/*
|
||||
* It matches, increment the ref count if the caller
|
||||
* requested allocation and return the info
|
||||
*/
|
||||
if (sparms->alloc)
|
||||
ctxt->shadow_ctxt.sh_res_tbl[shtbl_key].refcnt =
|
||||
ctxt->shadow_ctxt.sh_res_tbl[shtbl_key].refcnt + 1;
|
||||
|
||||
sparms->hit = 1;
|
||||
sparms->search_status = HIT;
|
||||
parms->hb_handle =
|
||||
TF_SHADOW_HB_HANDLE_CREATE(hb_idx, i);
|
||||
sparms->idx = TF_SHADOW_SHIDX_TO_IDX(ctxt, shtbl_key);
|
||||
sparms->ref_cnt =
|
||||
ctxt->shadow_ctxt.sh_res_tbl[shtbl_key].refcnt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* No hits, return avail entry if exists */
|
||||
if (be_avail < TF_SHADOW_HB_NUM_ELEM) {
|
||||
/*
|
||||
* There is an available hash entry, so return MISS and the
|
||||
* hash handle for the subsequent bind.
|
||||
*/
|
||||
parms->hb_handle = TF_SHADOW_HB_HANDLE_CREATE(hb_idx, be_avail);
|
||||
sparms->search_status = MISS;
|
||||
sparms->hit = 0;
|
||||
sparms->idx = 0;
|
||||
} else {
|
||||
/* No room for the entry in the hash table, must REJECT */
|
||||
sparms->search_status = REJECT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
tf_shadow_tbl_search(struct tf_shadow_tbl_search_parms *parms __rte_unused)
|
||||
tf_shadow_tbl_insert(struct tf_shadow_tbl_insert_parms *parms)
|
||||
{
|
||||
uint16_t idx;
|
||||
struct tf_shadow_tbl_ctxt *ctxt;
|
||||
struct tf_tbl_set_parms *sparms;
|
||||
struct tf_shadow_tbl_db *shadow_db;
|
||||
struct tf_shadow_tbl_shadow_result_entry *sr_entry;
|
||||
|
||||
if (!parms || !parms->sparms) {
|
||||
TFP_DRV_LOG(ERR, "Null parms\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sparms = parms->sparms;
|
||||
if (!sparms->data || !sparms->data_sz_in_bytes) {
|
||||
TFP_DRV_LOG(ERR, "%s:%s No result to set.\n",
|
||||
tf_dir_2_str(sparms->dir),
|
||||
tf_tbl_type_2_str(sparms->type));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
shadow_db = (struct tf_shadow_tbl_db *)parms->shadow_db;
|
||||
ctxt = tf_shadow_tbl_ctxt_get(shadow_db, sparms->type);
|
||||
if (!ctxt) {
|
||||
/* We aren't tracking this table, so return success */
|
||||
TFP_DRV_LOG(DEBUG, "%s Unable to get tbl mgr context\n",
|
||||
tf_tbl_type_2_str(sparms->type));
|
||||
return 0;
|
||||
}
|
||||
|
||||
idx = TF_SHADOW_IDX_TO_SHIDX(ctxt, sparms->idx);
|
||||
if (idx >= tf_shadow_tbl_sh_num_entries_get(ctxt)) {
|
||||
TFP_DRV_LOG(ERR, "%s:%s Invalid idx(0x%x)\n",
|
||||
tf_dir_2_str(sparms->dir),
|
||||
tf_tbl_type_2_str(sparms->type),
|
||||
sparms->idx);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Write the result table, the key/hash has been written already */
|
||||
sr_entry = &ctxt->shadow_ctxt.sh_res_tbl[idx];
|
||||
|
||||
/*
|
||||
* If the handle is not valid, the bind was never called. We aren't
|
||||
* tracking this entry.
|
||||
*/
|
||||
if (!TF_SHADOW_HB_HANDLE_IS_VALID(sr_entry->hb_handle))
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
tf_shadow_tbl_insert(struct tf_shadow_tbl_insert_parms *parms __rte_unused)
|
||||
tf_shadow_tbl_free_db(struct tf_shadow_tbl_free_db_parms *parms)
|
||||
{
|
||||
struct tf_shadow_tbl_db *shadow_db;
|
||||
int i;
|
||||
|
||||
TF_CHECK_PARMS1(parms);
|
||||
|
||||
shadow_db = (struct tf_shadow_tbl_db *)parms->shadow_db;
|
||||
if (!shadow_db) {
|
||||
TFP_DRV_LOG(DEBUG, "Shadow db is NULL cannot be freed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < TF_TBL_TYPE_MAX; i++) {
|
||||
if (shadow_db->ctxt[i]) {
|
||||
tf_shadow_tbl_ctxt_delete(shadow_db->ctxt[i]);
|
||||
tfp_free(shadow_db->ctxt[i]);
|
||||
}
|
||||
}
|
||||
|
||||
tfp_free(shadow_db);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
tf_shadow_tbl_remove(struct tf_shadow_tbl_remove_parms *parms __rte_unused)
|
||||
/**
|
||||
* Allocate the table resources for search and allocate
|
||||
*
|
||||
*/
|
||||
int tf_shadow_tbl_create_db(struct tf_shadow_tbl_create_db_parms *parms)
|
||||
{
|
||||
int rc;
|
||||
int i;
|
||||
uint16_t base;
|
||||
struct tfp_calloc_parms cparms;
|
||||
struct tf_shadow_tbl_db *shadow_db = NULL;
|
||||
|
||||
TF_CHECK_PARMS1(parms);
|
||||
|
||||
/* Build the shadow DB per the request */
|
||||
cparms.nitems = 1;
|
||||
cparms.size = sizeof(struct tf_shadow_tbl_db);
|
||||
cparms.alignment = 0;
|
||||
rc = tfp_calloc(&cparms);
|
||||
if (rc)
|
||||
return rc;
|
||||
shadow_db = (void *)cparms.mem_va;
|
||||
|
||||
for (i = 0; i < TF_TBL_TYPE_MAX; i++) {
|
||||
/* If the element didn't request an allocation no need
|
||||
* to create a pool nor verify if we got a reservation.
|
||||
*/
|
||||
if (!parms->cfg->alloc_cnt[i] ||
|
||||
!tf_shadow_tbl_is_searchable(i)) {
|
||||
shadow_db->ctxt[i] = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
cparms.nitems = 1;
|
||||
cparms.size = sizeof(struct tf_shadow_tbl_ctxt);
|
||||
cparms.alignment = 0;
|
||||
rc = tfp_calloc(&cparms);
|
||||
if (rc)
|
||||
goto error;
|
||||
|
||||
shadow_db->ctxt[i] = cparms.mem_va;
|
||||
base = parms->cfg->base_addr[i];
|
||||
rc = tf_shadow_tbl_ctxt_create(shadow_db->ctxt[i],
|
||||
parms->cfg->alloc_cnt[i],
|
||||
base);
|
||||
if (rc)
|
||||
goto error;
|
||||
}
|
||||
|
||||
*parms->shadow_db = (void *)shadow_db;
|
||||
|
||||
TFP_DRV_LOG(INFO,
|
||||
"TF SHADOW TABLE - initialized\n");
|
||||
|
||||
return 0;
|
||||
error:
|
||||
for (i = 0; i < TF_TBL_TYPE_MAX; i++) {
|
||||
if (shadow_db->ctxt[i]) {
|
||||
tf_shadow_tbl_ctxt_delete(shadow_db->ctxt[i]);
|
||||
tfp_free(shadow_db->ctxt[i]);
|
||||
}
|
||||
}
|
||||
|
||||
tfp_free(shadow_db);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
@ -8,8 +8,6 @@
|
||||
|
||||
#include "tf_core.h"
|
||||
|
||||
struct tf;
|
||||
|
||||
/**
|
||||
* The Shadow Table module provides shadow DB handling for table based
|
||||
* TF types. A shadow DB provides the capability that allows for reuse
|
||||
@ -32,37 +30,40 @@ struct tf;
|
||||
*/
|
||||
struct tf_shadow_tbl_cfg_parms {
|
||||
/**
|
||||
* TF Table type
|
||||
*/
|
||||
enum tf_tbl_type type;
|
||||
|
||||
/**
|
||||
* Number of entries the Shadow DB needs to hold
|
||||
* [in] The number of elements in the alloc_cnt and base_addr
|
||||
* For now, it should always be equal to TF_TBL_TYPE_MAX
|
||||
*/
|
||||
int num_entries;
|
||||
|
||||
/**
|
||||
* Element width for this table type
|
||||
* [in] Resource allocation count array
|
||||
* This array content originates from the tf_session_resources
|
||||
* that is passed in on session open
|
||||
* Array size is TF_TBL_TYPE_MAX
|
||||
*/
|
||||
int element_width;
|
||||
uint16_t *alloc_cnt;
|
||||
/**
|
||||
* [in] The base index for each table
|
||||
*/
|
||||
uint16_t base_addr[TF_TBL_TYPE_MAX];
|
||||
};
|
||||
|
||||
/**
|
||||
* Shadow table DB creation parameters
|
||||
*/
|
||||
struct tf_shadow_tbl_create_db_parms {
|
||||
/**
|
||||
* [in] Receive or transmit direction
|
||||
*/
|
||||
enum tf_dir dir;
|
||||
/**
|
||||
* [in] Configuration information for the shadow db
|
||||
*/
|
||||
struct tf_shadow_tbl_cfg_parms *cfg;
|
||||
/**
|
||||
* [in] Number of elements in the parms structure
|
||||
*/
|
||||
uint16_t num_elements;
|
||||
/**
|
||||
* [out] Shadow table DB handle
|
||||
*/
|
||||
void *tf_shadow_tbl_db;
|
||||
void **shadow_db;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -70,9 +71,9 @@ struct tf_shadow_tbl_create_db_parms {
|
||||
*/
|
||||
struct tf_shadow_tbl_free_db_parms {
|
||||
/**
|
||||
* Shadow table DB handle
|
||||
* [in] Shadow table DB handle
|
||||
*/
|
||||
void *tf_shadow_tbl_db;
|
||||
void *shadow_db;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -82,27 +83,49 @@ struct tf_shadow_tbl_search_parms {
|
||||
/**
|
||||
* [in] Shadow table DB handle
|
||||
*/
|
||||
void *tf_shadow_tbl_db;
|
||||
void *shadow_db;
|
||||
/**
|
||||
* [in] Table type
|
||||
* [in,out] The search parms from tf core
|
||||
*/
|
||||
enum tf_tbl_type type;
|
||||
/**
|
||||
* [in] Pointer to entry blob value in remap table to match
|
||||
*/
|
||||
uint8_t *entry;
|
||||
/**
|
||||
* [in] Size of the entry blob passed in bytes
|
||||
*/
|
||||
uint16_t entry_sz;
|
||||
/**
|
||||
* [out] Index of the found element returned if hit
|
||||
*/
|
||||
uint16_t *index;
|
||||
struct tf_tbl_alloc_search_parms *sparms;
|
||||
/**
|
||||
* [out] Reference count incremented if hit
|
||||
*/
|
||||
uint16_t *ref_cnt;
|
||||
uint32_t hb_handle;
|
||||
};
|
||||
|
||||
/**
|
||||
* Shadow Table bind index parameters
|
||||
*/
|
||||
struct tf_shadow_tbl_bind_index_parms {
|
||||
/**
|
||||
* [in] Shadow tcam DB handle
|
||||
*/
|
||||
void *shadow_db;
|
||||
/**
|
||||
* [in] receive or transmit direction
|
||||
*/
|
||||
enum tf_dir dir;
|
||||
/**
|
||||
* [in] TCAM table type
|
||||
*/
|
||||
enum tf_tbl_type type;
|
||||
/**
|
||||
* [in] index of the entry to program
|
||||
*/
|
||||
uint16_t idx;
|
||||
/**
|
||||
* [in] struct containing key
|
||||
*/
|
||||
uint8_t *data;
|
||||
/**
|
||||
* [in] data size in bytes
|
||||
*/
|
||||
uint16_t data_sz_in_bytes;
|
||||
/**
|
||||
* [in] The hash bucket handled returned from the search
|
||||
*/
|
||||
uint32_t hb_handle;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -112,27 +135,11 @@ struct tf_shadow_tbl_insert_parms {
|
||||
/**
|
||||
* [in] Shadow table DB handle
|
||||
*/
|
||||
void *tf_shadow_tbl_db;
|
||||
void *shadow_db;
|
||||
/**
|
||||
* [in] Tbl type
|
||||
* [in] The insert parms from tf core
|
||||
*/
|
||||
enum tf_tbl_type type;
|
||||
/**
|
||||
* [in] Pointer to entry blob value in remap table to match
|
||||
*/
|
||||
uint8_t *entry;
|
||||
/**
|
||||
* [in] Size of the entry blob passed in bytes
|
||||
*/
|
||||
uint16_t entry_sz;
|
||||
/**
|
||||
* [in] Entry to update
|
||||
*/
|
||||
uint16_t index;
|
||||
/**
|
||||
* [out] Reference count after insert
|
||||
*/
|
||||
uint16_t *ref_cnt;
|
||||
struct tf_tbl_set_parms *sparms;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -142,19 +149,11 @@ struct tf_shadow_tbl_remove_parms {
|
||||
/**
|
||||
* [in] Shadow table DB handle
|
||||
*/
|
||||
void *tf_shadow_tbl_db;
|
||||
void *shadow_db;
|
||||
/**
|
||||
* [in] Tbl type
|
||||
* [in] The free parms from tf core
|
||||
*/
|
||||
enum tf_tbl_type type;
|
||||
/**
|
||||
* [in] Entry to update
|
||||
*/
|
||||
uint16_t index;
|
||||
/**
|
||||
* [out] Reference count after removal
|
||||
*/
|
||||
uint16_t *ref_cnt;
|
||||
struct tf_tbl_free_parms *fparms;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -206,9 +205,26 @@ int tf_shadow_tbl_free_db(struct tf_shadow_tbl_free_db_parms *parms);
|
||||
* Returns
|
||||
* - (0) if successful, element was found.
|
||||
* - (-EINVAL) on failure.
|
||||
*
|
||||
* If there is a miss, but there is room for insertion, the hb_handle returned
|
||||
* is used for insertion during the bind index API
|
||||
*/
|
||||
int tf_shadow_tbl_search(struct tf_shadow_tbl_search_parms *parms);
|
||||
|
||||
/**
|
||||
* Bind Shadow table db hash and result tables with result from search/alloc
|
||||
*
|
||||
* [in] parms
|
||||
* Pointer to the search parameters
|
||||
*
|
||||
* Returns
|
||||
* - (0) if successful
|
||||
* - (-EINVAL) on failure.
|
||||
*
|
||||
* This is only called after a MISS in the search returns a hb_handle
|
||||
*/
|
||||
int tf_shadow_tbl_bind_index(struct tf_shadow_tbl_bind_index_parms *parms);
|
||||
|
||||
/**
|
||||
* Inserts an element into the Shadow table DB. Will fail if the
|
||||
* elements ref_count is different from 0. Ref_count after insert will
|
||||
|
@ -373,6 +373,12 @@ tf_shadow_tcam_clear_hash_entry(struct tf_shadow_tcam_ctxt *ctxt,
|
||||
case 3:
|
||||
*bucket = TF_SHADOW_TCAM_BE2_MASK_CLEAR(*bucket);
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* Since the BE_GET masks non-inclusive bits, this will not
|
||||
* happen.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,9 @@
|
||||
#include "tf_util.h"
|
||||
#include "tf_msg.h"
|
||||
#include "tfp.h"
|
||||
#include "tf_shadow_tbl.h"
|
||||
#include "tf_session.h"
|
||||
#include "tf_device.h"
|
||||
|
||||
|
||||
struct tf;
|
||||
@ -25,7 +28,7 @@ static void *tbl_db[TF_DIR_MAX];
|
||||
/**
|
||||
* Table Shadow DBs
|
||||
*/
|
||||
/* static void *shadow_tbl_db[TF_DIR_MAX]; */
|
||||
static void *shadow_tbl_db[TF_DIR_MAX];
|
||||
|
||||
/**
|
||||
* Init flag, set on bind and cleared on unbind
|
||||
@ -35,14 +38,19 @@ static uint8_t init;
|
||||
/**
|
||||
* Shadow init flag, set on bind and cleared on unbind
|
||||
*/
|
||||
/* static uint8_t shadow_init; */
|
||||
static uint8_t shadow_init;
|
||||
|
||||
int
|
||||
tf_tbl_bind(struct tf *tfp,
|
||||
struct tf_tbl_cfg_parms *parms)
|
||||
{
|
||||
int rc;
|
||||
int i;
|
||||
int rc, d, i;
|
||||
struct tf_rm_alloc_info info;
|
||||
struct tf_rm_free_db_parms fparms;
|
||||
struct tf_shadow_tbl_free_db_parms fshadow;
|
||||
struct tf_rm_get_alloc_info_parms ainfo;
|
||||
struct tf_shadow_tbl_cfg_parms shadow_cfg;
|
||||
struct tf_shadow_tbl_create_db_parms shadow_cdb;
|
||||
struct tf_rm_create_db_parms db_cfg = { 0 };
|
||||
|
||||
TF_CHECK_PARMS2(tfp, parms);
|
||||
@ -58,26 +66,86 @@ tf_tbl_bind(struct tf *tfp,
|
||||
db_cfg.num_elements = parms->num_elements;
|
||||
db_cfg.cfg = parms->cfg;
|
||||
|
||||
for (i = 0; i < TF_DIR_MAX; i++) {
|
||||
db_cfg.dir = i;
|
||||
db_cfg.alloc_cnt = parms->resources->tbl_cnt[i].cnt;
|
||||
db_cfg.rm_db = &tbl_db[i];
|
||||
for (d = 0; d < TF_DIR_MAX; d++) {
|
||||
db_cfg.dir = d;
|
||||
db_cfg.alloc_cnt = parms->resources->tbl_cnt[d].cnt;
|
||||
db_cfg.rm_db = &tbl_db[d];
|
||||
rc = tf_rm_create_db(tfp, &db_cfg);
|
||||
if (rc) {
|
||||
TFP_DRV_LOG(ERR,
|
||||
"%s: Table DB creation failed\n",
|
||||
tf_dir_2_str(i));
|
||||
tf_dir_2_str(d));
|
||||
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize the Shadow Table. */
|
||||
if (parms->shadow_copy) {
|
||||
for (d = 0; d < TF_DIR_MAX; d++) {
|
||||
memset(&shadow_cfg, 0, sizeof(shadow_cfg));
|
||||
memset(&shadow_cdb, 0, sizeof(shadow_cdb));
|
||||
/* Get the base addresses of the tables */
|
||||
for (i = 0; i < TF_TBL_TYPE_MAX; i++) {
|
||||
memset(&info, 0, sizeof(info));
|
||||
|
||||
if (!parms->resources->tbl_cnt[d].cnt[i])
|
||||
continue;
|
||||
ainfo.rm_db = tbl_db[d];
|
||||
ainfo.db_index = i;
|
||||
ainfo.info = &info;
|
||||
rc = tf_rm_get_info(&ainfo);
|
||||
if (rc)
|
||||
goto error;
|
||||
|
||||
shadow_cfg.base_addr[i] = info.entry.start;
|
||||
}
|
||||
|
||||
/* Create the shadow db */
|
||||
shadow_cfg.alloc_cnt =
|
||||
parms->resources->tbl_cnt[d].cnt;
|
||||
shadow_cfg.num_entries = parms->num_elements;
|
||||
|
||||
shadow_cdb.shadow_db = &shadow_tbl_db[d];
|
||||
shadow_cdb.cfg = &shadow_cfg;
|
||||
rc = tf_shadow_tbl_create_db(&shadow_cdb);
|
||||
if (rc) {
|
||||
TFP_DRV_LOG(ERR,
|
||||
"Shadow TBL DB creation failed "
|
||||
"rc=%d\n", rc);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
shadow_init = 1;
|
||||
}
|
||||
|
||||
init = 1;
|
||||
|
||||
TFP_DRV_LOG(INFO,
|
||||
"Table Type - initialized\n");
|
||||
|
||||
return 0;
|
||||
error:
|
||||
for (d = 0; d < TF_DIR_MAX; d++) {
|
||||
memset(&fparms, 0, sizeof(fparms));
|
||||
fparms.dir = d;
|
||||
fparms.rm_db = tbl_db[d];
|
||||
/* Ignoring return here since we are in the error case */
|
||||
(void)tf_rm_free_db(tfp, &fparms);
|
||||
|
||||
if (parms->shadow_copy) {
|
||||
fshadow.shadow_db = shadow_tbl_db[d];
|
||||
tf_shadow_tbl_free_db(&fshadow);
|
||||
shadow_tbl_db[d] = NULL;
|
||||
}
|
||||
|
||||
tbl_db[d] = NULL;
|
||||
}
|
||||
|
||||
shadow_init = 0;
|
||||
init = 0;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
@ -86,6 +154,7 @@ tf_tbl_unbind(struct tf *tfp)
|
||||
int rc;
|
||||
int i;
|
||||
struct tf_rm_free_db_parms fparms = { 0 };
|
||||
struct tf_shadow_tbl_free_db_parms fshadow;
|
||||
|
||||
TF_CHECK_PARMS1(tfp);
|
||||
|
||||
@ -104,9 +173,17 @@ tf_tbl_unbind(struct tf *tfp)
|
||||
return rc;
|
||||
|
||||
tbl_db[i] = NULL;
|
||||
|
||||
if (shadow_init) {
|
||||
memset(&fshadow, 0, sizeof(fshadow));
|
||||
fshadow.shadow_db = shadow_tbl_db[i];
|
||||
tf_shadow_tbl_free_db(&fshadow);
|
||||
shadow_tbl_db[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
init = 0;
|
||||
shadow_init = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -153,6 +230,7 @@ tf_tbl_free(struct tf *tfp __rte_unused,
|
||||
int rc;
|
||||
struct tf_rm_is_allocated_parms aparms = { 0 };
|
||||
struct tf_rm_free_parms fparms = { 0 };
|
||||
struct tf_shadow_tbl_remove_parms shparms;
|
||||
int allocated = 0;
|
||||
|
||||
TF_CHECK_PARMS2(tfp, parms);
|
||||
@ -182,6 +260,36 @@ tf_tbl_free(struct tf *tfp __rte_unused,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* The Shadow mgmt, if enabled, determines if the entry needs
|
||||
* to be deleted.
|
||||
*/
|
||||
if (shadow_init) {
|
||||
memset(&shparms, 0, sizeof(shparms));
|
||||
shparms.shadow_db = shadow_tbl_db[parms->dir];
|
||||
shparms.fparms = parms;
|
||||
rc = tf_shadow_tbl_remove(&shparms);
|
||||
if (rc) {
|
||||
/*
|
||||
* Should not get here, log it and let the entry be
|
||||
* deleted.
|
||||
*/
|
||||
TFP_DRV_LOG(ERR, "%s: Shadow free fail, "
|
||||
"type:%d index:%d deleting the entry.\n",
|
||||
tf_dir_2_str(parms->dir),
|
||||
parms->type,
|
||||
parms->idx);
|
||||
} else {
|
||||
/*
|
||||
* If the entry still has references, just return the
|
||||
* ref count to the caller. No need to remove entry
|
||||
* from rm.
|
||||
*/
|
||||
if (parms->ref_cnt >= 1)
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free requested element */
|
||||
fparms.rm_db = tbl_db[parms->dir];
|
||||
fparms.db_index = parms->type;
|
||||
@ -200,10 +308,124 @@ tf_tbl_free(struct tf *tfp __rte_unused,
|
||||
}
|
||||
|
||||
int
|
||||
tf_tbl_alloc_search(struct tf *tfp __rte_unused,
|
||||
struct tf_tbl_alloc_search_parms *parms __rte_unused)
|
||||
tf_tbl_alloc_search(struct tf *tfp,
|
||||
struct tf_tbl_alloc_search_parms *parms)
|
||||
{
|
||||
return 0;
|
||||
int rc, frc;
|
||||
uint32_t idx;
|
||||
struct tf_session *tfs;
|
||||
struct tf_dev_info *dev;
|
||||
struct tf_tbl_alloc_parms aparms;
|
||||
struct tf_shadow_tbl_search_parms sparms;
|
||||
struct tf_shadow_tbl_bind_index_parms bparms;
|
||||
struct tf_tbl_free_parms fparms;
|
||||
|
||||
TF_CHECK_PARMS2(tfp, parms);
|
||||
|
||||
if (!shadow_init || !shadow_tbl_db[parms->dir]) {
|
||||
TFP_DRV_LOG(ERR, "%s: Shadow TBL not initialized.\n",
|
||||
tf_dir_2_str(parms->dir));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(&sparms, 0, sizeof(sparms));
|
||||
sparms.sparms = parms;
|
||||
sparms.shadow_db = shadow_tbl_db[parms->dir];
|
||||
rc = tf_shadow_tbl_search(&sparms);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/*
|
||||
* The app didn't request us to alloc the entry, so return now.
|
||||
* The hit should have been updated in the original search parm.
|
||||
*/
|
||||
if (!parms->alloc || parms->search_status != MISS)
|
||||
return rc;
|
||||
|
||||
/* Retrieve the session information */
|
||||
rc = tf_session_get_session(tfp, &tfs);
|
||||
if (rc) {
|
||||
TFP_DRV_LOG(ERR,
|
||||
"%s: Failed to lookup session, rc:%s\n",
|
||||
tf_dir_2_str(parms->dir),
|
||||
strerror(-rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Retrieve the device information */
|
||||
rc = tf_session_get_device(tfs, &dev);
|
||||
if (rc) {
|
||||
TFP_DRV_LOG(ERR,
|
||||
"%s: Failed to lookup device, rc:%s\n",
|
||||
tf_dir_2_str(parms->dir),
|
||||
strerror(-rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Allocate the index */
|
||||
if (dev->ops->tf_dev_alloc_tbl == NULL) {
|
||||
rc = -EOPNOTSUPP;
|
||||
TFP_DRV_LOG(ERR,
|
||||
"%s: Operation not supported, rc:%s\n",
|
||||
tf_dir_2_str(parms->dir),
|
||||
strerror(-rc));
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
memset(&aparms, 0, sizeof(aparms));
|
||||
aparms.dir = parms->dir;
|
||||
aparms.type = parms->type;
|
||||
aparms.tbl_scope_id = parms->tbl_scope_id;
|
||||
aparms.idx = &idx;
|
||||
rc = dev->ops->tf_dev_alloc_tbl(tfp, &aparms);
|
||||
if (rc) {
|
||||
TFP_DRV_LOG(ERR,
|
||||
"%s: Table allocation failed, rc:%s\n",
|
||||
tf_dir_2_str(parms->dir),
|
||||
strerror(-rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Bind the allocated index to the data */
|
||||
memset(&bparms, 0, sizeof(bparms));
|
||||
bparms.shadow_db = shadow_tbl_db[parms->dir];
|
||||
bparms.dir = parms->dir;
|
||||
bparms.type = parms->type;
|
||||
bparms.idx = idx;
|
||||
bparms.data = parms->result;
|
||||
bparms.data_sz_in_bytes = parms->result_sz_in_bytes;
|
||||
bparms.hb_handle = sparms.hb_handle;
|
||||
rc = tf_shadow_tbl_bind_index(&bparms);
|
||||
if (rc) {
|
||||
/* Error binding entry, need to free the allocated idx */
|
||||
if (dev->ops->tf_dev_free_tbl == NULL) {
|
||||
rc = -EOPNOTSUPP;
|
||||
TFP_DRV_LOG(ERR,
|
||||
"%s: Operation not supported, rc:%s\n",
|
||||
tf_dir_2_str(parms->dir),
|
||||
strerror(-rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
memset(&fparms, 0, sizeof(fparms));
|
||||
fparms.dir = parms->dir;
|
||||
fparms.type = parms->type;
|
||||
fparms.idx = idx;
|
||||
frc = dev->ops->tf_dev_free_tbl(tfp, &fparms);
|
||||
if (frc) {
|
||||
TFP_DRV_LOG(ERR,
|
||||
"%s: Failed free index allocated during "
|
||||
"search. rc=%s\n",
|
||||
tf_dir_2_str(parms->dir),
|
||||
strerror(-frc));
|
||||
/* return the original failure. */
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
parms->idx = idx;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -144,29 +144,31 @@ struct tf_tbl_alloc_search_parms {
|
||||
*/
|
||||
uint32_t tbl_scope_id;
|
||||
/**
|
||||
* [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)
|
||||
* [in] Result data to search for
|
||||
*/
|
||||
uint8_t *result;
|
||||
/**
|
||||
* [in] Result data size in bytes (if search_enable)
|
||||
* [in] Result data size in bytes
|
||||
*/
|
||||
uint16_t result_sz_in_bytes;
|
||||
/**
|
||||
* [in] Whether or not to allocate on MISS, 1 is allocate.
|
||||
*/
|
||||
uint8_t alloc;
|
||||
/**
|
||||
* [out] If search_enable, set if matching entry found
|
||||
*/
|
||||
uint8_t hit;
|
||||
/**
|
||||
* [out] Current ref count after allocation (if search_enable)
|
||||
* [out] The status of the search (REJECT, MISS, HIT)
|
||||
*/
|
||||
enum tf_search_status search_status;
|
||||
/**
|
||||
* [out] Current ref count after allocation
|
||||
*/
|
||||
uint16_t ref_cnt;
|
||||
/**
|
||||
* [out] Idx of allocated entry or found entry (if search_enable)
|
||||
* [out] Idx of allocated entry or found entry
|
||||
*/
|
||||
uint32_t idx;
|
||||
};
|
||||
|
@ -134,7 +134,7 @@ struct tf_tcam_alloc_search_parms {
|
||||
/**
|
||||
* [out] Search result status (hit, miss, reject)
|
||||
*/
|
||||
enum tf_tcam_search_status search_status;
|
||||
enum tf_search_status search_status;
|
||||
/**
|
||||
* [out] Current refcnt after allocation
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user