xref: /freebsd/sys/dev/dpaa/qman.c (revision 22649d4dba730d46244fd2dff4fd174903c8379f)
1 /*
2  * Copyright (c) 2026 Justin Hibbits
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  */
6 /*-
7  * Copyright (c) 2011-2012 Semihalf.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/bus.h>
36 #include <sys/lock.h>
37 #include <sys/malloc.h>
38 #include <sys/module.h>
39 #include <sys/mutex.h>
40 #include <sys/proc.h>
41 #include <sys/pcpu.h>
42 #include <sys/rman.h>
43 #include <sys/sched.h>
44 #include <sys/smp.h>
45 
46 #include <machine/bus.h>
47 #include <machine/resource.h>
48 #include <machine/tlb.h>
49 
50 #include "dpaa_common.h"
51 #include "portals.h"
52 #include "qman.h"
53 #include "qman_var.h"
54 #include "qman_portal_if.h"
55 
56 /* Registers */
57 #define	QCSP_IO_CFG(n)		(0x004 + (n) * 16)
58 #define	  IO_CFG_SDEST_M	  0x00ff0000
59 #define	  IO_CFG_SDEST_S	  16
60 #define	QMAN_DCP_CFG(n)		(0x300 + (n) * 0x10)
61 #define	  DCP_CFG_ED		  0x00000100
62 #define	  DCP_CFG_ED_3		  0x00001000
63 #define	QMAN_PFDR_FP_LWIT	0x410
64 #define	QMAN_PFDR_CFG		0x414
65 #define	QMAN_SFDR_CFG		0x500
66 #define	QMAN_MCR		0xb00
67 #define	  MCR_INIT_PFDR		  0x01000000
68 #define	  MCR_READ_PFDR		  0x02000000
69 #define	  MCR_READ_SFDR		  0x03000000
70 #define	  MCR_QUERY_FQD_FILL	  0x10000000
71 #define	  MCR_QUERY_FQD_TAGS	  0x11000000
72 #define	  MCR_QUERY_FQD_CACHE	  0x12000000
73 #define	  MCR_QUERY_WQ		  0x20000000
74 #define	  MCR_RSLT_OK		  0xf0000000
75 #define	  MCR_RSLT_OK_DATA	  0xf1000000
76 #define	  MCR_RSLT_ABRT_INV	  0xf4000000
77 #define	  MCR_RSLT_ABRT_DIS	  0xf8000000
78 #define	  MCR_RSLT_ABRT_IDX	  0xff000000
79 #define	  MCR_RSLT_ABRT_MASK	  0xff000000
80 #define	QMAN_MCP0		0xb04
81 #define	QMAN_MCP1		0xb08
82 #define	QMAN_IP_REV_1		0xbf8
83 #define	  IP_MJ_M		  0x0000ff00
84 #define	  IP_MJ_S		  8
85 #define	  IP_MN_M		  0x000000ff
86 #define	QMAN_FQD_BARE		0xc00
87 #define	QMAN_FQD_BAR		0xc04
88 #define	QMAN_FQD_AR		0xc10
89 #define	  AR_EN			0x80000000
90 #define	QMAN_PFDR_BARE		0xc20
91 #define	QMAN_PFDR_BAR		0xc24
92 #define	QMAN_PFDR_AR		0xc30
93 #define	QMAN_QCSP_BARE		0xc80
94 #define	QMAN_QCSP_BAR		0xc84
95 #define	QMAN_QCSP_AR		0xc90
96 #define	QMAN_CI_SCHED_CFG	0xd00
97 #define	  CI_SCHED_CFG_SW	  0x80000000
98 #define	  CI_SCHED_CFG_SRCCIV	  0x04000000	/* Recommended */
99 #define	  CI_SCHED_CFG_SRQ_W_M	  0x00000700
100 #define	  CI_SCHED_CFG_SRQ_W_S	  8
101 #define	  CI_SCHED_CFG_RW_W_M	  0x00000070
102 #define	  CI_SCHED_CFG_RW_W_S	  4
103 #define	  CI_SCHED_CFG_BMAN_W_M	  0x00000007
104 #define	QMAN_ERR_ISR		0xe00
105 #define	QMAN_ERR_IER		0xe04
106 #define	QCSP_IO_CFG_3(n)	(0x1004 + (n) * 16)
107 
108 /* Software portals.  Cache-inhibited registers */
109 
110 #define	QCSP_DQRR_PDQCR		0x05c
111 
112 /* Software portals.  Cache-enabled registers */
113 
114 /*
115  * Context_A stashing config.
116  */
117 #define	QM_STASHING_EXCL_ANNOTATION	0x04
118 #define	QM_STASHING_EXCL_DATA		0x02
119 #define	QM_STASHING_EXCL_CONTEXT	0x01
120 
121 #define	QMAN_CHANNEL_POOL1_REV1		0x21
122 #define	QMAN_CHANNEL_POOL1_REV3		0x401
123 
124 #define	QMAN_PFDR_MAX			0xfffeff
125 
126 /* P1023 has only 3 pool channels, but we don't support that SoC. */
127 #define	QMAN_POOL_CHANNELS		15
128 
129 /* P1023 only supports 64 congestion groups... */
130 #define	QMAN_CGRS			256
131 
132 static struct qman_softc *qman_sc;
133 
134 static MALLOC_DEFINE(M_QMAN, "qman", "DPAA Queue Manager structures");
135 
136 int qman_channel_base;
137 int qman_total_fqids;
138 struct qman_fq **qman_fq_list;
139 
140 /* Entries sorted right-to-left in bit order of the ISR */
141 static const char * const qman_errors[] = {
142 	"Invalid enqueue queue",
143 	"Invalid enqueue channel!",
144 	"Invalid enqueue state",
145 	"Invalid enqueue overflow",
146 	"Invalid enqueue configuration",
147 	NULL,
148 	NULL,
149 	NULL,
150 	"Invalid dequeue queue",
151 	"Invalid dequeue source",
152 	"Invalid dequeue FQ",
153 	"Invalid dequeue direct connect portal",
154 	NULL,
155 	NULL,
156 	NULL,
157 	NULL,
158 	"Invalid command verb",
159 	"Invalid FQ flow control state",
160 	NULL,
161 	NULL,
162 	NULL,
163 	NULL,
164 	NULL,
165 	"Insufficient free PFDRs",
166 	"Single-bit ECC error",
167 	"Multi-bit ECC error",
168 	"PFDR low watermark",
169 	"Invalid target transaction",
170 	"Initiator data error",
171 	NULL,
172 	NULL
173 };
174 
175 static void
176 qman_isr(void *arg)
177 {
178 	struct qman_softc *sc = arg;
179 	uint32_t ier, isr, isr_bit;
180 	int i;
181 
182 	ier = bus_read_4(sc->sc_rres, QMAN_ERR_IER);
183 	isr = bus_read_4(sc->sc_rres, QMAN_ERR_ISR);
184 
185 	if ((ier & isr) == 0)
186 		return;
187 
188 	isr_bit = (isr & ier);
189 	for (i = 0; isr_bit != 0; i++, isr_bit >>= 1) {
190 		if (isr_bit & 1)
191 			device_printf(sc->sc_dev, "%s", qman_errors[i]);
192 	}
193 
194 	bus_write_4(sc->sc_rres, QMAN_ERR_ISR, isr);
195 }
196 
197 
198 /* Set up reserved memory configuration for PFDR and FQD, per `off`. */
199 static int
200 qman_set_memory(struct qman_softc *sc, vm_paddr_t pa,
201     vm_size_t size, bus_size_t off)
202 {
203 	uint32_t bar, bare;
204 	vm_paddr_t old_bar;
205 
206 	/*
207 	 * Register offsets:
208 	 * 0 - BARE
209 	 * 4 - BAR
210 	 * 0x10 - AR
211 	 */
212 	bare = bus_read_4(sc->sc_rres, off);
213 	bar = bus_read_4(sc->sc_rres, off + 4);
214 	old_bar = (vm_paddr_t)bare << 32 | bar;
215 
216 	if (old_bar != 0 && old_bar != pa) {
217 		device_printf(sc->sc_dev, "QMan BAR already initialized!\n");
218 		return (ENOMEM);
219 	} else if (old_bar == pa)
220 		return (EEXIST);
221 
222 	/*
223 	 * Zero the memory and flush cache through DMAP. QMan accesses the
224 	 * memory as non-coherent.
225 	 */
226 	memset((void *)PHYS_TO_DMAP(pa), 0, size);
227 	cpu_flush_dcache((void *)PHYS_TO_DMAP(pa), size);
228 
229 	bus_write_4(sc->sc_rres, off, pa >> 32);
230 	bus_write_4(sc->sc_rres, off + 4, (uint32_t)pa);
231 	bus_write_4(sc->sc_rres, off + 0x10, AR_EN | (ilog2(size) - 1));
232 
233 	return (0);
234 }
235 
236 /*
237  * Set up PFDR structures.  Some things to keep in mind:
238  * - npfdr is the total number of PFDRs in the private memory.  PFDRs are 64
239  *   bytes in size, so npfdr is (pfdr_sz/64).
240  * - PFDR 0-7 are reserved, so the base starts at 8, not 0, so we adjust
241  *   internally.
242  * - The second parameter is the last PFDR, not the number of PFDRs, so needs to
243  *   be adjusted down one more, so subtract 9.
244  */
245 static int
246 qman_setup_pfdr(struct qman_softc *sc, int npfdr)
247 {
248 	uint32_t res;
249 
250 	npfdr = min(npfdr, QMAN_PFDR_MAX);
251 	bus_write_4(sc->sc_rres, QMAN_MCP0, 8);
252 	bus_write_4(sc->sc_rres, QMAN_MCP1, npfdr - 9);
253 	bus_write_4(sc->sc_rres, QMAN_MCR, MCR_INIT_PFDR);
254 
255 	for (int timeout = 100000; timeout > 0; timeout--) {
256 		DELAY(1);
257 		res = bus_read_4(sc->sc_rres, QMAN_MCR);
258 		if (res >= MCR_RSLT_OK)
259 			break;
260 	}
261 
262 	if (res < MCR_RSLT_OK)
263 		return (EBUSY);
264 	if (res == MCR_RSLT_OK)
265 		return (0);
266 
267 	return (ENXIO);
268 }
269 
270 int
271 qman_attach(device_t dev)
272 {
273 	struct qman_softc *sc;
274 	int error;
275 	vm_paddr_t fqd_pa, pfdr_pa;
276 	vm_size_t fqd_sz, pfdr_sz;
277 	int qman_channel_pool1 = QMAN_CHANNEL_POOL1_REV1;
278 	uint32_t ver;
279 	uint32_t nfqd;
280 	bool qman3 = false;
281 
282 	sc = device_get_softc(dev);
283 	sc->sc_dev = dev;
284 	qman_sc = sc;
285 
286 	/* Allocate resources */
287 	sc->sc_rrid = 0;
288 	sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 0, RF_ACTIVE);
289 	if (sc->sc_rres == NULL) {
290 		device_printf(dev, "could not allocate memory.\n");
291 		goto err;
292 	}
293 
294 	sc->sc_irid = 0;
295 	sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ,
296 	    &sc->sc_irid, RF_ACTIVE | RF_SHAREABLE);
297 	if (sc->sc_ires == NULL) {
298 		device_printf(dev, "could not allocate error interrupt.\n");
299 		goto err;
300 	}
301 	error = dpaa_map_private_memory(dev, 0, "fsl,qman-fqd",
302 	    &fqd_pa, &fqd_sz);
303 	error = dpaa_map_private_memory(dev, 1, "fsl,qman-pfdr",
304 	    &pfdr_pa, &pfdr_sz);
305 
306 	bzero((void *)PHYS_TO_DMAP(fqd_pa), fqd_sz);
307 	cpu_flush_dcache((void *)PHYS_TO_DMAP(fqd_pa), fqd_sz);
308 	/*
309 	 * FQDs are 64 bytes in size, with 24 bit pointers, so FQIDs are 24
310 	 * bits, fits fine in a uint32_t.
311 	 */
312 	nfqd = fqd_sz / 64;
313 	qman_total_fqids = nfqd;
314 	qman_fq_list = malloc(nfqd * sizeof(struct qman_fq *), M_QMAN,
315 	    M_WAITOK);
316 
317 	error = qman_set_memory(sc, fqd_pa, fqd_sz, QMAN_FQD_BARE);
318 	if (error != 0 && error != EEXIST)
319 		goto err;
320 	error = qman_set_memory(sc, pfdr_pa, pfdr_sz, QMAN_PFDR_BARE);
321 	if (error != 0 && error != EEXIST)
322 		goto err;
323 	if (error == 0) {
324 		/* Initialize PFDRs if it hasn't been initialized before */
325 		error = qman_setup_pfdr(sc, pfdr_sz / 64);
326 		if (error != 0)
327 			goto err;
328 		/* Magic constant from documentation */
329 		bus_write_4(sc->sc_rres, QMAN_PFDR_CFG, 64);
330 	}
331 
332 	bus_write_4(sc->sc_rres, QMAN_ERR_ISR, 0xffffffff);
333 	bus_write_4(sc->sc_rres, QMAN_ERR_IER, 0xffffffff);
334 
335 	ver = bus_read_4(sc->sc_rres, QMAN_IP_REV_1);
336 	sc->sc_qman_major = ((ver & IP_MJ_M) >> IP_MJ_S);
337 	if (sc->sc_qman_major >= 3)
338 		qman3 = true;
339 
340 	if (qman3)
341 		qman_channel_pool1 = QMAN_CHANNEL_POOL1_REV3;
342 	qman_channel_base = qman_channel_pool1;
343 
344 	sc->sc_qman_base_channel = qman_channel_pool1;
345 
346 	sc->sc_fqalloc =
347 	    vmem_create("qman-fqalloc", 1, nfqd - 1, 1, 0, M_WAITOK);
348 	sc->sc_qpalloc =
349 	    vmem_create("qman-qpalloc", qman_channel_pool1,
350 	    QMAN_POOL_CHANNELS, 1, 0, M_WAITOK);
351 	sc->sc_cgalloc = vmem_create("qman-cgalloc", 0, QMAN_CGRS,
352 	    1, 0, M_WAITOK);
353 
354 	if (bus_setup_intr(dev, sc->sc_ires, INTR_TYPE_NET, NULL, qman_isr,
355 	    sc, &sc->sc_intr_cookie) != 0)
356 		goto err;
357 
358 	if (error != 0) {
359 		device_printf(dev, "could not be initialized\n");
360 		goto err;
361 	}
362 	bus_write_4(sc->sc_rres, QMAN_DCP_CFG(0),
363 	    qman3 ? DCP_CFG_ED_3 : DCP_CFG_ED);
364 	bus_write_4(sc->sc_rres, QMAN_DCP_CFG(1),
365 	    qman3 ? DCP_CFG_ED_3 : DCP_CFG_ED);
366 
367 	bus_write_4(sc->sc_rres, 0xd00, 0x80000322);
368 
369 	/* TODO: DO we need a taskqueue?  Allocate here if so */
370 
371 	return (0);
372 
373 err:
374 	qman_detach(dev);
375 	return (ENXIO);
376 }
377 
378 int
379 qman_detach(device_t dev)
380 {
381 	struct qman_softc *sc;
382 
383 	sc = device_get_softc(dev);
384 
385 	if (sc->sc_fqalloc != NULL)
386 		vmem_destroy(sc->sc_fqalloc);
387 	if (sc->sc_qpalloc != NULL)
388 		vmem_destroy(sc->sc_qpalloc);
389 	if (sc->sc_cgalloc != NULL)
390 		vmem_destroy(sc->sc_cgalloc);
391 
392 	if (sc->sc_intr_cookie != NULL)
393 		bus_teardown_intr(dev, sc->sc_ires, sc->sc_intr_cookie);
394 
395 	if (sc->sc_ires != NULL)
396 		bus_release_resource(dev, SYS_RES_IRQ,
397 		    sc->sc_irid, sc->sc_ires);
398 
399 	if (sc->sc_rres != NULL)
400 		bus_release_resource(dev, SYS_RES_MEMORY,
401 		    sc->sc_rrid, sc->sc_rres);
402 
403 	free(qman_fq_list, M_QMAN);
404 	qman_fq_list = NULL;
405 
406 	return (0);
407 }
408 
409 int
410 qman_suspend(device_t dev)
411 {
412 
413 	return (0);
414 }
415 
416 int
417 qman_resume(device_t dev)
418 {
419 
420 	return (0);
421 }
422 
423 int
424 qman_shutdown(device_t dev)
425 {
426 
427 	return (0);
428 }
429 
430 int
431 qman_alloc_channel(void)
432 {
433 	struct qman_softc *sc = qman_sc;
434 	vmem_addr_t channel;
435 
436 	vmem_alloc(sc->sc_qpalloc, 1, M_BESTFIT | M_WAITOK, &channel);
437 
438 	return (channel);
439 }
440 
441 void
442 qman_free_channel(int channel)
443 {
444 	struct qman_softc *sc = qman_sc;
445 
446 	vmem_free(sc->sc_qpalloc, channel, 1);
447 }
448 
449 int
450 qman_percpu_channel(int cpu)
451 {
452 	device_t portal;
453 	struct qman_portal_softc *sc;
454 
455 	portal = DPCPU_ID_GET(cpu, qman_affine_portal);
456 	if (portal == NULL)
457 		return (-1);
458 
459 	sc = device_get_softc(portal);
460 
461 	return (sc->sc_affine_channel);
462 }
463 
464 int
465 qman_alloc_fqid_range(uint32_t count, uint32_t align, uint32_t *basep)
466 {
467 	struct qman_softc *sc = qman_sc;
468 	vmem_addr_t base;
469 	int error;
470 
471 	error = vmem_xalloc(sc->sc_fqalloc, count, align, 0, 0,
472 	    VMEM_ADDR_MIN, VMEM_ADDR_MAX, M_BESTFIT | M_NOWAIT, &base);
473 	if (error != 0)
474 		return (error);
475 	*basep = base;
476 	return (0);
477 }
478 
479 void
480 qman_free_fqid_range(uint32_t base, uint32_t count)
481 {
482 	struct qman_softc *sc = qman_sc;
483 
484 	vmem_free(sc->sc_fqalloc, base, count);
485 }
486 
487 /**
488  * @group QMan API functions implementation.
489  * @{
490  */
491 
492 struct qman_fq *
493 qman_fq_from_index(uint32_t fqid)
494 {
495 	if (fqid > qman_total_fqids)
496 		return (NULL);
497 	return (qman_fq_list[fqid]);
498 }
499 
500 /* Allocate and initialize an FQ Range */
501 struct qman_fq *
502 qman_fq_create(uint32_t fqids_num, int channel, uint8_t wq,
503     bool force_fqid, uint32_t fqid_or_align, bool init_parked,
504     bool hold_active, bool prefer_in_cache, bool congst_avoid_ena,
505     void *congst_group, int8_t overhead_accounting_len,
506     uint32_t tail_drop_threshold,
507     uint8_t annotation_cl, uint8_t data_cl)
508 {
509 	union qman_mc_command cmd;
510 	struct qman_softc *sc;
511 	union qman_mc_result *res;
512 	struct qman_fq *fqh;
513 	device_t portal;
514 	vmem_addr_t fqid_base;
515 	uint8_t rslt;
516 
517 	sc = qman_sc;
518 
519 	bzero(&cmd, sizeof(cmd));
520 	if (force_fqid) {
521 		/*
522 		 * Caller has already reserved the FQID (typically via
523 		 * qman_alloc_fqid_range() for a KeyGen distribution range)
524 		 * and passes the concrete FQID via fqid_or_align.  Do not
525 		 * touch the vmem allocator; just record the base for
526 		 * downstream book-keeping.
527 		 */
528 		fqid_base = fqid_or_align;
529 	} else {
530 		int error;
531 
532 		error = vmem_alloc(sc->sc_fqalloc, fqids_num,
533 		    M_BESTFIT | M_WAITOK, &fqid_base);
534 		if (error != 0) {
535 			device_printf(sc->sc_dev,
536 			    "qman_fq_create: no FQID range of %u\n",
537 			    fqids_num);
538 			return (NULL);
539 		}
540 	}
541 	cmd.init_fq.fqid = fqid_base;
542 	cmd.init_fq.count = fqids_num - 1;
543 	cmd.init_fq.dest_chan = channel;
544 	cmd.init_fq.dest_wq = wq;
545 	cmd.init_fq.we_mask = QCSP_INIT_FQ_WE_DEST_WQ | QCSP_INIT_FQ_WE_FQ_CTRL;
546 	if (init_parked)
547 		cmd.init_fq.verb = QCSP_VERB_INIT_FQ_PARK;
548 	else
549 		cmd.init_fq.verb = QCSP_VERB_INIT_FQ_SCHED;
550 	cmd.init_fq.fq_ctrl = (prefer_in_cache ? QM_FQCTRL_LIC : 0) |
551 	    (hold_active ? QM_FQCTRL_HOLDACTIVE : 0) |
552 	    (congst_avoid_ena ? QM_FQCTRL_AVOIDBLOCK : 0);
553 
554 	/*
555 	 * Configure hardware cache stashing: on dequeue, QMan will push
556 	 * the requested number of cachelines of frame annotation and/or
557 	 * frame data into the destination core's cache, hiding memory
558 	 * latency for the RX callback.
559 	 */
560 	if (annotation_cl != 0 || data_cl != 0) {
561 		uint64_t excl, cl;
562 
563 		excl = (annotation_cl != 0 ? QM_STASHING_EXCL_ANNOTATION : 0) |
564 		    (data_cl != 0 ? QM_STASHING_EXCL_DATA : 0);
565 		cl = ((annotation_cl & 3) << 4) | ((data_cl & 3) << 2);
566 		/* excl in wire byte 0 (bits 63-56), cl in wire byte 1. */
567 		cmd.init_fq.context_a = (excl << 56) | (cl << 48);
568 		cmd.init_fq.fq_ctrl |= QM_FQCTRL_CTXASTASH;
569 		cmd.init_fq.we_mask |= QCSP_INIT_FQ_WE_CONTEXT_A;
570 	}
571 
572 	critical_enter();
573 
574 	/* Ensure we have got QMan port initialized */
575 	portal = DPCPU_GET(qman_affine_portal);
576 	res = QMAN_PORTAL_MC_SEND_RAW(portal, &cmd);
577 
578 	rslt = 0;
579 	if (res != NULL)
580 		rslt = res->init_fq.rslt;
581 
582 	critical_exit();
583 	if (res == NULL || rslt != QMAN_MC_RES_OK) {
584 		if (!force_fqid)
585 			vmem_free(sc->sc_fqalloc, fqid_base, fqids_num);
586 		goto err;
587 	}
588 
589 	fqh = malloc(sizeof(*fqh), M_QMAN, M_WAITOK | M_ZERO);
590 	fqh->fqid = fqid_base;
591 	fqh->fqid_count = fqids_num;
592 	fqh->force_fqid = force_fqid;
593 
594 	for (uint32_t i = 0; i < fqids_num; i++)
595 		qman_fq_list[fqid_base + i] = fqh;
596 
597 	return (fqh);
598 
599 err:
600 
601 	return (NULL);
602 }
603 
604 static int
605 qman_fq_retire_one(device_t portal, uint32_t fqid)
606 {
607 	union qman_mc_command cmd;
608 	union qman_mc_result *rr;
609 
610 	bzero(&cmd, sizeof(cmd));
611 
612 	cmd.alter_fqs.verb = QCSP_VERB_ALTER_FQ_RETIRE;
613 	cmd.alter_fqs.fqid = fqid;
614 	rr = QMAN_PORTAL_MC_SEND_RAW(portal, &cmd);
615 	if (rr == NULL)
616 		return (ETIMEDOUT);
617 
618 	if (rr->alter_fqs.rslt == QMAN_MC_RES_OK) {
619 		if (rr->alter_fqs.fqs & QMAN_MC_AFQS_NE) {
620 			/* TODO: Drain.... */
621 		}
622 		return (0);
623 	}
624 
625 	return (0);
626 }
627 
628 int
629 qman_fq_free(struct qman_fq *fq)
630 {
631 	struct qman_softc *sc;
632 	device_t portal;
633 	int error;
634 
635 	sc = qman_sc;
636 
637 	critical_enter();
638 	portal = DPCPU_GET(qman_affine_portal);
639 	for (uint32_t i = 0; i < fq->fqid_count; i++) {
640 		error = qman_fq_retire_one(portal, fq->fqid + i);
641 		if (error != 0) {
642 			critical_exit();
643 			return (error);
644 		}
645 	}
646 	/* TODO: Take FQ out of service. */
647 	critical_exit();
648 
649 	if (!fq->force_fqid)
650 		vmem_free(sc->sc_fqalloc, fq->fqid, fq->fqid_count);
651 	for (uint32_t i = 0; i < fq->fqid_count; i++)
652 		qman_fq_list[fq->fqid + i] = NULL;
653 	free(fq, M_QMAN);
654 
655 	return (0);
656 }
657 
658 int
659 qman_fq_register_cb(struct qman_fq *fq, qman_cb_dqrr callback,
660     void *ctx)
661 {
662 	fq->cb.dqrr = callback;
663 	fq->cb.ctx = ctx;
664 
665 	return (0);
666 }
667 
668 int
669 qman_fq_register_flush_cb(struct qman_fq *fq, qman_cb_flush flush)
670 {
671 	fq->cb.flush = flush;
672 	return (0);
673 }
674 
675 int
676 qman_fq_enqueue(struct qman_fq *fq, struct dpaa_fd *frame)
677 {
678 	struct qman_softc *sc;
679 	int error;
680 	void *portal;
681 
682 	sc = qman_sc;
683 	critical_enter();
684 
685 	/* Ensure we have got QMan port initialized */
686 	portal = DPCPU_GET(qman_affine_portal);
687 	if (portal == NULL) {
688 		device_printf(sc->sc_dev, "could not setup QMan portal\n");
689 		critical_exit();
690 		return (ENXIO);
691 	}
692 
693 	error = QMAN_PORTAL_ENQUEUE(portal, fq, frame);
694 
695 	critical_exit();
696 
697 	return (error);
698 }
699 
700 uint32_t
701 qman_fq_get_fqid(struct qman_fq *fq)
702 {
703 	return (fq->fqid);
704 }
705 
706 
707 uint32_t
708 qman_fq_get_counter(struct qman_fq *fq, int counter)
709 {
710 	union qman_mc_result *cmd_res;
711 	union qman_mc_command command;
712 	device_t portal;
713 	u_int ret = 0;
714 
715 	bzero(&command, sizeof(command));
716 	command.query_fq_np.verb = QCSP_VERB_QUERY_FQ_NP;
717 	command.query_fq_np.fqid = fq->fqid;
718 	critical_enter();
719 	portal = DPCPU_GET(qman_affine_portal);
720 	cmd_res = QMAN_PORTAL_MC_SEND_RAW(portal, &command);
721 	if (counter == QMAN_COUNTER_FRAME)
722 		ret = cmd_res->query_fq_np.frm_cnt;
723 	else if (counter == QMAN_COUNTER_BYTES)
724 		ret = cmd_res->query_fq_np.byte_cnt;
725 
726 	critical_exit();
727 
728 	return (ret);
729 }
730 
731 void
732 qman_set_sdest(uint16_t channel, int cpu)
733 {
734 	struct qman_softc *sc = qman_sc;
735 	uint32_t reg;
736 
737 	if (sc->sc_qman_major >= 3) {
738 		reg = bus_read_4(sc->sc_rres, QCSP_IO_CFG_3(channel));
739 		reg &= IO_CFG_SDEST_M;
740 		reg |= (cpu << IO_CFG_SDEST_S);
741 		bus_write_4(sc->sc_rres, QCSP_IO_CFG_3(channel), reg);
742 	} else {
743 		reg = bus_read_4(sc->sc_rres, QCSP_IO_CFG(channel));
744 		reg &= IO_CFG_SDEST_M;
745 		reg |= (cpu << IO_CFG_SDEST_S);
746 		bus_write_4(sc->sc_rres, QCSP_IO_CFG(channel), reg);
747 	}
748 }
749 
750 /*
751  * TODO: add polling and/or congestion support.
752  */
753 
754 /** @} */
755