1/*-
2 * Copyright (c) 2012-2016 Solarflare Communications Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 *    this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 *    this list of conditions and the following disclaimer in the documentation
12 *    and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * The views and conclusions contained in the software and documentation are
27 * those of the authors and should not be interpreted as representing official
28 * policies, either expressed or implied, of the FreeBSD Project.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: stable/10/sys/dev/sfxge/common/ef10_tx.c 342516 2018-12-26 10:25:01Z arybchik $");
33
34#include "efx.h"
35#include "efx_impl.h"
36
37
38#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
39
40#if EFSYS_OPT_QSTATS
41#define	EFX_TX_QSTAT_INCR(_etp, _stat)					\
42	do {								\
43		(_etp)->et_stat[_stat]++;				\
44	_NOTE(CONSTANTCONDITION)					\
45	} while (B_FALSE)
46#else
47#define	EFX_TX_QSTAT_INCR(_etp, _stat)
48#endif
49
50static	__checkReturn	efx_rc_t
51efx_mcdi_init_txq(
52	__in		efx_nic_t *enp,
53	__in		uint32_t size,
54	__in		uint32_t target_evq,
55	__in		uint32_t label,
56	__in		uint32_t instance,
57	__in		uint16_t flags,
58	__in		efsys_mem_t *esmp)
59{
60	efx_mcdi_req_t req;
61	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_INIT_TXQ_IN_LEN(EFX_TXQ_MAX_BUFS),
62		MC_CMD_INIT_TXQ_OUT_LEN);
63	efx_qword_t *dma_addr;
64	uint64_t addr;
65	int npages;
66	int i;
67	efx_rc_t rc;
68
69	EFSYS_ASSERT(EFX_TXQ_MAX_BUFS >=
70	    EFX_TXQ_NBUFS(enp->en_nic_cfg.enc_txq_max_ndescs));
71
72	npages = EFX_TXQ_NBUFS(size);
73	if (npages > MC_CMD_INIT_TXQ_IN_DMA_ADDR_MAXNUM) {
74		rc = EINVAL;
75		goto fail1;
76	}
77
78	req.emr_cmd = MC_CMD_INIT_TXQ;
79	req.emr_in_buf = payload;
80	req.emr_in_length = MC_CMD_INIT_TXQ_IN_LEN(npages);
81	req.emr_out_buf = payload;
82	req.emr_out_length = MC_CMD_INIT_TXQ_OUT_LEN;
83
84	MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_SIZE, size);
85	MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_TARGET_EVQ, target_evq);
86	MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_LABEL, label);
87	MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_INSTANCE, instance);
88
89	MCDI_IN_POPULATE_DWORD_9(req, INIT_TXQ_IN_FLAGS,
90	    INIT_TXQ_IN_FLAG_BUFF_MODE, 0,
91	    INIT_TXQ_IN_FLAG_IP_CSUM_DIS,
92	    (flags & EFX_TXQ_CKSUM_IPV4) ? 0 : 1,
93	    INIT_TXQ_IN_FLAG_TCP_CSUM_DIS,
94	    (flags & EFX_TXQ_CKSUM_TCPUDP) ? 0 : 1,
95	    INIT_TXQ_EXT_IN_FLAG_INNER_IP_CSUM_EN,
96	    (flags & EFX_TXQ_CKSUM_INNER_IPV4) ? 1 : 0,
97	    INIT_TXQ_EXT_IN_FLAG_INNER_TCP_CSUM_EN,
98	    (flags & EFX_TXQ_CKSUM_INNER_TCPUDP) ? 1 : 0,
99	    INIT_TXQ_EXT_IN_FLAG_TSOV2_EN, (flags & EFX_TXQ_FATSOV2) ? 1 : 0,
100	    INIT_TXQ_IN_FLAG_TCP_UDP_ONLY, 0,
101	    INIT_TXQ_IN_CRC_MODE, 0,
102	    INIT_TXQ_IN_FLAG_TIMESTAMP, 0);
103
104	MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_OWNER_ID, 0);
105	MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_PORT_ID, EVB_PORT_ID_ASSIGNED);
106
107	dma_addr = MCDI_IN2(req, efx_qword_t, INIT_TXQ_IN_DMA_ADDR);
108	addr = EFSYS_MEM_ADDR(esmp);
109
110	for (i = 0; i < npages; i++) {
111		EFX_POPULATE_QWORD_2(*dma_addr,
112		    EFX_DWORD_1, (uint32_t)(addr >> 32),
113		    EFX_DWORD_0, (uint32_t)(addr & 0xffffffff));
114
115		dma_addr++;
116		addr += EFX_BUF_SIZE;
117	}
118
119	efx_mcdi_execute(enp, &req);
120
121	if (req.emr_rc != 0) {
122		rc = req.emr_rc;
123		goto fail2;
124	}
125
126	return (0);
127
128fail2:
129	EFSYS_PROBE(fail2);
130fail1:
131	EFSYS_PROBE1(fail1, efx_rc_t, rc);
132
133	return (rc);
134}
135
136static	__checkReturn	efx_rc_t
137efx_mcdi_fini_txq(
138	__in		efx_nic_t *enp,
139	__in		uint32_t instance)
140{
141	efx_mcdi_req_t req;
142	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_FINI_TXQ_IN_LEN,
143		MC_CMD_FINI_TXQ_OUT_LEN);
144	efx_rc_t rc;
145
146	req.emr_cmd = MC_CMD_FINI_TXQ;
147	req.emr_in_buf = payload;
148	req.emr_in_length = MC_CMD_FINI_TXQ_IN_LEN;
149	req.emr_out_buf = payload;
150	req.emr_out_length = MC_CMD_FINI_TXQ_OUT_LEN;
151
152	MCDI_IN_SET_DWORD(req, FINI_TXQ_IN_INSTANCE, instance);
153
154	efx_mcdi_execute_quiet(enp, &req);
155
156	if (req.emr_rc != 0) {
157		rc = req.emr_rc;
158		goto fail1;
159	}
160
161	return (0);
162
163fail1:
164	/*
165	 * EALREADY is not an error, but indicates that the MC has rebooted and
166	 * that the TXQ has already been destroyed.
167	 */
168	if (rc != EALREADY)
169		EFSYS_PROBE1(fail1, efx_rc_t, rc);
170
171	return (rc);
172}
173
174	__checkReturn	efx_rc_t
175ef10_tx_init(
176	__in		efx_nic_t *enp)
177{
178	_NOTE(ARGUNUSED(enp))
179	return (0);
180}
181
182			void
183ef10_tx_fini(
184	__in		efx_nic_t *enp)
185{
186	_NOTE(ARGUNUSED(enp))
187}
188
189	__checkReturn	efx_rc_t
190ef10_tx_qcreate(
191	__in		efx_nic_t *enp,
192	__in		unsigned int index,
193	__in		unsigned int label,
194	__in		efsys_mem_t *esmp,
195	__in		size_t n,
196	__in		uint32_t id,
197	__in		uint16_t flags,
198	__in		efx_evq_t *eep,
199	__in		efx_txq_t *etp,
200	__out		unsigned int *addedp)
201{
202	efx_nic_cfg_t *encp = &enp->en_nic_cfg;
203	uint16_t inner_csum;
204	efx_desc_t desc;
205	efx_rc_t rc;
206
207	_NOTE(ARGUNUSED(id))
208
209	inner_csum = EFX_TXQ_CKSUM_INNER_IPV4 | EFX_TXQ_CKSUM_INNER_TCPUDP;
210	if (((flags & inner_csum) != 0) &&
211	    (encp->enc_tunnel_encapsulations_supported == 0)) {
212		rc = EINVAL;
213		goto fail1;
214	}
215
216	if ((rc = efx_mcdi_init_txq(enp, n, eep->ee_index, label, index, flags,
217	    esmp)) != 0)
218		goto fail2;
219
220	/*
221	 * A previous user of this TX queue may have written a descriptor to the
222	 * TX push collector, but not pushed the doorbell (e.g. after a crash).
223	 * The next doorbell write would then push the stale descriptor.
224	 *
225	 * Ensure the (per network port) TX push collector is cleared by writing
226	 * a no-op TX option descriptor. See bug29981 for details.
227	 */
228	*addedp = 1;
229	ef10_tx_qdesc_checksum_create(etp, flags, &desc);
230
231	EFSYS_MEM_WRITEQ(etp->et_esmp, 0, &desc.ed_eq);
232	ef10_tx_qpush(etp, *addedp, 0);
233
234	return (0);
235
236fail2:
237	EFSYS_PROBE(fail2);
238fail1:
239	EFSYS_PROBE1(fail1, efx_rc_t, rc);
240
241	return (rc);
242}
243
244		void
245ef10_tx_qdestroy(
246	__in	efx_txq_t *etp)
247{
248	/* FIXME */
249	_NOTE(ARGUNUSED(etp))
250	/* FIXME */
251}
252
253	__checkReturn	efx_rc_t
254ef10_tx_qpio_enable(
255	__in		efx_txq_t *etp)
256{
257	efx_nic_t *enp = etp->et_enp;
258	efx_piobuf_handle_t handle;
259	efx_rc_t rc;
260
261	if (etp->et_pio_size != 0) {
262		rc = EALREADY;
263		goto fail1;
264	}
265
266	/* Sub-allocate a PIO block from a piobuf */
267	if ((rc = ef10_nic_pio_alloc(enp,
268		    &etp->et_pio_bufnum,
269		    &handle,
270		    &etp->et_pio_blknum,
271		    &etp->et_pio_offset,
272		    &etp->et_pio_size)) != 0) {
273		goto fail2;
274	}
275	EFSYS_ASSERT3U(etp->et_pio_size, !=, 0);
276
277	/* Link the piobuf to this TXQ */
278	if ((rc = ef10_nic_pio_link(enp, etp->et_index, handle)) != 0) {
279		goto fail3;
280	}
281
282	/*
283	 * et_pio_offset is the offset of the sub-allocated block within the
284	 * hardware PIO buffer. It is used as the buffer address in the PIO
285	 * option descriptor.
286	 *
287	 * et_pio_write_offset is the offset of the sub-allocated block from the
288	 * start of the write-combined memory mapping, and is used for writing
289	 * data into the PIO buffer.
290	 */
291	etp->et_pio_write_offset =
292	    (etp->et_pio_bufnum * ER_DZ_TX_PIOBUF_STEP) +
293	    ER_DZ_TX_PIOBUF_OFST + etp->et_pio_offset;
294
295	return (0);
296
297fail3:
298	EFSYS_PROBE(fail3);
299	(void) ef10_nic_pio_free(enp, etp->et_pio_bufnum, etp->et_pio_blknum);
300	etp->et_pio_size = 0;
301fail2:
302	EFSYS_PROBE(fail2);
303fail1:
304	EFSYS_PROBE1(fail1, efx_rc_t, rc);
305
306	return (rc);
307}
308
309			void
310ef10_tx_qpio_disable(
311	__in		efx_txq_t *etp)
312{
313	efx_nic_t *enp = etp->et_enp;
314
315	if (etp->et_pio_size != 0) {
316		/* Unlink the piobuf from this TXQ */
317		if (ef10_nic_pio_unlink(enp, etp->et_index) != 0)
318			return;
319
320		/* Free the sub-allocated PIO block */
321		(void) ef10_nic_pio_free(enp, etp->et_pio_bufnum,
322		    etp->et_pio_blknum);
323		etp->et_pio_size = 0;
324		etp->et_pio_write_offset = 0;
325	}
326}
327
328	__checkReturn	efx_rc_t
329ef10_tx_qpio_write(
330	__in			efx_txq_t *etp,
331	__in_ecount(length)	uint8_t *buffer,
332	__in			size_t length,
333	__in			size_t offset)
334{
335	efx_nic_t *enp = etp->et_enp;
336	efsys_bar_t *esbp = enp->en_esbp;
337	uint32_t write_offset;
338	uint32_t write_offset_limit;
339	efx_qword_t *eqp;
340	efx_rc_t rc;
341
342	EFSYS_ASSERT(length % sizeof (efx_qword_t) == 0);
343
344	if (etp->et_pio_size == 0) {
345		rc = ENOENT;
346		goto fail1;
347	}
348	if (offset + length > etp->et_pio_size)	{
349		rc = ENOSPC;
350		goto fail2;
351	}
352
353	/*
354	 * Writes to PIO buffers must be 64 bit aligned, and multiples of
355	 * 64 bits.
356	 */
357	write_offset = etp->et_pio_write_offset + offset;
358	write_offset_limit = write_offset + length;
359	eqp = (efx_qword_t *)buffer;
360	while (write_offset < write_offset_limit) {
361		EFSYS_BAR_WC_WRITEQ(esbp, write_offset, eqp);
362		eqp++;
363		write_offset += sizeof (efx_qword_t);
364	}
365
366	return (0);
367
368fail2:
369	EFSYS_PROBE(fail2);
370fail1:
371	EFSYS_PROBE1(fail1, efx_rc_t, rc);
372
373	return (rc);
374}
375
376	__checkReturn	efx_rc_t
377ef10_tx_qpio_post(
378	__in			efx_txq_t *etp,
379	__in			size_t pkt_length,
380	__in			unsigned int completed,
381	__inout			unsigned int *addedp)
382{
383	efx_qword_t pio_desc;
384	unsigned int id;
385	size_t offset;
386	unsigned int added = *addedp;
387	efx_rc_t rc;
388
389
390	if (added - completed + 1 > EFX_TXQ_LIMIT(etp->et_mask + 1)) {
391		rc = ENOSPC;
392		goto fail1;
393	}
394
395	if (etp->et_pio_size == 0) {
396		rc = ENOENT;
397		goto fail2;
398	}
399
400	id = added++ & etp->et_mask;
401	offset = id * sizeof (efx_qword_t);
402
403	EFSYS_PROBE4(tx_pio_post, unsigned int, etp->et_index,
404		    unsigned int, id, uint32_t, etp->et_pio_offset,
405		    size_t, pkt_length);
406
407	EFX_POPULATE_QWORD_5(pio_desc,
408			ESF_DZ_TX_DESC_IS_OPT, 1,
409			ESF_DZ_TX_OPTION_TYPE, 1,
410			ESF_DZ_TX_PIO_CONT, 0,
411			ESF_DZ_TX_PIO_BYTE_CNT, pkt_length,
412			ESF_DZ_TX_PIO_BUF_ADDR, etp->et_pio_offset);
413
414	EFSYS_MEM_WRITEQ(etp->et_esmp, offset, &pio_desc);
415
416	EFX_TX_QSTAT_INCR(etp, TX_POST_PIO);
417
418	*addedp = added;
419	return (0);
420
421fail2:
422	EFSYS_PROBE(fail2);
423fail1:
424	EFSYS_PROBE1(fail1, efx_rc_t, rc);
425
426	return (rc);
427}
428
429	__checkReturn	efx_rc_t
430ef10_tx_qpost(
431	__in		efx_txq_t *etp,
432	__in_ecount(n)	efx_buffer_t *eb,
433	__in		unsigned int n,
434	__in		unsigned int completed,
435	__inout		unsigned int *addedp)
436{
437	unsigned int added = *addedp;
438	unsigned int i;
439	efx_rc_t rc;
440
441	if (added - completed + n > EFX_TXQ_LIMIT(etp->et_mask + 1)) {
442		rc = ENOSPC;
443		goto fail1;
444	}
445
446	for (i = 0; i < n; i++) {
447		efx_buffer_t *ebp = &eb[i];
448		efsys_dma_addr_t addr = ebp->eb_addr;
449		size_t size = ebp->eb_size;
450		boolean_t eop = ebp->eb_eop;
451		unsigned int id;
452		size_t offset;
453		efx_qword_t qword;
454
455		/* No limitations on boundary crossing */
456		EFSYS_ASSERT(size <=
457		    etp->et_enp->en_nic_cfg.enc_tx_dma_desc_size_max);
458
459		id = added++ & etp->et_mask;
460		offset = id * sizeof (efx_qword_t);
461
462		EFSYS_PROBE5(tx_post, unsigned int, etp->et_index,
463		    unsigned int, id, efsys_dma_addr_t, addr,
464		    size_t, size, boolean_t, eop);
465
466		EFX_POPULATE_QWORD_5(qword,
467		    ESF_DZ_TX_KER_TYPE, 0,
468		    ESF_DZ_TX_KER_CONT, (eop) ? 0 : 1,
469		    ESF_DZ_TX_KER_BYTE_CNT, (uint32_t)(size),
470		    ESF_DZ_TX_KER_BUF_ADDR_DW0, (uint32_t)(addr & 0xffffffff),
471		    ESF_DZ_TX_KER_BUF_ADDR_DW1, (uint32_t)(addr >> 32));
472
473		EFSYS_MEM_WRITEQ(etp->et_esmp, offset, &qword);
474	}
475
476	EFX_TX_QSTAT_INCR(etp, TX_POST);
477
478	*addedp = added;
479	return (0);
480
481fail1:
482	EFSYS_PROBE1(fail1, efx_rc_t, rc);
483
484	return (rc);
485}
486
487/*
488 * This improves performance by, when possible, pushing a TX descriptor at the
489 * same time as the doorbell. The descriptor must be added to the TXQ, so that
490 * can be used if the hardware decides not to use the pushed descriptor.
491 */
492			void
493ef10_tx_qpush(
494	__in		efx_txq_t *etp,
495	__in		unsigned int added,
496	__in		unsigned int pushed)
497{
498	efx_nic_t *enp = etp->et_enp;
499	unsigned int wptr;
500	unsigned int id;
501	size_t offset;
502	efx_qword_t desc;
503	efx_oword_t oword;
504
505	wptr = added & etp->et_mask;
506	id = pushed & etp->et_mask;
507	offset = id * sizeof (efx_qword_t);
508
509	EFSYS_MEM_READQ(etp->et_esmp, offset, &desc);
510
511	/*
512	 * SF Bug 65776: TSO option descriptors cannot be pushed if pacer bypass
513	 * is enabled on the event queue this transmit queue is attached to.
514	 *
515	 * To ensure the code is safe, it is easiest to simply test the type of
516	 * the descriptor to push, and only push it is if it not a TSO option
517	 * descriptor.
518	 */
519	if ((EFX_QWORD_FIELD(desc, ESF_DZ_TX_DESC_IS_OPT) != 1) ||
520	    (EFX_QWORD_FIELD(desc, ESF_DZ_TX_OPTION_TYPE) !=
521	    ESE_DZ_TX_OPTION_DESC_TSO)) {
522		/* Push the descriptor and update the wptr. */
523		EFX_POPULATE_OWORD_3(oword, ERF_DZ_TX_DESC_WPTR, wptr,
524		    ERF_DZ_TX_DESC_HWORD, EFX_QWORD_FIELD(desc, EFX_DWORD_1),
525		    ERF_DZ_TX_DESC_LWORD, EFX_QWORD_FIELD(desc, EFX_DWORD_0));
526
527		/* Ensure ordering of memory (descriptors) and PIO (doorbell) */
528		EFX_DMA_SYNC_QUEUE_FOR_DEVICE(etp->et_esmp, etp->et_mask + 1,
529					    wptr, id);
530		EFSYS_PIO_WRITE_BARRIER();
531		EFX_BAR_TBL_DOORBELL_WRITEO(enp, ER_DZ_TX_DESC_UPD_REG,
532					    etp->et_index, &oword);
533	} else {
534		efx_dword_t dword;
535
536		/*
537		 * Only update the wptr. This is signalled to the hardware by
538		 * only writing one DWORD of the doorbell register.
539		 */
540		EFX_POPULATE_OWORD_1(oword, ERF_DZ_TX_DESC_WPTR, wptr);
541		dword = oword.eo_dword[2];
542
543		/* Ensure ordering of memory (descriptors) and PIO (doorbell) */
544		EFX_DMA_SYNC_QUEUE_FOR_DEVICE(etp->et_esmp, etp->et_mask + 1,
545					    wptr, id);
546		EFSYS_PIO_WRITE_BARRIER();
547		EFX_BAR_TBL_WRITED2(enp, ER_DZ_TX_DESC_UPD_REG,
548				    etp->et_index, &dword, B_FALSE);
549	}
550}
551
552	__checkReturn	efx_rc_t
553ef10_tx_qdesc_post(
554	__in		efx_txq_t *etp,
555	__in_ecount(n)	efx_desc_t *ed,
556	__in		unsigned int n,
557	__in		unsigned int completed,
558	__inout		unsigned int *addedp)
559{
560	unsigned int added = *addedp;
561	unsigned int i;
562	efx_rc_t rc;
563
564	if (added - completed + n > EFX_TXQ_LIMIT(etp->et_mask + 1)) {
565		rc = ENOSPC;
566		goto fail1;
567	}
568
569	for (i = 0; i < n; i++) {
570		efx_desc_t *edp = &ed[i];
571		unsigned int id;
572		size_t offset;
573
574		id = added++ & etp->et_mask;
575		offset = id * sizeof (efx_desc_t);
576
577		EFSYS_MEM_WRITEQ(etp->et_esmp, offset, &edp->ed_eq);
578	}
579
580	EFSYS_PROBE3(tx_desc_post, unsigned int, etp->et_index,
581		    unsigned int, added, unsigned int, n);
582
583	EFX_TX_QSTAT_INCR(etp, TX_POST);
584
585	*addedp = added;
586	return (0);
587
588fail1:
589	EFSYS_PROBE1(fail1, efx_rc_t, rc);
590
591	return (rc);
592}
593
594	void
595ef10_tx_qdesc_dma_create(
596	__in	efx_txq_t *etp,
597	__in	efsys_dma_addr_t addr,
598	__in	size_t size,
599	__in	boolean_t eop,
600	__out	efx_desc_t *edp)
601{
602	_NOTE(ARGUNUSED(etp))
603
604	/* No limitations on boundary crossing */
605	EFSYS_ASSERT(size <= etp->et_enp->en_nic_cfg.enc_tx_dma_desc_size_max);
606
607	EFSYS_PROBE4(tx_desc_dma_create, unsigned int, etp->et_index,
608		    efsys_dma_addr_t, addr,
609		    size_t, size, boolean_t, eop);
610
611	EFX_POPULATE_QWORD_5(edp->ed_eq,
612		    ESF_DZ_TX_KER_TYPE, 0,
613		    ESF_DZ_TX_KER_CONT, (eop) ? 0 : 1,
614		    ESF_DZ_TX_KER_BYTE_CNT, (uint32_t)(size),
615		    ESF_DZ_TX_KER_BUF_ADDR_DW0, (uint32_t)(addr & 0xffffffff),
616		    ESF_DZ_TX_KER_BUF_ADDR_DW1, (uint32_t)(addr >> 32));
617}
618
619	void
620ef10_tx_qdesc_tso_create(
621	__in	efx_txq_t *etp,
622	__in	uint16_t ipv4_id,
623	__in	uint32_t tcp_seq,
624	__in	uint8_t  tcp_flags,
625	__out	efx_desc_t *edp)
626{
627	_NOTE(ARGUNUSED(etp))
628
629	EFSYS_PROBE4(tx_desc_tso_create, unsigned int, etp->et_index,
630		    uint16_t, ipv4_id, uint32_t, tcp_seq,
631		    uint8_t, tcp_flags);
632
633	EFX_POPULATE_QWORD_5(edp->ed_eq,
634			    ESF_DZ_TX_DESC_IS_OPT, 1,
635			    ESF_DZ_TX_OPTION_TYPE,
636			    ESE_DZ_TX_OPTION_DESC_TSO,
637			    ESF_DZ_TX_TSO_TCP_FLAGS, tcp_flags,
638			    ESF_DZ_TX_TSO_IP_ID, ipv4_id,
639			    ESF_DZ_TX_TSO_TCP_SEQNO, tcp_seq);
640}
641
642	void
643ef10_tx_qdesc_tso2_create(
644	__in			efx_txq_t *etp,
645	__in			uint16_t ipv4_id,
646	__in			uint32_t tcp_seq,
647	__in			uint16_t tcp_mss,
648	__out_ecount(count)	efx_desc_t *edp,
649	__in			int count)
650{
651	_NOTE(ARGUNUSED(etp, count))
652
653	EFSYS_PROBE4(tx_desc_tso2_create, unsigned int, etp->et_index,
654		    uint16_t, ipv4_id, uint32_t, tcp_seq,
655		    uint16_t, tcp_mss);
656
657	EFSYS_ASSERT(count >= EFX_TX_FATSOV2_OPT_NDESCS);
658
659	EFX_POPULATE_QWORD_5(edp[0].ed_eq,
660			    ESF_DZ_TX_DESC_IS_OPT, 1,
661			    ESF_DZ_TX_OPTION_TYPE,
662			    ESE_DZ_TX_OPTION_DESC_TSO,
663			    ESF_DZ_TX_TSO_OPTION_TYPE,
664			    ESE_DZ_TX_TSO_OPTION_DESC_FATSO2A,
665			    ESF_DZ_TX_TSO_IP_ID, ipv4_id,
666			    ESF_DZ_TX_TSO_TCP_SEQNO, tcp_seq);
667	EFX_POPULATE_QWORD_4(edp[1].ed_eq,
668			    ESF_DZ_TX_DESC_IS_OPT, 1,
669			    ESF_DZ_TX_OPTION_TYPE,
670			    ESE_DZ_TX_OPTION_DESC_TSO,
671			    ESF_DZ_TX_TSO_OPTION_TYPE,
672			    ESE_DZ_TX_TSO_OPTION_DESC_FATSO2B,
673			    ESF_DZ_TX_TSO_TCP_MSS, tcp_mss);
674}
675
676	void
677ef10_tx_qdesc_vlantci_create(
678	__in	efx_txq_t *etp,
679	__in	uint16_t  tci,
680	__out	efx_desc_t *edp)
681{
682	_NOTE(ARGUNUSED(etp))
683
684	EFSYS_PROBE2(tx_desc_vlantci_create, unsigned int, etp->et_index,
685		    uint16_t, tci);
686
687	EFX_POPULATE_QWORD_4(edp->ed_eq,
688			    ESF_DZ_TX_DESC_IS_OPT, 1,
689			    ESF_DZ_TX_OPTION_TYPE,
690			    ESE_DZ_TX_OPTION_DESC_VLAN,
691			    ESF_DZ_TX_VLAN_OP, tci ? 1 : 0,
692			    ESF_DZ_TX_VLAN_TAG1, tci);
693}
694
695	void
696ef10_tx_qdesc_checksum_create(
697	__in	efx_txq_t *etp,
698	__in	uint16_t flags,
699	__out	efx_desc_t *edp)
700{
701	_NOTE(ARGUNUSED(etp));
702
703	EFSYS_PROBE2(tx_desc_checksum_create, unsigned int, etp->et_index,
704		    uint32_t, flags);
705
706	EFX_POPULATE_QWORD_6(edp->ed_eq,
707	    ESF_DZ_TX_DESC_IS_OPT, 1,
708	    ESF_DZ_TX_OPTION_TYPE, ESE_DZ_TX_OPTION_DESC_CRC_CSUM,
709	    ESF_DZ_TX_OPTION_UDP_TCP_CSUM,
710	    (flags & EFX_TXQ_CKSUM_TCPUDP) ? 1 : 0,
711	    ESF_DZ_TX_OPTION_IP_CSUM,
712	    (flags & EFX_TXQ_CKSUM_IPV4) ? 1 : 0,
713	    ESF_DZ_TX_OPTION_INNER_UDP_TCP_CSUM,
714	    (flags & EFX_TXQ_CKSUM_INNER_TCPUDP) ? 1 : 0,
715	    ESF_DZ_TX_OPTION_INNER_IP_CSUM,
716	    (flags & EFX_TXQ_CKSUM_INNER_IPV4) ? 1 : 0);
717}
718
719
720	__checkReturn	efx_rc_t
721ef10_tx_qpace(
722	__in		efx_txq_t *etp,
723	__in		unsigned int ns)
724{
725	efx_rc_t rc;
726
727	/* FIXME */
728	_NOTE(ARGUNUSED(etp, ns))
729	_NOTE(CONSTANTCONDITION)
730	if (B_FALSE) {
731		rc = ENOTSUP;
732		goto fail1;
733	}
734	/* FIXME */
735
736	return (0);
737
738fail1:
739	/*
740	 * EALREADY is not an error, but indicates that the MC has rebooted and
741	 * that the TXQ has already been destroyed. Callers need to know that
742	 * the TXQ flush has completed to avoid waiting until timeout for a
743	 * flush done event that will not be delivered.
744	 */
745	if (rc != EALREADY)
746		EFSYS_PROBE1(fail1, efx_rc_t, rc);
747
748	return (rc);
749}
750
751	__checkReturn	efx_rc_t
752ef10_tx_qflush(
753	__in		efx_txq_t *etp)
754{
755	efx_nic_t *enp = etp->et_enp;
756	efx_rc_t rc;
757
758	if ((rc = efx_mcdi_fini_txq(enp, etp->et_index)) != 0)
759		goto fail1;
760
761	return (0);
762
763fail1:
764	EFSYS_PROBE1(fail1, efx_rc_t, rc);
765
766	return (rc);
767}
768
769			void
770ef10_tx_qenable(
771	__in		efx_txq_t *etp)
772{
773	/* FIXME */
774	_NOTE(ARGUNUSED(etp))
775	/* FIXME */
776}
777
778#if EFSYS_OPT_QSTATS
779			void
780ef10_tx_qstats_update(
781	__in				efx_txq_t *etp,
782	__inout_ecount(TX_NQSTATS)	efsys_stat_t *stat)
783{
784	unsigned int id;
785
786	for (id = 0; id < TX_NQSTATS; id++) {
787		efsys_stat_t *essp = &stat[id];
788
789		EFSYS_STAT_INCR(essp, etp->et_stat[id]);
790		etp->et_stat[id] = 0;
791	}
792}
793
794#endif /* EFSYS_OPT_QSTATS */
795
796#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
797