xref: /titanic_51/usr/src/uts/common/io/bnxe/577xx/drivers/common/lm/l4/lm_l4tx.c (revision d14abf155341d55053c76eeec58b787a456b753b)
1 
2 #include "lm5710.h"
3 #include "bd_chain.h"
4 #include "command.h"
5 #include "context.h"
6 #include "lm_l4fp.h"
7 #include "lm_l4sp.h"
8 #include "mm_l4if.h"
9 
10 
11 /* TODO: remove this temporary solution for solaris / linux compilation conflict, linux needs the
12  * first option, solaris the latter */
13 #if defined(__LINUX)
14 #define TOE_TX_INIT_ZERO {{0}}
15 #else
16 #define TOE_TX_INIT_ZERO {0}
17 #endif
18 
19 #define TOE_TX_DOORBELL(pdev,cid) do{\
20     struct doorbell db = TOE_TX_INIT_ZERO;\
21     db.header.data |= (TOE_CONNECTION_TYPE << DOORBELL_HDR_T_CONN_TYPE_SHIFT);\
22     DOORBELL((pdev), (cid), *((u32_t *)&db));\
23     } while(0)
24 
25 static __inline void _lm_tcp_tx_write_db(
26     lm_device_t  * pdev,
27     lm_tcp_con_t * tx_con,
28     u32_t cid,
29     u32_t nbytes,
30     u16_t nbds,
31     u8_t fin)
32 {
33     volatile struct toe_tx_db_data *db_data = tx_con->db_data.tx;
34 
35     db_data->bds_prod += nbds;       /* nbds should be written before nbytes (FW assumption) */
36     DbgBreakIf((db_data->bds_prod & 0xff) == 0);
37     db_data->bytes_prod_seq += nbytes;
38 
39     if(fin) {
40         DbgBreakIf(db_data->flags & (TOE_TX_DB_DATA_FIN << TOE_TX_DB_DATA_FIN_SHIFT));
41         db_data->flags |= (TOE_TX_DB_DATA_FIN << TOE_TX_DB_DATA_FIN_SHIFT);
42     }
43 
44     if (!(tx_con->flags & TCP_TX_DB_BLOCKED)) {
45         DbgMessage(pdev, INFORMl4tx,
46                     "ringing tx doorbell: cid=%d, (nbytes+=%d, nbds+=%d, fin=%d)\n",
47                     cid, nbytes, nbds, fin);
48         TOE_TX_DOORBELL(pdev, cid);
49     }
50 }
51 
52 static __inline void lm_tcp_tx_write_db(
53     lm_device_t *pdev,
54     lm_tcp_state_t *tcp,
55     u8_t post_end)
56 {
57     lm_tcp_con_t *tx_con = tcp->tx_con;
58 
59     /* define a policy for ringing the doorbell */
60     #define MAX_BYTES_PER_TX_DB    0xffff
61     #define MAX_BDS_PER_TX_DB      64
62 
63     if (post_end ||
64         tx_con->db_more_bytes >= MAX_BYTES_PER_TX_DB ||
65         tx_con->db_more_bds >= MAX_BDS_PER_TX_DB) {
66         _lm_tcp_tx_write_db(pdev, tx_con, tcp->cid, tx_con->db_more_bytes, tx_con->db_more_bds, 0);
67 
68         /* assert if the new addition will make the cyclic counter post_cnt smaller than comp_cnt */
69         DbgBreakIf(S64_SUB(tx_con->bytes_post_cnt + tx_con->db_more_bytes, tx_con->bytes_comp_cnt) < 0);
70         tx_con->bytes_post_cnt += tx_con->db_more_bytes;
71         tx_con->buffer_post_cnt += tx_con->db_more_bufs;
72         tx_con->db_more_bytes = tx_con->db_more_bds = tx_con->db_more_bufs = 0;
73         tx_con->fp_db_cnt++;
74     } else {
75         DbgMessage(pdev, INFORMl4tx,
76                     "skipped doorbell ringing for cid=%d\n", tcp->cid);
77     }
78 }
79 
80 /** Description:
81  *  Post a single tcp buffer to the Tx bd chain
82  * Assumptions:
83  *  - caller initiated tcp_buf->flags field with BUFFER_START/BUFFER_END appropriately
84  * Returns:
85  *  - SUCCESS - tcp buf was successfully attached to the bd chain
86  *  - RESOURCE - not enough available BDs on bd chain for given tcp buf
87  *  - CONNECTION_CLOSED - whenever connection's flag are marked as 'POST BLOCKED' */
88 lm_status_t lm_tcp_tx_post_buf(
89     struct _lm_device_t *pdev,
90     lm_tcp_state_t      *tcp,
91     lm_tcp_buffer_t     *tcp_buf,
92     lm_frag_list_t      *frag_list)
93 {
94     lm_tcp_con_t *tx_con;
95     lm_bd_chain_t *tx_chain;
96     struct toe_tx_bd *tx_bd = NULL ;
97     lm_frag_t *frag;
98     u32_t i, dbg_buf_size = 0;
99     u32_t dbg_bytes_prod_seq;
100     u16_t old_prod, new_prod;
101 
102     DbgMessage(pdev, VERBOSEl4tx, "###lm_tcp_tx_post_buf\n");
103     DbgBreakIf(!(pdev && tcp && tcp_buf && frag_list));
104     DbgBreakIf(tcp->cid && (tcp != lm_cid_cookie(pdev, TOE_CONNECTION_TYPE, tcp->cid)));
105     DbgBreakIf(frag_list->cnt == 0);
106     tx_con = tcp->tx_con;
107     tx_chain = &tx_con->bd_chain;
108     frag = frag_list->frag_arr;
109 
110     DbgBreakIf(tx_con->flags & TCP_FIN_REQ_POSTED);
111 
112     /* check if tx con is already closed */
113     if(tx_con->flags & TCP_TX_POST_BLOCKED) {
114         DbgMessage(pdev, WARNl4tx, "post tx buf failed, posting is blocked (cid=%d, con->flags=%x)\n",
115                     tcp->cid, tx_con->flags);
116         return LM_STATUS_CONNECTION_CLOSED;
117     }
118     /* check bd chain availability (including additional bd that should
119      * be kept available for future fin request) */
120     if(lm_bd_chain_avail_bds(tx_chain) < frag_list->cnt + 1) {
121         DbgMessage(pdev, INFORMl4tx, "post tx buf failed, tx chain is full (cid=%d, avail bds=%d, buf nfrags=%d)\n",
122                     tcp->cid, lm_bd_chain_avail_bds(tx_chain), frag_list->cnt);
123 
124         LM_COMMON_DRV_STATS_ATOMIC_INC_TOE(pdev, tx_no_l4_bd);
125 
126         if (tx_con->db_more_bds) {
127             /* if doorbell ringing was deferred (e.g. until an end of
128              * application buffer), it can no longer be deferred since
129              * the place in the bd chain is now required */
130             lm_tcp_tx_write_db(pdev, tcp, 1);
131         }
132         return LM_STATUS_RESOURCE;
133     }
134 
135     old_prod = lm_bd_chain_prod_idx(tx_chain);
136 
137     dbg_bytes_prod_seq = tx_con->db_data.tx->bytes_prod_seq + tx_con->db_more_bytes;
138      /* "attach" the frags to the bd chain */
139     for(i = 0; i < frag_list->cnt; i++, frag++) {
140         DbgBreakIf(frag->size > 0xffff || frag->size == 0); /* hw limit: each bd can point to a buffer with max size of 64KB */
141         tx_bd = (struct toe_tx_bd *)lm_toe_bd_chain_produce_bd(tx_chain);
142         tx_bd->addr_hi = frag->addr.as_u32.high;
143         tx_bd->addr_lo = frag->addr.as_u32.low;
144         tx_bd->flags = 0;
145         tx_bd->size = (u16_t)frag->size;
146         dbg_bytes_prod_seq += frag->size;
147         tx_bd->nextBdStartSeq = dbg_bytes_prod_seq;
148         dbg_buf_size += frag->size;
149 
150         /* Support for FW Nagle Algorithm:
151          * This bit, is to be set for every bd which is part of a tcp buffer which is equal to or larger than an mss.
152          */
153         if ((u32_t)frag_list->size >= tx_con->u.tx.mss) {
154             tx_bd->flags |= TOE_TX_BD_LARGE_IO;
155         }
156 
157         DbgMessage(pdev, VERBOSEl4tx, "Setting Tx BD, addr_lo=0x%x, addr_hi=0x%x, size=%d\n",
158                     tx_bd->addr_lo, tx_bd->addr_hi, tx_bd->size);
159     }
160 
161     DbgBreakIf(frag_list->cnt > 0xffff);
162     tcp_buf->bd_used = frag_list->cnt & 0xffff;
163     tcp_buf->size = tcp_buf->more_to_comp = (u32_t)frag_list->size;
164     DbgBreakIf(tcp_buf->size != dbg_buf_size);
165 
166     DbgBreakIf(!(tcp_buf->flags & TCP_BUF_FLAG_L4_POST_START ?
167                  tx_con->app_buf_bytes_acc_post == 0 :
168                  tx_con->app_buf_bytes_acc_post > 0));
169     tx_con->app_buf_bytes_acc_post += tcp_buf->size;
170     tx_con->db_more_bytes += tcp_buf->size;
171     new_prod = lm_bd_chain_prod_idx(tx_chain);
172     DbgBreakIf(S16_SUB(new_prod, old_prod) < tcp_buf->bd_used);
173     tx_con->db_more_bds += S16_SUB(new_prod, old_prod);
174     tx_con->db_more_bufs++;
175 
176     /* Support for FW Nagle Algorithm:
177      * This bit, is to be set for every bd which is part of a tcp buffer which is equal to or larger than an mss.
178      */
179     if (tcp_buf->size >= tx_con->u.tx.mss) {
180         tx_bd->flags |= TOE_TX_BD_LARGE_IO;
181     }
182 
183     /* special care in case of last tcp buffer of an application buffer */
184     if(tcp_buf->flags & TCP_BUF_FLAG_L4_POST_END) {
185         tcp_buf->app_buf_xferred = 0; /* just for safety */
186         tcp_buf->app_buf_size = tx_con->app_buf_bytes_acc_post;
187         tx_con->app_buf_bytes_acc_post = 0;
188 
189         /* special care for the last bd: */
190         tx_bd->flags |= TOE_TX_BD_NOTIFY;
191         tx_con->u.tx.bds_without_comp_flag = 0;
192         tx_bd->flags |= TOE_TX_BD_PUSH;
193 
194         DbgMessage(pdev, VERBOSEl4tx,
195                     "Setting Tx BD, last bd of app buf, flags=%d\n", tx_bd->flags);
196     } else {
197         /* make sure there aren't 'too many' bds without completion flag */
198         tx_con->u.tx.bds_without_comp_flag += tcp_buf->bd_used;
199         if (tx_con->u.tx.bds_without_comp_flag > (tx_chain->capacity - MAX_FRAG_CNT_PER_TB)) {
200             tx_bd->flags |= TOE_TX_BD_NOTIFY;
201             tx_con->u.tx.bds_without_comp_flag = 0;
202         }
203     }
204 
205     s_list_push_tail(&tx_con->active_tb_list, &tcp_buf->link);
206     tx_con->rq_nbytes += tcp_buf->size;
207     lm_tcp_tx_write_db(pdev, tcp, tcp_buf->flags & TCP_BUF_FLAG_L4_POST_END);
208 
209     /* network reachability (NOT IMPLEMENTED):
210     if(lm_neigh_is_cache_entry_staled(tcp->path->neigh))
211        lm_neigh_indicate_staled_cache_entry(tcp->path->neigh);
212     */
213 
214     DbgMessage(pdev, VERBOSEl4tx, "posted tx buf for cid=%d, buf size=%d, bd used=%d, buf flags=%x, app_buf_size=%d\n",
215                 tcp->cid, tcp_buf->size, tcp_buf->bd_used, tcp_buf->flags, tcp_buf->app_buf_size);
216     DbgMessage(pdev, VERBOSEl4tx, "after posting tx buf, tx_con->active_tb_list=%d\n",
217                 s_list_entry_cnt(&tx_con->active_tb_list));
218 
219     return LM_STATUS_SUCCESS;
220 } /* lm_tcp_tx_post_buf */
221 
222 /** Description
223  *  indicates graceful disconnect completion to client.
224  * Assumtpions:
225  *  tx-lock is taken by caller
226  */
227 static __inline void lm_tcp_tx_graceful_disconnect_complete(lm_device_t * pdev, lm_tcp_state_t * tcp)
228 {
229     u8_t ip_version;
230     DbgBreakIf(!s_list_is_empty(&tcp->tx_con->active_tb_list));
231     DbgBreakIf(tcp->tx_con->flags & TCP_FIN_REQ_COMPLETED);
232     tcp->tx_con->flags |= TCP_FIN_REQ_COMPLETED;
233     DbgMessage(pdev, INFORMl4tx, "fin request completed (cid=%d)\n", tcp->cid);
234     tcp->tcp_state_calc.fin_completed_time = mm_get_current_time(pdev);
235     if (!(tcp->tx_con->u.tx.flags & TCP_CON_FIN_REQ_LM_INTERNAL)) {
236         ip_version = (tcp->path->path_const.ip_version == IP_VERSION_IPV4)? STATS_IP_4_IDX : STATS_IP_6_IDX;
237         LM_COMMON_DRV_STATS_ATOMIC_INC_TOE(pdev, ipv[ip_version].out_fin);
238         mm_tcp_graceful_disconnect_done(pdev,tcp, LM_STATUS_SUCCESS);
239     }
240 }
241 
242 void lm_tcp_tx_cmp_process(
243     struct _lm_device_t *pdev,
244     lm_tcp_state_t      *tcp,
245     u32_t               completed_bytes
246     )
247 {
248     lm_tcp_con_t *tx_con = tcp->tx_con;
249     u32_t actual_completed; /* number of bytes actually completed (could be different than completed in case of fin) */
250     MM_INIT_TCP_LOCK_HANDLE();
251 
252     DbgMessage(pdev, VERBOSEl4tx, "##lm_tcp_tx_app_cmp_process, cid=%d, completed_bytes=%d\n",
253                 tcp->cid, completed_bytes);
254 
255     DbgBreakIf(tx_con->flags & TCP_TX_COMP_BLOCKED);
256 
257     if (!(tx_con->flags & TCP_DEFERRED_PROCESSING)) {
258         mm_acquire_tcp_lock(pdev, tx_con);
259     }
260     tx_con->bytes_comp_cnt += completed_bytes;
261     DbgBreakIf(S64_SUB(tx_con->bytes_post_cnt, tx_con->bytes_comp_cnt) < 0);
262 
263     DbgBreakIf(!completed_bytes);
264 
265     actual_completed = lm_tcp_complete_nbytes(pdev, tcp, tcp->tx_con, completed_bytes, FALSE);
266 
267     if (actual_completed != completed_bytes) {
268         DbgBreakIf(actual_completed > completed_bytes);
269         DbgBreakIf((completed_bytes - actual_completed) != 1);
270         DbgBreakIf(!(tx_con->flags & TCP_FIN_REQ_POSTED));
271         DbgBreakIf(tx_con->bytes_post_cnt != tx_con->bytes_comp_cnt);
272         /* fin completed */
273         tx_con->dpc_info.dpc_flags |= LM_TCP_DPC_FIN_CMP;
274         tx_con->dpc_info.dpc_comp_blocked = TRUE; /* TCP_FIN_REQ_COMPLETED */
275     }
276 
277     /* network reachability (NOT IMPLEMENTED):
278     lm_neigh_update_nic_reachability_time(tcp->path->neigh)
279     */
280     if (!(tx_con->flags & TCP_DEFERRED_PROCESSING)) {
281         mm_release_tcp_lock(pdev, tx_con);
282     }
283 
284 } /* lm_tcp_tx_app_cmp_process */
285 
286 u8_t lm_toe_is_tx_completion(lm_device_t *pdev, u8_t drv_toe_rss_id)
287 {
288     u8_t result = FALSE;
289     lm_tcp_scq_t *scq = NULL;
290 
291     DbgBreakIf(!(pdev && ARRSIZE(pdev->toe_info.scqs) > drv_toe_rss_id));
292 
293     scq = &pdev->toe_info.scqs[drv_toe_rss_id];
294 
295     if ( scq->hw_con_idx_ptr &&
296         *scq->hw_con_idx_ptr != lm_bd_chain_cons_idx(&scq->bd_chain) )
297     {
298         result = TRUE;
299     }
300     DbgMessage(pdev, INFORMl4int, "lm_toe_is_tx_completion(): result is:%s\n", result? "TRUE" : "FALSE");
301 
302     return result;
303 }
304 
305 void lm_tcp_tx_inc_trm_aborted_bytes(
306     struct _lm_device_t *pdev,
307     lm_tcp_state_t      *tcp,
308     u32_t               aborted_bytes
309     )
310 {
311     lm_tcp_con_t *tx_con = tcp->tx_con;
312     MM_INIT_TCP_LOCK_HANDLE();
313 
314     DbgMessage(pdev, VERBOSEl4tx, "##lm_tcp_tx_inc_aborted_count, cid=%d, aborted_bytes=%d\n",
315                 tcp->cid, aborted_bytes);
316 
317     if (!(tx_con->flags & TCP_DEFERRED_PROCESSING)) {
318         mm_acquire_tcp_lock(pdev, tx_con);
319     }
320 
321     tx_con->bytes_trm_aborted_cnt += aborted_bytes;
322 
323     if (!(tx_con->flags & TCP_DEFERRED_PROCESSING)) {
324         mm_release_tcp_lock(pdev, tx_con);
325     }
326 
327 } /* lm_tcp_tx_inc_aborted_count */
328 
329 /** Description
330  *   completes the fast-path operations for a certain connection
331  *  Assumption:
332  *   fp-tx lock is taken
333  */
334 void lm_tcp_tx_complete_tcp_fp(lm_device_t * pdev, lm_tcp_state_t * tcp, lm_tcp_con_t * con)
335 {
336     /**** Client completing :  may result in lock-release *****/
337     /* during lock-release, due to this function being called from service_deferred, more
338      * cqes can be processed. We don't want to mix. This function is mutually exclusive, so
339      * any processing makes it's way to being completed by calling this function.
340      * the following define a "fast-path completion"
341      * (i)   RQ buffers to be completed
342      *       defined by dpc_completed_tail and are collected during lm_tcp_complete_bufs BEFORE lock
343      *       is released, so no more buffer processing can make it's way into this buffer completion.
344      * (ii)  Fin to be completed
345      *       determined by the flags, since dpc_flags CAN be modified during processing we copy
346      *       them to a snapshot_flags parameter, which is initialized in this function only, so no fin
347      *       can can make its way in while we release the lock.
348      * (iv)  Remainders for sp
349      *       all sp operations are logged in dpc_flags. for the same reason as (iii) no sp commands can
350      *       make their way in during this fp-completion, all sp-processing after will relate to this point in time.
351      */
352 
353     con->dpc_info.snapshot_flags = con->dpc_info.dpc_flags;
354     con->dpc_info.dpc_flags = 0;
355 
356     /* complete buffers to client */
357     if (con->dpc_info.dpc_completed_tail != NULL) {
358         lm_tcp_complete_bufs(pdev, tcp, con);
359     }
360 
361     /* Graceful Disconnect */
362     if (con->dpc_info.snapshot_flags & LM_TCP_DPC_FIN_CMP) {
363         con->dpc_info.snapshot_flags &= ~LM_TCP_DPC_FIN_CMP;
364         lm_tcp_tx_graceful_disconnect_complete(pdev, con->tcp_state);
365     }
366 
367 }
368 
369 void lm_tcp_tx_process_cqe(
370     lm_device_t        * pdev,
371     struct toe_tx_cqe  * cqe,
372     lm_tcp_state_t     * tcp
373     )
374 {
375     enum toe_sq_opcode_type cmd;
376 
377     /* get the cmd from cqe */
378     cmd = ((cqe->params & TOE_TX_CQE_COMPLETION_OPCODE) >> TOE_TX_CQE_COMPLETION_OPCODE_SHIFT);
379 
380     DbgMessage(pdev, INFORMl4tx, "###lm_tcp_tx_process_cqe cid=%d cmd=%d\n", tcp->cid, cmd);
381     DbgBreakIf( ! (pdev && tcp) );
382     /* Check that the cqe len make sense, we could have got here by chance... */
383     DbgBreakIfAll(cqe->len & 0xc0000000); /* two upper bits on show a completion larger than 1GB - a bit odd...*/
384 
385     /* Three types of completios: fast-path, reset-recv, ramrod-cmp. All completions may have a
386      * fast-path part (nbytes completed) which will be handled in any case that cqe->len > 0 */
387 
388     /* complete data if anything needs to be complete */
389     if (cqe->len &&
390         ((tcp->tx_con->dpc_info.dpc_flags & LM_TCP_DPC_RESET_RECV /* RST recv on this DPC on a previous CQE */ ) ||
391          (tcp->tx_con->flags & TCP_REMOTE_RST_RECEIVED /* RST recv on previous DPC */ )))
392     {
393         /* 10/28/08 - Since in exterme cases current FW may not complete all sent+acked bytes
394            on RST recv cqe and do so only later on one of the following ramrod completions,
395            we need to ignore this too late completed bytes thus we nullify cqe->len */
396         DbgBreakIf((cmd != RAMROD_OPCODE_TOE_RESET_SEND) &&
397                    (cmd != RAMROD_OPCODE_TOE_INVALIDATE) &&
398                    (cmd != RAMROD_OPCODE_TOE_EMPTY_RAMROD) &&
399                    (cmd != RAMROD_OPCODE_TOE_TERMINATE));
400         lm_tcp_tx_inc_trm_aborted_bytes(pdev, tcp, cqe->len);
401         cqe->len = 0;
402     }
403     if (cqe->len) {
404         DbgBreakIf(tcp->tx_con->dpc_info.dpc_comp_blocked);
405         lm_tcp_tx_cmp_process(pdev, tcp, cqe->len);
406     }
407 
408     switch(cmd) {
409     case CMP_OPCODE_TOE_TX_CMP:
410         break;
411     case CMP_OPCODE_TOE_RST_RCV:
412         tcp->tx_con->dpc_info.dpc_flags |= LM_TCP_DPC_RESET_RECV;
413         tcp->tx_con->dpc_info.dpc_comp_blocked = TRUE; /* TCP_REMOTE_RST_RECEIVED */
414         break;
415     case RAMROD_OPCODE_TOE_RESET_SEND:
416         DbgBreakIf(! tcp->sp_request);
417         DbgBreakIf(tcp->sp_request->type != SP_REQUEST_ABORTIVE_DISCONNECT);
418         tcp->tx_con->dpc_info.dpc_flags |= LM_TCP_DPC_RAMROD_CMP;
419         tcp->tx_con->dpc_info.dpc_comp_blocked = TRUE; /* TCP_RST_REQ_COMPLETED */
420         break;
421     case RAMROD_OPCODE_TOE_INVALIDATE:
422         DbgBreakIf(! tcp->sp_request);
423         DbgBreakIf(tcp->sp_request->type != SP_REQUEST_INVALIDATE);
424         tcp->tx_con->dpc_info.dpc_flags |= LM_TCP_DPC_RAMROD_CMP;
425         tcp->tx_con->dpc_info.dpc_comp_blocked = TRUE; /* TCP_INV_REQ_COMPLETED */
426         break;
427     case RAMROD_OPCODE_TOE_TERMINATE:
428         DbgBreakIf(! tcp->sp_request);
429         DbgBreakIf(tcp->sp_request->type != SP_REQUEST_TERMINATE1_OFFLOAD);
430         tcp->tx_con->dpc_info.dpc_flags |= LM_TCP_DPC_RAMROD_CMP;
431         tcp->tx_con->dpc_info.dpc_comp_blocked = TRUE; /* TCP_TRM_REQ_COMPLETED */
432         break;
433     case RAMROD_OPCODE_TOE_EMPTY_RAMROD:
434         DbgBreakIf(cqe->len);
435         DbgBreakIf(! tcp->sp_request );
436         DbgBreakIf((tcp->sp_request->type != SP_REQUEST_PENDING_LOCAL_FIN_DISCONNECT) &&
437                    (tcp->sp_request->type != SP_REQUEST_PENDING_REMOTE_DISCONNECT) &&
438                    (tcp->sp_request->type != SP_REQUEST_PENDING_TX_RST));
439         tcp->tx_con->dpc_info.dpc_flags |= LM_TCP_DPC_RAMROD_CMP;
440         break;
441     default:
442         DbgMessage(pdev, FATAL, "unexpected tx cqe opcode=%d\n", cmd);
443         DbgBreakIfAll(TRUE);
444     }
445 }
446 
447 /** Description
448  *
449  * Assumptions
450  *   connections is initialzed with a dummy head.
451  */
452 void lm_tcp_tx_process_cqes(lm_device_t *pdev, u8_t drv_toe_rss_id, s_list_t * connections)
453 {
454     lm_tcp_scq_t *scq;
455     struct toe_tx_cqe *cqe, *hist_cqe;
456     lm_tcp_state_t *tcp;
457     u32_t cid;
458     u32_t avg_dpc_cnt;
459     u16_t cq_new_idx;
460     u16_t cq_old_idx;
461     u16_t num_to_reproduce = 0;
462     u8_t defer_cqe;
463     MM_INIT_TCP_LOCK_HANDLE();
464 
465     DbgMessage(pdev, VERBOSEl4int , "###lm_tcp_tx_process_cqes\n");
466 
467     scq = &pdev->toe_info.scqs[drv_toe_rss_id];
468     cq_new_idx = *(scq->hw_con_idx_ptr);
469     cq_old_idx = lm_bd_chain_cons_idx(&scq->bd_chain);
470     DbgBreakIf(S16_SUB(cq_new_idx, cq_old_idx) <= 0);
471 
472     /* save statistics */
473     scq->num_cqes_last_dpc = S16_SUB(cq_new_idx, cq_old_idx);
474     if (scq->num_cqes_last_dpc) { /* Exclude zeroed value from statistics*/
475         if(scq->max_cqes_per_dpc < scq->num_cqes_last_dpc) {
476             scq->max_cqes_per_dpc = scq->num_cqes_last_dpc;
477         }
478         /* we don't want to wrap around...*/
479         if ((scq->sum_cqes_last_x_dpcs + scq->num_cqes_last_dpc) < scq->sum_cqes_last_x_dpcs) {
480             scq->avg_dpc_cnt = 0;
481             scq->sum_cqes_last_x_dpcs = 0;
482         }
483         scq->sum_cqes_last_x_dpcs += scq->num_cqes_last_dpc;
484         scq->avg_dpc_cnt++;
485         avg_dpc_cnt = scq->avg_dpc_cnt;
486         if (avg_dpc_cnt) {
487             scq->avg_cqes_per_dpc = scq->sum_cqes_last_x_dpcs / avg_dpc_cnt;
488         } else {
489             scq->sum_cqes_last_x_dpcs = 0;
490         }
491     }
492 
493     while(cq_old_idx != cq_new_idx) {
494         DbgBreakIf(S16_SUB(cq_new_idx, cq_old_idx) <= 0);
495 
496         /* get next consumed cqe */
497         cqe = lm_toe_bd_chain_consume_bd(&scq->bd_chain);
498         DbgBreakIf(!cqe);
499         num_to_reproduce++;
500 
501         /* get tcp state from cqe */
502         cid = SW_CID(((cqe->params & TOE_TX_CQE_CID) >> TOE_TX_CQE_CID_SHIFT));
503         tcp = lm_cid_cookie(pdev, TOE_CONNECTION_TYPE, cid);
504         DbgBreakIf(!tcp);
505         /* save cqe in history_cqes */
506         hist_cqe = (struct toe_tx_cqe *)lm_tcp_qe_buffer_next_cqe_override(&tcp->tx_con->history_cqes);
507         *hist_cqe = *cqe;
508 
509         defer_cqe = ((tcp->tx_con->flags & TCP_TX_COMP_DEFERRED) == TCP_TX_COMP_DEFERRED);
510         if (defer_cqe) {
511             /* if we're deferring completions - just store the cqe and continue to the next one */
512             /* Return if we are still deferred (may have changed since initial check was w/o a lock */
513             mm_acquire_tcp_lock(pdev, tcp->tx_con);
514             /* check again under lock if we're deferred */
515             defer_cqe = ((tcp->tx_con->flags & TCP_TX_COMP_DEFERRED) == TCP_TX_COMP_DEFERRED);
516             if (defer_cqe) {
517                 tcp->tx_con->flags |= TCP_DEFERRED_PROCESSING;
518                 lm_tcp_tx_process_cqe(pdev, cqe, tcp);
519             }
520             mm_release_tcp_lock(pdev, tcp->tx_con);
521         }
522         if (!defer_cqe) {
523             /* connections will always be initialized to a dummy, so once a tcp connection is added to the
524              * list, it's link will be initialized to point to another link other than NULL */
525             if (s_list_next_entry(&tcp->tx_con->dpc_info.link) == NULL) {
526                 s_list_push_head(connections, &tcp->tx_con->dpc_info.link);
527             }
528             lm_tcp_tx_process_cqe(pdev, cqe, tcp);
529         }
530         cq_old_idx = lm_bd_chain_cons_idx(&scq->bd_chain);
531         /* GilR 5/12/2006 - TODO - decide with Alon if reading the hw_con again is required */
532         //cq_new_idx = *(scq->hw_con_idx_ptr);
533     }
534 
535     /* The fact that we post the producer here before we've handled any slow-path completions assures that
536      * the sp-ring will always be updated AFTER the producer was. */
537     if (num_to_reproduce) {
538         lm_toe_bd_chain_bds_produced(&scq->bd_chain, num_to_reproduce);
539 
540         /* GilR 5/13/2006 - TBA - save some stats? */
541 
542         /* notify the fw of the prod of the SCQ */
543         LM_INTMEM_WRITE16(pdev, CSTORM_TOE_CQ_PROD_OFFSET(LM_TOE_FW_RSS_ID(pdev,drv_toe_rss_id) , PORT_ID(pdev)),
544                           lm_bd_chain_prod_idx(&scq->bd_chain),  BAR_CSTRORM_INTMEM);
545     }
546 }
547 
548 void lm_toe_service_tx_intr(lm_device_t *pdev, u8_t drv_toe_rss_id)
549 {
550     s_list_t         connections;
551     s_list_entry_t   dummy;
552     lm_tcp_con_t   * con;
553     lm_tcp_state_t * tcp;
554 
555     MM_INIT_TCP_LOCK_HANDLE();
556 
557     DbgMessage(pdev, VERBOSEl4int , "###lm_toe_service_tx_intr\n");
558     DbgBreakIf(!(pdev && ARRSIZE(pdev->toe_info.scqs) > drv_toe_rss_id));
559 
560     s_list_clear(&connections);
561     s_list_push_head(&connections, &dummy);
562     /* process the cqes and initialize connections with all the connections that appeared
563      * in the DPC */
564     lm_tcp_tx_process_cqes(pdev,drv_toe_rss_id,&connections);
565 
566     /* complete the fp/sp parts of the connections remember to ignore the last one */
567     con = (lm_tcp_con_t *)s_list_peek_head(&connections);
568     tcp = con->tcp_state;
569     while (s_list_next_entry(&con->dpc_info.link) != NULL) {
570         mm_acquire_tcp_lock(pdev, con);
571         lm_tcp_tx_complete_tcp_fp(pdev, con->tcp_state, con);
572         mm_release_tcp_lock(pdev, con);
573         con = (lm_tcp_con_t *)s_list_next_entry(&con->dpc_info.link);
574         tcp = con->tcp_state;
575     }
576 
577     /* SP : traverse the connections. remember to ignore the last one */
578     con = (lm_tcp_con_t *)s_list_pop_head(&connections);
579     s_list_next_entry(&con->dpc_info.link) = NULL;
580     tcp = con->tcp_state;
581     while (s_list_entry_cnt(&connections) > 0) {
582         /* we access snapshot and not dpc, since once the dpc_flags were copied
583          * to snapshot they were zeroized */
584         if (con->dpc_info.snapshot_flags) {
585             lm_tcp_tx_complete_tcp_sp(pdev, tcp, con);
586         }
587         con = (lm_tcp_con_t *)s_list_pop_head(&connections);
588         s_list_next_entry(&con->dpc_info.link) = NULL;
589         tcp = con->tcp_state;
590     }
591 
592 }
593 
594 lm_status_t lm_tcp_graceful_disconnect(
595     IN lm_device_t          * pdev,
596     IN lm_tcp_state_t       * tcp_state
597 )
598 {
599     struct toe_tx_bd *tx_bd;
600     lm_tcp_con_t     *tcp_con = tcp_state->tx_con;
601     u16_t old_prod, new_prod;
602     u32_t dbg_bytes_prod_seq;
603 
604     DbgMessage(pdev, INFORMl4tx, "###lm_tcp_graceful_disconnect\n");
605 
606     if ( tcp_con->flags & TCP_TX_POST_BLOCKED ) {
607         return LM_STATUS_CONNECTION_CLOSED;
608     }
609 
610     DbgBreakIf( (tcp_con->app_buf_bytes_acc_post != 0) ||
611                 (tcp_con->db_more_bytes != 0) ||
612                 (tcp_con->db_more_bds != 0) ||
613                 (tcp_con->u.tx.bds_without_comp_flag != 0)
614                 );
615 
616     old_prod = lm_bd_chain_prod_idx(&(tcp_con->bd_chain));
617 
618     /* Post FIN BD on Tx chain */
619     tx_bd = (struct toe_tx_bd *)lm_toe_bd_chain_produce_bd(&(tcp_con->bd_chain));
620     tx_bd->flags = TOE_TX_BD_FIN;  /* Vladz: Pay attention when u move this
621                                              line - there is an assignment to flags, NOT bitwise OR */
622     tx_bd->flags |= TOE_TX_BD_NOTIFY;
623     tx_bd->size = 1;
624     /* For a safety */
625     tx_bd->addr_hi = tx_bd->addr_lo = 0;
626 
627     dbg_bytes_prod_seq = tcp_con->db_data.tx->bytes_prod_seq + tcp_con->db_more_bytes;
628     dbg_bytes_prod_seq += tx_bd->size;
629     tx_bd->nextBdStartSeq = dbg_bytes_prod_seq;
630 
631     new_prod = lm_bd_chain_prod_idx(&(tcp_con->bd_chain));
632     DbgBreakIf(S16_SUB(new_prod, old_prod) >= 3);
633     DbgBreakIf(S16_SUB(new_prod, old_prod) <= 0);
634 
635     DbgBreakIf(tcp_con->flags & TCP_FIN_REQ_POSTED);
636     tcp_con->flags |= TCP_FIN_REQ_POSTED;
637 
638     /* Update fin request time, if not already set by the caller */
639     if (!tcp_state->tcp_state_calc.fin_request_time) {
640         tcp_state->tcp_state_calc.fin_request_time = mm_get_current_time(pdev);
641         if (tcp_state->tcp_state_calc.fin_request_time == tcp_state->tcp_state_calc.fin_reception_time){
642             tcp_state->tcp_state_calc.fin_reception_time -= 1;
643         }
644     }
645 
646     /* Doorbell FIN */
647     _lm_tcp_tx_write_db(pdev, tcp_con, tcp_state->cid, 0, (u16_t)S16_SUB(new_prod, old_prod), 1);
648 
649     /* assert if the new addition will make the cyclic counter post_cnt smaller than comp_cnt */
650     DbgBreakIf(S64_SUB(tcp_con->bytes_post_cnt + 1, tcp_con->bytes_comp_cnt) < 0);
651     tcp_con->bytes_post_cnt++;
652     tcp_con->fp_db_cnt++;
653 
654     return LM_STATUS_SUCCESS;
655 }
656 
657 
658