xref: /illumos-gate/usr/src/uts/common/io/bnxe/bnxe_tx.c (revision 51396a8ee7fb52fe0ab33bfe7b4f495ad431904a)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2014 QLogic Corporation
24  * The contents of this file are subject to the terms of the
25  * QLogic End User License (the "License").
26  * You may not use this file except in compliance with the License.
27  *
28  * You can obtain a copy of the License at
29  * http://www.qlogic.com/Resources/Documents/DriverDownloadHelp/
30  * QLogic_End_User_Software_License.txt
31  * See the License for the specific language governing permissions
32  * and limitations under the License.
33  */
34 
35 /*
36  * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
37  */
38 
39 #include "bnxe.h"
40 
41 ddi_dma_attr_t bnxeTxDmaAttrib =
42 {
43     DMA_ATTR_V0,                /* dma_attr_version */
44     0,                          /* dma_attr_addr_lo */
45     0xffffffffffffffff,         /* dma_attr_addr_hi */
46     0xffffffffffffffff,         /* dma_attr_count_max */
47     BNXE_DMA_ALIGNMENT,         /* dma_attr_align */
48     0xffffffff,                 /* dma_attr_burstsizes */
49     1,                          /* dma_attr_minxfer */
50     0xffffffffffffffff,         /* dma_attr_maxxfer */
51     0xffffffffffffffff,         /* dma_attr_seg */
52     BNXE_MAX_DMA_SGLLEN,        /* dma_attr_sgllen */
53     1,                          /* dma_attr_granular */
54     0,                          /* dma_attr_flags */
55 };
56 
57 ddi_dma_attr_t bnxeTxCbDmaAttrib =
58 {
59     DMA_ATTR_V0,                /* dma_attr_version */
60     0,                          /* dma_attr_addr_lo */
61     0xffffffffffffffff,         /* dma_attr_addr_hi */
62     0xffffffffffffffff,         /* dma_attr_count_max */
63     BNXE_DMA_ALIGNMENT,         /* dma_attr_align */
64     0xffffffff,                 /* dma_attr_burstsizes */
65     1,                          /* dma_attr_minxfer */
66     0xffffffffffffffff,         /* dma_attr_maxxfer */
67     0xffffffffffffffff,         /* dma_attr_seg */
68     1,                          /* dma_attr_sgllen */
69     1,                          /* dma_attr_granular */
70     0,                          /* dma_attr_flags */
71 };
72 
73 
74 static um_txpacket_t * BnxeTxPktAlloc(um_device_t * pUM, size_t size);
75 
76 
77 static inline void BnxeTxPktUnmap(um_txpacket_t * pTxPkt)
78 {
79     int i;
80 
81     for (i = 0; i < pTxPkt->num_handles; i++)
82     {
83         ddi_dma_unbind_handle(pTxPkt->dmaHandles[i]);
84     }
85 
86     pTxPkt->num_handles = 0;
87 }
88 
89 
90 static void BnxeTxPktsFree(um_txpacket_t * pTxPkt)
91 {
92     int i;
93 
94     if (pTxPkt->num_handles > 0)
95     {
96         BnxeTxPktUnmap(pTxPkt);
97     }
98 
99     if (pTxPkt->pMblk != NULL)
100     {
101         freemsg(pTxPkt->pMblk);
102     }
103 
104     for (i = 0; i < BNXE_MAX_DMA_HANDLES_PER_PKT; i++)
105     {
106         ddi_dma_free_handle(&pTxPkt->dmaHandles[i]);
107     }
108 
109     pTxPkt->pMblk         = NULL;
110     pTxPkt->num_handles   = 0;
111     pTxPkt->frag_list.cnt = 0;
112 
113     ddi_dma_unbind_handle(pTxPkt->cbDmaHandle);
114     ddi_dma_mem_free(&pTxPkt->cbDmaAccHandle);
115     ddi_dma_free_handle(&pTxPkt->cbDmaHandle);
116     kmem_free(pTxPkt, sizeof(um_txpacket_t));
117 }
118 
119 
120 static void BnxeTxPktsFreeList(s_list_t * pPktList)
121 {
122     um_txpacket_t * pTxPkt;
123 
124     while (!s_list_is_empty(pPktList))
125     {
126         pTxPkt = (um_txpacket_t *)s_list_pop_head(pPktList);
127         BnxeTxPktsFree(pTxPkt);
128     }
129 }
130 
131 
132 /*
133  * Free the mblk and all frag mappings used by each packet in the list
134  * and then put the entire list on the free queue for immediate use.
135  */
136 void BnxeTxPktsReclaim(um_device_t * pUM,
137                        int           idx,
138                        s_list_t *    pPktList)
139 {
140     um_txpacket_t * pTxPkt;
141 
142     if (s_list_entry_cnt(pPktList) == 0)
143     {
144         return;
145     }
146 
147     for (pTxPkt = (um_txpacket_t *)s_list_peek_head(pPktList);
148          pTxPkt;
149          pTxPkt = (um_txpacket_t *)s_list_next_entry(&pTxPkt->lm_pkt.link))
150     {
151         if (pTxPkt->num_handles > 0)
152         {
153             BnxeTxPktUnmap(pTxPkt);
154         }
155 
156         if (pTxPkt->pMblk != NULL)
157         {
158             freemsg(pTxPkt->pMblk);
159             pTxPkt->pMblk = NULL;
160         }
161     }
162 
163     BNXE_LOCK_ENTER_FREETX(pUM, idx);
164     s_list_add_tail(&pUM->txq[idx].freeTxDescQ, pPktList);
165     BNXE_LOCK_EXIT_FREETX(pUM, idx);
166 }
167 
168 
169 /* Must be called with TX lock held!!! */
170 static int BnxeTxSendWaitingPkt(um_device_t * pUM,
171                                 int           idx)
172 {
173     TxQueue *       pTxQ = &pUM->txq[idx];
174     lm_device_t *   pLM = &pUM->lm_dev;
175     lm_tx_chain_t * pLmTxChain;
176     um_txpacket_t * pTxPkt;
177     int rc;
178 
179     pLmTxChain = &pLM->tx_info.chain[idx];
180 
181     while (s_list_entry_cnt(&pTxQ->waitTxDescQ))
182     {
183         pTxPkt = (um_txpacket_t *)s_list_peek_head(&pTxQ->waitTxDescQ);
184 
185         if (pTxPkt->frag_list.cnt + 2 > pLmTxChain->bd_chain.bd_left)
186         {
187             return BNXE_TX_DEFERPKT;
188         }
189 
190         pTxPkt = (um_txpacket_t *)s_list_pop_head(&pTxQ->waitTxDescQ);
191 
192         rc = lm_send_packet(pLM, idx, &pTxPkt->lm_pkt, &pTxPkt->frag_list);
193 
194         if (pUM->fmCapabilities &&
195             BnxeCheckAccHandle(pLM->vars.reg_handle[BAR_0]) != DDI_FM_OK)
196         {
197             ddi_fm_service_impact(pUM->pDev, DDI_SERVICE_DEGRADED);
198         }
199 
200         if (rc != LM_STATUS_SUCCESS)
201         {
202             /*
203              * Send failed (probably not enough BDs available)...
204              * Put the packet back at the head of the wait queue.
205              */
206             pTxQ->txFailed++;
207             s_list_push_head(&pTxQ->waitTxDescQ, &pTxPkt->lm_pkt.link);
208             return BNXE_TX_DEFERPKT;
209         }
210     }
211 
212     return BNXE_TX_GOODXMIT;
213 }
214 
215 
216 void BnxeTxRingProcess(um_device_t * pUM,
217                        int           idx)
218 {
219     TxQueue *       pTxQ = &pUM->txq[idx];
220     lm_device_t *   pLM = &pUM->lm_dev;
221     lm_tx_chain_t * pLmTxChain;
222     s_list_t        tmpList;
223     u32_t           pktsTxed;
224     int rc;
225 
226     s_list_clear(&tmpList);
227 
228     BNXE_LOCK_ENTER_TX(pUM, idx);
229 
230     pktsTxed = lm_get_packets_sent(&pUM->lm_dev, idx, &tmpList);
231 
232     if (pUM->fmCapabilities &&
233         BnxeCheckAccHandle(pUM->lm_dev.vars.reg_handle[BAR_0]) != DDI_FM_OK)
234     {
235         ddi_fm_service_impact(pUM->pDev, DDI_SERVICE_DEGRADED);
236     }
237 
238     if ((pktsTxed + s_list_entry_cnt(&pTxQ->sentTxQ)) >=
239         pUM->devParams.maxTxFree)
240     {
241         s_list_add_tail(&tmpList, &pTxQ->sentTxQ);
242         s_list_clear(&pTxQ->sentTxQ);
243     }
244     else
245     {
246         s_list_add_tail(&pTxQ->sentTxQ, &tmpList);
247         s_list_clear(&tmpList);
248     }
249 
250     BNXE_LOCK_EXIT_TX(pUM, idx);
251 
252     if (s_list_entry_cnt(&tmpList))
253     {
254         BnxeTxPktsReclaim(pUM, idx, &tmpList);
255     }
256 
257     if (pTxQ->noTxCredits == 0)
258     {
259         /* no need to notify the stack */
260         return;
261     }
262 
263     pLmTxChain = &pUM->lm_dev.tx_info.chain[idx];
264 
265     if (pTxQ->noTxCredits & BNXE_TX_RESOURCES_NO_CREDIT)
266     {
267         BNXE_LOCK_ENTER_TX(pUM, idx);
268         rc = BnxeTxSendWaitingPkt(pUM, idx);
269         BNXE_LOCK_EXIT_TX(pUM, idx);
270 
271         if ((rc == BNXE_TX_GOODXMIT) &&
272             (pLmTxChain->bd_chain.bd_left >= BNXE_MAX_DMA_FRAGS_PER_PKT))
273         {
274             atomic_and_32(&pTxQ->noTxCredits, ~BNXE_TX_RESOURCES_NO_CREDIT);
275         }
276     }
277 
278     if ((pTxQ->noTxCredits & BNXE_TX_RESOURCES_NO_DESC) &&
279         (s_list_entry_cnt(&pTxQ->freeTxDescQ) > pTxQ->thresh_pdwm))
280     {
281         atomic_and_32(&pTxQ->noTxCredits, ~BNXE_TX_RESOURCES_NO_DESC);
282     }
283 
284     if (pTxQ->noTxCredits == 0)
285     {
286         if (idx == FCOE_CID(pLM))
287         {
288             BnxeLogInfo(pUM, "FCoE tx credit ok, no upcall!");
289         }
290         else
291         {
292             /* notify the stack that tx resources are now available */
293 #if defined(BNXE_RINGS) && (defined(__S11) || defined(__S12))
294             mac_tx_ring_update(pUM->pMac, pTxQ->ringHandle);
295 #else
296             mac_tx_update(pUM->pMac);
297 #endif
298         }
299     }
300 }
301 
302 
303 static inline int BnxeTxPktMapFrag(um_device_t *   pUM,
304                                    um_txpacket_t * pTxPkt,
305                                    mblk_t *        pMblk)
306 {
307     ddi_dma_handle_t dmaHandle;
308     ddi_dma_cookie_t cookie;
309     lm_frag_t *      pFrag;
310     boolean_t        partial;
311     u32_t            bindLen;
312     u32_t            count;
313     int rc, i;
314 
315     if (pTxPkt->num_handles == BNXE_MAX_DMA_HANDLES_PER_PKT)
316     {
317         return BNXE_TX_RESOURCES_NO_OS_DMA_RES;
318     }
319 
320     if (pTxPkt->frag_list.cnt >= BNXE_MAX_DMA_FRAGS_PER_PKT)
321     {
322         return BNXE_TX_RESOURCES_TOO_MANY_FRAGS;
323     }
324 
325     dmaHandle = pTxPkt->dmaHandles[pTxPkt->num_handles];
326 
327     if ((rc = ddi_dma_addr_bind_handle(dmaHandle,
328                                        NULL,
329                                        (caddr_t)pMblk->b_rptr,
330                                        (pMblk->b_wptr - pMblk->b_rptr),
331                                        (DDI_DMA_WRITE | DDI_DMA_STREAMING),
332                                        DDI_DMA_DONTWAIT,
333                                        NULL,
334                                        &cookie,
335                                        &count)) != DDI_DMA_MAPPED)
336     {
337         BnxeLogWarn(pUM, "Failed to bind DMA address for tx packet (%d)", rc);
338         return BNXE_TX_RESOURCES_NO_OS_DMA_RES;
339     }
340 
341     /*
342      * ddi_dma_addr_bind_handle() correctly returns an error if the physical
343      * fragment count exceeds the maximum fragment count specified in the
344      * ddi_dma_attrib structure for the current pMblk.  However, a packet can
345      * span multiple mblk's.  The purpose of the check below is to make sure we
346      * do not overflow our fragment count limit based on what has already been
347      * mapped from this packet.
348      */
349     partial = ((pTxPkt->frag_list.cnt + count) >
350                (pMblk->b_cont ? BNXE_MAX_DMA_FRAGS_PER_PKT - 1
351                               : BNXE_MAX_DMA_FRAGS_PER_PKT));
352     if (partial)
353     {
354         /*
355          * Going to try a partial dma so (re)set count to the remaining number
356          * of dma fragments that are available leaving one fragment at the end.
357          */
358         count = (BNXE_MAX_DMA_FRAGS_PER_PKT - 1 - pTxPkt->frag_list.cnt);
359         if (count == 0)
360         {
361             /*
362              * No more dma fragments are available.  This fragment was not
363              * mapped and will be copied into the copy buffer along with the
364              * rest of the packet data.
365              */
366             ddi_dma_unbind_handle(dmaHandle);
367             return BNXE_TX_RESOURCES_TOO_MANY_FRAGS;
368         }
369     }
370 
371     pFrag = &pTxPkt->frag_list.frag_arr[pTxPkt->frag_list.cnt];
372     pTxPkt->frag_list.cnt += count;
373 
374     /* map "count" dma fragments */
375 
376     bindLen = 0;
377     for (i = 0; i < (count - 1); i++)
378     {
379         pFrag->addr.as_u64 = cookie.dmac_laddress;
380         bindLen += pFrag->size = cookie.dmac_size;
381 
382         pFrag++;
383 
384         ddi_dma_nextcookie(dmaHandle, &cookie);
385     }
386 
387     pFrag->addr.as_u64 = cookie.dmac_laddress;
388     bindLen += pFrag->size = cookie.dmac_size;
389 
390     pTxPkt->num_handles++;
391 
392     if (partial)
393     {
394         /*
395          * Move the mblk's read pointer past the data that was bound to a DMA
396          * fragment.  Any remaining data will get copied into the copy buffer.
397          */
398         pMblk->b_rptr += bindLen;
399         return BNXE_TX_RESOURCES_TOO_MANY_FRAGS;
400     }
401 
402     return 0;
403 }
404 
405 
406 static int BnxeTxPktCopy(um_device_t *   pUM,
407                          TxQueue *       pTxQ,
408                          um_txpacket_t * pTxPkt)
409 {
410     lm_frag_t * pCopyFrag = NULL;
411     size_t      msgSize;
412     size_t      copySize = 0;
413     size_t      pktLen = 0;
414     boolean_t   tryMap = B_TRUE;
415     mblk_t *    pMblk;
416     caddr_t     pTmp;
417     int rc;
418 
419     /* Walk the chain to get the total pkt length... */
420     for (pMblk = pTxPkt->pMblk; pMblk; pMblk = pMblk->b_cont)
421     {
422         pktLen += MBLKL(pMblk);
423     }
424 
425     /*
426      * If the packet length is under the tx copy threshold then copy
427      * the all data into the copy buffer.
428      */
429     if (pktLen < pUM->devParams.txCopyThreshold)
430     {
431         ASSERT(pktLen <= pTxPkt->cbLength);
432 
433         pTmp = pTxPkt->pCbBuf;
434 
435         for (pMblk = pTxPkt->pMblk; pMblk; pMblk = pMblk->b_cont)
436         {
437             if ((msgSize = MBLKL(pMblk)) == 0)
438             {
439                 continue;
440             }
441 
442             bcopy(pMblk->b_rptr, pTmp, msgSize);
443             pTmp += msgSize;
444         }
445 
446         pCopyFrag              = &pTxPkt->frag_list.frag_arr[0];
447         pCopyFrag->addr.as_u64 = pTxPkt->cbPhysAddr.as_u64;
448         pCopyFrag->size        = pktLen;
449         pTxPkt->frag_list.cnt++;
450 
451         copySize = pktLen;
452         pTxQ->txCopied++;
453 
454         /* Done! */
455         goto _BnxeTxPktCopy_DMA_SYNC_COPY_BUFFER;
456     }
457 
458     /* Try to DMA map all the blocks... */
459 
460     for (pMblk = pTxPkt->pMblk; pMblk; pMblk = pMblk->b_cont)
461     {
462         if ((msgSize = MBLKL(pMblk)) == 0)
463         {
464             continue;
465         }
466 
467         if (tryMap)
468         {
469             if (BnxeTxPktMapFrag(pUM, pTxPkt, pMblk) == 0)
470             {
471                 /*
472                  * The fragment was successfully mapped now move on to the
473                  * next one.  Here we set pCopyFrag to NULL which represents
474                  * a break of continuous data in the copy buffer.  If the
475                  * packet header was copied the first fragment points to the
476                  * beginning of the copy buffer.  Since this block was mapped
477                  * any future blocks that have to be copied must be handled by
478                  * a new fragment even though the fragment is pointed to the
479                  * copied data in the copy buffer.
480                  */
481                 pCopyFrag = NULL;
482                 continue;
483             }
484             else
485             {
486                 /*
487                  * The frament was not mapped or was partially mapped.  In
488                  * either case we will no longer try to map the remaining
489                  * blocks.  All remaining packet data is copied.
490                  */
491                 tryMap = B_FALSE;
492                 msgSize = MBLKL(pMblk); /* new msgSize with partial binding */
493             }
494         }
495 
496 #if 0
497         if ((copySize + msgSize) > pTxPkt->cbLength)
498         {
499             /* remaining packet is too large (length more than copy buffer) */
500             BnxeTxPktUnmap(pTxPkt);
501             return -1;
502         }
503 #else
504         ASSERT((copySize + msgSize) <= pTxPkt->cbLength);
505 #endif
506 
507         bcopy(pMblk->b_rptr, (pTxPkt->pCbBuf + copySize), msgSize);
508 
509         /*
510          * If pCopyFrag is already specified then simply update the copy size.
511          * If not then set pCopyFrag to the next available fragment.
512          */
513         if (pCopyFrag)
514         {
515             pCopyFrag->size += msgSize;
516         }
517         else
518         {
519             ASSERT((pTxPkt->frag_list.cnt + 1) <= BNXE_MAX_DMA_FRAGS_PER_PKT);
520             pCopyFrag              = &pTxPkt->frag_list.frag_arr[pTxPkt->frag_list.cnt++];
521             pCopyFrag->size        = msgSize;
522             pCopyFrag->addr.as_u64 = pTxPkt->cbPhysAddr.as_u64 + copySize;
523         }
524 
525         /* update count of bytes in the copy buffer needed for DMA sync */
526         copySize += msgSize;
527     }
528 
529 _BnxeTxPktCopy_DMA_SYNC_COPY_BUFFER:
530 
531     if (copySize > 0)
532     {
533         /* DMA sync the copy buffer before sending */
534 
535         rc = ddi_dma_sync(pTxPkt->cbDmaHandle, 0, copySize,
536                           DDI_DMA_SYNC_FORDEV);
537 
538         if (pUM->fmCapabilities &&
539             BnxeCheckDmaHandle(pTxPkt->cbDmaHandle) != DDI_FM_OK)
540         {
541             ddi_fm_service_impact(pUM->pDev, DDI_SERVICE_DEGRADED);
542         }
543 
544         if (rc != DDI_SUCCESS)
545         {
546             BnxeLogWarn(pUM, "(%d) Failed to dma sync tx copy (%p / %d)",
547                         rc, pTxPkt, copySize);
548         }
549     }
550 
551     if (pTxPkt->num_handles == 0)
552     {
553         freemsg(pTxPkt->pMblk);
554         pTxPkt->pMblk = NULL;
555     }
556 
557     return 0;
558 }
559 
560 
561 /* this code is derived from that shown in RFC 1071 Section 4.1 */
562 static inline u16_t BnxeCalcCksum(void * start,
563                                   u32_t  len,
564                                   u16_t  prev_sum)
565 {
566     u16_t * pword;
567     u32_t   sum = 0;
568 
569     pword = (u16_t *)start;
570 
571     for ( ; len > 1; len -= 2, pword++)
572     {
573         /* the inner loop */
574         sum += *pword;
575     }
576 
577     /* add left-over byte, if any */
578     if (len)
579     {
580         sum += (u16_t)(*((u8_t *)pword));
581     }
582 
583     sum += prev_sum;
584 
585     /* fold 32-bit sum to 16 bits */
586     while (sum >> 16)
587     {
588         sum = ((sum & 0xffff) + (sum >> 16));
589     }
590 
591     return (u16_t)sum;
592 }
593 
594 
595 /*
596  * Everest1 (i.e. 57710, 57711, 57711E) does not natively support UDP checksums
597  * and does not know anything about the UDP header and where the checksum field
598  * is located.  It only knows about TCP.  Therefore we "lie" to the hardware for
599  * outgoing UDP packets w/ checksum offload.  Since the checksum field offset
600  * for TCP is 16 bytes and for UDP it is 6 bytes we pass a pointer to the
601  * hardware that is 10 bytes less than the start of the UDP header.  This allows
602  * the hardware to write the checksum in the correct spot.  But the hardware
603  * will compute a checksum which includes the last 10 bytes of the IP header.
604  * To correct this we tweak the stack computed pseudo checksum by folding in the
605  * calculation of the inverse checksum for those final 10 bytes of the IP
606  * header.  This allows the correct checksum to be computed by the hardware.
607  */
608 
609 #define TCP_CS_OFFSET           16
610 #define UDP_CS_OFFSET           6
611 #define UDP_TCP_CS_OFFSET_DIFF  (TCP_CS_OFFSET - UDP_CS_OFFSET)
612 
613 static inline u16_t BnxeUdpPseudoCsum(um_device_t * pUM,
614                                       u8_t *        pUdpHdr,
615                                       u8_t *        pIpHdr,
616                                       u8_t          ipHdrLen)
617 {
618     u32_t sum32;
619     u16_t sum16;
620     u16_t pseudo_cs;
621 
622     ASSERT(ipHdrLen >= UDP_TCP_CS_OFFSET_DIFF);
623 
624     /* calc cksum on last UDP_TCP_CS_OFFSET_DIFF bytes of ip header */
625     sum16 = BnxeCalcCksum(&pIpHdr[ipHdrLen - UDP_TCP_CS_OFFSET_DIFF],
626                           UDP_TCP_CS_OFFSET_DIFF, 0);
627 
628     /* substruct the calculated cksum from the udp pseudo cksum */
629     pseudo_cs = (*((u16_t *)&pUdpHdr[6]));
630     sum16     = ~sum16;
631     sum32     = (pseudo_cs + sum16);
632 
633     /* fold 32-bit sum to 16 bits */
634     while (sum32 >> 16)
635     {
636         sum32 = ((sum32 & 0xffff) + (sum32 >> 16));
637     }
638 
639     return ntohs((u16_t)sum32);
640 }
641 
642 
643 static inline u16_t BnxeGetVlanTag(mblk_t * pMblk)
644 {
645     ASSERT(MBLKL(pMblk) >= sizeof(struct ether_vlan_header));
646     return GLD_VTAG_VID(ntohs(((struct ether_vlan_header *)pMblk->b_rptr)->ether_tci));
647 }
648 
649 
650 static inline int BnxeGetHdrInfo(um_device_t *   pUM,
651                                  um_txpacket_t * pTxPkt)
652 {
653     mblk_t *      pMblk;
654     size_t        msgSize;
655     uint32_t      csStart;
656     uint32_t      csStuff;
657     uint32_t      csFlags;
658     uint32_t      lso;
659     u8_t *        pL2Hdr;
660     uint32_t      l2HdrLen;
661     u8_t *        pL3Hdr;
662     u32_t         l3HdrLen;
663     u8_t *        pL4Hdr;
664     u32_t         l4HdrLen;
665 
666     pMblk = pTxPkt->pMblk;
667     msgSize = MBLKL(pMblk);
668 
669     /* At least the MAC header... */
670 #if 0
671     if (msgSize < sizeof(struct ether_header))
672     {
673         BnxeLogWarn(pUM, "Invalid initial segment size in packet!");
674         return -1;
675     }
676 #else
677     ASSERT(msgSize >= sizeof(struct ether_header));
678 #endif
679 
680     mac_hcksum_get(pMblk, &csStart, &csStuff, NULL, NULL, &csFlags);
681 
682     lso = DB_LSOFLAGS(pMblk) & HW_LSO;
683 
684     /* get the Ethernet header */
685     pL2Hdr = (u8_t *)pMblk->b_rptr;
686 
687     /* grab the destination mac addr */
688     memcpy(pTxPkt->tx_info.dst_mac_addr, pL2Hdr, 6);
689 
690     if (lso)
691     {
692         pTxPkt->tx_info.flags |= LM_TX_FLAG_TCP_LSO_FRAME;
693 
694         pTxPkt->tx_info.lso_mss = (u16_t)DB_LSOMSS(pMblk);
695     }
696     else if (!csFlags)
697     {
698         /* no offload requested, just check for VLAN */
699 
700         if (((struct ether_header *)pMblk->b_rptr)->ether_type ==
701             htons(ETHERTYPE_VLAN))
702         {
703             pTxPkt->tx_info.vlan_tag = BnxeGetVlanTag(pMblk);
704             pTxPkt->tx_info.flags |= LM_TX_FLAG_VLAN_TAG_EXISTS;
705         }
706 
707         return 0;
708     }
709 
710     if (((struct ether_header *)pL2Hdr)->ether_type == htons(ETHERTYPE_VLAN))
711     {
712         l2HdrLen = sizeof(struct ether_vlan_header);
713 
714         pTxPkt->tx_info.vlan_tag = BnxeGetVlanTag(pMblk);
715         pTxPkt->tx_info.flags |= LM_TX_FLAG_VLAN_TAG_EXISTS;
716     }
717     else
718     {
719         l2HdrLen = sizeof(struct ether_header);
720     }
721 
722     if (csFlags & HCK_IPV4_HDRCKSUM)
723     {
724         pTxPkt->tx_info.flags |= LM_TX_FLAG_COMPUTE_IP_CKSUM;
725     }
726 
727     if (csFlags & HCK_PARTIALCKSUM)
728     {
729         pTxPkt->tx_info.flags |= LM_TX_FLAG_COMPUTE_TCP_UDP_CKSUM;
730 
731         l3HdrLen = csStart;
732         l4HdrLen = (l2HdrLen + csStuff + sizeof(u16_t));
733 
734         /*
735          * For TCP, here we ignore the urgent pointer and size of the
736          * options.  We'll get that info later.
737          */
738     }
739     else if (lso)
740     {
741         /* Solaris doesn't do LSO if there is option in the IP header. */
742         l3HdrLen = sizeof(struct ip);
743         l4HdrLen = (l2HdrLen + l3HdrLen + sizeof(struct tcphdr));
744     }
745     else
746     {
747         return 0;
748     }
749 
750     if (msgSize >= l4HdrLen)
751     {
752         /* the header is in the first block */
753         pL3Hdr = (pL2Hdr + l2HdrLen);
754     }
755     else
756     {
757         if ((msgSize <= l2HdrLen) && pMblk->b_cont &&
758             ((msgSize + MBLKL(pMblk->b_cont)) >= l4HdrLen))
759         {
760             /* the header is in the second block */
761             pL3Hdr = pMblk->b_cont->b_rptr + (l2HdrLen - msgSize);
762         }
763         else
764         {
765             /* do a pullup to make sure headers are in the first block */
766             pUM->txMsgPullUp++;
767 
768             if ((pMblk = msgpullup(pMblk, l4HdrLen)) == NULL)
769             {
770                 return -1;
771             }
772 
773             freemsg(pTxPkt->pMblk);
774             pTxPkt->pMblk = pMblk;
775 
776             pL3Hdr = (pMblk->b_rptr + l2HdrLen);
777         }
778     }
779 
780     /* must be IPv4 or IPv6 */
781     ASSERT((pL3Hdr[0] & 0xf0) == 0x60 || (pL3Hdr[0] & 0xf0) == 0x40);
782 
783     if ((pL3Hdr[0] & 0xf0) == 0x60)
784     {
785         pTxPkt->tx_info.flags |= LM_TX_FLAG_IPV6_PACKET;
786     }
787 
788     if (lso || ((csStuff - csStart) == TCP_CS_OFFSET))
789     {
790         /* get the TCP header */
791         pL4Hdr   = (pL3Hdr + l3HdrLen);
792         l4HdrLen = ((pL4Hdr[12] & 0xf0) >> 2);
793 
794         pTxPkt->tx_info.cs_any_offset     = 0;
795         pTxPkt->tx_info.tcp_nonce_sum_bit = (pL4Hdr[12] & 0x1);
796         pTxPkt->tx_info.tcp_pseudo_csum   = ntohs(*((u16_t *)&pL4Hdr[TCP_CS_OFFSET]));
797 
798         if (lso)
799         {
800             pTxPkt->tx_info.lso_ipid         = ntohs(*((u16_t *)&pL3Hdr[4]));
801             pTxPkt->tx_info.lso_tcp_send_seq = ntohl(*((u32_t *)&pL4Hdr[4]));
802             pTxPkt->tx_info.lso_tcp_flags    = pL4Hdr[13];
803         }
804     }
805     else
806     {
807         ASSERT((csStuff - csStart) == UDP_CS_OFFSET);
808 
809         /* get the UDP header */
810         pL4Hdr = pL3Hdr + l3HdrLen;
811 
812         l4HdrLen = sizeof(struct udphdr);
813 
814         pTxPkt->tx_info.cs_any_offset     = UDP_TCP_CS_OFFSET_DIFF;
815         pTxPkt->tx_info.tcp_nonce_sum_bit = 0;
816         pTxPkt->tx_info.tcp_pseudo_csum   =
817             CHIP_IS_E1x(((lm_device_t *)pUM)) ?
818                 BnxeUdpPseudoCsum(pUM, pL4Hdr, pL3Hdr, l3HdrLen) :
819                 ntohs(*((u16_t *)&pL4Hdr[UDP_CS_OFFSET]));
820     }
821 
822     pTxPkt->tx_info.lso_ip_hdr_len  = l3HdrLen;
823     pTxPkt->tx_info.lso_tcp_hdr_len = l4HdrLen;
824 
825     return 0;
826 }
827 
828 
829 int BnxeTxSendMblk(um_device_t * pUM,
830                    int           idx,
831                    mblk_t *      pMblk,
832                    u32_t         flags,
833                    u16_t         vlan_tag)
834 {
835     lm_device_t *   pLM = &pUM->lm_dev;
836     TxQueue *       pTxQ = &pUM->txq[idx];
837     lm_tx_chain_t * pLmTxChain;
838     um_txpacket_t * pTxPkt;
839     s_list_t        tmpList;
840     u32_t           numPkts;
841     int rc;
842 
843     BNXE_LOCK_ENTER_FREETX(pUM, idx);
844 
845     pTxPkt = (um_txpacket_t *)s_list_pop_head(&pTxQ->freeTxDescQ);
846 
847     if (pTxQ->txLowWater > s_list_entry_cnt(&pTxQ->freeTxDescQ))
848     {
849         pTxQ->txLowWater = s_list_entry_cnt(&pTxQ->freeTxDescQ);
850     }
851 
852     BNXE_LOCK_EXIT_FREETX(pUM, idx);
853 
854     /* try to recycle if no more packet available */
855     if (pTxPkt == NULL)
856     {
857         pTxQ->txRecycle++;
858 
859         s_list_clear(&tmpList);
860 
861         BNXE_LOCK_ENTER_TX(pUM, idx);
862         numPkts = lm_get_packets_sent(pLM, idx, &tmpList);
863         BNXE_LOCK_EXIT_TX(pUM, idx);
864 
865         if (pUM->fmCapabilities &&
866             BnxeCheckAccHandle(pLM->vars.reg_handle[BAR_0]) != DDI_FM_OK)
867         {
868             ddi_fm_service_impact(pUM->pDev, DDI_SERVICE_DEGRADED);
869         }
870 
871         if (!numPkts)
872         {
873             atomic_or_32(&pTxQ->noTxCredits, BNXE_TX_RESOURCES_NO_DESC);
874             pTxQ->txBlocked++;
875             return BNXE_TX_HDWRFULL;
876         }
877 
878         /* steal the first packet from the list before reclaiming */
879 
880         pTxPkt = (um_txpacket_t *)s_list_pop_head(&tmpList);
881 
882         if (pTxPkt->num_handles)
883         {
884             BnxeTxPktUnmap(pTxPkt);
885         }
886 
887         if (pTxPkt->pMblk)
888         {
889             freemsg(pTxPkt->pMblk);
890             pTxPkt->pMblk = NULL;
891         }
892 
893         BnxeTxPktsReclaim(pUM, idx, &tmpList);
894     }
895 
896     pTxPkt->lm_pkt.link.next = NULL;
897 
898     pTxPkt->tx_info.flags    = 0;
899     pTxPkt->tx_info.vlan_tag = 0;
900     pTxPkt->frag_list.cnt    = 0;
901     pTxPkt->pMblk            = pMblk;
902 
903 #if 0
904     BnxeDumpPkt(pUM,
905                 (BNXE_FCOE(pUM) && (idx == FCOE_CID(&pUM->lm_dev))) ?
906                     "-> FCoE L2 TX ->" : "-> L2 TX ->",
907                 pMblk, B_TRUE);
908 #endif
909 
910     if (idx == FCOE_CID(pLM))
911     {
912         if (flags & PRV_TX_VLAN_TAG)
913         {
914             pTxPkt->tx_info.vlan_tag = vlan_tag;
915             pTxPkt->tx_info.flags |= LM_TX_FLAG_INSERT_VLAN_TAG;
916         }
917     }
918     else if (BnxeGetHdrInfo(pUM, pTxPkt))
919     {
920         goto BnxeTxSendMblk_fail;
921     }
922 
923     if (BnxeTxPktCopy(pUM, pTxQ, pTxPkt))
924     {
925         goto BnxeTxSendMblk_fail;
926     }
927 
928     /* Now try to send the packet... */
929 
930     pLmTxChain = &pLM->tx_info.chain[idx];
931 
932     BNXE_LOCK_ENTER_TX(pUM, idx);
933 
934     /* Try to reclaim sent packets if available BDs is lower than threshold */
935     if (pLmTxChain->bd_chain.bd_left < BNXE_MAX_DMA_FRAGS_PER_PKT + 2)
936     {
937         pTxQ->txRecycle++;
938 
939         s_list_clear(&tmpList);
940 
941         numPkts = lm_get_packets_sent(pLM, idx, &tmpList);
942 
943         if (pUM->fmCapabilities &&
944             BnxeCheckAccHandle(pLM->vars.reg_handle[BAR_0]) != DDI_FM_OK)
945         {
946             ddi_fm_service_impact(pUM->pDev, DDI_SERVICE_DEGRADED);
947         }
948 
949         if (numPkts)
950         {
951             BnxeTxPktsReclaim(pUM, idx, &tmpList);
952         }
953     }
954 
955     /*
956      * If there are no packets currently waiting to be sent and there are enough
957      * BDs available to satisfy this packet then send it now.
958      */
959     if (s_list_is_empty(&pTxQ->waitTxDescQ) &&
960         (pLmTxChain->bd_chain.bd_left >= pTxPkt->frag_list.cnt + 2))
961     {
962         rc = lm_send_packet(pLM, idx, &pTxPkt->lm_pkt, &pTxPkt->frag_list);
963 
964         if (pUM->fmCapabilities &&
965             BnxeCheckAccHandle(pLM->vars.reg_handle[BAR_0]) != DDI_FM_OK)
966         {
967             ddi_fm_service_impact(pUM->pDev, DDI_SERVICE_DEGRADED);
968         }
969 
970         if (pUM->fmCapabilities &&
971             BnxeCheckAccHandle(pLM->vars.reg_handle[BAR_1]) != DDI_FM_OK)
972         {
973             ddi_fm_service_impact(pUM->pDev, DDI_SERVICE_DEGRADED);
974         }
975 
976         if (rc == LM_STATUS_SUCCESS)
977         {
978             /* send completely successfully */
979             BNXE_LOCK_EXIT_TX(pUM, idx);
980             return BNXE_TX_GOODXMIT;
981         }
982 
983         /*
984          * Send failed (probably not enough BDs available)...
985          * Continue on with putting this packet on the wait queue.
986          */
987         pTxQ->txFailed++;
988     }
989 
990 #if 0
991     BnxeLogWarn(pUM, "WAIT TX DESCQ %lu %d %d",
992                 s_list_entry_cnt(&pTxQ->waitTxDescQ),
993                 pLmTxChain->bd_chain.bd_left, pTxPkt->frag_list.cnt);
994 #endif
995 
996     /*
997      * If we got here then there are other packets waiting to be sent or there
998      * aren't enough BDs available.  In either case put this packet at the end
999      * of the waiting queue.
1000      */
1001     s_list_push_tail(&pTxQ->waitTxDescQ, &pTxPkt->lm_pkt.link);
1002 
1003     pTxQ->txWait++;
1004 
1005     /*
1006      * If there appears to be a sufficient number of BDs available then make a
1007      * quick attempt to send as many waiting packets as possible.
1008      */
1009     if ((pLmTxChain->bd_chain.bd_left >= BNXE_MAX_DMA_FRAGS_PER_PKT) &&
1010         (BnxeTxSendWaitingPkt(pUM, idx) == BNXE_TX_GOODXMIT))
1011     {
1012         BNXE_LOCK_EXIT_TX(pUM, idx);
1013         return BNXE_TX_GOODXMIT;
1014     }
1015 
1016     /* Couldn't send anything! */
1017     atomic_or_32(&pTxQ->noTxCredits, BNXE_TX_RESOURCES_NO_CREDIT);
1018     pTxQ->txBlocked++;
1019 
1020     BNXE_LOCK_EXIT_TX(pUM, idx);
1021 
1022     return BNXE_TX_DEFERPKT;
1023 
1024 BnxeTxSendMblk_fail:
1025 
1026     pTxQ->txDiscards++;
1027 
1028     ASSERT(pTxPkt != NULL);
1029 
1030     if (pTxPkt->pMblk)
1031     {
1032         freemsg(pTxPkt->pMblk);
1033         pTxPkt->pMblk = NULL;
1034     }
1035 
1036     BNXE_LOCK_ENTER_FREETX(pUM, idx);
1037     s_list_push_tail(&pTxQ->freeTxDescQ, &pTxPkt->lm_pkt.link);
1038     BNXE_LOCK_EXIT_FREETX(pUM, idx);
1039 
1040     /*
1041      * Yes GOODXMIT since mblk was free'd here and this triggers caller to
1042      * try and send the next packet in its chain.
1043      */
1044     return BNXE_TX_GOODXMIT;
1045 }
1046 
1047 
1048 static void BnxeTxPktsAbortIdx(um_device_t * pUM,
1049                                int           idx)
1050 {
1051     s_list_t tmpList;
1052 
1053     BNXE_LOCK_ENTER_TX(pUM, idx);
1054     lm_abort(&pUM->lm_dev, ABORT_OP_INDICATE_TX_CHAIN, idx);
1055     tmpList = pUM->txq[idx].waitTxDescQ;
1056     s_list_clear(&pUM->txq[idx].waitTxDescQ);
1057     BNXE_LOCK_EXIT_TX(pUM, idx);
1058 
1059     BnxeTxPktsReclaim(pUM, idx, &tmpList);
1060 }
1061 
1062 
1063 void BnxeTxPktsAbort(um_device_t * pUM,
1064                      int           cliIdx)
1065 {
1066     int idx;
1067 
1068     switch (cliIdx)
1069     {
1070     case LM_CLI_IDX_FCOE:
1071 
1072         BnxeTxPktsAbortIdx(pUM, FCOE_CID(&pUM->lm_dev));
1073         break;
1074 
1075     case LM_CLI_IDX_NDIS:
1076 
1077         LM_FOREACH_TSS_IDX(&pUM->lm_dev, idx)
1078         {
1079             BnxeTxPktsAbortIdx(pUM, idx);
1080         }
1081 
1082         break;
1083 
1084     default:
1085 
1086         BnxeLogWarn(pUM, "ERROR: Invalid cliIdx for BnxeTxPktsAbort (%d)", cliIdx);
1087         break;
1088     }
1089 }
1090 
1091 
1092 static um_txpacket_t * BnxeTxPktAlloc(um_device_t * pUM,
1093                                       size_t        size)
1094 {
1095     um_txpacket_t *   pTxPkt;
1096     ddi_dma_cookie_t  cookie;
1097     u32_t             count;
1098     size_t            length;
1099     int rc, j;
1100 
1101     if ((pTxPkt = kmem_zalloc(sizeof(um_txpacket_t), KM_NOSLEEP)) == NULL)
1102     {
1103         return NULL;
1104     }
1105 
1106     pTxPkt->lm_pkt.l2pkt_tx_info = &pTxPkt->tx_info;
1107 
1108     if ((rc = ddi_dma_alloc_handle(pUM->pDev,
1109                                    &bnxeTxCbDmaAttrib,
1110                                    DDI_DMA_DONTWAIT,
1111                                    NULL,
1112                                    &pTxPkt->cbDmaHandle)) != DDI_SUCCESS)
1113     {
1114         BnxeLogWarn(pUM, "Failed to alloc DMA handle for Tx Desc (%d)", rc);
1115         kmem_free(pTxPkt, sizeof(um_txpacket_t));
1116         return NULL;
1117     }
1118 
1119     if ((rc = ddi_dma_mem_alloc(pTxPkt->cbDmaHandle,
1120                                 size,
1121                                 &bnxeAccessAttribBUF,
1122                                 DDI_DMA_STREAMING,
1123                                 DDI_DMA_DONTWAIT,
1124                                 NULL,
1125                                 &pTxPkt->pCbBuf,
1126                                 &length,
1127                                 &pTxPkt->cbDmaAccHandle)) != DDI_SUCCESS)
1128     {
1129         BnxeLogWarn(pUM, "Failed to alloc DMA memory for Tx Desc (%d)", rc);
1130         ddi_dma_free_handle(&pTxPkt->cbDmaHandle);
1131         kmem_free(pTxPkt, sizeof(um_txpacket_t));
1132         return NULL;
1133     }
1134 
1135     if ((rc = ddi_dma_addr_bind_handle(pTxPkt->cbDmaHandle,
1136                                        NULL,
1137                                        pTxPkt->pCbBuf,
1138                                        length,
1139                                        DDI_DMA_WRITE | DDI_DMA_STREAMING,
1140                                        DDI_DMA_DONTWAIT,
1141                                        NULL,
1142                                        &cookie,
1143                                        &count)) != DDI_DMA_MAPPED)
1144     {
1145         BnxeLogWarn(pUM, "Failed to bind DMA address for Tx Desc (%d)", rc);
1146         ddi_dma_mem_free(&pTxPkt->cbDmaAccHandle);
1147         ddi_dma_free_handle(&pTxPkt->cbDmaHandle);
1148         kmem_free(pTxPkt, sizeof(um_txpacket_t));
1149         return NULL;
1150     }
1151 
1152     pTxPkt->cbPhysAddr.as_u64 = cookie.dmac_laddress;
1153 
1154     for (j = 0; j < BNXE_MAX_DMA_HANDLES_PER_PKT; j++)
1155     {
1156         if ((rc = ddi_dma_alloc_handle(pUM->pDev,
1157                                        &bnxeTxDmaAttrib,
1158                                        DDI_DMA_DONTWAIT,
1159                                        NULL,
1160                                        &pTxPkt->dmaHandles[j])) !=
1161             DDI_SUCCESS)
1162         {
1163             BnxeLogWarn(pUM, "Failed to alloc DMA handles for Tx Pkt %d (%d)",
1164                         j, rc);
1165 
1166             for(--j; j >= 0; j--) /* unwind */
1167             {
1168                 ddi_dma_free_handle(&pTxPkt->dmaHandles[j]);
1169             }
1170 
1171             ddi_dma_unbind_handle(pTxPkt->cbDmaHandle);
1172             ddi_dma_mem_free(&pTxPkt->cbDmaAccHandle);
1173             ddi_dma_free_handle(&pTxPkt->cbDmaHandle);
1174             kmem_free(pTxPkt, sizeof(um_txpacket_t));
1175             return NULL;
1176         }
1177     }
1178 
1179     ASSERT(pTxPkt->pMblk == NULL);
1180     ASSERT(pTxPkt->num_handles == 0);
1181     ASSERT(pTxPkt->frag_list.cnt == 0);
1182     pTxPkt->cbLength = size;
1183 
1184     return pTxPkt;
1185 }
1186 
1187 
1188 static int BnxeTxPktsInitIdx(um_device_t * pUM,
1189                              int           idx)
1190 {
1191     lm_device_t *   pLM = &pUM->lm_dev;
1192     TxQueue *       pTxQ;
1193     um_txpacket_t * pTxPkt;
1194     s_list_t        tmpList;
1195     int i;
1196 
1197     pTxQ = &pUM->txq[idx];
1198 
1199     s_list_clear(&pTxQ->sentTxQ);
1200     s_list_clear(&pTxQ->freeTxDescQ);
1201     s_list_clear(&pTxQ->waitTxDescQ);
1202 
1203     pTxQ->desc_cnt    = pUM->devParams.numTxDesc[LM_CHAIN_IDX_CLI(pLM, idx)];
1204     pTxQ->txLowWater  = pUM->devParams.numTxDesc[LM_CHAIN_IDX_CLI(pLM, idx)];
1205     pTxQ->thresh_pdwm = BNXE_PDWM_THRESHOLD;
1206     pTxQ->txFailed    = 0;
1207     pTxQ->txDiscards  = 0;
1208     pTxQ->txRecycle   = 0;
1209     pTxQ->txCopied    = 0;
1210     pTxQ->txBlocked   = 0;
1211     pTxQ->txWait      = 0;
1212 
1213     if (pUM->devParams.lsoEnable)
1214     {
1215         for (i = 0; i < pTxQ->desc_cnt; i++)
1216         {
1217             pTxPkt = BnxeTxPktAlloc(pUM,
1218                                     (BNXE_IP_MAXLEN +
1219                                      sizeof(struct ether_vlan_header)));
1220             if (pTxPkt == NULL)
1221             {
1222                 BnxeLogWarn(pUM, "Failed to allocate all Tx Descs for LSO (%d/%d allocated), LSO is disabled",
1223                             i, pTxQ->desc_cnt);
1224 
1225                 /* free existing in freeTxDescQ... */
1226 
1227                 BNXE_LOCK_ENTER_FREETX(pUM, idx);
1228                 tmpList = pTxQ->freeTxDescQ;
1229                 s_list_clear(&pTxQ->freeTxDescQ);
1230                 BNXE_LOCK_EXIT_FREETX(pUM, idx);
1231 
1232                 BnxeTxPktsFreeList(&tmpList);
1233 
1234                 pUM->devParams.lsoEnable = 0; /* Disabling LSO! */
1235 
1236                 break;
1237             }
1238 
1239             BNXE_LOCK_ENTER_FREETX(pUM, idx);
1240             s_list_push_tail(&pTxQ->freeTxDescQ, &pTxPkt->lm_pkt.link);
1241             BNXE_LOCK_EXIT_FREETX(pUM, idx);
1242         }
1243     }
1244 
1245     if (!pUM->devParams.lsoEnable)
1246     {
1247         for (i = 0; i < pTxQ->desc_cnt; i++)
1248         {
1249             pTxPkt = BnxeTxPktAlloc(pUM,
1250                                     (pUM->devParams.mtu[LM_CHAIN_IDX_CLI(pLM, idx)] +
1251                                      sizeof(struct ether_vlan_header)));
1252             if (pTxPkt == NULL)
1253             {
1254                 BnxeLogWarn(pUM, "Failed to allocate all Tx Descs (%d/%d allocated)",
1255                             i, pTxQ->desc_cnt);
1256 
1257                 /* free existing in freeTxDescQ... */
1258 
1259                 BNXE_LOCK_ENTER_FREETX(pUM, idx);
1260                 tmpList = pTxQ->freeTxDescQ;
1261                 s_list_clear(&pTxQ->freeTxDescQ);
1262                 BNXE_LOCK_EXIT_FREETX(pUM, idx);
1263 
1264                 BnxeTxPktsFreeList(&tmpList);
1265 
1266                 return -1;
1267             }
1268 
1269             BNXE_LOCK_ENTER_FREETX(pUM, idx);
1270             s_list_push_tail(&pTxQ->freeTxDescQ, &pTxPkt->lm_pkt.link);
1271             BNXE_LOCK_EXIT_FREETX(pUM, idx);
1272         }
1273     }
1274 
1275     return 0;
1276 }
1277 
1278 
1279 int BnxeTxPktsInit(um_device_t * pUM,
1280                    int           cliIdx)
1281 {
1282     int idx, rc;
1283 
1284     switch (cliIdx)
1285     {
1286     case LM_CLI_IDX_FCOE:
1287 
1288         rc = BnxeTxPktsInitIdx(pUM, FCOE_CID(&pUM->lm_dev));
1289         break;
1290 
1291     case LM_CLI_IDX_NDIS:
1292 
1293         LM_FOREACH_TSS_IDX(&pUM->lm_dev, idx)
1294         {
1295             if ((rc = BnxeTxPktsInitIdx(pUM, idx)) < 0)
1296             {
1297                 break;
1298             }
1299         }
1300 
1301         break;
1302 
1303     default:
1304 
1305         BnxeLogWarn(pUM, "ERROR: Invalid cliIdx for BnxeTxPktsFini (%d)", cliIdx);
1306         rc = -1;
1307         break;
1308     }
1309 
1310     return rc;
1311 }
1312 
1313 
1314 static void BnxeTxPktsFiniIdx(um_device_t * pUM,
1315                               int           idx)
1316 {
1317     lm_device_t * pLM = &pUM->lm_dev;
1318     TxQueue *     pTxQ;
1319     s_list_t      tmpList;
1320 
1321     pTxQ = &pUM->txq[idx];
1322 
1323     BNXE_LOCK_ENTER_FREETX(pUM, idx);
1324     tmpList = pTxQ->freeTxDescQ;
1325     s_list_clear(&pTxQ->freeTxDescQ);
1326     BNXE_LOCK_EXIT_FREETX(pUM, idx);
1327 
1328     BNXE_LOCK_ENTER_TX(pUM, idx);
1329     s_list_add_tail(&tmpList, &pTxQ->sentTxQ);
1330     s_list_clear(&pTxQ->sentTxQ);
1331     BNXE_LOCK_EXIT_TX(pUM, idx);
1332 
1333     /* there could be more than originally allocated but less is bad */
1334     if (s_list_entry_cnt(&tmpList) <
1335         pUM->devParams.numTxDesc[LM_CHAIN_IDX_CLI(pLM, idx)])
1336     {
1337         BnxeLogWarn(pUM, "Missing TX descriptors (%lu / %d) (TxFail: %d)",
1338                     s_list_entry_cnt(&tmpList), pUM->devParams.numTxDesc,
1339                     pTxQ->txFailed);
1340     }
1341 
1342     BnxeTxPktsFreeList(&tmpList);
1343 }
1344 
1345 
1346 void BnxeTxPktsFini(um_device_t * pUM,
1347                     int           cliIdx)
1348 {
1349     int idx;
1350 
1351     switch (cliIdx)
1352     {
1353     case LM_CLI_IDX_FCOE:
1354 
1355         BnxeTxPktsFiniIdx(pUM, FCOE_CID(&pUM->lm_dev));
1356         break;
1357 
1358     case LM_CLI_IDX_NDIS:
1359 
1360         LM_FOREACH_TSS_IDX(&pUM->lm_dev, idx)
1361         {
1362             BnxeTxPktsFiniIdx(pUM, idx);
1363         }
1364 
1365         break;
1366 
1367     default:
1368 
1369         BnxeLogWarn(pUM, "ERROR: Invalid cliIdx for BnxeTxPktsFini (%d)", cliIdx);
1370         break;
1371     }
1372 }
1373 
1374