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