/* SPDX-License-Identifier: BSD-3-Clause * Copyright(c) 2014-2021 Broadcom * All rights reserved. */ #include #include #include "tf_core.h" #include "tfp.h" #include "ulp_mapper.h" #include "ulp_flow_db.h" /* Retrieve the generic table initialization parameters for the tbl_idx */ static struct bnxt_ulp_generic_tbl_params* ulp_mapper_gen_tbl_params_get(uint32_t tbl_idx) { if (tbl_idx >= BNXT_ULP_GEN_TBL_MAX_SZ) return NULL; return &ulp_generic_tbl_params[tbl_idx]; } /* * Initialize the generic table list * * mapper_data [in] Pointer to the mapper data and the generic table is * part of it * * returns 0 on success */ int32_t ulp_mapper_generic_tbl_list_init(struct bnxt_ulp_mapper_data *mapper_data) { struct bnxt_ulp_generic_tbl_params *tbl; struct ulp_mapper_gen_tbl_list *entry; struct ulp_hash_create_params cparams; uint32_t idx, size; /* Allocate the generic tables. */ for (idx = 0; idx < BNXT_ULP_GEN_TBL_MAX_SZ; idx++) { tbl = ulp_mapper_gen_tbl_params_get(idx); if (!tbl) { BNXT_TF_DBG(ERR, "Failed to get gen table parms %d\n", idx); return -EINVAL; } entry = &mapper_data->gen_tbl_list[idx]; if (tbl->result_num_entries != 0) { /* assign the name */ entry->gen_tbl_name = tbl->name; /* add 4 bytes for reference count */ entry->mem_data_size = (tbl->result_num_entries + 1) * (tbl->result_num_bytes + sizeof(uint32_t)); /* allocate the big chunk of memory */ entry->mem_data = rte_zmalloc("ulp mapper gen tbl", entry->mem_data_size, 0); if (!entry->mem_data) { BNXT_TF_DBG(ERR, "%s:Failed to alloc gen table %d\n", tbl->name, idx); return -ENOMEM; } /* Populate the generic table container */ entry->container.num_elem = tbl->result_num_entries; entry->container.byte_data_size = tbl->result_num_bytes; entry->container.ref_count = (uint32_t *)entry->mem_data; size = sizeof(uint32_t) * (tbl->result_num_entries + 1); entry->container.byte_data = &entry->mem_data[size]; entry->container.byte_order = tbl->result_byte_order; } else { BNXT_TF_DBG(DEBUG, "%s: Unused Gen tbl entry is %d\n", tbl->name, idx); /* return -EINVAL; */ } if (tbl->hash_tbl_entries) { cparams.key_size = tbl->key_num_bytes; cparams.num_buckets = tbl->num_buckets; cparams.num_hash_tbl_entries = tbl->hash_tbl_entries; cparams.num_key_entries = tbl->result_num_entries; if (ulp_gen_hash_tbl_list_init(&cparams, &entry->hash_tbl)) { BNXT_TF_DBG(ERR, "%s: Failed to alloc hash tbl %d\n", tbl->name, idx); return -ENOMEM; } } } /* success */ return 0; } /* * Free the generic table list * * mapper_data [in] Pointer to the mapper data and the generic table is * part of it * * returns 0 on success */ int32_t ulp_mapper_generic_tbl_list_deinit(struct bnxt_ulp_mapper_data *mapper_data) { struct ulp_mapper_gen_tbl_list *tbl_list; uint32_t idx; /* iterate the generic table. */ for (idx = 0; idx < BNXT_ULP_GEN_TBL_MAX_SZ; idx++) { tbl_list = &mapper_data->gen_tbl_list[idx]; if (tbl_list->mem_data) { rte_free(tbl_list->mem_data); tbl_list->mem_data = NULL; } if (tbl_list->hash_tbl) { ulp_gen_hash_tbl_list_deinit(tbl_list->hash_tbl); tbl_list->hash_tbl = NULL; } } /* success */ return 0; } /* * Get the generic table list entry * * tbl_list [in] - Ptr to generic table * key [in] - Key index to the table * entry [out] - output will include the entry if found * * returns 0 on success. */ int32_t ulp_mapper_gen_tbl_entry_get(struct ulp_mapper_gen_tbl_list *tbl_list, uint32_t key, struct ulp_mapper_gen_tbl_entry *entry) { /* populate the output and return the values */ if (key > tbl_list->container.num_elem) { BNXT_TF_DBG(ERR, "%s: invalid key %x:%x\n", tbl_list->gen_tbl_name, key, tbl_list->container.num_elem); return -EINVAL; } entry->ref_count = &tbl_list->container.ref_count[key]; entry->byte_data_size = tbl_list->container.byte_data_size; entry->byte_data = &tbl_list->container.byte_data[key * entry->byte_data_size]; entry->byte_order = tbl_list->container.byte_order; return 0; } /* * utility function to calculate the table idx * * res_sub_type [in] - Resource sub type * dir [in] - Direction * * returns None */ int32_t ulp_mapper_gen_tbl_idx_calculate(uint32_t res_sub_type, uint32_t dir) { int32_t tbl_idx; /* Validate for direction */ if (dir >= TF_DIR_MAX) { BNXT_TF_DBG(ERR, "invalid argument %x\n", dir); return -EINVAL; } tbl_idx = (res_sub_type << 1) | (dir & 0x1); if (tbl_idx >= BNXT_ULP_GEN_TBL_MAX_SZ) { BNXT_TF_DBG(ERR, "invalid table index %x\n", tbl_idx); return -EINVAL; } return tbl_idx; } /* * Set the data in the generic table entry, Data is in Big endian format * * entry [in] - generic table entry * len [in] - The length of the data in bits to be set * data [in] - pointer to the data to be used for setting the value. * data_size [in] - length of the data pointer in bytes. * * returns 0 on success */ int32_t ulp_mapper_gen_tbl_entry_data_set(struct ulp_mapper_gen_tbl_entry *entry, uint32_t len, uint8_t *data, uint32_t data_size) { /* validate the null arguments */ if (!entry || !data) { BNXT_TF_DBG(ERR, "invalid argument\n"); return -EINVAL; } /* check the size of the buffer for validation */ if (len > ULP_BYTE_2_BITS(entry->byte_data_size) || data_size < ULP_BITS_2_BYTE(len)) { BNXT_TF_DBG(ERR, "invalid offset or length %x:%x\n", len, entry->byte_data_size); return -EINVAL; } memcpy(entry->byte_data, data, ULP_BITS_2_BYTE(len)); return 0; } /* * Get the data in the generic table entry, Data is in Big endian format * * entry [in] - generic table entry * offset [in] - The offset in bits where the data has to get * len [in] - The length of the data in bits to be get * data [out] - pointer to the data to be used for setting the value. * data_size [in] - The size of data in bytes * * returns 0 on success */ int32_t ulp_mapper_gen_tbl_entry_data_get(struct ulp_mapper_gen_tbl_entry *entry, uint32_t offset, uint32_t len, uint8_t *data, uint32_t data_size) { /* validate the null arguments */ if (!entry || !data) { BNXT_TF_DBG(ERR, "invalid argument\n"); return -EINVAL; } /* check the size of the buffer for validation */ if ((offset + len) > ULP_BYTE_2_BITS(entry->byte_data_size) || len > ULP_BYTE_2_BITS(data_size)) { BNXT_TF_DBG(ERR, "invalid offset or length %x:%x:%x\n", offset, len, entry->byte_data_size); return -EINVAL; } if (entry->byte_order == BNXT_ULP_BYTE_ORDER_LE) ulp_bs_pull_lsb(entry->byte_data, data, data_size, offset, len); else ulp_bs_pull_msb(entry->byte_data, data, offset, len); return 0; } /* Free the generic table list entry * * ulp_ctx [in] - Pointer to the ulp context * tbl_idx [in] - Index of the generic table * ckey [in] - Key for the entry in the table * * returns 0 on success */ int32_t ulp_mapper_gen_tbl_entry_free(struct bnxt_ulp_context *ulp_ctx, uint32_t tbl_idx, uint32_t ckey) { struct ulp_flow_db_res_params res; res.direction = tbl_idx & 0x1; res.resource_sub_type = tbl_idx >> 1; res.resource_hndl = ckey; return ulp_mapper_gen_tbl_res_free(ulp_ctx, &res); } /* Free the generic table list resource * * ulp_ctx [in] - Pointer to the ulp context * res [in] - Pointer to flow db resource entry * * returns 0 on success */ int32_t ulp_mapper_gen_tbl_res_free(struct bnxt_ulp_context *ulp_ctx, struct ulp_flow_db_res_params *res) { struct bnxt_ulp_mapper_data *mapper_data; struct ulp_mapper_gen_tbl_list *gen_tbl_list; struct ulp_mapper_gen_tbl_entry entry; struct ulp_gen_hash_entry_params hash_entry; int32_t tbl_idx; uint32_t fid = 0; uint32_t key_idx; /* Extract the resource sub type and direction */ tbl_idx = ulp_mapper_gen_tbl_idx_calculate(res->resource_sub_type, res->direction); if (tbl_idx < 0) { BNXT_TF_DBG(ERR, "invalid argument %x:%x\n", res->resource_sub_type, res->direction); return -EINVAL; } mapper_data = bnxt_ulp_cntxt_ptr2_mapper_data_get(ulp_ctx); if (!mapper_data) { BNXT_TF_DBG(ERR, "invalid ulp context %x\n", tbl_idx); return -EINVAL; } /* get the generic table */ gen_tbl_list = &mapper_data->gen_tbl_list[tbl_idx]; /* Get the generic table entry*/ if (gen_tbl_list->hash_tbl) { /* use the hash index to get the value */ hash_entry.hash_index = (uint32_t)res->resource_hndl; if (ulp_gen_hash_tbl_list_index_search(gen_tbl_list->hash_tbl, &hash_entry)) { BNXT_TF_DBG(ERR, "Unable to find has entry %x:%x\n", tbl_idx, hash_entry.hash_index); return -EINVAL; } key_idx = hash_entry.key_idx; } else { key_idx = (uint32_t)res->resource_hndl; } if (ulp_mapper_gen_tbl_entry_get(gen_tbl_list, key_idx, &entry)) { BNXT_TF_DBG(ERR, "Gen tbl entry get failed %x:%" PRIX64 "\n", tbl_idx, res->resource_hndl); return -EINVAL; } /* Decrement the reference count */ if (!ULP_GEN_TBL_REF_CNT(&entry)) { BNXT_TF_DBG(ERR, "generic table corrupt %x:%" PRIX64 "\n", tbl_idx, res->resource_hndl); return -EINVAL; } ULP_GEN_TBL_REF_CNT_DEC(&entry); /* retain the details since there are other users */ if (ULP_GEN_TBL_REF_CNT(&entry)) return 0; /* Delete the generic table entry. First extract the fid */ if (ulp_mapper_gen_tbl_entry_data_get(&entry, ULP_GEN_TBL_FID_OFFSET, ULP_GEN_TBL_FID_SIZE_BITS, (uint8_t *)&fid, sizeof(fid))) { BNXT_TF_DBG(ERR, "Unable to get fid %x:%" PRIX64 "\n", tbl_idx, res->resource_hndl); return -EINVAL; } fid = tfp_be_to_cpu_32(fid); /* no need to del if fid is 0 since there is no associated resource */ if (fid) { /* Destroy the flow associated with the shared flow id */ if (ulp_mapper_flow_destroy(ulp_ctx, BNXT_ULP_FDB_TYPE_RID, fid)) BNXT_TF_DBG(ERR, "Error in deleting shared flow id %x\n", fid); } /* Delete the entry from the hash table */ if (gen_tbl_list->hash_tbl) ulp_gen_hash_tbl_list_del(gen_tbl_list->hash_tbl, &hash_entry); /* clear the byte data of the generic table entry */ memset(entry.byte_data, 0, entry.byte_data_size); return 0; } /* * Write the generic table list hash entry * * tbl_list [in] - pointer to the generic table list * hash_entry [in] - Hash table entry * gen_tbl_ent [out] - generic table entry * * returns 0 on success. */ int32_t ulp_mapper_gen_tbl_hash_entry_add(struct ulp_mapper_gen_tbl_list *tbl_list, struct ulp_gen_hash_entry_params *hash_entry, struct ulp_mapper_gen_tbl_entry *gen_tbl_ent) { uint32_t key; int32_t rc = 0; switch (hash_entry->search_flag) { case ULP_GEN_HASH_SEARCH_FOUND: BNXT_TF_DBG(ERR, "%s: gen hash entry already present\n", tbl_list->gen_tbl_name); return -EINVAL; case ULP_GEN_HASH_SEARCH_FULL: BNXT_TF_DBG(ERR, "%s: gen hash table is full\n", tbl_list->gen_tbl_name); return -EINVAL; case ULP_GEN_HASH_SEARCH_MISSED: rc = ulp_gen_hash_tbl_list_add(tbl_list->hash_tbl, hash_entry); if (rc) { BNXT_TF_DBG(ERR, "%s: gen hash table add failed\n", tbl_list->gen_tbl_name); return -EINVAL; } key = hash_entry->key_idx; gen_tbl_ent->ref_count = &tbl_list->container.ref_count[key]; gen_tbl_ent->byte_data_size = tbl_list->container.byte_data_size; gen_tbl_ent->byte_data = &tbl_list->container.byte_data[key * gen_tbl_ent->byte_data_size]; gen_tbl_ent->byte_order = tbl_list->container.byte_order; break; default: BNXT_TF_DBG(ERR, "%s: invalid search flag\n", tbl_list->gen_tbl_name); return -EINVAL; } return rc; }