1*eef4f27bSRobert Mustacchi /*
2*eef4f27bSRobert Mustacchi  * Copyright 2014-2017 Cavium, Inc.
3*eef4f27bSRobert Mustacchi  * The contents of this file are subject to the terms of the Common Development
4*eef4f27bSRobert Mustacchi  * and Distribution License, v.1,  (the "License").
5*eef4f27bSRobert Mustacchi  *
6*eef4f27bSRobert Mustacchi  * You may not use this file except in compliance with the License.
7*eef4f27bSRobert Mustacchi  *
8*eef4f27bSRobert Mustacchi  * You can obtain a copy of the License at available
9*eef4f27bSRobert Mustacchi  * at http://opensource.org/licenses/CDDL-1.0
10*eef4f27bSRobert Mustacchi  *
11*eef4f27bSRobert Mustacchi  * See the License for the specific language governing permissions and
12*eef4f27bSRobert Mustacchi  * limitations under the License.
13*eef4f27bSRobert Mustacchi  */
14*eef4f27bSRobert Mustacchi 
15*eef4f27bSRobert Mustacchi #include "lm5706.h"
16*eef4f27bSRobert Mustacchi 
17*eef4f27bSRobert Mustacchi 
18*eef4f27bSRobert Mustacchi #ifndef LM_NON_LEGACY_MODE_SUPPORT
19*eef4f27bSRobert Mustacchi /*******************************************************************************
20*eef4f27bSRobert Mustacchi  * Description:
21*eef4f27bSRobert Mustacchi  *
22*eef4f27bSRobert Mustacchi  * Return:
23*eef4f27bSRobert Mustacchi  ******************************************************************************/
24*eef4f27bSRobert Mustacchi lm_status_t
lm_send_packet(lm_device_t * pdev,u32_t chain_idx,lm_packet_t * packet,lm_frag_list_t * frags)25*eef4f27bSRobert Mustacchi lm_send_packet(
26*eef4f27bSRobert Mustacchi     lm_device_t *pdev,
27*eef4f27bSRobert Mustacchi     u32_t chain_idx,
28*eef4f27bSRobert Mustacchi     lm_packet_t *packet,
29*eef4f27bSRobert Mustacchi     lm_frag_list_t *frags)
30*eef4f27bSRobert Mustacchi {
31*eef4f27bSRobert Mustacchi     u16_t lso_bd_reserved;
32*eef4f27bSRobert Mustacchi     u16_t ipv6_ext_len;
33*eef4f27bSRobert Mustacchi     lm_tx_chain_t *txq;
34*eef4f27bSRobert Mustacchi     tx_bd_t *start_bd;
35*eef4f27bSRobert Mustacchi     tx_bd_t *last_bd;
36*eef4f27bSRobert Mustacchi     tx_bd_t *prod_bd;
37*eef4f27bSRobert Mustacchi     lm_frag_t *frag;
38*eef4f27bSRobert Mustacchi     u16_t prod_idx;
39*eef4f27bSRobert Mustacchi     u32_t flags;
40*eef4f27bSRobert Mustacchi     u32_t cnt;
41*eef4f27bSRobert Mustacchi 
42*eef4f27bSRobert Mustacchi     txq = &pdev->tx_info.chain[chain_idx];
43*eef4f27bSRobert Mustacchi 
44*eef4f27bSRobert Mustacchi     if(packet == NULL)
45*eef4f27bSRobert Mustacchi     {
46*eef4f27bSRobert Mustacchi         // hardcode offset in case of L2_ONLY (e.g Solaris)
47*eef4f27bSRobert Mustacchi         u32_t cmd_offset = 34*sizeof(u32_t); //  == OFFSETOF(l4_context_t, l4ctx_cmd)
48*eef4f27bSRobert Mustacchi         MBQ_WR16(
49*eef4f27bSRobert Mustacchi             pdev,
50*eef4f27bSRobert Mustacchi             GET_CID(txq->cid_addr),
51*eef4f27bSRobert Mustacchi             cmd_offset +
52*eef4f27bSRobert Mustacchi                 OFFSETOF(tcp_context_cmd_cell_te_t, ccell_tx_host_bidx),
53*eef4f27bSRobert Mustacchi             txq->prod_idx);
54*eef4f27bSRobert Mustacchi         MBQ_WR32(
55*eef4f27bSRobert Mustacchi             pdev,
56*eef4f27bSRobert Mustacchi             GET_CID(txq->cid_addr),
57*eef4f27bSRobert Mustacchi             cmd_offset +
58*eef4f27bSRobert Mustacchi                 OFFSETOF(tcp_context_cmd_cell_te_t, ccell_tx_host_bseq),
59*eef4f27bSRobert Mustacchi             txq->prod_bseq);
60*eef4f27bSRobert Mustacchi 
61*eef4f27bSRobert Mustacchi         return LM_STATUS_SUCCESS;
62*eef4f27bSRobert Mustacchi     }
63*eef4f27bSRobert Mustacchi 
64*eef4f27bSRobert Mustacchi     #if DBG
65*eef4f27bSRobert Mustacchi     if(frags->cnt == 0)
66*eef4f27bSRobert Mustacchi     {
67*eef4f27bSRobert Mustacchi         DbgBreakMsg("zero frag_cnt\n");
68*eef4f27bSRobert Mustacchi 
69*eef4f27bSRobert Mustacchi         return LM_STATUS_INVALID_PARAMETER;
70*eef4f27bSRobert Mustacchi     }
71*eef4f27bSRobert Mustacchi 
72*eef4f27bSRobert Mustacchi     packet->u1.tx.dbg_start_bd = txq->prod_bd;
73*eef4f27bSRobert Mustacchi     packet->u1.tx.dbg_start_bd_idx = txq->prod_idx;
74*eef4f27bSRobert Mustacchi     packet->u1.tx.dbg_frag_cnt = (u16_t) frags->cnt;
75*eef4f27bSRobert Mustacchi     #endif
76*eef4f27bSRobert Mustacchi 
77*eef4f27bSRobert Mustacchi     last_bd = NULL;
78*eef4f27bSRobert Mustacchi 
79*eef4f27bSRobert Mustacchi     if(frags->cnt > txq->bd_left)
80*eef4f27bSRobert Mustacchi     {
81*eef4f27bSRobert Mustacchi         /* The caller should have done this check before calling this
82*eef4f27bSRobert Mustacchi          * routine. */
83*eef4f27bSRobert Mustacchi         DbgBreakMsg("No tx bd left.\n");
84*eef4f27bSRobert Mustacchi 
85*eef4f27bSRobert Mustacchi         return LM_STATUS_RESOURCE;
86*eef4f27bSRobert Mustacchi     }
87*eef4f27bSRobert Mustacchi 
88*eef4f27bSRobert Mustacchi     txq->bd_left -= (u16_t) frags->cnt;
89*eef4f27bSRobert Mustacchi 
90*eef4f27bSRobert Mustacchi     packet->size = 0;
91*eef4f27bSRobert Mustacchi     flags = 0;
92*eef4f27bSRobert Mustacchi 
93*eef4f27bSRobert Mustacchi     if(packet->u1.tx.flags & LM_TX_FLAG_INSERT_VLAN_TAG)
94*eef4f27bSRobert Mustacchi     {
95*eef4f27bSRobert Mustacchi         flags |= TX_BD_FLAGS_VLAN_TAG;
96*eef4f27bSRobert Mustacchi     }
97*eef4f27bSRobert Mustacchi 
98*eef4f27bSRobert Mustacchi     if((packet->u1.tx.flags & LM_TX_FLAG_TCP_LSO_FRAME) == 0)
99*eef4f27bSRobert Mustacchi     {
100*eef4f27bSRobert Mustacchi         if(packet->u1.tx.flags & LM_TX_FLAG_COMPUTE_IP_CKSUM)
101*eef4f27bSRobert Mustacchi         {
102*eef4f27bSRobert Mustacchi             flags |= TX_BD_FLAGS_IP_CKSUM;
103*eef4f27bSRobert Mustacchi             LM_INC64(&pdev->tx_info.stats.ip_cso_frames, 1);
104*eef4f27bSRobert Mustacchi         }
105*eef4f27bSRobert Mustacchi 
106*eef4f27bSRobert Mustacchi         if(packet->u1.tx.flags & LM_TX_FLAG_COMPUTE_TCP_UDP_CKSUM)
107*eef4f27bSRobert Mustacchi         {
108*eef4f27bSRobert Mustacchi             flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
109*eef4f27bSRobert Mustacchi             if(packet->u1.tx.flags & LM_TX_FLAG_IPV6_PACKET)
110*eef4f27bSRobert Mustacchi             {
111*eef4f27bSRobert Mustacchi                 LM_INC64(&pdev->tx_info.stats.ipv6_tcp_udp_cso_frames, 1);
112*eef4f27bSRobert Mustacchi             }
113*eef4f27bSRobert Mustacchi             else
114*eef4f27bSRobert Mustacchi             {
115*eef4f27bSRobert Mustacchi                 LM_INC64(&pdev->tx_info.stats.ipv4_tcp_udp_cso_frames, 1);
116*eef4f27bSRobert Mustacchi             }
117*eef4f27bSRobert Mustacchi         }
118*eef4f27bSRobert Mustacchi     }
119*eef4f27bSRobert Mustacchi 
120*eef4f27bSRobert Mustacchi     if(packet->u1.tx.flags & LM_TX_FLAG_DONT_COMPUTE_CRC)
121*eef4f27bSRobert Mustacchi     {
122*eef4f27bSRobert Mustacchi         flags |= TX_BD_FLAGS_DONT_GEN_CRC;
123*eef4f27bSRobert Mustacchi     }
124*eef4f27bSRobert Mustacchi 
125*eef4f27bSRobert Mustacchi     if(packet->u1.tx.flags & LM_TX_FLAG_TCP_LSO_FRAME)
126*eef4f27bSRobert Mustacchi     {
127*eef4f27bSRobert Mustacchi         if(packet->u1.tx.flags & LM_TX_FLAG_IPV6_PACKET)
128*eef4f27bSRobert Mustacchi         {
129*eef4f27bSRobert Mustacchi             /* TCP option length - bottom 4 bits of TX_BD_FLAGS_SW_OPTION_WORD
130*eef4f27bSRobert Mustacchi              *    in term of the number of 4-byte words.
131*eef4f27bSRobert Mustacchi              * IP header length - bits 1-2 of bd flag, the upper 2 bits of
132*eef4f27bSRobert Mustacchi              *    tx_bd_reserved, and the upper 1 bit of
133*eef4f27bSRobert Mustacchi              *    TX_BD_FLAGS_SW_OPTION_WORD will be used for IPV6 extension
134*eef4f27bSRobert Mustacchi              *    header length in term of 8-btye words.
135*eef4f27bSRobert Mustacchi              * TX_BD_FLAGS_SW_FLAGS bit will be used to indicate IPV6 LSO. */
136*eef4f27bSRobert Mustacchi             flags |= TX_BD_FLAGS_SW_FLAGS;
137*eef4f27bSRobert Mustacchi 
138*eef4f27bSRobert Mustacchi             if(packet->u1.tx.flags & LM_TX_FLAG_TCP_LSO_SNAP_FRAME)
139*eef4f27bSRobert Mustacchi             {
140*eef4f27bSRobert Mustacchi                 flags |= TX_BD_FLAGS_SW_SNAP;
141*eef4f27bSRobert Mustacchi             }
142*eef4f27bSRobert Mustacchi 
143*eef4f27bSRobert Mustacchi             DbgBreakIf(packet->u1.tx.lso_tcp_hdr_len < 20 ||
144*eef4f27bSRobert Mustacchi                        packet->u1.tx.lso_tcp_hdr_len > 84 ||
145*eef4f27bSRobert Mustacchi                        packet->u1.tx.lso_tcp_hdr_len % 4);
146*eef4f27bSRobert Mustacchi 
147*eef4f27bSRobert Mustacchi             /* tcp option length in term of number of 32-bit word.  4 bits
148*eef4f27bSRobert Mustacchi              * are used for the number of words. */
149*eef4f27bSRobert Mustacchi             flags |= (packet->u1.tx.lso_tcp_hdr_len - 20) << 6;
150*eef4f27bSRobert Mustacchi 
151*eef4f27bSRobert Mustacchi             DbgBreakIf(packet->u1.tx.lso_ip_hdr_len < 20 ||
152*eef4f27bSRobert Mustacchi                        packet->u1.tx.lso_ip_hdr_len > 296 ||
153*eef4f27bSRobert Mustacchi                       (packet->u1.tx.lso_ip_hdr_len - 40) % 8);
154*eef4f27bSRobert Mustacchi 
155*eef4f27bSRobert Mustacchi             /* ipv6 extension header length.  6 bits are used for the number
156*eef4f27bSRobert Mustacchi              * of 64-bit words. */
157*eef4f27bSRobert Mustacchi             ipv6_ext_len = packet->u1.tx.lso_ip_hdr_len - 40;
158*eef4f27bSRobert Mustacchi 
159*eef4f27bSRobert Mustacchi             DbgBreakIf(ipv6_ext_len & 0x7);
160*eef4f27bSRobert Mustacchi 
161*eef4f27bSRobert Mustacchi             /* ext_len in number of 8-byte words. */
162*eef4f27bSRobert Mustacchi             ipv6_ext_len >>= 3;
163*eef4f27bSRobert Mustacchi 
164*eef4f27bSRobert Mustacchi             flags |= (ipv6_ext_len & 0x3) << 1;             /* bit 1-0 */
165*eef4f27bSRobert Mustacchi 
166*eef4f27bSRobert Mustacchi             lso_bd_reserved = packet->u1.tx.lso_mss;
167*eef4f27bSRobert Mustacchi             lso_bd_reserved |= (ipv6_ext_len & 0xc) << 12;  /* bit 3-2 */
168*eef4f27bSRobert Mustacchi 
169*eef4f27bSRobert Mustacchi             flags |= (ipv6_ext_len & 0x10) << 8;            /* bit 4  */
170*eef4f27bSRobert Mustacchi 
171*eef4f27bSRobert Mustacchi             DbgBreakIf(ipv6_ext_len >> 5);  /* bit 5 & high are invalid. */
172*eef4f27bSRobert Mustacchi 
173*eef4f27bSRobert Mustacchi             LM_INC64(&pdev->tx_info.stats.ipv6_lso_frames, 1);
174*eef4f27bSRobert Mustacchi         }
175*eef4f27bSRobert Mustacchi         else
176*eef4f27bSRobert Mustacchi         {
177*eef4f27bSRobert Mustacchi             flags |= TX_BD_FLAGS_SW_LSO;
178*eef4f27bSRobert Mustacchi             if(packet->u1.tx.flags & LM_TX_FLAG_TCP_LSO_SNAP_FRAME)
179*eef4f27bSRobert Mustacchi             {
180*eef4f27bSRobert Mustacchi                 flags |= TX_BD_FLAGS_SW_SNAP;
181*eef4f27bSRobert Mustacchi             }
182*eef4f27bSRobert Mustacchi 
183*eef4f27bSRobert Mustacchi             DbgBreakIf(packet->u1.tx.lso_ip_hdr_len +
184*eef4f27bSRobert Mustacchi                 packet->u1.tx.lso_tcp_hdr_len > 120);
185*eef4f27bSRobert Mustacchi 
186*eef4f27bSRobert Mustacchi             /* The size of IP and TCP options in term of 32-bit words. */
187*eef4f27bSRobert Mustacchi             flags |= (packet->u1.tx.lso_ip_hdr_len +
188*eef4f27bSRobert Mustacchi                 packet->u1.tx.lso_tcp_hdr_len - 40) << 6;
189*eef4f27bSRobert Mustacchi 
190*eef4f27bSRobert Mustacchi             lso_bd_reserved = packet->u1.tx.lso_mss;
191*eef4f27bSRobert Mustacchi 
192*eef4f27bSRobert Mustacchi             LM_INC64(&pdev->tx_info.stats.ipv4_lso_frames, 1);
193*eef4f27bSRobert Mustacchi         }
194*eef4f27bSRobert Mustacchi     }
195*eef4f27bSRobert Mustacchi     else
196*eef4f27bSRobert Mustacchi     {
197*eef4f27bSRobert Mustacchi         lso_bd_reserved = 0;
198*eef4f27bSRobert Mustacchi     }
199*eef4f27bSRobert Mustacchi 
200*eef4f27bSRobert Mustacchi     start_bd = txq->prod_bd;
201*eef4f27bSRobert Mustacchi     frag = frags->frag_arr;
202*eef4f27bSRobert Mustacchi 
203*eef4f27bSRobert Mustacchi     /* Get the pointer to the current BD and its index. */
204*eef4f27bSRobert Mustacchi     prod_idx = txq->prod_idx;
205*eef4f27bSRobert Mustacchi     prod_bd = txq->prod_bd;
206*eef4f27bSRobert Mustacchi 
207*eef4f27bSRobert Mustacchi     /* This is the number of times we cross a BD page boundary for this
208*eef4f27bSRobert Mustacchi      * packet.  This and the bd_used value will give us the total number
209*eef4f27bSRobert Mustacchi      * of BD slots needed to send this packet which is used to determine
210*eef4f27bSRobert Mustacchi      * if a packet has been sent.  We only need this because unlike L2
211*eef4f27bSRobert Mustacchi      * completion, LSO completion does not end at a request boundary.
212*eef4f27bSRobert Mustacchi      * For example, if we had an LSO request that spans BD#100-120.  We
213*eef4f27bSRobert Mustacchi      * could get a transmit consumer index of 115. */
214*eef4f27bSRobert Mustacchi     packet->u1.tx.span_pages = 0;
215*eef4f27bSRobert Mustacchi 
216*eef4f27bSRobert Mustacchi     /* Initialize the bd's of this packet. */
217*eef4f27bSRobert Mustacchi     for(cnt = 0; cnt < frags->cnt; cnt++)
218*eef4f27bSRobert Mustacchi     {
219*eef4f27bSRobert Mustacchi         DbgBreakIf(frag->size >= 0x10000 || frag->size == 0);
220*eef4f27bSRobert Mustacchi 
221*eef4f27bSRobert Mustacchi         prod_bd->tx_bd_haddr_lo = frag->addr.as_u32.low;
222*eef4f27bSRobert Mustacchi         prod_bd->tx_bd_haddr_hi = frag->addr.as_u32.high;
223*eef4f27bSRobert Mustacchi         prod_bd->tx_bd_nbytes = (u16_t) frag->size;
224*eef4f27bSRobert Mustacchi         prod_bd->tx_bd_vlan_tag = packet->u1.tx.vlan_tag;
225*eef4f27bSRobert Mustacchi         prod_bd->tx_bd_flags = (u16_t) flags;
226*eef4f27bSRobert Mustacchi 
227*eef4f27bSRobert Mustacchi         if(packet->u1.tx.flags & LM_TX_FLAG_TCP_LSO_FRAME)
228*eef4f27bSRobert Mustacchi         {
229*eef4f27bSRobert Mustacchi             prod_bd->tx_bd_reserved = lso_bd_reserved;
230*eef4f27bSRobert Mustacchi         }
231*eef4f27bSRobert Mustacchi         else if(pdev->params.test_mode & TEST_MODE_TX_BD_TAGGING)
232*eef4f27bSRobert Mustacchi         {
233*eef4f27bSRobert Mustacchi             prod_bd->tx_bd_reserved = prod_idx & 0x0fff;
234*eef4f27bSRobert Mustacchi             prod_bd->tx_bd_reserved |= (u16_t) (GET_CID(txq->cid_addr) << 12);
235*eef4f27bSRobert Mustacchi         }
236*eef4f27bSRobert Mustacchi 
237*eef4f27bSRobert Mustacchi         packet->size += frag->size;
238*eef4f27bSRobert Mustacchi 
239*eef4f27bSRobert Mustacchi         last_bd = prod_bd;
240*eef4f27bSRobert Mustacchi         frag++;
241*eef4f27bSRobert Mustacchi 
242*eef4f27bSRobert Mustacchi         /* Advance to the next BD. */
243*eef4f27bSRobert Mustacchi         prod_bd++;
244*eef4f27bSRobert Mustacchi         prod_idx++;
245*eef4f27bSRobert Mustacchi         if((prod_idx & MAX_BD_PER_PAGE) == MAX_BD_PER_PAGE)
246*eef4f27bSRobert Mustacchi         {
247*eef4f27bSRobert Mustacchi             /* Only increment span_pages when this BDs for this request
248*eef4f27bSRobert Mustacchi              * cross a page boundary. */
249*eef4f27bSRobert Mustacchi             if(cnt+1 < frags->cnt)
250*eef4f27bSRobert Mustacchi             {
251*eef4f27bSRobert Mustacchi                 packet->u1.tx.span_pages++;
252*eef4f27bSRobert Mustacchi             }
253*eef4f27bSRobert Mustacchi 
254*eef4f27bSRobert Mustacchi             prod_idx++;
255*eef4f27bSRobert Mustacchi             prod_bd = *((tx_bd_t **) ((tx_bd_next_t *)
256*eef4f27bSRobert Mustacchi                 prod_bd)->tx_bd_next_reserved);
257*eef4f27bSRobert Mustacchi         }
258*eef4f27bSRobert Mustacchi     }
259*eef4f27bSRobert Mustacchi 
260*eef4f27bSRobert Mustacchi     /* Set the bd flags of the first and last BDs. */
261*eef4f27bSRobert Mustacchi     flags |= TX_BD_FLAGS_END;
262*eef4f27bSRobert Mustacchi     if(packet->u1.tx.flags & LM_TX_FLAG_COAL_NOW)
263*eef4f27bSRobert Mustacchi     {
264*eef4f27bSRobert Mustacchi         flags |= TX_BD_FLAGS_COAL_NOW;
265*eef4f27bSRobert Mustacchi     }
266*eef4f27bSRobert Mustacchi 
267*eef4f27bSRobert Mustacchi     last_bd->tx_bd_flags |= (u16_t) flags;
268*eef4f27bSRobert Mustacchi     start_bd->tx_bd_flags |= TX_BD_FLAGS_START;
269*eef4f27bSRobert Mustacchi 
270*eef4f27bSRobert Mustacchi     #if INCLUDE_OFLD_SUPPORT
271*eef4f27bSRobert Mustacchi     /* We need to do the padding for the catchup path. */
272*eef4f27bSRobert Mustacchi     if(chain_idx == pdev->tx_info.cu_idx &&
273*eef4f27bSRobert Mustacchi         packet->size < MIN_ETHERNET_PACKET_SIZE)
274*eef4f27bSRobert Mustacchi     {
275*eef4f27bSRobert Mustacchi         last_bd->tx_bd_nbytes +=
276*eef4f27bSRobert Mustacchi             (u16_t) (MIN_ETHERNET_PACKET_SIZE - packet->size);
277*eef4f27bSRobert Mustacchi         packet->size = MIN_ETHERNET_PACKET_SIZE;
278*eef4f27bSRobert Mustacchi     }
279*eef4f27bSRobert Mustacchi     #endif
280*eef4f27bSRobert Mustacchi 
281*eef4f27bSRobert Mustacchi     /* Save the number of BDs used.  Later we need to add this value back
282*eef4f27bSRobert Mustacchi      * to txq->bd_left when the packet is sent. */
283*eef4f27bSRobert Mustacchi     packet->u1.tx.bd_used = (u16_t) frags->cnt;
284*eef4f27bSRobert Mustacchi 
285*eef4f27bSRobert Mustacchi     packet->u1.tx.next_bd_idx = prod_idx;
286*eef4f27bSRobert Mustacchi 
287*eef4f27bSRobert Mustacchi     txq->prod_bd = prod_bd;
288*eef4f27bSRobert Mustacchi     txq->prod_idx = prod_idx;
289*eef4f27bSRobert Mustacchi     txq->prod_bseq += packet->size;
290*eef4f27bSRobert Mustacchi #if (DBG)
291*eef4f27bSRobert Mustacchi     if (chain_idx == pdev->tx_info.cu_idx)
292*eef4f27bSRobert Mustacchi     {
293*eef4f27bSRobert Mustacchi         DbgBreakIf(packet->size > pdev->params.mtu + 4);
294*eef4f27bSRobert Mustacchi     }
295*eef4f27bSRobert Mustacchi     else
296*eef4f27bSRobert Mustacchi     {
297*eef4f27bSRobert Mustacchi         DbgBreakIf(packet->size > pdev->params.mtu &&
298*eef4f27bSRobert Mustacchi             (flags & (TX_BD_FLAGS_SW_LSO | TX_BD_FLAGS_SW_FLAGS)) == 0);
299*eef4f27bSRobert Mustacchi     }
300*eef4f27bSRobert Mustacchi #endif
301*eef4f27bSRobert Mustacchi     s_list_push_tail(&txq->active_descq, &packet->link);
302*eef4f27bSRobert Mustacchi 
303*eef4f27bSRobert Mustacchi     if(!(packet->u1.tx.flags & LM_TX_FLAG_SKIP_MBQ_WRITE))
304*eef4f27bSRobert Mustacchi     {
305*eef4f27bSRobert Mustacchi         // hardcode offset in case of L2_ONLY (e.g Solaris)
306*eef4f27bSRobert Mustacchi         u32_t cmd_offset = 34*sizeof(u32_t); //  == OFFSETOF(l4_context_t, l4ctx_cmd)
307*eef4f27bSRobert Mustacchi         MBQ_WR16(
308*eef4f27bSRobert Mustacchi             pdev,
309*eef4f27bSRobert Mustacchi             GET_CID(txq->cid_addr),
310*eef4f27bSRobert Mustacchi             cmd_offset +
311*eef4f27bSRobert Mustacchi                 OFFSETOF(tcp_context_cmd_cell_te_t, ccell_tx_host_bidx),
312*eef4f27bSRobert Mustacchi             txq->prod_idx);
313*eef4f27bSRobert Mustacchi         MBQ_WR32(
314*eef4f27bSRobert Mustacchi             pdev,
315*eef4f27bSRobert Mustacchi             GET_CID(txq->cid_addr),
316*eef4f27bSRobert Mustacchi             cmd_offset +
317*eef4f27bSRobert Mustacchi                 OFFSETOF(tcp_context_cmd_cell_te_t, ccell_tx_host_bseq),
318*eef4f27bSRobert Mustacchi             txq->prod_bseq);
319*eef4f27bSRobert Mustacchi     }
320*eef4f27bSRobert Mustacchi 
321*eef4f27bSRobert Mustacchi     return LM_STATUS_SUCCESS;
322*eef4f27bSRobert Mustacchi } /* lm_send_packet */
323*eef4f27bSRobert Mustacchi #else
324*eef4f27bSRobert Mustacchi /*******************************************************************************
325*eef4f27bSRobert Mustacchi  * Description:
326*eef4f27bSRobert Mustacchi  *
327*eef4f27bSRobert Mustacchi  * Return:
328*eef4f27bSRobert Mustacchi  ******************************************************************************/
329*eef4f27bSRobert Mustacchi lm_status_t
lm_send_packet(lm_device_t * pdev,u32_t chain_idx,lm_packet_t * packet,lm_frag_list_t * frags)330*eef4f27bSRobert Mustacchi lm_send_packet(
331*eef4f27bSRobert Mustacchi     lm_device_t *pdev,
332*eef4f27bSRobert Mustacchi     u32_t chain_idx,
333*eef4f27bSRobert Mustacchi     lm_packet_t *packet,
334*eef4f27bSRobert Mustacchi     lm_frag_list_t *frags)
335*eef4f27bSRobert Mustacchi {
336*eef4f27bSRobert Mustacchi     u16_t lso_bd_reserved;
337*eef4f27bSRobert Mustacchi     u16_t ipv6_ext_len;
338*eef4f27bSRobert Mustacchi     lm_tx_chain_t *txq;
339*eef4f27bSRobert Mustacchi     tx_bd_t *start_bd;
340*eef4f27bSRobert Mustacchi     tx_bd_t *last_bd;
341*eef4f27bSRobert Mustacchi     tx_bd_t *prod_bd;
342*eef4f27bSRobert Mustacchi     lm_frag_t *frag;
343*eef4f27bSRobert Mustacchi     u16_t prod_idx;
344*eef4f27bSRobert Mustacchi     u32_t flags;
345*eef4f27bSRobert Mustacchi     u32_t cnt;
346*eef4f27bSRobert Mustacchi     lm_pkt_tx_info_t *pkt_info;
347*eef4f27bSRobert Mustacchi 
348*eef4f27bSRobert Mustacchi     txq = &pdev->tx_info.chain[chain_idx];
349*eef4f27bSRobert Mustacchi 
350*eef4f27bSRobert Mustacchi     if(packet == NULL)
351*eef4f27bSRobert Mustacchi     {
352*eef4f27bSRobert Mustacchi         // hardcode offset in case of L2_ONLY (e.g Solaris)
353*eef4f27bSRobert Mustacchi         u32_t cmd_offset = 34*sizeof(u32_t); //  == OFFSETOF(l4_context_t, l4ctx_cmd)
354*eef4f27bSRobert Mustacchi         MBQ_WR16(
355*eef4f27bSRobert Mustacchi             pdev,
356*eef4f27bSRobert Mustacchi             GET_CID(txq->cid_addr),
357*eef4f27bSRobert Mustacchi             cmd_offset +
358*eef4f27bSRobert Mustacchi                 OFFSETOF(tcp_context_cmd_cell_te_t, ccell_tx_host_bidx),
359*eef4f27bSRobert Mustacchi             txq->prod_idx);
360*eef4f27bSRobert Mustacchi         if(pdev->vars.enable_cu_rate_limiter &&
361*eef4f27bSRobert Mustacchi            txq->idx == TX_CHAIN_IDX1)
362*eef4f27bSRobert Mustacchi         {
363*eef4f27bSRobert Mustacchi             REG_WR_IND(
364*eef4f27bSRobert Mustacchi                 pdev,
365*eef4f27bSRobert Mustacchi                 OFFSETOF(reg_space_t, com.com_scratch[0])+COM_HSI_OFFSETOFF(com_cu_host_bseq),
366*eef4f27bSRobert Mustacchi                 txq->prod_bseq);
367*eef4f27bSRobert Mustacchi         }
368*eef4f27bSRobert Mustacchi         else
369*eef4f27bSRobert Mustacchi         {
370*eef4f27bSRobert Mustacchi         	MBQ_WR32(
371*eef4f27bSRobert Mustacchi             	pdev,
372*eef4f27bSRobert Mustacchi             	GET_CID(txq->cid_addr),
373*eef4f27bSRobert Mustacchi             	cmd_offset +
374*eef4f27bSRobert Mustacchi                 OFFSETOF(tcp_context_cmd_cell_te_t, ccell_tx_host_bseq),
375*eef4f27bSRobert Mustacchi             	txq->prod_bseq);
376*eef4f27bSRobert Mustacchi         }
377*eef4f27bSRobert Mustacchi 
378*eef4f27bSRobert Mustacchi         return LM_STATUS_SUCCESS;
379*eef4f27bSRobert Mustacchi     }
380*eef4f27bSRobert Mustacchi 
381*eef4f27bSRobert Mustacchi     #if DBG
382*eef4f27bSRobert Mustacchi     if(frags->cnt == 0)
383*eef4f27bSRobert Mustacchi     {
384*eef4f27bSRobert Mustacchi         DbgBreakMsg("zero frag_cnt\n");
385*eef4f27bSRobert Mustacchi 
386*eef4f27bSRobert Mustacchi         return LM_STATUS_INVALID_PARAMETER;
387*eef4f27bSRobert Mustacchi     }
388*eef4f27bSRobert Mustacchi 
389*eef4f27bSRobert Mustacchi     packet->u1.tx.dbg_start_bd = txq->prod_bd;
390*eef4f27bSRobert Mustacchi     packet->u1.tx.dbg_start_bd_idx = txq->prod_idx;
391*eef4f27bSRobert Mustacchi     packet->u1.tx.dbg_frag_cnt = (u16_t) frags->cnt;
392*eef4f27bSRobert Mustacchi     #endif
393*eef4f27bSRobert Mustacchi 
394*eef4f27bSRobert Mustacchi     last_bd = NULL;
395*eef4f27bSRobert Mustacchi 
396*eef4f27bSRobert Mustacchi     if(frags->cnt > txq->bd_left)
397*eef4f27bSRobert Mustacchi     {
398*eef4f27bSRobert Mustacchi         /* The caller should have done this check before calling this
399*eef4f27bSRobert Mustacchi          * routine. */
400*eef4f27bSRobert Mustacchi         DbgBreakMsg("No tx bd left.\n");
401*eef4f27bSRobert Mustacchi 
402*eef4f27bSRobert Mustacchi         return LM_STATUS_RESOURCE;
403*eef4f27bSRobert Mustacchi     }
404*eef4f27bSRobert Mustacchi 
405*eef4f27bSRobert Mustacchi     txq->bd_left -= (u16_t) frags->cnt;
406*eef4f27bSRobert Mustacchi 
407*eef4f27bSRobert Mustacchi     pkt_info = packet->u1.tx.tx_pkt_info;
408*eef4f27bSRobert Mustacchi     packet->u1.tx.size = 0;
409*eef4f27bSRobert Mustacchi     flags = 0;
410*eef4f27bSRobert Mustacchi 
411*eef4f27bSRobert Mustacchi     if(pkt_info->flags & LM_TX_FLAG_INSERT_VLAN_TAG)
412*eef4f27bSRobert Mustacchi     {
413*eef4f27bSRobert Mustacchi         flags |= TX_BD_FLAGS_VLAN_TAG;
414*eef4f27bSRobert Mustacchi     }
415*eef4f27bSRobert Mustacchi 
416*eef4f27bSRobert Mustacchi     if((pkt_info->flags & LM_TX_FLAG_TCP_LSO_FRAME) == 0)
417*eef4f27bSRobert Mustacchi     {
418*eef4f27bSRobert Mustacchi         if(pkt_info->flags & LM_TX_FLAG_COMPUTE_IP_CKSUM)
419*eef4f27bSRobert Mustacchi         {
420*eef4f27bSRobert Mustacchi             flags |= TX_BD_FLAGS_IP_CKSUM;
421*eef4f27bSRobert Mustacchi             LM_INC64(&pdev->tx_info.stats.ip_cso_frames, 1);
422*eef4f27bSRobert Mustacchi         }
423*eef4f27bSRobert Mustacchi 
424*eef4f27bSRobert Mustacchi         if(pkt_info->flags & LM_TX_FLAG_COMPUTE_TCP_UDP_CKSUM)
425*eef4f27bSRobert Mustacchi         {
426*eef4f27bSRobert Mustacchi             flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
427*eef4f27bSRobert Mustacchi             if(pkt_info->flags & LM_TX_FLAG_IPV6_PACKET)
428*eef4f27bSRobert Mustacchi             {
429*eef4f27bSRobert Mustacchi                 LM_INC64(&pdev->tx_info.stats.ipv6_tcp_udp_cso_frames, 1);
430*eef4f27bSRobert Mustacchi             }
431*eef4f27bSRobert Mustacchi             else
432*eef4f27bSRobert Mustacchi             {
433*eef4f27bSRobert Mustacchi                 LM_INC64(&pdev->tx_info.stats.ipv4_tcp_udp_cso_frames, 1);
434*eef4f27bSRobert Mustacchi             }
435*eef4f27bSRobert Mustacchi         }
436*eef4f27bSRobert Mustacchi     }
437*eef4f27bSRobert Mustacchi 
438*eef4f27bSRobert Mustacchi     if(pkt_info->flags & LM_TX_FLAG_DONT_COMPUTE_CRC)
439*eef4f27bSRobert Mustacchi     {
440*eef4f27bSRobert Mustacchi         flags |= TX_BD_FLAGS_DONT_GEN_CRC;
441*eef4f27bSRobert Mustacchi     }
442*eef4f27bSRobert Mustacchi 
443*eef4f27bSRobert Mustacchi     if(pkt_info->flags & LM_TX_FLAG_TCP_LSO_FRAME)
444*eef4f27bSRobert Mustacchi     {
445*eef4f27bSRobert Mustacchi         if(pkt_info->flags & LM_TX_FLAG_IPV6_PACKET)
446*eef4f27bSRobert Mustacchi         {
447*eef4f27bSRobert Mustacchi             /* TCP option length - bottom 4 bits of TX_BD_FLAGS_SW_OPTION_WORD
448*eef4f27bSRobert Mustacchi              *    in term of the number of 4-byte words.
449*eef4f27bSRobert Mustacchi              * IP header length - bits 1-2 of bd flag, the upper 2 bits of
450*eef4f27bSRobert Mustacchi              *    tx_bd_reserved, and the upper 1 bit of
451*eef4f27bSRobert Mustacchi              *    TX_BD_FLAGS_SW_OPTION_WORD will be used for IPV6 extension
452*eef4f27bSRobert Mustacchi              *    header length in term of 8-btye words.
453*eef4f27bSRobert Mustacchi              * TX_BD_FLAGS_SW_FLAGS bit will be used to indicate IPV6 LSO. */
454*eef4f27bSRobert Mustacchi             flags |= TX_BD_FLAGS_SW_FLAGS;
455*eef4f27bSRobert Mustacchi 
456*eef4f27bSRobert Mustacchi             if(pkt_info->flags & LM_TX_FLAG_TCP_LSO_SNAP_FRAME)
457*eef4f27bSRobert Mustacchi             {
458*eef4f27bSRobert Mustacchi                 flags |= TX_BD_FLAGS_SW_SNAP;
459*eef4f27bSRobert Mustacchi             }
460*eef4f27bSRobert Mustacchi 
461*eef4f27bSRobert Mustacchi             DbgBreakIf(pkt_info->lso_tcp_hdr_len < 20 ||
462*eef4f27bSRobert Mustacchi                        pkt_info->lso_tcp_hdr_len > 84 ||
463*eef4f27bSRobert Mustacchi                        pkt_info->lso_tcp_hdr_len % 4);
464*eef4f27bSRobert Mustacchi 
465*eef4f27bSRobert Mustacchi             /* tcp option length in term of number of 32-bit word.  4 bits
466*eef4f27bSRobert Mustacchi              * are used for the number of words. */
467*eef4f27bSRobert Mustacchi             flags |= (pkt_info->lso_tcp_hdr_len - 20) << 6;
468*eef4f27bSRobert Mustacchi 
469*eef4f27bSRobert Mustacchi             DbgBreakIf(pkt_info->lso_ip_hdr_len < 20 ||
470*eef4f27bSRobert Mustacchi                        pkt_info->lso_ip_hdr_len > 296 ||
471*eef4f27bSRobert Mustacchi                       (pkt_info->lso_ip_hdr_len - 40) % 8);
472*eef4f27bSRobert Mustacchi 
473*eef4f27bSRobert Mustacchi             /* ipv6 extension header length.  6 bits are used for the number
474*eef4f27bSRobert Mustacchi              * of 64-bit words. */
475*eef4f27bSRobert Mustacchi             ipv6_ext_len = pkt_info->lso_ip_hdr_len - 40;
476*eef4f27bSRobert Mustacchi 
477*eef4f27bSRobert Mustacchi             DbgBreakIf(ipv6_ext_len & 0x7);
478*eef4f27bSRobert Mustacchi 
479*eef4f27bSRobert Mustacchi             /* ext_len in number of 8-byte words. */
480*eef4f27bSRobert Mustacchi             ipv6_ext_len >>= 3;
481*eef4f27bSRobert Mustacchi 
482*eef4f27bSRobert Mustacchi             flags |= (ipv6_ext_len & 0x3) << 1;             /* bit 1-0 */
483*eef4f27bSRobert Mustacchi 
484*eef4f27bSRobert Mustacchi             lso_bd_reserved = pkt_info->lso_mss;
485*eef4f27bSRobert Mustacchi             lso_bd_reserved |= (ipv6_ext_len & 0xc) << 12;  /* bit 3-2 */
486*eef4f27bSRobert Mustacchi 
487*eef4f27bSRobert Mustacchi             flags |= (ipv6_ext_len & 0x10) << 8;            /* bit 4  */
488*eef4f27bSRobert Mustacchi 
489*eef4f27bSRobert Mustacchi             DbgBreakIf(ipv6_ext_len >> 5);  /* bit 5 & high are invalid. */
490*eef4f27bSRobert Mustacchi 
491*eef4f27bSRobert Mustacchi             LM_INC64(&pdev->tx_info.stats.ipv6_lso_frames, 1);
492*eef4f27bSRobert Mustacchi         }
493*eef4f27bSRobert Mustacchi         else
494*eef4f27bSRobert Mustacchi         {
495*eef4f27bSRobert Mustacchi             flags |= TX_BD_FLAGS_SW_LSO;
496*eef4f27bSRobert Mustacchi             if(pkt_info->flags & LM_TX_FLAG_TCP_LSO_SNAP_FRAME)
497*eef4f27bSRobert Mustacchi             {
498*eef4f27bSRobert Mustacchi                 flags |= TX_BD_FLAGS_SW_SNAP;
499*eef4f27bSRobert Mustacchi             }
500*eef4f27bSRobert Mustacchi 
501*eef4f27bSRobert Mustacchi             DbgBreakIf(pkt_info->lso_ip_hdr_len +
502*eef4f27bSRobert Mustacchi                 pkt_info->lso_tcp_hdr_len > 120);
503*eef4f27bSRobert Mustacchi 
504*eef4f27bSRobert Mustacchi             /* The size of IP and TCP options in term of 32-bit words. */
505*eef4f27bSRobert Mustacchi             flags |= (pkt_info->lso_ip_hdr_len +
506*eef4f27bSRobert Mustacchi                 pkt_info->lso_tcp_hdr_len - 40) << 6;
507*eef4f27bSRobert Mustacchi 
508*eef4f27bSRobert Mustacchi             lso_bd_reserved = pkt_info->lso_mss;
509*eef4f27bSRobert Mustacchi 
510*eef4f27bSRobert Mustacchi             LM_INC64(&pdev->tx_info.stats.ipv4_lso_frames, 1);
511*eef4f27bSRobert Mustacchi         }
512*eef4f27bSRobert Mustacchi     }
513*eef4f27bSRobert Mustacchi     else
514*eef4f27bSRobert Mustacchi     {
515*eef4f27bSRobert Mustacchi         lso_bd_reserved = 0;
516*eef4f27bSRobert Mustacchi     }
517*eef4f27bSRobert Mustacchi 
518*eef4f27bSRobert Mustacchi     start_bd = txq->prod_bd;
519*eef4f27bSRobert Mustacchi     frag = frags->frag_arr;
520*eef4f27bSRobert Mustacchi 
521*eef4f27bSRobert Mustacchi     /* Get the pointer to the current BD and its index. */
522*eef4f27bSRobert Mustacchi     prod_idx = txq->prod_idx;
523*eef4f27bSRobert Mustacchi     prod_bd = txq->prod_bd;
524*eef4f27bSRobert Mustacchi 
525*eef4f27bSRobert Mustacchi     /* This is the number of times we cross a BD page boundary for this
526*eef4f27bSRobert Mustacchi      * packet.  This and the bd_used value will give us the total number
527*eef4f27bSRobert Mustacchi      * of BD slots needed to send this packet which is used to determine
528*eef4f27bSRobert Mustacchi      * if a packet has been sent.  We only need this because unlike L2
529*eef4f27bSRobert Mustacchi      * completion, LSO completion does not end at a request boundary.
530*eef4f27bSRobert Mustacchi      * For example, if we had an LSO request that spans BD#100-120.  We
531*eef4f27bSRobert Mustacchi      * could get a transmit consumer index of 115. */
532*eef4f27bSRobert Mustacchi     packet->u1.tx.span_pages = 0;
533*eef4f27bSRobert Mustacchi 
534*eef4f27bSRobert Mustacchi     /* Initialize the bd's of this packet. */
535*eef4f27bSRobert Mustacchi     for(cnt = 0; cnt < frags->cnt; cnt++)
536*eef4f27bSRobert Mustacchi     {
537*eef4f27bSRobert Mustacchi         DbgBreakIf(frag->size >= 0x10000 || frag->size == 0);
538*eef4f27bSRobert Mustacchi 
539*eef4f27bSRobert Mustacchi         prod_bd->tx_bd_haddr_lo = frag->addr.as_u32.low;
540*eef4f27bSRobert Mustacchi         prod_bd->tx_bd_haddr_hi = frag->addr.as_u32.high;
541*eef4f27bSRobert Mustacchi         prod_bd->tx_bd_nbytes = (u16_t) frag->size;
542*eef4f27bSRobert Mustacchi         prod_bd->tx_bd_vlan_tag = pkt_info->vlan_tag;
543*eef4f27bSRobert Mustacchi         prod_bd->tx_bd_flags = (u16_t) flags;
544*eef4f27bSRobert Mustacchi 
545*eef4f27bSRobert Mustacchi         if(pkt_info->flags & LM_TX_FLAG_TCP_LSO_FRAME)
546*eef4f27bSRobert Mustacchi         {
547*eef4f27bSRobert Mustacchi             prod_bd->tx_bd_reserved = lso_bd_reserved;
548*eef4f27bSRobert Mustacchi         }
549*eef4f27bSRobert Mustacchi         else if(pdev->params.test_mode & TEST_MODE_TX_BD_TAGGING)
550*eef4f27bSRobert Mustacchi         {
551*eef4f27bSRobert Mustacchi             prod_bd->tx_bd_reserved = prod_idx & 0x0fff;
552*eef4f27bSRobert Mustacchi             prod_bd->tx_bd_reserved |= (u16_t) (GET_CID(txq->cid_addr) << 12);
553*eef4f27bSRobert Mustacchi         }
554*eef4f27bSRobert Mustacchi 
555*eef4f27bSRobert Mustacchi         packet->u1.tx.size += frag->size;
556*eef4f27bSRobert Mustacchi 
557*eef4f27bSRobert Mustacchi         last_bd = prod_bd;
558*eef4f27bSRobert Mustacchi         frag++;
559*eef4f27bSRobert Mustacchi 
560*eef4f27bSRobert Mustacchi         /* Advance to the next BD. */
561*eef4f27bSRobert Mustacchi         prod_bd++;
562*eef4f27bSRobert Mustacchi         prod_idx++;
563*eef4f27bSRobert Mustacchi         if((prod_idx & MAX_BD_PER_PAGE) == MAX_BD_PER_PAGE)
564*eef4f27bSRobert Mustacchi         {
565*eef4f27bSRobert Mustacchi             /* Only increment span_pages when this BDs for this request
566*eef4f27bSRobert Mustacchi              * cross a page boundary. */
567*eef4f27bSRobert Mustacchi             if(cnt+1 < frags->cnt)
568*eef4f27bSRobert Mustacchi             {
569*eef4f27bSRobert Mustacchi                 packet->u1.tx.span_pages++;
570*eef4f27bSRobert Mustacchi             }
571*eef4f27bSRobert Mustacchi 
572*eef4f27bSRobert Mustacchi             prod_idx++;
573*eef4f27bSRobert Mustacchi             prod_bd = *((tx_bd_t **) ((tx_bd_next_t *)
574*eef4f27bSRobert Mustacchi                 prod_bd)->tx_bd_next_reserved);
575*eef4f27bSRobert Mustacchi         }
576*eef4f27bSRobert Mustacchi     }
577*eef4f27bSRobert Mustacchi 
578*eef4f27bSRobert Mustacchi     /* Set the bd flags of the first and last BDs. */
579*eef4f27bSRobert Mustacchi     flags |= TX_BD_FLAGS_END;
580*eef4f27bSRobert Mustacchi     if(pkt_info->flags & LM_TX_FLAG_COAL_NOW)
581*eef4f27bSRobert Mustacchi     {
582*eef4f27bSRobert Mustacchi         flags |= TX_BD_FLAGS_COAL_NOW;
583*eef4f27bSRobert Mustacchi     }
584*eef4f27bSRobert Mustacchi 
585*eef4f27bSRobert Mustacchi     last_bd->tx_bd_flags |= (u16_t) flags;
586*eef4f27bSRobert Mustacchi     start_bd->tx_bd_flags |= TX_BD_FLAGS_START;
587*eef4f27bSRobert Mustacchi 
588*eef4f27bSRobert Mustacchi     #if INCLUDE_OFLD_SUPPORT
589*eef4f27bSRobert Mustacchi     /* We need to do the padding for the catchup path. */
590*eef4f27bSRobert Mustacchi     if(chain_idx == pdev->tx_info.cu_idx &&
591*eef4f27bSRobert Mustacchi         packet->u1.tx.size < MIN_ETHERNET_PACKET_SIZE)
592*eef4f27bSRobert Mustacchi     {
593*eef4f27bSRobert Mustacchi         last_bd->tx_bd_nbytes +=
594*eef4f27bSRobert Mustacchi             (u16_t) (MIN_ETHERNET_PACKET_SIZE - packet->u1.tx.size);
595*eef4f27bSRobert Mustacchi         packet->u1.tx.size = MIN_ETHERNET_PACKET_SIZE;
596*eef4f27bSRobert Mustacchi     }
597*eef4f27bSRobert Mustacchi     #endif
598*eef4f27bSRobert Mustacchi 
599*eef4f27bSRobert Mustacchi     /* Save the number of BDs used.  Later we need to add this value back
600*eef4f27bSRobert Mustacchi      * to txq->bd_left when the packet is sent. */
601*eef4f27bSRobert Mustacchi     packet->u1.tx.bd_used = (u16_t) frags->cnt;
602*eef4f27bSRobert Mustacchi 
603*eef4f27bSRobert Mustacchi     packet->u1.tx.next_bd_idx = prod_idx;
604*eef4f27bSRobert Mustacchi 
605*eef4f27bSRobert Mustacchi     txq->prod_bd = prod_bd;
606*eef4f27bSRobert Mustacchi     txq->prod_idx = prod_idx;
607*eef4f27bSRobert Mustacchi     txq->prod_bseq += packet->u1.tx.size;
608*eef4f27bSRobert Mustacchi #if (DBG)
609*eef4f27bSRobert Mustacchi     if (chain_idx == pdev->tx_info.cu_idx)
610*eef4f27bSRobert Mustacchi     {
611*eef4f27bSRobert Mustacchi         DbgBreakIf(packet->u1.tx.size > pdev->params.mtu + 4);
612*eef4f27bSRobert Mustacchi     }
613*eef4f27bSRobert Mustacchi     else
614*eef4f27bSRobert Mustacchi     {
615*eef4f27bSRobert Mustacchi         DbgBreakIf(packet->u1.tx.size > pdev->params.mtu &&
616*eef4f27bSRobert Mustacchi             (flags & (TX_BD_FLAGS_SW_LSO | TX_BD_FLAGS_SW_FLAGS)) == 0);
617*eef4f27bSRobert Mustacchi     }
618*eef4f27bSRobert Mustacchi #endif
619*eef4f27bSRobert Mustacchi     s_list_push_tail(&txq->active_descq, &packet->link);
620*eef4f27bSRobert Mustacchi 
621*eef4f27bSRobert Mustacchi     if(!(pkt_info->flags & LM_TX_FLAG_SKIP_MBQ_WRITE))
622*eef4f27bSRobert Mustacchi     {
623*eef4f27bSRobert Mustacchi         // hardcode offset in case of L2_ONLY (e.g Solaris)
624*eef4f27bSRobert Mustacchi         u32_t cmd_offset = 34*sizeof(u32_t); //  == OFFSETOF(l4_context_t, l4ctx_cmd)
625*eef4f27bSRobert Mustacchi         MBQ_WR16(
626*eef4f27bSRobert Mustacchi             pdev,
627*eef4f27bSRobert Mustacchi             GET_CID(txq->cid_addr),
628*eef4f27bSRobert Mustacchi             cmd_offset +
629*eef4f27bSRobert Mustacchi                 OFFSETOF(tcp_context_cmd_cell_te_t, ccell_tx_host_bidx),
630*eef4f27bSRobert Mustacchi             txq->prod_idx);
631*eef4f27bSRobert Mustacchi         if(pdev->vars.enable_cu_rate_limiter &&
632*eef4f27bSRobert Mustacchi            txq->idx == TX_CHAIN_IDX1)
633*eef4f27bSRobert Mustacchi         {
634*eef4f27bSRobert Mustacchi             REG_WR_IND(
635*eef4f27bSRobert Mustacchi                 pdev,
636*eef4f27bSRobert Mustacchi                 OFFSETOF(reg_space_t, com.com_scratch[0])+COM_HSI_OFFSETOFF(com_cu_host_bseq),
637*eef4f27bSRobert Mustacchi                 txq->prod_bseq);
638*eef4f27bSRobert Mustacchi         }
639*eef4f27bSRobert Mustacchi         else
640*eef4f27bSRobert Mustacchi         {
641*eef4f27bSRobert Mustacchi         	MBQ_WR32(
642*eef4f27bSRobert Mustacchi             	pdev,
643*eef4f27bSRobert Mustacchi             	GET_CID(txq->cid_addr),
644*eef4f27bSRobert Mustacchi             	cmd_offset +
645*eef4f27bSRobert Mustacchi                 OFFSETOF(tcp_context_cmd_cell_te_t, ccell_tx_host_bseq),
646*eef4f27bSRobert Mustacchi             	txq->prod_bseq);
647*eef4f27bSRobert Mustacchi         }
648*eef4f27bSRobert Mustacchi     }
649*eef4f27bSRobert Mustacchi 
650*eef4f27bSRobert Mustacchi     return LM_STATUS_SUCCESS;
651*eef4f27bSRobert Mustacchi } /* lm_send_packet */
652*eef4f27bSRobert Mustacchi #endif /* LM_NON_LEGACY_MODE_SUPPORT */
653*eef4f27bSRobert Mustacchi 
654*eef4f27bSRobert Mustacchi 
655*eef4f27bSRobert Mustacchi /*******************************************************************************
656*eef4f27bSRobert Mustacchi  * Description:
657*eef4f27bSRobert Mustacchi  *
658*eef4f27bSRobert Mustacchi  * Return:
659*eef4f27bSRobert Mustacchi  ******************************************************************************/
660*eef4f27bSRobert Mustacchi STATIC u32_t
get_packets_sent(struct _lm_device_t * pdev,lm_tx_chain_t * txq,u16_t hw_con_idx,s_list_t * sent_list)661*eef4f27bSRobert Mustacchi get_packets_sent(
662*eef4f27bSRobert Mustacchi     struct _lm_device_t *pdev,
663*eef4f27bSRobert Mustacchi     lm_tx_chain_t *txq,
664*eef4f27bSRobert Mustacchi     u16_t hw_con_idx,
665*eef4f27bSRobert Mustacchi     s_list_t *sent_list)
666*eef4f27bSRobert Mustacchi {
667*eef4f27bSRobert Mustacchi     lm_packet_t *pkt;
668*eef4f27bSRobert Mustacchi     u32_t pkt_cnt;
669*eef4f27bSRobert Mustacchi 
670*eef4f27bSRobert Mustacchi     /* The consumer index may stop at the end of a page boundary.
671*eef4f27bSRobert Mustacchi      * In this case, we need to advance the next to the next one. */
672*eef4f27bSRobert Mustacchi     if((hw_con_idx & MAX_BD_PER_PAGE) == MAX_BD_PER_PAGE)
673*eef4f27bSRobert Mustacchi     {
674*eef4f27bSRobert Mustacchi         hw_con_idx++;
675*eef4f27bSRobert Mustacchi     }
676*eef4f27bSRobert Mustacchi 
677*eef4f27bSRobert Mustacchi     pkt_cnt = 0;
678*eef4f27bSRobert Mustacchi 
679*eef4f27bSRobert Mustacchi     while(txq->con_idx != hw_con_idx)
680*eef4f27bSRobert Mustacchi     {
681*eef4f27bSRobert Mustacchi         DbgBreakIf(S16_SUB(hw_con_idx, txq->con_idx) <= 0);
682*eef4f27bSRobert Mustacchi 
683*eef4f27bSRobert Mustacchi         pkt = (lm_packet_t *) s_list_peek_head(&txq->active_descq);
684*eef4f27bSRobert Mustacchi 
685*eef4f27bSRobert Mustacchi         DbgBreakIf(pkt == NULL);
686*eef4f27bSRobert Mustacchi 
687*eef4f27bSRobert Mustacchi         if(!pkt)
688*eef4f27bSRobert Mustacchi 		{
689*eef4f27bSRobert Mustacchi 			DbgBreakIf(!s_list_is_empty(&txq->active_descq));
690*eef4f27bSRobert Mustacchi 			break;
691*eef4f27bSRobert Mustacchi 		}
692*eef4f27bSRobert Mustacchi         /* LSO requests may not complete at the request boundary.
693*eef4f27bSRobert Mustacchi          *
694*eef4f27bSRobert Mustacchi          * if(pkt->u1.tx.flags & LM_TX_FLAG_TCP_LSO_FRAME) */
695*eef4f27bSRobert Mustacchi         {
696*eef4f27bSRobert Mustacchi             if((u16_t) S16_SUB(hw_con_idx, txq->con_idx) <
697*eef4f27bSRobert Mustacchi                 pkt->u1.tx.bd_used + pkt->u1.tx.span_pages)
698*eef4f27bSRobert Mustacchi             {
699*eef4f27bSRobert Mustacchi                 break;
700*eef4f27bSRobert Mustacchi             }
701*eef4f27bSRobert Mustacchi         }
702*eef4f27bSRobert Mustacchi 
703*eef4f27bSRobert Mustacchi         #if DBG
704*eef4f27bSRobert Mustacchi         DbgBreakIf(pkt->u1.tx.dbg_start_bd_idx != txq->con_idx);
705*eef4f27bSRobert Mustacchi 
706*eef4f27bSRobert Mustacchi         /* Make sure hw_con_idx ends at an l2 packet boundary.  For LSO,
707*eef4f27bSRobert Mustacchi          * request, hw_con_idx may not end at the request boundary. */
708*eef4f27bSRobert Mustacchi         while(pkt)
709*eef4f27bSRobert Mustacchi         {
710*eef4f27bSRobert Mustacchi             if(S16_SUB(hw_con_idx, pkt->u1.tx.next_bd_idx) <= 0)
711*eef4f27bSRobert Mustacchi             {
712*eef4f27bSRobert Mustacchi                 break;
713*eef4f27bSRobert Mustacchi             }
714*eef4f27bSRobert Mustacchi 
715*eef4f27bSRobert Mustacchi             pkt = (lm_packet_t *) s_list_next_entry(&pkt->link);
716*eef4f27bSRobert Mustacchi         }
717*eef4f27bSRobert Mustacchi 
718*eef4f27bSRobert Mustacchi         DbgBreakIf(pkt == NULL);
719*eef4f27bSRobert Mustacchi 
720*eef4f27bSRobert Mustacchi         /* catchup workaround.
721*eef4f27bSRobert Mustacchi          * DbgBreakIf(
722*eef4f27bSRobert Mustacchi          *    !(pkt->u1.tx.flags & LM_TX_FLAG_TCP_LSO_FRAME) &&
723*eef4f27bSRobert Mustacchi          *    (hw_con_idx != pkt->u1.tx.next_bd_idx)); */
724*eef4f27bSRobert Mustacchi         #endif
725*eef4f27bSRobert Mustacchi 
726*eef4f27bSRobert Mustacchi         pkt = (lm_packet_t *) s_list_pop_head(&txq->active_descq);
727*eef4f27bSRobert Mustacchi 
728*eef4f27bSRobert Mustacchi         /* Advance the txq->con_idx to the start bd_idx of the next packet. */
729*eef4f27bSRobert Mustacchi         txq->con_idx = pkt->u1.tx.next_bd_idx;
730*eef4f27bSRobert Mustacchi 
731*eef4f27bSRobert Mustacchi         pkt->status = LM_STATUS_SUCCESS;
732*eef4f27bSRobert Mustacchi 
733*eef4f27bSRobert Mustacchi         txq->bd_left += pkt->u1.tx.bd_used;
734*eef4f27bSRobert Mustacchi 
735*eef4f27bSRobert Mustacchi         s_list_push_tail(sent_list, &pkt->link);
736*eef4f27bSRobert Mustacchi 
737*eef4f27bSRobert Mustacchi         pkt_cnt++;
738*eef4f27bSRobert Mustacchi     }
739*eef4f27bSRobert Mustacchi 
740*eef4f27bSRobert Mustacchi     return pkt_cnt;
741*eef4f27bSRobert Mustacchi } /* get_packets_sent */
742*eef4f27bSRobert Mustacchi 
743*eef4f27bSRobert Mustacchi 
744*eef4f27bSRobert Mustacchi 
745*eef4f27bSRobert Mustacchi /*******************************************************************************
746*eef4f27bSRobert Mustacchi  * Description:
747*eef4f27bSRobert Mustacchi  *
748*eef4f27bSRobert Mustacchi  * Return:
749*eef4f27bSRobert Mustacchi  ******************************************************************************/
750*eef4f27bSRobert Mustacchi u32_t
lm_get_packets_sent(struct _lm_device_t * pdev,u32_t qidx,u32_t con_idx,s_list_t * sent_list)751*eef4f27bSRobert Mustacchi lm_get_packets_sent(
752*eef4f27bSRobert Mustacchi     struct _lm_device_t *pdev,
753*eef4f27bSRobert Mustacchi     u32_t qidx,
754*eef4f27bSRobert Mustacchi     u32_t con_idx,
755*eef4f27bSRobert Mustacchi     s_list_t *sent_list)
756*eef4f27bSRobert Mustacchi {
757*eef4f27bSRobert Mustacchi     lm_tx_chain_t *txq;
758*eef4f27bSRobert Mustacchi     u16_t hw_con_idx;
759*eef4f27bSRobert Mustacchi     u32_t pkts_added;
760*eef4f27bSRobert Mustacchi     u32_t pkt_cnt;
761*eef4f27bSRobert Mustacchi 
762*eef4f27bSRobert Mustacchi     txq = &pdev->tx_info.chain[qidx];
763*eef4f27bSRobert Mustacchi 
764*eef4f27bSRobert Mustacchi     if(con_idx)
765*eef4f27bSRobert Mustacchi     {
766*eef4f27bSRobert Mustacchi         hw_con_idx = con_idx & 0xffff;
767*eef4f27bSRobert Mustacchi 
768*eef4f27bSRobert Mustacchi         pkt_cnt = get_packets_sent(pdev, txq, hw_con_idx, sent_list);
769*eef4f27bSRobert Mustacchi     }
770*eef4f27bSRobert Mustacchi     else
771*eef4f27bSRobert Mustacchi     {
772*eef4f27bSRobert Mustacchi         pkt_cnt = 0;
773*eef4f27bSRobert Mustacchi 
774*eef4f27bSRobert Mustacchi         for(; ;)
775*eef4f27bSRobert Mustacchi         {
776*eef4f27bSRobert Mustacchi             hw_con_idx = *txq->hw_con_idx_ptr;
777*eef4f27bSRobert Mustacchi 
778*eef4f27bSRobert Mustacchi             pkts_added = get_packets_sent(pdev, txq, hw_con_idx, sent_list);
779*eef4f27bSRobert Mustacchi             if(pkts_added == 0)
780*eef4f27bSRobert Mustacchi             {
781*eef4f27bSRobert Mustacchi                 break;
782*eef4f27bSRobert Mustacchi             }
783*eef4f27bSRobert Mustacchi 
784*eef4f27bSRobert Mustacchi             pkt_cnt += pkts_added;
785*eef4f27bSRobert Mustacchi         }
786*eef4f27bSRobert Mustacchi     }
787*eef4f27bSRobert Mustacchi 
788*eef4f27bSRobert Mustacchi     return pkt_cnt;
789*eef4f27bSRobert Mustacchi } /* lm_get_packets_sent */
790*eef4f27bSRobert Mustacchi 
791*eef4f27bSRobert Mustacchi 
792*eef4f27bSRobert Mustacchi 
793*eef4f27bSRobert Mustacchi /*******************************************************************************
794*eef4f27bSRobert Mustacchi  * Description:
795*eef4f27bSRobert Mustacchi  *
796*eef4f27bSRobert Mustacchi  * Return:
797*eef4f27bSRobert Mustacchi  ******************************************************************************/
798*eef4f27bSRobert Mustacchi void
lm_service_tx_int(lm_device_t * pdev,u32_t chain_idx)799*eef4f27bSRobert Mustacchi lm_service_tx_int(
800*eef4f27bSRobert Mustacchi     lm_device_t *pdev,
801*eef4f27bSRobert Mustacchi     u32_t chain_idx)
802*eef4f27bSRobert Mustacchi {
803*eef4f27bSRobert Mustacchi     lm_packet_t *pkt_arr[MAX_PACKETS_PER_INDICATION];
804*eef4f27bSRobert Mustacchi     lm_packet_t **pkt_arr_ptr;
805*eef4f27bSRobert Mustacchi     s_list_t sent_list;
806*eef4f27bSRobert Mustacchi     lm_packet_t *pkt;
807*eef4f27bSRobert Mustacchi     u32_t pkt_cnt;
808*eef4f27bSRobert Mustacchi 
809*eef4f27bSRobert Mustacchi     s_list_init(&sent_list, NULL, NULL, 0);
810*eef4f27bSRobert Mustacchi 
811*eef4f27bSRobert Mustacchi     (void) lm_get_packets_sent(pdev, chain_idx, 0, &sent_list);
812*eef4f27bSRobert Mustacchi 
813*eef4f27bSRobert Mustacchi     while(!s_list_is_empty(&sent_list))
814*eef4f27bSRobert Mustacchi     {
815*eef4f27bSRobert Mustacchi         pkt_arr_ptr = pkt_arr;
816*eef4f27bSRobert Mustacchi 
817*eef4f27bSRobert Mustacchi         for(pkt_cnt = 0; pkt_cnt < MAX_PACKETS_PER_INDICATION; pkt_cnt++)
818*eef4f27bSRobert Mustacchi         {
819*eef4f27bSRobert Mustacchi             pkt = (lm_packet_t *) s_list_pop_head(&sent_list);
820*eef4f27bSRobert Mustacchi             if(pkt == NULL)
821*eef4f27bSRobert Mustacchi             {
822*eef4f27bSRobert Mustacchi                 break;
823*eef4f27bSRobert Mustacchi             }
824*eef4f27bSRobert Mustacchi 
825*eef4f27bSRobert Mustacchi             *pkt_arr_ptr = pkt;
826*eef4f27bSRobert Mustacchi             pkt_arr_ptr++;
827*eef4f27bSRobert Mustacchi         }
828*eef4f27bSRobert Mustacchi 
829*eef4f27bSRobert Mustacchi         mm_indicate_tx(pdev, chain_idx, pkt_arr, pkt_cnt);
830*eef4f27bSRobert Mustacchi     }
831*eef4f27bSRobert Mustacchi } /* lm_service_tx_int */
832*eef4f27bSRobert Mustacchi 
833*eef4f27bSRobert Mustacchi 
834*eef4f27bSRobert Mustacchi 
835*eef4f27bSRobert Mustacchi /*******************************************************************************
836*eef4f27bSRobert Mustacchi  * Description:
837*eef4f27bSRobert Mustacchi  *
838*eef4f27bSRobert Mustacchi  * Return:
839*eef4f27bSRobert Mustacchi  ******************************************************************************/
840*eef4f27bSRobert Mustacchi void
lm_send_abort(struct _lm_device_t * pdev,u32_t idx)841*eef4f27bSRobert Mustacchi lm_send_abort(
842*eef4f27bSRobert Mustacchi     struct _lm_device_t *pdev,
843*eef4f27bSRobert Mustacchi     u32_t idx)
844*eef4f27bSRobert Mustacchi {
845*eef4f27bSRobert Mustacchi     lm_tx_chain_t *txq;
846*eef4f27bSRobert Mustacchi     lm_packet_t *pkt;
847*eef4f27bSRobert Mustacchi 
848*eef4f27bSRobert Mustacchi     DbgBreakIf(idx >= pdev->tx_info.num_txq);
849*eef4f27bSRobert Mustacchi 
850*eef4f27bSRobert Mustacchi     txq = &pdev->tx_info.chain[idx];
851*eef4f27bSRobert Mustacchi 
852*eef4f27bSRobert Mustacchi     for(; ;)
853*eef4f27bSRobert Mustacchi     {
854*eef4f27bSRobert Mustacchi         pkt = (lm_packet_t *) s_list_pop_head(&txq->active_descq);
855*eef4f27bSRobert Mustacchi         if(pkt == NULL)
856*eef4f27bSRobert Mustacchi         {
857*eef4f27bSRobert Mustacchi             break;
858*eef4f27bSRobert Mustacchi         }
859*eef4f27bSRobert Mustacchi 
860*eef4f27bSRobert Mustacchi         pkt->status = LM_STATUS_ABORTED;
861*eef4f27bSRobert Mustacchi         pdev->tx_info.stats.aborted++;
862*eef4f27bSRobert Mustacchi         txq->bd_left += pkt->u1.tx.bd_used;
863*eef4f27bSRobert Mustacchi 
864*eef4f27bSRobert Mustacchi         mm_indicate_tx(pdev, idx, &pkt, 1);
865*eef4f27bSRobert Mustacchi     }
866*eef4f27bSRobert Mustacchi 
867*eef4f27bSRobert Mustacchi     DbgBreakIf(txq->bd_left !=
868*eef4f27bSRobert Mustacchi         pdev->params.l2_tx_bd_page_cnt[txq->idx] * MAX_BD_PER_PAGE - 1);
869*eef4f27bSRobert Mustacchi } /* lm_send_abort */
870