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