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