1227569Sphilip/*-
2227569Sphilip * Copyright 2007-2009 Solarflare Communications Inc.  All rights reserved.
3227569Sphilip *
4227569Sphilip * Redistribution and use in source and binary forms, with or without
5227569Sphilip * modification, are permitted provided that the following conditions
6227569Sphilip * are met:
7227569Sphilip * 1. Redistributions of source code must retain the above copyright
8227569Sphilip *    notice, this list of conditions and the following disclaimer.
9227569Sphilip * 2. Redistributions in binary form must reproduce the above copyright
10227569Sphilip *    notice, this list of conditions and the following disclaimer in the
11227569Sphilip *    documentation and/or other materials provided with the distribution.
12227569Sphilip *
13227569Sphilip * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
14227569Sphilip * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15227569Sphilip * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16227569Sphilip * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17227569Sphilip * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18227569Sphilip * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19227569Sphilip * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20227569Sphilip * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21227569Sphilip * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22227569Sphilip * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23227569Sphilip * SUCH DAMAGE.
24227569Sphilip */
25227569Sphilip
26228078Sphilip#include <sys/cdefs.h>
27228078Sphilip__FBSDID("$FreeBSD$");
28228078Sphilip
29227569Sphilip#include "efsys.h"
30227569Sphilip#include "efx.h"
31227569Sphilip#include "efx_types.h"
32227569Sphilip#include "efx_regs.h"
33227569Sphilip#include "efx_impl.h"
34227569Sphilip
35227569Sphilip#if EFSYS_OPT_QSTATS
36227569Sphilip#define	EFX_TX_QSTAT_INCR(_etp, _stat)					\
37227569Sphilip	do {								\
38227569Sphilip		(_etp)->et_stat[_stat]++;				\
39227569Sphilip	_NOTE(CONSTANTCONDITION)					\
40227569Sphilip	} while (B_FALSE)
41227569Sphilip#else
42227569Sphilip#define	EFX_TX_QSTAT_INCR(_etp, _stat)
43227569Sphilip#endif
44227569Sphilip
45227569Sphilip	__checkReturn	int
46227569Sphilipefx_tx_init(
47227569Sphilip	__in		efx_nic_t *enp)
48227569Sphilip{
49227569Sphilip	efx_oword_t oword;
50227569Sphilip	int rc;
51227569Sphilip
52227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
53227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
54227569Sphilip
55227569Sphilip	if (!(enp->en_mod_flags & EFX_MOD_EV)) {
56227569Sphilip		rc = EINVAL;
57227569Sphilip		goto fail1;
58227569Sphilip	}
59227569Sphilip
60227569Sphilip	if (enp->en_mod_flags & EFX_MOD_TX) {
61227569Sphilip		rc = EINVAL;
62227569Sphilip		goto fail2;
63227569Sphilip	}
64227569Sphilip
65227569Sphilip	EFSYS_ASSERT3U(enp->en_tx_qcount, ==, 0);
66227569Sphilip
67227569Sphilip	/*
68227569Sphilip	 * Disable the timer-based TX DMA backoff and allow TX DMA to be
69227569Sphilip	 * controlled by the RX FIFO fill level (although always allow a
70227569Sphilip	 * minimal trickle).
71227569Sphilip	 */
72227569Sphilip	EFX_BAR_READO(enp, FR_AZ_TX_RESERVED_REG, &oword);
73227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_RX_SPACER, 0xfe);
74227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_RX_SPACER_EN, 1);
75227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_ONE_PKT_PER_Q, 1);
76227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_PUSH_EN, 0);
77227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DIS_NON_IP_EV, 1);
78227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_PREF_THRESHOLD, 2);
79227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_PREF_WD_TMR, 0x3fffff);
80227569Sphilip
81227569Sphilip	/*
82227569Sphilip	 * Filter all packets less than 14 bytes to avoid parsing
83227569Sphilip	 * errors.
84227569Sphilip	 */
85227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1);
86227569Sphilip	EFX_BAR_WRITEO(enp, FR_AZ_TX_RESERVED_REG, &oword);
87227569Sphilip
88227569Sphilip	/*
89227569Sphilip	 * Do not set TX_NO_EOP_DISC_EN, since it limits packets to 16
90227569Sphilip	 * descriptors (which is bad).
91227569Sphilip	 */
92227569Sphilip	EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword);
93227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_NO_EOP_DISC_EN, 0);
94227569Sphilip	EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword);
95227569Sphilip
96227569Sphilip	enp->en_mod_flags |= EFX_MOD_TX;
97227569Sphilip	return (0);
98227569Sphilip
99227569Sphilipfail2:
100227569Sphilip	EFSYS_PROBE(fail2);
101227569Sphilipfail1:
102227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
103227569Sphilip
104227569Sphilip	return (rc);
105227569Sphilip}
106227569Sphilip
107227569Sphilip#if EFSYS_OPT_FILTER
108227569Sphilipextern	__checkReturn	int
109227569Sphilipefx_tx_filter_insert(
110227569Sphilip	__in		efx_txq_t *etp,
111227569Sphilip	__inout		efx_filter_spec_t *spec)
112227569Sphilip{
113227569Sphilip	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
114227569Sphilip	EFSYS_ASSERT3P(spec, !=, NULL);
115227569Sphilip
116227569Sphilip	spec->efs_dmaq_id = (uint16_t)etp->et_index;
117227569Sphilip	return efx_filter_insert_filter(etp->et_enp, spec, B_FALSE);
118227569Sphilip}
119227569Sphilip#endif
120227569Sphilip
121227569Sphilip#if EFSYS_OPT_FILTER
122227569Sphilipextern	__checkReturn	int
123227569Sphilipefx_tx_filter_remove(
124227569Sphilip	__in		efx_txq_t *etp,
125227569Sphilip	__inout		efx_filter_spec_t *spec)
126227569Sphilip{
127227569Sphilip	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
128227569Sphilip	EFSYS_ASSERT3P(spec, !=, NULL);
129227569Sphilip
130227569Sphilip	spec->efs_dmaq_id = (uint16_t)etp->et_index;
131227569Sphilip	return efx_filter_remove_filter(etp->et_enp, spec);
132227569Sphilip}
133227569Sphilip#endif
134227569Sphilip
135227569Sphilip#define	EFX_TX_DESC(_etp, _addr, _size, _eop, _added)			\
136227569Sphilip	do {								\
137227569Sphilip		unsigned int id;					\
138227569Sphilip		size_t offset;						\
139227569Sphilip		efx_qword_t qword;					\
140227569Sphilip									\
141227569Sphilip		id = (_added)++ & (_etp)->et_mask;			\
142227569Sphilip		offset = id * sizeof (efx_qword_t);			\
143227569Sphilip									\
144227569Sphilip		EFSYS_PROBE5(tx_post, unsigned int, (_etp)->et_index,	\
145227569Sphilip		    unsigned int, id, efsys_dma_addr_t, (_addr),	\
146227569Sphilip		    size_t, (_size), boolean_t, (_eop));		\
147227569Sphilip									\
148227569Sphilip		EFX_POPULATE_QWORD_4(qword,				\
149227569Sphilip		    FSF_AZ_TX_KER_CONT, (_eop) ? 0 : 1,			\
150227569Sphilip		    FSF_AZ_TX_KER_BYTE_COUNT, (uint32_t)(_size),	\
151227569Sphilip		    FSF_AZ_TX_KER_BUF_ADDR_DW0,				\
152227569Sphilip		    (uint32_t)((_addr) & 0xffffffff),			\
153227569Sphilip		    FSF_AZ_TX_KER_BUF_ADDR_DW1,				\
154227569Sphilip		    (uint32_t)((_addr) >> 32));				\
155227569Sphilip		EFSYS_MEM_WRITEQ((_etp)->et_esmp, offset, &qword);	\
156227569Sphilip									\
157227569Sphilip		_NOTE(CONSTANTCONDITION)				\
158227569Sphilip	} while (B_FALSE)
159227569Sphilip
160227569Sphilip	__checkReturn	int
161227569Sphilipefx_tx_qpost(
162227569Sphilip	__in		efx_txq_t *etp,
163227569Sphilip	__in_ecount(n)	efx_buffer_t *eb,
164227569Sphilip	__in		unsigned int n,
165227569Sphilip	__in		unsigned int completed,
166227569Sphilip	__inout		unsigned int *addedp)
167227569Sphilip{
168227569Sphilip	unsigned int added = *addedp;
169227569Sphilip	unsigned int i;
170227569Sphilip	int rc = ENOSPC;
171227569Sphilip
172227569Sphilip	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
173227569Sphilip
174227569Sphilip	if (added - completed + n > EFX_TXQ_LIMIT(etp->et_mask + 1))
175227569Sphilip		goto fail1;
176227569Sphilip
177227569Sphilip	for (i = 0; i < n; i++) {
178227569Sphilip		efx_buffer_t *ebp = &eb[i];
179227569Sphilip		efsys_dma_addr_t start = ebp->eb_addr;
180227569Sphilip		size_t size = ebp->eb_size;
181227569Sphilip		efsys_dma_addr_t end = start + size;
182227569Sphilip
183227569Sphilip		/* Fragments must not span 4k boundaries. */
184227569Sphilip		EFSYS_ASSERT(P2ROUNDUP(start + 1, 4096) >= end);
185227569Sphilip
186227569Sphilip		EFX_TX_DESC(etp, start, size, ebp->eb_eop, added);
187227569Sphilip	}
188227569Sphilip
189227569Sphilip	EFX_TX_QSTAT_INCR(etp, TX_POST);
190227569Sphilip
191227569Sphilip	*addedp = added;
192227569Sphilip	return (0);
193227569Sphilip
194227569Sphilipfail1:
195227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
196227569Sphilip
197227569Sphilip	return (rc);
198227569Sphilip}
199227569Sphilip
200227569Sphilip		void
201227569Sphilipefx_tx_qpush(
202227569Sphilip	__in	efx_txq_t *etp,
203227569Sphilip	__in	unsigned int added)
204227569Sphilip{
205227569Sphilip	efx_nic_t *enp = etp->et_enp;
206227569Sphilip	uint32_t wptr;
207227569Sphilip	efx_dword_t dword;
208227569Sphilip	efx_oword_t oword;
209227569Sphilip
210227569Sphilip	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
211227569Sphilip
212227569Sphilip	/* Guarantee ordering of memory (descriptors) and PIO (doorbell) */
213227569Sphilip	EFSYS_PIO_WRITE_BARRIER();
214227569Sphilip
215227569Sphilip	/* Push the populated descriptors out */
216227569Sphilip	wptr = added & etp->et_mask;
217227569Sphilip
218227569Sphilip	EFX_POPULATE_OWORD_1(oword, FRF_AZ_TX_DESC_WPTR, wptr);
219227569Sphilip
220227569Sphilip	/* Only write the third DWORD */
221227569Sphilip	EFX_POPULATE_DWORD_1(dword,
222227569Sphilip	    EFX_DWORD_0, EFX_OWORD_FIELD(oword, EFX_DWORD_3));
223227569Sphilip	EFX_BAR_TBL_WRITED3(enp, FR_BZ_TX_DESC_UPD_REGP0,
224227569Sphilip			    etp->et_index, &dword, B_FALSE);
225227569Sphilip}
226227569Sphilip
227227569Sphilip		void
228227569Sphilipefx_tx_qflush(
229227569Sphilip	__in	efx_txq_t *etp)
230227569Sphilip{
231227569Sphilip	efx_nic_t *enp = etp->et_enp;
232227569Sphilip	efx_oword_t oword;
233227569Sphilip	uint32_t label;
234227569Sphilip
235227569Sphilip	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
236227569Sphilip
237227569Sphilip	label = etp->et_index;
238227569Sphilip
239227569Sphilip	/* Flush the queue */
240227569Sphilip	EFX_POPULATE_OWORD_2(oword, FRF_AZ_TX_FLUSH_DESCQ_CMD, 1,
241227569Sphilip	    FRF_AZ_TX_FLUSH_DESCQ, label);
242227569Sphilip	EFX_BAR_WRITEO(enp, FR_AZ_TX_FLUSH_DESCQ_REG, &oword);
243227569Sphilip}
244227569Sphilip
245227569Sphilip		void
246227569Sphilipefx_tx_qenable(
247227569Sphilip	__in	efx_txq_t *etp)
248227569Sphilip{
249227569Sphilip	efx_nic_t *enp = etp->et_enp;
250227569Sphilip	efx_oword_t oword;
251227569Sphilip
252227569Sphilip	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
253227569Sphilip
254227569Sphilip	EFX_BAR_TBL_READO(enp, FR_AZ_TX_DESC_PTR_TBL,
255227569Sphilip			    etp->et_index, &oword);
256227569Sphilip
257227569Sphilip	EFSYS_PROBE5(tx_descq_ptr, unsigned int, etp->et_index,
258227569Sphilip	    uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_3),
259227569Sphilip	    uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_2),
260227569Sphilip	    uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_1),
261227569Sphilip	    uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_0));
262227569Sphilip
263227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DC_HW_RPTR, 0);
264227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DESCQ_HW_RPTR, 0);
265227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DESCQ_EN, 1);
266227569Sphilip
267227569Sphilip	EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_DESC_PTR_TBL,
268227569Sphilip			    etp->et_index, &oword);
269227569Sphilip}
270227569Sphilip
271227569Sphilip	__checkReturn	int
272227569Sphilipefx_tx_qcreate(
273227569Sphilip	__in		efx_nic_t *enp,
274227569Sphilip	__in		unsigned int index,
275227569Sphilip	__in		unsigned int label,
276227569Sphilip	__in		efsys_mem_t *esmp,
277227569Sphilip	__in		size_t n,
278227569Sphilip	__in		uint32_t id,
279227569Sphilip	__in		uint16_t flags,
280227569Sphilip	__in		efx_evq_t *eep,
281227569Sphilip	__deref_out	efx_txq_t **etpp)
282227569Sphilip{
283227569Sphilip	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
284227569Sphilip	efx_txq_t *etp;
285227569Sphilip	efx_oword_t oword;
286227569Sphilip	uint32_t size;
287227569Sphilip	int rc;
288227569Sphilip
289227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
290227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TX);
291227569Sphilip
292227569Sphilip	EFX_STATIC_ASSERT(EFX_EV_TX_NLABELS == (1 << FRF_AZ_TX_DESCQ_LABEL_WIDTH));
293265884Sgnn	/*	EFSYS_ASSERT3U(label, <, EFX_EV_TX_NLABELS);*/
294227569Sphilip	EFSYS_ASSERT3U(enp->en_tx_qcount + 1, <, encp->enc_txq_limit);
295227569Sphilip
296227569Sphilip	if (!ISP2(n) || !(n & EFX_TXQ_NDESCS_MASK)) {
297227569Sphilip		rc = EINVAL;
298227569Sphilip		goto fail1;
299227569Sphilip	}
300227569Sphilip	if (index >= encp->enc_txq_limit) {
301227569Sphilip		rc = EINVAL;
302227569Sphilip		goto fail2;
303227569Sphilip	}
304227569Sphilip	for (size = 0; (1 << size) <= (EFX_TXQ_MAXNDESCS / EFX_TXQ_MINNDESCS);
305227569Sphilip	    size++)
306227569Sphilip		if ((1 << size) == (int)(n / EFX_TXQ_MINNDESCS))
307227569Sphilip			break;
308227569Sphilip	if (id + (1 << size) >= encp->enc_buftbl_limit) {
309227569Sphilip		rc = EINVAL;
310227569Sphilip		goto fail3;
311227569Sphilip	}
312227569Sphilip
313227569Sphilip	/* Allocate an TXQ object */
314227569Sphilip	EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (efx_txq_t), etp);
315227569Sphilip
316227569Sphilip	if (etp == NULL) {
317227569Sphilip		rc = ENOMEM;
318227569Sphilip		goto fail4;
319227569Sphilip	}
320227569Sphilip
321227569Sphilip	etp->et_magic = EFX_TXQ_MAGIC;
322227569Sphilip	etp->et_enp = enp;
323227569Sphilip	etp->et_index = index;
324227569Sphilip	etp->et_mask = n - 1;
325227569Sphilip	etp->et_esmp = esmp;
326227569Sphilip
327227569Sphilip	/* Set up the new descriptor queue */
328227569Sphilip	EFX_POPULATE_OWORD_6(oword,
329227569Sphilip	    FRF_AZ_TX_DESCQ_BUF_BASE_ID, id,
330227569Sphilip	    FRF_AZ_TX_DESCQ_EVQ_ID, eep->ee_index,
331227569Sphilip	    FRF_AZ_TX_DESCQ_OWNER_ID, 0,
332227569Sphilip	    FRF_AZ_TX_DESCQ_LABEL, label,
333227569Sphilip	    FRF_AZ_TX_DESCQ_SIZE, size,
334227569Sphilip	    FRF_AZ_TX_DESCQ_TYPE, 0);
335227569Sphilip
336227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_NON_IP_DROP_DIS, 1);
337227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_IP_CHKSM_DIS,
338227569Sphilip	    (flags & EFX_CKSUM_IPV4) ? 0 : 1);
339227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_TCP_CHKSM_DIS,
340227569Sphilip	    (flags & EFX_CKSUM_TCPUDP) ? 0 : 1);
341227569Sphilip
342227569Sphilip	EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_DESC_PTR_TBL,
343227569Sphilip	    etp->et_index, &oword);
344227569Sphilip
345227569Sphilip	enp->en_tx_qcount++;
346227569Sphilip	*etpp = etp;
347227569Sphilip	return (0);
348227569Sphilip
349227569Sphilipfail4:
350227569Sphilip	EFSYS_PROBE(fail4);
351227569Sphilipfail3:
352227569Sphilip	EFSYS_PROBE(fail3);
353227569Sphilipfail2:
354227569Sphilip	EFSYS_PROBE(fail2);
355227569Sphilipfail1:
356227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
357227569Sphilip
358227569Sphilip	return (rc);
359227569Sphilip}
360227569Sphilip
361227569Sphilip#if EFSYS_OPT_NAMES
362227569Sphilip/* START MKCONFIG GENERATED EfxTransmitQueueStatNamesBlock 78ca9ab00287fffb */
363227569Sphilipstatic const char 	__cs * __cs __efx_tx_qstat_name[] = {
364227569Sphilip	"post",
365227569Sphilip	"unaligned_split",
366227569Sphilip};
367227569Sphilip/* END MKCONFIG GENERATED EfxTransmitQueueStatNamesBlock */
368227569Sphilip
369227569Sphilip		const char __cs *
370227569Sphilipefx_tx_qstat_name(
371227569Sphilip	__in	efx_nic_t *enp,
372227569Sphilip	__in	unsigned int id)
373227569Sphilip{
374227569Sphilip	_NOTE(ARGUNUSED(enp))
375227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
376227569Sphilip	EFSYS_ASSERT3U(id, <, TX_NQSTATS);
377227569Sphilip
378227569Sphilip	return (__efx_tx_qstat_name[id]);
379227569Sphilip}
380227569Sphilip#endif	/* EFSYS_OPT_NAMES */
381227569Sphilip
382227569Sphilip#if EFSYS_OPT_QSTATS
383227569Sphilip					void
384227569Sphilipefx_tx_qstats_update(
385227569Sphilip	__in				efx_txq_t *etp,
386227569Sphilip	__inout_ecount(TX_NQSTATS)	efsys_stat_t *stat)
387227569Sphilip{
388227569Sphilip	unsigned int id;
389227569Sphilip
390227569Sphilip	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
391227569Sphilip
392227569Sphilip	for (id = 0; id < TX_NQSTATS; id++) {
393227569Sphilip		efsys_stat_t *essp = &stat[id];
394227569Sphilip
395227569Sphilip		EFSYS_STAT_INCR(essp, etp->et_stat[id]);
396227569Sphilip		etp->et_stat[id] = 0;
397227569Sphilip	}
398227569Sphilip}
399227569Sphilip#endif	/* EFSYS_OPT_QSTATS */
400227569Sphilip
401227569Sphilip		void
402227569Sphilipefx_tx_qdestroy(
403227569Sphilip	__in	efx_txq_t *etp)
404227569Sphilip{
405227569Sphilip	efx_nic_t *enp = etp->et_enp;
406227569Sphilip	efx_oword_t oword;
407227569Sphilip
408227569Sphilip	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
409227569Sphilip
410227569Sphilip	EFSYS_ASSERT(enp->en_tx_qcount != 0);
411227569Sphilip	--enp->en_tx_qcount;
412227569Sphilip
413227569Sphilip	/* Purge descriptor queue */
414227569Sphilip	EFX_ZERO_OWORD(oword);
415227569Sphilip
416227569Sphilip	EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_DESC_PTR_TBL,
417227569Sphilip			    etp->et_index, &oword);
418227569Sphilip
419227569Sphilip	/* Free the TXQ object */
420227569Sphilip	EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_txq_t), etp);
421227569Sphilip}
422227569Sphilip
423227569Sphilip		void
424227569Sphilipefx_tx_fini(
425227569Sphilip	__in	efx_nic_t *enp)
426227569Sphilip{
427227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
428227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
429227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TX);
430227569Sphilip	EFSYS_ASSERT3U(enp->en_tx_qcount, ==, 0);
431227569Sphilip
432227569Sphilip	enp->en_mod_flags &= ~EFX_MOD_TX;
433227569Sphilip}
434