xref: /freebsd/sys/dev/sfxge/common/efx_tx.c (revision 45229bd409651f852d589e75c65d25c6a15bc0cd)
1e948693eSPhilip Paeps /*-
23c838a9fSAndrew Rybchenko  * Copyright (c) 2007-2015 Solarflare Communications Inc.
33c838a9fSAndrew Rybchenko  * All rights reserved.
4e948693eSPhilip Paeps  *
5e948693eSPhilip Paeps  * Redistribution and use in source and binary forms, with or without
63c838a9fSAndrew Rybchenko  * modification, are permitted provided that the following conditions are met:
7e948693eSPhilip Paeps  *
83c838a9fSAndrew Rybchenko  * 1. Redistributions of source code must retain the above copyright notice,
93c838a9fSAndrew Rybchenko  *    this list of conditions and the following disclaimer.
103c838a9fSAndrew Rybchenko  * 2. Redistributions in binary form must reproduce the above copyright notice,
113c838a9fSAndrew Rybchenko  *    this list of conditions and the following disclaimer in the documentation
123c838a9fSAndrew Rybchenko  *    and/or other materials provided with the distribution.
133c838a9fSAndrew Rybchenko  *
143c838a9fSAndrew Rybchenko  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
153c838a9fSAndrew Rybchenko  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
163c838a9fSAndrew Rybchenko  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
173c838a9fSAndrew Rybchenko  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
183c838a9fSAndrew Rybchenko  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
193c838a9fSAndrew Rybchenko  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
203c838a9fSAndrew Rybchenko  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
213c838a9fSAndrew Rybchenko  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
223c838a9fSAndrew Rybchenko  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
233c838a9fSAndrew Rybchenko  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
243c838a9fSAndrew Rybchenko  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
253c838a9fSAndrew Rybchenko  *
263c838a9fSAndrew Rybchenko  * The views and conclusions contained in the software and documentation are
273c838a9fSAndrew Rybchenko  * those of the authors and should not be interpreted as representing official
283c838a9fSAndrew Rybchenko  * policies, either expressed or implied, of the FreeBSD Project.
29e948693eSPhilip Paeps  */
30e948693eSPhilip Paeps 
315dee87d7SPhilip Paeps #include <sys/cdefs.h>
325dee87d7SPhilip Paeps __FBSDID("$FreeBSD$");
335dee87d7SPhilip Paeps 
34e948693eSPhilip Paeps #include "efsys.h"
35e948693eSPhilip Paeps #include "efx.h"
36e948693eSPhilip Paeps #include "efx_types.h"
37e948693eSPhilip Paeps #include "efx_regs.h"
38e948693eSPhilip Paeps #include "efx_impl.h"
39e948693eSPhilip Paeps 
40e948693eSPhilip Paeps #if EFSYS_OPT_QSTATS
41e948693eSPhilip Paeps #define	EFX_TX_QSTAT_INCR(_etp, _stat)					\
42e948693eSPhilip Paeps 	do {								\
43e948693eSPhilip Paeps 		(_etp)->et_stat[_stat]++;				\
44e948693eSPhilip Paeps 	_NOTE(CONSTANTCONDITION)					\
45e948693eSPhilip Paeps 	} while (B_FALSE)
46e948693eSPhilip Paeps #else
47e948693eSPhilip Paeps #define	EFX_TX_QSTAT_INCR(_etp, _stat)
48e948693eSPhilip Paeps #endif
49e948693eSPhilip Paeps 
503c838a9fSAndrew Rybchenko #if EFSYS_OPT_FALCON || EFSYS_OPT_SIENA
513c838a9fSAndrew Rybchenko 
523c838a9fSAndrew Rybchenko static	__checkReturn	int
533c838a9fSAndrew Rybchenko falconsiena_tx_init(
543c838a9fSAndrew Rybchenko 	__in		efx_nic_t *enp);
553c838a9fSAndrew Rybchenko 
563c838a9fSAndrew Rybchenko static			void
573c838a9fSAndrew Rybchenko falconsiena_tx_fini(
583c838a9fSAndrew Rybchenko 	__in		efx_nic_t *enp);
593c838a9fSAndrew Rybchenko 
603c838a9fSAndrew Rybchenko static	__checkReturn	int
613c838a9fSAndrew Rybchenko falconsiena_tx_qcreate(
623c838a9fSAndrew Rybchenko 	__in		efx_nic_t *enp,
633c838a9fSAndrew Rybchenko 	__in		unsigned int index,
643c838a9fSAndrew Rybchenko 	__in		unsigned int label,
653c838a9fSAndrew Rybchenko 	__in		efsys_mem_t *esmp,
663c838a9fSAndrew Rybchenko 	__in		size_t n,
673c838a9fSAndrew Rybchenko 	__in		uint32_t id,
683c838a9fSAndrew Rybchenko 	__in		uint16_t flags,
693c838a9fSAndrew Rybchenko 	__in		efx_evq_t *eep,
703c838a9fSAndrew Rybchenko 	__in		efx_txq_t *etp,
713c838a9fSAndrew Rybchenko 	__out		unsigned int *addedp);
723c838a9fSAndrew Rybchenko 
733c838a9fSAndrew Rybchenko static		void
743c838a9fSAndrew Rybchenko falconsiena_tx_qdestroy(
753c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp);
763c838a9fSAndrew Rybchenko 
773c838a9fSAndrew Rybchenko static	__checkReturn	int
783c838a9fSAndrew Rybchenko falconsiena_tx_qpost(
793c838a9fSAndrew Rybchenko 	__in		efx_txq_t *etp,
803c838a9fSAndrew Rybchenko 	__in_ecount(n)	efx_buffer_t *eb,
813c838a9fSAndrew Rybchenko 	__in		unsigned int n,
823c838a9fSAndrew Rybchenko 	__in		unsigned int completed,
833c838a9fSAndrew Rybchenko 	__inout		unsigned int *addedp);
843c838a9fSAndrew Rybchenko 
853c838a9fSAndrew Rybchenko static			void
863c838a9fSAndrew Rybchenko falconsiena_tx_qpush(
873c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp,
883c838a9fSAndrew Rybchenko 	__in	unsigned int added,
893c838a9fSAndrew Rybchenko 	__in	unsigned int pushed);
903c838a9fSAndrew Rybchenko 
913c838a9fSAndrew Rybchenko static	__checkReturn	int
923c838a9fSAndrew Rybchenko falconsiena_tx_qpace(
933c838a9fSAndrew Rybchenko 	__in		efx_txq_t *etp,
943c838a9fSAndrew Rybchenko 	__in		unsigned int ns);
953c838a9fSAndrew Rybchenko 
963c838a9fSAndrew Rybchenko static	__checkReturn	int
973c838a9fSAndrew Rybchenko falconsiena_tx_qflush(
983c838a9fSAndrew Rybchenko 	__in		efx_txq_t *etp);
993c838a9fSAndrew Rybchenko 
1003c838a9fSAndrew Rybchenko static			void
1013c838a9fSAndrew Rybchenko falconsiena_tx_qenable(
1023c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp);
1033c838a9fSAndrew Rybchenko 
1043c838a9fSAndrew Rybchenko 	__checkReturn	int
1053c838a9fSAndrew Rybchenko falconsiena_tx_qdesc_post(
1063c838a9fSAndrew Rybchenko 	__in		efx_txq_t *etp,
1073c838a9fSAndrew Rybchenko 	__in_ecount(n)	efx_desc_t *ed,
1083c838a9fSAndrew Rybchenko 	__in		unsigned int n,
1093c838a9fSAndrew Rybchenko 	__in		unsigned int completed,
1103c838a9fSAndrew Rybchenko 	__inout		unsigned int *addedp);
1113c838a9fSAndrew Rybchenko 
1123c838a9fSAndrew Rybchenko 	void
1133c838a9fSAndrew Rybchenko falconsiena_tx_qdesc_dma_create(
1143c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp,
1153c838a9fSAndrew Rybchenko 	__in	efsys_dma_addr_t addr,
1163c838a9fSAndrew Rybchenko 	__in	size_t size,
1173c838a9fSAndrew Rybchenko 	__in	boolean_t eop,
1183c838a9fSAndrew Rybchenko 	__out	efx_desc_t *edp);
1193c838a9fSAndrew Rybchenko 
1203c838a9fSAndrew Rybchenko #if EFSYS_OPT_QSTATS
1213c838a9fSAndrew Rybchenko static			void
1223c838a9fSAndrew Rybchenko falconsiena_tx_qstats_update(
1233c838a9fSAndrew Rybchenko 	__in				efx_txq_t *etp,
1243c838a9fSAndrew Rybchenko 	__inout_ecount(TX_NQSTATS)	efsys_stat_t *stat);
1253c838a9fSAndrew Rybchenko #endif
1263c838a9fSAndrew Rybchenko 
1273c838a9fSAndrew Rybchenko #endif /* EFSYS_OPT_FALCON || EFSYS_OPT_SIENA */
1283c838a9fSAndrew Rybchenko 
1293c838a9fSAndrew Rybchenko 
1303c838a9fSAndrew Rybchenko #if EFSYS_OPT_FALCON
1313c838a9fSAndrew Rybchenko static efx_tx_ops_t	__efx_tx_falcon_ops = {
1323c838a9fSAndrew Rybchenko 	falconsiena_tx_init,			/* etxo_init */
1333c838a9fSAndrew Rybchenko 	falconsiena_tx_fini,			/* etxo_fini */
1343c838a9fSAndrew Rybchenko 	falconsiena_tx_qcreate,			/* etxo_qcreate */
1353c838a9fSAndrew Rybchenko 	falconsiena_tx_qdestroy,		/* etxo_qdestroy */
1363c838a9fSAndrew Rybchenko 	falconsiena_tx_qpost,			/* etxo_qpost */
1373c838a9fSAndrew Rybchenko 	falconsiena_tx_qpush,			/* etxo_qpush */
1383c838a9fSAndrew Rybchenko 	falconsiena_tx_qpace,			/* etxo_qpace */
1393c838a9fSAndrew Rybchenko 	falconsiena_tx_qflush,			/* etxo_qflush */
1403c838a9fSAndrew Rybchenko 	falconsiena_tx_qenable,			/* etxo_qenable */
1413c838a9fSAndrew Rybchenko 	NULL,					/* etxo_qpio_enable */
1423c838a9fSAndrew Rybchenko 	NULL,					/* etxo_qpio_disable */
1433c838a9fSAndrew Rybchenko 	NULL,					/* etxo_qpio_write */
1443c838a9fSAndrew Rybchenko 	NULL,					/* etxo_qpio_post */
1453c838a9fSAndrew Rybchenko 	falconsiena_tx_qdesc_post,		/* etxo_qdesc_post */
1463c838a9fSAndrew Rybchenko 	falconsiena_tx_qdesc_dma_create,	/* etxo_qdesc_dma_create */
1473c838a9fSAndrew Rybchenko 	NULL,					/* etxo_qdesc_tso_create */
1483c838a9fSAndrew Rybchenko 	NULL,					/* etxo_qdesc_vlantci_create */
1493c838a9fSAndrew Rybchenko #if EFSYS_OPT_QSTATS
1503c838a9fSAndrew Rybchenko 	falconsiena_tx_qstats_update,		/* etxo_qstats_update */
1513c838a9fSAndrew Rybchenko #endif
1523c838a9fSAndrew Rybchenko };
1533c838a9fSAndrew Rybchenko #endif /* EFSYS_OPT_FALCON */
1543c838a9fSAndrew Rybchenko 
1553c838a9fSAndrew Rybchenko #if EFSYS_OPT_SIENA
1563c838a9fSAndrew Rybchenko static efx_tx_ops_t	__efx_tx_siena_ops = {
1573c838a9fSAndrew Rybchenko 	falconsiena_tx_init,			/* etxo_init */
1583c838a9fSAndrew Rybchenko 	falconsiena_tx_fini,			/* etxo_fini */
1593c838a9fSAndrew Rybchenko 	falconsiena_tx_qcreate,			/* etxo_qcreate */
1603c838a9fSAndrew Rybchenko 	falconsiena_tx_qdestroy,		/* etxo_qdestroy */
1613c838a9fSAndrew Rybchenko 	falconsiena_tx_qpost,			/* etxo_qpost */
1623c838a9fSAndrew Rybchenko 	falconsiena_tx_qpush,			/* etxo_qpush */
1633c838a9fSAndrew Rybchenko 	falconsiena_tx_qpace,			/* etxo_qpace */
1643c838a9fSAndrew Rybchenko 	falconsiena_tx_qflush,			/* etxo_qflush */
1653c838a9fSAndrew Rybchenko 	falconsiena_tx_qenable,			/* etxo_qenable */
1663c838a9fSAndrew Rybchenko 	NULL,					/* etxo_qpio_enable */
1673c838a9fSAndrew Rybchenko 	NULL,					/* etxo_qpio_disable */
1683c838a9fSAndrew Rybchenko 	NULL,					/* etxo_qpio_write */
1693c838a9fSAndrew Rybchenko 	NULL,					/* etxo_qpio_post */
1703c838a9fSAndrew Rybchenko 	falconsiena_tx_qdesc_post,		/* etxo_qdesc_post */
1713c838a9fSAndrew Rybchenko 	falconsiena_tx_qdesc_dma_create,	/* etxo_qdesc_dma_create */
1723c838a9fSAndrew Rybchenko 	NULL,					/* etxo_qdesc_tso_create */
1733c838a9fSAndrew Rybchenko 	NULL,					/* etxo_qdesc_vlantci_create */
1743c838a9fSAndrew Rybchenko #if EFSYS_OPT_QSTATS
1753c838a9fSAndrew Rybchenko 	falconsiena_tx_qstats_update,		/* etxo_qstats_update */
1763c838a9fSAndrew Rybchenko #endif
1773c838a9fSAndrew Rybchenko };
1783c838a9fSAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */
1793c838a9fSAndrew Rybchenko 
1803c838a9fSAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON
1813c838a9fSAndrew Rybchenko static efx_tx_ops_t	__efx_tx_hunt_ops = {
1823c838a9fSAndrew Rybchenko 	hunt_tx_init,				/* etxo_init */
1833c838a9fSAndrew Rybchenko 	hunt_tx_fini,				/* etxo_fini */
1843c838a9fSAndrew Rybchenko 	hunt_tx_qcreate,			/* etxo_qcreate */
1853c838a9fSAndrew Rybchenko 	hunt_tx_qdestroy,			/* etxo_qdestroy */
1863c838a9fSAndrew Rybchenko 	hunt_tx_qpost,				/* etxo_qpost */
1873c838a9fSAndrew Rybchenko 	hunt_tx_qpush,				/* etxo_qpush */
1883c838a9fSAndrew Rybchenko 	hunt_tx_qpace,				/* etxo_qpace */
1893c838a9fSAndrew Rybchenko 	hunt_tx_qflush,				/* etxo_qflush */
1903c838a9fSAndrew Rybchenko 	hunt_tx_qenable,			/* etxo_qenable */
1913c838a9fSAndrew Rybchenko 	hunt_tx_qpio_enable,			/* etxo_qpio_enable */
1923c838a9fSAndrew Rybchenko 	hunt_tx_qpio_disable,			/* etxo_qpio_disable */
1933c838a9fSAndrew Rybchenko 	hunt_tx_qpio_write,			/* etxo_qpio_write */
1943c838a9fSAndrew Rybchenko 	hunt_tx_qpio_post,			/* etxo_qpio_post */
1953c838a9fSAndrew Rybchenko 	hunt_tx_qdesc_post,			/* etxo_qdesc_post */
1963c838a9fSAndrew Rybchenko 	hunt_tx_qdesc_dma_create,		/* etxo_qdesc_dma_create */
1973c838a9fSAndrew Rybchenko 	hunt_tx_qdesc_tso_create,		/* etxo_qdesc_tso_create */
1983c838a9fSAndrew Rybchenko 	hunt_tx_qdesc_vlantci_create,		/* etxo_qdesc_vlantci_create */
1993c838a9fSAndrew Rybchenko #if EFSYS_OPT_QSTATS
2003c838a9fSAndrew Rybchenko 	hunt_tx_qstats_update,			/* etxo_qstats_update */
2013c838a9fSAndrew Rybchenko #endif
2023c838a9fSAndrew Rybchenko };
2033c838a9fSAndrew Rybchenko #endif /* EFSYS_OPT_HUNTINGTON */
2043c838a9fSAndrew Rybchenko 
205e948693eSPhilip Paeps 	__checkReturn	int
206e948693eSPhilip Paeps efx_tx_init(
207e948693eSPhilip Paeps 	__in		efx_nic_t *enp)
208e948693eSPhilip Paeps {
2093c838a9fSAndrew Rybchenko 	efx_tx_ops_t *etxop;
210e948693eSPhilip Paeps 	int rc;
211e948693eSPhilip Paeps 
212e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
213e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
214e948693eSPhilip Paeps 
215e948693eSPhilip Paeps 	if (!(enp->en_mod_flags & EFX_MOD_EV)) {
216e948693eSPhilip Paeps 		rc = EINVAL;
217e948693eSPhilip Paeps 		goto fail1;
218e948693eSPhilip Paeps 	}
219e948693eSPhilip Paeps 
220e948693eSPhilip Paeps 	if (enp->en_mod_flags & EFX_MOD_TX) {
221e948693eSPhilip Paeps 		rc = EINVAL;
222e948693eSPhilip Paeps 		goto fail2;
223e948693eSPhilip Paeps 	}
224e948693eSPhilip Paeps 
2253c838a9fSAndrew Rybchenko 	switch (enp->en_family) {
2263c838a9fSAndrew Rybchenko #if EFSYS_OPT_FALCON
2273c838a9fSAndrew Rybchenko 	case EFX_FAMILY_FALCON:
2283c838a9fSAndrew Rybchenko 		etxop = (efx_tx_ops_t *)&__efx_tx_falcon_ops;
2293c838a9fSAndrew Rybchenko 		break;
2303c838a9fSAndrew Rybchenko #endif /* EFSYS_OPT_FALCON */
2313c838a9fSAndrew Rybchenko 
2323c838a9fSAndrew Rybchenko #if EFSYS_OPT_SIENA
2333c838a9fSAndrew Rybchenko 	case EFX_FAMILY_SIENA:
2343c838a9fSAndrew Rybchenko 		etxop = (efx_tx_ops_t *)&__efx_tx_siena_ops;
2353c838a9fSAndrew Rybchenko 		break;
2363c838a9fSAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */
2373c838a9fSAndrew Rybchenko 
2383c838a9fSAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON
2393c838a9fSAndrew Rybchenko 	case EFX_FAMILY_HUNTINGTON:
2403c838a9fSAndrew Rybchenko 		etxop = (efx_tx_ops_t *)&__efx_tx_hunt_ops;
2413c838a9fSAndrew Rybchenko 		break;
2423c838a9fSAndrew Rybchenko #endif /* EFSYS_OPT_HUNTINGTON */
2433c838a9fSAndrew Rybchenko 
2443c838a9fSAndrew Rybchenko 	default:
2453c838a9fSAndrew Rybchenko 		EFSYS_ASSERT(0);
2463c838a9fSAndrew Rybchenko 		rc = ENOTSUP;
2473c838a9fSAndrew Rybchenko 		goto fail3;
2483c838a9fSAndrew Rybchenko 	}
2493c838a9fSAndrew Rybchenko 
250e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_tx_qcount, ==, 0);
251e948693eSPhilip Paeps 
2523c838a9fSAndrew Rybchenko 	if ((rc = etxop->etxo_init(enp)) != 0)
2533c838a9fSAndrew Rybchenko 		goto fail4;
2543c838a9fSAndrew Rybchenko 
2553c838a9fSAndrew Rybchenko 	enp->en_etxop = etxop;
2563c838a9fSAndrew Rybchenko 	enp->en_mod_flags |= EFX_MOD_TX;
2573c838a9fSAndrew Rybchenko 	return (0);
2583c838a9fSAndrew Rybchenko 
2593c838a9fSAndrew Rybchenko fail4:
2603c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail4);
2613c838a9fSAndrew Rybchenko fail3:
2623c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail3);
2633c838a9fSAndrew Rybchenko fail2:
2643c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
2653c838a9fSAndrew Rybchenko fail1:
2663c838a9fSAndrew Rybchenko 	EFSYS_PROBE1(fail1, int, rc);
2673c838a9fSAndrew Rybchenko 
2683c838a9fSAndrew Rybchenko 	enp->en_etxop = NULL;
2693c838a9fSAndrew Rybchenko 	enp->en_mod_flags &= ~EFX_MOD_TX;
2703c838a9fSAndrew Rybchenko 	return (rc);
2713c838a9fSAndrew Rybchenko }
2723c838a9fSAndrew Rybchenko 
2733c838a9fSAndrew Rybchenko 			void
2743c838a9fSAndrew Rybchenko efx_tx_fini(
2753c838a9fSAndrew Rybchenko 	__in	efx_nic_t *enp)
2763c838a9fSAndrew Rybchenko {
2773c838a9fSAndrew Rybchenko 	efx_tx_ops_t *etxop = enp->en_etxop;
2783c838a9fSAndrew Rybchenko 
2793c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
2803c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
2813c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TX);
2823c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_tx_qcount, ==, 0);
2833c838a9fSAndrew Rybchenko 
2843c838a9fSAndrew Rybchenko 	etxop->etxo_fini(enp);
2853c838a9fSAndrew Rybchenko 
2863c838a9fSAndrew Rybchenko 	enp->en_etxop = NULL;
2873c838a9fSAndrew Rybchenko 	enp->en_mod_flags &= ~EFX_MOD_TX;
2883c838a9fSAndrew Rybchenko }
2893c838a9fSAndrew Rybchenko 
2903c838a9fSAndrew Rybchenko 	__checkReturn	int
2913c838a9fSAndrew Rybchenko efx_tx_qcreate(
2923c838a9fSAndrew Rybchenko 	__in		efx_nic_t *enp,
2933c838a9fSAndrew Rybchenko 	__in		unsigned int index,
2943c838a9fSAndrew Rybchenko 	__in		unsigned int label,
2953c838a9fSAndrew Rybchenko 	__in		efsys_mem_t *esmp,
2963c838a9fSAndrew Rybchenko 	__in		size_t n,
2973c838a9fSAndrew Rybchenko 	__in		uint32_t id,
2983c838a9fSAndrew Rybchenko 	__in		uint16_t flags,
2993c838a9fSAndrew Rybchenko 	__in		efx_evq_t *eep,
3003c838a9fSAndrew Rybchenko 	__deref_out	efx_txq_t **etpp,
3013c838a9fSAndrew Rybchenko 	__out		unsigned int *addedp)
3023c838a9fSAndrew Rybchenko {
3033c838a9fSAndrew Rybchenko 	efx_tx_ops_t *etxop = enp->en_etxop;
3043c838a9fSAndrew Rybchenko 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
3053c838a9fSAndrew Rybchenko 	efx_txq_t *etp;
3063c838a9fSAndrew Rybchenko 	int rc;
3073c838a9fSAndrew Rybchenko 
3083c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
3093c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TX);
3103c838a9fSAndrew Rybchenko 
3113c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_tx_qcount + 1, <, encp->enc_txq_limit);
3123c838a9fSAndrew Rybchenko 
3133c838a9fSAndrew Rybchenko 	/* Allocate an TXQ object */
3143c838a9fSAndrew Rybchenko 	EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (efx_txq_t), etp);
3153c838a9fSAndrew Rybchenko 
3163c838a9fSAndrew Rybchenko 	if (etp == NULL) {
3173c838a9fSAndrew Rybchenko 		rc = ENOMEM;
3183c838a9fSAndrew Rybchenko 		goto fail1;
3193c838a9fSAndrew Rybchenko 	}
3203c838a9fSAndrew Rybchenko 
3213c838a9fSAndrew Rybchenko 	etp->et_magic = EFX_TXQ_MAGIC;
3223c838a9fSAndrew Rybchenko 	etp->et_enp = enp;
3233c838a9fSAndrew Rybchenko 	etp->et_index = index;
3243c838a9fSAndrew Rybchenko 	etp->et_mask = n - 1;
3253c838a9fSAndrew Rybchenko 	etp->et_esmp = esmp;
3263c838a9fSAndrew Rybchenko 
3273c838a9fSAndrew Rybchenko 	/* Initial descriptor index may be modified by etxo_qcreate */
3283c838a9fSAndrew Rybchenko 	*addedp = 0;
3293c838a9fSAndrew Rybchenko 
3303c838a9fSAndrew Rybchenko 	if ((rc = etxop->etxo_qcreate(enp, index, label, esmp,
3313c838a9fSAndrew Rybchenko 	    n, id, flags, eep, etp, addedp)) != 0)
3323c838a9fSAndrew Rybchenko 			goto fail2;
3333c838a9fSAndrew Rybchenko 
3343c838a9fSAndrew Rybchenko 	enp->en_tx_qcount++;
3353c838a9fSAndrew Rybchenko 	*etpp = etp;
3363c838a9fSAndrew Rybchenko 
3373c838a9fSAndrew Rybchenko 	return (0);
3383c838a9fSAndrew Rybchenko 
3393c838a9fSAndrew Rybchenko fail2:
3403c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
3413c838a9fSAndrew Rybchenko 	EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_txq_t), etp);
3423c838a9fSAndrew Rybchenko fail1:
3433c838a9fSAndrew Rybchenko 	EFSYS_PROBE1(fail1, int, rc);
3443c838a9fSAndrew Rybchenko 	return (rc);
3453c838a9fSAndrew Rybchenko }
3463c838a9fSAndrew Rybchenko 
3473c838a9fSAndrew Rybchenko 		void
3483c838a9fSAndrew Rybchenko efx_tx_qdestroy(
3493c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp)
3503c838a9fSAndrew Rybchenko {
3513c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
3523c838a9fSAndrew Rybchenko 	efx_tx_ops_t *etxop = enp->en_etxop;
3533c838a9fSAndrew Rybchenko 
3543c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
3553c838a9fSAndrew Rybchenko 
3563c838a9fSAndrew Rybchenko 	EFSYS_ASSERT(enp->en_tx_qcount != 0);
3573c838a9fSAndrew Rybchenko 	--enp->en_tx_qcount;
3583c838a9fSAndrew Rybchenko 
3593c838a9fSAndrew Rybchenko 	etxop->etxo_qdestroy(etp);
3603c838a9fSAndrew Rybchenko 
3613c838a9fSAndrew Rybchenko 	/* Free the TXQ object */
3623c838a9fSAndrew Rybchenko 	EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_txq_t), etp);
3633c838a9fSAndrew Rybchenko }
3643c838a9fSAndrew Rybchenko 
3653c838a9fSAndrew Rybchenko 	__checkReturn	int
3663c838a9fSAndrew Rybchenko efx_tx_qpost(
3673c838a9fSAndrew Rybchenko 	__in		efx_txq_t *etp,
3683c838a9fSAndrew Rybchenko 	__in_ecount(n)	efx_buffer_t *eb,
3693c838a9fSAndrew Rybchenko 	__in		unsigned int n,
3703c838a9fSAndrew Rybchenko 	__in		unsigned int completed,
3713c838a9fSAndrew Rybchenko 	__inout		unsigned int *addedp)
3723c838a9fSAndrew Rybchenko {
3733c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
3743c838a9fSAndrew Rybchenko 	efx_tx_ops_t *etxop = enp->en_etxop;
3753c838a9fSAndrew Rybchenko 	int rc;
3763c838a9fSAndrew Rybchenko 
3773c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
3783c838a9fSAndrew Rybchenko 
3793c838a9fSAndrew Rybchenko 	if ((rc = etxop->etxo_qpost(etp, eb,
3803c838a9fSAndrew Rybchenko 	    n, completed, addedp)) != 0)
3813c838a9fSAndrew Rybchenko 		goto fail1;
3823c838a9fSAndrew Rybchenko 
3833c838a9fSAndrew Rybchenko 	return (0);
3843c838a9fSAndrew Rybchenko 
3853c838a9fSAndrew Rybchenko fail1:
3863c838a9fSAndrew Rybchenko 	EFSYS_PROBE1(fail1, int, rc);
3873c838a9fSAndrew Rybchenko 	return (rc);
3883c838a9fSAndrew Rybchenko }
3893c838a9fSAndrew Rybchenko 
3903c838a9fSAndrew Rybchenko 			void
3913c838a9fSAndrew Rybchenko efx_tx_qpush(
3923c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp,
3933c838a9fSAndrew Rybchenko 	__in	unsigned int added,
3943c838a9fSAndrew Rybchenko 	__in	unsigned int pushed)
3953c838a9fSAndrew Rybchenko {
3963c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
3973c838a9fSAndrew Rybchenko 	efx_tx_ops_t *etxop = enp->en_etxop;
3983c838a9fSAndrew Rybchenko 
3993c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
4003c838a9fSAndrew Rybchenko 
4013c838a9fSAndrew Rybchenko 	etxop->etxo_qpush(etp, added, pushed);
4023c838a9fSAndrew Rybchenko }
4033c838a9fSAndrew Rybchenko 
4043c838a9fSAndrew Rybchenko 	__checkReturn	int
4053c838a9fSAndrew Rybchenko efx_tx_qpace(
4063c838a9fSAndrew Rybchenko 	__in		efx_txq_t *etp,
4073c838a9fSAndrew Rybchenko 	__in		unsigned int ns)
4083c838a9fSAndrew Rybchenko {
4093c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
4103c838a9fSAndrew Rybchenko 	efx_tx_ops_t *etxop = enp->en_etxop;
4113c838a9fSAndrew Rybchenko 	int rc;
4123c838a9fSAndrew Rybchenko 
4133c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
4143c838a9fSAndrew Rybchenko 
4153c838a9fSAndrew Rybchenko 	if ((rc = etxop->etxo_qpace(etp, ns)) != 0)
4163c838a9fSAndrew Rybchenko 		goto fail1;
4173c838a9fSAndrew Rybchenko 
4183c838a9fSAndrew Rybchenko 	return (0);
4193c838a9fSAndrew Rybchenko 
4203c838a9fSAndrew Rybchenko fail1:
4213c838a9fSAndrew Rybchenko 	EFSYS_PROBE1(fail1, int, rc);
4223c838a9fSAndrew Rybchenko 	return (rc);
4233c838a9fSAndrew Rybchenko }
4243c838a9fSAndrew Rybchenko 
4253c838a9fSAndrew Rybchenko 	__checkReturn	int
4263c838a9fSAndrew Rybchenko efx_tx_qflush(
4273c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp)
4283c838a9fSAndrew Rybchenko {
4293c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
4303c838a9fSAndrew Rybchenko 	efx_tx_ops_t *etxop = enp->en_etxop;
4313c838a9fSAndrew Rybchenko 	int rc;
4323c838a9fSAndrew Rybchenko 
4333c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
4343c838a9fSAndrew Rybchenko 
4353c838a9fSAndrew Rybchenko 	if ((rc = etxop->etxo_qflush(etp)) != 0)
4363c838a9fSAndrew Rybchenko 		goto fail1;
4373c838a9fSAndrew Rybchenko 
4383c838a9fSAndrew Rybchenko 	return (0);
4393c838a9fSAndrew Rybchenko 
4403c838a9fSAndrew Rybchenko fail1:
4413c838a9fSAndrew Rybchenko 	EFSYS_PROBE1(fail1, int, rc);
4423c838a9fSAndrew Rybchenko 	return (rc);
4433c838a9fSAndrew Rybchenko }
4443c838a9fSAndrew Rybchenko 
4453c838a9fSAndrew Rybchenko 			void
4463c838a9fSAndrew Rybchenko efx_tx_qenable(
4473c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp)
4483c838a9fSAndrew Rybchenko {
4493c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
4503c838a9fSAndrew Rybchenko 	efx_tx_ops_t *etxop = enp->en_etxop;
4513c838a9fSAndrew Rybchenko 
4523c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
4533c838a9fSAndrew Rybchenko 
4543c838a9fSAndrew Rybchenko 	etxop->etxo_qenable(etp);
4553c838a9fSAndrew Rybchenko }
4563c838a9fSAndrew Rybchenko 
4573c838a9fSAndrew Rybchenko 	__checkReturn	int
4583c838a9fSAndrew Rybchenko efx_tx_qpio_enable(
4593c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp)
4603c838a9fSAndrew Rybchenko {
4613c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
4623c838a9fSAndrew Rybchenko 	efx_tx_ops_t *etxop = enp->en_etxop;
4633c838a9fSAndrew Rybchenko 	int rc;
4643c838a9fSAndrew Rybchenko 
4653c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
4663c838a9fSAndrew Rybchenko 
4673c838a9fSAndrew Rybchenko 	if (~enp->en_features & EFX_FEATURE_PIO_BUFFERS) {
4683c838a9fSAndrew Rybchenko 		rc = ENOTSUP;
4693c838a9fSAndrew Rybchenko 		goto fail1;
4703c838a9fSAndrew Rybchenko 	}
4713c838a9fSAndrew Rybchenko 	if (etxop->etxo_qpio_enable == NULL) {
4723c838a9fSAndrew Rybchenko 		rc = ENOTSUP;
4733c838a9fSAndrew Rybchenko 		goto fail2;
4743c838a9fSAndrew Rybchenko 	}
4753c838a9fSAndrew Rybchenko 	if ((rc = etxop->etxo_qpio_enable(etp)) != 0)
4763c838a9fSAndrew Rybchenko 		goto fail3;
4773c838a9fSAndrew Rybchenko 
4783c838a9fSAndrew Rybchenko 	return (0);
4793c838a9fSAndrew Rybchenko 
4803c838a9fSAndrew Rybchenko fail3:
4813c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail3);
4823c838a9fSAndrew Rybchenko fail2:
4833c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
4843c838a9fSAndrew Rybchenko fail1:
4853c838a9fSAndrew Rybchenko 	EFSYS_PROBE1(fail1, int, rc);
4863c838a9fSAndrew Rybchenko 	return (rc);
4873c838a9fSAndrew Rybchenko }
4883c838a9fSAndrew Rybchenko 
4893c838a9fSAndrew Rybchenko 		void
4903c838a9fSAndrew Rybchenko efx_tx_qpio_disable(
4913c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp)
4923c838a9fSAndrew Rybchenko {
4933c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
4943c838a9fSAndrew Rybchenko 	efx_tx_ops_t *etxop = enp->en_etxop;
4953c838a9fSAndrew Rybchenko 
4963c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
4973c838a9fSAndrew Rybchenko 
4983c838a9fSAndrew Rybchenko 	if (etxop->etxo_qpio_disable != NULL)
4993c838a9fSAndrew Rybchenko 		etxop->etxo_qpio_disable(etp);
5003c838a9fSAndrew Rybchenko }
5013c838a9fSAndrew Rybchenko 
5023c838a9fSAndrew Rybchenko 	__checkReturn	int
5033c838a9fSAndrew Rybchenko efx_tx_qpio_write(
5043c838a9fSAndrew Rybchenko 	__in			efx_txq_t *etp,
5053c838a9fSAndrew Rybchenko 	__in_ecount(buf_length)	uint8_t *buffer,
5063c838a9fSAndrew Rybchenko 	__in			size_t buf_length,
5073c838a9fSAndrew Rybchenko 	__in			size_t pio_buf_offset)
5083c838a9fSAndrew Rybchenko {
5093c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
5103c838a9fSAndrew Rybchenko 	efx_tx_ops_t *etxop = enp->en_etxop;
5113c838a9fSAndrew Rybchenko 	int rc;
5123c838a9fSAndrew Rybchenko 
5133c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
5143c838a9fSAndrew Rybchenko 
5153c838a9fSAndrew Rybchenko 	if (etxop->etxo_qpio_write != NULL) {
5163c838a9fSAndrew Rybchenko 		if ((rc = etxop->etxo_qpio_write(etp, buffer, buf_length,
5173c838a9fSAndrew Rybchenko 						pio_buf_offset)) != 0)
5183c838a9fSAndrew Rybchenko 			goto fail1;
5193c838a9fSAndrew Rybchenko 		return (0);
5203c838a9fSAndrew Rybchenko 	}
5213c838a9fSAndrew Rybchenko 
5223c838a9fSAndrew Rybchenko 	return (ENOTSUP);
5233c838a9fSAndrew Rybchenko 
5243c838a9fSAndrew Rybchenko fail1:
5253c838a9fSAndrew Rybchenko 	EFSYS_PROBE1(fail1, int, rc);
5263c838a9fSAndrew Rybchenko 	return (rc);
5273c838a9fSAndrew Rybchenko }
5283c838a9fSAndrew Rybchenko 
5293c838a9fSAndrew Rybchenko 	__checkReturn	int
5303c838a9fSAndrew Rybchenko efx_tx_qpio_post(
5313c838a9fSAndrew Rybchenko 	__in			efx_txq_t *etp,
5323c838a9fSAndrew Rybchenko 	__in			size_t pkt_length,
5333c838a9fSAndrew Rybchenko 	__in			unsigned int completed,
5343c838a9fSAndrew Rybchenko 	__inout			unsigned int *addedp)
5353c838a9fSAndrew Rybchenko {
5363c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
5373c838a9fSAndrew Rybchenko 	efx_tx_ops_t *etxop = enp->en_etxop;
5383c838a9fSAndrew Rybchenko 	int rc;
5393c838a9fSAndrew Rybchenko 
5403c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
5413c838a9fSAndrew Rybchenko 
5423c838a9fSAndrew Rybchenko 	if (etxop->etxo_qpio_post != NULL) {
5433c838a9fSAndrew Rybchenko 		if ((rc = etxop->etxo_qpio_post(etp, pkt_length, completed,
5443c838a9fSAndrew Rybchenko 						addedp)) != 0)
5453c838a9fSAndrew Rybchenko 			goto fail1;
5463c838a9fSAndrew Rybchenko 		return (0);
5473c838a9fSAndrew Rybchenko 	}
5483c838a9fSAndrew Rybchenko 
5493c838a9fSAndrew Rybchenko 	return (ENOTSUP);
5503c838a9fSAndrew Rybchenko 
5513c838a9fSAndrew Rybchenko fail1:
5523c838a9fSAndrew Rybchenko 	EFSYS_PROBE1(fail1, int, rc);
5533c838a9fSAndrew Rybchenko 	return (rc);
5543c838a9fSAndrew Rybchenko }
5553c838a9fSAndrew Rybchenko 
5563c838a9fSAndrew Rybchenko 	__checkReturn	int
5573c838a9fSAndrew Rybchenko efx_tx_qdesc_post(
5583c838a9fSAndrew Rybchenko 	__in		efx_txq_t *etp,
5593c838a9fSAndrew Rybchenko 	__in_ecount(n)	efx_desc_t *ed,
5603c838a9fSAndrew Rybchenko 	__in		unsigned int n,
5613c838a9fSAndrew Rybchenko 	__in		unsigned int completed,
5623c838a9fSAndrew Rybchenko 	__inout		unsigned int *addedp)
5633c838a9fSAndrew Rybchenko {
5643c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
5653c838a9fSAndrew Rybchenko 	efx_tx_ops_t *etxop = enp->en_etxop;
5663c838a9fSAndrew Rybchenko 	int rc;
5673c838a9fSAndrew Rybchenko 
5683c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
5693c838a9fSAndrew Rybchenko 
5703c838a9fSAndrew Rybchenko 	if ((rc = etxop->etxo_qdesc_post(etp, ed,
5713c838a9fSAndrew Rybchenko 	    n, completed, addedp)) != 0)
5723c838a9fSAndrew Rybchenko 		goto fail1;
5733c838a9fSAndrew Rybchenko 
5743c838a9fSAndrew Rybchenko 	return (0);
5753c838a9fSAndrew Rybchenko 
5763c838a9fSAndrew Rybchenko fail1:
5773c838a9fSAndrew Rybchenko 	EFSYS_PROBE1(fail1, int, rc);
5783c838a9fSAndrew Rybchenko 	return (rc);
5793c838a9fSAndrew Rybchenko }
5803c838a9fSAndrew Rybchenko 
5813c838a9fSAndrew Rybchenko 	void
5823c838a9fSAndrew Rybchenko efx_tx_qdesc_dma_create(
5833c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp,
5843c838a9fSAndrew Rybchenko 	__in	efsys_dma_addr_t addr,
5853c838a9fSAndrew Rybchenko 	__in	size_t size,
5863c838a9fSAndrew Rybchenko 	__in	boolean_t eop,
5873c838a9fSAndrew Rybchenko 	__out	efx_desc_t *edp)
5883c838a9fSAndrew Rybchenko {
5893c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
5903c838a9fSAndrew Rybchenko 	efx_tx_ops_t *etxop = enp->en_etxop;
5913c838a9fSAndrew Rybchenko 
5923c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
5933c838a9fSAndrew Rybchenko 	EFSYS_ASSERT(etxop->etxo_qdesc_dma_create != NULL);
5943c838a9fSAndrew Rybchenko 
5953c838a9fSAndrew Rybchenko 	etxop->etxo_qdesc_dma_create(etp, addr, size, eop, edp);
5963c838a9fSAndrew Rybchenko }
5973c838a9fSAndrew Rybchenko 
5983c838a9fSAndrew Rybchenko 	void
5993c838a9fSAndrew Rybchenko efx_tx_qdesc_tso_create(
6003c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp,
6013c838a9fSAndrew Rybchenko 	__in	uint16_t ipv4_id,
6023c838a9fSAndrew Rybchenko 	__in	uint32_t tcp_seq,
6033c838a9fSAndrew Rybchenko 	__in	uint8_t  tcp_flags,
6043c838a9fSAndrew Rybchenko 	__out	efx_desc_t *edp)
6053c838a9fSAndrew Rybchenko {
6063c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
6073c838a9fSAndrew Rybchenko 	efx_tx_ops_t *etxop = enp->en_etxop;
6083c838a9fSAndrew Rybchenko 
6093c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
6103c838a9fSAndrew Rybchenko 	EFSYS_ASSERT(etxop->etxo_qdesc_tso_create != NULL);
6113c838a9fSAndrew Rybchenko 
6123c838a9fSAndrew Rybchenko 	etxop->etxo_qdesc_tso_create(etp, ipv4_id, tcp_seq, tcp_flags, edp);
6133c838a9fSAndrew Rybchenko }
6143c838a9fSAndrew Rybchenko 
6153c838a9fSAndrew Rybchenko 	void
6163c838a9fSAndrew Rybchenko efx_tx_qdesc_vlantci_create(
6173c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp,
6183c838a9fSAndrew Rybchenko 	__in	uint16_t tci,
6193c838a9fSAndrew Rybchenko 	__out	efx_desc_t *edp)
6203c838a9fSAndrew Rybchenko {
6213c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
6223c838a9fSAndrew Rybchenko 	efx_tx_ops_t *etxop = enp->en_etxop;
6233c838a9fSAndrew Rybchenko 
6243c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
6253c838a9fSAndrew Rybchenko 	EFSYS_ASSERT(etxop->etxo_qdesc_vlantci_create != NULL);
6263c838a9fSAndrew Rybchenko 
6273c838a9fSAndrew Rybchenko 	etxop->etxo_qdesc_vlantci_create(etp, tci, edp);
6283c838a9fSAndrew Rybchenko }
6293c838a9fSAndrew Rybchenko 
6303c838a9fSAndrew Rybchenko 
6313c838a9fSAndrew Rybchenko #if EFSYS_OPT_QSTATS
6323c838a9fSAndrew Rybchenko 			void
6333c838a9fSAndrew Rybchenko efx_tx_qstats_update(
6343c838a9fSAndrew Rybchenko 	__in				efx_txq_t *etp,
6353c838a9fSAndrew Rybchenko 	__inout_ecount(TX_NQSTATS)	efsys_stat_t *stat)
6363c838a9fSAndrew Rybchenko {
6373c838a9fSAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
6383c838a9fSAndrew Rybchenko 	efx_tx_ops_t *etxop = enp->en_etxop;
6393c838a9fSAndrew Rybchenko 
6403c838a9fSAndrew Rybchenko 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
6413c838a9fSAndrew Rybchenko 
6423c838a9fSAndrew Rybchenko 	etxop->etxo_qstats_update(etp, stat);
6433c838a9fSAndrew Rybchenko }
6443c838a9fSAndrew Rybchenko #endif
6453c838a9fSAndrew Rybchenko 
6463c838a9fSAndrew Rybchenko 
6473c838a9fSAndrew Rybchenko #if EFSYS_OPT_FALCON || EFSYS_OPT_SIENA
6483c838a9fSAndrew Rybchenko 
6493c838a9fSAndrew Rybchenko static	__checkReturn	int
6503c838a9fSAndrew Rybchenko falconsiena_tx_init(
6513c838a9fSAndrew Rybchenko 	__in		efx_nic_t *enp)
6523c838a9fSAndrew Rybchenko {
6533c838a9fSAndrew Rybchenko 	efx_oword_t oword;
6543c838a9fSAndrew Rybchenko 
655e948693eSPhilip Paeps 	/*
656e948693eSPhilip Paeps 	 * Disable the timer-based TX DMA backoff and allow TX DMA to be
657e948693eSPhilip Paeps 	 * controlled by the RX FIFO fill level (although always allow a
658e948693eSPhilip Paeps 	 * minimal trickle).
659e948693eSPhilip Paeps 	 */
660e948693eSPhilip Paeps 	EFX_BAR_READO(enp, FR_AZ_TX_RESERVED_REG, &oword);
661e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_RX_SPACER, 0xfe);
662e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_RX_SPACER_EN, 1);
663e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_ONE_PKT_PER_Q, 1);
664e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_PUSH_EN, 0);
665e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DIS_NON_IP_EV, 1);
666e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_PREF_THRESHOLD, 2);
667e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_PREF_WD_TMR, 0x3fffff);
668e948693eSPhilip Paeps 
669e948693eSPhilip Paeps 	/*
670e948693eSPhilip Paeps 	 * Filter all packets less than 14 bytes to avoid parsing
671e948693eSPhilip Paeps 	 * errors.
672e948693eSPhilip Paeps 	 */
673e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1);
674e948693eSPhilip Paeps 	EFX_BAR_WRITEO(enp, FR_AZ_TX_RESERVED_REG, &oword);
675e948693eSPhilip Paeps 
676e948693eSPhilip Paeps 	/*
677e948693eSPhilip Paeps 	 * Do not set TX_NO_EOP_DISC_EN, since it limits packets to 16
678e948693eSPhilip Paeps 	 * descriptors (which is bad).
679e948693eSPhilip Paeps 	 */
680e948693eSPhilip Paeps 	EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword);
681e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_NO_EOP_DISC_EN, 0);
682e948693eSPhilip Paeps 	EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword);
683e948693eSPhilip Paeps 
684e948693eSPhilip Paeps 	return (0);
685e948693eSPhilip Paeps }
686e948693eSPhilip Paeps 
687e948693eSPhilip Paeps #define	EFX_TX_DESC(_etp, _addr, _size, _eop, _added)			\
688e948693eSPhilip Paeps 	do {								\
689e948693eSPhilip Paeps 		unsigned int id;					\
690e948693eSPhilip Paeps 		size_t offset;						\
691e948693eSPhilip Paeps 		efx_qword_t qword;					\
692e948693eSPhilip Paeps 									\
693e948693eSPhilip Paeps 		id = (_added)++ & (_etp)->et_mask;			\
694e948693eSPhilip Paeps 		offset = id * sizeof (efx_qword_t);			\
695e948693eSPhilip Paeps 									\
696e948693eSPhilip Paeps 		EFSYS_PROBE5(tx_post, unsigned int, (_etp)->et_index,	\
697e948693eSPhilip Paeps 		    unsigned int, id, efsys_dma_addr_t, (_addr),	\
698e948693eSPhilip Paeps 		    size_t, (_size), boolean_t, (_eop));		\
699e948693eSPhilip Paeps 									\
700e948693eSPhilip Paeps 		EFX_POPULATE_QWORD_4(qword,				\
701e948693eSPhilip Paeps 		    FSF_AZ_TX_KER_CONT, (_eop) ? 0 : 1,			\
702e948693eSPhilip Paeps 		    FSF_AZ_TX_KER_BYTE_COUNT, (uint32_t)(_size),	\
703e948693eSPhilip Paeps 		    FSF_AZ_TX_KER_BUF_ADDR_DW0,				\
704e948693eSPhilip Paeps 		    (uint32_t)((_addr) & 0xffffffff),			\
705e948693eSPhilip Paeps 		    FSF_AZ_TX_KER_BUF_ADDR_DW1,				\
706e948693eSPhilip Paeps 		    (uint32_t)((_addr) >> 32));				\
707e948693eSPhilip Paeps 		EFSYS_MEM_WRITEQ((_etp)->et_esmp, offset, &qword);	\
708e948693eSPhilip Paeps 									\
709e948693eSPhilip Paeps 		_NOTE(CONSTANTCONDITION)				\
710e948693eSPhilip Paeps 	} while (B_FALSE)
711e948693eSPhilip Paeps 
7123c838a9fSAndrew Rybchenko static	__checkReturn	int
7133c838a9fSAndrew Rybchenko falconsiena_tx_qpost(
714e948693eSPhilip Paeps 	__in		efx_txq_t *etp,
715e948693eSPhilip Paeps 	__in_ecount(n)	efx_buffer_t *eb,
716e948693eSPhilip Paeps 	__in		unsigned int n,
717e948693eSPhilip Paeps 	__in		unsigned int completed,
718e948693eSPhilip Paeps 	__inout		unsigned int *addedp)
719e948693eSPhilip Paeps {
720e948693eSPhilip Paeps 	unsigned int added = *addedp;
721e948693eSPhilip Paeps 	unsigned int i;
722e948693eSPhilip Paeps 	int rc = ENOSPC;
723e948693eSPhilip Paeps 
724e948693eSPhilip Paeps 	if (added - completed + n > EFX_TXQ_LIMIT(etp->et_mask + 1))
725e948693eSPhilip Paeps 		goto fail1;
726e948693eSPhilip Paeps 
727e948693eSPhilip Paeps 	for (i = 0; i < n; i++) {
728e948693eSPhilip Paeps 		efx_buffer_t *ebp = &eb[i];
729e948693eSPhilip Paeps 		efsys_dma_addr_t start = ebp->eb_addr;
730e948693eSPhilip Paeps 		size_t size = ebp->eb_size;
731e948693eSPhilip Paeps 		efsys_dma_addr_t end = start + size;
732e948693eSPhilip Paeps 
733e948693eSPhilip Paeps 		/* Fragments must not span 4k boundaries. */
734e948693eSPhilip Paeps 		EFSYS_ASSERT(P2ROUNDUP(start + 1, 4096) >= end);
735e948693eSPhilip Paeps 
736e948693eSPhilip Paeps 		EFX_TX_DESC(etp, start, size, ebp->eb_eop, added);
737e948693eSPhilip Paeps 	}
738e948693eSPhilip Paeps 
739e948693eSPhilip Paeps 	EFX_TX_QSTAT_INCR(etp, TX_POST);
740e948693eSPhilip Paeps 
741e948693eSPhilip Paeps 	*addedp = added;
742e948693eSPhilip Paeps 	return (0);
743e948693eSPhilip Paeps 
744e948693eSPhilip Paeps fail1:
745e948693eSPhilip Paeps 	EFSYS_PROBE1(fail1, int, rc);
746e948693eSPhilip Paeps 
747e948693eSPhilip Paeps 	return (rc);
748e948693eSPhilip Paeps }
749e948693eSPhilip Paeps 
7503c838a9fSAndrew Rybchenko static		void
7513c838a9fSAndrew Rybchenko falconsiena_tx_qpush(
752e948693eSPhilip Paeps 	__in	efx_txq_t *etp,
7533c838a9fSAndrew Rybchenko 	__in	unsigned int added,
7543c838a9fSAndrew Rybchenko 	__in	unsigned int pushed)
755e948693eSPhilip Paeps {
756e948693eSPhilip Paeps 	efx_nic_t *enp = etp->et_enp;
757e948693eSPhilip Paeps 	uint32_t wptr;
758e948693eSPhilip Paeps 	efx_dword_t dword;
759e948693eSPhilip Paeps 	efx_oword_t oword;
760e948693eSPhilip Paeps 
761e948693eSPhilip Paeps 	/* Push the populated descriptors out */
762e948693eSPhilip Paeps 	wptr = added & etp->et_mask;
763e948693eSPhilip Paeps 
764e948693eSPhilip Paeps 	EFX_POPULATE_OWORD_1(oword, FRF_AZ_TX_DESC_WPTR, wptr);
765e948693eSPhilip Paeps 
766e948693eSPhilip Paeps 	/* Only write the third DWORD */
767e948693eSPhilip Paeps 	EFX_POPULATE_DWORD_1(dword,
768e948693eSPhilip Paeps 	    EFX_DWORD_0, EFX_OWORD_FIELD(oword, EFX_DWORD_3));
7693c838a9fSAndrew Rybchenko 
7703c838a9fSAndrew Rybchenko 	/* Guarantee ordering of memory (descriptors) and PIO (doorbell) */
7713c838a9fSAndrew Rybchenko 	EFX_DMA_SYNC_QUEUE_FOR_DEVICE(etp->et_esmp, etp->et_mask + 1,
7723c838a9fSAndrew Rybchenko 	    wptr, pushed & etp->et_mask);
7733c838a9fSAndrew Rybchenko 	EFSYS_PIO_WRITE_BARRIER();
774e948693eSPhilip Paeps 	EFX_BAR_TBL_WRITED3(enp, FR_BZ_TX_DESC_UPD_REGP0,
775e948693eSPhilip Paeps 			    etp->et_index, &dword, B_FALSE);
776e948693eSPhilip Paeps }
777e948693eSPhilip Paeps 
7782fc13da6SAndrew Rybchenko #define	EFX_MAX_PACE_VALUE 20
7792fc13da6SAndrew Rybchenko #define	EFX_TX_PACE_CLOCK_BASE	104
7802fc13da6SAndrew Rybchenko 
7813c838a9fSAndrew Rybchenko static	__checkReturn	int
7823c838a9fSAndrew Rybchenko falconsiena_tx_qpace(
7832fc13da6SAndrew Rybchenko 	__in		efx_txq_t *etp,
7842fc13da6SAndrew Rybchenko 	__in		unsigned int ns)
7852fc13da6SAndrew Rybchenko {
7862fc13da6SAndrew Rybchenko 	efx_nic_t *enp = etp->et_enp;
7872fc13da6SAndrew Rybchenko 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
7882fc13da6SAndrew Rybchenko 	efx_oword_t oword;
7892fc13da6SAndrew Rybchenko 	unsigned int pace_val;
7902fc13da6SAndrew Rybchenko 	unsigned int timer_period;
7912fc13da6SAndrew Rybchenko 	int rc;
7922fc13da6SAndrew Rybchenko 
7932fc13da6SAndrew Rybchenko 	if (ns == 0) {
7942fc13da6SAndrew Rybchenko 		pace_val = 0;
7952fc13da6SAndrew Rybchenko 	} else {
7962fc13da6SAndrew Rybchenko 		/*
7972fc13da6SAndrew Rybchenko 		 * The pace_val to write into the table is s.t
7982fc13da6SAndrew Rybchenko 		 * ns <= timer_period * (2 ^ pace_val)
7992fc13da6SAndrew Rybchenko 		 */
8002fc13da6SAndrew Rybchenko 		timer_period = EFX_TX_PACE_CLOCK_BASE / encp->enc_clk_mult;
8012fc13da6SAndrew Rybchenko 		for (pace_val = 1; pace_val <= EFX_MAX_PACE_VALUE; pace_val++) {
8022fc13da6SAndrew Rybchenko 			if ((timer_period << pace_val) >= ns)
8032fc13da6SAndrew Rybchenko 				break;
8042fc13da6SAndrew Rybchenko 		}
8052fc13da6SAndrew Rybchenko 	}
8062fc13da6SAndrew Rybchenko 	if (pace_val > EFX_MAX_PACE_VALUE) {
8072fc13da6SAndrew Rybchenko 		rc = EINVAL;
8082fc13da6SAndrew Rybchenko 		goto fail1;
8092fc13da6SAndrew Rybchenko 	}
8102fc13da6SAndrew Rybchenko 
8112fc13da6SAndrew Rybchenko 	/* Update the pacing table */
8122fc13da6SAndrew Rybchenko 	EFX_POPULATE_OWORD_1(oword, FRF_AZ_TX_PACE, pace_val);
8133c838a9fSAndrew Rybchenko 	EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_PACE_TBL, etp->et_index,
8143c838a9fSAndrew Rybchenko 	    &oword, B_TRUE);
8152fc13da6SAndrew Rybchenko 
8162fc13da6SAndrew Rybchenko 	return (0);
8172fc13da6SAndrew Rybchenko 
8182fc13da6SAndrew Rybchenko fail1:
8192fc13da6SAndrew Rybchenko 	EFSYS_PROBE1(fail1, int, rc);
8202fc13da6SAndrew Rybchenko 
8212fc13da6SAndrew Rybchenko 	return (rc);
8222fc13da6SAndrew Rybchenko }
8232fc13da6SAndrew Rybchenko 
8243c838a9fSAndrew Rybchenko static	__checkReturn	int
8253c838a9fSAndrew Rybchenko falconsiena_tx_qflush(
826e948693eSPhilip Paeps 	__in		efx_txq_t *etp)
827e948693eSPhilip Paeps {
828e948693eSPhilip Paeps 	efx_nic_t *enp = etp->et_enp;
829e948693eSPhilip Paeps 	efx_oword_t oword;
830e948693eSPhilip Paeps 	uint32_t label;
831e948693eSPhilip Paeps 
8322fc13da6SAndrew Rybchenko 	efx_tx_qpace(etp, 0);
8332fc13da6SAndrew Rybchenko 
834e948693eSPhilip Paeps 	label = etp->et_index;
835e948693eSPhilip Paeps 
836e948693eSPhilip Paeps 	/* Flush the queue */
837e948693eSPhilip Paeps 	EFX_POPULATE_OWORD_2(oword, FRF_AZ_TX_FLUSH_DESCQ_CMD, 1,
838e948693eSPhilip Paeps 	    FRF_AZ_TX_FLUSH_DESCQ, label);
839e948693eSPhilip Paeps 	EFX_BAR_WRITEO(enp, FR_AZ_TX_FLUSH_DESCQ_REG, &oword);
8403c838a9fSAndrew Rybchenko 
8413c838a9fSAndrew Rybchenko 	return (0);
842e948693eSPhilip Paeps }
843e948693eSPhilip Paeps 
8443c838a9fSAndrew Rybchenko static		void
8453c838a9fSAndrew Rybchenko falconsiena_tx_qenable(
846e948693eSPhilip Paeps 	__in	efx_txq_t *etp)
847e948693eSPhilip Paeps {
848e948693eSPhilip Paeps 	efx_nic_t *enp = etp->et_enp;
849e948693eSPhilip Paeps 	efx_oword_t oword;
850e948693eSPhilip Paeps 
851e948693eSPhilip Paeps 	EFX_BAR_TBL_READO(enp, FR_AZ_TX_DESC_PTR_TBL,
8523c838a9fSAndrew Rybchenko 			    etp->et_index, &oword, B_TRUE);
853e948693eSPhilip Paeps 
854e948693eSPhilip Paeps 	EFSYS_PROBE5(tx_descq_ptr, unsigned int, etp->et_index,
855e948693eSPhilip Paeps 	    uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_3),
856e948693eSPhilip Paeps 	    uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_2),
857e948693eSPhilip Paeps 	    uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_1),
858e948693eSPhilip Paeps 	    uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_0));
859e948693eSPhilip Paeps 
860e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DC_HW_RPTR, 0);
861e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DESCQ_HW_RPTR, 0);
862e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DESCQ_EN, 1);
863e948693eSPhilip Paeps 
864e948693eSPhilip Paeps 	EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_DESC_PTR_TBL,
8653c838a9fSAndrew Rybchenko 			    etp->et_index, &oword, B_TRUE);
866e948693eSPhilip Paeps }
867e948693eSPhilip Paeps 
8683c838a9fSAndrew Rybchenko static	__checkReturn	int
8693c838a9fSAndrew Rybchenko falconsiena_tx_qcreate(
870e948693eSPhilip Paeps 	__in		efx_nic_t *enp,
871e948693eSPhilip Paeps 	__in		unsigned int index,
872e948693eSPhilip Paeps 	__in		unsigned int label,
873e948693eSPhilip Paeps 	__in		efsys_mem_t *esmp,
874e948693eSPhilip Paeps 	__in		size_t n,
875e948693eSPhilip Paeps 	__in		uint32_t id,
876e948693eSPhilip Paeps 	__in		uint16_t flags,
877e948693eSPhilip Paeps 	__in		efx_evq_t *eep,
8783c838a9fSAndrew Rybchenko 	__in		efx_txq_t *etp,
8793c838a9fSAndrew Rybchenko 	__out		unsigned int *addedp)
880e948693eSPhilip Paeps {
881e948693eSPhilip Paeps 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
882e948693eSPhilip Paeps 	efx_oword_t oword;
883e948693eSPhilip Paeps 	uint32_t size;
884e948693eSPhilip Paeps 	int rc;
885e948693eSPhilip Paeps 
886c071447aSAndrew Rybchenko 	EFX_STATIC_ASSERT(EFX_EV_TX_NLABELS ==
887c071447aSAndrew Rybchenko 	    (1 << FRF_AZ_TX_DESCQ_LABEL_WIDTH));
888c071447aSAndrew Rybchenko 	EFSYS_ASSERT3U(label, <, EFX_EV_TX_NLABELS);
889e948693eSPhilip Paeps 
8903c838a9fSAndrew Rybchenko 	EFSYS_ASSERT(ISP2(EFX_TXQ_MAXNDESCS(encp)));
8913c838a9fSAndrew Rybchenko 	EFX_STATIC_ASSERT(ISP2(EFX_TXQ_MINNDESCS));
8923c838a9fSAndrew Rybchenko 
8933c838a9fSAndrew Rybchenko 	if (!ISP2(n) || (n < EFX_TXQ_MINNDESCS) || (n > EFX_EVQ_MAXNEVS)) {
894e948693eSPhilip Paeps 		rc = EINVAL;
895e948693eSPhilip Paeps 		goto fail1;
896e948693eSPhilip Paeps 	}
897e948693eSPhilip Paeps 	if (index >= encp->enc_txq_limit) {
898e948693eSPhilip Paeps 		rc = EINVAL;
899e948693eSPhilip Paeps 		goto fail2;
900e948693eSPhilip Paeps 	}
9013c838a9fSAndrew Rybchenko 	for (size = 0;
9023c838a9fSAndrew Rybchenko 	    (1 << size) <= (EFX_TXQ_MAXNDESCS(encp) / EFX_TXQ_MINNDESCS);
903e948693eSPhilip Paeps 	    size++)
904e948693eSPhilip Paeps 		if ((1 << size) == (int)(n / EFX_TXQ_MINNDESCS))
905e948693eSPhilip Paeps 			break;
906e948693eSPhilip Paeps 	if (id + (1 << size) >= encp->enc_buftbl_limit) {
907e948693eSPhilip Paeps 		rc = EINVAL;
908e948693eSPhilip Paeps 		goto fail3;
909e948693eSPhilip Paeps 	}
910e948693eSPhilip Paeps 
911e948693eSPhilip Paeps 	/* Set up the new descriptor queue */
912*45229bd4SAndrew Rybchenko 	*addedp = 0;
913*45229bd4SAndrew Rybchenko 
914e948693eSPhilip Paeps 	EFX_POPULATE_OWORD_6(oword,
915e948693eSPhilip Paeps 	    FRF_AZ_TX_DESCQ_BUF_BASE_ID, id,
916e948693eSPhilip Paeps 	    FRF_AZ_TX_DESCQ_EVQ_ID, eep->ee_index,
917e948693eSPhilip Paeps 	    FRF_AZ_TX_DESCQ_OWNER_ID, 0,
918e948693eSPhilip Paeps 	    FRF_AZ_TX_DESCQ_LABEL, label,
919e948693eSPhilip Paeps 	    FRF_AZ_TX_DESCQ_SIZE, size,
920e948693eSPhilip Paeps 	    FRF_AZ_TX_DESCQ_TYPE, 0);
921e948693eSPhilip Paeps 
922e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_NON_IP_DROP_DIS, 1);
923e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_IP_CHKSM_DIS,
924e948693eSPhilip Paeps 	    (flags & EFX_CKSUM_IPV4) ? 0 : 1);
925e948693eSPhilip Paeps 	EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_TCP_CHKSM_DIS,
926e948693eSPhilip Paeps 	    (flags & EFX_CKSUM_TCPUDP) ? 0 : 1);
927e948693eSPhilip Paeps 
928e948693eSPhilip Paeps 	EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_DESC_PTR_TBL,
9293c838a9fSAndrew Rybchenko 	    etp->et_index, &oword, B_TRUE);
930e948693eSPhilip Paeps 
931e948693eSPhilip Paeps 	return (0);
932e948693eSPhilip Paeps 
933e948693eSPhilip Paeps fail3:
934e948693eSPhilip Paeps 	EFSYS_PROBE(fail3);
935e948693eSPhilip Paeps fail2:
936e948693eSPhilip Paeps 	EFSYS_PROBE(fail2);
937e948693eSPhilip Paeps fail1:
938e948693eSPhilip Paeps 	EFSYS_PROBE1(fail1, int, rc);
939e948693eSPhilip Paeps 
940e948693eSPhilip Paeps 	return (rc);
941e948693eSPhilip Paeps }
942e948693eSPhilip Paeps 
9433c838a9fSAndrew Rybchenko 	__checkReturn	int
9443c838a9fSAndrew Rybchenko falconsiena_tx_qdesc_post(
9453c838a9fSAndrew Rybchenko 	__in		efx_txq_t *etp,
9463c838a9fSAndrew Rybchenko 	__in_ecount(n)	efx_desc_t *ed,
9473c838a9fSAndrew Rybchenko 	__in		unsigned int n,
9483c838a9fSAndrew Rybchenko 	__in		unsigned int completed,
9493c838a9fSAndrew Rybchenko 	__inout		unsigned int *addedp)
9503c838a9fSAndrew Rybchenko {
9513c838a9fSAndrew Rybchenko 	unsigned int added = *addedp;
9523c838a9fSAndrew Rybchenko 	unsigned int i;
9533c838a9fSAndrew Rybchenko 	int rc;
9543c838a9fSAndrew Rybchenko 
9553c838a9fSAndrew Rybchenko 	if (added - completed + n > EFX_TXQ_LIMIT(etp->et_mask + 1)) {
9563c838a9fSAndrew Rybchenko 		rc = ENOSPC;
9573c838a9fSAndrew Rybchenko 		goto fail1;
9583c838a9fSAndrew Rybchenko 	}
9593c838a9fSAndrew Rybchenko 
9603c838a9fSAndrew Rybchenko 	for (i = 0; i < n; i++) {
9613c838a9fSAndrew Rybchenko 		efx_desc_t *edp = &ed[i];
9623c838a9fSAndrew Rybchenko 		unsigned int id;
9633c838a9fSAndrew Rybchenko 		size_t offset;
9643c838a9fSAndrew Rybchenko 
9653c838a9fSAndrew Rybchenko 		id = added++ & etp->et_mask;
9663c838a9fSAndrew Rybchenko 		offset = id * sizeof (efx_desc_t);
9673c838a9fSAndrew Rybchenko 
9683c838a9fSAndrew Rybchenko 		EFSYS_MEM_WRITEQ(etp->et_esmp, offset, &edp->ed_eq);
9693c838a9fSAndrew Rybchenko 	}
9703c838a9fSAndrew Rybchenko 
9713c838a9fSAndrew Rybchenko 	EFSYS_PROBE3(tx_desc_post, unsigned int, etp->et_index,
9723c838a9fSAndrew Rybchenko 		    unsigned int, added, unsigned int, n);
9733c838a9fSAndrew Rybchenko 
9743c838a9fSAndrew Rybchenko 	EFX_TX_QSTAT_INCR(etp, TX_POST);
9753c838a9fSAndrew Rybchenko 
9763c838a9fSAndrew Rybchenko 	*addedp = added;
9773c838a9fSAndrew Rybchenko 	return (0);
9783c838a9fSAndrew Rybchenko 
9793c838a9fSAndrew Rybchenko fail1:
9803c838a9fSAndrew Rybchenko 	EFSYS_PROBE1(fail1, int, rc);
9813c838a9fSAndrew Rybchenko 	return (rc);
9823c838a9fSAndrew Rybchenko }
9833c838a9fSAndrew Rybchenko 
9843c838a9fSAndrew Rybchenko 	void
9853c838a9fSAndrew Rybchenko falconsiena_tx_qdesc_dma_create(
9863c838a9fSAndrew Rybchenko 	__in	efx_txq_t *etp,
9873c838a9fSAndrew Rybchenko 	__in	efsys_dma_addr_t addr,
9883c838a9fSAndrew Rybchenko 	__in	size_t size,
9893c838a9fSAndrew Rybchenko 	__in	boolean_t eop,
9903c838a9fSAndrew Rybchenko 	__out	efx_desc_t *edp)
9913c838a9fSAndrew Rybchenko {
9923c838a9fSAndrew Rybchenko 	/* Fragments must not span 4k boundaries. */
9933c838a9fSAndrew Rybchenko 	EFSYS_ASSERT(P2ROUNDUP(addr + 1, 4096) >= addr + size);
9943c838a9fSAndrew Rybchenko 
9953c838a9fSAndrew Rybchenko 	EFSYS_PROBE4(tx_desc_dma_create, unsigned int, etp->et_index,
9963c838a9fSAndrew Rybchenko 		    efsys_dma_addr_t, addr,
9973c838a9fSAndrew Rybchenko 		    size_t, size, boolean_t, eop);
9983c838a9fSAndrew Rybchenko 
9993c838a9fSAndrew Rybchenko 	EFX_POPULATE_QWORD_4(edp->ed_eq,
10003c838a9fSAndrew Rybchenko 			    FSF_AZ_TX_KER_CONT, eop ? 0 : 1,
10013c838a9fSAndrew Rybchenko 			    FSF_AZ_TX_KER_BYTE_COUNT, (uint32_t)size,
10023c838a9fSAndrew Rybchenko 			    FSF_AZ_TX_KER_BUF_ADDR_DW0,
10033c838a9fSAndrew Rybchenko 			    (uint32_t)(addr & 0xffffffff),
10043c838a9fSAndrew Rybchenko 			    FSF_AZ_TX_KER_BUF_ADDR_DW1,
10053c838a9fSAndrew Rybchenko 			    (uint32_t)(addr >> 32));
10063c838a9fSAndrew Rybchenko }
10073c838a9fSAndrew Rybchenko 
10083c838a9fSAndrew Rybchenko #endif /* EFSYS_OPT_FALCON || EFSYS_OPT_SIENA */
10093c838a9fSAndrew Rybchenko 
1010fe900081SAndrew Rybchenko #if EFSYS_OPT_QSTATS
1011e948693eSPhilip Paeps #if EFSYS_OPT_NAMES
10123c838a9fSAndrew Rybchenko /* START MKCONFIG GENERATED EfxTransmitQueueStatNamesBlock 9d8d26a0a5e2c453 */
10133c838a9fSAndrew Rybchenko static const char 	*__efx_tx_qstat_name[] = {
1014e948693eSPhilip Paeps 	"post",
10153c838a9fSAndrew Rybchenko 	"post_pio",
1016e948693eSPhilip Paeps };
1017e948693eSPhilip Paeps /* END MKCONFIG GENERATED EfxTransmitQueueStatNamesBlock */
1018e948693eSPhilip Paeps 
10193c838a9fSAndrew Rybchenko 		const char *
1020e948693eSPhilip Paeps efx_tx_qstat_name(
1021e948693eSPhilip Paeps 	__in	efx_nic_t *enp,
1022e948693eSPhilip Paeps 	__in	unsigned int id)
1023e948693eSPhilip Paeps {
1024e948693eSPhilip Paeps 	_NOTE(ARGUNUSED(enp))
1025e948693eSPhilip Paeps 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1026e948693eSPhilip Paeps 	EFSYS_ASSERT3U(id, <, TX_NQSTATS);
1027e948693eSPhilip Paeps 
1028e948693eSPhilip Paeps 	return (__efx_tx_qstat_name[id]);
1029e948693eSPhilip Paeps }
1030e948693eSPhilip Paeps #endif	/* EFSYS_OPT_NAMES */
1031fe900081SAndrew Rybchenko #endif /* EFSYS_OPT_QSTATS */
1032e948693eSPhilip Paeps 
10333c838a9fSAndrew Rybchenko #if EFSYS_OPT_FALCON || EFSYS_OPT_SIENA
10343c838a9fSAndrew Rybchenko 
1035e948693eSPhilip Paeps #if EFSYS_OPT_QSTATS
10363c838a9fSAndrew Rybchenko static					void
10373c838a9fSAndrew Rybchenko falconsiena_tx_qstats_update(
1038e948693eSPhilip Paeps 	__in				efx_txq_t *etp,
1039e948693eSPhilip Paeps 	__inout_ecount(TX_NQSTATS)	efsys_stat_t *stat)
1040e948693eSPhilip Paeps {
1041e948693eSPhilip Paeps 	unsigned int id;
1042e948693eSPhilip Paeps 
1043e948693eSPhilip Paeps 	for (id = 0; id < TX_NQSTATS; id++) {
1044e948693eSPhilip Paeps 		efsys_stat_t *essp = &stat[id];
1045e948693eSPhilip Paeps 
1046e948693eSPhilip Paeps 		EFSYS_STAT_INCR(essp, etp->et_stat[id]);
1047e948693eSPhilip Paeps 		etp->et_stat[id] = 0;
1048e948693eSPhilip Paeps 	}
1049e948693eSPhilip Paeps }
1050e948693eSPhilip Paeps #endif	/* EFSYS_OPT_QSTATS */
1051e948693eSPhilip Paeps 
10523c838a9fSAndrew Rybchenko static		void
10533c838a9fSAndrew Rybchenko falconsiena_tx_qdestroy(
1054e948693eSPhilip Paeps 	__in	efx_txq_t *etp)
1055e948693eSPhilip Paeps {
1056e948693eSPhilip Paeps 	efx_nic_t *enp = etp->et_enp;
1057e948693eSPhilip Paeps 	efx_oword_t oword;
1058e948693eSPhilip Paeps 
1059e948693eSPhilip Paeps 	/* Purge descriptor queue */
1060e948693eSPhilip Paeps 	EFX_ZERO_OWORD(oword);
1061e948693eSPhilip Paeps 
1062e948693eSPhilip Paeps 	EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_DESC_PTR_TBL,
10633c838a9fSAndrew Rybchenko 			    etp->et_index, &oword, B_TRUE);
1064e948693eSPhilip Paeps }
1065e948693eSPhilip Paeps 
10663c838a9fSAndrew Rybchenko static		void
10673c838a9fSAndrew Rybchenko falconsiena_tx_fini(
1068e948693eSPhilip Paeps 	__in	efx_nic_t *enp)
1069e948693eSPhilip Paeps {
10703c838a9fSAndrew Rybchenko 	_NOTE(ARGUNUSED(enp))
1071e948693eSPhilip Paeps }
10723c838a9fSAndrew Rybchenko 
10733c838a9fSAndrew Rybchenko #endif /* EFSYS_OPT_FALCON || EFSYS_OPT_SIENA */
1074