xref: /illumos-gate/usr/src/uts/common/io/bnx/bnxsnd.c (revision ec71f88e)
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 /*
16eef4f27bSRobert Mustacchi  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
17eef4f27bSRobert Mustacchi  * Copyright (c) 2019, Joyent, Inc.
18eef4f27bSRobert Mustacchi  */
19eef4f27bSRobert Mustacchi 
20eef4f27bSRobert Mustacchi #include "bnxsnd.h"
21eef4f27bSRobert Mustacchi 
22eef4f27bSRobert Mustacchi 
23eef4f27bSRobert Mustacchi /* Low water marks for transmit credits. */
24eef4f27bSRobert Mustacchi #define	BNX_DCOPY_ALIGN			32
25eef4f27bSRobert Mustacchi #define	BNX_XMIT_INIT_FAIL_THRESH	1
26eef4f27bSRobert Mustacchi #define	BNX_PDWM_THRESHOLD		8
27eef4f27bSRobert Mustacchi 
28eef4f27bSRobert Mustacchi 
29eef4f27bSRobert Mustacchi #ifndef NUM_TX_CHAIN
30eef4f27bSRobert Mustacchi #error NUM_TX_CHAIN is not defined.
31eef4f27bSRobert Mustacchi #else
32eef4f27bSRobert Mustacchi /*
33eef4f27bSRobert Mustacchi  * Range check NUM_TX_CHAIN.  Technically the LM controls this definition,
34eef4f27bSRobert Mustacchi  * but it makes sense to use what the LM uses.
35eef4f27bSRobert Mustacchi  */
36eef4f27bSRobert Mustacchi #if NUM_TX_CHAIN < 0
37eef4f27bSRobert Mustacchi #error Invalid NUM_TX_CHAIN definition.
38eef4f27bSRobert Mustacchi #elif NUM_TX_CHAIN > 1
39eef4f27bSRobert Mustacchi #warning NUM_TX_CHAIN is greater than 1.
40eef4f27bSRobert Mustacchi #endif
41eef4f27bSRobert Mustacchi #endif
42eef4f27bSRobert Mustacchi 
43eef4f27bSRobert Mustacchi 
44eef4f27bSRobert Mustacchi static ddi_dma_attr_t bnx_snd_dma_attrib = {
45eef4f27bSRobert Mustacchi 	DMA_ATTR_V0,			/* dma_attr_version */
46eef4f27bSRobert Mustacchi 	0,				/* dma_attr_addr_lo */
47eef4f27bSRobert Mustacchi 	0xffffffffffffffff,		/* dma_attr_addr_hi */
48eef4f27bSRobert Mustacchi 	0x0ffffff,			/* dma_attr_count_max */
49eef4f27bSRobert Mustacchi 	BNX_DMA_ALIGNMENT,		/* dma_attr_align */
50eef4f27bSRobert Mustacchi 	0xffffffff,			/* dma_attr_burstsizes */
51eef4f27bSRobert Mustacchi 	1,				/* dma_attr_minxfer */
52eef4f27bSRobert Mustacchi 	0x00ffffff,			/* dma_attr_maxxfer */
53eef4f27bSRobert Mustacchi 	0xffffffff,			/* dma_attr_seg */
54eef4f27bSRobert Mustacchi 	BNX_MAX_SGL_ENTRIES,		/* dma_attr_sgllen */
55eef4f27bSRobert Mustacchi 	BNX_MIN_BYTES_PER_FRAGMENT,	/* dma_attr_granular */
56eef4f27bSRobert Mustacchi 	0,				/* dma_attr_flags */
57eef4f27bSRobert Mustacchi };
58eef4f27bSRobert Mustacchi 
59eef4f27bSRobert Mustacchi /*
60eef4f27bSRobert Mustacchi  * Description:  This function will map the fragments of the message block
61eef4f27bSRobert Mustacchi  *
62eef4f27bSRobert Mustacchi  * Return:  DDI_DMA_MAPPED:   Success
63eef4f27bSRobert Mustacchi  *          DDI_DMA_INUSE:    Another I/O transaction is using the DMA handle
64eef4f27bSRobert Mustacchi  *          DDI_DMA_NORESOURCES: No resources are available at the present time
65eef4f27bSRobert Mustacchi  *          DDI_DMA_NOMAPPING: The object cannot be reached by the device
66eef4f27bSRobert Mustacchi  *                             requesting the resources.
67eef4f27bSRobert Mustacchi  *          DDI_DMA_TOOBIG:   The object is too big. A request of this size can
68eef4f27bSRobert Mustacchi  *                            never be satisfied on this particular system.
69eef4f27bSRobert Mustacchi  *                            The maximum size varies depending on machine
70eef4f27bSRobert Mustacchi  *                            and configuration.
71eef4f27bSRobert Mustacchi  */
72eef4f27bSRobert Mustacchi static int
bnx_xmit_frag_map(mblk_t * mp,ddi_dma_handle_t * handle,lm_frag_list_t * fraglist)73eef4f27bSRobert Mustacchi bnx_xmit_frag_map(mblk_t *mp, ddi_dma_handle_t *handle,
74eef4f27bSRobert Mustacchi     lm_frag_list_t *fraglist)
75eef4f27bSRobert Mustacchi {
76eef4f27bSRobert Mustacchi 	int i;
77eef4f27bSRobert Mustacchi 	uint_t ccount;
78eef4f27bSRobert Mustacchi 	ddi_dma_cookie_t cookie;
79eef4f27bSRobert Mustacchi 	lm_frag_t *fragment;
80eef4f27bSRobert Mustacchi 
81eef4f27bSRobert Mustacchi 	if (fraglist->cnt >= BNX_MAX_SGL_ENTRIES) {
82eef4f27bSRobert Mustacchi 		return (DDI_DMA_NOMAPPING);
83eef4f27bSRobert Mustacchi 	}
84eef4f27bSRobert Mustacchi 
85eef4f27bSRobert Mustacchi 	i = ddi_dma_addr_bind_handle(*handle, NULL,
86eef4f27bSRobert Mustacchi 	    (caddr_t)mp->b_rptr, mp->b_wptr - mp->b_rptr,
87eef4f27bSRobert Mustacchi 	    DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, NULL,
88eef4f27bSRobert Mustacchi 	    &cookie, &ccount);
89eef4f27bSRobert Mustacchi 	if (i != DDI_DMA_MAPPED) {
90eef4f27bSRobert Mustacchi 		return (i);
91eef4f27bSRobert Mustacchi 	}
92eef4f27bSRobert Mustacchi 
93eef4f27bSRobert Mustacchi 	/*
94eef4f27bSRobert Mustacchi 	 * It looks strange at first, but the below check is needed.
95eef4f27bSRobert Mustacchi 	 * ddi_dma_addr_bind_handle() correctly returns an error if
96eef4f27bSRobert Mustacchi 	 * the physical fragment count exceeds the maximum fragment
97eef4f27bSRobert Mustacchi 	 * count specified in the ddi_dma_attrib structure for the
98eef4f27bSRobert Mustacchi 	 * current mp.  However, a packet can span multiple mp's.
99eef4f27bSRobert Mustacchi 	 * The purpose of the check below is to make sure we do not
100eef4f27bSRobert Mustacchi 	 * overflow the global fragment count limit.
101eef4f27bSRobert Mustacchi 	 */
102eef4f27bSRobert Mustacchi 	if (fraglist->cnt + ccount > BNX_MAX_SGL_ENTRIES) {
103eef4f27bSRobert Mustacchi 		/* We hit our fragment count limit. */
104eef4f27bSRobert Mustacchi 		(void) ddi_dma_unbind_handle(*handle);
105eef4f27bSRobert Mustacchi 
106eef4f27bSRobert Mustacchi 		return (DDI_DMA_NOMAPPING);
107eef4f27bSRobert Mustacchi 	}
108eef4f27bSRobert Mustacchi 
109eef4f27bSRobert Mustacchi 	fragment = &(fraglist->frag_arr[fraglist->cnt]);
110eef4f27bSRobert Mustacchi 	fraglist->cnt += ccount;
111eef4f27bSRobert Mustacchi 
112eef4f27bSRobert Mustacchi 	for (i = 0; i < ccount-1; i++) {
113eef4f27bSRobert Mustacchi 		fragment->addr.as_u64 = cookie.dmac_laddress;
114eef4f27bSRobert Mustacchi 		fragment->size = cookie.dmac_size;
115eef4f27bSRobert Mustacchi 
116eef4f27bSRobert Mustacchi 		fragment++;
117eef4f27bSRobert Mustacchi 
118eef4f27bSRobert Mustacchi 		ddi_dma_nextcookie(*handle, &cookie);
119eef4f27bSRobert Mustacchi 	}
120eef4f27bSRobert Mustacchi 
121eef4f27bSRobert Mustacchi 	fragment->addr.as_u64 = cookie.dmac_laddress;
122eef4f27bSRobert Mustacchi 	fragment->size = cookie.dmac_size;
123eef4f27bSRobert Mustacchi 
124eef4f27bSRobert Mustacchi 	return (0);
125eef4f27bSRobert Mustacchi }
126eef4f27bSRobert Mustacchi 
127eef4f27bSRobert Mustacchi static void
bnx_xmit_pkt_unmap(um_txpacket_t * const umpacket)128eef4f27bSRobert Mustacchi bnx_xmit_pkt_unmap(um_txpacket_t * const umpacket)
129eef4f27bSRobert Mustacchi {
130eef4f27bSRobert Mustacchi 	int i;
131eef4f27bSRobert Mustacchi 
132eef4f27bSRobert Mustacchi 	for (i = 0; i < umpacket->num_handles; i++) {
133eef4f27bSRobert Mustacchi 		(void) ddi_dma_unbind_handle(umpacket->dma_handle[i]);
134eef4f27bSRobert Mustacchi 	}
135eef4f27bSRobert Mustacchi 
136eef4f27bSRobert Mustacchi 	umpacket->num_handles = 0;
137eef4f27bSRobert Mustacchi }
138eef4f27bSRobert Mustacchi 
139eef4f27bSRobert Mustacchi int
bnx_xmit_pkt_map(um_txpacket_t * const umpacket,mblk_t * mp)140eef4f27bSRobert Mustacchi bnx_xmit_pkt_map(um_txpacket_t * const umpacket, mblk_t * mp)
141eef4f27bSRobert Mustacchi {
142eef4f27bSRobert Mustacchi 	int rc;
143eef4f27bSRobert Mustacchi 	u32_t num_dma_handle;
144eef4f27bSRobert Mustacchi 
145eef4f27bSRobert Mustacchi 	num_dma_handle = umpacket->num_handles;
146eef4f27bSRobert Mustacchi 
147eef4f27bSRobert Mustacchi 	if (num_dma_handle == BNX_MAX_SGL_ENTRIES) {
148eef4f27bSRobert Mustacchi 		return (BNX_TX_RESOURCES_TOO_MANY_FRAGS);
149eef4f27bSRobert Mustacchi 	}
150eef4f27bSRobert Mustacchi 
151eef4f27bSRobert Mustacchi 	rc = bnx_xmit_frag_map(mp, &umpacket->dma_handle[num_dma_handle++],
152eef4f27bSRobert Mustacchi 	    &(umpacket->frag_list));
153eef4f27bSRobert Mustacchi 	if (rc) {
154eef4f27bSRobert Mustacchi 		return (BNX_TX_RESOURCES_NO_OS_DMA_RES);
155eef4f27bSRobert Mustacchi 	}
156eef4f27bSRobert Mustacchi 
157eef4f27bSRobert Mustacchi 	umpacket->num_handles = num_dma_handle;
158eef4f27bSRobert Mustacchi 
159eef4f27bSRobert Mustacchi 	return (0);
160eef4f27bSRobert Mustacchi }
161eef4f27bSRobert Mustacchi 
162eef4f27bSRobert Mustacchi static void
bnx_xmit_pkt_cpy(um_device_t * const umdevice,um_txpacket_t * const umpacket)163eef4f27bSRobert Mustacchi bnx_xmit_pkt_cpy(um_device_t * const umdevice, um_txpacket_t * const umpacket)
164eef4f27bSRobert Mustacchi {
165eef4f27bSRobert Mustacchi 	size_t msgsize;
166eef4f27bSRobert Mustacchi 	u32_t cpysize;
167eef4f27bSRobert Mustacchi 	lm_frag_t *cpyfrag;
168eef4f27bSRobert Mustacchi 	boolean_t map_enable;
169eef4f27bSRobert Mustacchi 	mblk_t *mp;
170eef4f27bSRobert Mustacchi 	int rc;
171eef4f27bSRobert Mustacchi 
172eef4f27bSRobert Mustacchi 	map_enable = B_TRUE;
173eef4f27bSRobert Mustacchi 	cpysize = 0;
174eef4f27bSRobert Mustacchi 	cpyfrag = NULL;
175eef4f27bSRobert Mustacchi 
176eef4f27bSRobert Mustacchi 	for (mp = umpacket->mp; mp; mp = mp->b_cont) {
177eef4f27bSRobert Mustacchi 		msgsize = MBLKL(mp);
178eef4f27bSRobert Mustacchi 
179eef4f27bSRobert Mustacchi 		if (msgsize == 0)
180eef4f27bSRobert Mustacchi 			continue;
181eef4f27bSRobert Mustacchi 
182eef4f27bSRobert Mustacchi 		if (map_enable && msgsize > umdevice->tx_copy_threshold) {
183eef4f27bSRobert Mustacchi 			rc = bnx_xmit_pkt_map(umpacket, mp);
184eef4f27bSRobert Mustacchi 			if (rc == 0) {
185eef4f27bSRobert Mustacchi 				cpyfrag = NULL;
186eef4f27bSRobert Mustacchi 				continue;
187eef4f27bSRobert Mustacchi 			} else {
188eef4f27bSRobert Mustacchi 				map_enable = B_FALSE;
189eef4f27bSRobert Mustacchi 			}
190eef4f27bSRobert Mustacchi 		}
191eef4f27bSRobert Mustacchi 
192eef4f27bSRobert Mustacchi 		ASSERT(cpysize + msgsize <= umdevice->dev_var.mtu +
193eef4f27bSRobert Mustacchi 		    sizeof (struct ether_vlan_header));
194eef4f27bSRobert Mustacchi 
195eef4f27bSRobert Mustacchi 		bcopy(mp->b_rptr, (char *)umpacket->cpymem + cpysize, msgsize);
196eef4f27bSRobert Mustacchi 
197eef4f27bSRobert Mustacchi 		if (cpyfrag != NULL) {
198eef4f27bSRobert Mustacchi 			cpyfrag->size += msgsize;
199eef4f27bSRobert Mustacchi 		} else {
200eef4f27bSRobert Mustacchi 			cpyfrag = &umpacket->frag_list.frag_arr[
201eef4f27bSRobert Mustacchi 			    umpacket->frag_list.cnt++];
202eef4f27bSRobert Mustacchi 			ASSERT(umpacket->frag_list.cnt <= BNX_MAX_SGL_ENTRIES +
203eef4f27bSRobert Mustacchi 			    1);
204eef4f27bSRobert Mustacchi 			cpyfrag->size = msgsize;
205eef4f27bSRobert Mustacchi 
206eef4f27bSRobert Mustacchi 			cpyfrag->addr.as_u64 = umpacket->cpyphy.as_u64 +
207eef4f27bSRobert Mustacchi 			    cpysize;
208eef4f27bSRobert Mustacchi 		}
209eef4f27bSRobert Mustacchi 
210eef4f27bSRobert Mustacchi 		cpysize += msgsize;
211eef4f27bSRobert Mustacchi 	}
212eef4f27bSRobert Mustacchi 
213eef4f27bSRobert Mustacchi 	if (cpysize > 0) {
214eef4f27bSRobert Mustacchi 		(void) ddi_dma_sync(*(umpacket->cpyhdl), umpacket->cpyoff,
215eef4f27bSRobert Mustacchi 		    cpysize, DDI_DMA_SYNC_FORDEV);
216eef4f27bSRobert Mustacchi 	}
217eef4f27bSRobert Mustacchi 
218eef4f27bSRobert Mustacchi 	if (umpacket->num_handles == 0) {
219eef4f27bSRobert Mustacchi 		freemsg(umpacket->mp);
220eef4f27bSRobert Mustacchi 		umpacket->mp = NULL;
221eef4f27bSRobert Mustacchi 	}
222eef4f27bSRobert Mustacchi 
223eef4f27bSRobert Mustacchi }
224eef4f27bSRobert Mustacchi 
225eef4f27bSRobert Mustacchi static int
bnx_xmit_pkt_init(um_device_t * const umdevice,um_txpacket_t * const umpacket,int num,lm_u64_t memphys)226eef4f27bSRobert Mustacchi bnx_xmit_pkt_init(um_device_t * const umdevice, um_txpacket_t * const umpacket,
227eef4f27bSRobert Mustacchi     int num, lm_u64_t memphys)
228eef4f27bSRobert Mustacchi {
229eef4f27bSRobert Mustacchi 	int i;
230eef4f27bSRobert Mustacchi 	int rc;
231eef4f27bSRobert Mustacchi 	um_xmit_qinfo * xmitinfo;
232eef4f27bSRobert Mustacchi 
233eef4f27bSRobert Mustacchi 	xmitinfo = &_TX_QINFO(umdevice, 0);
234eef4f27bSRobert Mustacchi 
235eef4f27bSRobert Mustacchi 	for (i = 0; i < BNX_MAX_SGL_ENTRIES; i++) {
236eef4f27bSRobert Mustacchi 		rc = ddi_dma_alloc_handle(umdevice->os_param.dip,
237eef4f27bSRobert Mustacchi 		    &bnx_snd_dma_attrib, DDI_DMA_DONTWAIT,
238eef4f27bSRobert Mustacchi 		    (void *)0, &umpacket->dma_handle[i]);
239eef4f27bSRobert Mustacchi 		if (rc != DDI_SUCCESS) {
240eef4f27bSRobert Mustacchi 			cmn_err(CE_WARN, "%s:%s failed. (errno=%d)",
241eef4f27bSRobert Mustacchi 			    umdevice->dev_name, __func__, rc);
242eef4f27bSRobert Mustacchi 			goto error;
243eef4f27bSRobert Mustacchi 		}
244eef4f27bSRobert Mustacchi 	}
245eef4f27bSRobert Mustacchi 
246eef4f27bSRobert Mustacchi 	/* Init the relavant informations in the packet structure */
247eef4f27bSRobert Mustacchi 	umpacket->mp = NULL;
248eef4f27bSRobert Mustacchi 	umpacket->num_handles = 0;
249eef4f27bSRobert Mustacchi 	umpacket->frag_list.cnt = 0;
250eef4f27bSRobert Mustacchi 
251eef4f27bSRobert Mustacchi 	umpacket->cpyhdl = &(xmitinfo->dcpyhndl);
252eef4f27bSRobert Mustacchi 	umpacket->cpyoff = num * xmitinfo->dcpyhard;
253eef4f27bSRobert Mustacchi 	umpacket->cpymem = xmitinfo->dcpyvirt + umpacket->cpyoff;
254eef4f27bSRobert Mustacchi 	umpacket->cpyphy = memphys;
255eef4f27bSRobert Mustacchi 
256eef4f27bSRobert Mustacchi 	return (rc);
257eef4f27bSRobert Mustacchi 
258eef4f27bSRobert Mustacchi error:
259eef4f27bSRobert Mustacchi 	for (i--; i >= 0; i--) {
260eef4f27bSRobert Mustacchi 		ddi_dma_free_handle(&umpacket->dma_handle[i]);
261eef4f27bSRobert Mustacchi 	}
262eef4f27bSRobert Mustacchi 
263eef4f27bSRobert Mustacchi 	return (-1);
264eef4f27bSRobert Mustacchi }
265eef4f27bSRobert Mustacchi 
266eef4f27bSRobert Mustacchi static void
bnx_xmit_pkt_fini(um_txpacket_t * const umpacket)267eef4f27bSRobert Mustacchi bnx_xmit_pkt_fini(um_txpacket_t * const umpacket)
268eef4f27bSRobert Mustacchi {
269eef4f27bSRobert Mustacchi 	int i;
270eef4f27bSRobert Mustacchi 
271eef4f27bSRobert Mustacchi 	for (i = BNX_MAX_SGL_ENTRIES - 1; i >= 0; i--) {
272eef4f27bSRobert Mustacchi 		ddi_dma_free_handle(&umpacket->dma_handle[i]);
273eef4f27bSRobert Mustacchi 	}
274eef4f27bSRobert Mustacchi 
275eef4f27bSRobert Mustacchi 	umpacket->mp = NULL;
276eef4f27bSRobert Mustacchi 	umpacket->num_handles = 0;
277eef4f27bSRobert Mustacchi 	umpacket->frag_list.cnt = 0;
278eef4f27bSRobert Mustacchi 
279eef4f27bSRobert Mustacchi 	umpacket->cpyhdl = NULL;
280eef4f27bSRobert Mustacchi 	umpacket->cpyoff = 0;
281eef4f27bSRobert Mustacchi 	umpacket->cpymem = NULL;
282eef4f27bSRobert Mustacchi }
283eef4f27bSRobert Mustacchi 
284eef4f27bSRobert Mustacchi static int
bnx_xmit_packet(um_device_t * const umdevice,const unsigned int ringidx,um_txpacket_t * const umpacket)285eef4f27bSRobert Mustacchi bnx_xmit_packet(um_device_t * const umdevice, const unsigned int ringidx,
286eef4f27bSRobert Mustacchi     um_txpacket_t * const umpacket)
287eef4f27bSRobert Mustacchi {
288eef4f27bSRobert Mustacchi 	int rc;
289eef4f27bSRobert Mustacchi 	s_list_t *waitq;
290eef4f27bSRobert Mustacchi 	lm_tx_chain_t *txq;
291eef4f27bSRobert Mustacchi 	lm_packet_t *lmpacket;
292eef4f27bSRobert Mustacchi 	lm_device_t *lmdevice;
293eef4f27bSRobert Mustacchi 	lm_frag_list_t *lmfraglist;
294eef4f27bSRobert Mustacchi 
295eef4f27bSRobert Mustacchi 	lmdevice = &(umdevice->lm_dev);
296eef4f27bSRobert Mustacchi 	lmpacket = &(umpacket->lm_pkt);
297eef4f27bSRobert Mustacchi 
298eef4f27bSRobert Mustacchi 	lmfraglist = &(umpacket->frag_list);
299eef4f27bSRobert Mustacchi 	txq = &lmdevice->tx_info.chain[ringidx];
300eef4f27bSRobert Mustacchi 
301eef4f27bSRobert Mustacchi 	/* Try to recycle, if available bd is lower than threshold */
302eef4f27bSRobert Mustacchi 	if (txq->bd_left < BNX_MAX_SGL_ENTRIES) {
303eef4f27bSRobert Mustacchi 		s_list_t xmitpkts;
304eef4f27bSRobert Mustacchi 
305eef4f27bSRobert Mustacchi 		s_list_init(&xmitpkts, NULL, NULL, 0);
306eef4f27bSRobert Mustacchi 
307eef4f27bSRobert Mustacchi 		rc = lm_get_packets_sent(lmdevice, ringidx, 0, &xmitpkts);
308eef4f27bSRobert Mustacchi 
309eef4f27bSRobert Mustacchi 		if (rc) {
310eef4f27bSRobert Mustacchi 			bnx_xmit_ring_reclaim(umdevice, ringidx, &xmitpkts);
311eef4f27bSRobert Mustacchi 		}
312eef4f27bSRobert Mustacchi 	}
313eef4f27bSRobert Mustacchi 
314eef4f27bSRobert Mustacchi 	waitq = &_TXQ_RESC_DESC(umdevice, ringidx);
315eef4f27bSRobert Mustacchi 	if (s_list_is_empty(waitq) && txq->bd_left >= lmfraglist->cnt) {
316eef4f27bSRobert Mustacchi 		(void) lm_send_packet(lmdevice, ringidx, lmpacket, lmfraglist);
317eef4f27bSRobert Mustacchi 
318eef4f27bSRobert Mustacchi 		return (BNX_SEND_GOODXMIT);
319eef4f27bSRobert Mustacchi 	}
320eef4f27bSRobert Mustacchi 
321eef4f27bSRobert Mustacchi 	s_list_push_tail(waitq, &umpacket->lm_pkt.link);
322eef4f27bSRobert Mustacchi 
323eef4f27bSRobert Mustacchi 	if (txq->bd_left >= BNX_MAX_SGL_ENTRIES) {
324eef4f27bSRobert Mustacchi 		rc = bnx_xmit_ring_xmit_qpkt(umdevice, ringidx);
325eef4f27bSRobert Mustacchi 		if (rc == BNX_SEND_GOODXMIT) {
326eef4f27bSRobert Mustacchi 			return (BNX_SEND_GOODXMIT);
327eef4f27bSRobert Mustacchi 		}
328eef4f27bSRobert Mustacchi 	}
329eef4f27bSRobert Mustacchi 
330eef4f27bSRobert Mustacchi 	umdevice->no_tx_credits |= BNX_TX_RESOURCES_NO_CREDIT;
331eef4f27bSRobert Mustacchi 
332eef4f27bSRobert Mustacchi 	return (BNX_SEND_DEFERPKT);
333eef4f27bSRobert Mustacchi }
334eef4f27bSRobert Mustacchi 
335eef4f27bSRobert Mustacchi static int
bnx_xmit_ring_cpybuf_alloc(um_device_t * const umdevice,um_xmit_qinfo * const xmitinfo,unsigned int buffsize)336eef4f27bSRobert Mustacchi bnx_xmit_ring_cpybuf_alloc(um_device_t * const umdevice,
337eef4f27bSRobert Mustacchi     um_xmit_qinfo * const xmitinfo,
338eef4f27bSRobert Mustacchi     unsigned int buffsize)
339eef4f27bSRobert Mustacchi {
340eef4f27bSRobert Mustacchi 	int rc;
341eef4f27bSRobert Mustacchi 	size_t actualsize;
342eef4f27bSRobert Mustacchi 	unsigned int alignedsize;
343eef4f27bSRobert Mustacchi 	unsigned int count;
344eef4f27bSRobert Mustacchi 	ddi_dma_cookie_t cookie;
345eef4f27bSRobert Mustacchi 
346eef4f27bSRobert Mustacchi 	ASSERT(buffsize > 0);
347eef4f27bSRobert Mustacchi 
348eef4f27bSRobert Mustacchi 	alignedsize = buffsize;
349eef4f27bSRobert Mustacchi 	alignedsize += (BNX_DCOPY_ALIGN - 1);
350eef4f27bSRobert Mustacchi 	alignedsize &= ~((unsigned int)(BNX_DCOPY_ALIGN - 1));
351eef4f27bSRobert Mustacchi 
352eef4f27bSRobert Mustacchi 	/* We want double copy buffers to be completely contiguous. */
353eef4f27bSRobert Mustacchi 	rc = ddi_dma_alloc_handle(umdevice->os_param.dip, &bnx_std_dma_attrib,
354eef4f27bSRobert Mustacchi 	    DDI_DMA_DONTWAIT, (void *)0, &xmitinfo->dcpyhndl);
355eef4f27bSRobert Mustacchi 	if (rc != DDI_SUCCESS) {
356eef4f27bSRobert Mustacchi 		cmn_err(CE_WARN,
357eef4f27bSRobert Mustacchi 		    "%s: %s: Failed to alloc phys dma handle.\n",
358eef4f27bSRobert Mustacchi 		    umdevice->dev_name, __func__);
359eef4f27bSRobert Mustacchi 		return (-1);
360eef4f27bSRobert Mustacchi 	}
361eef4f27bSRobert Mustacchi 
362eef4f27bSRobert Mustacchi 	rc = ddi_dma_mem_alloc(xmitinfo->dcpyhndl,
363eef4f27bSRobert Mustacchi 	    alignedsize * xmitinfo->desc_cnt, &bnxAccessAttribBUF,
364eef4f27bSRobert Mustacchi 	    DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, (void *)0,
365eef4f27bSRobert Mustacchi 	    &xmitinfo->dcpyvirt, &actualsize, &xmitinfo->dcpyahdl);
366eef4f27bSRobert Mustacchi 	if (rc != DDI_SUCCESS) {
367eef4f27bSRobert Mustacchi 		cmn_err(CE_WARN,
368eef4f27bSRobert Mustacchi 		    "%s: %s: Failed to alloc phys memory.\n",
369eef4f27bSRobert Mustacchi 		    umdevice->dev_name, __func__);
370eef4f27bSRobert Mustacchi 		goto error1;
371eef4f27bSRobert Mustacchi 	}
372eef4f27bSRobert Mustacchi 
373eef4f27bSRobert Mustacchi 	rc = ddi_dma_addr_bind_handle(xmitinfo->dcpyhndl,
374eef4f27bSRobert Mustacchi 	    (struct as *)0, xmitinfo->dcpyvirt, actualsize,
375eef4f27bSRobert Mustacchi 	    DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, (void *)0,
376eef4f27bSRobert Mustacchi 	    &cookie, &count);
377eef4f27bSRobert Mustacchi 	if (rc != DDI_SUCCESS) {
378eef4f27bSRobert Mustacchi 		cmn_err(CE_WARN,
379eef4f27bSRobert Mustacchi 		    "%s: %s: Failed to bind DMA address.\n",
380eef4f27bSRobert Mustacchi 		    umdevice->dev_name, __func__);
381eef4f27bSRobert Mustacchi 		goto error2;
382eef4f27bSRobert Mustacchi 	}
383eef4f27bSRobert Mustacchi 
384eef4f27bSRobert Mustacchi 	xmitinfo->dcpyhard = alignedsize;
385eef4f27bSRobert Mustacchi 	xmitinfo->dcpyphys.as_u64 = (u64_t)cookie.dmac_laddress;
386eef4f27bSRobert Mustacchi 
387eef4f27bSRobert Mustacchi 	return (0);
388eef4f27bSRobert Mustacchi 
389eef4f27bSRobert Mustacchi error2:
390eef4f27bSRobert Mustacchi 	ddi_dma_mem_free(&xmitinfo->dcpyahdl);
391eef4f27bSRobert Mustacchi 
392eef4f27bSRobert Mustacchi error1:
393eef4f27bSRobert Mustacchi 	ddi_dma_free_handle(&xmitinfo->dcpyhndl);
394eef4f27bSRobert Mustacchi 
395eef4f27bSRobert Mustacchi 	return (-1);
396eef4f27bSRobert Mustacchi }
397eef4f27bSRobert Mustacchi 
398eef4f27bSRobert Mustacchi static void
bnx_xmit_ring_cpybuf_free(um_device_t * const umdevice,um_xmit_qinfo * const xmitinfo)399eef4f27bSRobert Mustacchi bnx_xmit_ring_cpybuf_free(um_device_t * const umdevice,
400eef4f27bSRobert Mustacchi     um_xmit_qinfo * const xmitinfo)
401eef4f27bSRobert Mustacchi {
402eef4f27bSRobert Mustacchi 	(void) ddi_dma_unbind_handle(xmitinfo->dcpyhndl);
403eef4f27bSRobert Mustacchi 	ddi_dma_mem_free(&xmitinfo->dcpyahdl);
404eef4f27bSRobert Mustacchi 	ddi_dma_free_handle(&xmitinfo->dcpyhndl);
405eef4f27bSRobert Mustacchi 
406eef4f27bSRobert Mustacchi 	xmitinfo->dcpyvirt = NULL;
407eef4f27bSRobert Mustacchi 	xmitinfo->dcpyphys.as_u64 = 0;
408eef4f27bSRobert Mustacchi 	xmitinfo->dcpyhard = 0;
409eef4f27bSRobert Mustacchi }
410eef4f27bSRobert Mustacchi 
411eef4f27bSRobert Mustacchi static int
bnx_xmit_ring_init(um_device_t * const umdevice,const unsigned int ringidx)412eef4f27bSRobert Mustacchi bnx_xmit_ring_init(um_device_t * const umdevice, const unsigned int ringidx)
413eef4f27bSRobert Mustacchi {
414eef4f27bSRobert Mustacchi 	int i;
415eef4f27bSRobert Mustacchi 	size_t memsize;
416eef4f27bSRobert Mustacchi 	void *memvirt;
417eef4f27bSRobert Mustacchi 	s_list_t *freeq;
418eef4f27bSRobert Mustacchi 	lm_u64_t memphys;
419eef4f27bSRobert Mustacchi 	um_txpacket_t *umpacket;
420eef4f27bSRobert Mustacchi 	um_xmit_qinfo *xmitinfo;
421eef4f27bSRobert Mustacchi 
422eef4f27bSRobert Mustacchi 	xmitinfo = &_TX_QINFO(umdevice, ringidx);
423eef4f27bSRobert Mustacchi 
424eef4f27bSRobert Mustacchi 	s_list_init(&_TXQ_FREE_DESC(umdevice, ringidx), NULL, NULL, 0);
425eef4f27bSRobert Mustacchi 	s_list_init(&_TXQ_RESC_DESC(umdevice, ringidx), NULL, NULL, 0);
426eef4f27bSRobert Mustacchi 
427eef4f27bSRobert Mustacchi 	if (xmitinfo->desc_cnt == 0) {
428eef4f27bSRobert Mustacchi 		return (0);
429eef4f27bSRobert Mustacchi 	}
430eef4f27bSRobert Mustacchi 
431eef4f27bSRobert Mustacchi 	xmitinfo->thresh_pdwm = BNX_PDWM_THRESHOLD;
432eef4f27bSRobert Mustacchi 
433eef4f27bSRobert Mustacchi 	memsize = xmitinfo->desc_cnt * sizeof (um_txpacket_t);
434eef4f27bSRobert Mustacchi 	memvirt = kmem_zalloc(memsize, KM_NOSLEEP);
435eef4f27bSRobert Mustacchi 	if (memvirt == NULL) {
436eef4f27bSRobert Mustacchi 		cmn_err(CE_WARN, "%s: Failed to allocate TX packet "
437eef4f27bSRobert Mustacchi 		    "descriptor memory (%d).\n", umdevice->dev_name, ringidx);
438eef4f27bSRobert Mustacchi 		return (-1);
439eef4f27bSRobert Mustacchi 	}
440eef4f27bSRobert Mustacchi 
441eef4f27bSRobert Mustacchi 	xmitinfo->desc_mem.addr = memvirt;
442eef4f27bSRobert Mustacchi 	xmitinfo->desc_mem.size = memsize;
443eef4f27bSRobert Mustacchi 
444eef4f27bSRobert Mustacchi 	if (bnx_xmit_ring_cpybuf_alloc(umdevice, xmitinfo,
445eef4f27bSRobert Mustacchi 	    umdevice->dev_var.mtu + sizeof (struct ether_vlan_header))) {
446eef4f27bSRobert Mustacchi 		kmem_free(xmitinfo->desc_mem.addr, xmitinfo->desc_mem.size);
447eef4f27bSRobert Mustacchi 		xmitinfo->desc_mem.addr = NULL;
448eef4f27bSRobert Mustacchi 		xmitinfo->desc_mem.size = 0;
449eef4f27bSRobert Mustacchi 
450eef4f27bSRobert Mustacchi 		return (-1);
451eef4f27bSRobert Mustacchi 	}
452eef4f27bSRobert Mustacchi 
453eef4f27bSRobert Mustacchi 	/*
454eef4f27bSRobert Mustacchi 	 * Driver successfully allocated memory for this transmit queue, now
455eef4f27bSRobert Mustacchi 	 * link them together and place them in the free pool.
456eef4f27bSRobert Mustacchi 	 */
457eef4f27bSRobert Mustacchi 
458eef4f27bSRobert Mustacchi 	freeq = &_TXQ_FREE_DESC(umdevice, ringidx);
459eef4f27bSRobert Mustacchi 	umpacket = (um_txpacket_t *)memvirt;
460eef4f27bSRobert Mustacchi 
461eef4f27bSRobert Mustacchi 	memphys = xmitinfo->dcpyphys;
462eef4f27bSRobert Mustacchi 
463eef4f27bSRobert Mustacchi 	for (i = 0; i < xmitinfo->desc_cnt; i++) {
464eef4f27bSRobert Mustacchi 		if (bnx_xmit_pkt_init(umdevice, umpacket, i, memphys)) {
465eef4f27bSRobert Mustacchi 			break;
466eef4f27bSRobert Mustacchi 		}
467eef4f27bSRobert Mustacchi 
468eef4f27bSRobert Mustacchi 		LM_INC64(&memphys, xmitinfo->dcpyhard);
469eef4f27bSRobert Mustacchi 
470eef4f27bSRobert Mustacchi 		s_list_push_tail(freeq, &umpacket->lm_pkt.link);
471eef4f27bSRobert Mustacchi 
472eef4f27bSRobert Mustacchi 		umpacket++;
473eef4f27bSRobert Mustacchi 	}
474eef4f27bSRobert Mustacchi 
475eef4f27bSRobert Mustacchi 	mutex_init(&xmitinfo->free_mutex, NULL, MUTEX_DRIVER,
476eef4f27bSRobert Mustacchi 	    DDI_INTR_PRI(umdevice->intrPriority));
477eef4f27bSRobert Mustacchi 
478eef4f27bSRobert Mustacchi 	return (0);
479eef4f27bSRobert Mustacchi }
480eef4f27bSRobert Mustacchi 
481eef4f27bSRobert Mustacchi void
bnx_xmit_ring_reclaim(um_device_t * const umdevice,const unsigned int ringidx,s_list_t * srcq)482eef4f27bSRobert Mustacchi bnx_xmit_ring_reclaim(um_device_t * const umdevice,
483eef4f27bSRobert Mustacchi     const unsigned int ringidx, s_list_t *srcq)
484eef4f27bSRobert Mustacchi {
485eef4f27bSRobert Mustacchi 	s_list_t *freeq;
486eef4f27bSRobert Mustacchi 	s_list_entry_t *lmpacket;
487eef4f27bSRobert Mustacchi 	um_txpacket_t *umpacket;
488eef4f27bSRobert Mustacchi 	um_xmit_qinfo *xmitinfo;
489eef4f27bSRobert Mustacchi 
490eef4f27bSRobert Mustacchi 	if (s_list_entry_cnt(srcq) ==  0) {
491eef4f27bSRobert Mustacchi 		return;
492eef4f27bSRobert Mustacchi 	}
493eef4f27bSRobert Mustacchi 
494eef4f27bSRobert Mustacchi 	for (lmpacket = s_list_peek_head(srcq); lmpacket;
495eef4f27bSRobert Mustacchi 	    lmpacket = s_list_next_entry(lmpacket)) {
496eef4f27bSRobert Mustacchi 
497eef4f27bSRobert Mustacchi 		umpacket = (um_txpacket_t *)lmpacket;
498eef4f27bSRobert Mustacchi 
499eef4f27bSRobert Mustacchi 		if (umpacket->num_handles > 0) {
500eef4f27bSRobert Mustacchi 			bnx_xmit_pkt_unmap(umpacket);
501eef4f27bSRobert Mustacchi 		}
502eef4f27bSRobert Mustacchi 
503eef4f27bSRobert Mustacchi 		if (umpacket->mp != NULL) {
504eef4f27bSRobert Mustacchi 			freemsg(umpacket->mp);
505eef4f27bSRobert Mustacchi 			umpacket->mp = NULL;
506eef4f27bSRobert Mustacchi 		}
507eef4f27bSRobert Mustacchi 	}
508eef4f27bSRobert Mustacchi 
509eef4f27bSRobert Mustacchi 	freeq = &_TXQ_FREE_DESC(umdevice, ringidx);
510eef4f27bSRobert Mustacchi 	xmitinfo = &_TX_QINFO(umdevice, ringidx);
511eef4f27bSRobert Mustacchi 
512eef4f27bSRobert Mustacchi 	mutex_enter(&xmitinfo->free_mutex);
513eef4f27bSRobert Mustacchi 	s_list_add_tail(freeq, srcq);
514eef4f27bSRobert Mustacchi 	mutex_exit(&xmitinfo->free_mutex);
515eef4f27bSRobert Mustacchi 
516eef4f27bSRobert Mustacchi }
517eef4f27bSRobert Mustacchi 
518eef4f27bSRobert Mustacchi int
bnx_xmit_ring_xmit_qpkt(um_device_t * const umdevice,const unsigned int ringidx)519eef4f27bSRobert Mustacchi bnx_xmit_ring_xmit_qpkt(um_device_t * const umdevice,
520eef4f27bSRobert Mustacchi     const unsigned int ringidx)
521eef4f27bSRobert Mustacchi {
522eef4f27bSRobert Mustacchi 	s_list_t *waitq;
523eef4f27bSRobert Mustacchi 	lm_tx_chain_t *txq;
524eef4f27bSRobert Mustacchi 	lm_packet_t *lmpacket;
525eef4f27bSRobert Mustacchi 	lm_device_t *lmdevice;
526eef4f27bSRobert Mustacchi 	lm_frag_list_t *lmfraglist;
527eef4f27bSRobert Mustacchi 	um_txpacket_t *umpacket;
528eef4f27bSRobert Mustacchi 	int rc = 0;
529eef4f27bSRobert Mustacchi 
530eef4f27bSRobert Mustacchi 	lmdevice = &(umdevice->lm_dev);
531eef4f27bSRobert Mustacchi 	waitq = &_TXQ_RESC_DESC(umdevice, ringidx);
532eef4f27bSRobert Mustacchi 	txq = &lmdevice->tx_info.chain[ringidx];
533eef4f27bSRobert Mustacchi 
534eef4f27bSRobert Mustacchi 	while (s_list_entry_cnt(waitq)) {
535eef4f27bSRobert Mustacchi 		umpacket = (um_txpacket_t *)s_list_peek_head(waitq);
536eef4f27bSRobert Mustacchi 		lmfraglist = &(umpacket->frag_list);
537eef4f27bSRobert Mustacchi 
538eef4f27bSRobert Mustacchi 		if (lmfraglist->cnt > txq->bd_left) {
539eef4f27bSRobert Mustacchi 			rc = BNX_SEND_DEFERPKT;
540eef4f27bSRobert Mustacchi 			break;
541eef4f27bSRobert Mustacchi 		}
542eef4f27bSRobert Mustacchi 
543eef4f27bSRobert Mustacchi 		umpacket = (um_txpacket_t *)s_list_pop_head(waitq);
544eef4f27bSRobert Mustacchi 		lmpacket = &(umpacket->lm_pkt);
545eef4f27bSRobert Mustacchi 
546eef4f27bSRobert Mustacchi 		/*
547eef4f27bSRobert Mustacchi 		 * The main way that this can fail is in the check we just
548eef4f27bSRobert Mustacchi 		 * performed around the fragment list versus txq, so we ignore
549eef4f27bSRobert Mustacchi 		 * the return value.
550eef4f27bSRobert Mustacchi 		 */
551eef4f27bSRobert Mustacchi 		(void) lm_send_packet(lmdevice, ringidx, lmpacket, lmfraglist);
552eef4f27bSRobert Mustacchi 	}
553eef4f27bSRobert Mustacchi 
554eef4f27bSRobert Mustacchi 	return (rc);
555eef4f27bSRobert Mustacchi }
556eef4f27bSRobert Mustacchi 
557eef4f27bSRobert Mustacchi int
bnx_xmit_ring_xmit_mblk(um_device_t * const umdevice,const unsigned int ringidx,mblk_t * mp)558eef4f27bSRobert Mustacchi bnx_xmit_ring_xmit_mblk(um_device_t * const umdevice,
559eef4f27bSRobert Mustacchi     const unsigned int ringidx, mblk_t *mp)
560eef4f27bSRobert Mustacchi {
561eef4f27bSRobert Mustacchi 	int rc;
562eef4f27bSRobert Mustacchi 	uint32_t pflags;
563eef4f27bSRobert Mustacchi 	s_list_t *txfreeq;
564eef4f27bSRobert Mustacchi 	lm_packet_t *lmpacket;
565eef4f27bSRobert Mustacchi 	um_txpacket_t *umpacket;
566eef4f27bSRobert Mustacchi 	um_xmit_qinfo *xmitinfo;
567eef4f27bSRobert Mustacchi 
568eef4f27bSRobert Mustacchi 	xmitinfo = &_TX_QINFO(umdevice, ringidx);
569eef4f27bSRobert Mustacchi 
570eef4f27bSRobert Mustacchi 	txfreeq = &_TXQ_FREE_DESC(umdevice, ringidx);
571eef4f27bSRobert Mustacchi 
572eef4f27bSRobert Mustacchi 	mutex_enter(&xmitinfo->free_mutex);
573eef4f27bSRobert Mustacchi 	umpacket = (um_txpacket_t *)s_list_pop_head(txfreeq);
574eef4f27bSRobert Mustacchi 	mutex_exit(&xmitinfo->free_mutex);
575eef4f27bSRobert Mustacchi 
576eef4f27bSRobert Mustacchi 	/* Try to recycle, if no more packet available */
577eef4f27bSRobert Mustacchi 	if (umpacket == NULL) {
578eef4f27bSRobert Mustacchi 		s_list_t  xmitpkts;
579eef4f27bSRobert Mustacchi 		lm_device_t *lmdevice;
580eef4f27bSRobert Mustacchi 
581eef4f27bSRobert Mustacchi 		lmdevice = &(umdevice->lm_dev);
582eef4f27bSRobert Mustacchi 
583eef4f27bSRobert Mustacchi 		s_list_init(&xmitpkts, NULL, NULL, 0);
584eef4f27bSRobert Mustacchi 
585eef4f27bSRobert Mustacchi 		mutex_enter(&umdevice->os_param.xmit_mutex);
586eef4f27bSRobert Mustacchi 		rc = lm_get_packets_sent(lmdevice, ringidx, 0, &xmitpkts);
587eef4f27bSRobert Mustacchi 		if (rc == 0) {
588eef4f27bSRobert Mustacchi 			umdevice->no_tx_credits |= BNX_TX_RESOURCES_NO_DESC;
589eef4f27bSRobert Mustacchi 
590eef4f27bSRobert Mustacchi 			mutex_exit(&umdevice->os_param.xmit_mutex);
591eef4f27bSRobert Mustacchi 			return (BNX_SEND_HDWRFULL);
592eef4f27bSRobert Mustacchi 		}
593eef4f27bSRobert Mustacchi 		mutex_exit(&umdevice->os_param.xmit_mutex);
594eef4f27bSRobert Mustacchi 
595eef4f27bSRobert Mustacchi 		umpacket = (um_txpacket_t *)s_list_pop_head(&xmitpkts);
596eef4f27bSRobert Mustacchi 		if (umpacket->num_handles > 0) {
597eef4f27bSRobert Mustacchi 			bnx_xmit_pkt_unmap(umpacket);
598eef4f27bSRobert Mustacchi 		}
599eef4f27bSRobert Mustacchi 		if (umpacket->mp != NULL) {
600eef4f27bSRobert Mustacchi 			freemsg(umpacket->mp);
601eef4f27bSRobert Mustacchi 			umpacket->mp = NULL;
602eef4f27bSRobert Mustacchi 		}
603eef4f27bSRobert Mustacchi 
604eef4f27bSRobert Mustacchi 		/* clean up resources */
605eef4f27bSRobert Mustacchi 		bnx_xmit_ring_reclaim(umdevice, ringidx, &xmitpkts);
606eef4f27bSRobert Mustacchi 	}
607eef4f27bSRobert Mustacchi 
608eef4f27bSRobert Mustacchi 	umpacket->lm_pkt.link.next = NULL;
609eef4f27bSRobert Mustacchi 	ASSERT(umpacket->mp == NULL);
610eef4f27bSRobert Mustacchi 	ASSERT(umpacket->num_handles == 0);
611eef4f27bSRobert Mustacchi 	umpacket->frag_list.cnt = 0;
612eef4f27bSRobert Mustacchi 	umpacket->mp = mp;
613eef4f27bSRobert Mustacchi 
614*ec71f88eSPatrick Mooney 	mac_hcksum_get(mp, NULL, NULL, NULL, NULL, &pflags);
615eef4f27bSRobert Mustacchi 
616eef4f27bSRobert Mustacchi 	bnx_xmit_pkt_cpy(umdevice, umpacket);
617eef4f27bSRobert Mustacchi 
618eef4f27bSRobert Mustacchi 	lmpacket = &(umpacket->lm_pkt);
619eef4f27bSRobert Mustacchi 
620eef4f27bSRobert Mustacchi 	lmpacket->u1.tx.flags   = 0;
621eef4f27bSRobert Mustacchi 	lmpacket->u1.tx.lso_mss = 0;
622eef4f27bSRobert Mustacchi 
623eef4f27bSRobert Mustacchi 	lmpacket->u1.tx.vlan_tag = 0;
624eef4f27bSRobert Mustacchi 
625eef4f27bSRobert Mustacchi 	if (pflags & HCK_IPV4_HDRCKSUM) {
626eef4f27bSRobert Mustacchi 		lmpacket->u1.tx.flags |= LM_TX_FLAG_COMPUTE_IP_CKSUM;
627eef4f27bSRobert Mustacchi 	}
628eef4f27bSRobert Mustacchi 
629eef4f27bSRobert Mustacchi 	if (pflags & HCK_FULLCKSUM) {
630eef4f27bSRobert Mustacchi 		lmpacket->u1.tx.flags |= LM_TX_FLAG_COMPUTE_TCP_UDP_CKSUM;
631eef4f27bSRobert Mustacchi 	}
632eef4f27bSRobert Mustacchi 
633eef4f27bSRobert Mustacchi 	mutex_enter(&umdevice->os_param.xmit_mutex);
634eef4f27bSRobert Mustacchi 	rc = bnx_xmit_packet(umdevice, ringidx, umpacket);
635eef4f27bSRobert Mustacchi 	mutex_exit(&umdevice->os_param.xmit_mutex);
636eef4f27bSRobert Mustacchi 
637eef4f27bSRobert Mustacchi 	return (rc);
638eef4f27bSRobert Mustacchi }
639eef4f27bSRobert Mustacchi 
640eef4f27bSRobert Mustacchi void
bnx_xmit_ring_intr(um_device_t * const umdevice,const unsigned int ringidx)641eef4f27bSRobert Mustacchi bnx_xmit_ring_intr(um_device_t * const umdevice, const unsigned int ringidx)
642eef4f27bSRobert Mustacchi {
643eef4f27bSRobert Mustacchi 	u32_t rc;
644eef4f27bSRobert Mustacchi 	s_list_t xmitpkts;
645eef4f27bSRobert Mustacchi 	lm_device_t *lmdevice;
646eef4f27bSRobert Mustacchi 
647eef4f27bSRobert Mustacchi 	lmdevice = &(umdevice->lm_dev);
648eef4f27bSRobert Mustacchi 
649eef4f27bSRobert Mustacchi 	s_list_init(&xmitpkts, NULL, NULL, 0);
650eef4f27bSRobert Mustacchi 
651eef4f27bSRobert Mustacchi 	mutex_enter(&umdevice->os_param.xmit_mutex);
652eef4f27bSRobert Mustacchi 
653eef4f27bSRobert Mustacchi 	rc = lm_get_packets_sent(lmdevice, ringidx, 0, &xmitpkts);
654eef4f27bSRobert Mustacchi 
655eef4f27bSRobert Mustacchi 	mutex_exit(&umdevice->os_param.xmit_mutex);
656eef4f27bSRobert Mustacchi 
657eef4f27bSRobert Mustacchi 	if (rc) {
658eef4f27bSRobert Mustacchi 		bnx_xmit_ring_reclaim(umdevice, ringidx, &xmitpkts);
659eef4f27bSRobert Mustacchi 	}
660eef4f27bSRobert Mustacchi }
661eef4f27bSRobert Mustacchi 
662eef4f27bSRobert Mustacchi void
bnx_xmit_ring_post(um_device_t * const umdevice,const unsigned int ringidx)663eef4f27bSRobert Mustacchi bnx_xmit_ring_post(um_device_t * const umdevice, const unsigned int ringidx)
664eef4f27bSRobert Mustacchi {
665eef4f27bSRobert Mustacchi 	int rc;
666eef4f27bSRobert Mustacchi 	s_list_t *freeq;
667eef4f27bSRobert Mustacchi 	lm_device_t *lmdevice;
668eef4f27bSRobert Mustacchi 	um_xmit_qinfo *xmitinfo;
669eef4f27bSRobert Mustacchi 	lm_tx_chain_t *lmtxring;
670eef4f27bSRobert Mustacchi 
671eef4f27bSRobert Mustacchi 	if (umdevice->no_tx_credits != 0) {
672eef4f27bSRobert Mustacchi 		if (umdevice->no_tx_credits & BNX_TX_RESOURCES_NO_CREDIT) {
673eef4f27bSRobert Mustacchi 			rc = bnx_xmit_ring_xmit_qpkt(umdevice, ringidx);
674eef4f27bSRobert Mustacchi 
675eef4f27bSRobert Mustacchi 			if (rc == BNX_SEND_GOODXMIT) {
676eef4f27bSRobert Mustacchi 				lmdevice = &(umdevice->lm_dev);
677eef4f27bSRobert Mustacchi 				lmtxring = &(lmdevice->tx_info.chain[ringidx]);
678eef4f27bSRobert Mustacchi 
679eef4f27bSRobert Mustacchi 				if (lmtxring->bd_left >= BNX_MAX_SGL_ENTRIES) {
680eef4f27bSRobert Mustacchi 					umdevice->no_tx_credits &=
681eef4f27bSRobert Mustacchi 					    ~BNX_TX_RESOURCES_NO_CREDIT;
682eef4f27bSRobert Mustacchi 				}
683eef4f27bSRobert Mustacchi 			}
684eef4f27bSRobert Mustacchi 		}
685eef4f27bSRobert Mustacchi 
686eef4f27bSRobert Mustacchi 		if (umdevice->no_tx_credits & BNX_TX_RESOURCES_NO_DESC) {
687eef4f27bSRobert Mustacchi 			freeq = &_TXQ_FREE_DESC(umdevice, ringidx);
688eef4f27bSRobert Mustacchi 			xmitinfo = &_TX_QINFO(umdevice, ringidx);
689eef4f27bSRobert Mustacchi 
690eef4f27bSRobert Mustacchi 			if (s_list_entry_cnt(freeq) > xmitinfo->thresh_pdwm) {
691eef4f27bSRobert Mustacchi 				umdevice->no_tx_credits &=
692eef4f27bSRobert Mustacchi 				    ~BNX_TX_RESOURCES_NO_DESC;
693eef4f27bSRobert Mustacchi 			}
694eef4f27bSRobert Mustacchi 		}
695eef4f27bSRobert Mustacchi 
696eef4f27bSRobert Mustacchi 		if (umdevice->no_tx_credits == 0) {
697eef4f27bSRobert Mustacchi 			mac_tx_update(umdevice->os_param.macp);
698eef4f27bSRobert Mustacchi 		}
699eef4f27bSRobert Mustacchi 	}
700eef4f27bSRobert Mustacchi }
701eef4f27bSRobert Mustacchi 
702eef4f27bSRobert Mustacchi static void
bnx_xmit_ring_fini(um_device_t * const umdevice,const unsigned int ringidx)703eef4f27bSRobert Mustacchi bnx_xmit_ring_fini(um_device_t * const umdevice, const unsigned int ringidx)
704eef4f27bSRobert Mustacchi {
705eef4f27bSRobert Mustacchi 	s_list_t *srcq;
706eef4f27bSRobert Mustacchi 	um_txpacket_t *umpacket;
707eef4f27bSRobert Mustacchi 	um_xmit_qinfo *xmitinfo;
708eef4f27bSRobert Mustacchi 
709eef4f27bSRobert Mustacchi 	xmitinfo = &_TX_QINFO(umdevice, ringidx);
710eef4f27bSRobert Mustacchi 
711eef4f27bSRobert Mustacchi 	mutex_destroy(&xmitinfo->free_mutex);
712eef4f27bSRobert Mustacchi 
713eef4f27bSRobert Mustacchi 	srcq = &_TXQ_FREE_DESC(umdevice, ringidx);
714eef4f27bSRobert Mustacchi 
715eef4f27bSRobert Mustacchi 	/* CONSTANTCONDITION */
716eef4f27bSRobert Mustacchi 	/* Pop all the packet descriptors off the free list and discard them. */
717eef4f27bSRobert Mustacchi 	while (1) {
718eef4f27bSRobert Mustacchi 		umpacket = (um_txpacket_t *)s_list_pop_head(srcq);
719eef4f27bSRobert Mustacchi 		if (umpacket == NULL) {
720eef4f27bSRobert Mustacchi 			break;
721eef4f27bSRobert Mustacchi 		}
722eef4f27bSRobert Mustacchi 
723eef4f27bSRobert Mustacchi 		bnx_xmit_pkt_fini(umpacket);
724eef4f27bSRobert Mustacchi 	}
725eef4f27bSRobert Mustacchi 
726eef4f27bSRobert Mustacchi 	bnx_xmit_ring_cpybuf_free(umdevice, xmitinfo);
727eef4f27bSRobert Mustacchi 
728eef4f27bSRobert Mustacchi 	kmem_free(xmitinfo->desc_mem.addr, xmitinfo->desc_mem.size);
729eef4f27bSRobert Mustacchi 	xmitinfo->desc_mem.addr = NULL;
730eef4f27bSRobert Mustacchi 	xmitinfo->desc_mem.size = 0;
731eef4f27bSRobert Mustacchi }
732eef4f27bSRobert Mustacchi 
733eef4f27bSRobert Mustacchi int
bnx_txpkts_init(um_device_t * const umdevice)734eef4f27bSRobert Mustacchi bnx_txpkts_init(um_device_t * const umdevice)
735eef4f27bSRobert Mustacchi {
736eef4f27bSRobert Mustacchi 	int i;
737eef4f27bSRobert Mustacchi 	int alloccnt;
738eef4f27bSRobert Mustacchi 	um_xmit_qinfo *xmitinfo;
739eef4f27bSRobert Mustacchi 
740eef4f27bSRobert Mustacchi 	xmitinfo = &_TX_QINFO(umdevice, 0);
741eef4f27bSRobert Mustacchi 
742eef4f27bSRobert Mustacchi 	mutex_init(&umdevice->os_param.xmit_mutex, NULL,
743eef4f27bSRobert Mustacchi 	    MUTEX_DRIVER, DDI_INTR_PRI(umdevice->intrPriority));
744eef4f27bSRobert Mustacchi 
745eef4f27bSRobert Mustacchi 	alloccnt = 0;
746eef4f27bSRobert Mustacchi 
747eef4f27bSRobert Mustacchi 	/* Allocate packet descriptors for the TX queue. */
748eef4f27bSRobert Mustacchi 	for (i = TX_CHAIN_IDX0; i < NUM_TX_CHAIN; i++) {
749eef4f27bSRobert Mustacchi 		int desc_cnt;
750eef4f27bSRobert Mustacchi 
751eef4f27bSRobert Mustacchi 		if (bnx_xmit_ring_init(umdevice, i)) {
752eef4f27bSRobert Mustacchi 			goto error;
753eef4f27bSRobert Mustacchi 		}
754eef4f27bSRobert Mustacchi 
755eef4f27bSRobert Mustacchi 		desc_cnt = s_list_entry_cnt(&_TXQ_FREE_DESC(umdevice, i));
756eef4f27bSRobert Mustacchi 
757eef4f27bSRobert Mustacchi 		if (desc_cnt != xmitinfo->desc_cnt) {
758eef4f27bSRobert Mustacchi 			cmn_err(CE_NOTE,
759eef4f27bSRobert Mustacchi 			    "%s: %d tx buffers requested.  %d allocated.\n",
760eef4f27bSRobert Mustacchi 			    umdevice->dev_name, xmitinfo->desc_cnt, desc_cnt);
761eef4f27bSRobert Mustacchi 		}
762eef4f27bSRobert Mustacchi 
763eef4f27bSRobert Mustacchi 		alloccnt += desc_cnt;
764eef4f27bSRobert Mustacchi 	}
765eef4f27bSRobert Mustacchi 
766eef4f27bSRobert Mustacchi 	/* FIXME -- Review TX buffer allocation failure threshold. */
767eef4f27bSRobert Mustacchi 	if (alloccnt < BNX_XMIT_INIT_FAIL_THRESH) {
768eef4f27bSRobert Mustacchi 		cmn_err(CE_WARN,
769eef4f27bSRobert Mustacchi 		    "%s: Failed to allocate minimum number of TX buffers.\n",
770eef4f27bSRobert Mustacchi 		    umdevice->dev_name);
771eef4f27bSRobert Mustacchi 
772eef4f27bSRobert Mustacchi 		goto error;
773eef4f27bSRobert Mustacchi 	}
774eef4f27bSRobert Mustacchi 
775eef4f27bSRobert Mustacchi 	return (0);
776eef4f27bSRobert Mustacchi 
777eef4f27bSRobert Mustacchi error:
778eef4f27bSRobert Mustacchi 	for (i--; i >= TX_CHAIN_IDX0; i--) {
779eef4f27bSRobert Mustacchi 		bnx_xmit_ring_fini(umdevice, i);
780eef4f27bSRobert Mustacchi 	}
781eef4f27bSRobert Mustacchi 
782eef4f27bSRobert Mustacchi 	mutex_destroy(&umdevice->os_param.xmit_mutex);
783eef4f27bSRobert Mustacchi 
784eef4f27bSRobert Mustacchi 	return (-1);
785eef4f27bSRobert Mustacchi }
786eef4f27bSRobert Mustacchi 
787eef4f27bSRobert Mustacchi void
bnx_txpkts_flush(um_device_t * const umdevice)788eef4f27bSRobert Mustacchi bnx_txpkts_flush(um_device_t * const umdevice)
789eef4f27bSRobert Mustacchi {
790eef4f27bSRobert Mustacchi 	int i;
791eef4f27bSRobert Mustacchi 	boolean_t notx_fl = B_FALSE;
792eef4f27bSRobert Mustacchi 
793eef4f27bSRobert Mustacchi 	for (i = NUM_TX_CHAIN - 1; i >= TX_CHAIN_IDX0; i--) {
794eef4f27bSRobert Mustacchi 		lm_abort(&(umdevice->lm_dev), ABORT_OP_TX_CHAIN, i);
795eef4f27bSRobert Mustacchi 
796eef4f27bSRobert Mustacchi 		bnx_xmit_ring_reclaim(umdevice, i,
797eef4f27bSRobert Mustacchi 		    &_TXQ_RESC_DESC(umdevice, i));
798eef4f27bSRobert Mustacchi 
799eef4f27bSRobert Mustacchi 		s_list_init(&_TXQ_RESC_DESC(umdevice, i), NULL, NULL, 0);
800eef4f27bSRobert Mustacchi 
801eef4f27bSRobert Mustacchi 		if (umdevice->no_tx_credits & BNX_TX_RESOURCES_NO_CREDIT) {
802eef4f27bSRobert Mustacchi 			umdevice->no_tx_credits &= ~BNX_TX_RESOURCES_NO_CREDIT;
803eef4f27bSRobert Mustacchi 			notx_fl = B_TRUE;
804eef4f27bSRobert Mustacchi 		}
805eef4f27bSRobert Mustacchi 		if (umdevice->no_tx_credits & BNX_TX_RESOURCES_NO_DESC) {
806eef4f27bSRobert Mustacchi 			umdevice->no_tx_credits &= ~BNX_TX_RESOURCES_NO_DESC;
807eef4f27bSRobert Mustacchi 			notx_fl = B_TRUE;
808eef4f27bSRobert Mustacchi 		}
809eef4f27bSRobert Mustacchi 		if (umdevice->no_tx_credits == 0 && notx_fl == B_TRUE) {
810eef4f27bSRobert Mustacchi 			mac_tx_update(umdevice->os_param.macp);
811eef4f27bSRobert Mustacchi 		}
812eef4f27bSRobert Mustacchi 	}
813eef4f27bSRobert Mustacchi }
814eef4f27bSRobert Mustacchi 
815eef4f27bSRobert Mustacchi void
bnx_txpkts_intr(um_device_t * const umdevice)816eef4f27bSRobert Mustacchi bnx_txpkts_intr(um_device_t * const umdevice)
817eef4f27bSRobert Mustacchi {
818eef4f27bSRobert Mustacchi 	int i;
819eef4f27bSRobert Mustacchi 
820eef4f27bSRobert Mustacchi 	for (i = TX_CHAIN_IDX0; i < NUM_TX_CHAIN; i++) {
821eef4f27bSRobert Mustacchi 		bnx_xmit_ring_post(umdevice, i);
822eef4f27bSRobert Mustacchi 	}
823eef4f27bSRobert Mustacchi }
824eef4f27bSRobert Mustacchi 
825eef4f27bSRobert Mustacchi void
bnx_txpkts_fini(um_device_t * const umdevice)826eef4f27bSRobert Mustacchi bnx_txpkts_fini(um_device_t * const umdevice)
827eef4f27bSRobert Mustacchi {
828eef4f27bSRobert Mustacchi 	int i;
829eef4f27bSRobert Mustacchi 
830eef4f27bSRobert Mustacchi 	for (i = NUM_TX_CHAIN - 1; i >= TX_CHAIN_IDX0; i--) {
831eef4f27bSRobert Mustacchi 		bnx_xmit_ring_fini(umdevice, i);
832eef4f27bSRobert Mustacchi 	}
833eef4f27bSRobert Mustacchi 
834eef4f27bSRobert Mustacchi 	mutex_destroy(&umdevice->os_param.xmit_mutex);
835eef4f27bSRobert Mustacchi }
836