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