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