#include "lm5710.h"
#include "bd_chain.h"
#include "lm_l4fp.h"
#include "mm_l4if.h"
void lm_tcp_complete_bufs(
struct _lm_device_t *pdev,
lm_tcp_state_t *tcp,
lm_tcp_con_t *con)
{
s_list_t completed_bufs;
s_list_clear(&completed_bufs);
DbgBreakIf(con->dpc_info.dpc_completed_tail == NULL);
s_list_split(&con->active_tb_list, &completed_bufs,
con->dpc_info.dpc_completed_tail, con->dpc_info.dpc_bufs_completed);
con->dpc_info.dpc_completed_tail = NULL;
DbgBreakIf(con->rq_nbytes < con->dpc_info.dpc_actual_bytes_completed);
con->rq_nbytes -= con->dpc_info.dpc_actual_bytes_completed;
lm_bd_chain_bds_consumed(&con->bd_chain, con->dpc_info.dpc_bd_used);
con->dpc_info.dpc_bd_used = 0;
con->dpc_info.dpc_bufs_completed = 0;
con->buffer_completed_cnt += s_list_entry_cnt(&completed_bufs);
DbgMessage(pdev, VERBOSEl4fp,
"cid=%d, completing %d bufs towards mm, actual_completed_bytes=%d, %d bufs still in active tb list\n",
tcp->cid, s_list_entry_cnt(&completed_bufs), con->dpc_info.dpc_actual_bytes_completed, s_list_entry_cnt(&con->active_tb_list));
con->dpc_info.dpc_actual_bytes_completed = 0;
DbgBreakIf(s_list_is_empty(&completed_bufs));
if (!con->rq_completion_calls) {
lm_tcp_buffer_t *tcp_buf = (lm_tcp_buffer_t *)s_list_peek_head(&completed_bufs);
if (tcp_buf->flags & TCP_BUF_FLAG_L4_PARTIAL_FILLED) {
RESET_FLAGS(con->db_data.rx->flags, TOE_RX_DB_DATA_PARTIAL_FILLED_BUF);
}
}
con->rq_completion_calls++;
mm_tcp_complete_bufs(pdev, tcp, con, &completed_bufs, LM_STATUS_SUCCESS);
}
u32_t lm_tcp_complete_nbytes(
struct _lm_device_t *pdev,
lm_tcp_state_t *tcp,
lm_tcp_con_t *con,
u32_t completed_bytes,
u8_t push
)
{
lm_tcp_buffer_t * tcp_buf = lm_tcp_next_entry_dpc_active_list(con);
u32_t actual_completed_bytes = completed_bytes;
u8_t dbg_no_more_bufs = FALSE;
UNREFERENCED_PARAMETER_(tcp);
DbgMessage(pdev, VERBOSEl4fp, "#lm_tcp_complete_bufs\n");
con->dpc_info.dpc_rq_placed_bytes += completed_bytes;
DbgBreakIf((con->type == TCP_CON_TYPE_RX) && !tcp_buf);
while(tcp_buf && tcp_buf->more_to_comp <= completed_bytes) {
DbgBreakIf((tcp_buf->more_to_comp == tcp_buf->size) &&
!(tcp_buf->flags & TCP_BUF_FLAG_L4_POST_START ?
con->app_buf_bytes_acc_comp == 0 :
con->app_buf_bytes_acc_comp > 0));
completed_bytes -= tcp_buf->more_to_comp;
con->app_buf_bytes_acc_comp += tcp_buf->more_to_comp;
tcp_buf->more_to_comp = 0;
con->dpc_info.dpc_completed_tail = &tcp_buf->link;
con->dpc_info.dpc_bd_used += tcp_buf->bd_used;
con->dpc_info.dpc_bufs_completed += 1;
con->dpc_info.dpc_actual_bytes_completed += tcp_buf->size;
if(tcp_buf->flags & TCP_BUF_FLAG_L4_POST_END) {
tcp_buf->app_buf_xferred = con->app_buf_bytes_acc_comp;
DbgBreakIf(tcp_buf->app_buf_xferred != tcp_buf->app_buf_size);
con->app_buf_bytes_acc_comp = 0;
} else {
if (tcp_buf->flags & TCP_BUF_FLAG_L4_SPLIT) {
DbgBreakIf(GET_FLAGS(con->flags, TCP_POST_DELAYED) == 0);
con->dpc_info.dpc_unblock_post = TRUE;
RESET_FLAGS(tcp_buf->flags, TCP_BUF_FLAG_L4_SPLIT);
dbg_no_more_bufs = TRUE;
}
tcp_buf->app_buf_xferred = 0;
}
tcp_buf = (lm_tcp_buffer_t *)s_list_next_entry(&tcp_buf->link);
DbgBreakIf((con->type == TCP_CON_TYPE_RX) && completed_bytes && !tcp_buf);
DbgBreakIf((con->type == TCP_CON_TYPE_TX) && completed_bytes > 1 && !tcp_buf);
DbgBreakIf(tcp_buf && dbg_no_more_bufs);
}
if(tcp_buf) {
DbgBreakIf((tcp_buf->more_to_comp == tcp_buf->size) &&
!(tcp_buf->flags & TCP_BUF_FLAG_L4_POST_START ?
con->app_buf_bytes_acc_comp == 0 :
con->app_buf_bytes_acc_comp > 0));
tcp_buf->more_to_comp -= completed_bytes;
con->app_buf_bytes_acc_comp += completed_bytes;
completed_bytes = 0;
if(push && ((tcp_buf->flags & TCP_BUF_FLAG_L4_PARTIAL_FILLED) || (con->app_buf_bytes_acc_comp > 0)) ) {
DbgBreakIf(con->type != TCP_CON_TYPE_RX);
DbgBreakIf((push == 1) && (tcp_buf->flags & TCP_BUF_FLAG_L4_RX_NO_PUSH));
do {
tcp_buf = lm_tcp_next_entry_dpc_active_list(con);
DbgBreakIf(!tcp_buf);
actual_completed_bytes += tcp_buf->more_to_comp;
con->bytes_push_skip_cnt += tcp_buf->more_to_comp;
tcp_buf->more_to_comp = 0;
con->partially_completed_buf_cnt++;
con->dpc_info.dpc_completed_tail = &tcp_buf->link;
con->dpc_info.dpc_bd_used += tcp_buf->bd_used;
con->dpc_info.dpc_bufs_completed += 1;
con->dpc_info.dpc_actual_bytes_completed += tcp_buf->size;
} while ( !(GET_FLAGS(tcp_buf->flags, TCP_BUF_FLAG_L4_POST_END)) && !(GET_FLAGS(tcp_buf->flags, TCP_BUF_FLAG_L4_SPLIT)) );
if (GET_FLAGS(tcp_buf->flags, TCP_BUF_FLAG_L4_SPLIT)) {
DbgBreakIf(GET_FLAGS(con->flags, TCP_POST_DELAYED) == 0);
SET_FLAGS(con->flags, TCP_POST_COMPLETE_SPLIT);
con->dpc_info.dpc_unblock_post = TRUE;
RESET_FLAGS(tcp_buf->flags ,TCP_BUF_FLAG_L4_SPLIT);
} else {
tcp_buf->app_buf_xferred = con->app_buf_bytes_acc_comp;
DbgBreakIf(tcp_buf->app_buf_xferred >= tcp_buf->app_buf_size);
con->app_buf_bytes_acc_comp = 0;
}
}
}
DbgBreakIf((con->type == TCP_CON_TYPE_RX) && (completed_bytes != 0));
DbgBreakIf((con->type == TCP_CON_TYPE_TX) && (completed_bytes > 1));
return actual_completed_bytes - completed_bytes;
}
void lm_tcp_abort_bufs(
struct _lm_device_t * pdev,
lm_tcp_state_t * tcp,
lm_tcp_con_t * con,
lm_status_t stat
)
{
lm_tcp_buffer_t * tcp_buf;
s_list_entry_t * lentry_p;
s_list_t tmp_list;
DbgBreakIf( ! (pdev && con) );
DbgMessage(pdev, INFORMl4,
"#lm_tcp_abort_bufs: tcp=%p, con type=%d, stat=%d\n",
tcp, con->type, stat);
s_list_init(&tmp_list, NULL, NULL, 0);
if (!lm_reset_is_inprogress(pdev))
{
DbgBreakIf ((con->type == TCP_CON_TYPE_RX) && (con->u.rx.skp_bytes_copied));
}
lentry_p = s_list_pop_head(&con->active_tb_list);
while( lentry_p) {
tcp_buf = (lm_tcp_buffer_t *)lentry_p;
con->rq_nbytes -= tcp_buf->size;
tcp_buf->app_buf_xferred = 0;
if (tcp_buf->flags & TCP_BUF_FLAG_L4_POST_END) {
tcp_buf->app_buf_xferred = con->app_buf_bytes_acc_comp;
DbgBreakIf(tcp_buf->app_buf_size < con->app_buf_bytes_acc_comp);
con->app_buf_bytes_acc_comp = 0;
DbgBreakIf(S32_SUB(S64_SUB(con->bytes_post_cnt, con->bytes_comp_cnt), (tcp_buf->app_buf_size - tcp_buf->app_buf_xferred)) < 0);
con->bytes_comp_cnt += (tcp_buf->app_buf_size - tcp_buf->app_buf_xferred);
con->bytes_aborted_cnt += (tcp_buf->app_buf_size - tcp_buf->app_buf_xferred);
}
s_list_push_tail(&tmp_list, &tcp_buf->link);
lentry_p = s_list_pop_head(&con->active_tb_list);
}
if(s_list_entry_cnt(&tmp_list)) {
con->buffer_aborted_cnt += s_list_entry_cnt(&tmp_list);
if (lm_fl_reset_is_inprogress(pdev)) {
con->abortion_under_flr++;
}
mm_tcp_complete_bufs(pdev, tcp, con, &tmp_list, stat);
}
con->flags |= TCP_BUFFERS_ABORTED;
mm_tcp_abort_bufs(pdev,tcp,con,stat);
DbgBreakIf(!s_list_is_empty(&con->active_tb_list));
}
char * lm_tcp_qe_buffer_next_free_cqe(lm_tcp_qe_buffer_t * cqe_buffer)
{
char * cqe;
cqe = cqe_buffer->head;
if(cqe == cqe_buffer->last) {
cqe_buffer->head = cqe_buffer->first;
} else {
cqe_buffer->head = cqe + cqe_buffer->qe_size;
}
DbgBreakIf(cqe_buffer->left == 0);
cqe_buffer->left--;
return cqe;
}
char * lm_tcp_qe_buffer_next_occupied_cqe(lm_tcp_qe_buffer_t * cqe_buffer)
{
char * cqe;
cqe = cqe_buffer->tail;
if ((cqe == cqe_buffer->head) && (cqe_buffer->left > 0)) {
return NULL;
}
if(cqe == cqe_buffer->last) {
cqe_buffer->tail = cqe_buffer->first;
} else {
cqe_buffer->tail = cqe + cqe_buffer->qe_size;
}
cqe_buffer->left++;
return cqe;
}
u8_t lm_tcp_qe_buffer_is_empty(lm_tcp_qe_buffer_t * cqe_buffer)
{
return ((cqe_buffer->head == cqe_buffer->tail) && (cqe_buffer->left > 0));
}
char * lm_tcp_qe_buffer_next_cqe_override(lm_tcp_qe_buffer_t * cqe_buffer)
{
char * cqe;
cqe = cqe_buffer->head;
if(cqe == cqe_buffer->last) {
cqe_buffer->head = cqe_buffer->first;
} else {
cqe_buffer->head = cqe + cqe_buffer->qe_size;
}
if (cqe_buffer->left) {
cqe_buffer->left--;
}
return cqe;
}