xref: /freebsd/sys/dev/dpaa/qman.c (revision 7a40b8a89e7da2a7e8d8e132bc37885b22e9bfb1)
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 #define	QCSP_VERB_INIT_FQ_PARK		0x40
115 #define	QCSP_VERB_INIT_FQ_SCHED		0x41
116 #define	QCSP_VERB_QUERY_FQ		0x44
117 #define	QCSP_VERB_QUERY_FQ_NP		0x45
118 #define	QCSP_VERB_ALTER_FQ_SCHED	0x48
119 #define	QCSP_VERB_ALTER_FQ_FE		0x49
120 #define	QCSP_VERB_ALTER_FQ_RETIRE	0x4a
121 #define	QCSP_VERB_ALTER_FQ_TAKE_OUT	0x4b
122 #define	QCSP_VERB_ALTER_FQ_RETIRE_CTXB	0x4c
123 #define	QCSP_VERB_ALTER_FQ_XON		0x4d
124 #define	QCSP_VERB_ALTER_FQ_XOFF		0x4e
125 
126 /* Init FQ */
127 #define	QCSP_INIT_FQ_WE_OAC		0x0100
128 #define	QCSP_INIT_FQ_WE_ORPC		0x0080
129 #define	QCSP_INIT_FQ_WE_CGID		0x0040
130 #define	QCSP_INIT_FQ_WE_FQ_CTRL		0x0020
131 #define	QCSP_INIT_FQ_WE_DEST_WQ		0x0010
132 #define	QCSP_INIT_FQ_WE_ICS_CRED	0x0008
133 #define	QCSP_INIT_FQ_WE_TD_THRESH	0x0004
134 #define	QCSP_INIT_FQ_WE_CONTEXT_B	0x0002
135 #define	QCSP_INIT_FQ_WE_CONTEXT_A	0x0001
136 
137 #define	QMAN_MC_RES_OK			0xf0
138 
139 #define	QMAN_MC_AFQS_NE			0x01
140 
141 /* Init FQ options */
142 #define	QM_FQCTRL_CGE			0x0400
143 #define	QM_FQCTRL_TDE			0x0200
144 #define	QM_FQCTRL_ORP			0x0100
145 #define	QM_FQCTRL_CTXASTASH		0x0080
146 #define	QM_FQCTRL_CPCSTASH		0x0040
147 #define	QM_FQCTRL_FORCESFDR		0x0008
148 #define	QM_FQCTRL_AVOIDBLOCK		0x0004
149 #define	QM_FQCTRL_HOLDACTIVE		0x0002
150 #define	QM_FQCTRL_LIC			0x0001
151 
152 #define	QMAN_CHANNEL_POOL1_REV1		0x21
153 #define	QMAN_CHANNEL_POOL1_REV3		0x401
154 
155 #define	QMAN_PFDR_MAX			0xfffeff
156 
157 /* P1023 has only 3 pool channels, but we don't support that SoC. */
158 #define	QMAN_POOL_CHANNELS		15
159 
160 /* P1023 only supports 64 congestion groups... */
161 #define	QMAN_CGRS			256
162 
163 static struct qman_softc *qman_sc;
164 
165 static MALLOC_DEFINE(M_QMAN, "qman", "DPAA Queue Manager structures");
166 
167 int qman_channel_base;
168 int qman_total_fqids;
169 struct qman_fq **qman_fq_list;
170 
171 /* Entries sorted right-to-left in bit order of the ISR */
172 static const char * const qman_errors[] = {
173 	"Invalid enqueue queue",
174 	"Invalid enqueue channel!",
175 	"Invalid enqueue state",
176 	"Invalid enqueue overflow",
177 	"Invalid enqueue configuration",
178 	NULL,
179 	NULL,
180 	NULL,
181 	"Invalid dequeue queue",
182 	"Invalid dequeue source",
183 	"Invalid dequeue FQ",
184 	"Invalid dequeue direct connect portal",
185 	NULL,
186 	NULL,
187 	NULL,
188 	NULL,
189 	"Invalid command verb",
190 	"Invalid FQ flow control state",
191 	NULL,
192 	NULL,
193 	NULL,
194 	NULL,
195 	NULL,
196 	"Insufficient free PFDRs",
197 	"Single-bit ECC error",
198 	"Multi-bit ECC error",
199 	"PFDR low watermark",
200 	"Invalid target transaction",
201 	"Initiator data error",
202 	NULL,
203 	NULL
204 };
205 
206 static void
qman_isr(void * arg)207 qman_isr(void *arg)
208 {
209 	struct qman_softc *sc = arg;
210 	uint32_t ier, isr, isr_bit;
211 	int i;
212 
213 	ier = bus_read_4(sc->sc_rres, QMAN_ERR_IER);
214 	isr = bus_read_4(sc->sc_rres, QMAN_ERR_ISR);
215 
216 	if ((ier & isr) == 0)
217 		return;
218 
219 	isr_bit = (isr & ier);
220 	for (i = 0; isr_bit != 0; i++, isr_bit >>= 1) {
221 		if (isr_bit & 1)
222 			device_printf(sc->sc_dev, "%s", qman_errors[i]);
223 	}
224 
225 	bus_write_4(sc->sc_rres, QMAN_ERR_ISR, isr);
226 }
227 
228 
229 /* Set up reserved memory configuration for PFDR and FQD, per `off`. */
230 static int
qman_set_memory(struct qman_softc * sc,vm_paddr_t pa,vm_size_t size,bus_size_t off)231 qman_set_memory(struct qman_softc *sc, vm_paddr_t pa,
232     vm_size_t size, bus_size_t off)
233 {
234 	uint32_t bar, bare;
235 	vm_paddr_t old_bar;
236 
237 	/*
238 	 * Register offsets:
239 	 * 0 - BARE
240 	 * 4 - BAR
241 	 * 0x10 - AR
242 	 */
243 	bare = bus_read_4(sc->sc_rres, off);
244 	bar = bus_read_4(sc->sc_rres, off + 4);
245 	old_bar = (vm_paddr_t)bare << 32 | bar;
246 
247 	if (old_bar != 0 && old_bar != pa) {
248 		device_printf(sc->sc_dev, "QMan BAR already initialized!\n");
249 		return (ENOMEM);
250 	} else if (old_bar == pa)
251 		return (EEXIST);
252 
253 	/*
254 	 * Zero the memory and flush cache through DMAP. QMan accesses the
255 	 * memory as non-coherent.
256 	 */
257 	memset((void *)PHYS_TO_DMAP(pa), 0, size);
258 	cpu_flush_dcache((void *)PHYS_TO_DMAP(pa), size);
259 
260 	bus_write_4(sc->sc_rres, off, pa >> 32);
261 	bus_write_4(sc->sc_rres, off + 4, (uint32_t)pa);
262 	bus_write_4(sc->sc_rres, off + 0x10, AR_EN | (ilog2(size) - 1));
263 
264 	return (0);
265 }
266 
267 /*
268  * Set up PFDR structures.  Some things to keep in mind:
269  * - npfdr is the total number of PFDRs in the private memory.  PFDRs are 64
270  *   bytes in size, so npfdr is (pfdr_sz/64).
271  * - PFDR 0-7 are reserved, so the base starts at 8, not 0, so we adjust
272  *   internally.
273  * - The second parameter is the last PFDR, not the number of PFDRs, so needs to
274  *   be adjusted down one more, so subtract 9.
275  */
276 static int
qman_setup_pfdr(struct qman_softc * sc,int npfdr)277 qman_setup_pfdr(struct qman_softc *sc, int npfdr)
278 {
279 	uint32_t res;
280 
281 	npfdr = min(npfdr, QMAN_PFDR_MAX);
282 	bus_write_4(sc->sc_rres, QMAN_MCP0, 8);
283 	bus_write_4(sc->sc_rres, QMAN_MCP1, npfdr - 9);
284 	bus_write_4(sc->sc_rres, QMAN_MCR, MCR_INIT_PFDR);
285 
286 	for (int timeout = 100000; timeout > 0; timeout--) {
287 		DELAY(1);
288 		res = bus_read_4(sc->sc_rres, QMAN_MCR);
289 		if (res >= MCR_RSLT_OK)
290 			break;
291 	}
292 
293 	if (res < MCR_RSLT_OK)
294 		return (EBUSY);
295 	if (res == MCR_RSLT_OK)
296 		return (0);
297 
298 	return (ENXIO);
299 }
300 
301 int
qman_attach(device_t dev)302 qman_attach(device_t dev)
303 {
304 	struct qman_softc *sc;
305 	int error;
306 	vm_paddr_t fqd_pa, pfdr_pa;
307 	vm_size_t fqd_sz, pfdr_sz;
308 	int qman_channel_pool1 = QMAN_CHANNEL_POOL1_REV1;
309 	uint32_t ver;
310 	uint32_t nfqd;
311 	bool qman3 = false;
312 
313 	sc = device_get_softc(dev);
314 	sc->sc_dev = dev;
315 	qman_sc = sc;
316 
317 	/* Allocate resources */
318 	sc->sc_rrid = 0;
319 	sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 0, RF_ACTIVE);
320 	if (sc->sc_rres == NULL) {
321 		device_printf(dev, "could not allocate memory.\n");
322 		goto err;
323 	}
324 
325 	sc->sc_irid = 0;
326 	sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ,
327 	    &sc->sc_irid, RF_ACTIVE | RF_SHAREABLE);
328 	if (sc->sc_ires == NULL) {
329 		device_printf(dev, "could not allocate error interrupt.\n");
330 		goto err;
331 	}
332 	error = dpaa_map_private_memory(dev, 0, "fsl,qman-fqd",
333 	    &fqd_pa, &fqd_sz);
334 	error = dpaa_map_private_memory(dev, 1, "fsl,qman-pfdr",
335 	    &pfdr_pa, &pfdr_sz);
336 
337 	bzero((void *)PHYS_TO_DMAP(fqd_pa), fqd_sz);
338 	cpu_flush_dcache((void *)PHYS_TO_DMAP(fqd_pa), fqd_sz);
339 	/*
340 	 * FQDs are 64 bytes in size, with 24 bit pointers, so FQIDs are 24
341 	 * bits, fits fine in a uint32_t.
342 	 */
343 	nfqd = fqd_sz / 64;
344 	qman_total_fqids = nfqd;
345 	qman_channel_base = qman_channel_pool1;
346 	qman_fq_list = malloc(nfqd * sizeof(struct qman_fq *), M_QMAN,
347 	    M_WAITOK);
348 
349 	error = qman_set_memory(sc, fqd_pa, fqd_sz, QMAN_FQD_BARE);
350 	if (error != 0 && error != EEXIST)
351 		goto err;
352 	error = qman_set_memory(sc, pfdr_pa, pfdr_sz, QMAN_PFDR_BARE);
353 	if (error != 0 && error != EEXIST)
354 		goto err;
355 	if (error == 0) {
356 		/* Initialize PFDRs if it hasn't been initialized before */
357 		error = qman_setup_pfdr(sc, pfdr_sz / 64);
358 		if (error != 0)
359 			goto err;
360 		/* Magic constant from documentation */
361 		bus_write_4(sc->sc_rres, QMAN_PFDR_CFG, 64);
362 	}
363 
364 	bus_write_4(sc->sc_rres, QMAN_ERR_ISR, 0xffffffff);
365 	bus_write_4(sc->sc_rres, QMAN_ERR_IER, 0xffffffff);
366 
367 	ver = bus_read_4(sc->sc_rres, QMAN_IP_REV_1);
368 	sc->sc_qman_major = ((ver & IP_MJ_M) >> IP_MJ_S);
369 	if (sc->sc_qman_major >= 3)
370 		qman3 = true;
371 
372 	if (qman3)
373 		qman_channel_pool1 = QMAN_CHANNEL_POOL1_REV3;
374 
375 	sc->sc_qman_base_channel = qman_channel_pool1;
376 
377 	sc->sc_fqalloc =
378 	    vmem_create("qman-fqalloc", 1, nfqd - 1, 1, 0, M_WAITOK);
379 	sc->sc_qpalloc =
380 	    vmem_create("qman-fqalloc", qman_channel_pool1,
381 	    QMAN_POOL_CHANNELS, 1, 0, M_WAITOK);
382 	sc->sc_cgalloc = vmem_create("qman->cgalloc", 0, QMAN_CGRS,
383 	    1, 0, M_WAITOK);
384 
385 	if (bus_setup_intr(dev, sc->sc_ires, INTR_TYPE_NET, NULL, qman_isr,
386 	    sc, &sc->sc_intr_cookie) != 0)
387 		goto err;
388 
389 	if (error != 0) {
390 		device_printf(dev, "could not be initialized\n");
391 		goto err;
392 	}
393 	bus_write_4(sc->sc_rres, QMAN_DCP_CFG(0),
394 	    qman3 ? DCP_CFG_ED_3 : DCP_CFG_ED);
395 	bus_write_4(sc->sc_rres, QMAN_DCP_CFG(1),
396 	    qman3 ? DCP_CFG_ED_3 : DCP_CFG_ED);
397 
398 	bus_write_4(sc->sc_rres, 0xd00, 0x80000322);
399 
400 	/* TODO: DO we need a taskqueue?  Allocate here if so */
401 
402 	return (0);
403 
404 err:
405 	qman_detach(dev);
406 	return (ENXIO);
407 }
408 
409 int
qman_detach(device_t dev)410 qman_detach(device_t dev)
411 {
412 	struct qman_softc *sc;
413 
414 	sc = device_get_softc(dev);
415 
416 	if (sc->sc_fqalloc != NULL)
417 		vmem_destroy(sc->sc_fqalloc);
418 	if (sc->sc_qpalloc != NULL)
419 		vmem_destroy(sc->sc_qpalloc);
420 	if (sc->sc_cgalloc != NULL)
421 		vmem_destroy(sc->sc_cgalloc);
422 
423 	if (sc->sc_intr_cookie != NULL)
424 		bus_teardown_intr(dev, sc->sc_ires, sc->sc_intr_cookie);
425 
426 	if (sc->sc_ires != NULL)
427 		bus_release_resource(dev, SYS_RES_IRQ,
428 		    sc->sc_irid, sc->sc_ires);
429 
430 	if (sc->sc_rres != NULL)
431 		bus_release_resource(dev, SYS_RES_MEMORY,
432 		    sc->sc_rrid, sc->sc_rres);
433 
434 	free(qman_fq_list, M_QMAN);
435 	qman_fq_list = NULL;
436 
437 	return (0);
438 }
439 
440 int
qman_suspend(device_t dev)441 qman_suspend(device_t dev)
442 {
443 
444 	return (0);
445 }
446 
447 int
qman_resume(device_t dev)448 qman_resume(device_t dev)
449 {
450 
451 	return (0);
452 }
453 
454 int
qman_shutdown(device_t dev)455 qman_shutdown(device_t dev)
456 {
457 
458 	return (0);
459 }
460 
461 int
qman_alloc_channel(void)462 qman_alloc_channel(void)
463 {
464 	struct qman_softc *sc = qman_sc;
465 	vmem_addr_t channel;
466 
467 	vmem_alloc(sc->sc_qpalloc, 1, M_BESTFIT | M_WAITOK, &channel);
468 
469 	return (channel);
470 }
471 
472 void
qman_free_channel(int channel)473 qman_free_channel(int channel)
474 {
475 	struct qman_softc *sc = qman_sc;
476 
477 	vmem_free(sc->sc_qpalloc, channel, 1);
478 }
479 
480 /**
481  * @group QMan API functions implementation.
482  * @{
483  */
484 
485 struct qman_fq *
qman_fq_from_index(uint32_t fqid)486 qman_fq_from_index(uint32_t fqid)
487 {
488 	if (fqid > qman_total_fqids)
489 		return (NULL);
490 	return (qman_fq_list[fqid]);
491 }
492 
493 /* Allocate and initialize an FQ Range */
494 struct qman_fq *
qman_fq_create(uint32_t fqids_num,int channel,uint8_t wq,bool force_fqid,uint32_t fqid_or_align,bool init_parked,bool hold_active,bool prefer_in_cache,bool congst_avoid_ena,void * congst_group,int8_t overhead_accounting_len,uint32_t tail_drop_threshold)495 qman_fq_create(uint32_t fqids_num, int channel, uint8_t wq,
496     bool force_fqid, uint32_t fqid_or_align, bool init_parked,
497     bool hold_active, bool prefer_in_cache, bool congst_avoid_ena,
498     void *congst_group, int8_t overhead_accounting_len,
499     uint32_t tail_drop_threshold)
500 {
501 	union qman_mc_command cmd;
502 	struct qman_softc *sc;
503 	union qman_mc_result *res;
504 	struct qman_fq *fqh;
505 	device_t portal;
506 	vmem_addr_t fqid_base;
507 	uint8_t rslt;
508 
509 	sc = qman_sc;
510 
511 	if (fqids_num != 1) {
512 		device_printf(sc->sc_dev,
513 		    "Only one fq allocation allowed currently\n");
514 		return (NULL);
515 	}
516 
517 	bzero(&cmd, sizeof(cmd));
518 	vmem_alloc(sc->sc_fqalloc, fqids_num, M_BESTFIT | M_WAITOK, &fqid_base);
519 	cmd.init_fq.fqid = fqid_base;
520 	cmd.init_fq.count = fqids_num - 1;
521 	cmd.init_fq.dest_chan = channel;
522 	cmd.init_fq.dest_wq = wq;
523 	cmd.init_fq.we_mask = QCSP_INIT_FQ_WE_DEST_WQ | QCSP_INIT_FQ_WE_FQ_CTRL;
524 	if (init_parked)
525 		cmd.init_fq.verb = QCSP_VERB_INIT_FQ_PARK;
526 	else
527 		cmd.init_fq.verb = QCSP_VERB_INIT_FQ_SCHED;
528 	cmd.init_fq.fq_ctrl = (prefer_in_cache ? QM_FQCTRL_LIC : 0) |
529 	    (hold_active ? QM_FQCTRL_HOLDACTIVE : 0) |
530 	    (congst_avoid_ena ? QM_FQCTRL_AVOIDBLOCK : 0);
531 
532 	critical_enter();
533 
534 	/* Ensure we have got QMan port initialized */
535 	portal = DPCPU_GET(qman_affine_portal);
536 	res = QMAN_PORTAL_MC_SEND_RAW(portal, &cmd);
537 
538 	rslt = 0;
539 	if (res != NULL)
540 		rslt = res->init_fq.rslt;
541 
542 	critical_exit();
543 	if (res == NULL || rslt != QMAN_MC_RES_OK) {
544 		vmem_free(sc->sc_fqalloc, fqid_base, fqids_num);
545 		goto err;
546 	}
547 
548 	fqh = malloc(sizeof(*fqh), M_QMAN, M_WAITOK | M_ZERO);
549 	fqh->fqid = fqid_base;
550 
551 	qman_fq_list[fqid_base] = fqh;
552 
553 	return (fqh);
554 
555 err:
556 
557 	return (NULL);
558 }
559 
560 static int
qman_fq_retire(device_t portal,struct qman_fq * fq)561 qman_fq_retire(device_t portal, struct qman_fq *fq)
562 {
563 	union qman_mc_command cmd;
564 	union qman_mc_result *rr;
565 
566 	bzero(&cmd, sizeof(cmd));
567 
568 	cmd.alter_fqs.verb = QCSP_VERB_ALTER_FQ_RETIRE;
569 	cmd.alter_fqs.fqid = fq->fqid;
570 	rr = QMAN_PORTAL_MC_SEND_RAW(portal, &cmd);
571 	if (rr == NULL)
572 		return (ETIMEDOUT);
573 
574 	if (rr->alter_fqs.rslt == QMAN_MC_RES_OK) {
575 		if (rr->alter_fqs.fqs & QMAN_MC_AFQS_NE) {
576 			/* TODO: Drain.... */
577 		}
578 		return (0);
579 	}
580 
581 	return (0);
582 }
583 
584 int
qman_fq_free(struct qman_fq * fq)585 qman_fq_free(struct qman_fq *fq)
586 {
587 	struct qman_softc *sc;
588 	int error;
589 
590 	sc = qman_sc;
591 
592 	critical_enter();
593 	error = qman_fq_retire(DPCPU_GET(qman_affine_portal), fq);
594 	/* TODO: Take FQ out of service. */
595 	critical_exit();
596 	if (error != 0)
597 		return (error);
598 	vmem_free(sc->sc_fqalloc, fq->fqid, 1);
599 	qman_fq_list[fq->fqid] = NULL;
600 	free(fq, M_QMAN);
601 
602 	return (0);
603 }
604 
605 int
qman_fq_register_cb(struct qman_fq * fq,qman_cb_dqrr callback,void * ctx)606 qman_fq_register_cb(struct qman_fq *fq, qman_cb_dqrr callback,
607     void *ctx)
608 {
609 	fq->cb.dqrr = callback;
610 	fq->cb.ctx = ctx;
611 
612 	return (0);
613 }
614 
615 int
qman_fq_enqueue(struct qman_fq * fq,struct dpaa_fd * frame)616 qman_fq_enqueue(struct qman_fq *fq, struct dpaa_fd *frame)
617 {
618 	struct qman_softc *sc;
619 	int error;
620 	void *portal;
621 
622 	sc = qman_sc;
623 	critical_enter();
624 
625 	/* Ensure we have got QMan port initialized */
626 	portal = DPCPU_GET(qman_affine_portal);
627 	if (portal == NULL) {
628 		device_printf(sc->sc_dev, "could not setup QMan portal\n");
629 		critical_exit();
630 		return (ENXIO);
631 	}
632 
633 	error = QMAN_PORTAL_ENQUEUE(portal, fq, frame);
634 
635 	critical_exit();
636 
637 	return (error);
638 }
639 
640 uint32_t
qman_fq_get_fqid(struct qman_fq * fq)641 qman_fq_get_fqid(struct qman_fq *fq)
642 {
643 	return (fq->fqid);
644 }
645 
646 
647 uint32_t
qman_fq_get_counter(struct qman_fq * fq,int counter)648 qman_fq_get_counter(struct qman_fq *fq, int counter)
649 {
650 	union qman_mc_result *cmd_res;
651 	union qman_mc_command command;
652 	device_t portal;
653 	u_int ret = 0;
654 
655 	bzero(&command, sizeof(command));
656 	command.query_fq_np.verb = QCSP_VERB_QUERY_FQ_NP;
657 	command.query_fq_np.fqid = fq->fqid;
658 	critical_enter();
659 	portal = DPCPU_GET(qman_affine_portal);
660 	cmd_res = QMAN_PORTAL_MC_SEND_RAW(portal, &command);
661 	if (counter == QMAN_COUNTER_FRAME)
662 		ret = cmd_res->query_fq_np.frm_cnt;
663 	else if (counter == QMAN_COUNTER_BYTES)
664 		ret = cmd_res->query_fq_np.byte_cnt;
665 
666 	critical_exit();
667 
668 	return (ret);
669 }
670 
671 void
qman_set_sdest(uint16_t channel,int cpu)672 qman_set_sdest(uint16_t channel, int cpu)
673 {
674 	struct qman_softc *sc = qman_sc;
675 	uint32_t reg;
676 
677 	if (sc->sc_qman_major >= 3) {
678 		reg = bus_read_4(sc->sc_rres, QCSP_IO_CFG_3(channel));
679 		reg &= IO_CFG_SDEST_M;
680 		reg |= (cpu << IO_CFG_SDEST_S);
681 		bus_write_4(sc->sc_rres, QCSP_IO_CFG_3(channel), reg);
682 	} else {
683 		reg = bus_read_4(sc->sc_rres, QCSP_IO_CFG(channel));
684 		reg &= IO_CFG_SDEST_M;
685 		reg |= (cpu << IO_CFG_SDEST_S);
686 		bus_write_4(sc->sc_rres, QCSP_IO_CFG(channel), reg);
687 	}
688 }
689 
690 /*
691  * TODO: add polling and/or congestion support.
692  */
693 
694 /** @} */
695