xref: /freebsd/sys/dev/dpaa/if_dtsec_rm.c (revision f126890ac5386406dadf7c4cfa9566cbb56537c5)
1 /*-
2  * Copyright (c) 2012 Semihalf.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/param.h>
28 #include <sys/systm.h>
29 #include <sys/kernel.h>
30 #include <sys/module.h>
31 #include <sys/bus.h>
32 #include <sys/rman.h>
33 #include <sys/malloc.h>
34 #include <sys/mbuf.h>
35 #include <sys/socket.h>
36 #include <sys/sysctl.h>
37 #include <sys/sockio.h>
38 
39 #include <net/ethernet.h>
40 #include <net/if.h>
41 #include <net/if_dl.h>
42 #include <net/if_media.h>
43 #include <net/if_types.h>
44 #include <net/if_arp.h>
45 
46 #include <dev/mii/mii.h>
47 #include <dev/mii/miivar.h>
48 
49 #include "miibus_if.h"
50 
51 #include <contrib/ncsw/inc/integrations/dpaa_integration_ext.h>
52 #include <contrib/ncsw/inc/Peripherals/fm_ext.h>
53 #include <contrib/ncsw/inc/Peripherals/fm_mac_ext.h>
54 #include <contrib/ncsw/inc/Peripherals/fm_port_ext.h>
55 #include <contrib/ncsw/inc/xx_ext.h>
56 
57 #include "fman.h"
58 #include "bman.h"
59 #include "qman.h"
60 #include "if_dtsec.h"
61 #include "if_dtsec_rm.h"
62 
63 
64 /**
65  * @group dTSEC RM private defines.
66  * @{
67  */
68 #define	DTSEC_BPOOLS_USED	(1)
69 #define	DTSEC_MAX_TX_QUEUE_LEN	256
70 
71 struct dtsec_rm_frame_info {
72 	struct mbuf			*fi_mbuf;
73 	t_DpaaSGTE			fi_sgt[DPAA_NUM_OF_SG_TABLE_ENTRY];
74 };
75 
76 enum dtsec_rm_pool_params {
77 	DTSEC_RM_POOL_RX_LOW_MARK	= 16,
78 	DTSEC_RM_POOL_RX_HIGH_MARK	= 64,
79 	DTSEC_RM_POOL_RX_MAX_SIZE	= 256,
80 
81 	DTSEC_RM_POOL_FI_LOW_MARK	= 16,
82 	DTSEC_RM_POOL_FI_HIGH_MARK	= 64,
83 	DTSEC_RM_POOL_FI_MAX_SIZE	= 256,
84 };
85 
86 #define	DTSEC_RM_FQR_RX_CHANNEL		e_QM_FQ_CHANNEL_POOL1
87 #define	DTSEC_RM_FQR_TX_CONF_CHANNEL	e_QM_FQ_CHANNEL_SWPORTAL0
88 enum dtsec_rm_fqr_params {
89 	DTSEC_RM_FQR_RX_WQ		= 1,
90 	DTSEC_RM_FQR_TX_WQ		= 1,
91 	DTSEC_RM_FQR_TX_CONF_WQ		= 1
92 };
93 /** @} */
94 
95 
96 /**
97  * @group dTSEC Frame Info routines.
98  * @{
99  */
100 void
101 dtsec_rm_fi_pool_free(struct dtsec_softc *sc)
102 {
103 
104 	if (sc->sc_fi_zone != NULL)
105 		uma_zdestroy(sc->sc_fi_zone);
106 }
107 
108 int
109 dtsec_rm_fi_pool_init(struct dtsec_softc *sc)
110 {
111 
112 	snprintf(sc->sc_fi_zname, sizeof(sc->sc_fi_zname), "%s: Frame Info",
113 	    device_get_nameunit(sc->sc_dev));
114 
115 	sc->sc_fi_zone = uma_zcreate(sc->sc_fi_zname,
116 	    sizeof(struct dtsec_rm_frame_info), NULL, NULL, NULL, NULL,
117 	    UMA_ALIGN_PTR, 0);
118 	if (sc->sc_fi_zone == NULL)
119 		return (EIO);
120 
121 	return (0);
122 }
123 
124 static struct dtsec_rm_frame_info *
125 dtsec_rm_fi_alloc(struct dtsec_softc *sc)
126 {
127 	struct dtsec_rm_frame_info *fi;
128 
129 	fi = uma_zalloc(sc->sc_fi_zone, M_NOWAIT);
130 
131 	return (fi);
132 }
133 
134 static void
135 dtsec_rm_fi_free(struct dtsec_softc *sc, struct dtsec_rm_frame_info *fi)
136 {
137 
138 	uma_zfree(sc->sc_fi_zone, fi);
139 }
140 /** @} */
141 
142 
143 /**
144  * @group dTSEC FMan PORT routines.
145  * @{
146  */
147 int
148 dtsec_rm_fm_port_rx_init(struct dtsec_softc *sc, int unit)
149 {
150 	t_FmPortParams params;
151 	t_FmPortRxParams *rx_params;
152 	t_FmExtPools *pool_params;
153 	t_Error error;
154 
155 	memset(&params, 0, sizeof(params));
156 
157 	params.baseAddr = sc->sc_fm_base + sc->sc_port_rx_hw_id;
158 	params.h_Fm = sc->sc_fmh;
159 	params.portType = dtsec_fm_port_rx_type(sc->sc_eth_dev_type);
160 	params.portId = sc->sc_eth_id;
161 	params.independentModeEnable = false;
162 	params.liodnBase = FM_PORT_LIODN_BASE;
163 	params.f_Exception = dtsec_fm_port_rx_exception_callback;
164 	params.h_App = sc;
165 
166 	rx_params = &params.specificParams.rxParams;
167 	rx_params->errFqid = sc->sc_rx_fqid;
168 	rx_params->dfltFqid = sc->sc_rx_fqid;
169 	rx_params->liodnOffset = 0;
170 
171 	pool_params = &rx_params->extBufPools;
172 	pool_params->numOfPoolsUsed = DTSEC_BPOOLS_USED;
173 	pool_params->extBufPool->id = sc->sc_rx_bpid;
174 	pool_params->extBufPool->size = FM_PORT_BUFFER_SIZE;
175 
176 	sc->sc_rxph = FM_PORT_Config(&params);
177 	if (sc->sc_rxph == NULL) {
178 		device_printf(sc->sc_dev, "couldn't configure FM Port RX.\n");
179 		return (ENXIO);
180 	}
181 
182 	error = FM_PORT_Init(sc->sc_rxph);
183 	if (error != E_OK) {
184 		device_printf(sc->sc_dev, "couldn't initialize FM Port RX.\n");
185 		FM_PORT_Free(sc->sc_rxph);
186 		return (ENXIO);
187 	}
188 
189 	if (bootverbose)
190 		device_printf(sc->sc_dev, "RX hw port 0x%02x initialized.\n",
191 		    sc->sc_port_rx_hw_id);
192 
193 	return (0);
194 }
195 
196 int
197 dtsec_rm_fm_port_tx_init(struct dtsec_softc *sc, int unit)
198 {
199 	t_FmPortParams params;
200 	t_FmPortNonRxParams *tx_params;
201 	t_Error error;
202 
203 	memset(&params, 0, sizeof(params));
204 
205 	params.baseAddr = sc->sc_fm_base + sc->sc_port_tx_hw_id;
206 	params.h_Fm = sc->sc_fmh;
207 	params.portType = dtsec_fm_port_tx_type(sc->sc_eth_dev_type);
208 	params.portId = sc->sc_eth_id;
209 	params.independentModeEnable = false;
210 	params.liodnBase = FM_PORT_LIODN_BASE;
211 	params.f_Exception = dtsec_fm_port_tx_exception_callback;
212 	params.h_App = sc;
213 
214 	tx_params = &params.specificParams.nonRxParams;
215 	tx_params->errFqid = sc->sc_tx_conf_fqid;
216 	tx_params->dfltFqid = sc->sc_tx_conf_fqid;
217 	tx_params->qmChannel = sc->sc_port_tx_qman_chan;
218 #ifdef FM_OP_PARTITION_ERRATA_FMANx8
219 	tx_params->opLiodnOffset = 0;
220 #endif
221 
222 	sc->sc_txph = FM_PORT_Config(&params);
223 	if (sc->sc_txph == NULL) {
224 		device_printf(sc->sc_dev, "couldn't configure FM Port TX.\n");
225 		return (ENXIO);
226 	}
227 
228 	error = FM_PORT_Init(sc->sc_txph);
229 	if (error != E_OK) {
230 		device_printf(sc->sc_dev, "couldn't initialize FM Port TX.\n");
231 		FM_PORT_Free(sc->sc_txph);
232 		return (ENXIO);
233 	}
234 
235 	if (bootverbose)
236 		device_printf(sc->sc_dev, "TX hw port 0x%02x initialized.\n",
237 		    sc->sc_port_tx_hw_id);
238 
239 	return (0);
240 }
241 /** @} */
242 
243 
244 /**
245  * @group dTSEC buffer pools routines.
246  * @{
247  */
248 static t_Error
249 dtsec_rm_pool_rx_put_buffer(t_Handle h_BufferPool, uint8_t *buffer,
250     t_Handle context)
251 {
252 	struct dtsec_softc *sc;
253 
254 	sc = h_BufferPool;
255 	uma_zfree(sc->sc_rx_zone, buffer);
256 
257 	return (E_OK);
258 }
259 
260 static uint8_t *
261 dtsec_rm_pool_rx_get_buffer(t_Handle h_BufferPool, t_Handle *context)
262 {
263 	struct dtsec_softc *sc;
264 	uint8_t *buffer;
265 
266 	sc = h_BufferPool;
267 	buffer = uma_zalloc(sc->sc_rx_zone, M_NOWAIT);
268 
269 	return (buffer);
270 }
271 
272 static void
273 dtsec_rm_pool_rx_depleted(t_Handle h_App, bool in)
274 {
275 	struct dtsec_softc *sc;
276 	unsigned int count;
277 
278 	sc = h_App;
279 
280 	if (!in)
281 		return;
282 
283 	while (1) {
284 		count = bman_count(sc->sc_rx_pool);
285 		if (count > DTSEC_RM_POOL_RX_HIGH_MARK)
286 			return;
287 
288 		bman_pool_fill(sc->sc_rx_pool, DTSEC_RM_POOL_RX_HIGH_MARK);
289 	}
290 }
291 
292 void
293 dtsec_rm_pool_rx_free(struct dtsec_softc *sc)
294 {
295 
296 	if (sc->sc_rx_pool != NULL)
297 		bman_pool_destroy(sc->sc_rx_pool);
298 
299 	if (sc->sc_rx_zone != NULL)
300 		uma_zdestroy(sc->sc_rx_zone);
301 }
302 
303 int
304 dtsec_rm_pool_rx_init(struct dtsec_softc *sc)
305 {
306 
307 	/* FM_PORT_BUFFER_SIZE must be less than PAGE_SIZE */
308 	CTASSERT(FM_PORT_BUFFER_SIZE < PAGE_SIZE);
309 
310 	snprintf(sc->sc_rx_zname, sizeof(sc->sc_rx_zname), "%s: RX Buffers",
311 	    device_get_nameunit(sc->sc_dev));
312 
313 	sc->sc_rx_zone = uma_zcreate(sc->sc_rx_zname, FM_PORT_BUFFER_SIZE, NULL,
314 	    NULL, NULL, NULL, FM_PORT_BUFFER_SIZE - 1, 0);
315 	if (sc->sc_rx_zone == NULL)
316 		return (EIO);
317 
318 	sc->sc_rx_pool = bman_pool_create(&sc->sc_rx_bpid, FM_PORT_BUFFER_SIZE,
319 	    0, 0, DTSEC_RM_POOL_RX_MAX_SIZE, dtsec_rm_pool_rx_get_buffer,
320 	    dtsec_rm_pool_rx_put_buffer, DTSEC_RM_POOL_RX_LOW_MARK,
321 	    DTSEC_RM_POOL_RX_HIGH_MARK, 0, 0, dtsec_rm_pool_rx_depleted, sc, NULL,
322 	    NULL);
323 	if (sc->sc_rx_pool == NULL) {
324 		device_printf(sc->sc_dev, "NULL rx pool  somehow\n");
325 		dtsec_rm_pool_rx_free(sc);
326 		return (EIO);
327 	}
328 
329 	return (0);
330 }
331 /** @} */
332 
333 
334 /**
335  * @group dTSEC Frame Queue Range routines.
336  * @{
337  */
338 static void
339 dtsec_rm_fqr_mext_free(struct mbuf *m)
340 {
341 	struct dtsec_softc *sc;
342 	void *buffer;
343 
344 	buffer = m->m_ext.ext_arg1;
345 	sc = m->m_ext.ext_arg2;
346 	if (bman_count(sc->sc_rx_pool) <= DTSEC_RM_POOL_RX_MAX_SIZE)
347 		bman_put_buffer(sc->sc_rx_pool, buffer);
348 	else
349 		dtsec_rm_pool_rx_put_buffer(sc, buffer, NULL);
350 }
351 
352 static e_RxStoreResponse
353 dtsec_rm_fqr_rx_callback(t_Handle app, t_Handle fqr, t_Handle portal,
354     uint32_t fqid_off, t_DpaaFD *frame)
355 {
356 	struct dtsec_softc *sc;
357 	struct mbuf *m;
358 	void *frame_va;
359 
360 	m = NULL;
361 	sc = app;
362 
363 	frame_va = DPAA_FD_GET_ADDR(frame);
364 	KASSERT(DPAA_FD_GET_FORMAT(frame) == e_DPAA_FD_FORMAT_TYPE_SHORT_SBSF,
365 	    ("%s(): Got unsupported frame format 0x%02X!", __func__,
366 	    DPAA_FD_GET_FORMAT(frame)));
367 
368 	KASSERT(DPAA_FD_GET_OFFSET(frame) == 0,
369 	    ("%s(): Only offset 0 is supported!", __func__));
370 
371 	if (DPAA_FD_GET_STATUS(frame) != 0) {
372 		device_printf(sc->sc_dev, "RX error: 0x%08X\n",
373 		    DPAA_FD_GET_STATUS(frame));
374 		goto err;
375 	}
376 
377 	m = m_gethdr(M_NOWAIT, MT_HEADER);
378 	if (m == NULL)
379 		goto err;
380 
381 	m_extadd(m, frame_va, FM_PORT_BUFFER_SIZE,
382 	    dtsec_rm_fqr_mext_free, frame_va, sc, 0,
383 	    EXT_NET_DRV);
384 
385 	m->m_pkthdr.rcvif = sc->sc_ifnet;
386 	m->m_len = DPAA_FD_GET_LENGTH(frame);
387 	m_fixhdr(m);
388 
389 	if_input(sc->sc_ifnet, m);
390 
391 	return (e_RX_STORE_RESPONSE_CONTINUE);
392 
393 err:
394 	bman_put_buffer(sc->sc_rx_pool, frame_va);
395 	if (m != NULL)
396 		m_freem(m);
397 
398 	return (e_RX_STORE_RESPONSE_CONTINUE);
399 }
400 
401 static e_RxStoreResponse
402 dtsec_rm_fqr_tx_confirm_callback(t_Handle app, t_Handle fqr, t_Handle portal,
403     uint32_t fqid_off, t_DpaaFD *frame)
404 {
405 	struct dtsec_rm_frame_info *fi;
406 	struct dtsec_softc *sc;
407 	unsigned int qlen;
408 	t_DpaaSGTE *sgt0;
409 
410 	sc = app;
411 
412 	if (DPAA_FD_GET_STATUS(frame) != 0)
413 		device_printf(sc->sc_dev, "TX error: 0x%08X\n",
414 		    DPAA_FD_GET_STATUS(frame));
415 
416 	/*
417 	 * We are storing struct dtsec_rm_frame_info in first entry
418 	 * of scatter-gather table.
419 	 */
420 	sgt0 = DPAA_FD_GET_ADDR(frame);
421 	fi = DPAA_SGTE_GET_ADDR(sgt0);
422 
423 	/* Free transmitted frame */
424 	m_freem(fi->fi_mbuf);
425 	dtsec_rm_fi_free(sc, fi);
426 
427 	qlen = qman_fqr_get_counter(sc->sc_tx_conf_fqr, 0,
428 	    e_QM_FQR_COUNTERS_FRAME);
429 
430 	if (qlen == 0) {
431 		DTSEC_LOCK(sc);
432 
433 		if (sc->sc_tx_fqr_full) {
434 			sc->sc_tx_fqr_full = 0;
435 			dtsec_rm_if_start_locked(sc);
436 		}
437 
438 		DTSEC_UNLOCK(sc);
439 	}
440 
441 	return (e_RX_STORE_RESPONSE_CONTINUE);
442 }
443 
444 void
445 dtsec_rm_fqr_rx_free(struct dtsec_softc *sc)
446 {
447 
448 	if (sc->sc_rx_fqr)
449 		qman_fqr_free(sc->sc_rx_fqr);
450 }
451 
452 int
453 dtsec_rm_fqr_rx_init(struct dtsec_softc *sc)
454 {
455 	t_Error error;
456 	t_Handle fqr;
457 
458 	/* Default Frame Queue */
459 	fqr = qman_fqr_create(1, DTSEC_RM_FQR_RX_CHANNEL, DTSEC_RM_FQR_RX_WQ,
460 	    false, 0, false, false, true, false, 0, 0, 0);
461 	if (fqr == NULL) {
462 		device_printf(sc->sc_dev, "could not create default RX queue"
463 		    "\n");
464 		return (EIO);
465 	}
466 
467 	sc->sc_rx_fqr = fqr;
468 	sc->sc_rx_fqid = qman_fqr_get_base_fqid(fqr);
469 
470 	error = qman_fqr_register_cb(fqr, dtsec_rm_fqr_rx_callback, sc);
471 	if (error != E_OK) {
472 		device_printf(sc->sc_dev, "could not register RX callback\n");
473 		dtsec_rm_fqr_rx_free(sc);
474 		return (EIO);
475 	}
476 
477 	return (0);
478 }
479 
480 void
481 dtsec_rm_fqr_tx_free(struct dtsec_softc *sc)
482 {
483 
484 	if (sc->sc_tx_fqr)
485 		qman_fqr_free(sc->sc_tx_fqr);
486 
487 	if (sc->sc_tx_conf_fqr)
488 		qman_fqr_free(sc->sc_tx_conf_fqr);
489 }
490 
491 int
492 dtsec_rm_fqr_tx_init(struct dtsec_softc *sc)
493 {
494 	t_Error error;
495 	t_Handle fqr;
496 
497 	/* TX Frame Queue */
498 	fqr = qman_fqr_create(1, sc->sc_port_tx_qman_chan,
499 	    DTSEC_RM_FQR_TX_WQ, false, 0, false, false, true, false, 0, 0, 0);
500 	if (fqr == NULL) {
501 		device_printf(sc->sc_dev, "could not create default TX queue"
502 		    "\n");
503 		return (EIO);
504 	}
505 
506 	sc->sc_tx_fqr = fqr;
507 
508 	/* TX Confirmation Frame Queue */
509 	fqr = qman_fqr_create(1, DTSEC_RM_FQR_TX_CONF_CHANNEL,
510 	    DTSEC_RM_FQR_TX_CONF_WQ, false, 0, false, false, true, false, 0, 0,
511 	    0);
512 	if (fqr == NULL) {
513 		device_printf(sc->sc_dev, "could not create TX confirmation "
514 		    "queue\n");
515 		dtsec_rm_fqr_tx_free(sc);
516 		return (EIO);
517 	}
518 
519 	sc->sc_tx_conf_fqr = fqr;
520 	sc->sc_tx_conf_fqid = qman_fqr_get_base_fqid(fqr);
521 
522 	error = qman_fqr_register_cb(fqr, dtsec_rm_fqr_tx_confirm_callback, sc);
523 	if (error != E_OK) {
524 		device_printf(sc->sc_dev, "could not register TX confirmation "
525 		    "callback\n");
526 		dtsec_rm_fqr_tx_free(sc);
527 		return (EIO);
528 	}
529 
530 	return (0);
531 }
532 /** @} */
533 
534 
535 /**
536  * @group dTSEC IFnet routines.
537  * @{
538  */
539 void
540 dtsec_rm_if_start_locked(struct dtsec_softc *sc)
541 {
542 	vm_size_t dsize, psize, ssize;
543 	struct dtsec_rm_frame_info *fi;
544 	unsigned int qlen, i;
545 	struct mbuf *m0, *m;
546 	vm_offset_t vaddr;
547 	t_DpaaFD fd;
548 
549 	DTSEC_LOCK_ASSERT(sc);
550 	/* TODO: IFF_DRV_OACTIVE */
551 
552 	if ((sc->sc_mii->mii_media_status & IFM_ACTIVE) == 0)
553 		return;
554 
555 	if ((if_getdrvflags(sc->sc_ifnet) & IFF_DRV_RUNNING) != IFF_DRV_RUNNING)
556 		return;
557 
558 	while (!if_sendq_empty(sc->sc_ifnet)) {
559 		/* Check length of the TX queue */
560 		qlen = qman_fqr_get_counter(sc->sc_tx_fqr, 0,
561 		    e_QM_FQR_COUNTERS_FRAME);
562 
563 		if (qlen >= DTSEC_MAX_TX_QUEUE_LEN) {
564 			sc->sc_tx_fqr_full = 1;
565 			return;
566 		}
567 
568 		fi = dtsec_rm_fi_alloc(sc);
569 		if (fi == NULL)
570 			return;
571 
572 		m0 = if_dequeue(sc->sc_ifnet);
573 		if (m0 == NULL) {
574 			dtsec_rm_fi_free(sc, fi);
575 			return;
576 		}
577 
578 		i = 0;
579 		m = m0;
580 		psize = 0;
581 		dsize = 0;
582 		fi->fi_mbuf = m0;
583 		while (m && i < DPAA_NUM_OF_SG_TABLE_ENTRY) {
584 			if (m->m_len == 0)
585 				continue;
586 
587 			/*
588 			 * First entry in scatter-gather table is used to keep
589 			 * pointer to frame info structure.
590 			 */
591 			DPAA_SGTE_SET_ADDR(&fi->fi_sgt[i], (void *)fi);
592 			DPAA_SGTE_SET_LENGTH(&fi->fi_sgt[i], 0);
593 
594 			DPAA_SGTE_SET_EXTENSION(&fi->fi_sgt[i], 0);
595 			DPAA_SGTE_SET_FINAL(&fi->fi_sgt[i], 0);
596 			DPAA_SGTE_SET_BPID(&fi->fi_sgt[i], 0);
597 			DPAA_SGTE_SET_OFFSET(&fi->fi_sgt[i], 0);
598 			i++;
599 
600 			dsize = m->m_len;
601 			vaddr = (vm_offset_t)m->m_data;
602 			while (dsize > 0 && i < DPAA_NUM_OF_SG_TABLE_ENTRY) {
603 				ssize = PAGE_SIZE - (vaddr & PAGE_MASK);
604 				if (m->m_len < ssize)
605 					ssize = m->m_len;
606 
607 				DPAA_SGTE_SET_ADDR(&fi->fi_sgt[i],
608 				    (void *)vaddr);
609 				DPAA_SGTE_SET_LENGTH(&fi->fi_sgt[i], ssize);
610 
611 				DPAA_SGTE_SET_EXTENSION(&fi->fi_sgt[i], 0);
612 				DPAA_SGTE_SET_FINAL(&fi->fi_sgt[i], 0);
613 				DPAA_SGTE_SET_BPID(&fi->fi_sgt[i], 0);
614 				DPAA_SGTE_SET_OFFSET(&fi->fi_sgt[i], 0);
615 
616 				dsize -= ssize;
617 				vaddr += ssize;
618 				psize += ssize;
619 				i++;
620 			}
621 
622 			if (dsize > 0)
623 				break;
624 
625 			m = m->m_next;
626 		}
627 
628 		/* Check if SG table was constructed properly */
629 		if (m != NULL || dsize != 0) {
630 			dtsec_rm_fi_free(sc, fi);
631 			m_freem(m0);
632 			continue;
633 		}
634 
635 		DPAA_SGTE_SET_FINAL(&fi->fi_sgt[i-1], 1);
636 
637 		DPAA_FD_SET_ADDR(&fd, fi->fi_sgt);
638 		DPAA_FD_SET_LENGTH(&fd, psize);
639 		DPAA_FD_SET_FORMAT(&fd, e_DPAA_FD_FORMAT_TYPE_SHORT_MBSF);
640 
641 		fd.liodn = 0;
642 		fd.bpid = 0;
643 		fd.elion = 0;
644 		DPAA_FD_SET_OFFSET(&fd, 0);
645 		DPAA_FD_SET_STATUS(&fd, 0);
646 
647 		DTSEC_UNLOCK(sc);
648 		if (qman_fqr_enqueue(sc->sc_tx_fqr, 0, &fd) != E_OK) {
649 			dtsec_rm_fi_free(sc, fi);
650 			m_freem(m0);
651 		}
652 		DTSEC_LOCK(sc);
653 	}
654 }
655 /** @} */
656