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.3/sys/dev/sfxge/common/hunt_tx.c 294381 2016-01-20 07:51:23Z arybchik $");
33283514Sarybchik
34283514Sarybchik#include "efx.h"
35283514Sarybchik#include "efx_impl.h"
36283514Sarybchik
37283514Sarybchik
38283514Sarybchik#if EFSYS_OPT_HUNTINGTON
39283514Sarybchik
40283514Sarybchik#if EFSYS_OPT_QSTATS
41283514Sarybchik#define	EFX_TX_QSTAT_INCR(_etp, _stat)					\
42283514Sarybchik	do {								\
43283514Sarybchik		(_etp)->et_stat[_stat]++;				\
44283514Sarybchik	_NOTE(CONSTANTCONDITION)					\
45283514Sarybchik	} while (B_FALSE)
46283514Sarybchik#else
47283514Sarybchik#define	EFX_TX_QSTAT_INCR(_etp, _stat)
48283514Sarybchik#endif
49283514Sarybchik
50293927Sarybchikstatic	__checkReturn	efx_rc_t
51283514Sarybchikefx_mcdi_init_txq(
52283514Sarybchik	__in		efx_nic_t *enp,
53283514Sarybchik	__in		uint32_t size,
54283514Sarybchik	__in		uint32_t target_evq,
55283514Sarybchik	__in		uint32_t label,
56283514Sarybchik	__in		uint32_t instance,
57283514Sarybchik	__in		uint16_t flags,
58283514Sarybchik	__in		efsys_mem_t *esmp)
59283514Sarybchik{
60283514Sarybchik	efx_mcdi_req_t req;
61283514Sarybchik	uint8_t payload[MAX(MC_CMD_INIT_TXQ_IN_LEN(EFX_TXQ_MAX_BUFS),
62283514Sarybchik			    MC_CMD_INIT_TXQ_OUT_LEN)];
63283514Sarybchik	efx_qword_t *dma_addr;
64283514Sarybchik	uint64_t addr;
65283514Sarybchik	int npages;
66283514Sarybchik	int i;
67293927Sarybchik	efx_rc_t rc;
68283514Sarybchik
69283514Sarybchik	EFSYS_ASSERT(EFX_TXQ_MAX_BUFS >=
70283514Sarybchik	    EFX_TXQ_NBUFS(EFX_TXQ_MAXNDESCS(&enp->en_nic_cfg)));
71283514Sarybchik
72283514Sarybchik	npages = EFX_TXQ_NBUFS(size);
73283514Sarybchik	if (npages > MC_CMD_INIT_TXQ_IN_DMA_ADDR_MAXNUM) {
74283514Sarybchik		rc = EINVAL;
75283514Sarybchik		goto fail1;
76283514Sarybchik	}
77283514Sarybchik
78283514Sarybchik	(void) memset(payload, 0, sizeof (payload));
79283514Sarybchik	req.emr_cmd = MC_CMD_INIT_TXQ;
80283514Sarybchik	req.emr_in_buf = payload;
81283514Sarybchik	req.emr_in_length = MC_CMD_INIT_TXQ_IN_LEN(npages);
82283514Sarybchik	req.emr_out_buf = payload;
83283514Sarybchik	req.emr_out_length = MC_CMD_INIT_TXQ_OUT_LEN;
84283514Sarybchik
85283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_SIZE, size);
86283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_TARGET_EVQ, target_evq);
87283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_LABEL, label);
88283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_INSTANCE, instance);
89283514Sarybchik
90294381Sarybchik	MCDI_IN_POPULATE_DWORD_7(req, INIT_TXQ_IN_FLAGS,
91283514Sarybchik	    INIT_TXQ_IN_FLAG_BUFF_MODE, 0,
92293955Sarybchik	    INIT_TXQ_IN_FLAG_IP_CSUM_DIS,
93293955Sarybchik	    (flags & EFX_TXQ_CKSUM_IPV4) ? 0 : 1,
94293955Sarybchik	    INIT_TXQ_IN_FLAG_TCP_CSUM_DIS,
95293955Sarybchik	    (flags & EFX_TXQ_CKSUM_TCPUDP) ? 0 : 1,
96294381Sarybchik	    INIT_TXQ_EXT_IN_FLAG_TSOV2_EN, (flags & EFX_TXQ_FATSOV2) ? 1 : 0,
97283514Sarybchik	    INIT_TXQ_IN_FLAG_TCP_UDP_ONLY, 0,
98283514Sarybchik	    INIT_TXQ_IN_CRC_MODE, 0,
99283514Sarybchik	    INIT_TXQ_IN_FLAG_TIMESTAMP, 0);
100283514Sarybchik
101283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_OWNER_ID, 0);
102283514Sarybchik	MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_PORT_ID, EVB_PORT_ID_ASSIGNED);
103283514Sarybchik
104283514Sarybchik	dma_addr = MCDI_IN2(req, efx_qword_t, INIT_TXQ_IN_DMA_ADDR);
105283514Sarybchik	addr = EFSYS_MEM_ADDR(esmp);
106283514Sarybchik
107283514Sarybchik	for (i = 0; i < npages; i++) {
108283514Sarybchik		EFX_POPULATE_QWORD_2(*dma_addr,
109283514Sarybchik		    EFX_DWORD_1, (uint32_t)(addr >> 32),
110283514Sarybchik		    EFX_DWORD_0, (uint32_t)(addr & 0xffffffff));
111283514Sarybchik
112283514Sarybchik		dma_addr++;
113283514Sarybchik		addr += EFX_BUF_SIZE;
114283514Sarybchik	}
115283514Sarybchik
116283514Sarybchik	efx_mcdi_execute(enp, &req);
117283514Sarybchik
118283514Sarybchik	if (req.emr_rc != 0) {
119283514Sarybchik		rc = req.emr_rc;
120283514Sarybchik		goto fail2;
121283514Sarybchik	}
122283514Sarybchik
123283514Sarybchik	return (0);
124283514Sarybchik
125283514Sarybchikfail2:
126283514Sarybchik	EFSYS_PROBE(fail2);
127283514Sarybchikfail1:
128293927Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
129283514Sarybchik
130283514Sarybchik	return (rc);
131283514Sarybchik}
132283514Sarybchik
133293927Sarybchikstatic	__checkReturn	efx_rc_t
134283514Sarybchikefx_mcdi_fini_txq(
135283514Sarybchik	__in		efx_nic_t *enp,
136283514Sarybchik	__in		uint32_t instance)
137283514Sarybchik{
138283514Sarybchik	efx_mcdi_req_t req;
139283514Sarybchik	uint8_t payload[MAX(MC_CMD_FINI_TXQ_IN_LEN,
140283514Sarybchik			    MC_CMD_FINI_TXQ_OUT_LEN)];
141293927Sarybchik	efx_rc_t rc;
142283514Sarybchik
143283514Sarybchik	(void) memset(payload, 0, sizeof (payload));
144283514Sarybchik	req.emr_cmd = MC_CMD_FINI_TXQ;
145283514Sarybchik	req.emr_in_buf = payload;
146283514Sarybchik	req.emr_in_length = MC_CMD_FINI_TXQ_IN_LEN;
147283514Sarybchik	req.emr_out_buf = payload;
148283514Sarybchik	req.emr_out_length = MC_CMD_FINI_TXQ_OUT_LEN;
149283514Sarybchik
150283514Sarybchik	MCDI_IN_SET_DWORD(req, FINI_TXQ_IN_INSTANCE, instance);
151283514Sarybchik
152283514Sarybchik	efx_mcdi_execute(enp, &req);
153283514Sarybchik
154283514Sarybchik	if ((req.emr_rc != 0) && (req.emr_rc != MC_CMD_ERR_EALREADY)) {
155283514Sarybchik		rc = req.emr_rc;
156283514Sarybchik		goto fail1;
157283514Sarybchik	}
158283514Sarybchik
159283514Sarybchik	return (0);
160283514Sarybchik
161283514Sarybchikfail1:
162293927Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
163283514Sarybchik
164283514Sarybchik	return (rc);
165283514Sarybchik}
166283514Sarybchik
167293927Sarybchik	__checkReturn	efx_rc_t
168293987Sarybchikef10_tx_init(
169283514Sarybchik	__in		efx_nic_t *enp)
170283514Sarybchik{
171283514Sarybchik	_NOTE(ARGUNUSED(enp))
172283514Sarybchik	return (0);
173283514Sarybchik}
174283514Sarybchik
175283514Sarybchik			void
176293987Sarybchikef10_tx_fini(
177283514Sarybchik	__in		efx_nic_t *enp)
178283514Sarybchik{
179283514Sarybchik	_NOTE(ARGUNUSED(enp))
180283514Sarybchik}
181283514Sarybchik
182293927Sarybchik	__checkReturn	efx_rc_t
183293987Sarybchikef10_tx_qcreate(
184283514Sarybchik	__in		efx_nic_t *enp,
185283514Sarybchik	__in		unsigned int index,
186283514Sarybchik	__in		unsigned int label,
187283514Sarybchik	__in		efsys_mem_t *esmp,
188283514Sarybchik	__in		size_t n,
189283514Sarybchik	__in		uint32_t id,
190283514Sarybchik	__in		uint16_t flags,
191283514Sarybchik	__in		efx_evq_t *eep,
192283514Sarybchik	__in		efx_txq_t *etp,
193283514Sarybchik	__out		unsigned int *addedp)
194283514Sarybchik{
195283514Sarybchik	efx_qword_t desc;
196293927Sarybchik	efx_rc_t rc;
197283514Sarybchik
198283514Sarybchik
199283514Sarybchik	if ((rc = efx_mcdi_init_txq(enp, n, eep->ee_index, label, index, flags,
200283514Sarybchik	    esmp)) != 0)
201283514Sarybchik		goto fail1;
202283514Sarybchik
203283514Sarybchik	/*
204283514Sarybchik	 * A previous user of this TX queue may have written a descriptor to the
205283514Sarybchik	 * TX push collector, but not pushed the doorbell (e.g. after a crash).
206283514Sarybchik	 * The next doorbell write would then push the stale descriptor.
207283514Sarybchik	 *
208283514Sarybchik	 * Ensure the (per network port) TX push collector is cleared by writing
209283514Sarybchik	 * a no-op TX option descriptor. See bug29981 for details.
210283514Sarybchik	 */
211283514Sarybchik	*addedp = 1;
212283514Sarybchik	EFX_POPULATE_QWORD_4(desc,
213283514Sarybchik	    ESF_DZ_TX_DESC_IS_OPT, 1,
214283514Sarybchik	    ESF_DZ_TX_OPTION_TYPE, ESE_DZ_TX_OPTION_DESC_CRC_CSUM,
215293955Sarybchik	    ESF_DZ_TX_OPTION_UDP_TCP_CSUM,
216293955Sarybchik	    (flags & EFX_TXQ_CKSUM_TCPUDP) ? 1 : 0,
217293955Sarybchik	    ESF_DZ_TX_OPTION_IP_CSUM,
218293955Sarybchik	    (flags & EFX_TXQ_CKSUM_IPV4) ? 1 : 0);
219283514Sarybchik
220283514Sarybchik	EFSYS_MEM_WRITEQ(etp->et_esmp, 0, &desc);
221293987Sarybchik	ef10_tx_qpush(etp, *addedp, 0);
222283514Sarybchik
223283514Sarybchik	return (0);
224283514Sarybchik
225283514Sarybchikfail1:
226293927Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
227283514Sarybchik
228283514Sarybchik	return (rc);
229283514Sarybchik}
230283514Sarybchik
231283514Sarybchik		void
232293987Sarybchikef10_tx_qdestroy(
233283514Sarybchik	__in	efx_txq_t *etp)
234283514Sarybchik{
235283514Sarybchik	/* FIXME */
236283514Sarybchik	_NOTE(ARGUNUSED(etp))
237283514Sarybchik	/* FIXME */
238283514Sarybchik}
239283514Sarybchik
240293927Sarybchik	__checkReturn	efx_rc_t
241293987Sarybchikef10_tx_qpio_enable(
242283514Sarybchik	__in		efx_txq_t *etp)
243283514Sarybchik{
244283514Sarybchik	efx_nic_t *enp = etp->et_enp;
245283514Sarybchik	efx_piobuf_handle_t handle;
246293927Sarybchik	efx_rc_t rc;
247283514Sarybchik
248283514Sarybchik	if (etp->et_pio_size != 0) {
249283514Sarybchik		rc = EALREADY;
250283514Sarybchik		goto fail1;
251283514Sarybchik	}
252283514Sarybchik
253283514Sarybchik	/* Sub-allocate a PIO block from a piobuf */
254294006Sarybchik	if ((rc = ef10_nic_pio_alloc(enp,
255283514Sarybchik		    &etp->et_pio_bufnum,
256283514Sarybchik		    &handle,
257283514Sarybchik		    &etp->et_pio_blknum,
258283514Sarybchik		    &etp->et_pio_offset,
259283514Sarybchik		    &etp->et_pio_size)) != 0) {
260283514Sarybchik		goto fail2;
261283514Sarybchik	}
262283514Sarybchik	EFSYS_ASSERT3U(etp->et_pio_size, !=, 0);
263283514Sarybchik
264283514Sarybchik	/* Link the piobuf to this TXQ */
265294006Sarybchik	if ((rc = ef10_nic_pio_link(enp, etp->et_index, handle)) != 0) {
266283514Sarybchik		goto fail3;
267283514Sarybchik	}
268283514Sarybchik
269283514Sarybchik	/*
270283514Sarybchik	 * et_pio_offset is the offset of the sub-allocated block within the
271283514Sarybchik	 * hardware PIO buffer. It is used as the buffer address in the PIO
272283514Sarybchik	 * option descriptor.
273283514Sarybchik	 *
274283514Sarybchik	 * et_pio_write_offset is the offset of the sub-allocated block from the
275283514Sarybchik	 * start of the write-combined memory mapping, and is used for writing
276283514Sarybchik	 * data into the PIO buffer.
277283514Sarybchik	 */
278283514Sarybchik	etp->et_pio_write_offset =
279283514Sarybchik	    (etp->et_pio_bufnum * ER_DZ_TX_PIOBUF_STEP) +
280283514Sarybchik	    ER_DZ_TX_PIOBUF_OFST + etp->et_pio_offset;
281283514Sarybchik
282283514Sarybchik	return (0);
283283514Sarybchik
284283514Sarybchikfail3:
285283514Sarybchik	EFSYS_PROBE(fail3);
286294006Sarybchik	ef10_nic_pio_free(enp, etp->et_pio_bufnum, etp->et_pio_blknum);
287283514Sarybchik	etp->et_pio_size = 0;
288283514Sarybchikfail2:
289283514Sarybchik	EFSYS_PROBE(fail2);
290283514Sarybchikfail1:
291293927Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
292283514Sarybchik
293283514Sarybchik	return (rc);
294283514Sarybchik}
295283514Sarybchik
296283514Sarybchik			void
297293987Sarybchikef10_tx_qpio_disable(
298283514Sarybchik	__in		efx_txq_t *etp)
299283514Sarybchik{
300283514Sarybchik	efx_nic_t *enp = etp->et_enp;
301283514Sarybchik
302283514Sarybchik	if (etp->et_pio_size != 0) {
303283514Sarybchik		/* Unlink the piobuf from this TXQ */
304294006Sarybchik		ef10_nic_pio_unlink(enp, etp->et_index);
305283514Sarybchik
306283514Sarybchik		/* Free the sub-allocated PIO block */
307294006Sarybchik		ef10_nic_pio_free(enp, etp->et_pio_bufnum, etp->et_pio_blknum);
308283514Sarybchik		etp->et_pio_size = 0;
309283514Sarybchik		etp->et_pio_write_offset = 0;
310283514Sarybchik	}
311283514Sarybchik}
312283514Sarybchik
313293927Sarybchik	__checkReturn	efx_rc_t
314293987Sarybchikef10_tx_qpio_write(
315283514Sarybchik	__in			efx_txq_t *etp,
316283514Sarybchik	__in_ecount(length)	uint8_t *buffer,
317283514Sarybchik	__in			size_t length,
318283514Sarybchik	__in			size_t offset)
319283514Sarybchik{
320283514Sarybchik	efx_nic_t *enp = etp->et_enp;
321283514Sarybchik	efsys_bar_t *esbp = enp->en_esbp;
322283514Sarybchik	uint32_t write_offset;
323283514Sarybchik	uint32_t write_offset_limit;
324283514Sarybchik	efx_qword_t *eqp;
325293927Sarybchik	efx_rc_t rc;
326283514Sarybchik
327283514Sarybchik	EFSYS_ASSERT(length % sizeof (efx_qword_t) == 0);
328283514Sarybchik
329283514Sarybchik	if (etp->et_pio_size == 0) {
330283514Sarybchik		rc = ENOENT;
331283514Sarybchik		goto fail1;
332283514Sarybchik	}
333283514Sarybchik	if (offset + length > etp->et_pio_size)	{
334283514Sarybchik		rc = ENOSPC;
335283514Sarybchik		goto fail2;
336283514Sarybchik	}
337283514Sarybchik
338283514Sarybchik	/*
339283514Sarybchik	 * Writes to PIO buffers must be 64 bit aligned, and multiples of
340283514Sarybchik	 * 64 bits.
341283514Sarybchik	 */
342283514Sarybchik	write_offset = etp->et_pio_write_offset + offset;
343283514Sarybchik	write_offset_limit = write_offset + length;
344283514Sarybchik	eqp = (efx_qword_t *)buffer;
345283514Sarybchik	while (write_offset < write_offset_limit) {
346283514Sarybchik		EFSYS_BAR_WC_WRITEQ(esbp, write_offset, eqp);
347283514Sarybchik		eqp++;
348283514Sarybchik		write_offset += sizeof (efx_qword_t);
349283514Sarybchik	}
350283514Sarybchik
351283514Sarybchik	return (0);
352283514Sarybchik
353283514Sarybchikfail2:
354283514Sarybchik	EFSYS_PROBE(fail2);
355283514Sarybchikfail1:
356293927Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
357283514Sarybchik
358283514Sarybchik	return (rc);
359283514Sarybchik}
360283514Sarybchik
361293927Sarybchik	__checkReturn	efx_rc_t
362293987Sarybchikef10_tx_qpio_post(
363283514Sarybchik	__in			efx_txq_t *etp,
364283514Sarybchik	__in			size_t pkt_length,
365283514Sarybchik	__in			unsigned int completed,
366283514Sarybchik	__inout			unsigned int *addedp)
367283514Sarybchik{
368283514Sarybchik	efx_qword_t pio_desc;
369283514Sarybchik	unsigned int id;
370283514Sarybchik	size_t offset;
371283514Sarybchik	unsigned int added = *addedp;
372293927Sarybchik	efx_rc_t rc;
373283514Sarybchik
374283514Sarybchik
375283514Sarybchik	if (added - completed + 1 > EFX_TXQ_LIMIT(etp->et_mask + 1)) {
376283514Sarybchik		rc = ENOSPC;
377283514Sarybchik		goto fail1;
378283514Sarybchik	}
379283514Sarybchik
380283514Sarybchik	if (etp->et_pio_size == 0) {
381283514Sarybchik		rc = ENOENT;
382283514Sarybchik		goto fail2;
383283514Sarybchik	}
384283514Sarybchik
385283514Sarybchik	id = added++ & etp->et_mask;
386283514Sarybchik	offset = id * sizeof (efx_qword_t);
387283514Sarybchik
388283514Sarybchik	EFSYS_PROBE4(tx_pio_post, unsigned int, etp->et_index,
389283514Sarybchik		    unsigned int, id, uint32_t, etp->et_pio_offset,
390283514Sarybchik		    size_t, pkt_length);
391283514Sarybchik
392283514Sarybchik	EFX_POPULATE_QWORD_5(pio_desc,
393283514Sarybchik			ESF_DZ_TX_DESC_IS_OPT, 1,
394283514Sarybchik			ESF_DZ_TX_OPTION_TYPE, 1,
395283514Sarybchik			ESF_DZ_TX_PIO_CONT, 0,
396283514Sarybchik			ESF_DZ_TX_PIO_BYTE_CNT, pkt_length,
397283514Sarybchik			ESF_DZ_TX_PIO_BUF_ADDR, etp->et_pio_offset);
398283514Sarybchik
399283514Sarybchik	EFSYS_MEM_WRITEQ(etp->et_esmp, offset, &pio_desc);
400283514Sarybchik
401283514Sarybchik	EFX_TX_QSTAT_INCR(etp, TX_POST_PIO);
402283514Sarybchik
403283514Sarybchik	*addedp = added;
404283514Sarybchik	return (0);
405283514Sarybchik
406283514Sarybchikfail2:
407283514Sarybchik	EFSYS_PROBE(fail2);
408283514Sarybchikfail1:
409293927Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
410283514Sarybchik
411283514Sarybchik	return (rc);
412283514Sarybchik}
413283514Sarybchik
414293927Sarybchik	__checkReturn	efx_rc_t
415293987Sarybchikef10_tx_qpost(
416283514Sarybchik	__in		efx_txq_t *etp,
417283514Sarybchik	__in_ecount(n)	efx_buffer_t *eb,
418283514Sarybchik	__in		unsigned int n,
419283514Sarybchik	__in		unsigned int completed,
420283514Sarybchik	__inout		unsigned int *addedp)
421283514Sarybchik{
422283514Sarybchik	unsigned int added = *addedp;
423283514Sarybchik	unsigned int i;
424293927Sarybchik	efx_rc_t rc;
425283514Sarybchik
426283514Sarybchik	if (added - completed + n > EFX_TXQ_LIMIT(etp->et_mask + 1)) {
427283514Sarybchik		rc = ENOSPC;
428283514Sarybchik		goto fail1;
429283514Sarybchik	}
430283514Sarybchik
431283514Sarybchik	for (i = 0; i < n; i++) {
432283514Sarybchik		efx_buffer_t *ebp = &eb[i];
433283514Sarybchik		efsys_dma_addr_t addr = ebp->eb_addr;
434283514Sarybchik		size_t size = ebp->eb_size;
435283514Sarybchik		boolean_t eop = ebp->eb_eop;
436283514Sarybchik		unsigned int id;
437283514Sarybchik		size_t offset;
438283514Sarybchik		efx_qword_t qword;
439283514Sarybchik
440283514Sarybchik		/* Fragments must not span 4k boundaries. */
441283514Sarybchik		EFSYS_ASSERT(P2ROUNDUP(addr + 1, 4096) >= (addr + size));
442283514Sarybchik
443283514Sarybchik		id = added++ & etp->et_mask;
444283514Sarybchik		offset = id * sizeof (efx_qword_t);
445283514Sarybchik
446283514Sarybchik		EFSYS_PROBE5(tx_post, unsigned int, etp->et_index,
447283514Sarybchik		    unsigned int, id, efsys_dma_addr_t, addr,
448283514Sarybchik		    size_t, size, boolean_t, eop);
449283514Sarybchik
450283514Sarybchik		EFX_POPULATE_QWORD_5(qword,
451283514Sarybchik		    ESF_DZ_TX_KER_TYPE, 0,
452283514Sarybchik		    ESF_DZ_TX_KER_CONT, (eop) ? 0 : 1,
453283514Sarybchik		    ESF_DZ_TX_KER_BYTE_CNT, (uint32_t)(size),
454283514Sarybchik		    ESF_DZ_TX_KER_BUF_ADDR_DW0, (uint32_t)(addr & 0xffffffff),
455283514Sarybchik		    ESF_DZ_TX_KER_BUF_ADDR_DW1, (uint32_t)(addr >> 32));
456283514Sarybchik
457283514Sarybchik		EFSYS_MEM_WRITEQ(etp->et_esmp, offset, &qword);
458283514Sarybchik	}
459283514Sarybchik
460283514Sarybchik	EFX_TX_QSTAT_INCR(etp, TX_POST);
461283514Sarybchik
462283514Sarybchik	*addedp = added;
463283514Sarybchik	return (0);
464283514Sarybchik
465283514Sarybchikfail1:
466293927Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
467283514Sarybchik
468283514Sarybchik	return (rc);
469283514Sarybchik}
470283514Sarybchik
471283514Sarybchik/*
472283514Sarybchik * This improves performance by pushing a TX descriptor at the same time as the
473283514Sarybchik * doorbell. The descriptor must be added to the TXQ, so that can be used if the
474283514Sarybchik * hardware decides not to use the pushed descriptor.
475283514Sarybchik */
476283514Sarybchik			void
477293987Sarybchikef10_tx_qpush(
478283514Sarybchik	__in		efx_txq_t *etp,
479283514Sarybchik	__in		unsigned int added,
480283514Sarybchik	__in		unsigned int pushed)
481283514Sarybchik{
482283514Sarybchik	efx_nic_t *enp = etp->et_enp;
483283514Sarybchik	unsigned int wptr;
484283514Sarybchik	unsigned int id;
485283514Sarybchik	size_t offset;
486283514Sarybchik	efx_qword_t desc;
487283514Sarybchik	efx_oword_t oword;
488283514Sarybchik
489283514Sarybchik	wptr = added & etp->et_mask;
490283514Sarybchik	id = pushed & etp->et_mask;
491283514Sarybchik	offset = id * sizeof (efx_qword_t);
492283514Sarybchik
493283514Sarybchik	EFSYS_MEM_READQ(etp->et_esmp, offset, &desc);
494283514Sarybchik	EFX_POPULATE_OWORD_3(oword,
495283514Sarybchik	    ERF_DZ_TX_DESC_WPTR, wptr,
496283514Sarybchik	    ERF_DZ_TX_DESC_HWORD, EFX_QWORD_FIELD(desc, EFX_DWORD_1),
497283514Sarybchik	    ERF_DZ_TX_DESC_LWORD, EFX_QWORD_FIELD(desc, EFX_DWORD_0));
498283514Sarybchik
499283514Sarybchik	/* Guarantee ordering of memory (descriptors) and PIO (doorbell) */
500283514Sarybchik	EFX_DMA_SYNC_QUEUE_FOR_DEVICE(etp->et_esmp, etp->et_mask + 1, wptr, id);
501283514Sarybchik	EFSYS_PIO_WRITE_BARRIER();
502283514Sarybchik	EFX_BAR_TBL_DOORBELL_WRITEO(enp, ER_DZ_TX_DESC_UPD_REG, etp->et_index,
503283514Sarybchik				    &oword);
504283514Sarybchik}
505283514Sarybchik
506293927Sarybchik	__checkReturn	efx_rc_t
507293987Sarybchikef10_tx_qdesc_post(
508283514Sarybchik	__in		efx_txq_t *etp,
509283514Sarybchik	__in_ecount(n)	efx_desc_t *ed,
510283514Sarybchik	__in		unsigned int n,
511283514Sarybchik	__in		unsigned int completed,
512283514Sarybchik	__inout		unsigned int *addedp)
513283514Sarybchik{
514283514Sarybchik	unsigned int added = *addedp;
515283514Sarybchik	unsigned int i;
516293927Sarybchik	efx_rc_t rc;
517283514Sarybchik
518283514Sarybchik	if (added - completed + n > EFX_TXQ_LIMIT(etp->et_mask + 1)) {
519283514Sarybchik		rc = ENOSPC;
520283514Sarybchik		goto fail1;
521283514Sarybchik	}
522283514Sarybchik
523283514Sarybchik	for (i = 0; i < n; i++) {
524283514Sarybchik		efx_desc_t *edp = &ed[i];
525283514Sarybchik		unsigned int id;
526283514Sarybchik		size_t offset;
527283514Sarybchik
528283514Sarybchik		id = added++ & etp->et_mask;
529283514Sarybchik		offset = id * sizeof (efx_desc_t);
530283514Sarybchik
531283514Sarybchik		EFSYS_MEM_WRITEQ(etp->et_esmp, offset, &edp->ed_eq);
532283514Sarybchik	}
533283514Sarybchik
534283514Sarybchik	EFSYS_PROBE3(tx_desc_post, unsigned int, etp->et_index,
535283514Sarybchik		    unsigned int, added, unsigned int, n);
536283514Sarybchik
537283514Sarybchik	EFX_TX_QSTAT_INCR(etp, TX_POST);
538283514Sarybchik
539283514Sarybchik	*addedp = added;
540283514Sarybchik	return (0);
541283514Sarybchik
542283514Sarybchikfail1:
543293927Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
544283514Sarybchik
545283514Sarybchik	return (rc);
546283514Sarybchik}
547283514Sarybchik
548283514Sarybchik	void
549293987Sarybchikef10_tx_qdesc_dma_create(
550283514Sarybchik	__in	efx_txq_t *etp,
551283514Sarybchik	__in	efsys_dma_addr_t addr,
552283514Sarybchik	__in	size_t size,
553283514Sarybchik	__in	boolean_t eop,
554283514Sarybchik	__out	efx_desc_t *edp)
555283514Sarybchik{
556283514Sarybchik	/* Fragments must not span 4k boundaries. */
557283514Sarybchik	EFSYS_ASSERT(P2ROUNDUP(addr + 1, 4096) >= addr + size);
558283514Sarybchik
559283514Sarybchik	EFSYS_PROBE4(tx_desc_dma_create, unsigned int, etp->et_index,
560283514Sarybchik		    efsys_dma_addr_t, addr,
561283514Sarybchik		    size_t, size, boolean_t, eop);
562283514Sarybchik
563283514Sarybchik	EFX_POPULATE_QWORD_5(edp->ed_eq,
564283514Sarybchik		    ESF_DZ_TX_KER_TYPE, 0,
565283514Sarybchik		    ESF_DZ_TX_KER_CONT, (eop) ? 0 : 1,
566283514Sarybchik		    ESF_DZ_TX_KER_BYTE_CNT, (uint32_t)(size),
567283514Sarybchik		    ESF_DZ_TX_KER_BUF_ADDR_DW0, (uint32_t)(addr & 0xffffffff),
568283514Sarybchik		    ESF_DZ_TX_KER_BUF_ADDR_DW1, (uint32_t)(addr >> 32));
569283514Sarybchik}
570283514Sarybchik
571283514Sarybchik	void
572283514Sarybchikhunt_tx_qdesc_tso_create(
573283514Sarybchik	__in	efx_txq_t *etp,
574283514Sarybchik	__in	uint16_t ipv4_id,
575283514Sarybchik	__in	uint32_t tcp_seq,
576283514Sarybchik	__in	uint8_t  tcp_flags,
577283514Sarybchik	__out	efx_desc_t *edp)
578283514Sarybchik{
579283514Sarybchik	EFSYS_PROBE4(tx_desc_tso_create, unsigned int, etp->et_index,
580283514Sarybchik		    uint16_t, ipv4_id, uint32_t, tcp_seq,
581283514Sarybchik		    uint8_t, tcp_flags);
582283514Sarybchik
583283514Sarybchik	EFX_POPULATE_QWORD_5(edp->ed_eq,
584283514Sarybchik			    ESF_DZ_TX_DESC_IS_OPT, 1,
585283514Sarybchik			    ESF_DZ_TX_OPTION_TYPE,
586283514Sarybchik			    ESE_DZ_TX_OPTION_DESC_TSO,
587283514Sarybchik			    ESF_DZ_TX_TSO_TCP_FLAGS, tcp_flags,
588283514Sarybchik			    ESF_DZ_TX_TSO_IP_ID, ipv4_id,
589283514Sarybchik			    ESF_DZ_TX_TSO_TCP_SEQNO, tcp_seq);
590283514Sarybchik}
591283514Sarybchik
592283514Sarybchik	void
593294381Sarybchikef10_tx_qdesc_tso2_create(
594294381Sarybchik	__in			efx_txq_t *etp,
595294381Sarybchik	__in			uint16_t ipv4_id,
596294381Sarybchik	__in			uint32_t tcp_seq,
597294381Sarybchik	__in			uint16_t tcp_mss,
598294381Sarybchik	__out_ecount(count)	efx_desc_t *edp,
599294381Sarybchik	__in			int count)
600294381Sarybchik{
601294381Sarybchik	EFSYS_PROBE4(tx_desc_tso2_create, unsigned int, etp->et_index,
602294381Sarybchik		    uint16_t, ipv4_id, uint32_t, tcp_seq,
603294381Sarybchik		    uint16_t, tcp_mss);
604294381Sarybchik
605294381Sarybchik	EFSYS_ASSERT(count >= EFX_TX_FATSOV2_OPT_NDESCS);
606294381Sarybchik
607294381Sarybchik	EFX_POPULATE_QWORD_5(edp[0].ed_eq,
608294381Sarybchik			    ESF_DZ_TX_DESC_IS_OPT, 1,
609294381Sarybchik			    ESF_DZ_TX_OPTION_TYPE,
610294381Sarybchik			    ESE_DZ_TX_OPTION_DESC_TSO,
611294381Sarybchik			    ESF_DZ_TX_TSO_OPTION_TYPE,
612294381Sarybchik			    ESE_DZ_TX_TSO_OPTION_DESC_FATSO2A,
613294381Sarybchik			    ESF_DZ_TX_TSO_IP_ID, ipv4_id,
614294381Sarybchik			    ESF_DZ_TX_TSO_TCP_SEQNO, tcp_seq);
615294381Sarybchik	EFX_POPULATE_QWORD_4(edp[1].ed_eq,
616294381Sarybchik			    ESF_DZ_TX_DESC_IS_OPT, 1,
617294381Sarybchik			    ESF_DZ_TX_OPTION_TYPE,
618294381Sarybchik			    ESE_DZ_TX_OPTION_DESC_TSO,
619294381Sarybchik			    ESF_DZ_TX_TSO_OPTION_TYPE,
620294381Sarybchik			    ESE_DZ_TX_TSO_OPTION_DESC_FATSO2B,
621294381Sarybchik			    ESF_DZ_TX_TSO_TCP_MSS, tcp_mss);
622294381Sarybchik}
623294381Sarybchik
624294381Sarybchik	void
625293987Sarybchikef10_tx_qdesc_vlantci_create(
626283514Sarybchik	__in	efx_txq_t *etp,
627283514Sarybchik	__in	uint16_t  tci,
628283514Sarybchik	__out	efx_desc_t *edp)
629283514Sarybchik{
630283514Sarybchik	EFSYS_PROBE2(tx_desc_vlantci_create, unsigned int, etp->et_index,
631283514Sarybchik		    uint16_t, tci);
632283514Sarybchik
633283514Sarybchik	EFX_POPULATE_QWORD_4(edp->ed_eq,
634283514Sarybchik			    ESF_DZ_TX_DESC_IS_OPT, 1,
635283514Sarybchik			    ESF_DZ_TX_OPTION_TYPE,
636283514Sarybchik			    ESE_DZ_TX_OPTION_DESC_VLAN,
637283514Sarybchik			    ESF_DZ_TX_VLAN_OP, tci ? 1 : 0,
638283514Sarybchik			    ESF_DZ_TX_VLAN_TAG1, tci);
639283514Sarybchik}
640283514Sarybchik
641283514Sarybchik
642293927Sarybchik	__checkReturn	efx_rc_t
643293987Sarybchikef10_tx_qpace(
644283514Sarybchik	__in		efx_txq_t *etp,
645283514Sarybchik	__in		unsigned int ns)
646283514Sarybchik{
647293927Sarybchik	efx_rc_t rc;
648283514Sarybchik
649283514Sarybchik	/* FIXME */
650283514Sarybchik	_NOTE(ARGUNUSED(etp, ns))
651283514Sarybchik	if (B_FALSE) {
652283514Sarybchik		rc = ENOTSUP;
653283514Sarybchik		goto fail1;
654283514Sarybchik	}
655283514Sarybchik	/* FIXME */
656283514Sarybchik
657283514Sarybchik	return (0);
658283514Sarybchik
659283514Sarybchikfail1:
660293927Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
661283514Sarybchik
662283514Sarybchik	return (rc);
663283514Sarybchik}
664283514Sarybchik
665293927Sarybchik	__checkReturn	efx_rc_t
666293987Sarybchikef10_tx_qflush(
667283514Sarybchik	__in		efx_txq_t *etp)
668283514Sarybchik{
669283514Sarybchik	efx_nic_t *enp = etp->et_enp;
670293927Sarybchik	efx_rc_t rc;
671283514Sarybchik
672283514Sarybchik	if ((rc = efx_mcdi_fini_txq(enp, etp->et_index)) != 0)
673283514Sarybchik		goto fail1;
674283514Sarybchik
675283514Sarybchik	return (0);
676283514Sarybchik
677283514Sarybchikfail1:
678293927Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
679283514Sarybchik
680283514Sarybchik	return (rc);
681283514Sarybchik}
682283514Sarybchik
683283514Sarybchik			void
684293987Sarybchikef10_tx_qenable(
685283514Sarybchik	__in		efx_txq_t *etp)
686283514Sarybchik{
687283514Sarybchik	/* FIXME */
688283514Sarybchik	_NOTE(ARGUNUSED(etp))
689283514Sarybchik	/* FIXME */
690283514Sarybchik}
691283514Sarybchik
692283514Sarybchik#if EFSYS_OPT_QSTATS
693283514Sarybchik			void
694293987Sarybchikef10_tx_qstats_update(
695283514Sarybchik	__in				efx_txq_t *etp,
696283514Sarybchik	__inout_ecount(TX_NQSTATS)	efsys_stat_t *stat)
697283514Sarybchik{
698283514Sarybchik	unsigned int id;
699283514Sarybchik
700283514Sarybchik	for (id = 0; id < TX_NQSTATS; id++) {
701283514Sarybchik		efsys_stat_t *essp = &stat[id];
702283514Sarybchik
703283514Sarybchik		EFSYS_STAT_INCR(essp, etp->et_stat[id]);
704283514Sarybchik		etp->et_stat[id] = 0;
705283514Sarybchik	}
706283514Sarybchik}
707283514Sarybchik
708283514Sarybchik#endif /* EFSYS_OPT_QSTATS */
709283514Sarybchik
710283514Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */
711