1283514Sarybchik/*-
2283514Sarybchik * Copyright (c) 2012-2015 Solarflare Communications Inc.
3283514Sarybchik * All rights reserved.
4283514Sarybchik *
5283514Sarybchik * Redistribution and use in source and binary forms, with or without
6283514Sarybchik * modification, are permitted provided that the following conditions are met:
7283514Sarybchik *
8283514Sarybchik * 1. Redistributions of source code must retain the above copyright notice,
9283514Sarybchik *    this list of conditions and the following disclaimer.
10283514Sarybchik * 2. Redistributions in binary form must reproduce the above copyright notice,
11283514Sarybchik *    this list of conditions and the following disclaimer in the documentation
12283514Sarybchik *    and/or other materials provided with the distribution.
13283514Sarybchik *
14283514Sarybchik * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15283514Sarybchik * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16283514Sarybchik * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17283514Sarybchik * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18283514Sarybchik * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19283514Sarybchik * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20283514Sarybchik * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21283514Sarybchik * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22283514Sarybchik * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23283514Sarybchik * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24283514Sarybchik * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25283514Sarybchik *
26283514Sarybchik * The views and conclusions contained in the software and documentation are
27283514Sarybchik * those of the authors and should not be interpreted as representing official
28283514Sarybchik * policies, either expressed or implied, of the FreeBSD Project.
29283514Sarybchik */
30283514Sarybchik
31283514Sarybchik#include <sys/cdefs.h>
32283514Sarybchik__FBSDID("$FreeBSD: releng/10.2/sys/dev/sfxge/common/hunt_tx.c 284555 2015-06-18 15:46:39Z arybchik $");
33283514Sarybchik
34283514Sarybchik#include "efsys.h"
35283514Sarybchik#include "efx.h"
36283514Sarybchik#include "efx_impl.h"
37283514Sarybchik
38283514Sarybchik
39283514Sarybchik#if EFSYS_OPT_HUNTINGTON
40283514Sarybchik
41283514Sarybchik#if EFSYS_OPT_QSTATS
42283514Sarybchik#define	EFX_TX_QSTAT_INCR(_etp, _stat)					\
43283514Sarybchik	do {								\
44283514Sarybchik		(_etp)->et_stat[_stat]++;				\
45283514Sarybchik	_NOTE(CONSTANTCONDITION)					\
46283514Sarybchik	} while (B_FALSE)
47283514Sarybchik#else
48283514Sarybchik#define	EFX_TX_QSTAT_INCR(_etp, _stat)
49283514Sarybchik#endif
50283514Sarybchik
51283514Sarybchikstatic	__checkReturn	int
52283514Sarybchikefx_mcdi_init_txq(
53283514Sarybchik	__in		efx_nic_t *enp,
54283514Sarybchik	__in		uint32_t size,
55283514Sarybchik	__in		uint32_t target_evq,
56283514Sarybchik	__in		uint32_t label,
57283514Sarybchik	__in		uint32_t instance,
58283514Sarybchik	__in		uint16_t flags,
59283514Sarybchik	__in		efsys_mem_t *esmp)
60283514Sarybchik{
61283514Sarybchik	efx_mcdi_req_t req;
62283514Sarybchik	uint8_t payload[MAX(MC_CMD_INIT_TXQ_IN_LEN(EFX_TXQ_MAX_BUFS),
63283514Sarybchik			    MC_CMD_INIT_TXQ_OUT_LEN)];
64283514Sarybchik	efx_qword_t *dma_addr;
65283514Sarybchik	uint64_t addr;
66283514Sarybchik	int npages;
67283514Sarybchik	int i;
68283514Sarybchik	int rc;
69283514Sarybchik
70283514Sarybchik	EFSYS_ASSERT(EFX_TXQ_MAX_BUFS >=
71283514Sarybchik	    EFX_TXQ_NBUFS(EFX_TXQ_MAXNDESCS(&enp->en_nic_cfg)));
72283514Sarybchik
73283514Sarybchik	npages = EFX_TXQ_NBUFS(size);
74283514Sarybchik	if (npages > MC_CMD_INIT_TXQ_IN_DMA_ADDR_MAXNUM) {
75283514Sarybchik		rc = EINVAL;
76283514Sarybchik		goto fail1;
77283514Sarybchik	}
78283514Sarybchik
79283514Sarybchik	(void) memset(payload, 0, sizeof (payload));
80283514Sarybchik	req.emr_cmd = MC_CMD_INIT_TXQ;
81283514Sarybchik	req.emr_in_buf = payload;
82283514Sarybchik	req.emr_in_length = MC_CMD_INIT_TXQ_IN_LEN(npages);
83283514Sarybchik	req.emr_out_buf = payload;
84283514Sarybchik	req.emr_out_length = MC_CMD_INIT_TXQ_OUT_LEN;
85283514Sarybchik
86283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_SIZE, size);
87283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_TARGET_EVQ, target_evq);
88283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_LABEL, label);
89283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_INSTANCE, instance);
90283514Sarybchik
91283514Sarybchik	MCDI_IN_POPULATE_DWORD_6(req, INIT_TXQ_IN_FLAGS,
92283514Sarybchik	    INIT_TXQ_IN_FLAG_BUFF_MODE, 0,
93283514Sarybchik	    INIT_TXQ_IN_FLAG_IP_CSUM_DIS, (flags & EFX_CKSUM_IPV4) ? 0 : 1,
94283514Sarybchik	    INIT_TXQ_IN_FLAG_TCP_CSUM_DIS, (flags & EFX_CKSUM_TCPUDP) ? 0 : 1,
95283514Sarybchik	    INIT_TXQ_IN_FLAG_TCP_UDP_ONLY, 0,
96283514Sarybchik	    INIT_TXQ_IN_CRC_MODE, 0,
97283514Sarybchik	    INIT_TXQ_IN_FLAG_TIMESTAMP, 0);
98283514Sarybchik
99283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_OWNER_ID, 0);
100283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_PORT_ID, EVB_PORT_ID_ASSIGNED);
101283514Sarybchik
102283514Sarybchik	dma_addr = MCDI_IN2(req, efx_qword_t, INIT_TXQ_IN_DMA_ADDR);
103283514Sarybchik	addr = EFSYS_MEM_ADDR(esmp);
104283514Sarybchik
105283514Sarybchik	for (i = 0; i < npages; i++) {
106283514Sarybchik		EFX_POPULATE_QWORD_2(*dma_addr,
107283514Sarybchik		    EFX_DWORD_1, (uint32_t)(addr >> 32),
108283514Sarybchik		    EFX_DWORD_0, (uint32_t)(addr & 0xffffffff));
109283514Sarybchik
110283514Sarybchik		dma_addr++;
111283514Sarybchik		addr += EFX_BUF_SIZE;
112283514Sarybchik	}
113283514Sarybchik
114283514Sarybchik	efx_mcdi_execute(enp, &req);
115283514Sarybchik
116283514Sarybchik	if (req.emr_rc != 0) {
117283514Sarybchik		rc = req.emr_rc;
118283514Sarybchik		goto fail2;
119283514Sarybchik	}
120283514Sarybchik
121283514Sarybchik	return (0);
122283514Sarybchik
123283514Sarybchikfail2:
124283514Sarybchik	EFSYS_PROBE(fail2);
125283514Sarybchikfail1:
126283514Sarybchik	EFSYS_PROBE1(fail1, int, rc);
127283514Sarybchik
128283514Sarybchik	return (rc);
129283514Sarybchik}
130283514Sarybchik
131283514Sarybchikstatic	__checkReturn	int
132283514Sarybchikefx_mcdi_fini_txq(
133283514Sarybchik	__in		efx_nic_t *enp,
134283514Sarybchik	__in		uint32_t instance)
135283514Sarybchik{
136283514Sarybchik	efx_mcdi_req_t req;
137283514Sarybchik	uint8_t payload[MAX(MC_CMD_FINI_TXQ_IN_LEN,
138283514Sarybchik			    MC_CMD_FINI_TXQ_OUT_LEN)];
139283514Sarybchik	int rc;
140283514Sarybchik
141283514Sarybchik	(void) memset(payload, 0, sizeof (payload));
142283514Sarybchik	req.emr_cmd = MC_CMD_FINI_TXQ;
143283514Sarybchik	req.emr_in_buf = payload;
144283514Sarybchik	req.emr_in_length = MC_CMD_FINI_TXQ_IN_LEN;
145283514Sarybchik	req.emr_out_buf = payload;
146283514Sarybchik	req.emr_out_length = MC_CMD_FINI_TXQ_OUT_LEN;
147283514Sarybchik
148283514Sarybchik	MCDI_IN_SET_DWORD(req, FINI_TXQ_IN_INSTANCE, instance);
149283514Sarybchik
150283514Sarybchik	efx_mcdi_execute(enp, &req);
151283514Sarybchik
152283514Sarybchik	if ((req.emr_rc != 0) && (req.emr_rc != MC_CMD_ERR_EALREADY)) {
153283514Sarybchik		rc = req.emr_rc;
154283514Sarybchik		goto fail1;
155283514Sarybchik	}
156283514Sarybchik
157283514Sarybchik	return (0);
158283514Sarybchik
159283514Sarybchikfail1:
160283514Sarybchik	EFSYS_PROBE1(fail1, int, rc);
161283514Sarybchik
162283514Sarybchik	return (rc);
163283514Sarybchik}
164283514Sarybchik
165283514Sarybchik	__checkReturn	int
166283514Sarybchikhunt_tx_init(
167283514Sarybchik	__in		efx_nic_t *enp)
168283514Sarybchik{
169283514Sarybchik	_NOTE(ARGUNUSED(enp))
170283514Sarybchik	return (0);
171283514Sarybchik}
172283514Sarybchik
173283514Sarybchik			void
174283514Sarybchikhunt_tx_fini(
175283514Sarybchik	__in		efx_nic_t *enp)
176283514Sarybchik{
177283514Sarybchik	_NOTE(ARGUNUSED(enp))
178283514Sarybchik}
179283514Sarybchik
180283514Sarybchik	__checkReturn	int
181283514Sarybchikhunt_tx_qcreate(
182283514Sarybchik	__in		efx_nic_t *enp,
183283514Sarybchik	__in		unsigned int index,
184283514Sarybchik	__in		unsigned int label,
185283514Sarybchik	__in		efsys_mem_t *esmp,
186283514Sarybchik	__in		size_t n,
187283514Sarybchik	__in		uint32_t id,
188283514Sarybchik	__in		uint16_t flags,
189283514Sarybchik	__in		efx_evq_t *eep,
190283514Sarybchik	__in		efx_txq_t *etp,
191283514Sarybchik	__out		unsigned int *addedp)
192283514Sarybchik{
193283514Sarybchik	efx_qword_t desc;
194283514Sarybchik	int rc;
195283514Sarybchik
196283514Sarybchik
197283514Sarybchik	if ((rc = efx_mcdi_init_txq(enp, n, eep->ee_index, label, index, flags,
198283514Sarybchik	    esmp)) != 0)
199283514Sarybchik		goto fail1;
200283514Sarybchik
201283514Sarybchik	/*
202283514Sarybchik	 * A previous user of this TX queue may have written a descriptor to the
203283514Sarybchik	 * TX push collector, but not pushed the doorbell (e.g. after a crash).
204283514Sarybchik	 * The next doorbell write would then push the stale descriptor.
205283514Sarybchik	 *
206283514Sarybchik	 * Ensure the (per network port) TX push collector is cleared by writing
207283514Sarybchik	 * a no-op TX option descriptor. See bug29981 for details.
208283514Sarybchik	 */
209283514Sarybchik	*addedp = 1;
210283514Sarybchik	EFX_POPULATE_QWORD_4(desc,
211283514Sarybchik	    ESF_DZ_TX_DESC_IS_OPT, 1,
212283514Sarybchik	    ESF_DZ_TX_OPTION_TYPE, ESE_DZ_TX_OPTION_DESC_CRC_CSUM,
213283514Sarybchik	    ESF_DZ_TX_OPTION_UDP_TCP_CSUM, (flags & EFX_CKSUM_TCPUDP) ? 1 : 0,
214283514Sarybchik	    ESF_DZ_TX_OPTION_IP_CSUM, (flags & EFX_CKSUM_IPV4) ? 1 : 0);
215283514Sarybchik
216283514Sarybchik	EFSYS_MEM_WRITEQ(etp->et_esmp, 0, &desc);
217283514Sarybchik	hunt_tx_qpush(etp, *addedp, 0);
218283514Sarybchik
219283514Sarybchik	return (0);
220283514Sarybchik
221283514Sarybchikfail1:
222283514Sarybchik	EFSYS_PROBE1(fail1, int, rc);
223283514Sarybchik
224283514Sarybchik	return (rc);
225283514Sarybchik}
226283514Sarybchik
227283514Sarybchik		void
228283514Sarybchikhunt_tx_qdestroy(
229283514Sarybchik	__in	efx_txq_t *etp)
230283514Sarybchik{
231283514Sarybchik	/* FIXME */
232283514Sarybchik	_NOTE(ARGUNUSED(etp))
233283514Sarybchik	/* FIXME */
234283514Sarybchik}
235283514Sarybchik
236283514Sarybchik	__checkReturn	int
237283514Sarybchikhunt_tx_qpio_enable(
238283514Sarybchik	__in		efx_txq_t *etp)
239283514Sarybchik{
240283514Sarybchik	efx_nic_t *enp = etp->et_enp;
241283514Sarybchik	efx_piobuf_handle_t handle;
242283514Sarybchik	int rc;
243283514Sarybchik
244283514Sarybchik	if (etp->et_pio_size != 0) {
245283514Sarybchik		rc = EALREADY;
246283514Sarybchik		goto fail1;
247283514Sarybchik	}
248283514Sarybchik
249283514Sarybchik	/* Sub-allocate a PIO block from a piobuf */
250283514Sarybchik	if ((rc = hunt_nic_pio_alloc(enp,
251283514Sarybchik		    &etp->et_pio_bufnum,
252283514Sarybchik		    &handle,
253283514Sarybchik		    &etp->et_pio_blknum,
254283514Sarybchik		    &etp->et_pio_offset,
255283514Sarybchik		    &etp->et_pio_size)) != 0) {
256283514Sarybchik		goto fail2;
257283514Sarybchik	}
258283514Sarybchik	EFSYS_ASSERT3U(etp->et_pio_size, !=, 0);
259283514Sarybchik
260283514Sarybchik	/* Link the piobuf to this TXQ */
261283514Sarybchik	if ((rc = hunt_nic_pio_link(enp, etp->et_index, handle)) != 0) {
262283514Sarybchik		goto fail3;
263283514Sarybchik	}
264283514Sarybchik
265283514Sarybchik	/*
266283514Sarybchik	 * et_pio_offset is the offset of the sub-allocated block within the
267283514Sarybchik	 * hardware PIO buffer. It is used as the buffer address in the PIO
268283514Sarybchik	 * option descriptor.
269283514Sarybchik	 *
270283514Sarybchik	 * et_pio_write_offset is the offset of the sub-allocated block from the
271283514Sarybchik	 * start of the write-combined memory mapping, and is used for writing
272283514Sarybchik	 * data into the PIO buffer.
273283514Sarybchik	 */
274283514Sarybchik	etp->et_pio_write_offset =
275283514Sarybchik	    (etp->et_pio_bufnum * ER_DZ_TX_PIOBUF_STEP) +
276283514Sarybchik	    ER_DZ_TX_PIOBUF_OFST + etp->et_pio_offset;
277283514Sarybchik
278283514Sarybchik	return (0);
279283514Sarybchik
280283514Sarybchikfail3:
281283514Sarybchik	EFSYS_PROBE(fail3);
282283514Sarybchik	hunt_nic_pio_free(enp, etp->et_pio_bufnum, etp->et_pio_blknum);
283283514Sarybchik	etp->et_pio_size = 0;
284283514Sarybchikfail2:
285283514Sarybchik	EFSYS_PROBE(fail2);
286283514Sarybchikfail1:
287283514Sarybchik	EFSYS_PROBE1(fail1, int, rc);
288283514Sarybchik
289283514Sarybchik	return (rc);
290283514Sarybchik}
291283514Sarybchik
292283514Sarybchik			void
293283514Sarybchikhunt_tx_qpio_disable(
294283514Sarybchik	__in		efx_txq_t *etp)
295283514Sarybchik{
296283514Sarybchik	efx_nic_t *enp = etp->et_enp;
297283514Sarybchik
298283514Sarybchik	if (etp->et_pio_size != 0) {
299283514Sarybchik		/* Unlink the piobuf from this TXQ */
300283514Sarybchik		hunt_nic_pio_unlink(enp, etp->et_index);
301283514Sarybchik
302283514Sarybchik		/* Free the sub-allocated PIO block */
303283514Sarybchik		hunt_nic_pio_free(enp, etp->et_pio_bufnum, etp->et_pio_blknum);
304283514Sarybchik		etp->et_pio_size = 0;
305283514Sarybchik		etp->et_pio_write_offset = 0;
306283514Sarybchik	}
307283514Sarybchik}
308283514Sarybchik
309283514Sarybchik	__checkReturn	int
310283514Sarybchikhunt_tx_qpio_write(
311283514Sarybchik	__in			efx_txq_t *etp,
312283514Sarybchik	__in_ecount(length)	uint8_t *buffer,
313283514Sarybchik	__in			size_t length,
314283514Sarybchik	__in			size_t offset)
315283514Sarybchik{
316283514Sarybchik	efx_nic_t *enp = etp->et_enp;
317283514Sarybchik	efsys_bar_t *esbp = enp->en_esbp;
318283514Sarybchik	uint32_t write_offset;
319283514Sarybchik	uint32_t write_offset_limit;
320283514Sarybchik	efx_qword_t *eqp;
321283514Sarybchik	int rc;
322283514Sarybchik
323283514Sarybchik	EFSYS_ASSERT(length % sizeof (efx_qword_t) == 0);
324283514Sarybchik
325283514Sarybchik	if (etp->et_pio_size == 0) {
326283514Sarybchik		rc = ENOENT;
327283514Sarybchik		goto fail1;
328283514Sarybchik	}
329283514Sarybchik	if (offset + length > etp->et_pio_size)	{
330283514Sarybchik		rc = ENOSPC;
331283514Sarybchik		goto fail2;
332283514Sarybchik	}
333283514Sarybchik
334283514Sarybchik	/*
335283514Sarybchik	 * Writes to PIO buffers must be 64 bit aligned, and multiples of
336283514Sarybchik	 * 64 bits.
337283514Sarybchik	 */
338283514Sarybchik	write_offset = etp->et_pio_write_offset + offset;
339283514Sarybchik	write_offset_limit = write_offset + length;
340283514Sarybchik	eqp = (efx_qword_t *)buffer;
341283514Sarybchik	while (write_offset < write_offset_limit) {
342283514Sarybchik		EFSYS_BAR_WC_WRITEQ(esbp, write_offset, eqp);
343283514Sarybchik		eqp++;
344283514Sarybchik		write_offset += sizeof (efx_qword_t);
345283514Sarybchik	}
346283514Sarybchik
347283514Sarybchik	return (0);
348283514Sarybchik
349283514Sarybchikfail2:
350283514Sarybchik	EFSYS_PROBE(fail2);
351283514Sarybchikfail1:
352283514Sarybchik	EFSYS_PROBE1(fail1, int, rc);
353283514Sarybchik
354283514Sarybchik	return (rc);
355283514Sarybchik}
356283514Sarybchik
357283514Sarybchik	__checkReturn	int
358283514Sarybchikhunt_tx_qpio_post(
359283514Sarybchik	__in			efx_txq_t *etp,
360283514Sarybchik	__in			size_t pkt_length,
361283514Sarybchik	__in			unsigned int completed,
362283514Sarybchik	__inout			unsigned int *addedp)
363283514Sarybchik{
364283514Sarybchik	efx_qword_t pio_desc;
365283514Sarybchik	unsigned int id;
366283514Sarybchik	size_t offset;
367283514Sarybchik	unsigned int added = *addedp;
368283514Sarybchik	int rc;
369283514Sarybchik
370283514Sarybchik
371283514Sarybchik	if (added - completed + 1 > EFX_TXQ_LIMIT(etp->et_mask + 1)) {
372283514Sarybchik		rc = ENOSPC;
373283514Sarybchik		goto fail1;
374283514Sarybchik	}
375283514Sarybchik
376283514Sarybchik	if (etp->et_pio_size == 0) {
377283514Sarybchik		rc = ENOENT;
378283514Sarybchik		goto fail2;
379283514Sarybchik	}
380283514Sarybchik
381283514Sarybchik	id = added++ & etp->et_mask;
382283514Sarybchik	offset = id * sizeof (efx_qword_t);
383283514Sarybchik
384283514Sarybchik	EFSYS_PROBE4(tx_pio_post, unsigned int, etp->et_index,
385283514Sarybchik		    unsigned int, id, uint32_t, etp->et_pio_offset,
386283514Sarybchik		    size_t, pkt_length);
387283514Sarybchik
388283514Sarybchik	EFX_POPULATE_QWORD_5(pio_desc,
389283514Sarybchik			ESF_DZ_TX_DESC_IS_OPT, 1,
390283514Sarybchik			ESF_DZ_TX_OPTION_TYPE, 1,
391283514Sarybchik			ESF_DZ_TX_PIO_CONT, 0,
392283514Sarybchik			ESF_DZ_TX_PIO_BYTE_CNT, pkt_length,
393283514Sarybchik			ESF_DZ_TX_PIO_BUF_ADDR, etp->et_pio_offset);
394283514Sarybchik
395283514Sarybchik	EFSYS_MEM_WRITEQ(etp->et_esmp, offset, &pio_desc);
396283514Sarybchik
397283514Sarybchik	EFX_TX_QSTAT_INCR(etp, TX_POST_PIO);
398283514Sarybchik
399283514Sarybchik	*addedp = added;
400283514Sarybchik	return (0);
401283514Sarybchik
402283514Sarybchikfail2:
403283514Sarybchik	EFSYS_PROBE(fail2);
404283514Sarybchikfail1:
405283514Sarybchik	EFSYS_PROBE1(fail1, int, rc);
406283514Sarybchik
407283514Sarybchik	return (rc);
408283514Sarybchik}
409283514Sarybchik
410283514Sarybchik	__checkReturn	int
411283514Sarybchikhunt_tx_qpost(
412283514Sarybchik	__in		efx_txq_t *etp,
413283514Sarybchik	__in_ecount(n)	efx_buffer_t *eb,
414283514Sarybchik	__in		unsigned int n,
415283514Sarybchik	__in		unsigned int completed,
416283514Sarybchik	__inout		unsigned int *addedp)
417283514Sarybchik{
418283514Sarybchik	unsigned int added = *addedp;
419283514Sarybchik	unsigned int i;
420283514Sarybchik	int rc;
421283514Sarybchik
422283514Sarybchik	if (added - completed + n > EFX_TXQ_LIMIT(etp->et_mask + 1)) {
423283514Sarybchik		rc = ENOSPC;
424283514Sarybchik		goto fail1;
425283514Sarybchik	}
426283514Sarybchik
427283514Sarybchik	for (i = 0; i < n; i++) {
428283514Sarybchik		efx_buffer_t *ebp = &eb[i];
429283514Sarybchik		efsys_dma_addr_t addr = ebp->eb_addr;
430283514Sarybchik		size_t size = ebp->eb_size;
431283514Sarybchik		boolean_t eop = ebp->eb_eop;
432283514Sarybchik		unsigned int id;
433283514Sarybchik		size_t offset;
434283514Sarybchik		efx_qword_t qword;
435283514Sarybchik
436283514Sarybchik		/* Fragments must not span 4k boundaries. */
437283514Sarybchik		EFSYS_ASSERT(P2ROUNDUP(addr + 1, 4096) >= (addr + size));
438283514Sarybchik
439283514Sarybchik		id = added++ & etp->et_mask;
440283514Sarybchik		offset = id * sizeof (efx_qword_t);
441283514Sarybchik
442283514Sarybchik		EFSYS_PROBE5(tx_post, unsigned int, etp->et_index,
443283514Sarybchik		    unsigned int, id, efsys_dma_addr_t, addr,
444283514Sarybchik		    size_t, size, boolean_t, eop);
445283514Sarybchik
446283514Sarybchik		EFX_POPULATE_QWORD_5(qword,
447283514Sarybchik		    ESF_DZ_TX_KER_TYPE, 0,
448283514Sarybchik		    ESF_DZ_TX_KER_CONT, (eop) ? 0 : 1,
449283514Sarybchik		    ESF_DZ_TX_KER_BYTE_CNT, (uint32_t)(size),
450283514Sarybchik		    ESF_DZ_TX_KER_BUF_ADDR_DW0, (uint32_t)(addr & 0xffffffff),
451283514Sarybchik		    ESF_DZ_TX_KER_BUF_ADDR_DW1, (uint32_t)(addr >> 32));
452283514Sarybchik
453283514Sarybchik		EFSYS_MEM_WRITEQ(etp->et_esmp, offset, &qword);
454283514Sarybchik	}
455283514Sarybchik
456283514Sarybchik	EFX_TX_QSTAT_INCR(etp, TX_POST);
457283514Sarybchik
458283514Sarybchik	*addedp = added;
459283514Sarybchik	return (0);
460283514Sarybchik
461283514Sarybchikfail1:
462283514Sarybchik	EFSYS_PROBE1(fail1, int, rc);
463283514Sarybchik
464283514Sarybchik	return (rc);
465283514Sarybchik}
466283514Sarybchik
467283514Sarybchik/*
468283514Sarybchik * This improves performance by pushing a TX descriptor at the same time as the
469283514Sarybchik * doorbell. The descriptor must be added to the TXQ, so that can be used if the
470283514Sarybchik * hardware decides not to use the pushed descriptor.
471283514Sarybchik */
472283514Sarybchik			void
473283514Sarybchikhunt_tx_qpush(
474283514Sarybchik	__in		efx_txq_t *etp,
475283514Sarybchik	__in		unsigned int added,
476283514Sarybchik	__in		unsigned int pushed)
477283514Sarybchik{
478283514Sarybchik	efx_nic_t *enp = etp->et_enp;
479283514Sarybchik	unsigned int wptr;
480283514Sarybchik	unsigned int id;
481283514Sarybchik	size_t offset;
482283514Sarybchik	efx_qword_t desc;
483283514Sarybchik	efx_oword_t oword;
484283514Sarybchik
485283514Sarybchik	wptr = added & etp->et_mask;
486283514Sarybchik	id = pushed & etp->et_mask;
487283514Sarybchik	offset = id * sizeof (efx_qword_t);
488283514Sarybchik
489283514Sarybchik	EFSYS_MEM_READQ(etp->et_esmp, offset, &desc);
490283514Sarybchik	EFX_POPULATE_OWORD_3(oword,
491283514Sarybchik	    ERF_DZ_TX_DESC_WPTR, wptr,
492283514Sarybchik	    ERF_DZ_TX_DESC_HWORD, EFX_QWORD_FIELD(desc, EFX_DWORD_1),
493283514Sarybchik	    ERF_DZ_TX_DESC_LWORD, EFX_QWORD_FIELD(desc, EFX_DWORD_0));
494283514Sarybchik
495283514Sarybchik	/* Guarantee ordering of memory (descriptors) and PIO (doorbell) */
496283514Sarybchik	EFX_DMA_SYNC_QUEUE_FOR_DEVICE(etp->et_esmp, etp->et_mask + 1, wptr, id);
497283514Sarybchik	EFSYS_PIO_WRITE_BARRIER();
498283514Sarybchik	EFX_BAR_TBL_DOORBELL_WRITEO(enp, ER_DZ_TX_DESC_UPD_REG, etp->et_index,
499283514Sarybchik				    &oword);
500283514Sarybchik}
501283514Sarybchik
502283514Sarybchik	__checkReturn	int
503283514Sarybchikhunt_tx_qdesc_post(
504283514Sarybchik	__in		efx_txq_t *etp,
505283514Sarybchik	__in_ecount(n)	efx_desc_t *ed,
506283514Sarybchik	__in		unsigned int n,
507283514Sarybchik	__in		unsigned int completed,
508283514Sarybchik	__inout		unsigned int *addedp)
509283514Sarybchik{
510283514Sarybchik	unsigned int added = *addedp;
511283514Sarybchik	unsigned int i;
512283514Sarybchik	int rc;
513283514Sarybchik
514283514Sarybchik	if (added - completed + n > EFX_TXQ_LIMIT(etp->et_mask + 1)) {
515283514Sarybchik		rc = ENOSPC;
516283514Sarybchik		goto fail1;
517283514Sarybchik	}
518283514Sarybchik
519283514Sarybchik	for (i = 0; i < n; i++) {
520283514Sarybchik		efx_desc_t *edp = &ed[i];
521283514Sarybchik		unsigned int id;
522283514Sarybchik		size_t offset;
523283514Sarybchik
524283514Sarybchik		id = added++ & etp->et_mask;
525283514Sarybchik		offset = id * sizeof (efx_desc_t);
526283514Sarybchik
527283514Sarybchik		EFSYS_MEM_WRITEQ(etp->et_esmp, offset, &edp->ed_eq);
528283514Sarybchik	}
529283514Sarybchik
530283514Sarybchik	EFSYS_PROBE3(tx_desc_post, unsigned int, etp->et_index,
531283514Sarybchik		    unsigned int, added, unsigned int, n);
532283514Sarybchik
533283514Sarybchik	EFX_TX_QSTAT_INCR(etp, TX_POST);
534283514Sarybchik
535283514Sarybchik	*addedp = added;
536283514Sarybchik	return (0);
537283514Sarybchik
538283514Sarybchikfail1:
539283514Sarybchik	EFSYS_PROBE1(fail1, int, rc);
540283514Sarybchik
541283514Sarybchik	return (rc);
542283514Sarybchik}
543283514Sarybchik
544283514Sarybchik	void
545283514Sarybchikhunt_tx_qdesc_dma_create(
546283514Sarybchik	__in	efx_txq_t *etp,
547283514Sarybchik	__in	efsys_dma_addr_t addr,
548283514Sarybchik	__in	size_t size,
549283514Sarybchik	__in	boolean_t eop,
550283514Sarybchik	__out	efx_desc_t *edp)
551283514Sarybchik{
552283514Sarybchik	/* Fragments must not span 4k boundaries. */
553283514Sarybchik	EFSYS_ASSERT(P2ROUNDUP(addr + 1, 4096) >= addr + size);
554283514Sarybchik
555283514Sarybchik	EFSYS_PROBE4(tx_desc_dma_create, unsigned int, etp->et_index,
556283514Sarybchik		    efsys_dma_addr_t, addr,
557283514Sarybchik		    size_t, size, boolean_t, eop);
558283514Sarybchik
559283514Sarybchik	EFX_POPULATE_QWORD_5(edp->ed_eq,
560283514Sarybchik		    ESF_DZ_TX_KER_TYPE, 0,
561283514Sarybchik		    ESF_DZ_TX_KER_CONT, (eop) ? 0 : 1,
562283514Sarybchik		    ESF_DZ_TX_KER_BYTE_CNT, (uint32_t)(size),
563283514Sarybchik		    ESF_DZ_TX_KER_BUF_ADDR_DW0, (uint32_t)(addr & 0xffffffff),
564283514Sarybchik		    ESF_DZ_TX_KER_BUF_ADDR_DW1, (uint32_t)(addr >> 32));
565283514Sarybchik}
566283514Sarybchik
567283514Sarybchik	void
568283514Sarybchikhunt_tx_qdesc_tso_create(
569283514Sarybchik	__in	efx_txq_t *etp,
570283514Sarybchik	__in	uint16_t ipv4_id,
571283514Sarybchik	__in	uint32_t tcp_seq,
572283514Sarybchik	__in	uint8_t  tcp_flags,
573283514Sarybchik	__out	efx_desc_t *edp)
574283514Sarybchik{
575283514Sarybchik	EFSYS_PROBE4(tx_desc_tso_create, unsigned int, etp->et_index,
576283514Sarybchik		    uint16_t, ipv4_id, uint32_t, tcp_seq,
577283514Sarybchik		    uint8_t, tcp_flags);
578283514Sarybchik
579283514Sarybchik	EFX_POPULATE_QWORD_5(edp->ed_eq,
580283514Sarybchik			    ESF_DZ_TX_DESC_IS_OPT, 1,
581283514Sarybchik			    ESF_DZ_TX_OPTION_TYPE,
582283514Sarybchik			    ESE_DZ_TX_OPTION_DESC_TSO,
583283514Sarybchik			    ESF_DZ_TX_TSO_TCP_FLAGS, tcp_flags,
584283514Sarybchik			    ESF_DZ_TX_TSO_IP_ID, ipv4_id,
585283514Sarybchik			    ESF_DZ_TX_TSO_TCP_SEQNO, tcp_seq);
586283514Sarybchik}
587283514Sarybchik
588283514Sarybchik	void
589283514Sarybchikhunt_tx_qdesc_vlantci_create(
590283514Sarybchik	__in	efx_txq_t *etp,
591283514Sarybchik	__in	uint16_t  tci,
592283514Sarybchik	__out	efx_desc_t *edp)
593283514Sarybchik{
594283514Sarybchik	EFSYS_PROBE2(tx_desc_vlantci_create, unsigned int, etp->et_index,
595283514Sarybchik		    uint16_t, tci);
596283514Sarybchik
597283514Sarybchik	EFX_POPULATE_QWORD_4(edp->ed_eq,
598283514Sarybchik			    ESF_DZ_TX_DESC_IS_OPT, 1,
599283514Sarybchik			    ESF_DZ_TX_OPTION_TYPE,
600283514Sarybchik			    ESE_DZ_TX_OPTION_DESC_VLAN,
601283514Sarybchik			    ESF_DZ_TX_VLAN_OP, tci ? 1 : 0,
602283514Sarybchik			    ESF_DZ_TX_VLAN_TAG1, tci);
603283514Sarybchik}
604283514Sarybchik
605283514Sarybchik
606283514Sarybchik	__checkReturn	int
607283514Sarybchikhunt_tx_qpace(
608283514Sarybchik	__in		efx_txq_t *etp,
609283514Sarybchik	__in		unsigned int ns)
610283514Sarybchik{
611283514Sarybchik	int rc;
612283514Sarybchik
613283514Sarybchik	/* FIXME */
614283514Sarybchik	_NOTE(ARGUNUSED(etp, ns))
615283514Sarybchik	if (B_FALSE) {
616283514Sarybchik		rc = ENOTSUP;
617283514Sarybchik		goto fail1;
618283514Sarybchik	}
619283514Sarybchik	/* FIXME */
620283514Sarybchik
621283514Sarybchik	return (0);
622283514Sarybchik
623283514Sarybchikfail1:
624283514Sarybchik	EFSYS_PROBE1(fail1, int, rc);
625283514Sarybchik
626283514Sarybchik	return (rc);
627283514Sarybchik}
628283514Sarybchik
629283514Sarybchik	__checkReturn	int
630283514Sarybchikhunt_tx_qflush(
631283514Sarybchik	__in		efx_txq_t *etp)
632283514Sarybchik{
633283514Sarybchik	efx_nic_t *enp = etp->et_enp;
634283514Sarybchik	int rc;
635283514Sarybchik
636283514Sarybchik	if ((rc = efx_mcdi_fini_txq(enp, etp->et_index)) != 0)
637283514Sarybchik		goto fail1;
638283514Sarybchik
639283514Sarybchik	return (0);
640283514Sarybchik
641283514Sarybchikfail1:
642283514Sarybchik	EFSYS_PROBE1(fail1, int, rc);
643283514Sarybchik
644283514Sarybchik	return (rc);
645283514Sarybchik}
646283514Sarybchik
647283514Sarybchik			void
648283514Sarybchikhunt_tx_qenable(
649283514Sarybchik	__in		efx_txq_t *etp)
650283514Sarybchik{
651283514Sarybchik	/* FIXME */
652283514Sarybchik	_NOTE(ARGUNUSED(etp))
653283514Sarybchik	/* FIXME */
654283514Sarybchik}
655283514Sarybchik
656283514Sarybchik#if EFSYS_OPT_QSTATS
657283514Sarybchik			void
658283514Sarybchikhunt_tx_qstats_update(
659283514Sarybchik	__in				efx_txq_t *etp,
660283514Sarybchik	__inout_ecount(TX_NQSTATS)	efsys_stat_t *stat)
661283514Sarybchik{
662283514Sarybchik	/*
663283514Sarybchik	 * TBD: Consider a common Siena/Huntington function.  The code is
664283514Sarybchik	 * essentially identical.
665283514Sarybchik	 */
666283514Sarybchik
667283514Sarybchik	unsigned int id;
668283514Sarybchik
669283514Sarybchik	for (id = 0; id < TX_NQSTATS; id++) {
670283514Sarybchik		efsys_stat_t *essp = &stat[id];
671283514Sarybchik
672283514Sarybchik		EFSYS_STAT_INCR(essp, etp->et_stat[id]);
673283514Sarybchik		etp->et_stat[id] = 0;
674283514Sarybchik	}
675283514Sarybchik}
676283514Sarybchik
677283514Sarybchik#endif /* EFSYS_OPT_QSTATS */
678283514Sarybchik
679283514Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */
680