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