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