xref: /freebsd/sys/dev/dpaa/dpaa_eth.c (revision d59c7ea2701fe7b73b32eef49a7c712ef38de5a0)
1 /*-
2  * Copyright (c) 2026 Justin Hibbits
3  * Copyright (c) 2012 Semihalf.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/kernel.h>
31 #include <sys/module.h>
32 #include <sys/bus.h>
33 #include <sys/rman.h>
34 #include <sys/malloc.h>
35 #include <sys/mbuf.h>
36 #include <sys/smp.h>
37 #include <sys/socket.h>
38 #include <sys/sockio.h>
39 #include <sys/sysctl.h>
40 
41 #include <net/ethernet.h>
42 #include <net/if.h>
43 #include <net/if_dl.h>
44 #include <net/if_media.h>
45 #include <net/if_types.h>
46 #include <net/if_arp.h>
47 #include <netinet/ip.h>
48 #include <netinet/ip6.h>
49 
50 #include <dev/mii/mii.h>
51 #include <dev/mii/miivar.h>
52 
53 #include <vm/vm.h>
54 #include <vm/pmap.h>
55 
56 #include "miibus_if.h"
57 
58 #include "bman.h"
59 #include "dpaa_common.h"
60 #include "dpaa_eth.h"
61 #include "fman.h"
62 #include "fman_parser.h"
63 #include "fman_port.h"
64 #include "fman_if.h"
65 #include "fman_port_if.h"
66 #include "if_dtsec.h"
67 #include "qman.h"
68 #include "qman_var.h"
69 #include "qman_portal_if.h"
70 
71 
72 #define DPAA_ETH_LOCK(sc)		mtx_lock(&(sc)->sc_lock)
73 #define DPAA_ETH_UNLOCK(sc)		mtx_unlock(&(sc)->sc_lock)
74 #define DPAA_ETH_LOCK_ASSERT(sc)	mtx_assert(&(sc)->sc_lock, MA_OWNED)
75 
76 /*
77  * On 64-bit Book-E the direct map is always present, and the driver's
78  * UMA zones plus page-sized mbuf clusters live in it.  Bypass the
79  * page-table walk in pmap_kextract() for those; fall back for
80  * MJUM9BYTES/MJUM16BYTES clusters, which are kmem_alloc_contig()'d
81  * into KVA.
82  */
83 static inline vm_paddr_t
84 dpaa_eth_va_to_phys(vm_offset_t va)
85 {
86 	if (__predict_true(va >= DMAP_BASE_ADDRESS && va <= DMAP_MAX_ADDRESS))
87 		return (DMAP_TO_PHYS(va));
88 	return (pmap_kextract(va));
89 }
90 
91 /**
92  * @group dTSEC RM private defines.
93  * @{
94  */
95 #define	DTSEC_BPOOLS_USED	(1)
96 #define	DTSEC_MAX_TX_QUEUE_LEN	256
97 /*
98  * Sample the hardware TX FQ counter every Nth packet.  The FQ counter is
99  * 24 bits and the soft cap above is 256, so overshoot by N is trivial.
100  */
101 #define	DTSEC_MAX_TX_QUEUE_CHECK_INTERVAL	32
102 /*
103  * Confirmation callback drain-detection.  Fast path (TX not backpressured)
104  * skips the MC call entirely; when flagged, we sample every Nth callback to
105  * detect the drain-to-zero transition.
106  */
107 #define	DTSEC_TX_CONF_CHECK_INTERVAL		32
108 
109 struct dpaa_eth_frame_info {
110 	struct fman_internal_context	fi_ic;
111 	struct mbuf			*fi_mbuf;
112 	struct dpaa_sgte		fi_sgt[DPAA_NUM_OF_SG_TABLE_ENTRY];
113 };
114 
115 enum dpaa_eth_pool_params {
116 	DTSEC_RM_POOL_RX_LOW_MARK	= 16,
117 	DTSEC_RM_POOL_RX_HIGH_MARK	= 64,
118 	DTSEC_RM_POOL_RX_MAX_SIZE	= 256,
119 	/*
120 	 * MAX_SIZE is a soft cap set well below the BMan hardware pool
121 	 * limit, so sampling the depth every N put-backs per CPU is safe:
122 	 * worst-case overshoot is N * ncpus buffers, still tiny vs. the
123 	 * hardware pool.
124 	 */
125 	DTSEC_RM_POOL_RX_CHECK_INTERVAL	= 32,
126 
127 	DTSEC_RM_POOL_FI_LOW_MARK	= 16,
128 	DTSEC_RM_POOL_FI_HIGH_MARK	= 64,
129 	DTSEC_RM_POOL_FI_MAX_SIZE	= 256,
130 };
131 
132 #define	DTSEC_RM_FQR_RX_CHANNEL		0x401
133 #define	DTSEC_RM_FQR_TX_CONF_CHANNEL	0
134 enum dpaa_eth_fq_params {
135 	DTSEC_RM_FQR_RX_WQ		= 1,
136 	DTSEC_RM_FQR_TX_WQ		= 1,
137 	DTSEC_RM_FQR_TX_CONF_WQ		= 1
138 };
139 /** @} */
140 
141 
142 /**
143  * @group dTSEC Frame Info routines.
144  * @{
145  */
146 void
147 dpaa_eth_fi_pool_free(struct dpaa_eth_softc *sc)
148 {
149 
150 	if (sc->sc_fi_zone != NULL)
151 		uma_zdestroy(sc->sc_fi_zone);
152 }
153 
154 int
155 dpaa_eth_fi_pool_init(struct dpaa_eth_softc *sc)
156 {
157 
158 	snprintf(sc->sc_fi_zname, sizeof(sc->sc_fi_zname), "%s: Frame Info",
159 	    device_get_nameunit(sc->sc_dev));
160 
161 	sc->sc_fi_zone = uma_zcreate(sc->sc_fi_zname,
162 	    sizeof(struct dpaa_eth_frame_info), NULL, NULL, NULL, NULL,
163 	    UMA_ALIGN_PTR, 0);
164 
165 	return (0);
166 }
167 
168 static struct dpaa_eth_frame_info *
169 dpaa_eth_fi_alloc(struct dpaa_eth_softc *sc)
170 {
171 	struct dpaa_eth_frame_info *fi;
172 
173 	fi = uma_zalloc(sc->sc_fi_zone, M_NOWAIT | M_ZERO);
174 
175 	return (fi);
176 }
177 
178 static void
179 dpaa_eth_fi_free(struct dpaa_eth_softc *sc, struct dpaa_eth_frame_info *fi)
180 {
181 
182 	uma_zfree(sc->sc_fi_zone, fi);
183 }
184 /** @} */
185 
186 
187 /**
188  * @group dTSEC FMan PORT routines.
189  * @{
190  */
191 int
192 dpaa_eth_fm_port_rx_init(struct dpaa_eth_softc *sc)
193 {
194 	struct fman_port_params params;
195 	int error;
196 
197 	params.dflt_fqid = sc->sc_rx_fqid;
198 	params.err_fqid = sc->sc_rx_fqid;
199 	params.rx_params.num_pools = 1;
200 	params.rx_params.bpools[0].bpid = bman_get_bpid(sc->sc_rx_pool);
201 	params.rx_params.bpools[0].size = MCLBYTES;
202 	error = FMAN_PORT_CONFIG(sc->sc_rx_port, &params);
203 	error = FMAN_PORT_INIT(sc->sc_rx_port);
204 	if (error != 0) {
205 		device_printf(sc->sc_dev, "couldn't initialize FM Port RX.\n");
206 		return (ENXIO);
207 	}
208 
209 	return (0);
210 }
211 
212 int
213 dpaa_eth_fm_port_tx_init(struct dpaa_eth_softc *sc)
214 {
215 	struct fman_port_params params;
216 	int error;
217 
218 	params.dflt_fqid = sc->sc_tx_conf_fqid;
219 	params.err_fqid = sc->sc_tx_conf_fqid;
220 
221 	error = FMAN_PORT_CONFIG(sc->sc_tx_port, &params);
222 	error = FMAN_PORT_INIT(sc->sc_tx_port);
223 	if (error != 0) {
224 		device_printf(sc->sc_dev, "couldn't initialize FM Port TX.\n");
225 		return (ENXIO);
226 	}
227 
228 	return (0);
229 }
230 /** @} */
231 
232 
233 /**
234  * @group dTSEC buffer pools routines.
235  * @{
236  */
237 static int
238 dpaa_eth_pool_rx_put_buffer(struct dpaa_eth_softc *sc, uint8_t *buffer,
239     void *context)
240 {
241 
242 	uma_zfree(sc->sc_rx_zone, buffer);
243 
244 	return (0);
245 }
246 
247 static int
248 dtsec_add_buffers(struct dpaa_eth_softc *sc, int count)
249 {
250 	struct bman_buffer bufs[8] = {};
251 	int err;
252 	int c;
253 
254 	while (count > 0) {
255 		c = min(8, count);
256 		for (int i = 0; i < c; i++) {
257 			void *b;
258 			vm_paddr_t pa;
259 
260 			b = uma_zalloc(sc->sc_rx_zone, M_NOWAIT);
261 			if (b == NULL)
262 				return (ENOMEM);
263 			pa = DMAP_TO_PHYS((vm_offset_t)b);
264 			bufs[i].buf_hi = (pa >> 32);
265 			bufs[i].buf_lo = (pa & 0xffffffff);
266 		}
267 
268 		err = bman_put_buffers(sc->sc_rx_pool, bufs, c);
269 		if (err != 0)
270 			return (err);
271 		count -= c;
272 	}
273 
274 	return (0);
275 }
276 
277 static void
278 dpaa_eth_pool_rx_depleted(void *h_App, bool in)
279 {
280 	struct dpaa_eth_softc *sc;
281 	unsigned int count;
282 
283 	sc = h_App;
284 
285 	if (!in)
286 		return;
287 
288 	while (1) {
289 		count = bman_count(sc->sc_rx_pool);
290 		if (count > DTSEC_RM_POOL_RX_HIGH_MARK)
291 			return;
292 
293 		/* Can only release 8 buffers at a time */
294 		count = min(DTSEC_RM_POOL_RX_HIGH_MARK - count + 8, 8);
295 		if (dtsec_add_buffers(sc, count) != 0)
296 			return;
297 	}
298 }
299 
300 void
301 dpaa_eth_pool_rx_free(struct dpaa_eth_softc *sc)
302 {
303 
304 	if (sc->sc_rx_pool != NULL)
305 		bman_pool_destroy(sc->sc_rx_pool);
306 
307 	if (sc->sc_rx_zone != NULL)
308 		uma_zdestroy(sc->sc_rx_zone);
309 
310 	free(sc->sc_rx_pool_check_cnt, M_DEVBUF);
311 	sc->sc_rx_pool_check_cnt = NULL;
312 }
313 
314 int
315 dpaa_eth_pool_rx_init(struct dpaa_eth_softc *sc)
316 {
317 
318 	/* MCLBYTES must be less than PAGE_SIZE */
319 	CTASSERT(MCLBYTES < PAGE_SIZE);
320 
321 	snprintf(sc->sc_rx_zname, sizeof(sc->sc_rx_zname), "%s: RX Buffers",
322 	    device_get_nameunit(sc->sc_dev));
323 
324 	sc->sc_rx_zone = uma_zcreate(sc->sc_rx_zname, MCLBYTES, NULL,
325 	    NULL, NULL, NULL, MCLBYTES - 1, 0);
326 
327 	sc->sc_rx_pool_check_cnt = malloc_aligned(
328 	    (mp_maxid + 1) * sizeof(struct dpaa_pcpu_cnt),
329 	    CACHE_LINE_SIZE, M_DEVBUF, M_WAITOK | M_ZERO);
330 
331 	sc->sc_rx_pool = bman_pool_create(&sc->sc_rx_bpid, MCLBYTES,
332 	    DTSEC_RM_POOL_RX_MAX_SIZE, DTSEC_RM_POOL_RX_LOW_MARK,
333 	    DTSEC_RM_POOL_RX_HIGH_MARK, 0, 0, dpaa_eth_pool_rx_depleted, sc);
334 	if (sc->sc_rx_pool == NULL) {
335 		device_printf(sc->sc_dev, "NULL rx pool  somehow\n");
336 		dpaa_eth_pool_rx_free(sc);
337 		return (EIO);
338 	}
339 
340 	dtsec_add_buffers(sc, DTSEC_RM_POOL_RX_HIGH_MARK);
341 
342 	return (0);
343 }
344 /** @} */
345 
346 
347 /**
348  * @group dTSEC Frame Queue Range routines.
349  * @{
350  */
351 static void
352 dpaa_eth_fq_mext_free(struct mbuf *m)
353 {
354 	struct dpaa_eth_softc *sc;
355 	void *buffer;
356 
357 	buffer = m->m_ext.ext_arg1;
358 	sc = m->m_ext.ext_arg2;
359 	/*
360 	 * Sloppy per-CPU sampling: no pin, no atomic.  A stray migration
361 	 * between the curcpu read and the increment can only mis-attribute
362 	 * one bump to the wrong CPU's counter; the sampling rate stays
363 	 * within the acceptable slop window.
364 	 */
365 	if ((++sc->sc_rx_pool_check_cnt[curcpu].cnt &
366 	    (DTSEC_RM_POOL_RX_CHECK_INTERVAL - 1)) == 0 &&
367 	    bman_count(sc->sc_rx_pool) > DTSEC_RM_POOL_RX_MAX_SIZE)
368 		dpaa_eth_pool_rx_put_buffer(sc, buffer, NULL);
369 	else
370 		bman_put_buffer(sc->sc_rx_pool,
371 		    DMAP_TO_PHYS((vm_offset_t)buffer), sc->sc_rx_bpid);
372 }
373 
374 static int
375 dpaa_eth_update_csum_flags(struct qman_fd *frame,
376     struct fman_parse_result *prs, struct mbuf *m)
377 {
378 	uint16_t l3r = be16toh(prs->l3r);
379 
380 	/* TODO: nested protocols? */
381 	if ((l3r & L3R_FIRST_IP_M) != 0) {
382 		m->m_pkthdr.csum_flags |= CSUM_L3_CALC;
383 		if ((l3r & L3R_FIRST_ERROR) == 0)
384 			m->m_pkthdr.csum_flags |= CSUM_L3_VALID;
385 	}
386 	if (frame->cmd_stat & DPAA_FD_RX_STATUS_L4CV) {
387 		m->m_pkthdr.csum_flags |= CSUM_L4_CALC;
388 		m->m_pkthdr.csum_data = 0xffff;
389 		if ((prs->l4r & L4R_TYPE_M) != 0 &&
390 		    (prs->l4r & L4R_ERR) == 0)
391 			m->m_pkthdr.csum_flags |= CSUM_L4_VALID;
392 	}
393 
394 	return (0);
395 }
396 
397 static int
398 dpaa_eth_fq_rx_callback(device_t portal, struct qman_fq *fq,
399     struct qman_fd *frame, void *app)
400 {
401 	struct dpaa_eth_softc *sc;
402 	struct mbuf *m;
403 	struct fman_internal_context *frame_ic;
404 	void *frame_va;
405 
406 	m = NULL;
407 	sc = app;
408 
409 	frame_va = DPAA_FD_GET_ADDR(frame);
410 	frame_ic = frame_va;	/* internal context at head of the frame */
411 	/* Only simple (single- or multi-) frames are supported. */
412 	KASSERT(frame->format == 0 || frame->format == 4,
413 	    ("%s(): Got unsupported frame format 0x%02X!", __func__,
414 	    frame->format));
415 
416 	if ((frame->cmd_stat & DPAA_FD_CMD_STAT_ERR_M) != 0) {
417 		device_printf(sc->sc_dev, "RX error: 0x%08X\n",
418 		    frame->cmd_stat);
419 		goto err;
420 	}
421 
422 	m = m_gethdr(M_NOWAIT, MT_HEADER);
423 	if (m == NULL)
424 		goto err;
425 
426 	if (frame->format == 0) {
427 		/* Single-frame format */
428 		m_extadd(m, (char *)frame_va + frame->offset, frame->length,
429 		    dpaa_eth_fq_mext_free, frame_va, sc, 0, EXT_NET_DRV);
430 	} else {
431 		struct dpaa_sgte *sgt =
432 		    (struct dpaa_sgte *)(char *)frame_va + frame->offset;
433 		/* Simple multi-frame format */
434 		for (int i = 0; i < DPAA_NUM_OF_SG_TABLE_ENTRY; i++) {
435 			if (sgt[i].length > 0)
436 				m_extadd(m, PHYS_TO_DMAP(sgt[i].addr),
437 				    sgt[i].length, dpaa_eth_fq_mext_free,
438 				    PHYS_TO_DMAP(sgt[i].addr), sc, 0,
439 				    EXT_NET_DRV);
440 			if (sgt[i].final)
441 				break;
442 		}
443 		/* Free the SGT buffer, it's no longer needed. */
444 		bman_put_buffer(sc->sc_rx_pool, frame->addr, sc->sc_rx_bpid);
445 	}
446 
447 	if (if_getcapenable(sc->sc_ifnet) & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6))
448 		dpaa_eth_update_csum_flags(frame, &frame_ic->prs, m);
449 
450 	m->m_pkthdr.rcvif = sc->sc_ifnet;
451 	m->m_len = frame->length;
452 	m_fixhdr(m);
453 
454 	if_input(sc->sc_ifnet, m);
455 
456 	return (1);
457 
458 err:
459 	bman_put_buffer(sc->sc_rx_pool, frame->addr, sc->sc_rx_bpid);
460 	if (m != NULL)
461 		m_freem(m);
462 
463 	return (1);
464 }
465 
466 static int
467 dpaa_eth_fq_tx_confirm_callback(device_t portal, struct qman_fq *fq,
468     struct qman_fd *frame, void *app)
469 {
470 	struct dpaa_eth_frame_info *fi;
471 	struct dpaa_eth_softc *sc;
472 
473 	sc = app;
474 
475 	if ((frame->cmd_stat & DPAA_FD_TX_STAT_ERR_M) != 0)
476 		device_printf(sc->sc_dev, "TX error: 0x%08X\n",
477 		    frame->cmd_stat);
478 
479 	/*
480 	 * We are storing struct dpaa_eth_frame_info in first entry
481 	 * of scatter-gather table.
482 	 */
483 	fi = (struct dpaa_eth_frame_info *)PHYS_TO_DMAP(frame->addr);
484 
485 	/* Free transmitted frame */
486 	m_freem(fi->fi_mbuf);
487 	dpaa_eth_fi_free(sc, fi);
488 
489 	/*
490 	 * Fast path: TX isn't backpressured, so there's nothing to
491 	 * restart.  Acquire load pairs with the release store on the
492 	 * TX path so a concurrent set of the flag is observed here.
493 	 */
494 	if (atomic_load_acq_int(&sc->sc_tx_fq_full) == 0)
495 		return (1);
496 
497 	/* Rate-limit the MC round-trip to detect drain-to-zero. */
498 	if ((sc->sc_tx_conf_check_cnt++ &
499 	    (DTSEC_TX_CONF_CHECK_INTERVAL - 1)) != 0)
500 		return (1);
501 	if (qman_fq_get_counter(sc->sc_tx_conf_fq, QMAN_COUNTER_FRAME) != 0)
502 		return (1);
503 
504 	DPAA_ETH_LOCK(sc);
505 	if (sc->sc_tx_fq_full) {
506 		atomic_store_rel_int(&sc->sc_tx_fq_full, 0);
507 		dpaa_eth_if_start_locked(sc);
508 	}
509 	DPAA_ETH_UNLOCK(sc);
510 
511 	return (1);
512 }
513 
514 void
515 dpaa_eth_fq_rx_free(struct dpaa_eth_softc *sc)
516 {
517 	int cpu;
518 
519 	if (sc->sc_rx_fq)
520 		qman_fq_free(sc->sc_rx_fq);
521 	if (sc->sc_rx_channel != 0) {
522 		CPU_FOREACH(cpu) {
523 			device_t portal = DPCPU_ID_GET(cpu, qman_affine_portal);
524 			QMAN_PORTAL_STATIC_DEQUEUE_RM_CHANNEL(portal,
525 			    sc->sc_rx_channel);
526 		}
527 		qman_free_channel(sc->sc_rx_channel);
528 	}
529 }
530 
531 int
532 dpaa_eth_fq_rx_init(struct dpaa_eth_softc *sc)
533 {
534 	void *fq;
535 	int error;
536 	int cpu;
537 
538 	/* Default Frame Queue */
539 	if (sc->sc_rx_channel == 0)
540 		sc->sc_rx_channel = qman_alloc_channel();
541 	/*
542 	 * Stash 1 cacheline of frame annotation (parse result / IC) and
543 	 * 1 of frame data head into the destination core's cache when
544 	 * QMan dequeues an RX frame -- the RX callback reads both.
545 	 */
546 	fq = qman_fq_create(1, sc->sc_rx_channel, DTSEC_RM_FQR_RX_WQ,
547 	    false, 0, false, false, true, false, 0, 0, 0, 1, 1);
548 	if (fq == NULL) {
549 		device_printf(sc->sc_dev,
550 		    "could not create default RX queue\n");
551 		return (EIO);
552 	}
553 
554 	CPU_FOREACH(cpu) {
555 		device_t portal = DPCPU_ID_GET(cpu, qman_affine_portal);
556 		QMAN_PORTAL_STATIC_DEQUEUE_CHANNEL(portal, sc->sc_rx_channel);
557 	}
558 
559 	sc->sc_rx_fq = fq;
560 	sc->sc_rx_fqid = qman_fq_get_fqid(fq);
561 
562 	error = qman_fq_register_cb(fq, dpaa_eth_fq_rx_callback, sc);
563 	if (error != 0) {
564 		device_printf(sc->sc_dev, "could not register RX callback\n");
565 		dpaa_eth_fq_rx_free(sc);
566 		return (EIO);
567 	}
568 
569 	return (0);
570 }
571 
572 void
573 dpaa_eth_fq_tx_free(struct dpaa_eth_softc *sc)
574 {
575 
576 	if (sc->sc_tx_fq)
577 		qman_fq_free(sc->sc_tx_fq);
578 
579 	if (sc->sc_tx_conf_fq)
580 		qman_fq_free(sc->sc_tx_conf_fq);
581 }
582 
583 int
584 dpaa_eth_fq_tx_init(struct dpaa_eth_softc *sc)
585 {
586 	int error;
587 	void *fq;
588 
589 	/* TX Frame Queue */
590 	fq = qman_fq_create(1, sc->sc_port_tx_qman_chan,
591 	    DTSEC_RM_FQR_TX_WQ, false, 0, false, false, true, false, 0, 0, 0,
592 	    0, 0);
593 	if (fq == NULL) {
594 		device_printf(sc->sc_dev, "could not create default TX queue"
595 		    "\n");
596 		return (EIO);
597 	}
598 
599 	sc->sc_tx_fq = fq;
600 
601 	if (sc->sc_rx_channel == 0)
602 		sc->sc_rx_channel = qman_alloc_channel();
603 	/* TX Confirmation Frame Queue */
604 	fq = qman_fq_create(1, sc->sc_rx_channel,
605 	    DTSEC_RM_FQR_TX_CONF_WQ, false, 0, false, false, true, false, 0, 0,
606 	    0, 0, 0);
607 	if (fq == NULL) {
608 		device_printf(sc->sc_dev, "could not create TX confirmation "
609 		    "queue\n");
610 		dpaa_eth_fq_tx_free(sc);
611 		return (EIO);
612 	}
613 
614 	sc->sc_tx_conf_fq = fq;
615 	sc->sc_tx_conf_fqid = qman_fq_get_fqid(fq);
616 
617 	error = qman_fq_register_cb(fq, dpaa_eth_fq_tx_confirm_callback, sc);
618 	if (error != 0) {
619 		device_printf(sc->sc_dev, "could not register TX confirmation "
620 		    "callback\n");
621 		dpaa_eth_fq_tx_free(sc);
622 		return (EIO);
623 	}
624 
625 	return (0);
626 }
627 /** @} */
628 
629 /* Returns the cmd_stat field for the frame descriptor */
630 static uint32_t
631 dpaa_eth_tx_add_csum(struct dpaa_eth_frame_info *fi)
632 {
633 	struct mbuf *m = fi->fi_mbuf;
634 	struct fman_parse_result *prs = &fi->fi_ic.prs;
635 	uint32_t csum_flags = m->m_pkthdr.csum_flags;
636 	uint8_t ether_size = ETHER_HDR_LEN;
637 
638 	if ((csum_flags & CSUM_FLAGS_TX) == 0)
639 		return (0);
640 
641 	if (m->m_flags & M_VLANTAG)
642 		ether_size += ETHER_VLAN_ENCAP_LEN;
643 	if (csum_flags & CSUM_IP)
644 		prs->l3r = L3R_FIRST_IPV4;
645 	if (csum_flags & CSUM_IP_UDP) {
646 		prs->l4r = L4R_TYPE_UDP;
647 		prs->l4_off = ether_size + sizeof(struct ip);
648 	} else if (csum_flags & CSUM_IP_TCP) {
649 		prs->l4r = L4R_TYPE_TCP;
650 		prs->l4_off = ether_size + sizeof(struct ip);
651 	} else if (csum_flags & CSUM_IP6_UDP) {
652 		prs->l3r = L3R_FIRST_IPV6;
653 		prs->l4r = L4R_TYPE_UDP;
654 		prs->l4_off = ether_size + sizeof(struct ip6_hdr);
655 	} else if (csum_flags & CSUM_IP6_TCP) {
656 		prs->l3r = L3R_FIRST_IPV6;
657 		prs->l4r = L4R_TYPE_TCP;
658 		prs->l4_off = ether_size + sizeof(struct ip6_hdr);
659 	}
660 
661 	prs->ip_off[0] = ether_size;
662 
663 	return (DPAA_FD_TX_CMD_RPD | DPAA_FD_TX_CMD_DTC);
664 }
665 
666 /**
667  * @group dTSEC IFnet routines.
668  * @{
669  */
670 void
671 dpaa_eth_if_start_locked(struct dpaa_eth_softc *sc)
672 {
673 	vm_size_t dsize, psize, ssize;
674 	struct dpaa_eth_frame_info *fi;
675 	unsigned int i;
676 	struct mbuf *m0, *m;
677 	vm_offset_t vaddr;
678 	struct dpaa_fd fd;
679 
680 	DPAA_ETH_LOCK_ASSERT(sc);
681 	/* TODO: IFF_DRV_OACTIVE */
682 
683 	if ((sc->sc_mii->mii_media_status & IFM_ACTIVE) == 0)
684 		return;
685 
686 	if ((if_getdrvflags(sc->sc_ifnet) & IFF_DRV_RUNNING) != IFF_DRV_RUNNING)
687 		return;
688 
689 	if (sc->sc_tx_fq_full)
690 		return;
691 
692 	while (!if_sendq_empty(sc->sc_ifnet)) {
693 		if ((sc->sc_tx_queue_check_cnt++ &
694 		    (DTSEC_MAX_TX_QUEUE_CHECK_INTERVAL - 1)) == 0 &&
695 		    qman_fq_get_counter(sc->sc_tx_fq, QMAN_COUNTER_FRAME) >=
696 		    DTSEC_MAX_TX_QUEUE_LEN) {
697 			atomic_store_rel_int(&sc->sc_tx_fq_full, 1);
698 			sc->sc_tx_queue_check_cnt = 0;
699 			return;
700 		}
701 
702 		fi = dpaa_eth_fi_alloc(sc);
703 		if (fi == NULL)
704 			return;
705 
706 		m0 = if_dequeue(sc->sc_ifnet);
707 		if (m0 == NULL) {
708 			dpaa_eth_fi_free(sc, fi);
709 			return;
710 		}
711 
712 		i = 0;
713 		m = m0;
714 		psize = 0;
715 		dsize = 0;
716 		fi->fi_mbuf = m0;
717 
718 		while (m && i < DPAA_NUM_OF_SG_TABLE_ENTRY) {
719 			if (m->m_len == 0)
720 				continue;
721 
722 			dsize = m->m_len;
723 			vaddr = (vm_offset_t)m->m_data;
724 			while (dsize > 0 && i < DPAA_NUM_OF_SG_TABLE_ENTRY) {
725 				ssize = PAGE_SIZE - (vaddr & PAGE_MASK);
726 				if (m->m_len < ssize)
727 					ssize = m->m_len;
728 
729 				fi->fi_sgt[i].addr = dpaa_eth_va_to_phys(vaddr);
730 				fi->fi_sgt[i].length = ssize;
731 
732 				fi->fi_sgt[i].extension = 0;
733 				fi->fi_sgt[i].final = 0;
734 				fi->fi_sgt[i].bpid = 0;
735 				fi->fi_sgt[i].offset = 0;
736 
737 				dsize -= ssize;
738 				vaddr += ssize;
739 				psize += ssize;
740 				i++;
741 			}
742 
743 			if (dsize > 0)
744 				break;
745 
746 			m = m->m_next;
747 		}
748 
749 		/* Check if SG table was constructed properly */
750 		if (m != NULL || dsize != 0) {
751 			dpaa_eth_fi_free(sc, fi);
752 			m_freem(m0);
753 			continue;
754 		}
755 
756 		fi->fi_sgt[i - 1].final = 1;
757 
758 		fd.addr = DMAP_TO_PHYS((vm_offset_t)fi);
759 		fd.length = psize;
760 		fd.format = DPAA_FD_FORMAT_SHORT_MBSF;
761 
762 		fd.liodn = 0;
763 		fd.bpid = 0;
764 		fd.eliodn = 0;
765 		fd.offset = offsetof(struct dpaa_eth_frame_info, fi_sgt);
766 		fd.cmd_stat = dpaa_eth_tx_add_csum(fi);
767 
768 		DPAA_ETH_UNLOCK(sc);
769 		if (qman_fq_enqueue(sc->sc_tx_fq, &fd) != 0) {
770 			dpaa_eth_fi_free(sc, fi);
771 			m_freem(m0);
772 		}
773 		DPAA_ETH_LOCK(sc);
774 	}
775 }
776 /** @} */
777