xref: /freebsd/sys/dev/dpaa/qman.c (revision d59c7ea2701fe7b73b32eef49a7c712ef38de5a0)
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_channel_base = qman_channel_pool1;
315 	qman_fq_list = malloc(nfqd * sizeof(struct qman_fq *), M_QMAN,
316 	    M_WAITOK);
317 
318 	error = qman_set_memory(sc, fqd_pa, fqd_sz, QMAN_FQD_BARE);
319 	if (error != 0 && error != EEXIST)
320 		goto err;
321 	error = qman_set_memory(sc, pfdr_pa, pfdr_sz, QMAN_PFDR_BARE);
322 	if (error != 0 && error != EEXIST)
323 		goto err;
324 	if (error == 0) {
325 		/* Initialize PFDRs if it hasn't been initialized before */
326 		error = qman_setup_pfdr(sc, pfdr_sz / 64);
327 		if (error != 0)
328 			goto err;
329 		/* Magic constant from documentation */
330 		bus_write_4(sc->sc_rres, QMAN_PFDR_CFG, 64);
331 	}
332 
333 	bus_write_4(sc->sc_rres, QMAN_ERR_ISR, 0xffffffff);
334 	bus_write_4(sc->sc_rres, QMAN_ERR_IER, 0xffffffff);
335 
336 	ver = bus_read_4(sc->sc_rres, QMAN_IP_REV_1);
337 	sc->sc_qman_major = ((ver & IP_MJ_M) >> IP_MJ_S);
338 	if (sc->sc_qman_major >= 3)
339 		qman3 = true;
340 
341 	if (qman3)
342 		qman_channel_pool1 = QMAN_CHANNEL_POOL1_REV3;
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-fqalloc", 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 /**
450  * @group QMan API functions implementation.
451  * @{
452  */
453 
454 struct qman_fq *
455 qman_fq_from_index(uint32_t fqid)
456 {
457 	if (fqid > qman_total_fqids)
458 		return (NULL);
459 	return (qman_fq_list[fqid]);
460 }
461 
462 /* Allocate and initialize an FQ Range */
463 struct qman_fq *
464 qman_fq_create(uint32_t fqids_num, int channel, uint8_t wq,
465     bool force_fqid, uint32_t fqid_or_align, bool init_parked,
466     bool hold_active, bool prefer_in_cache, bool congst_avoid_ena,
467     void *congst_group, int8_t overhead_accounting_len,
468     uint32_t tail_drop_threshold,
469     uint8_t annotation_cl, uint8_t data_cl)
470 {
471 	union qman_mc_command cmd;
472 	struct qman_softc *sc;
473 	union qman_mc_result *res;
474 	struct qman_fq *fqh;
475 	device_t portal;
476 	vmem_addr_t fqid_base;
477 	uint8_t rslt;
478 
479 	sc = qman_sc;
480 
481 	if (fqids_num != 1) {
482 		device_printf(sc->sc_dev,
483 		    "Only one fq allocation allowed currently\n");
484 		return (NULL);
485 	}
486 
487 	bzero(&cmd, sizeof(cmd));
488 	vmem_alloc(sc->sc_fqalloc, fqids_num, M_BESTFIT | M_WAITOK, &fqid_base);
489 	cmd.init_fq.fqid = fqid_base;
490 	cmd.init_fq.count = fqids_num - 1;
491 	cmd.init_fq.dest_chan = channel;
492 	cmd.init_fq.dest_wq = wq;
493 	cmd.init_fq.we_mask = QCSP_INIT_FQ_WE_DEST_WQ | QCSP_INIT_FQ_WE_FQ_CTRL;
494 	if (init_parked)
495 		cmd.init_fq.verb = QCSP_VERB_INIT_FQ_PARK;
496 	else
497 		cmd.init_fq.verb = QCSP_VERB_INIT_FQ_SCHED;
498 	cmd.init_fq.fq_ctrl = (prefer_in_cache ? QM_FQCTRL_LIC : 0) |
499 	    (hold_active ? QM_FQCTRL_HOLDACTIVE : 0) |
500 	    (congst_avoid_ena ? QM_FQCTRL_AVOIDBLOCK : 0);
501 
502 	/*
503 	 * Configure hardware cache stashing: on dequeue, QMan will push
504 	 * the requested number of cachelines of frame annotation and/or
505 	 * frame data into the destination core's cache, hiding memory
506 	 * latency for the RX callback.
507 	 */
508 	if (annotation_cl != 0 || data_cl != 0) {
509 		uint64_t excl, cl;
510 
511 		excl = (annotation_cl != 0 ? QM_STASHING_EXCL_ANNOTATION : 0) |
512 		    (data_cl != 0 ? QM_STASHING_EXCL_DATA : 0);
513 		cl = ((annotation_cl & 3) << 4) | ((data_cl & 3) << 2);
514 		/* excl in wire byte 0 (bits 63-56), cl in wire byte 1. */
515 		cmd.init_fq.context_a = (excl << 56) | (cl << 48);
516 		cmd.init_fq.fq_ctrl |= QM_FQCTRL_CTXASTASH;
517 		cmd.init_fq.we_mask |= QCSP_INIT_FQ_WE_CONTEXT_A;
518 	}
519 
520 	critical_enter();
521 
522 	/* Ensure we have got QMan port initialized */
523 	portal = DPCPU_GET(qman_affine_portal);
524 	res = QMAN_PORTAL_MC_SEND_RAW(portal, &cmd);
525 
526 	rslt = 0;
527 	if (res != NULL)
528 		rslt = res->init_fq.rslt;
529 
530 	critical_exit();
531 	if (res == NULL || rslt != QMAN_MC_RES_OK) {
532 		vmem_free(sc->sc_fqalloc, fqid_base, fqids_num);
533 		goto err;
534 	}
535 
536 	fqh = malloc(sizeof(*fqh), M_QMAN, M_WAITOK | M_ZERO);
537 	fqh->fqid = fqid_base;
538 
539 	qman_fq_list[fqid_base] = fqh;
540 
541 	return (fqh);
542 
543 err:
544 
545 	return (NULL);
546 }
547 
548 static int
549 qman_fq_retire(device_t portal, struct qman_fq *fq)
550 {
551 	union qman_mc_command cmd;
552 	union qman_mc_result *rr;
553 
554 	bzero(&cmd, sizeof(cmd));
555 
556 	cmd.alter_fqs.verb = QCSP_VERB_ALTER_FQ_RETIRE;
557 	cmd.alter_fqs.fqid = fq->fqid;
558 	rr = QMAN_PORTAL_MC_SEND_RAW(portal, &cmd);
559 	if (rr == NULL)
560 		return (ETIMEDOUT);
561 
562 	if (rr->alter_fqs.rslt == QMAN_MC_RES_OK) {
563 		if (rr->alter_fqs.fqs & QMAN_MC_AFQS_NE) {
564 			/* TODO: Drain.... */
565 		}
566 		return (0);
567 	}
568 
569 	return (0);
570 }
571 
572 int
573 qman_fq_free(struct qman_fq *fq)
574 {
575 	struct qman_softc *sc;
576 	int error;
577 
578 	sc = qman_sc;
579 
580 	critical_enter();
581 	error = qman_fq_retire(DPCPU_GET(qman_affine_portal), fq);
582 	/* TODO: Take FQ out of service. */
583 	critical_exit();
584 	if (error != 0)
585 		return (error);
586 	vmem_free(sc->sc_fqalloc, fq->fqid, 1);
587 	qman_fq_list[fq->fqid] = NULL;
588 	free(fq, M_QMAN);
589 
590 	return (0);
591 }
592 
593 int
594 qman_fq_register_cb(struct qman_fq *fq, qman_cb_dqrr callback,
595     void *ctx)
596 {
597 	fq->cb.dqrr = callback;
598 	fq->cb.ctx = ctx;
599 
600 	return (0);
601 }
602 
603 int
604 qman_fq_enqueue(struct qman_fq *fq, struct dpaa_fd *frame)
605 {
606 	struct qman_softc *sc;
607 	int error;
608 	void *portal;
609 
610 	sc = qman_sc;
611 	critical_enter();
612 
613 	/* Ensure we have got QMan port initialized */
614 	portal = DPCPU_GET(qman_affine_portal);
615 	if (portal == NULL) {
616 		device_printf(sc->sc_dev, "could not setup QMan portal\n");
617 		critical_exit();
618 		return (ENXIO);
619 	}
620 
621 	error = QMAN_PORTAL_ENQUEUE(portal, fq, frame);
622 
623 	critical_exit();
624 
625 	return (error);
626 }
627 
628 uint32_t
629 qman_fq_get_fqid(struct qman_fq *fq)
630 {
631 	return (fq->fqid);
632 }
633 
634 
635 uint32_t
636 qman_fq_get_counter(struct qman_fq *fq, int counter)
637 {
638 	union qman_mc_result *cmd_res;
639 	union qman_mc_command command;
640 	device_t portal;
641 	u_int ret = 0;
642 
643 	bzero(&command, sizeof(command));
644 	command.query_fq_np.verb = QCSP_VERB_QUERY_FQ_NP;
645 	command.query_fq_np.fqid = fq->fqid;
646 	critical_enter();
647 	portal = DPCPU_GET(qman_affine_portal);
648 	cmd_res = QMAN_PORTAL_MC_SEND_RAW(portal, &command);
649 	if (counter == QMAN_COUNTER_FRAME)
650 		ret = cmd_res->query_fq_np.frm_cnt;
651 	else if (counter == QMAN_COUNTER_BYTES)
652 		ret = cmd_res->query_fq_np.byte_cnt;
653 
654 	critical_exit();
655 
656 	return (ret);
657 }
658 
659 void
660 qman_set_sdest(uint16_t channel, int cpu)
661 {
662 	struct qman_softc *sc = qman_sc;
663 	uint32_t reg;
664 
665 	if (sc->sc_qman_major >= 3) {
666 		reg = bus_read_4(sc->sc_rres, QCSP_IO_CFG_3(channel));
667 		reg &= IO_CFG_SDEST_M;
668 		reg |= (cpu << IO_CFG_SDEST_S);
669 		bus_write_4(sc->sc_rres, QCSP_IO_CFG_3(channel), reg);
670 	} else {
671 		reg = bus_read_4(sc->sc_rres, QCSP_IO_CFG(channel));
672 		reg &= IO_CFG_SDEST_M;
673 		reg |= (cpu << IO_CFG_SDEST_S);
674 		bus_write_4(sc->sc_rres, QCSP_IO_CFG(channel), reg);
675 	}
676 }
677 
678 /*
679  * TODO: add polling and/or congestion support.
680  */
681 
682 /** @} */
683