xref: /freebsd/sys/dev/sfxge/common/efx_tx.c (revision 4142e8cfbb7d4cbd038b3b053bc1fe5a90afdaf6)
1e948693eSPhilip Paeps /*-
2718cf2ccSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3718cf2ccSPedro F. Giffuni  *
4929c7febSAndrew Rybchenko  * Copyright (c) 2007-2016 Solarflare Communications Inc.
53c838a9fSAndrew Rybchenko  * All rights reserved.
6e948693eSPhilip Paeps  *
7e948693eSPhilip Paeps  * Redistribution and use in source and binary forms, with or without
83c838a9fSAndrew Rybchenko  * modification, are permitted provided that the following conditions are met:
9e948693eSPhilip Paeps  *
103c838a9fSAndrew Rybchenko  * 1. Redistributions of source code must retain the above copyright notice,
113c838a9fSAndrew Rybchenko  *    this list of conditions and the following disclaimer.
123c838a9fSAndrew Rybchenko  * 2. Redistributions in binary form must reproduce the above copyright notice,
133c838a9fSAndrew Rybchenko  *    this list of conditions and the following disclaimer in the documentation
143c838a9fSAndrew Rybchenko  *    and/or other materials provided with the distribution.
153c838a9fSAndrew Rybchenko  *
163c838a9fSAndrew Rybchenko  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
173c838a9fSAndrew Rybchenko  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
183c838a9fSAndrew Rybchenko  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
193c838a9fSAndrew Rybchenko  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
203c838a9fSAndrew Rybchenko  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
213c838a9fSAndrew Rybchenko  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
223c838a9fSAndrew Rybchenko  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
233c838a9fSAndrew Rybchenko  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
243c838a9fSAndrew Rybchenko  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
253c838a9fSAndrew Rybchenko  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
263c838a9fSAndrew Rybchenko  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
273c838a9fSAndrew Rybchenko  *
283c838a9fSAndrew Rybchenko  * The views and conclusions contained in the software and documentation are
293c838a9fSAndrew Rybchenko  * those of the authors and should not be interpreted as representing official
303c838a9fSAndrew Rybchenko  * policies, either expressed or implied, of the FreeBSD Project.
31e948693eSPhilip Paeps  */
32e948693eSPhilip Paeps 
335dee87d7SPhilip Paeps #include <sys/cdefs.h>
345dee87d7SPhilip Paeps __FBSDID("$FreeBSD$");
355dee87d7SPhilip Paeps 
36e948693eSPhilip Paeps #include "efx.h"
37e948693eSPhilip Paeps #include "efx_impl.h"
38e948693eSPhilip Paeps 
39e948693eSPhilip Paeps #if EFSYS_OPT_QSTATS
40e948693eSPhilip Paeps #define	EFX_TX_QSTAT_INCR(_etp, _stat)					\
41e948693eSPhilip Paeps 	do {								\
42e948693eSPhilip Paeps 		(_etp)->et_stat[_stat]++;				\
43e948693eSPhilip Paeps 	_NOTE(CONSTANTCONDITION)					\
44e948693eSPhilip Paeps 	} while (B_FALSE)
45e948693eSPhilip Paeps #else
46e948693eSPhilip Paeps #define	EFX_TX_QSTAT_INCR(_etp, _stat)
47e948693eSPhilip Paeps #endif
48e948693eSPhilip Paeps 
49e75412c9SAndrew Rybchenko #if EFSYS_OPT_SIENA
503c838a9fSAndrew Rybchenko 
51460cb568SAndrew Rybchenko static	__checkReturn	efx_rc_t
5296ffcdeeSAndrew Rybchenko siena_tx_init(
533c838a9fSAndrew Rybchenko 	__in		efx_nic_t *enp);
543c838a9fSAndrew Rybchenko 
553c838a9fSAndrew Rybchenko static			void
5696ffcdeeSAndrew Rybchenko siena_tx_fini(
573c838a9fSAndrew Rybchenko 	__in		efx_nic_t *enp);
583c838a9fSAndrew Rybchenko 
59460cb568SAndrew Rybchenko static	__checkReturn	efx_rc_t
6096ffcdeeSAndrew Rybchenko siena_tx_qcreate(
613c838a9fSAndrew Rybchenko 	__in		efx_nic_t *enp,
623c838a9fSAndrew Rybchenko 	__in		unsigned int index,
633c838a9fSAndrew Rybchenko 	__in		unsigned int label,
643c838a9fSAndrew Rybchenko 	__in		efsys_mem_t *esmp,
650c9ef1f5SAndrew Rybchenko 	__in		size_t ndescs,
663c838a9fSAndrew Rybchenko 	__in		uint32_t id,
673c838a9fSAndrew Rybchenko 	__in		uint16_t flags,
683c838a9fSAndrew Rybchenko 	__in		efx_evq_t *eep,
693c838a9fSAndrew Rybchenko 	__in		efx_txq_t *etp,
703c838a9fSAndrew Rybchenko 	__out		unsigned int *addedp);
713c838a9fSAndrew Rybchenko 
723c838a9fSAndrew Rybchenko static		void
7396ffcdeeSAndrew Rybchenko siena_tx_qdestroy(
743c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp);
753c838a9fSAndrew Rybchenko 
76460cb568SAndrew Rybchenko static	__checkReturn		efx_rc_t
7796ffcdeeSAndrew Rybchenko siena_tx_qpost(
783c838a9fSAndrew Rybchenko 	__in			efx_txq_t *etp,
790c9ef1f5SAndrew Rybchenko 	__in_ecount(ndescs)	efx_buffer_t *eb,
800c9ef1f5SAndrew Rybchenko 	__in			unsigned int ndescs,
813c838a9fSAndrew Rybchenko 	__in			unsigned int completed,
823c838a9fSAndrew Rybchenko 	__inout			unsigned int *addedp);
833c838a9fSAndrew Rybchenko 
843c838a9fSAndrew Rybchenko static			void
8596ffcdeeSAndrew Rybchenko siena_tx_qpush(
863c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp,
873c838a9fSAndrew Rybchenko 	__in	unsigned int added,
883c838a9fSAndrew Rybchenko 	__in	unsigned int pushed);
893c838a9fSAndrew Rybchenko 
90460cb568SAndrew Rybchenko static	__checkReturn	efx_rc_t
9196ffcdeeSAndrew Rybchenko siena_tx_qpace(
923c838a9fSAndrew Rybchenko 	__in		efx_txq_t *etp,
933c838a9fSAndrew Rybchenko 	__in		unsigned int ns);
943c838a9fSAndrew Rybchenko 
95460cb568SAndrew Rybchenko static	__checkReturn	efx_rc_t
9696ffcdeeSAndrew Rybchenko siena_tx_qflush(
973c838a9fSAndrew Rybchenko 	__in		efx_txq_t *etp);
983c838a9fSAndrew Rybchenko 
993c838a9fSAndrew Rybchenko static			void
10096ffcdeeSAndrew Rybchenko siena_tx_qenable(
1013c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp);
1023c838a9fSAndrew Rybchenko 
103460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
10496ffcdeeSAndrew Rybchenko siena_tx_qdesc_post(
1053c838a9fSAndrew Rybchenko 	__in			efx_txq_t *etp,
1060c9ef1f5SAndrew Rybchenko 	__in_ecount(ndescs)	efx_desc_t *ed,
1070c9ef1f5SAndrew Rybchenko 	__in			unsigned int ndescs,
1083c838a9fSAndrew Rybchenko 	__in			unsigned int completed,
1093c838a9fSAndrew Rybchenko 	__inout			unsigned int *addedp);
1103c838a9fSAndrew Rybchenko 
1113c838a9fSAndrew Rybchenko 	void
11296ffcdeeSAndrew Rybchenko siena_tx_qdesc_dma_create(
1133c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp,
1143c838a9fSAndrew Rybchenko 	__in	efsys_dma_addr_t addr,
1153c838a9fSAndrew Rybchenko 	__in	size_t size,
1163c838a9fSAndrew Rybchenko 	__in	boolean_t eop,
1173c838a9fSAndrew Rybchenko 	__out	efx_desc_t *edp);
1183c838a9fSAndrew Rybchenko 
1193c838a9fSAndrew Rybchenko #if EFSYS_OPT_QSTATS
1203c838a9fSAndrew Rybchenko static			void
12196ffcdeeSAndrew Rybchenko siena_tx_qstats_update(
1223c838a9fSAndrew Rybchenko 	__in				efx_txq_t *etp,
1233c838a9fSAndrew Rybchenko 	__inout_ecount(TX_NQSTATS)	efsys_stat_t *stat);
1243c838a9fSAndrew Rybchenko #endif
1253c838a9fSAndrew Rybchenko 
126e75412c9SAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */
1273c838a9fSAndrew Rybchenko 
1283c838a9fSAndrew Rybchenko 
1293c838a9fSAndrew Rybchenko #if EFSYS_OPT_SIENA
130ec831f7fSAndrew Rybchenko static const efx_tx_ops_t	__efx_tx_siena_ops = {
13196ffcdeeSAndrew Rybchenko 	siena_tx_init,				/* etxo_init */
13296ffcdeeSAndrew Rybchenko 	siena_tx_fini,				/* etxo_fini */
13396ffcdeeSAndrew Rybchenko 	siena_tx_qcreate,			/* etxo_qcreate */
13496ffcdeeSAndrew Rybchenko 	siena_tx_qdestroy,			/* etxo_qdestroy */
13596ffcdeeSAndrew Rybchenko 	siena_tx_qpost,				/* etxo_qpost */
13696ffcdeeSAndrew Rybchenko 	siena_tx_qpush,				/* etxo_qpush */
13796ffcdeeSAndrew Rybchenko 	siena_tx_qpace,				/* etxo_qpace */
13896ffcdeeSAndrew Rybchenko 	siena_tx_qflush,			/* etxo_qflush */
13996ffcdeeSAndrew Rybchenko 	siena_tx_qenable,			/* etxo_qenable */
1403c838a9fSAndrew Rybchenko 	NULL,					/* etxo_qpio_enable */
1413c838a9fSAndrew Rybchenko 	NULL,					/* etxo_qpio_disable */
1423c838a9fSAndrew Rybchenko 	NULL,					/* etxo_qpio_write */
1433c838a9fSAndrew Rybchenko 	NULL,					/* etxo_qpio_post */
14496ffcdeeSAndrew Rybchenko 	siena_tx_qdesc_post,			/* etxo_qdesc_post */
14596ffcdeeSAndrew Rybchenko 	siena_tx_qdesc_dma_create,		/* etxo_qdesc_dma_create */
1463c838a9fSAndrew Rybchenko 	NULL,					/* etxo_qdesc_tso_create */
1474ab49369SAndrew Rybchenko 	NULL,					/* etxo_qdesc_tso2_create */
1483c838a9fSAndrew Rybchenko 	NULL,					/* etxo_qdesc_vlantci_create */
1494effeb9eSAndrew Rybchenko 	NULL,					/* etxo_qdesc_checksum_create */
1503c838a9fSAndrew Rybchenko #if EFSYS_OPT_QSTATS
15196ffcdeeSAndrew Rybchenko 	siena_tx_qstats_update,			/* etxo_qstats_update */
1523c838a9fSAndrew Rybchenko #endif
1533c838a9fSAndrew Rybchenko };
1543c838a9fSAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */
1553c838a9fSAndrew Rybchenko 
1563c838a9fSAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON
157ec831f7fSAndrew Rybchenko static const efx_tx_ops_t	__efx_tx_hunt_ops = {
158cc62e811SAndrew Rybchenko 	ef10_tx_init,				/* etxo_init */
159cc62e811SAndrew Rybchenko 	ef10_tx_fini,				/* etxo_fini */
160cc62e811SAndrew Rybchenko 	ef10_tx_qcreate,			/* etxo_qcreate */
161cc62e811SAndrew Rybchenko 	ef10_tx_qdestroy,			/* etxo_qdestroy */
162cc62e811SAndrew Rybchenko 	ef10_tx_qpost,				/* etxo_qpost */
163cc62e811SAndrew Rybchenko 	ef10_tx_qpush,				/* etxo_qpush */
164cc62e811SAndrew Rybchenko 	ef10_tx_qpace,				/* etxo_qpace */
165cc62e811SAndrew Rybchenko 	ef10_tx_qflush,				/* etxo_qflush */
166cc62e811SAndrew Rybchenko 	ef10_tx_qenable,			/* etxo_qenable */
167cc62e811SAndrew Rybchenko 	ef10_tx_qpio_enable,			/* etxo_qpio_enable */
168cc62e811SAndrew Rybchenko 	ef10_tx_qpio_disable,			/* etxo_qpio_disable */
169cc62e811SAndrew Rybchenko 	ef10_tx_qpio_write,			/* etxo_qpio_write */
170cc62e811SAndrew Rybchenko 	ef10_tx_qpio_post,			/* etxo_qpio_post */
171cc62e811SAndrew Rybchenko 	ef10_tx_qdesc_post,			/* etxo_qdesc_post */
172cc62e811SAndrew Rybchenko 	ef10_tx_qdesc_dma_create,		/* etxo_qdesc_dma_create */
17369fb4e16SAndrew Rybchenko 	ef10_tx_qdesc_tso_create,		/* etxo_qdesc_tso_create */
1744ab49369SAndrew Rybchenko 	ef10_tx_qdesc_tso2_create,		/* etxo_qdesc_tso2_create */
175cc62e811SAndrew Rybchenko 	ef10_tx_qdesc_vlantci_create,		/* etxo_qdesc_vlantci_create */
1764effeb9eSAndrew Rybchenko 	ef10_tx_qdesc_checksum_create,		/* etxo_qdesc_checksum_create */
1773c838a9fSAndrew Rybchenko #if EFSYS_OPT_QSTATS
178cc62e811SAndrew Rybchenko 	ef10_tx_qstats_update,			/* etxo_qstats_update */
1793c838a9fSAndrew Rybchenko #endif
1803c838a9fSAndrew Rybchenko };
1813c838a9fSAndrew Rybchenko #endif /* EFSYS_OPT_HUNTINGTON */
1823c838a9fSAndrew Rybchenko 
183cc62e811SAndrew Rybchenko #if EFSYS_OPT_MEDFORD
184ec831f7fSAndrew Rybchenko static const efx_tx_ops_t	__efx_tx_medford_ops = {
185cc62e811SAndrew Rybchenko 	ef10_tx_init,				/* etxo_init */
186cc62e811SAndrew Rybchenko 	ef10_tx_fini,				/* etxo_fini */
187cc62e811SAndrew Rybchenko 	ef10_tx_qcreate,			/* etxo_qcreate */
188cc62e811SAndrew Rybchenko 	ef10_tx_qdestroy,			/* etxo_qdestroy */
189cc62e811SAndrew Rybchenko 	ef10_tx_qpost,				/* etxo_qpost */
190cc62e811SAndrew Rybchenko 	ef10_tx_qpush,				/* etxo_qpush */
191cc62e811SAndrew Rybchenko 	ef10_tx_qpace,				/* etxo_qpace */
192cc62e811SAndrew Rybchenko 	ef10_tx_qflush,				/* etxo_qflush */
193cc62e811SAndrew Rybchenko 	ef10_tx_qenable,			/* etxo_qenable */
194cc62e811SAndrew Rybchenko 	ef10_tx_qpio_enable,			/* etxo_qpio_enable */
195cc62e811SAndrew Rybchenko 	ef10_tx_qpio_disable,			/* etxo_qpio_disable */
196cc62e811SAndrew Rybchenko 	ef10_tx_qpio_write,			/* etxo_qpio_write */
197cc62e811SAndrew Rybchenko 	ef10_tx_qpio_post,			/* etxo_qpio_post */
198cc62e811SAndrew Rybchenko 	ef10_tx_qdesc_post,			/* etxo_qdesc_post */
199cc62e811SAndrew Rybchenko 	ef10_tx_qdesc_dma_create,		/* etxo_qdesc_dma_create */
200cc62e811SAndrew Rybchenko 	NULL,					/* etxo_qdesc_tso_create */
2014ab49369SAndrew Rybchenko 	ef10_tx_qdesc_tso2_create,		/* etxo_qdesc_tso2_create */
202cc62e811SAndrew Rybchenko 	ef10_tx_qdesc_vlantci_create,		/* etxo_qdesc_vlantci_create */
2034effeb9eSAndrew Rybchenko 	ef10_tx_qdesc_checksum_create,		/* etxo_qdesc_checksum_create */
204cc62e811SAndrew Rybchenko #if EFSYS_OPT_QSTATS
205cc62e811SAndrew Rybchenko 	ef10_tx_qstats_update,			/* etxo_qstats_update */
206cc62e811SAndrew Rybchenko #endif
207cc62e811SAndrew Rybchenko };
208cc62e811SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD */
209cc62e811SAndrew Rybchenko 
21020c5aab3SAndrew Rybchenko #if EFSYS_OPT_MEDFORD2
21120c5aab3SAndrew Rybchenko static const efx_tx_ops_t	__efx_tx_medford2_ops = {
21220c5aab3SAndrew Rybchenko 	ef10_tx_init,				/* etxo_init */
21320c5aab3SAndrew Rybchenko 	ef10_tx_fini,				/* etxo_fini */
21420c5aab3SAndrew Rybchenko 	ef10_tx_qcreate,			/* etxo_qcreate */
21520c5aab3SAndrew Rybchenko 	ef10_tx_qdestroy,			/* etxo_qdestroy */
21620c5aab3SAndrew Rybchenko 	ef10_tx_qpost,				/* etxo_qpost */
21720c5aab3SAndrew Rybchenko 	ef10_tx_qpush,				/* etxo_qpush */
21820c5aab3SAndrew Rybchenko 	ef10_tx_qpace,				/* etxo_qpace */
21920c5aab3SAndrew Rybchenko 	ef10_tx_qflush,				/* etxo_qflush */
22020c5aab3SAndrew Rybchenko 	ef10_tx_qenable,			/* etxo_qenable */
22120c5aab3SAndrew Rybchenko 	ef10_tx_qpio_enable,			/* etxo_qpio_enable */
22220c5aab3SAndrew Rybchenko 	ef10_tx_qpio_disable,			/* etxo_qpio_disable */
22320c5aab3SAndrew Rybchenko 	ef10_tx_qpio_write,			/* etxo_qpio_write */
22420c5aab3SAndrew Rybchenko 	ef10_tx_qpio_post,			/* etxo_qpio_post */
22520c5aab3SAndrew Rybchenko 	ef10_tx_qdesc_post,			/* etxo_qdesc_post */
22620c5aab3SAndrew Rybchenko 	ef10_tx_qdesc_dma_create,		/* etxo_qdesc_dma_create */
22720c5aab3SAndrew Rybchenko 	NULL,					/* etxo_qdesc_tso_create */
22820c5aab3SAndrew Rybchenko 	ef10_tx_qdesc_tso2_create,		/* etxo_qdesc_tso2_create */
22920c5aab3SAndrew Rybchenko 	ef10_tx_qdesc_vlantci_create,		/* etxo_qdesc_vlantci_create */
2304effeb9eSAndrew Rybchenko 	ef10_tx_qdesc_checksum_create,		/* etxo_qdesc_checksum_create */
23120c5aab3SAndrew Rybchenko #if EFSYS_OPT_QSTATS
23220c5aab3SAndrew Rybchenko 	ef10_tx_qstats_update,			/* etxo_qstats_update */
23320c5aab3SAndrew Rybchenko #endif
23420c5aab3SAndrew Rybchenko };
23520c5aab3SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD2 */
23620c5aab3SAndrew Rybchenko 
23720c5aab3SAndrew Rybchenko 
238460cb568SAndrew Rybchenko 	__checkReturn	efx_rc_t
239e948693eSPhilip Paeps efx_tx_init(
240e948693eSPhilip Paeps 	__in		efx_nic_t *enp)
241e948693eSPhilip Paeps {
242ec831f7fSAndrew Rybchenko 	const efx_tx_ops_t *etxop;
243460cb568SAndrew Rybchenko 	efx_rc_t rc;
244e948693eSPhilip Paeps 
245e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
246e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
247e948693eSPhilip Paeps 
248e948693eSPhilip Paeps 	if (!(enp->en_mod_flags & EFX_MOD_EV)) {
249e948693eSPhilip Paeps 		rc = EINVAL;
250e948693eSPhilip Paeps 		goto fail1;
251e948693eSPhilip Paeps 	}
252e948693eSPhilip Paeps 
253e948693eSPhilip Paeps 	if (enp->en_mod_flags & EFX_MOD_TX) {
254e948693eSPhilip Paeps 		rc = EINVAL;
255e948693eSPhilip Paeps 		goto fail2;
256e948693eSPhilip Paeps 	}
257e948693eSPhilip Paeps 
2583c838a9fSAndrew Rybchenko 	switch (enp->en_family) {
2593c838a9fSAndrew Rybchenko #if EFSYS_OPT_SIENA
2603c838a9fSAndrew Rybchenko 	case EFX_FAMILY_SIENA:
261ec831f7fSAndrew Rybchenko 		etxop = &__efx_tx_siena_ops;
2623c838a9fSAndrew Rybchenko 		break;
2633c838a9fSAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */
2643c838a9fSAndrew Rybchenko 
2653c838a9fSAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON
2663c838a9fSAndrew Rybchenko 	case EFX_FAMILY_HUNTINGTON:
267ec831f7fSAndrew Rybchenko 		etxop = &__efx_tx_hunt_ops;
2683c838a9fSAndrew Rybchenko 		break;
2693c838a9fSAndrew Rybchenko #endif /* EFSYS_OPT_HUNTINGTON */
2703c838a9fSAndrew Rybchenko 
271cc62e811SAndrew Rybchenko #if EFSYS_OPT_MEDFORD
272cc62e811SAndrew Rybchenko 	case EFX_FAMILY_MEDFORD:
273ec831f7fSAndrew Rybchenko 		etxop = &__efx_tx_medford_ops;
274cc62e811SAndrew Rybchenko 		break;
275cc62e811SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD */
276cc62e811SAndrew Rybchenko 
27720c5aab3SAndrew Rybchenko #if EFSYS_OPT_MEDFORD2
27820c5aab3SAndrew Rybchenko 	case EFX_FAMILY_MEDFORD2:
27920c5aab3SAndrew Rybchenko 		etxop = &__efx_tx_medford2_ops;
28020c5aab3SAndrew Rybchenko 		break;
28120c5aab3SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD2 */
28220c5aab3SAndrew Rybchenko 
2833c838a9fSAndrew Rybchenko 	default:
2843c838a9fSAndrew Rybchenko 		EFSYS_ASSERT(0);
2853c838a9fSAndrew Rybchenko 		rc = ENOTSUP;
2863c838a9fSAndrew Rybchenko 		goto fail3;
2873c838a9fSAndrew Rybchenko 	}
2883c838a9fSAndrew Rybchenko 
289e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_tx_qcount, ==, 0);
290e948693eSPhilip Paeps 
2913c838a9fSAndrew Rybchenko 	if ((rc = etxop->etxo_init(enp)) != 0)
2923c838a9fSAndrew Rybchenko 		goto fail4;
2933c838a9fSAndrew Rybchenko 
2943c838a9fSAndrew Rybchenko 	enp->en_etxop = etxop;
2953c838a9fSAndrew Rybchenko 	enp->en_mod_flags |= EFX_MOD_TX;
2963c838a9fSAndrew Rybchenko 	return (0);
2973c838a9fSAndrew Rybchenko 
2983c838a9fSAndrew Rybchenko fail4:
2993c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail4);
3003c838a9fSAndrew Rybchenko fail3:
3013c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail3);
3023c838a9fSAndrew Rybchenko fail2:
3033c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
3043c838a9fSAndrew Rybchenko fail1:
305460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
3063c838a9fSAndrew Rybchenko 
3073c838a9fSAndrew Rybchenko 	enp->en_etxop = NULL;
3083c838a9fSAndrew Rybchenko 	enp->en_mod_flags &= ~EFX_MOD_TX;
3093c838a9fSAndrew Rybchenko 	return (rc);
3103c838a9fSAndrew Rybchenko }
3113c838a9fSAndrew Rybchenko 
3123c838a9fSAndrew Rybchenko 			void
3133c838a9fSAndrew Rybchenko efx_tx_fini(
3143c838a9fSAndrew Rybchenko 	__in	efx_nic_t *enp)
3153c838a9fSAndrew Rybchenko {
316ec831f7fSAndrew Rybchenko 	const efx_tx_ops_t *etxop = enp->en_etxop;
3173c838a9fSAndrew Rybchenko 
3183c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
3193c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
3203c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TX);
3213c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_tx_qcount, ==, 0);
3223c838a9fSAndrew Rybchenko 
3233c838a9fSAndrew Rybchenko 	etxop->etxo_fini(enp);
3243c838a9fSAndrew Rybchenko 
3253c838a9fSAndrew Rybchenko 	enp->en_etxop = NULL;
3263c838a9fSAndrew Rybchenko 	enp->en_mod_flags &= ~EFX_MOD_TX;
3273c838a9fSAndrew Rybchenko }
3283c838a9fSAndrew Rybchenko 
329460cb568SAndrew Rybchenko 	__checkReturn	efx_rc_t
3303c838a9fSAndrew Rybchenko efx_tx_qcreate(
3313c838a9fSAndrew Rybchenko 	__in		efx_nic_t *enp,
3323c838a9fSAndrew Rybchenko 	__in		unsigned int index,
3333c838a9fSAndrew Rybchenko 	__in		unsigned int label,
3343c838a9fSAndrew Rybchenko 	__in		efsys_mem_t *esmp,
3350c9ef1f5SAndrew Rybchenko 	__in		size_t ndescs,
3363c838a9fSAndrew Rybchenko 	__in		uint32_t id,
3373c838a9fSAndrew Rybchenko 	__in		uint16_t flags,
3383c838a9fSAndrew Rybchenko 	__in		efx_evq_t *eep,
3393c838a9fSAndrew Rybchenko 	__deref_out	efx_txq_t **etpp,
3403c838a9fSAndrew Rybchenko 	__out		unsigned int *addedp)
3413c838a9fSAndrew Rybchenko {
342ec831f7fSAndrew Rybchenko 	const efx_tx_ops_t *etxop = enp->en_etxop;
3433c838a9fSAndrew Rybchenko 	efx_txq_t *etp;
344460cb568SAndrew Rybchenko 	efx_rc_t rc;
3453c838a9fSAndrew Rybchenko 
3463c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
3473c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TX);
3483c838a9fSAndrew Rybchenko 
349cc8d2b23SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_tx_qcount + 1, <,
350cc8d2b23SAndrew Rybchenko 	    enp->en_nic_cfg.enc_txq_limit);
3513c838a9fSAndrew Rybchenko 
3523c838a9fSAndrew Rybchenko 	/* Allocate an TXQ object */
3533c838a9fSAndrew Rybchenko 	EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (efx_txq_t), etp);
3543c838a9fSAndrew Rybchenko 
3553c838a9fSAndrew Rybchenko 	if (etp == NULL) {
3563c838a9fSAndrew Rybchenko 		rc = ENOMEM;
3573c838a9fSAndrew Rybchenko 		goto fail1;
3583c838a9fSAndrew Rybchenko 	}
3593c838a9fSAndrew Rybchenko 
3603c838a9fSAndrew Rybchenko 	etp->et_magic = EFX_TXQ_MAGIC;
3613c838a9fSAndrew Rybchenko 	etp->et_enp = enp;
3623c838a9fSAndrew Rybchenko 	etp->et_index = index;
3630c9ef1f5SAndrew Rybchenko 	etp->et_mask = ndescs - 1;
3643c838a9fSAndrew Rybchenko 	etp->et_esmp = esmp;
3653c838a9fSAndrew Rybchenko 
3663c838a9fSAndrew Rybchenko 	/* Initial descriptor index may be modified by etxo_qcreate */
3673c838a9fSAndrew Rybchenko 	*addedp = 0;
3683c838a9fSAndrew Rybchenko 
3693c838a9fSAndrew Rybchenko 	if ((rc = etxop->etxo_qcreate(enp, index, label, esmp,
3700c9ef1f5SAndrew Rybchenko 	    ndescs, id, flags, eep, etp, addedp)) != 0)
3713c838a9fSAndrew Rybchenko 		goto fail2;
3723c838a9fSAndrew Rybchenko 
3733c838a9fSAndrew Rybchenko 	enp->en_tx_qcount++;
3743c838a9fSAndrew Rybchenko 	*etpp = etp;
3753c838a9fSAndrew Rybchenko 
3763c838a9fSAndrew Rybchenko 	return (0);
3773c838a9fSAndrew Rybchenko 
3783c838a9fSAndrew Rybchenko fail2:
3793c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
3803c838a9fSAndrew Rybchenko 	EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_txq_t), etp);
3813c838a9fSAndrew Rybchenko fail1:
382460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
3833c838a9fSAndrew Rybchenko 	return (rc);
3843c838a9fSAndrew Rybchenko }
3853c838a9fSAndrew Rybchenko 
3863c838a9fSAndrew Rybchenko 		void
3873c838a9fSAndrew Rybchenko efx_tx_qdestroy(
3883c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp)
3893c838a9fSAndrew Rybchenko {
3903c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
391ec831f7fSAndrew Rybchenko 	const efx_tx_ops_t *etxop = enp->en_etxop;
3923c838a9fSAndrew Rybchenko 
3933c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
3943c838a9fSAndrew Rybchenko 
3953c838a9fSAndrew Rybchenko 	EFSYS_ASSERT(enp->en_tx_qcount != 0);
3963c838a9fSAndrew Rybchenko 	--enp->en_tx_qcount;
3973c838a9fSAndrew Rybchenko 
3983c838a9fSAndrew Rybchenko 	etxop->etxo_qdestroy(etp);
3993c838a9fSAndrew Rybchenko 
4003c838a9fSAndrew Rybchenko 	/* Free the TXQ object */
4013c838a9fSAndrew Rybchenko 	EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_txq_t), etp);
4023c838a9fSAndrew Rybchenko }
4033c838a9fSAndrew Rybchenko 
404460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
4053c838a9fSAndrew Rybchenko efx_tx_qpost(
4063c838a9fSAndrew Rybchenko 	__in			efx_txq_t *etp,
4070c9ef1f5SAndrew Rybchenko 	__in_ecount(ndescs)	efx_buffer_t *eb,
4080c9ef1f5SAndrew Rybchenko 	__in			unsigned int ndescs,
4093c838a9fSAndrew Rybchenko 	__in			unsigned int completed,
4103c838a9fSAndrew Rybchenko 	__inout			unsigned int *addedp)
4113c838a9fSAndrew Rybchenko {
4123c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
413ec831f7fSAndrew Rybchenko 	const efx_tx_ops_t *etxop = enp->en_etxop;
414460cb568SAndrew Rybchenko 	efx_rc_t rc;
4153c838a9fSAndrew Rybchenko 
4163c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
4173c838a9fSAndrew Rybchenko 
4180c9ef1f5SAndrew Rybchenko 	if ((rc = etxop->etxo_qpost(etp, eb, ndescs, completed, addedp)) != 0)
4193c838a9fSAndrew Rybchenko 		goto fail1;
4203c838a9fSAndrew Rybchenko 
4213c838a9fSAndrew Rybchenko 	return (0);
4223c838a9fSAndrew Rybchenko 
4233c838a9fSAndrew Rybchenko fail1:
424460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
4253c838a9fSAndrew Rybchenko 	return (rc);
4263c838a9fSAndrew Rybchenko }
4273c838a9fSAndrew Rybchenko 
4283c838a9fSAndrew Rybchenko 			void
4293c838a9fSAndrew Rybchenko efx_tx_qpush(
4303c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp,
4313c838a9fSAndrew Rybchenko 	__in	unsigned int added,
4323c838a9fSAndrew Rybchenko 	__in	unsigned int pushed)
4333c838a9fSAndrew Rybchenko {
4343c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
435ec831f7fSAndrew Rybchenko 	const efx_tx_ops_t *etxop = enp->en_etxop;
4363c838a9fSAndrew Rybchenko 
4373c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
4383c838a9fSAndrew Rybchenko 
4393c838a9fSAndrew Rybchenko 	etxop->etxo_qpush(etp, added, pushed);
4403c838a9fSAndrew Rybchenko }
4413c838a9fSAndrew Rybchenko 
442460cb568SAndrew Rybchenko 	__checkReturn	efx_rc_t
4433c838a9fSAndrew Rybchenko efx_tx_qpace(
4443c838a9fSAndrew Rybchenko 	__in		efx_txq_t *etp,
4453c838a9fSAndrew Rybchenko 	__in		unsigned int ns)
4463c838a9fSAndrew Rybchenko {
4473c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
448ec831f7fSAndrew Rybchenko 	const efx_tx_ops_t *etxop = enp->en_etxop;
449460cb568SAndrew Rybchenko 	efx_rc_t rc;
4503c838a9fSAndrew Rybchenko 
4513c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
4523c838a9fSAndrew Rybchenko 
4533c838a9fSAndrew Rybchenko 	if ((rc = etxop->etxo_qpace(etp, ns)) != 0)
4543c838a9fSAndrew Rybchenko 		goto fail1;
4553c838a9fSAndrew Rybchenko 
4563c838a9fSAndrew Rybchenko 	return (0);
4573c838a9fSAndrew Rybchenko 
4583c838a9fSAndrew Rybchenko fail1:
459460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
4603c838a9fSAndrew Rybchenko 	return (rc);
4613c838a9fSAndrew Rybchenko }
4623c838a9fSAndrew Rybchenko 
463460cb568SAndrew Rybchenko 	__checkReturn	efx_rc_t
4643c838a9fSAndrew Rybchenko efx_tx_qflush(
4653c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp)
4663c838a9fSAndrew Rybchenko {
4673c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
468ec831f7fSAndrew Rybchenko 	const efx_tx_ops_t *etxop = enp->en_etxop;
469460cb568SAndrew Rybchenko 	efx_rc_t rc;
4703c838a9fSAndrew Rybchenko 
4713c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
4723c838a9fSAndrew Rybchenko 
4733c838a9fSAndrew Rybchenko 	if ((rc = etxop->etxo_qflush(etp)) != 0)
4743c838a9fSAndrew Rybchenko 		goto fail1;
4753c838a9fSAndrew Rybchenko 
4763c838a9fSAndrew Rybchenko 	return (0);
4773c838a9fSAndrew Rybchenko 
4783c838a9fSAndrew Rybchenko fail1:
479460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
4803c838a9fSAndrew Rybchenko 	return (rc);
4813c838a9fSAndrew Rybchenko }
4823c838a9fSAndrew Rybchenko 
4833c838a9fSAndrew Rybchenko 			void
4843c838a9fSAndrew Rybchenko efx_tx_qenable(
4853c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp)
4863c838a9fSAndrew Rybchenko {
4873c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
488ec831f7fSAndrew Rybchenko 	const efx_tx_ops_t *etxop = enp->en_etxop;
4893c838a9fSAndrew Rybchenko 
4903c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
4913c838a9fSAndrew Rybchenko 
4923c838a9fSAndrew Rybchenko 	etxop->etxo_qenable(etp);
4933c838a9fSAndrew Rybchenko }
4943c838a9fSAndrew Rybchenko 
495460cb568SAndrew Rybchenko 	__checkReturn	efx_rc_t
4963c838a9fSAndrew Rybchenko efx_tx_qpio_enable(
4973c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp)
4983c838a9fSAndrew Rybchenko {
4993c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
500ec831f7fSAndrew Rybchenko 	const efx_tx_ops_t *etxop = enp->en_etxop;
501460cb568SAndrew Rybchenko 	efx_rc_t rc;
5023c838a9fSAndrew Rybchenko 
5033c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
5043c838a9fSAndrew Rybchenko 
5053c838a9fSAndrew Rybchenko 	if (~enp->en_features & EFX_FEATURE_PIO_BUFFERS) {
5063c838a9fSAndrew Rybchenko 		rc = ENOTSUP;
5073c838a9fSAndrew Rybchenko 		goto fail1;
5083c838a9fSAndrew Rybchenko 	}
5093c838a9fSAndrew Rybchenko 	if (etxop->etxo_qpio_enable == NULL) {
5103c838a9fSAndrew Rybchenko 		rc = ENOTSUP;
5113c838a9fSAndrew Rybchenko 		goto fail2;
5123c838a9fSAndrew Rybchenko 	}
5133c838a9fSAndrew Rybchenko 	if ((rc = etxop->etxo_qpio_enable(etp)) != 0)
5143c838a9fSAndrew Rybchenko 		goto fail3;
5153c838a9fSAndrew Rybchenko 
5163c838a9fSAndrew Rybchenko 	return (0);
5173c838a9fSAndrew Rybchenko 
5183c838a9fSAndrew Rybchenko fail3:
5193c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail3);
5203c838a9fSAndrew Rybchenko fail2:
5213c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
5223c838a9fSAndrew Rybchenko fail1:
523460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
5243c838a9fSAndrew Rybchenko 	return (rc);
5253c838a9fSAndrew Rybchenko }
5263c838a9fSAndrew Rybchenko 
5273c838a9fSAndrew Rybchenko 		void
5283c838a9fSAndrew Rybchenko efx_tx_qpio_disable(
5293c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp)
5303c838a9fSAndrew Rybchenko {
5313c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
532ec831f7fSAndrew Rybchenko 	const efx_tx_ops_t *etxop = enp->en_etxop;
5333c838a9fSAndrew Rybchenko 
5343c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
5353c838a9fSAndrew Rybchenko 
5363c838a9fSAndrew Rybchenko 	if (etxop->etxo_qpio_disable != NULL)
5373c838a9fSAndrew Rybchenko 		etxop->etxo_qpio_disable(etp);
5383c838a9fSAndrew Rybchenko }
5393c838a9fSAndrew Rybchenko 
540460cb568SAndrew Rybchenko 	__checkReturn	efx_rc_t
5413c838a9fSAndrew Rybchenko efx_tx_qpio_write(
5423c838a9fSAndrew Rybchenko 	__in			efx_txq_t *etp,
5433c838a9fSAndrew Rybchenko 	__in_ecount(buf_length)	uint8_t *buffer,
5443c838a9fSAndrew Rybchenko 	__in			size_t buf_length,
5453c838a9fSAndrew Rybchenko 	__in			size_t pio_buf_offset)
5463c838a9fSAndrew Rybchenko {
5473c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
548ec831f7fSAndrew Rybchenko 	const efx_tx_ops_t *etxop = enp->en_etxop;
549460cb568SAndrew Rybchenko 	efx_rc_t rc;
5503c838a9fSAndrew Rybchenko 
5513c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
5523c838a9fSAndrew Rybchenko 
5533c838a9fSAndrew Rybchenko 	if (etxop->etxo_qpio_write != NULL) {
5543c838a9fSAndrew Rybchenko 		if ((rc = etxop->etxo_qpio_write(etp, buffer, buf_length,
5553c838a9fSAndrew Rybchenko 						pio_buf_offset)) != 0)
5563c838a9fSAndrew Rybchenko 			goto fail1;
5573c838a9fSAndrew Rybchenko 		return (0);
5583c838a9fSAndrew Rybchenko 	}
5593c838a9fSAndrew Rybchenko 
5603c838a9fSAndrew Rybchenko 	return (ENOTSUP);
5613c838a9fSAndrew Rybchenko 
5623c838a9fSAndrew Rybchenko fail1:
563460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
5643c838a9fSAndrew Rybchenko 	return (rc);
5653c838a9fSAndrew Rybchenko }
5663c838a9fSAndrew Rybchenko 
567460cb568SAndrew Rybchenko 	__checkReturn	efx_rc_t
5683c838a9fSAndrew Rybchenko efx_tx_qpio_post(
5693c838a9fSAndrew Rybchenko 	__in			efx_txq_t *etp,
5703c838a9fSAndrew Rybchenko 	__in			size_t pkt_length,
5713c838a9fSAndrew Rybchenko 	__in			unsigned int completed,
5723c838a9fSAndrew Rybchenko 	__inout			unsigned int *addedp)
5733c838a9fSAndrew Rybchenko {
5743c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
575ec831f7fSAndrew Rybchenko 	const efx_tx_ops_t *etxop = enp->en_etxop;
576460cb568SAndrew Rybchenko 	efx_rc_t rc;
5773c838a9fSAndrew Rybchenko 
5783c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
5793c838a9fSAndrew Rybchenko 
5803c838a9fSAndrew Rybchenko 	if (etxop->etxo_qpio_post != NULL) {
5813c838a9fSAndrew Rybchenko 		if ((rc = etxop->etxo_qpio_post(etp, pkt_length, completed,
5823c838a9fSAndrew Rybchenko 						addedp)) != 0)
5833c838a9fSAndrew Rybchenko 			goto fail1;
5843c838a9fSAndrew Rybchenko 		return (0);
5853c838a9fSAndrew Rybchenko 	}
5863c838a9fSAndrew Rybchenko 
5873c838a9fSAndrew Rybchenko 	return (ENOTSUP);
5883c838a9fSAndrew Rybchenko 
5893c838a9fSAndrew Rybchenko fail1:
590460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
5913c838a9fSAndrew Rybchenko 	return (rc);
5923c838a9fSAndrew Rybchenko }
5933c838a9fSAndrew Rybchenko 
594460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
5953c838a9fSAndrew Rybchenko efx_tx_qdesc_post(
5963c838a9fSAndrew Rybchenko 	__in			efx_txq_t *etp,
5970c9ef1f5SAndrew Rybchenko 	__in_ecount(ndescs)	efx_desc_t *ed,
5980c9ef1f5SAndrew Rybchenko 	__in			unsigned int ndescs,
5993c838a9fSAndrew Rybchenko 	__in			unsigned int completed,
6003c838a9fSAndrew Rybchenko 	__inout			unsigned int *addedp)
6013c838a9fSAndrew Rybchenko {
6023c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
603ec831f7fSAndrew Rybchenko 	const efx_tx_ops_t *etxop = enp->en_etxop;
604460cb568SAndrew Rybchenko 	efx_rc_t rc;
6053c838a9fSAndrew Rybchenko 
6063c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
6073c838a9fSAndrew Rybchenko 
6083c838a9fSAndrew Rybchenko 	if ((rc = etxop->etxo_qdesc_post(etp, ed,
6090c9ef1f5SAndrew Rybchenko 	    ndescs, completed, addedp)) != 0)
6103c838a9fSAndrew Rybchenko 		goto fail1;
6113c838a9fSAndrew Rybchenko 
6123c838a9fSAndrew Rybchenko 	return (0);
6133c838a9fSAndrew Rybchenko 
6143c838a9fSAndrew Rybchenko fail1:
615460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
6163c838a9fSAndrew Rybchenko 	return (rc);
6173c838a9fSAndrew Rybchenko }
6183c838a9fSAndrew Rybchenko 
6193c838a9fSAndrew Rybchenko 	void
6203c838a9fSAndrew Rybchenko efx_tx_qdesc_dma_create(
6213c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp,
6223c838a9fSAndrew Rybchenko 	__in	efsys_dma_addr_t addr,
6233c838a9fSAndrew Rybchenko 	__in	size_t size,
6243c838a9fSAndrew Rybchenko 	__in	boolean_t eop,
6253c838a9fSAndrew Rybchenko 	__out	efx_desc_t *edp)
6263c838a9fSAndrew Rybchenko {
6273c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
628ec831f7fSAndrew Rybchenko 	const efx_tx_ops_t *etxop = enp->en_etxop;
6293c838a9fSAndrew Rybchenko 
6303c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
6313c838a9fSAndrew Rybchenko 	EFSYS_ASSERT(etxop->etxo_qdesc_dma_create != NULL);
6323c838a9fSAndrew Rybchenko 
6333c838a9fSAndrew Rybchenko 	etxop->etxo_qdesc_dma_create(etp, addr, size, eop, edp);
6343c838a9fSAndrew Rybchenko }
6353c838a9fSAndrew Rybchenko 
6363c838a9fSAndrew Rybchenko 	void
6373c838a9fSAndrew Rybchenko efx_tx_qdesc_tso_create(
6383c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp,
6393c838a9fSAndrew Rybchenko 	__in	uint16_t ipv4_id,
6403c838a9fSAndrew Rybchenko 	__in	uint32_t tcp_seq,
6413c838a9fSAndrew Rybchenko 	__in	uint8_t  tcp_flags,
6423c838a9fSAndrew Rybchenko 	__out	efx_desc_t *edp)
6433c838a9fSAndrew Rybchenko {
6443c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
645ec831f7fSAndrew Rybchenko 	const efx_tx_ops_t *etxop = enp->en_etxop;
6463c838a9fSAndrew Rybchenko 
6473c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
6483c838a9fSAndrew Rybchenko 	EFSYS_ASSERT(etxop->etxo_qdesc_tso_create != NULL);
6493c838a9fSAndrew Rybchenko 
6503c838a9fSAndrew Rybchenko 	etxop->etxo_qdesc_tso_create(etp, ipv4_id, tcp_seq, tcp_flags, edp);
6513c838a9fSAndrew Rybchenko }
6523c838a9fSAndrew Rybchenko 
6533c838a9fSAndrew Rybchenko 	void
6544ab49369SAndrew Rybchenko efx_tx_qdesc_tso2_create(
6554ab49369SAndrew Rybchenko 	__in			efx_txq_t *etp,
6564ab49369SAndrew Rybchenko 	__in			uint16_t ipv4_id,
657*4142e8cfSAndrew Rybchenko 	__in			uint16_t outer_ipv4_id,
6584ab49369SAndrew Rybchenko 	__in			uint32_t tcp_seq,
6594ab49369SAndrew Rybchenko 	__in			uint16_t mss,
6604ab49369SAndrew Rybchenko 	__out_ecount(count)	efx_desc_t *edp,
6614ab49369SAndrew Rybchenko 	__in			int count)
6624ab49369SAndrew Rybchenko {
6634ab49369SAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
664ec831f7fSAndrew Rybchenko 	const efx_tx_ops_t *etxop = enp->en_etxop;
6654ab49369SAndrew Rybchenko 
6664ab49369SAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
6674ab49369SAndrew Rybchenko 	EFSYS_ASSERT(etxop->etxo_qdesc_tso2_create != NULL);
6684ab49369SAndrew Rybchenko 
669*4142e8cfSAndrew Rybchenko 	etxop->etxo_qdesc_tso2_create(etp, ipv4_id, outer_ipv4_id,
670*4142e8cfSAndrew Rybchenko 	    tcp_seq, mss, edp, count);
6714ab49369SAndrew Rybchenko }
6724ab49369SAndrew Rybchenko 
6734ab49369SAndrew Rybchenko 	void
6743c838a9fSAndrew Rybchenko efx_tx_qdesc_vlantci_create(
6753c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp,
6763c838a9fSAndrew Rybchenko 	__in	uint16_t tci,
6773c838a9fSAndrew Rybchenko 	__out	efx_desc_t *edp)
6783c838a9fSAndrew Rybchenko {
6793c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
680ec831f7fSAndrew Rybchenko 	const efx_tx_ops_t *etxop = enp->en_etxop;
6813c838a9fSAndrew Rybchenko 
6823c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
6833c838a9fSAndrew Rybchenko 	EFSYS_ASSERT(etxop->etxo_qdesc_vlantci_create != NULL);
6843c838a9fSAndrew Rybchenko 
6853c838a9fSAndrew Rybchenko 	etxop->etxo_qdesc_vlantci_create(etp, tci, edp);
6863c838a9fSAndrew Rybchenko }
6873c838a9fSAndrew Rybchenko 
6884effeb9eSAndrew Rybchenko 	void
6894effeb9eSAndrew Rybchenko efx_tx_qdesc_checksum_create(
6904effeb9eSAndrew Rybchenko 	__in	efx_txq_t *etp,
6914effeb9eSAndrew Rybchenko 	__in	uint16_t flags,
6924effeb9eSAndrew Rybchenko 	__out	efx_desc_t *edp)
6934effeb9eSAndrew Rybchenko {
6944effeb9eSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
6954effeb9eSAndrew Rybchenko 	const efx_tx_ops_t *etxop = enp->en_etxop;
6964effeb9eSAndrew Rybchenko 
6974effeb9eSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
6984effeb9eSAndrew Rybchenko 	EFSYS_ASSERT(etxop->etxo_qdesc_checksum_create != NULL);
6994effeb9eSAndrew Rybchenko 
7004effeb9eSAndrew Rybchenko 	etxop->etxo_qdesc_checksum_create(etp, flags, edp);
7014effeb9eSAndrew Rybchenko }
7024effeb9eSAndrew Rybchenko 
7033c838a9fSAndrew Rybchenko 
7043c838a9fSAndrew Rybchenko #if EFSYS_OPT_QSTATS
7053c838a9fSAndrew Rybchenko 			void
7063c838a9fSAndrew Rybchenko efx_tx_qstats_update(
7073c838a9fSAndrew Rybchenko 	__in				efx_txq_t *etp,
7083c838a9fSAndrew Rybchenko 	__inout_ecount(TX_NQSTATS)	efsys_stat_t *stat)
7093c838a9fSAndrew Rybchenko {
7103c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
711ec831f7fSAndrew Rybchenko 	const efx_tx_ops_t *etxop = enp->en_etxop;
7123c838a9fSAndrew Rybchenko 
7133c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
7143c838a9fSAndrew Rybchenko 
7153c838a9fSAndrew Rybchenko 	etxop->etxo_qstats_update(etp, stat);
7163c838a9fSAndrew Rybchenko }
7173c838a9fSAndrew Rybchenko #endif
7183c838a9fSAndrew Rybchenko 
7193c838a9fSAndrew Rybchenko 
720e75412c9SAndrew Rybchenko #if EFSYS_OPT_SIENA
7213c838a9fSAndrew Rybchenko 
722460cb568SAndrew Rybchenko static	__checkReturn	efx_rc_t
72396ffcdeeSAndrew Rybchenko siena_tx_init(
7243c838a9fSAndrew Rybchenko 	__in		efx_nic_t *enp)
7253c838a9fSAndrew Rybchenko {
7263c838a9fSAndrew Rybchenko 	efx_oword_t oword;
7273c838a9fSAndrew Rybchenko 
728e948693eSPhilip Paeps 	/*
729e948693eSPhilip Paeps 	 * Disable the timer-based TX DMA backoff and allow TX DMA to be
730e948693eSPhilip Paeps 	 * controlled by the RX FIFO fill level (although always allow a
731e948693eSPhilip Paeps 	 * minimal trickle).
732e948693eSPhilip Paeps 	 */
733e948693eSPhilip Paeps 	EFX_BAR_READO(enp, FR_AZ_TX_RESERVED_REG, &oword);
734e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_RX_SPACER, 0xfe);
735e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_RX_SPACER_EN, 1);
736e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_ONE_PKT_PER_Q, 1);
737e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_PUSH_EN, 0);
738e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DIS_NON_IP_EV, 1);
739e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_PREF_THRESHOLD, 2);
740e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_PREF_WD_TMR, 0x3fffff);
741e948693eSPhilip Paeps 
742e948693eSPhilip Paeps 	/*
743e948693eSPhilip Paeps 	 * Filter all packets less than 14 bytes to avoid parsing
744e948693eSPhilip Paeps 	 * errors.
745e948693eSPhilip Paeps 	 */
746e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1);
747e948693eSPhilip Paeps 	EFX_BAR_WRITEO(enp, FR_AZ_TX_RESERVED_REG, &oword);
748e948693eSPhilip Paeps 
749e948693eSPhilip Paeps 	/*
750e948693eSPhilip Paeps 	 * Do not set TX_NO_EOP_DISC_EN, since it limits packets to 16
751e948693eSPhilip Paeps 	 * descriptors (which is bad).
752e948693eSPhilip Paeps 	 */
753e948693eSPhilip Paeps 	EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword);
754e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_NO_EOP_DISC_EN, 0);
755e948693eSPhilip Paeps 	EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword);
756e948693eSPhilip Paeps 
757e948693eSPhilip Paeps 	return (0);
758e948693eSPhilip Paeps }
759e948693eSPhilip Paeps 
760e948693eSPhilip Paeps #define	EFX_TX_DESC(_etp, _addr, _size, _eop, _added)			\
761e948693eSPhilip Paeps 	do {								\
762e948693eSPhilip Paeps 		unsigned int id;					\
763e948693eSPhilip Paeps 		size_t offset;						\
764e948693eSPhilip Paeps 		efx_qword_t qword;					\
765e948693eSPhilip Paeps 									\
766e948693eSPhilip Paeps 		id = (_added)++ & (_etp)->et_mask;			\
767e948693eSPhilip Paeps 		offset = id * sizeof (efx_qword_t);			\
768e948693eSPhilip Paeps 									\
769e948693eSPhilip Paeps 		EFSYS_PROBE5(tx_post, unsigned int, (_etp)->et_index,	\
770e948693eSPhilip Paeps 		    unsigned int, id, efsys_dma_addr_t, (_addr),	\
771e948693eSPhilip Paeps 		    size_t, (_size), boolean_t, (_eop));		\
772e948693eSPhilip Paeps 									\
773e948693eSPhilip Paeps 		EFX_POPULATE_QWORD_4(qword,				\
774e948693eSPhilip Paeps 		    FSF_AZ_TX_KER_CONT, (_eop) ? 0 : 1,			\
775e948693eSPhilip Paeps 		    FSF_AZ_TX_KER_BYTE_COUNT, (uint32_t)(_size),	\
776e948693eSPhilip Paeps 		    FSF_AZ_TX_KER_BUF_ADDR_DW0,				\
777e948693eSPhilip Paeps 		    (uint32_t)((_addr) & 0xffffffff),			\
778e948693eSPhilip Paeps 		    FSF_AZ_TX_KER_BUF_ADDR_DW1,				\
779e948693eSPhilip Paeps 		    (uint32_t)((_addr) >> 32));				\
780e948693eSPhilip Paeps 		EFSYS_MEM_WRITEQ((_etp)->et_esmp, offset, &qword);	\
781e948693eSPhilip Paeps 									\
782e948693eSPhilip Paeps 		_NOTE(CONSTANTCONDITION)				\
783e948693eSPhilip Paeps 	} while (B_FALSE)
784e948693eSPhilip Paeps 
785460cb568SAndrew Rybchenko static	__checkReturn		efx_rc_t
78696ffcdeeSAndrew Rybchenko siena_tx_qpost(
787e948693eSPhilip Paeps 	__in			efx_txq_t *etp,
7880c9ef1f5SAndrew Rybchenko 	__in_ecount(ndescs)	efx_buffer_t *eb,
7890c9ef1f5SAndrew Rybchenko 	__in			unsigned int ndescs,
790e948693eSPhilip Paeps 	__in			unsigned int completed,
791e948693eSPhilip Paeps 	__inout			unsigned int *addedp)
792e948693eSPhilip Paeps {
793e948693eSPhilip Paeps 	unsigned int added = *addedp;
794e948693eSPhilip Paeps 	unsigned int i;
795e948693eSPhilip Paeps 	int rc = ENOSPC;
796e948693eSPhilip Paeps 
7970c9ef1f5SAndrew Rybchenko 	if (added - completed + ndescs > EFX_TXQ_LIMIT(etp->et_mask + 1))
798e948693eSPhilip Paeps 		goto fail1;
799e948693eSPhilip Paeps 
8000c9ef1f5SAndrew Rybchenko 	for (i = 0; i < ndescs; i++) {
801e948693eSPhilip Paeps 		efx_buffer_t *ebp = &eb[i];
802e948693eSPhilip Paeps 		efsys_dma_addr_t start = ebp->eb_addr;
803e948693eSPhilip Paeps 		size_t size = ebp->eb_size;
804e948693eSPhilip Paeps 		efsys_dma_addr_t end = start + size;
805e948693eSPhilip Paeps 
8066a09b206SAndrew Rybchenko 		/*
8076a09b206SAndrew Rybchenko 		 * Fragments must not span 4k boundaries.
8086a09b206SAndrew Rybchenko 		 * Here it is a stricter requirement than the maximum length.
8096a09b206SAndrew Rybchenko 		 */
8106a09b206SAndrew Rybchenko 		EFSYS_ASSERT(P2ROUNDUP(start + 1,
8116a09b206SAndrew Rybchenko 		    etp->et_enp->en_nic_cfg.enc_tx_dma_desc_boundary) >= end);
812e948693eSPhilip Paeps 
813e948693eSPhilip Paeps 		EFX_TX_DESC(etp, start, size, ebp->eb_eop, added);
814e948693eSPhilip Paeps 	}
815e948693eSPhilip Paeps 
816e948693eSPhilip Paeps 	EFX_TX_QSTAT_INCR(etp, TX_POST);
817e948693eSPhilip Paeps 
818e948693eSPhilip Paeps 	*addedp = added;
819e948693eSPhilip Paeps 	return (0);
820e948693eSPhilip Paeps 
821e948693eSPhilip Paeps fail1:
822460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
823e948693eSPhilip Paeps 
824e948693eSPhilip Paeps 	return (rc);
825e948693eSPhilip Paeps }
826e948693eSPhilip Paeps 
8273c838a9fSAndrew Rybchenko static		void
82896ffcdeeSAndrew Rybchenko siena_tx_qpush(
829e948693eSPhilip Paeps 	__in	efx_txq_t *etp,
8303c838a9fSAndrew Rybchenko 	__in	unsigned int added,
8313c838a9fSAndrew Rybchenko 	__in	unsigned int pushed)
832e948693eSPhilip Paeps {
833e948693eSPhilip Paeps 	efx_nic_t *enp = etp->et_enp;
834e948693eSPhilip Paeps 	uint32_t wptr;
835e948693eSPhilip Paeps 	efx_dword_t dword;
836e948693eSPhilip Paeps 	efx_oword_t oword;
837e948693eSPhilip Paeps 
838e948693eSPhilip Paeps 	/* Push the populated descriptors out */
839e948693eSPhilip Paeps 	wptr = added & etp->et_mask;
840e948693eSPhilip Paeps 
841e948693eSPhilip Paeps 	EFX_POPULATE_OWORD_1(oword, FRF_AZ_TX_DESC_WPTR, wptr);
842e948693eSPhilip Paeps 
843e948693eSPhilip Paeps 	/* Only write the third DWORD */
844e948693eSPhilip Paeps 	EFX_POPULATE_DWORD_1(dword,
845e948693eSPhilip Paeps 	    EFX_DWORD_0, EFX_OWORD_FIELD(oword, EFX_DWORD_3));
8463c838a9fSAndrew Rybchenko 
8473c838a9fSAndrew Rybchenko 	/* Guarantee ordering of memory (descriptors) and PIO (doorbell) */
8483c838a9fSAndrew Rybchenko 	EFX_DMA_SYNC_QUEUE_FOR_DEVICE(etp->et_esmp, etp->et_mask + 1,
8493c838a9fSAndrew Rybchenko 	    wptr, pushed & etp->et_mask);
8503c838a9fSAndrew Rybchenko 	EFSYS_PIO_WRITE_BARRIER();
851e948693eSPhilip Paeps 	EFX_BAR_TBL_WRITED3(enp, FR_BZ_TX_DESC_UPD_REGP0,
852e948693eSPhilip Paeps 			    etp->et_index, &dword, B_FALSE);
853e948693eSPhilip Paeps }
854e948693eSPhilip Paeps 
8552fc13da6SAndrew Rybchenko #define	EFX_MAX_PACE_VALUE 20
8562fc13da6SAndrew Rybchenko #define	EFX_TX_PACE_CLOCK_BASE	104
8572fc13da6SAndrew Rybchenko 
858460cb568SAndrew Rybchenko static	__checkReturn	efx_rc_t
85996ffcdeeSAndrew Rybchenko siena_tx_qpace(
8602fc13da6SAndrew Rybchenko 	__in		efx_txq_t *etp,
8612fc13da6SAndrew Rybchenko 	__in		unsigned int ns)
8622fc13da6SAndrew Rybchenko {
8632fc13da6SAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
8642fc13da6SAndrew Rybchenko 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
8652fc13da6SAndrew Rybchenko 	efx_oword_t oword;
8662fc13da6SAndrew Rybchenko 	unsigned int pace_val;
8672fc13da6SAndrew Rybchenko 	unsigned int timer_period;
868460cb568SAndrew Rybchenko 	efx_rc_t rc;
8692fc13da6SAndrew Rybchenko 
8702fc13da6SAndrew Rybchenko 	if (ns == 0) {
8712fc13da6SAndrew Rybchenko 		pace_val = 0;
8722fc13da6SAndrew Rybchenko 	} else {
8732fc13da6SAndrew Rybchenko 		/*
8742fc13da6SAndrew Rybchenko 		 * The pace_val to write into the table is s.t
8752fc13da6SAndrew Rybchenko 		 * ns <= timer_period * (2 ^ pace_val)
8762fc13da6SAndrew Rybchenko 		 */
8772fc13da6SAndrew Rybchenko 		timer_period = EFX_TX_PACE_CLOCK_BASE / encp->enc_clk_mult;
8782fc13da6SAndrew Rybchenko 		for (pace_val = 1; pace_val <= EFX_MAX_PACE_VALUE; pace_val++) {
8792fc13da6SAndrew Rybchenko 			if ((timer_period << pace_val) >= ns)
8802fc13da6SAndrew Rybchenko 				break;
8812fc13da6SAndrew Rybchenko 		}
8822fc13da6SAndrew Rybchenko 	}
8832fc13da6SAndrew Rybchenko 	if (pace_val > EFX_MAX_PACE_VALUE) {
8842fc13da6SAndrew Rybchenko 		rc = EINVAL;
8852fc13da6SAndrew Rybchenko 		goto fail1;
8862fc13da6SAndrew Rybchenko 	}
8872fc13da6SAndrew Rybchenko 
8882fc13da6SAndrew Rybchenko 	/* Update the pacing table */
8892fc13da6SAndrew Rybchenko 	EFX_POPULATE_OWORD_1(oword, FRF_AZ_TX_PACE, pace_val);
8903c838a9fSAndrew Rybchenko 	EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_PACE_TBL, etp->et_index,
8913c838a9fSAndrew Rybchenko 	    &oword, B_TRUE);
8922fc13da6SAndrew Rybchenko 
8932fc13da6SAndrew Rybchenko 	return (0);
8942fc13da6SAndrew Rybchenko 
8952fc13da6SAndrew Rybchenko fail1:
896460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
8972fc13da6SAndrew Rybchenko 
8982fc13da6SAndrew Rybchenko 	return (rc);
8992fc13da6SAndrew Rybchenko }
9002fc13da6SAndrew Rybchenko 
901460cb568SAndrew Rybchenko static	__checkReturn	efx_rc_t
90296ffcdeeSAndrew Rybchenko siena_tx_qflush(
903e948693eSPhilip Paeps 	__in		efx_txq_t *etp)
904e948693eSPhilip Paeps {
905e948693eSPhilip Paeps 	efx_nic_t *enp = etp->et_enp;
906e948693eSPhilip Paeps 	efx_oword_t oword;
907e948693eSPhilip Paeps 	uint32_t label;
908e948693eSPhilip Paeps 
9092fc13da6SAndrew Rybchenko 	efx_tx_qpace(etp, 0);
9102fc13da6SAndrew Rybchenko 
911e948693eSPhilip Paeps 	label = etp->et_index;
912e948693eSPhilip Paeps 
913e948693eSPhilip Paeps 	/* Flush the queue */
914e948693eSPhilip Paeps 	EFX_POPULATE_OWORD_2(oword, FRF_AZ_TX_FLUSH_DESCQ_CMD, 1,
915e948693eSPhilip Paeps 	    FRF_AZ_TX_FLUSH_DESCQ, label);
916e948693eSPhilip Paeps 	EFX_BAR_WRITEO(enp, FR_AZ_TX_FLUSH_DESCQ_REG, &oword);
9173c838a9fSAndrew Rybchenko 
9183c838a9fSAndrew Rybchenko 	return (0);
919e948693eSPhilip Paeps }
920e948693eSPhilip Paeps 
9213c838a9fSAndrew Rybchenko static		void
92296ffcdeeSAndrew Rybchenko siena_tx_qenable(
923e948693eSPhilip Paeps 	__in	efx_txq_t *etp)
924e948693eSPhilip Paeps {
925e948693eSPhilip Paeps 	efx_nic_t *enp = etp->et_enp;
926e948693eSPhilip Paeps 	efx_oword_t oword;
927e948693eSPhilip Paeps 
928e948693eSPhilip Paeps 	EFX_BAR_TBL_READO(enp, FR_AZ_TX_DESC_PTR_TBL,
9293c838a9fSAndrew Rybchenko 			    etp->et_index, &oword, B_TRUE);
930e948693eSPhilip Paeps 
931e948693eSPhilip Paeps 	EFSYS_PROBE5(tx_descq_ptr, unsigned int, etp->et_index,
932e948693eSPhilip Paeps 	    uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_3),
933e948693eSPhilip Paeps 	    uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_2),
934e948693eSPhilip Paeps 	    uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_1),
935e948693eSPhilip Paeps 	    uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_0));
936e948693eSPhilip Paeps 
937e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DC_HW_RPTR, 0);
938e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DESCQ_HW_RPTR, 0);
939e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DESCQ_EN, 1);
940e948693eSPhilip Paeps 
941e948693eSPhilip Paeps 	EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_DESC_PTR_TBL,
9423c838a9fSAndrew Rybchenko 			    etp->et_index, &oword, B_TRUE);
943e948693eSPhilip Paeps }
944e948693eSPhilip Paeps 
945460cb568SAndrew Rybchenko static	__checkReturn	efx_rc_t
94696ffcdeeSAndrew Rybchenko siena_tx_qcreate(
947e948693eSPhilip Paeps 	__in		efx_nic_t *enp,
948e948693eSPhilip Paeps 	__in		unsigned int index,
949e948693eSPhilip Paeps 	__in		unsigned int label,
950e948693eSPhilip Paeps 	__in		efsys_mem_t *esmp,
9510c9ef1f5SAndrew Rybchenko 	__in		size_t ndescs,
952e948693eSPhilip Paeps 	__in		uint32_t id,
953e948693eSPhilip Paeps 	__in		uint16_t flags,
954e948693eSPhilip Paeps 	__in		efx_evq_t *eep,
9553c838a9fSAndrew Rybchenko 	__in		efx_txq_t *etp,
9563c838a9fSAndrew Rybchenko 	__out		unsigned int *addedp)
957e948693eSPhilip Paeps {
958e948693eSPhilip Paeps 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
959e948693eSPhilip Paeps 	efx_oword_t oword;
960e948693eSPhilip Paeps 	uint32_t size;
96118b602f9SAndrew Rybchenko 	uint16_t inner_csum;
962460cb568SAndrew Rybchenko 	efx_rc_t rc;
963e948693eSPhilip Paeps 
964a92a2133SAndrew Rybchenko 	_NOTE(ARGUNUSED(esmp))
965a92a2133SAndrew Rybchenko 
966c071447aSAndrew Rybchenko 	EFX_STATIC_ASSERT(EFX_EV_TX_NLABELS ==
967c071447aSAndrew Rybchenko 	    (1 << FRF_AZ_TX_DESCQ_LABEL_WIDTH));
968c071447aSAndrew Rybchenko 	EFSYS_ASSERT3U(label, <, EFX_EV_TX_NLABELS);
969e948693eSPhilip Paeps 
970d343a7f4SAndrew Rybchenko 	EFSYS_ASSERT(ISP2(encp->enc_txq_max_ndescs));
9713c838a9fSAndrew Rybchenko 	EFX_STATIC_ASSERT(ISP2(EFX_TXQ_MINNDESCS));
9723c838a9fSAndrew Rybchenko 
9730c9ef1f5SAndrew Rybchenko 	if (!ISP2(ndescs) ||
9740c9ef1f5SAndrew Rybchenko 	    (ndescs < EFX_TXQ_MINNDESCS) || (ndescs > EFX_EVQ_MAXNEVS)) {
975e948693eSPhilip Paeps 		rc = EINVAL;
976e948693eSPhilip Paeps 		goto fail1;
977e948693eSPhilip Paeps 	}
978e948693eSPhilip Paeps 	if (index >= encp->enc_txq_limit) {
979e948693eSPhilip Paeps 		rc = EINVAL;
980e948693eSPhilip Paeps 		goto fail2;
981e948693eSPhilip Paeps 	}
9823c838a9fSAndrew Rybchenko 	for (size = 0;
983d343a7f4SAndrew Rybchenko 	    (1 << size) <= (int)(encp->enc_txq_max_ndescs / EFX_TXQ_MINNDESCS);
984e948693eSPhilip Paeps 	    size++)
9850c9ef1f5SAndrew Rybchenko 		if ((1 << size) == (int)(ndescs / EFX_TXQ_MINNDESCS))
986e948693eSPhilip Paeps 			break;
987e948693eSPhilip Paeps 	if (id + (1 << size) >= encp->enc_buftbl_limit) {
988e948693eSPhilip Paeps 		rc = EINVAL;
989e948693eSPhilip Paeps 		goto fail3;
990e948693eSPhilip Paeps 	}
991e948693eSPhilip Paeps 
99218b602f9SAndrew Rybchenko 	inner_csum = EFX_TXQ_CKSUM_INNER_IPV4 | EFX_TXQ_CKSUM_INNER_TCPUDP;
99318b602f9SAndrew Rybchenko 	if ((flags & inner_csum) != 0) {
99418b602f9SAndrew Rybchenko 		rc = EINVAL;
99518b602f9SAndrew Rybchenko 		goto fail4;
99618b602f9SAndrew Rybchenko 	}
99718b602f9SAndrew Rybchenko 
998e948693eSPhilip Paeps 	/* Set up the new descriptor queue */
99945229bd4SAndrew Rybchenko 	*addedp = 0;
100045229bd4SAndrew Rybchenko 
1001e948693eSPhilip Paeps 	EFX_POPULATE_OWORD_6(oword,
1002e948693eSPhilip Paeps 	    FRF_AZ_TX_DESCQ_BUF_BASE_ID, id,
1003e948693eSPhilip Paeps 	    FRF_AZ_TX_DESCQ_EVQ_ID, eep->ee_index,
1004e948693eSPhilip Paeps 	    FRF_AZ_TX_DESCQ_OWNER_ID, 0,
1005e948693eSPhilip Paeps 	    FRF_AZ_TX_DESCQ_LABEL, label,
1006e948693eSPhilip Paeps 	    FRF_AZ_TX_DESCQ_SIZE, size,
1007e948693eSPhilip Paeps 	    FRF_AZ_TX_DESCQ_TYPE, 0);
1008e948693eSPhilip Paeps 
1009e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_NON_IP_DROP_DIS, 1);
1010e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_IP_CHKSM_DIS,
10119dd0e15fSAndrew Rybchenko 	    (flags & EFX_TXQ_CKSUM_IPV4) ? 0 : 1);
1012e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_TCP_CHKSM_DIS,
10139dd0e15fSAndrew Rybchenko 	    (flags & EFX_TXQ_CKSUM_TCPUDP) ? 0 : 1);
1014e948693eSPhilip Paeps 
1015e948693eSPhilip Paeps 	EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_DESC_PTR_TBL,
10163c838a9fSAndrew Rybchenko 	    etp->et_index, &oword, B_TRUE);
1017e948693eSPhilip Paeps 
1018e948693eSPhilip Paeps 	return (0);
1019e948693eSPhilip Paeps 
102018b602f9SAndrew Rybchenko fail4:
102118b602f9SAndrew Rybchenko 	EFSYS_PROBE(fail4);
1022e948693eSPhilip Paeps fail3:
1023e948693eSPhilip Paeps 	EFSYS_PROBE(fail3);
1024e948693eSPhilip Paeps fail2:
1025e948693eSPhilip Paeps 	EFSYS_PROBE(fail2);
1026e948693eSPhilip Paeps fail1:
1027460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1028e948693eSPhilip Paeps 
1029e948693eSPhilip Paeps 	return (rc);
1030e948693eSPhilip Paeps }
1031e948693eSPhilip Paeps 
1032460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
103396ffcdeeSAndrew Rybchenko siena_tx_qdesc_post(
10343c838a9fSAndrew Rybchenko 	__in			efx_txq_t *etp,
10350c9ef1f5SAndrew Rybchenko 	__in_ecount(ndescs)	efx_desc_t *ed,
10360c9ef1f5SAndrew Rybchenko 	__in			unsigned int ndescs,
10373c838a9fSAndrew Rybchenko 	__in			unsigned int completed,
10383c838a9fSAndrew Rybchenko 	__inout			unsigned int *addedp)
10393c838a9fSAndrew Rybchenko {
10403c838a9fSAndrew Rybchenko 	unsigned int added = *addedp;
10413c838a9fSAndrew Rybchenko 	unsigned int i;
1042460cb568SAndrew Rybchenko 	efx_rc_t rc;
10433c838a9fSAndrew Rybchenko 
10440c9ef1f5SAndrew Rybchenko 	if (added - completed + ndescs > EFX_TXQ_LIMIT(etp->et_mask + 1)) {
10453c838a9fSAndrew Rybchenko 		rc = ENOSPC;
10463c838a9fSAndrew Rybchenko 		goto fail1;
10473c838a9fSAndrew Rybchenko 	}
10483c838a9fSAndrew Rybchenko 
10490c9ef1f5SAndrew Rybchenko 	for (i = 0; i < ndescs; i++) {
10503c838a9fSAndrew Rybchenko 		efx_desc_t *edp = &ed[i];
10513c838a9fSAndrew Rybchenko 		unsigned int id;
10523c838a9fSAndrew Rybchenko 		size_t offset;
10533c838a9fSAndrew Rybchenko 
10543c838a9fSAndrew Rybchenko 		id = added++ & etp->et_mask;
10553c838a9fSAndrew Rybchenko 		offset = id * sizeof (efx_desc_t);
10563c838a9fSAndrew Rybchenko 
10573c838a9fSAndrew Rybchenko 		EFSYS_MEM_WRITEQ(etp->et_esmp, offset, &edp->ed_eq);
10583c838a9fSAndrew Rybchenko 	}
10593c838a9fSAndrew Rybchenko 
10603c838a9fSAndrew Rybchenko 	EFSYS_PROBE3(tx_desc_post, unsigned int, etp->et_index,
10610c9ef1f5SAndrew Rybchenko 		    unsigned int, added, unsigned int, ndescs);
10623c838a9fSAndrew Rybchenko 
10633c838a9fSAndrew Rybchenko 	EFX_TX_QSTAT_INCR(etp, TX_POST);
10643c838a9fSAndrew Rybchenko 
10653c838a9fSAndrew Rybchenko 	*addedp = added;
10663c838a9fSAndrew Rybchenko 	return (0);
10673c838a9fSAndrew Rybchenko 
10683c838a9fSAndrew Rybchenko fail1:
1069460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
10703c838a9fSAndrew Rybchenko 	return (rc);
10713c838a9fSAndrew Rybchenko }
10723c838a9fSAndrew Rybchenko 
10733c838a9fSAndrew Rybchenko 	void
107496ffcdeeSAndrew Rybchenko siena_tx_qdesc_dma_create(
10753c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp,
10763c838a9fSAndrew Rybchenko 	__in	efsys_dma_addr_t addr,
10773c838a9fSAndrew Rybchenko 	__in	size_t size,
10783c838a9fSAndrew Rybchenko 	__in	boolean_t eop,
10793c838a9fSAndrew Rybchenko 	__out	efx_desc_t *edp)
10803c838a9fSAndrew Rybchenko {
10816a09b206SAndrew Rybchenko 	/*
10826a09b206SAndrew Rybchenko 	 * Fragments must not span 4k boundaries.
10836a09b206SAndrew Rybchenko 	 * Here it is a stricter requirement than the maximum length.
10846a09b206SAndrew Rybchenko 	 */
10856a09b206SAndrew Rybchenko 	EFSYS_ASSERT(P2ROUNDUP(addr + 1,
10866a09b206SAndrew Rybchenko 	    etp->et_enp->en_nic_cfg.enc_tx_dma_desc_boundary) >= addr + size);
10873c838a9fSAndrew Rybchenko 
10883c838a9fSAndrew Rybchenko 	EFSYS_PROBE4(tx_desc_dma_create, unsigned int, etp->et_index,
10893c838a9fSAndrew Rybchenko 		    efsys_dma_addr_t, addr,
10903c838a9fSAndrew Rybchenko 		    size_t, size, boolean_t, eop);
10913c838a9fSAndrew Rybchenko 
10923c838a9fSAndrew Rybchenko 	EFX_POPULATE_QWORD_4(edp->ed_eq,
10933c838a9fSAndrew Rybchenko 			    FSF_AZ_TX_KER_CONT, eop ? 0 : 1,
10943c838a9fSAndrew Rybchenko 			    FSF_AZ_TX_KER_BYTE_COUNT, (uint32_t)size,
10953c838a9fSAndrew Rybchenko 			    FSF_AZ_TX_KER_BUF_ADDR_DW0,
10963c838a9fSAndrew Rybchenko 			    (uint32_t)(addr & 0xffffffff),
10973c838a9fSAndrew Rybchenko 			    FSF_AZ_TX_KER_BUF_ADDR_DW1,
10983c838a9fSAndrew Rybchenko 			    (uint32_t)(addr >> 32));
10993c838a9fSAndrew Rybchenko }
11003c838a9fSAndrew Rybchenko 
1101e75412c9SAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */
11023c838a9fSAndrew Rybchenko 
1103fe900081SAndrew Rybchenko #if EFSYS_OPT_QSTATS
1104e948693eSPhilip Paeps #if EFSYS_OPT_NAMES
1105a260bd77SAndrew Rybchenko /* START MKCONFIG GENERATED EfxTransmitQueueStatNamesBlock 2866874ecd7a363b */
1106a260bd77SAndrew Rybchenko static const char * const __efx_tx_qstat_name[] = {
1107e948693eSPhilip Paeps 	"post",
11083c838a9fSAndrew Rybchenko 	"post_pio",
1109e948693eSPhilip Paeps };
1110e948693eSPhilip Paeps /* END MKCONFIG GENERATED EfxTransmitQueueStatNamesBlock */
1111e948693eSPhilip Paeps 
11123c838a9fSAndrew Rybchenko 		const char *
1113e948693eSPhilip Paeps efx_tx_qstat_name(
1114e948693eSPhilip Paeps 	__in	efx_nic_t *enp,
1115e948693eSPhilip Paeps 	__in	unsigned int id)
1116e948693eSPhilip Paeps {
1117e948693eSPhilip Paeps 	_NOTE(ARGUNUSED(enp))
1118e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1119e948693eSPhilip Paeps 	EFSYS_ASSERT3U(id, <, TX_NQSTATS);
1120e948693eSPhilip Paeps 
1121e948693eSPhilip Paeps 	return (__efx_tx_qstat_name[id]);
1122e948693eSPhilip Paeps }
1123e948693eSPhilip Paeps #endif	/* EFSYS_OPT_NAMES */
1124fe900081SAndrew Rybchenko #endif /* EFSYS_OPT_QSTATS */
1125e948693eSPhilip Paeps 
1126e75412c9SAndrew Rybchenko #if EFSYS_OPT_SIENA
11273c838a9fSAndrew Rybchenko 
1128e948693eSPhilip Paeps #if EFSYS_OPT_QSTATS
11293c838a9fSAndrew Rybchenko static					void
113096ffcdeeSAndrew Rybchenko siena_tx_qstats_update(
1131e948693eSPhilip Paeps 	__in				efx_txq_t *etp,
1132e948693eSPhilip Paeps 	__inout_ecount(TX_NQSTATS)	efsys_stat_t *stat)
1133e948693eSPhilip Paeps {
1134e948693eSPhilip Paeps 	unsigned int id;
1135e948693eSPhilip Paeps 
1136e948693eSPhilip Paeps 	for (id = 0; id < TX_NQSTATS; id++) {
1137e948693eSPhilip Paeps 		efsys_stat_t *essp = &stat[id];
1138e948693eSPhilip Paeps 
1139e948693eSPhilip Paeps 		EFSYS_STAT_INCR(essp, etp->et_stat[id]);
1140e948693eSPhilip Paeps 		etp->et_stat[id] = 0;
1141e948693eSPhilip Paeps 	}
1142e948693eSPhilip Paeps }
1143e948693eSPhilip Paeps #endif	/* EFSYS_OPT_QSTATS */
1144e948693eSPhilip Paeps 
11453c838a9fSAndrew Rybchenko static		void
114696ffcdeeSAndrew Rybchenko siena_tx_qdestroy(
1147e948693eSPhilip Paeps 	__in	efx_txq_t *etp)
1148e948693eSPhilip Paeps {
1149e948693eSPhilip Paeps 	efx_nic_t *enp = etp->et_enp;
1150e948693eSPhilip Paeps 	efx_oword_t oword;
1151e948693eSPhilip Paeps 
1152e948693eSPhilip Paeps 	/* Purge descriptor queue */
1153e948693eSPhilip Paeps 	EFX_ZERO_OWORD(oword);
1154e948693eSPhilip Paeps 
1155e948693eSPhilip Paeps 	EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_DESC_PTR_TBL,
11563c838a9fSAndrew Rybchenko 			    etp->et_index, &oword, B_TRUE);
1157e948693eSPhilip Paeps }
1158e948693eSPhilip Paeps 
11593c838a9fSAndrew Rybchenko static		void
116096ffcdeeSAndrew Rybchenko siena_tx_fini(
1161e948693eSPhilip Paeps 	__in	efx_nic_t *enp)
1162e948693eSPhilip Paeps {
11633c838a9fSAndrew Rybchenko 	_NOTE(ARGUNUSED(enp))
1164e948693eSPhilip Paeps }
11653c838a9fSAndrew Rybchenko 
1166e75412c9SAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */
1167