#include "context.h"
#include "command.h"
#include "cdu_def.h"
#include "bd_chain.h"
void * lm_get_context(struct _lm_device_t *pdev, u32_t cid){
void * ret = NULL;
u32_t page,off;
DbgBreakIf(cid > pdev->params.max_func_connections);
DbgBreakIf(pdev->context_info->array[cid].invalid != LM_CONTEXT_VALID);
page = cid / (pdev->params.num_context_in_page);
off = cid % (pdev->params.num_context_in_page);
ret = (void*)((char*)pdev->vars.context_cdu_virt_addr_table[page] + (pdev->params.context_line_size * off));
return ret;
}
u64_t lm_get_context_phys(struct _lm_device_t *pdev, u32_t cid){
u64_t ret = 0;
u32_t page,off;
DbgBreakIf(cid > pdev->params.max_func_connections);
DbgBreakIf(pdev->context_info->array[cid].invalid != LM_CONTEXT_VALID);
page = cid / (pdev->params.num_context_in_page);
off = cid % (pdev->params.num_context_in_page);
ret = (pdev->vars.context_cdu_phys_addr_table[page].as_u64 + (pdev->params.context_line_size * off));
return ret;
}
extern u32_t LOG2(u32_t v);
static lm_status_t lm_setup_searcher_hash_info(struct _lm_device_t *pdev)
{
u32_t num_con = 0 ;
u32_t alloc_size = 0 ;
lm_context_info_t* context = NULL;
lm_searcher_hash_info_t* hash_info = NULL;
int offset = 0 ;
if ( CHK_NULL(pdev) || CHK_NULL( pdev->context_info ) )
{
DbgBreakMsg("Invalid Parameters") ;
return LM_STATUS_INVALID_PARAMETER ;
}
context = pdev->context_info;
hash_info = &context->searcher_hash;
DbgBreakIf(!pdev->params.max_func_connections);
if CHK_NULL( hash_info->searcher_table)
{
DbgBreakIf(!( hash_info->searcher_table));
return LM_STATUS_FAILURE;
}
num_con = pdev->params.max_func_connections;
alloc_size = sizeof(lm_searcher_hash_entry_t) * num_con;
mm_mem_zero(hash_info->searcher_table, alloc_size);
*(u32_t *)(&hash_info->searcher_key[0]) = 0x63285672;
*(u32_t *)(&hash_info->searcher_key[4]) = 0x24B8F2CC;
*(u32_t *)(&hash_info->searcher_key[8]) = 0x223AEF9B;
*(u32_t *)(&hash_info->searcher_key[12]) = 0x26001E3A;
*(u32_t *)(&hash_info->searcher_key[16]) = 0x7AE91116;
*(u32_t *)(&hash_info->searcher_key[20]) = 0x5CE5230B;
*(u32_t *)(&hash_info->searcher_key[24]) = 0x298D8ADF;
*(u32_t *)(&hash_info->searcher_key[28]) = 0x6EB0FF09;
*(u32_t *)(&hash_info->searcher_key[32]) = 0x1830F82F;
*(u32_t *)(&hash_info->searcher_key[36]) = 0x1E46BE7;
for (offset = 0; offset < 10; offset++)
{
int j,k;
u32_t bitsOffset = 32*offset;
u8_t _byte;
for (j= 0; j < 4; j++)
{
_byte = (u8_t)((*(u32_t *)(&hash_info->searcher_key[offset*4]) >> (j*8)) & 0xff);
for (k = 0; k < 8; k++)
{
hash_info->searcher_key_bits[bitsOffset+(j*8)+k] = ((_byte<<(k%8))& 0x80) ? 1 : 0;
}
}
}
hash_info->num_hash_bits = (u8_t)LOG2(num_con);
return LM_STATUS_SUCCESS ;
}
static lm_status_t lm_alloc_searcher_hash_info(struct _lm_device_t *pdev)
{
u32_t num_con = 0 ;
u32_t alloc_size = 0 ;
lm_searcher_hash_info_t* hash_info = NULL ;
u8_t mm_cli_idx = 0 ;
if CHK_NULL(pdev)
{
return LM_STATUS_INVALID_PARAMETER ;
}
mm_cli_idx = LM_RESOURCE_COMMON;
num_con = pdev->params.max_func_connections;
alloc_size = sizeof(lm_searcher_hash_entry_t) * num_con;
hash_info = &pdev->context_info->searcher_hash;
if CHK_NULL(hash_info)
{
return LM_STATUS_INVALID_PARAMETER ;
}
hash_info->searcher_table = mm_alloc_mem(pdev, alloc_size, mm_cli_idx);
if CHK_NULL( hash_info->searcher_table )
{
DbgBreakIf(DBG_BREAK_ON(MEMORY_ALLOCATION_FAILURE));
return LM_STATUS_RESOURCE ;
}
return LM_STATUS_SUCCESS ;
}
lm_status_t lm_init_cid_resc(struct _lm_device_t *pdev, u32_t cid)
{
lm_cid_resc_t *cid_resc = NULL;
int i = 0;
if CHK_NULL(pdev)
{
return LM_STATUS_INVALID_PARAMETER;
}
cid_resc = &pdev->context_info->array[cid].cid_resc;
if CHK_NULL(cid_resc)
{
return LM_STATUS_INVALID_PARAMETER;
}
for (i = 0; i < ARRSIZE(cid_resc->cookies); i++)
{
cid_resc->cookies[i] = NULL;
}
cid_resc->cid_pending = LM_CID_STATE_VALID;
lm_sp_req_manager_init(pdev, cid);
return LM_STATUS_SUCCESS;
}
lm_status_t lm_setup_context_pool(struct _lm_device_t *pdev)
{
u32_t num_con = 0;
lm_context_info_t * context = NULL ;
u32_t i,j;
struct lm_context_cookie* array = NULL ;
lm_searcher_hash_entry_t* searcher_table = NULL ;
if CHK_NULL(pdev)
{
DbgBreakIf(!pdev);
return LM_STATUS_INVALID_PARAMETER;
}
context = pdev->context_info;
if CHK_NULL(context)
{
DbgBreakIf( context == NULL );
return LM_STATUS_INVALID_PARAMETER;
}
num_con = pdev->params.max_func_connections;
array = context->array ;
searcher_table = context->searcher_hash.searcher_table ;
mm_mem_zero( context, sizeof(lm_context_info_t) ) ;
context->array = array ;
context->searcher_hash.searcher_table = searcher_table ;
context->proto_start[ETH_CONNECTION_TYPE] = 0;
context->proto_end [ETH_CONNECTION_TYPE] = pdev->params.max_eth_including_vfs_conns - 1;
context->proto_start[TOE_CONNECTION_TYPE] = context->proto_end [ETH_CONNECTION_TYPE] + 1;
context->proto_end [TOE_CONNECTION_TYPE] = context->proto_start[TOE_CONNECTION_TYPE] + pdev->params.max_func_toe_cons - 1;
context->proto_start[RDMA_CONNECTION_TYPE] = context->proto_end [TOE_CONNECTION_TYPE] + 1;
context->proto_end [RDMA_CONNECTION_TYPE] = context->proto_start[RDMA_CONNECTION_TYPE] + pdev->params.max_func_rdma_cons - 1;
context->proto_start[ISCSI_CONNECTION_TYPE] = context->proto_end [RDMA_CONNECTION_TYPE] + 1;
context->proto_end [ISCSI_CONNECTION_TYPE] = context->proto_start[ISCSI_CONNECTION_TYPE] + pdev->params.max_func_iscsi_cons - 1;
context->proto_start[FCOE_CONNECTION_TYPE] = context->proto_end [ISCSI_CONNECTION_TYPE] + 1;
context->proto_end [FCOE_CONNECTION_TYPE] = context->proto_start[FCOE_CONNECTION_TYPE] + pdev->params.max_func_fcoe_cons - 1;
DbgBreakIf(context->proto_end[MAX_PROTO - 1] > pdev->params.max_func_connections -1);
if CHK_NULL(context->array)
{
DbgBreakIf(!( context->array));
return LM_STATUS_INVALID_PARAMETER;
}
mm_mem_zero(context->array, sizeof(struct lm_context_cookie)*num_con);
ASSERT_STATIC( ARRSIZE(context->proto_start) == ARRSIZE(context->proto_end) );
for (i = 0; i < ARRSIZE(context->proto_start); i++ )
{
for (j = context->proto_start[i]; j <= context->proto_end[i]; j++)
{
context->array[j].next = j+1;
context->array[j].invalid = LM_CONTEXT_VALID;
context->array[j].ip_type = 0;
context->array[j].h_val = 0;
lm_init_cid_resc(pdev, j);
}
if (context->proto_start[i] <= context->proto_end[i]) {
context->proto_ffree[i] = context->proto_start[i];
}
else
{
context->proto_ffree[i] = 0;
}
context->proto_pending[i] = 0;
context->array[context->proto_end[i]].next = 0;
}
for (j = context->proto_start[ETH_CONNECTION_TYPE]; j <= context->proto_end[ETH_CONNECTION_TYPE]; j++)
{
#ifdef VF_INVOLVED
if (IS_CHANNEL_VFDEV(pdev)) {
context->array[j].cid_resc.mapped_cid_bar_addr =
(volatile void *)((u8_t*)pdev->vars.mapped_bar_addr[BAR_0] + j*lm_vf_get_doorbell_size(pdev) + VF_BAR0_DB_OFFSET);
#ifdef __SunOS
context->array[j].cid_resc.reg_handle = pdev->vars.reg_handle[BAR_0];
#endif
} else
#endif
{
context->array[j].cid_resc.mapped_cid_bar_addr =
(volatile void *)((u8_t*)pdev->vars.mapped_bar_addr[BAR_1] + j*LM_DQ_CID_SIZE);
#ifdef __SunOS
context->array[j].cid_resc.reg_handle = pdev->vars.reg_handle[BAR_1];
#endif
}
}
return lm_setup_searcher_hash_info(pdev) ;
}
lm_status_t lm_alloc_context_pool(struct _lm_device_t *pdev){
u32_t num_con = 0 ;
lm_context_info_t * context = NULL ;
u8_t mm_cli_idx = 0;
if CHK_NULL(pdev)
{
DbgBreakIf(!pdev);
return LM_STATUS_INVALID_PARAMETER ;
}
if ERR_IF( NULL != pdev->context_info )
{
DbgBreakIf( pdev->context_info != NULL ) ;
return LM_STATUS_FAILURE ;
}
mm_cli_idx = LM_RESOURCE_COMMON;
num_con = pdev->params.max_func_connections ;
context = mm_alloc_mem(pdev, sizeof(lm_context_info_t), mm_cli_idx);
if CHK_NULL(context)
{
DbgBreakIf(DBG_BREAK_ON(MEMORY_ALLOCATION_FAILURE));
return LM_STATUS_RESOURCE ;
}
context->array = mm_alloc_mem(pdev, sizeof(struct lm_context_cookie)*num_con, mm_cli_idx);
if CHK_NULL(context->array)
{
DbgBreakIf(DBG_BREAK_ON(MEMORY_ALLOCATION_FAILURE));
return LM_STATUS_RESOURCE ;
}
pdev->context_info = context;
return lm_alloc_searcher_hash_info(pdev);
}
void lm_release_context_pool(struct _lm_device_t *pdev){
lm_context_info_t* context = NULL;
u32_t i, j;
DbgBreakIf( pdev->context_info == NULL );
context = pdev->context_info;
pdev->context_info = NULL;
for (i=0; i<(pdev->params.max_func_connections); i++ )
{
for (j = 0; j < MAX_PROTO; j++)
{
DbgBreakIf( context->array[i].cid_resc.cookies[j] != NULL );
}
}
DbgBreakIf(context->searcher_hash.num_tuples);
}
static u32_t _lm_searcher_mirror_hash_calc(lm_searcher_hash_info_t *hash_info, lm_4tuple_t *tuple)
{
u8_t in_str[MAX_SEARCHER_IN_STR] = {0};
u8_t* in_str_bits = hash_info->searcher_in_str_bits;
u8_t* key_bits = hash_info->searcher_key_bits;
u32_t in_bits = 0;
u32_t result = 0;
u16_t i = 0;
u16_t j = 0;
if (tuple->ip_type == LM_IP_TYPE_V4)
{
*(u32_t *)(&in_str[0]) = HTON32(tuple->src_ip[0]);
*(u32_t *)(&in_str[4]) = HTON32(tuple->dst_ip[0]);
*(u16_t *)(&in_str[8]) = tuple->src_port;
*(u16_t *)(&in_str[10]) = tuple->dst_port;
in_bits = 12 * 8;
}
else
{
*(u32_t *)(&in_str[0]) = HTON32(tuple->src_ip[0]);
*(u32_t *)(&in_str[4]) = HTON32(tuple->src_ip[1]);
*(u32_t *)(&in_str[8]) = HTON32(tuple->src_ip[2]);
*(u32_t *)(&in_str[12]) = HTON32(tuple->src_ip[3]);
*(u32_t *)(&in_str[16]) = HTON32(tuple->dst_ip[0]);
*(u32_t *)(&in_str[20]) = HTON32(tuple->dst_ip[1]);
*(u32_t *)(&in_str[24]) = HTON32(tuple->dst_ip[2]);
*(u32_t *)(&in_str[28]) = HTON32(tuple->dst_ip[3]);
*(u16_t *)(&in_str[32]) = tuple->src_port;
*(u16_t *)(&in_str[34]) = tuple->dst_port;
in_bits = 36 * 8;
}
for (i = 0; i < in_bits; i++)
{
in_str_bits[i] = ((in_str[i/8]<<(i%8)) & 0x80) ? 1 : 0;
}
for (i = 0; i < 32; i++)
{
u8_t h = 0;
for (j = 0; j < in_bits; j++)
{
h ^= key_bits[i+j] & in_str_bits[j];
}
result |= (h<<(32-i-1));
}
return result;
}
lm_status_t lm_searcher_mirror_hash_insert(struct _lm_device_t *pdev, u32_t cid, lm_4tuple_t *tuple)
{
lm_context_info_t *context = NULL;
lm_searcher_hash_entry_t *hash_entry = NULL;
u32_t h_val = 0;
u8_t temp_ipv6, temp_ipv4, temp_depth_ipv4, is_ipv4;
lm_status_t lm_status = LM_STATUS_SUCCESS;
#define SRC_HASH_DEPTH_TH 15
MM_ACQUIRE_CID_LOCK(pdev);
context = pdev->context_info;
is_ipv4 = (tuple->ip_type == LM_IP_TYPE_V4 ? 1 : 0);
h_val = _lm_searcher_mirror_hash_calc(&context->searcher_hash, tuple);
h_val &= ((1 << context->searcher_hash.num_hash_bits) - 1);
if (h_val == ((1 << context->searcher_hash.num_hash_bits) - 1)) {
h_val = 0;
}
hash_entry = &context->searcher_hash.searcher_table[h_val];
temp_ipv6 = hash_entry->num_ipv6 + (is_ipv4 ? 0 : 1);
temp_ipv4 = hash_entry->num_ipv4 + is_ipv4;
temp_depth_ipv4 = (temp_ipv4 / 2) + (temp_ipv4 % 2);
if (temp_depth_ipv4 < hash_entry->depth_ipv4) {
temp_depth_ipv4 = hash_entry->depth_ipv4;
}
if (temp_depth_ipv4 + temp_ipv6 > SRC_HASH_DEPTH_TH) {
DbgBreakMsg("Reached searcher hash limit\n");
lm_status = LM_STATUS_FAILURE;
} else {
hash_entry->num_ipv6 = temp_ipv6;
hash_entry->num_ipv4 = temp_ipv4;
hash_entry->depth_ipv4 = temp_depth_ipv4;
if (context->searcher_hash.hash_depth_reached < hash_entry->depth_ipv4 + hash_entry->num_ipv6) {
context->searcher_hash.hash_depth_reached = hash_entry->depth_ipv4 + hash_entry->num_ipv6;
}
context->searcher_hash.num_tuples++;
DbgBreakIf(context->array[cid].ip_type);
context->array[cid].ip_type = tuple->ip_type;
context->array[cid].h_val = h_val;
}
MM_RELEASE_CID_LOCK(pdev);
return lm_status;
}
void lm_searcher_mirror_hash_remove(struct _lm_device_t *pdev, u32_t cid)
{
lm_context_info_t *context = NULL;
lm_searcher_hash_entry_t *hash_entry = NULL;
u32_t h_val = 0;
MM_ACQUIRE_CID_LOCK(pdev);
context = pdev->context_info;
if(!context->array[cid].ip_type) {
DbgMessage(pdev, WARN,
"not removing CID %d from SRC hash (hash insert was not called for this cid)\n"
,cid);
MM_RELEASE_CID_LOCK(pdev);
return;
}
h_val = context->array[cid].h_val;
hash_entry = &context->searcher_hash.searcher_table[h_val];
if (context->array[cid].ip_type == LM_IP_TYPE_V6) {
DbgBreakIf(!hash_entry->num_ipv6);
hash_entry->num_ipv6--;
}
else
{
DbgBreakIf(!hash_entry->num_ipv4);
hash_entry->num_ipv4--;
if (hash_entry->num_ipv4 < hash_entry->depth_ipv4)
{
hash_entry->depth_ipv4 = hash_entry->num_ipv4;
}
}
context->searcher_hash.num_tuples--;
context->array[cid].ip_type = 0;
context->array[cid].h_val = 0;
MM_RELEASE_CID_LOCK(pdev);
}
lm_status_t lm_allocate_cid(struct _lm_device_t *pdev, u32_t type, void * cookie, s32_t * out_cid){
lm_context_info_t *context = NULL;
lm_status_t lm_status = LM_STATUS_SUCCESS;
u32_t cid = (u32_t)-1;
lm_address_t phy_addr = {{0}} ;
if ( CHK_NULL(out_cid) ||
CHK_NULL(pdev) ||
CHK_NULL(pdev->context_info) ||
CHK_NULL(pdev->context_info->array) ||
CHK_NULL(cookie) ||
ERR_IF(type >= ARRSIZE(pdev->context_info->proto_pending)) )
{
DbgBreakIf(!out_cid) ;
DbgBreakIf(!pdev);
DbgBreakIf(!pdev->context_info);
DbgBreakIf(!pdev->context_info->array);
DbgBreakIf(!cookie);
DbgBreakIf(type >= ARRSIZE(pdev->context_info->proto_pending)) ;
return LM_STATUS_INVALID_PARAMETER ;
}
context = pdev->context_info;
*out_cid = 0;
MM_ACQUIRE_CID_LOCK(pdev);
if (context->proto_ffree[type]==0) {
if ((pdev->params.cid_allocation_mode == LM_CID_ALLOC_REGULAR) || (context->proto_pending[type] == 0)) {
lm_status = LM_STATUS_RESOURCE;
}
else
{
cid = context->proto_pending[type];
context->proto_pending[type] = context->array[cid].next;
context->array[cid].next = 0;
context->array[cid].cid_resc.cookies[type] = cookie;
context->array[cid].cid_resc.cid_pending = LM_CID_STATE_PENDING;
lm_sp_req_manager_init(pdev, cid);
*out_cid = cid;
cid = context->proto_pending[type];
if (cid) {
context->array[cid].prev = 0;
}
lm_status = LM_STATUS_PENDING;
}
}else{
cid = context->proto_ffree[type];
context->proto_ffree[type] = context->array[cid].next;
context->array[cid].next = 0;
context->array[cid].prev = 0;
context->array[cid].cid_resc.cookies[type] = cookie;
lm_sp_req_manager_init(pdev, cid);
*out_cid = cid;
lm_status = LM_STATUS_SUCCESS;
}
MM_RELEASE_CID_LOCK(pdev);
if(LM_STATUS_SUCCESS == lm_status)
{
phy_addr.as_u32.low = (pdev->hw_info.mem_base[BAR_1].as_u32.low) & 0xfffffff0;
phy_addr.as_u32.high = pdev->hw_info.mem_base[BAR_1].as_u32.high;
LM_INC64(&phy_addr,(cid*LM_DQ_CID_SIZE));
#ifdef __SunOS
context->array[cid].cid_resc.mapped_cid_bar_addr =
#ifdef VF_INVOLVED
(volatile void *)((u8_t*)pdev->vars.mapped_bar_addr[BAR_1] + cid*LM_DQ_CID_SIZE);
context->array[cid].cid_resc.reg_handle = pdev->vars.reg_handle[BAR_1];
#else
(volatile void *)mm_map_io_space_solaris(pdev,
phy_addr,
BAR_1,
(cid * LM_DQ_CID_SIZE),
LM_DQ_CID_SIZE,
&context->array[cid].cid_resc.reg_handle);
#endif
#else
context->array[cid].cid_resc.mapped_cid_bar_addr =
#ifdef VF_INVOLVED
(volatile void *)((u8_t*)pdev->vars.mapped_bar_addr[BAR_1] + cid*LM_DQ_CID_SIZE);
#else
(volatile void *)mm_map_io_space(pdev, phy_addr, LM_DQ_CID_SIZE);
#endif
#endif
if CHK_NULL(context->array[cid].cid_resc.mapped_cid_bar_addr)
{
DbgMessage(pdev, FATAL, "lm_allocate_cid: mm_map_io_space failed. address low=%d address high=%d\n", phy_addr.as_u32.low,phy_addr.as_u32.high );
MM_ACQUIRE_CID_LOCK(pdev);
context->array[cid].next = pdev->context_info->proto_ffree[type];
context->proto_ffree[type] = cid;
context->array[cid].invalid = LM_CONTEXT_VALID;
MM_RELEASE_CID_LOCK(pdev);
lm_status = LM_STATUS_RESOURCE;
*out_cid =0;
}
}
return lm_status;
}
void lm_cfc_delete(struct _lm_device_t *pdev, void *param)
{
u32_t cid = (u32_t)(uintptr_t)param;
u8_t flr_in_progress = lm_fl_reset_is_inprogress(pdev);
if ( CHK_NULL(pdev) ||
ERR_IF(cid > pdev->params.max_func_connections) ||
ERR_IF(pdev->context_info->array[cid].invalid != LM_CONTEXT_INVALID_WAIT) )
{
DbgBreakIf(!pdev);
DbgBreakIf(cid > pdev->params.max_func_connections);
if (!flr_in_progress)
{
DbgBreakIf(pdev->context_info->array[cid].invalid != LM_CONTEXT_INVALID_WAIT);
}
else
{
DbgMessage(pdev, FATAL, "lm_cfc_delete: invalid %d for cid=%d\n", pdev->context_info->array[cid].invalid,cid);
if (pdev->context_info->array[cid].invalid != LM_CONTEXT_INVALID_DELETE)
{
DbgBreakIf(1);
}
}
}
DbgMessage(pdev, WARN, "lm_cfc_delete: cid=0x%x\n",cid);
pdev->context_info->array[cid].invalid = LM_CONTEXT_INVALID_DELETE;
if (lm_fl_reset_is_inprogress(pdev))
{
lm_recycle_cid(pdev, cid);
}
else
{
lm_command_post(pdev,
cid,
RAMROD_CMD_ID_COMMON_CFC_DEL,
CMD_PRIORITY_NORMAL,
NONE_CONNECTION_TYPE,
0 );
}
return;
}
void lm_free_cid(struct _lm_device_t *pdev, u32_t type, u32_t cid, u8_t notify_fw){
u32_t delay_time = 0;
u32_t curr_cid = 0;
u8_t recycle_now = 0;
u8_t proto_idx = 0;
if ( CHK_NULL(pdev) ||
CHK_NULL(pdev->context_info) ||
ERR_IF(type >= ARRSIZE(pdev->context_info->proto_end)) ||
ERR_IF(cid > (pdev->context_info->proto_end[type])) ||
ERR_IF(cid < (pdev->context_info->proto_start[type])) ||
(!lm_fl_reset_is_inprogress(pdev) && (pdev->context_info->array[cid].invalid != LM_CONTEXT_VALID)))
{
DbgBreakIf(!pdev);
DbgBreakIf(!pdev->context_info);
DbgBreakIf(type >= ARRSIZE(pdev->context_info->proto_end));
DbgBreakIf(cid > (pdev->context_info->proto_end[type]));
DbgBreakIf(cid < (pdev->context_info->proto_start[type]));
DbgBreakIf(pdev->context_info->array[cid].invalid != LM_CONTEXT_VALID);
return;
}
MM_ACQUIRE_CID_LOCK(pdev);
for (proto_idx = 0; proto_idx < MAX_PROTO; proto_idx++)
{
DbgBreakIf(pdev->context_info->array[cid].cid_resc.cookies[proto_idx]);
}
lm_sp_req_manager_shutdown(pdev, cid);
if (notify_fw)
{
#if !(defined(DOS) || defined(__LINUX))
delay_time = LM_FREE_CID_DELAY_TIME(pdev);
#else
delay_time = 0;
#endif
pdev->context_info->array[cid].invalid = LM_CONTEXT_INVALID_WAIT;
recycle_now = FALSE;
curr_cid = pdev->context_info->proto_pending[type];
pdev->context_info->array[cid].next = curr_cid;
pdev->context_info->array[cid].prev = 0;
if (curr_cid != 0)
{
pdev->context_info->array[curr_cid].prev = cid;
}
pdev->context_info->proto_pending[type] = cid;
}
else
{
pdev->context_info->array[cid].invalid = LM_CONTEXT_INVALID_DELETE;
recycle_now = TRUE;
}
MM_RELEASE_CID_LOCK(pdev);
if (recycle_now) {
lm_recycle_cid(pdev, cid);
}
else
{
if (type == TOE_CONNECTION_TYPE)
{
DbgMessage(pdev, WARN, "lm_free_cid: CFC delete: cid=0x%x\n",cid);
lm_cfc_delete(pdev,(void *)(uintptr_t)cid);
}
else
{
DbgMessage(pdev, WARN, "lm_free_cid: schedule CFC delete: cid=0x%x\n",cid);
mm_schedule_task(pdev,delay_time,lm_cfc_delete,
(void *)(uintptr_t)cid);
}
}
}
void lm_recycle_cid(struct _lm_device_t *pdev, u32_t cid){
u32_t type = MAX_PROTO+1;
u32_t prev_cid, next_cid;
u32_t i;
u8_t call_cb = TRUE;
if ( CHK_NULL(pdev) ||
ERR_IF(pdev->context_info->array[cid].invalid != LM_CONTEXT_INVALID_DELETE) ||
ERR_IF(cid > pdev->params.max_func_connections) )
{
DbgBreakIf(!pdev);
DbgBreakIf(pdev->context_info->array[cid].invalid != LM_CONTEXT_INVALID_DELETE);
DbgBreakIf(cid > pdev->params.max_func_connections);
return;
}
for (i=0; i < MAX_PROTO; i++ ) {
if ((cid >= pdev->context_info->proto_start[i]) && (cid <= pdev->context_info->proto_end[i]))
{
type = i;
break;
}
}
if ERR_IF(type >= ARRSIZE(pdev->context_info->proto_pending))
{
DbgBreakIf(type >= ARRSIZE(pdev->context_info->proto_pending)) ;
return;
}
MM_ACQUIRE_CID_LOCK(pdev);
#ifdef _VBD_
if ((type == TOE_CONNECTION_TYPE) && (pdev->ofld_info.l4_params.ticks_per_second != 0))
{
pdev->vars.last_recycling_timestamp = mm_get_current_time(pdev) * 1000 / pdev->ofld_info.l4_params.ticks_per_second;
}
#endif
if (pdev->context_info->array[cid].cid_resc.cid_pending == FALSE) {
prev_cid = pdev->context_info->array[cid].prev;
next_cid = pdev->context_info->array[cid].next;
if (prev_cid) {
pdev->context_info->array[prev_cid].next = next_cid;
}
if (next_cid) {
pdev->context_info->array[next_cid].prev = prev_cid;
}
if (pdev->context_info->proto_pending[type] == cid) {
DbgBreakIf(prev_cid != 0);
pdev->context_info->proto_pending[type] = next_cid;
}
pdev->context_info->array[cid].prev = pdev->context_info->array[cid].next = 0;
pdev->context_info->array[cid].next = pdev->context_info->proto_ffree[type];
pdev->context_info->array[cid].invalid = LM_CONTEXT_VALID;
pdev->context_info->array[cid].cfc_delete_cnt = 0;
pdev->context_info->proto_ffree[type] = cid;
call_cb = FALSE;
#ifndef VF_INVOLVED
mm_unmap_io_space(pdev,(void *)pdev->context_info->array[cid].cid_resc.mapped_cid_bar_addr, LM_DQ_CID_SIZE);
#endif
}
else
{
pdev->context_info->array[cid].invalid = LM_CONTEXT_VALID;
call_cb = TRUE;
}
lm_set_cdu_validation_data(pdev, cid, TRUE );
MM_RELEASE_CID_LOCK(pdev);
if (pdev->cid_recycled_callbacks[type] && call_cb) {
pdev->cid_recycled_callbacks[type](pdev, pdev->context_info->array[cid].cid_resc.cookies[type], cid);
}
return;
}
void * lm_cid_cookie(struct _lm_device_t *pdev, u32_t type, u32_t cid){
if ( CHK_NULL(pdev) ||
CHK_NULL(pdev->context_info) ||
ERR_IF(type >= MAX_PROTO) ||
ERR_IF(cid > (pdev->context_info->proto_end[MAX_PROTO - 1])) ||
CHK_NULL(pdev->context_info->array[cid].cid_resc.cookies[type]) ||
ERR_IF(pdev->context_info->array[cid].invalid != LM_CONTEXT_VALID) )
{
DbgBreakIf(!pdev);
DbgBreakIf(!pdev->context_info);
DbgBreakIf(type >= MAX_PROTO);
DbgBreakIf(cid > (pdev->context_info->proto_end[MAX_PROTO - 1]));
DbgBreakIf(pdev->context_info->array[cid].invalid != LM_CONTEXT_VALID);
}
if (pdev->context_info->array[cid].cid_resc.cookies[type] == NULL)
{
return NULL;
}
if (pdev->context_info->array[cid].cid_resc.cid_pending != LM_CID_STATE_VALID)
{
return NULL;
}
return pdev->context_info->array[cid].cid_resc.cookies[type];
}
lm_cid_resc_t * lm_cid_resc(struct _lm_device_t *pdev, u32_t cid){
if ( CHK_NULL(pdev) ||
CHK_NULL(pdev->context_info) ||
ERR_IF(cid > (pdev->context_info->proto_end[MAX_PROTO - 1])) )
{
DbgBreakIf(!pdev);
DbgBreakIf(!pdev->context_info);
DbgBreakIf(cid > (pdev->context_info->proto_end[MAX_PROTO - 1]));
}
return &pdev->context_info->array[cid].cid_resc;
}
u8_t lm_map_cid_to_proto(struct _lm_device_t * pdev, u32_t cid)
{
u8_t type = MAX_PROTO+1;
u8_t i;
if (!pdev || cid > pdev->params.max_func_connections) {
return type;
}
for (i=0; i < MAX_PROTO; i++ ) {
if ((cid >= pdev->context_info->proto_start[i]) && (cid <= pdev->context_info->proto_end[i])) {
type = i;
break;
}
}
return type;
}
void lm_init_connection_context(struct _lm_device_t *pdev, u32_t const sw_cid, u8_t sb_id)
{
struct eth_context * context = NULL;
if ( CHK_NULL(pdev) ||
ERR_IF(sw_cid < PFDEV(pdev)->context_info->proto_start[ETH_CONNECTION_TYPE]) ||
ERR_IF(sw_cid > PFDEV(pdev)->context_info->proto_end[ETH_CONNECTION_TYPE]) )
{
DbgBreakIf(!pdev);
DbgBreakIf(sw_cid < PFDEV(pdev)->context_info->proto_start[ETH_CONNECTION_TYPE]);
DbgBreakIf(sw_cid > PFDEV(pdev)->context_info->proto_end[ETH_CONNECTION_TYPE]);
}
context = lm_get_context(PFDEV(pdev), VF_TO_PF_CID(pdev,sw_cid));
mm_mem_zero( context, sizeof(struct eth_context) ) ;
lm_set_cdu_validation_data(pdev, VF_TO_PF_CID(pdev,sw_cid), FALSE );
}
lm_status_t
lm_set_cid_resc(
IN struct _lm_device_t *pdev,
IN u32_t type,
IN void *cookie,
IN u32_t cid)
{
lm_status_t lm_status = LM_STATUS_SUCCESS;
lm_cid_resc_t *cid_resc = NULL;
if CHK_NULL(pdev)
{
return LM_STATUS_INVALID_PARAMETER;
}
MM_ACQUIRE_CID_LOCK(pdev);
cid_resc = lm_cid_resc(pdev, cid);
if CHK_NULL(cid_resc)
{
MM_RELEASE_CID_LOCK(pdev);
return LM_STATUS_INVALID_PARAMETER;
}
cid_resc->cookies[type] = cookie;
MM_RELEASE_CID_LOCK(pdev);
return lm_status;
}
lm_status_t
lm_free_cid_resc(
IN struct _lm_device_t *pdev,
IN u32_t type,
IN u32_t cid,
IN u8_t notify_fw)
{
lm_cid_resc_t *cid_resc = NULL;
u8_t proto_idx = 0;
if (CHK_NULL(pdev) || (cid == 0))
{
return LM_STATUS_INVALID_PARAMETER;
}
MM_ACQUIRE_CID_LOCK(pdev);
cid_resc = lm_cid_resc(pdev, cid);
if CHK_NULL(cid_resc)
{
MM_RELEASE_CID_LOCK(pdev);
return LM_STATUS_INVALID_PARAMETER;
}
cid_resc->cookies[type] = NULL;
while ((proto_idx < MAX_PROTO) && (cid_resc->cookies[proto_idx] == NULL))
{
proto_idx++;
}
MM_RELEASE_CID_LOCK(pdev);
if (proto_idx == MAX_PROTO)
{
lm_free_cid(pdev, lm_map_cid_to_proto(pdev, cid), cid, notify_fw);
}
return LM_STATUS_SUCCESS;
}
lm_sp_req_manager_t *
lm_cid_sp_req_mgr(
IN struct _lm_device_t *pdev,
IN u32_t cid
)
{
lm_cid_resc_t *cid_resc = NULL;
if CHK_NULL(pdev)
{
return NULL;
}
cid_resc = lm_cid_resc(pdev, cid);
if CHK_NULL(cid_resc)
{
return NULL;
}
return &cid_resc->sp_req_mgr;
}
lm_cid_state_enum
lm_cid_state(
IN struct _lm_device_t *pdev,
IN u32_t cid
)
{
lm_cid_resc_t *cid_resc = NULL;
if CHK_NULL(pdev)
{
return LM_CID_STATE_ERROR;
}
cid_resc = lm_cid_resc(pdev, cid);
if CHK_NULL(cid_resc)
{
return LM_CID_STATE_ERROR;
}
return (lm_cid_state_enum)cid_resc->cid_pending;
}
lm_status_t
lm_set_cid_state(
IN struct _lm_device_t *pdev,
IN u32_t cid,
IN lm_cid_state_enum state
)
{
lm_cid_resc_t *cid_resc = NULL;
if CHK_NULL(pdev)
{
return LM_STATUS_INVALID_PARAMETER;
}
MM_ACQUIRE_CID_LOCK(pdev);
cid_resc = lm_cid_resc(pdev, cid);
if CHK_NULL(cid_resc)
{
MM_RELEASE_CID_LOCK(pdev);
return LM_STATUS_INVALID_PARAMETER;
}
cid_resc->cid_pending = state;
MM_RELEASE_CID_LOCK(pdev);
return LM_STATUS_SUCCESS;
}
lm_status_t lm_set_cdu_validation_data(struct _lm_device_t *pdev, s32_t cid, u8_t invalidate)
{
lm_status_t lm_status = LM_STATUS_SUCCESS;
void *context = NULL;
u8_t *cdu_reserved = NULL;
u8_t *cdu_usage = NULL;
u8_t proto_type = 0;
context = lm_get_context(PFDEV(pdev), cid);
if (!context) {
return LM_STATUS_FAILURE;
}
proto_type = lm_map_cid_to_proto(PFDEV(pdev), cid);
switch (proto_type) {
case TOE_CONNECTION_TYPE:
cdu_reserved = &((struct toe_context *)context)->xstorm_ag_context.cdu_reserved;
cdu_usage = &(((struct toe_context *)context)->ustorm_ag_context.cdu_usage);
break;
case ETH_CONNECTION_TYPE:
cdu_reserved = &(((struct eth_context *)context)->xstorm_ag_context.cdu_reserved);
cdu_usage = &(((struct eth_context *)context)->ustorm_ag_context.cdu_usage);
break;
case ISCSI_CONNECTION_TYPE:
cdu_reserved = &(((struct iscsi_context *)context)->xstorm_ag_context.cdu_reserved);
cdu_usage = &(((struct iscsi_context *)context)->ustorm_ag_context.cdu_usage);
break;
case FCOE_CONNECTION_TYPE:
cdu_reserved = &(((struct fcoe_context *)context)->xstorm_ag_context.cdu_reserved);
cdu_usage = &(((struct fcoe_context *)context)->ustorm_ag_context.cdu_usage);
break;
default:
lm_status = LM_STATUS_FAILURE;
break;
}
if (cdu_reserved && cdu_usage) {
if (invalidate) {
*cdu_reserved = CDU_RSRVD_INVALIDATE_CONTEXT_VALUE(*cdu_reserved);
*cdu_usage = CDU_RSRVD_INVALIDATE_CONTEXT_VALUE(*cdu_usage);
} else {
*cdu_reserved = CDU_RSRVD_VALUE_TYPE_A(HW_CID(pdev, cid), CDU_REGION_NUMBER_XCM_AG, proto_type);
*cdu_usage = CDU_RSRVD_VALUE_TYPE_A(HW_CID(pdev, cid), CDU_REGION_NUMBER_UCM_AG, proto_type);
}
}
return lm_status;
}
lm_status_t lm_get_context_size(struct _lm_device_t *pdev, s32_t * context_size)
{
*context_size = LM_CONTEXT_SIZE;
return LM_STATUS_SUCCESS;
}
lm_status_t lm_set_con_state(struct _lm_device_t *pdev, u32_t cid, u32_t state)
{
lm_cid_resc_t * cid_resc = lm_cid_resc(pdev, cid);
if CHK_NULL(cid_resc)
{
return LM_STATUS_INVALID_PARAMETER;
}
cid_resc->con_state = state;
return LM_STATUS_SUCCESS;
}
u32_t lm_get_con_state(struct _lm_device_t *pdev, u32_t cid)
{
const lm_cid_resc_t * cid_resc = lm_cid_resc(pdev, cid);
if CHK_NULL(cid_resc)
{
return LM_CON_STATE_CLOSE;
}
return cid_resc->con_state;
}