xref: /freebsd/sys/dev/sfxge/common/efx_tx.c (revision 26a222dc0c048fc071b548eadad7b80405a1b126)
1 /*-
2  * Copyright 2007-2009 Solarflare Communications Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25 
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28 
29 #include "efsys.h"
30 #include "efx.h"
31 #include "efx_types.h"
32 #include "efx_regs.h"
33 #include "efx_impl.h"
34 
35 #if EFSYS_OPT_QSTATS
36 #define	EFX_TX_QSTAT_INCR(_etp, _stat)					\
37 	do {								\
38 		(_etp)->et_stat[_stat]++;				\
39 	_NOTE(CONSTANTCONDITION)					\
40 	} while (B_FALSE)
41 #else
42 #define	EFX_TX_QSTAT_INCR(_etp, _stat)
43 #endif
44 
45 	__checkReturn	int
46 efx_tx_init(
47 	__in		efx_nic_t *enp)
48 {
49 	efx_oword_t oword;
50 	int rc;
51 
52 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
53 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
54 
55 	if (!(enp->en_mod_flags & EFX_MOD_EV)) {
56 		rc = EINVAL;
57 		goto fail1;
58 	}
59 
60 	if (enp->en_mod_flags & EFX_MOD_TX) {
61 		rc = EINVAL;
62 		goto fail2;
63 	}
64 
65 	EFSYS_ASSERT3U(enp->en_tx_qcount, ==, 0);
66 
67 	/*
68 	 * Disable the timer-based TX DMA backoff and allow TX DMA to be
69 	 * controlled by the RX FIFO fill level (although always allow a
70 	 * minimal trickle).
71 	 */
72 	EFX_BAR_READO(enp, FR_AZ_TX_RESERVED_REG, &oword);
73 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_RX_SPACER, 0xfe);
74 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_RX_SPACER_EN, 1);
75 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_ONE_PKT_PER_Q, 1);
76 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_PUSH_EN, 0);
77 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DIS_NON_IP_EV, 1);
78 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_PREF_THRESHOLD, 2);
79 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_PREF_WD_TMR, 0x3fffff);
80 
81 	/*
82 	 * Filter all packets less than 14 bytes to avoid parsing
83 	 * errors.
84 	 */
85 	EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1);
86 	EFX_BAR_WRITEO(enp, FR_AZ_TX_RESERVED_REG, &oword);
87 
88 	/*
89 	 * Do not set TX_NO_EOP_DISC_EN, since it limits packets to 16
90 	 * descriptors (which is bad).
91 	 */
92 	EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword);
93 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_NO_EOP_DISC_EN, 0);
94 	EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword);
95 
96 	enp->en_mod_flags |= EFX_MOD_TX;
97 	return (0);
98 
99 fail2:
100 	EFSYS_PROBE(fail2);
101 fail1:
102 	EFSYS_PROBE1(fail1, int, rc);
103 
104 	return (rc);
105 }
106 
107 #if EFSYS_OPT_FILTER
108 extern	__checkReturn	int
109 efx_tx_filter_insert(
110 	__in		efx_txq_t *etp,
111 	__inout		efx_filter_spec_t *spec)
112 {
113 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
114 	EFSYS_ASSERT3P(spec, !=, NULL);
115 
116 	spec->efs_dmaq_id = (uint16_t)etp->et_index;
117 	return (efx_filter_insert_filter(etp->et_enp, spec, B_FALSE));
118 }
119 #endif
120 
121 #if EFSYS_OPT_FILTER
122 extern	__checkReturn	int
123 efx_tx_filter_remove(
124 	__in		efx_txq_t *etp,
125 	__inout		efx_filter_spec_t *spec)
126 {
127 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
128 	EFSYS_ASSERT3P(spec, !=, NULL);
129 
130 	spec->efs_dmaq_id = (uint16_t)etp->et_index;
131 	return (efx_filter_remove_filter(etp->et_enp, spec));
132 }
133 #endif
134 
135 #define	EFX_TX_DESC(_etp, _addr, _size, _eop, _added)			\
136 	do {								\
137 		unsigned int id;					\
138 		size_t offset;						\
139 		efx_qword_t qword;					\
140 									\
141 		id = (_added)++ & (_etp)->et_mask;			\
142 		offset = id * sizeof (efx_qword_t);			\
143 									\
144 		EFSYS_PROBE5(tx_post, unsigned int, (_etp)->et_index,	\
145 		    unsigned int, id, efsys_dma_addr_t, (_addr),	\
146 		    size_t, (_size), boolean_t, (_eop));		\
147 									\
148 		EFX_POPULATE_QWORD_4(qword,				\
149 		    FSF_AZ_TX_KER_CONT, (_eop) ? 0 : 1,			\
150 		    FSF_AZ_TX_KER_BYTE_COUNT, (uint32_t)(_size),	\
151 		    FSF_AZ_TX_KER_BUF_ADDR_DW0,				\
152 		    (uint32_t)((_addr) & 0xffffffff),			\
153 		    FSF_AZ_TX_KER_BUF_ADDR_DW1,				\
154 		    (uint32_t)((_addr) >> 32));				\
155 		EFSYS_MEM_WRITEQ((_etp)->et_esmp, offset, &qword);	\
156 									\
157 		_NOTE(CONSTANTCONDITION)				\
158 	} while (B_FALSE)
159 
160 	__checkReturn	int
161 efx_tx_qpost(
162 	__in		efx_txq_t *etp,
163 	__in_ecount(n)	efx_buffer_t *eb,
164 	__in		unsigned int n,
165 	__in		unsigned int completed,
166 	__inout		unsigned int *addedp)
167 {
168 	unsigned int added = *addedp;
169 	unsigned int i;
170 	int rc = ENOSPC;
171 
172 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
173 
174 	if (added - completed + n > EFX_TXQ_LIMIT(etp->et_mask + 1))
175 		goto fail1;
176 
177 	for (i = 0; i < n; i++) {
178 		efx_buffer_t *ebp = &eb[i];
179 		efsys_dma_addr_t start = ebp->eb_addr;
180 		size_t size = ebp->eb_size;
181 		efsys_dma_addr_t end = start + size;
182 
183 		/* Fragments must not span 4k boundaries. */
184 		EFSYS_ASSERT(P2ROUNDUP(start + 1, 4096) >= end);
185 
186 		EFX_TX_DESC(etp, start, size, ebp->eb_eop, added);
187 	}
188 
189 	EFX_TX_QSTAT_INCR(etp, TX_POST);
190 
191 	*addedp = added;
192 	return (0);
193 
194 fail1:
195 	EFSYS_PROBE1(fail1, int, rc);
196 
197 	return (rc);
198 }
199 
200 		void
201 efx_tx_qpush(
202 	__in	efx_txq_t *etp,
203 	__in	unsigned int added)
204 {
205 	efx_nic_t *enp = etp->et_enp;
206 	uint32_t wptr;
207 	efx_dword_t dword;
208 	efx_oword_t oword;
209 
210 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
211 
212 	/* Guarantee ordering of memory (descriptors) and PIO (doorbell) */
213 	EFSYS_PIO_WRITE_BARRIER();
214 
215 	/* Push the populated descriptors out */
216 	wptr = added & etp->et_mask;
217 
218 	EFX_POPULATE_OWORD_1(oword, FRF_AZ_TX_DESC_WPTR, wptr);
219 
220 	/* Only write the third DWORD */
221 	EFX_POPULATE_DWORD_1(dword,
222 	    EFX_DWORD_0, EFX_OWORD_FIELD(oword, EFX_DWORD_3));
223 	EFX_BAR_TBL_WRITED3(enp, FR_BZ_TX_DESC_UPD_REGP0,
224 			    etp->et_index, &dword, B_FALSE);
225 }
226 
227 #define	EFX_MAX_PACE_VALUE 20
228 #define	EFX_TX_PACE_CLOCK_BASE	104
229 
230 	__checkReturn	int
231 efx_tx_qpace(
232 	__in		efx_txq_t *etp,
233 	__in		unsigned int ns)
234 {
235 	efx_nic_t *enp = etp->et_enp;
236 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
237 	efx_oword_t oword;
238 	unsigned int pace_val;
239 	unsigned int timer_period;
240 	int rc;
241 
242 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
243 
244 	if (ns == 0) {
245 		pace_val = 0;
246 	} else {
247 		/*
248 		 * The pace_val to write into the table is s.t
249 		 * ns <= timer_period * (2 ^ pace_val)
250 		 */
251 		timer_period = EFX_TX_PACE_CLOCK_BASE / encp->enc_clk_mult;
252 		for (pace_val = 1; pace_val <= EFX_MAX_PACE_VALUE; pace_val++) {
253 			if ((timer_period << pace_val) >= ns)
254 				break;
255 		}
256 	}
257 	if (pace_val > EFX_MAX_PACE_VALUE) {
258 		rc = EINVAL;
259 		goto fail1;
260 	}
261 
262 	/* Update the pacing table */
263 	EFX_POPULATE_OWORD_1(oword, FRF_AZ_TX_PACE, pace_val);
264 	EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_PACE_TBL, etp->et_index, &oword);
265 
266 	return (0);
267 
268 fail1:
269 	EFSYS_PROBE1(fail1, int, rc);
270 
271 	return (rc);
272 }
273 
274 		void
275 efx_tx_qflush(
276 	__in	efx_txq_t *etp)
277 {
278 	efx_nic_t *enp = etp->et_enp;
279 	efx_oword_t oword;
280 	uint32_t label;
281 
282 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
283 
284 	efx_tx_qpace(etp, 0);
285 
286 	label = etp->et_index;
287 
288 	/* Flush the queue */
289 	EFX_POPULATE_OWORD_2(oword, FRF_AZ_TX_FLUSH_DESCQ_CMD, 1,
290 	    FRF_AZ_TX_FLUSH_DESCQ, label);
291 	EFX_BAR_WRITEO(enp, FR_AZ_TX_FLUSH_DESCQ_REG, &oword);
292 }
293 
294 		void
295 efx_tx_qenable(
296 	__in	efx_txq_t *etp)
297 {
298 	efx_nic_t *enp = etp->et_enp;
299 	efx_oword_t oword;
300 
301 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
302 
303 	EFX_BAR_TBL_READO(enp, FR_AZ_TX_DESC_PTR_TBL,
304 			    etp->et_index, &oword);
305 
306 	EFSYS_PROBE5(tx_descq_ptr, unsigned int, etp->et_index,
307 	    uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_3),
308 	    uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_2),
309 	    uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_1),
310 	    uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_0));
311 
312 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DC_HW_RPTR, 0);
313 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DESCQ_HW_RPTR, 0);
314 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DESCQ_EN, 1);
315 
316 	EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_DESC_PTR_TBL,
317 			    etp->et_index, &oword);
318 }
319 
320 	__checkReturn	int
321 efx_tx_qcreate(
322 	__in		efx_nic_t *enp,
323 	__in		unsigned int index,
324 	__in		unsigned int label,
325 	__in		efsys_mem_t *esmp,
326 	__in		size_t n,
327 	__in		uint32_t id,
328 	__in		uint16_t flags,
329 	__in		efx_evq_t *eep,
330 	__deref_out	efx_txq_t **etpp)
331 {
332 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
333 	efx_txq_t *etp;
334 	efx_oword_t oword;
335 	uint32_t size;
336 	int rc;
337 
338 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
339 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TX);
340 
341 	EFX_STATIC_ASSERT(EFX_EV_TX_NLABELS ==
342 	    (1 << FRF_AZ_TX_DESCQ_LABEL_WIDTH));
343 	EFSYS_ASSERT3U(label, <, EFX_EV_TX_NLABELS);
344 	EFSYS_ASSERT3U(enp->en_tx_qcount + 1, <, encp->enc_txq_limit);
345 
346 	if (!ISP2(n) || !(n & EFX_TXQ_NDESCS_MASK)) {
347 		rc = EINVAL;
348 		goto fail1;
349 	}
350 	if (index >= encp->enc_txq_limit) {
351 		rc = EINVAL;
352 		goto fail2;
353 	}
354 	for (size = 0; (1 << size) <= (EFX_TXQ_MAXNDESCS / EFX_TXQ_MINNDESCS);
355 	    size++)
356 		if ((1 << size) == (int)(n / EFX_TXQ_MINNDESCS))
357 			break;
358 	if (id + (1 << size) >= encp->enc_buftbl_limit) {
359 		rc = EINVAL;
360 		goto fail3;
361 	}
362 
363 	/* Allocate an TXQ object */
364 	EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (efx_txq_t), etp);
365 
366 	if (etp == NULL) {
367 		rc = ENOMEM;
368 		goto fail4;
369 	}
370 
371 	etp->et_magic = EFX_TXQ_MAGIC;
372 	etp->et_enp = enp;
373 	etp->et_index = index;
374 	etp->et_mask = n - 1;
375 	etp->et_esmp = esmp;
376 
377 	/* Set up the new descriptor queue */
378 	EFX_POPULATE_OWORD_6(oword,
379 	    FRF_AZ_TX_DESCQ_BUF_BASE_ID, id,
380 	    FRF_AZ_TX_DESCQ_EVQ_ID, eep->ee_index,
381 	    FRF_AZ_TX_DESCQ_OWNER_ID, 0,
382 	    FRF_AZ_TX_DESCQ_LABEL, label,
383 	    FRF_AZ_TX_DESCQ_SIZE, size,
384 	    FRF_AZ_TX_DESCQ_TYPE, 0);
385 
386 	EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_NON_IP_DROP_DIS, 1);
387 	EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_IP_CHKSM_DIS,
388 	    (flags & EFX_CKSUM_IPV4) ? 0 : 1);
389 	EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_TCP_CHKSM_DIS,
390 	    (flags & EFX_CKSUM_TCPUDP) ? 0 : 1);
391 
392 	EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_DESC_PTR_TBL,
393 	    etp->et_index, &oword);
394 
395 	enp->en_tx_qcount++;
396 	*etpp = etp;
397 	return (0);
398 
399 fail4:
400 	EFSYS_PROBE(fail4);
401 fail3:
402 	EFSYS_PROBE(fail3);
403 fail2:
404 	EFSYS_PROBE(fail2);
405 fail1:
406 	EFSYS_PROBE1(fail1, int, rc);
407 
408 	return (rc);
409 }
410 
411 #if EFSYS_OPT_QSTATS
412 #if EFSYS_OPT_NAMES
413 /* START MKCONFIG GENERATED EfxTransmitQueueStatNamesBlock 78ca9ab00287fffb */
414 static const char 	__cs * __cs __efx_tx_qstat_name[] = {
415 	"post",
416 	"unaligned_split",
417 };
418 /* END MKCONFIG GENERATED EfxTransmitQueueStatNamesBlock */
419 
420 		const char __cs *
421 efx_tx_qstat_name(
422 	__in	efx_nic_t *enp,
423 	__in	unsigned int id)
424 {
425 	_NOTE(ARGUNUSED(enp))
426 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
427 	EFSYS_ASSERT3U(id, <, TX_NQSTATS);
428 
429 	return (__efx_tx_qstat_name[id]);
430 }
431 #endif	/* EFSYS_OPT_NAMES */
432 #endif	/* EFSYS_OPT_QSTATS */
433 
434 #if EFSYS_OPT_QSTATS
435 					void
436 efx_tx_qstats_update(
437 	__in				efx_txq_t *etp,
438 	__inout_ecount(TX_NQSTATS)	efsys_stat_t *stat)
439 {
440 	unsigned int id;
441 
442 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
443 
444 	for (id = 0; id < TX_NQSTATS; id++) {
445 		efsys_stat_t *essp = &stat[id];
446 
447 		EFSYS_STAT_INCR(essp, etp->et_stat[id]);
448 		etp->et_stat[id] = 0;
449 	}
450 }
451 #endif	/* EFSYS_OPT_QSTATS */
452 
453 		void
454 efx_tx_qdestroy(
455 	__in	efx_txq_t *etp)
456 {
457 	efx_nic_t *enp = etp->et_enp;
458 	efx_oword_t oword;
459 
460 	EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
461 
462 	EFSYS_ASSERT(enp->en_tx_qcount != 0);
463 	--enp->en_tx_qcount;
464 
465 	/* Purge descriptor queue */
466 	EFX_ZERO_OWORD(oword);
467 
468 	EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_DESC_PTR_TBL,
469 			    etp->et_index, &oword);
470 
471 	/* Free the TXQ object */
472 	EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_txq_t), etp);
473 }
474 
475 		void
476 efx_tx_fini(
477 	__in	efx_nic_t *enp)
478 {
479 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
480 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
481 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TX);
482 	EFSYS_ASSERT3U(enp->en_tx_qcount, ==, 0);
483 
484 	enp->en_mod_flags &= ~EFX_MOD_TX;
485 }
486