1 /*-
2 * SPDX-License-Identifier: BSD-3-Clause AND BSD-2-Clause
3 *
4 * Copyright © 2014-2016 Freescale Semiconductor, Inc.
5 * Copyright © 2016-2019 NXP
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * 3. Neither the name of the copyright holder nor the names of its
19 * contributors may be used to endorse or promote products derived from this
20 * software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *
34 * Original source file obtained from:
35 * drivers/soc/fsl/dpio/qbman-portal.c
36 *
37 * Commit: 4c86114194e644b6da9107d75910635c9e87179e
38 * Repository: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
39 */
40
41 /*
42 * Copyright © 2021-2022 Dmitry Salychev
43 *
44 * Redistribution and use in source and binary forms, with or without
45 * modification, are permitted provided that the following conditions
46 * are met:
47 * 1. Redistributions of source code must retain the above copyright
48 * notice, this list of conditions and the following disclaimer.
49 * 2. Redistributions in binary form must reproduce the above copyright
50 * notice, this list of conditions and the following disclaimer in the
51 * documentation and/or other materials provided with the distribution.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 */
65
66 #include <sys/cdefs.h>
67 __FBSDID("$FreeBSD$");
68
69 /*
70 * DPAA2 QBMan software portal.
71 */
72
73 #include <sys/param.h>
74 #include <sys/kernel.h>
75 #include <sys/bus.h>
76 #include <sys/rman.h>
77 #include <sys/module.h>
78 #include <sys/malloc.h>
79 #include <sys/mutex.h>
80 #include <sys/time.h>
81 #include <sys/types.h>
82 #include <sys/systm.h>
83 #include <sys/condvar.h>
84 #include <sys/lock.h>
85
86 #include <machine/bus.h>
87 #include <machine/resource.h>
88 #include <machine/atomic.h>
89
90 #include "pcib_if.h"
91 #include "pci_if.h"
92
93 #include "dpaa2_swp.h"
94 #include "dpaa2_mc.h"
95 #include "dpaa2_bp.h"
96
97 #define CMD_SPIN_TIMEOUT 100u /* us */
98 #define CMD_SPIN_ATTEMPTS 2000u /* 200 ms max. */
99
100 #define CMD_VERB_MASK 0x7Fu
101
102 /* Shifts in the VERB byte of the enqueue command descriptor. */
103 #define ENQ_CMD_ORP_ENABLE_SHIFT 2
104 #define ENQ_CMD_IRQ_ON_DISPATCH_SHIFT 3
105 #define ENQ_CMD_TARGET_TYPE_SHIFT 4
106 #define ENQ_CMD_DCA_EN_SHIFT 7
107 /* VERB byte options of the enqueue command descriptor. */
108 #define ENQ_CMD_EMPTY 0u
109 #define ENQ_CMD_RESPONSE_ALWAYS 1u
110 #define ENQ_CMD_REJECTS_TO_FQ 2u
111
112 #define ENQ_DESC_FD_OFFSET 32u
113
114 #define ENQ_DCA_IDXMASK 0x0Fu
115 #define ENQ_FLAG_DCA (1ull << 31)
116
117 /* QBMan portal command codes. */
118 #define CMDID_SWP_MC_ACQUIRE 0x30
119 #define CMDID_SWP_BP_QUERY 0x32
120 #define CMDID_SWP_WQCHAN_CONFIGURE 0x46
121
122 /* QBMan portal command result codes. */
123 #define QBMAN_CMD_RC_OK 0xF0
124
125 /* SDQCR attribute codes */
126 #define QB_SDQCR_FC_SHIFT 29u
127 #define QB_SDQCR_FC_MASK 0x1u
128 #define QB_SDQCR_DCT_SHIFT 24u
129 #define QB_SDQCR_DCT_MASK 0x3u
130 #define QB_SDQCR_TOK_SHIFT 16u
131 #define QB_SDQCR_TOK_MASK 0xFFu
132 #define QB_SDQCR_SRC_SHIFT 0u
133 #define QB_SDQCR_SRC_MASK 0xFFFFu
134
135 /* Shifts in the VERB byte of the volatile dequeue command. */
136 #define QB_VDQCR_VERB_DCT0_SHIFT 0
137 #define QB_VDQCR_VERB_DCT1_SHIFT 1
138 #define QB_VDQCR_VERB_DT0_SHIFT 2
139 #define QB_VDQCR_VERB_DT1_SHIFT 3
140 #define QB_VDQCR_VERB_RLS_SHIFT 4
141 #define QB_VDQCR_VERB_WAE_SHIFT 5
142 #define QB_VDQCR_VERB_RAD_SHIFT 6
143
144 /* Maximum timeout period for the DQRR interrupt. */
145 #define DQRR_MAX_ITP 4096u
146 #define DQRR_PI_MASK 0x0Fu
147
148 /* Release Array Allocation register helpers. */
149 #define RAR_IDX(rar) ((rar) & 0x7u)
150 #define RAR_VB(rar) ((rar) & 0x80u)
151 #define RAR_SUCCESS(rar) ((rar) & 0x100u)
152
153 MALLOC_DEFINE(M_DPAA2_SWP, "dpaa2_swp", "DPAA2 QBMan Software Portal");
154
155 enum qbman_sdqcr_dct {
156 qbman_sdqcr_dct_null = 0,
157 qbman_sdqcr_dct_prio_ics,
158 qbman_sdqcr_dct_active_ics,
159 qbman_sdqcr_dct_active
160 };
161
162 enum qbman_sdqcr_fc {
163 qbman_sdqcr_fc_one = 0,
164 qbman_sdqcr_fc_up_to_3 = 1
165 };
166
167 /* Routines to execute software portal commands. */
168 static int dpaa2_swp_exec_mgmt_command(struct dpaa2_swp *,
169 struct dpaa2_swp_cmd *, struct dpaa2_swp_rsp *, uint8_t);
170 static int dpaa2_swp_exec_br_command(struct dpaa2_swp *, struct dpaa2_swp_cmd *,
171 uint32_t);
172 static int dpaa2_swp_exec_vdc_command_locked(struct dpaa2_swp *,
173 struct dpaa2_swp_cmd *);
174
175 /* Management Commands helpers. */
176 static int dpaa2_swp_send_mgmt_command(struct dpaa2_swp *,
177 struct dpaa2_swp_cmd *, uint8_t);
178 static int dpaa2_swp_wait_for_mgmt_response(struct dpaa2_swp *,
179 struct dpaa2_swp_rsp *);
180
181 /* Helper subroutines. */
182 static int dpaa2_swp_cyc_diff(uint8_t, uint8_t, uint8_t);
183
184 int
185 dpaa2_swp_init_portal(struct dpaa2_swp **swp, struct dpaa2_swp_desc *desc,
186 uint16_t flags)
187 {
188 struct dpaa2_swp *p;
189 uint32_t reg, mask_size, eqcr_pi; /* EQCR producer index */
190
191 if (!swp || !desc)
192 return (DPAA2_SWP_STAT_EINVAL);
193
194 p = malloc(sizeof(struct dpaa2_swp), M_DPAA2_SWP,
195 flags & DPAA2_SWP_NOWAIT_ALLOC
196 ? (M_NOWAIT | M_ZERO)
197 : (M_WAITOK | M_ZERO));
198 if (!p)
199 return (DPAA2_SWP_STAT_NO_MEMORY);
200
201 mtx_init(&p->lock, "swp_sleep_lock", NULL, MTX_DEF);
202
203 p->cfg.mem_backed = false;
204 p->cfg.writes_cinh = true;
205
206 p->desc = desc;
207 p->flags = flags;
208 p->mc.valid_bit = DPAA2_SWP_VALID_BIT;
209 p->mr.valid_bit = DPAA2_SWP_VALID_BIT;
210
211 /* FIXME: Memory-backed mode doesn't work now. Why? */
212 p->cena_res = desc->cena_res;
213 p->cena_map = desc->cena_map;
214 p->cinh_res = desc->cinh_res;
215 p->cinh_map = desc->cinh_map;
216
217 /* Static Dequeue Command Register configuration. */
218 p->sdq = 0;
219 p->sdq |= qbman_sdqcr_dct_prio_ics << QB_SDQCR_DCT_SHIFT;
220 p->sdq |= qbman_sdqcr_fc_up_to_3 << QB_SDQCR_FC_SHIFT;
221 p->sdq |= DPAA2_SWP_SDQCR_TOKEN << QB_SDQCR_TOK_SHIFT;
222
223 /* Volatile Dequeue Command configuration. */
224 p->vdq.valid_bit = DPAA2_SWP_VALID_BIT;
225
226 /* Dequeue Response Ring configuration */
227 p->dqrr.next_idx = 0;
228 p->dqrr.valid_bit = DPAA2_SWP_VALID_BIT;
229 if ((desc->swp_version & DPAA2_SWP_REV_MASK) < DPAA2_SWP_REV_4100) {
230 p->dqrr.ring_size = 4;
231 p->dqrr.reset_bug = 1;
232 } else {
233 p->dqrr.ring_size = 8;
234 p->dqrr.reset_bug = 0;
235 }
236
237 if ((desc->swp_version & DPAA2_SWP_REV_MASK) < DPAA2_SWP_REV_5000) {
238 reg = dpaa2_swp_set_cfg(
239 p->dqrr.ring_size, /* max. entries QMan writes to DQRR */
240 1, /* writes enabled in the CINH memory only */
241 0, /* EQCR_CI stashing threshold */
242 3, /* RPM: RCR in array mode */
243 2, /* DCM: Discrete consumption ack */
244 2, /* EPM: EQCR in ring mode (FIFO) */
245 1, /* mem stashing drop enable enable */
246 1, /* mem stashing priority enable */
247 1, /* mem stashing enable */
248 1, /* dequeue stashing priority enable */
249 0, /* dequeue stashing enable enable */
250 0 /* EQCR_CI stashing priority enable */
251 );
252 reg &= ~(1 << DPAA2_SWP_CFG_CPBS_SHIFT); /* QMan-backed mode */
253 } else {
254 bus_set_region_4(p->cena_map, 0, 0,
255 rman_get_size(p->cena_res) / 4);
256
257 reg = dpaa2_swp_set_cfg(
258 p->dqrr.ring_size, /* max. entries QMan writes to DQRR */ /* DQRR_MF */
259 1, /* writes enabled in the CINH memory only */ /* WN */
260 0, /* EQCR_CI stashing is disabled */ /* EST */
261 3, /* RPM: RCR in array mode */ /* RPM */
262 2, /* DCM: Discrete consumption ack */ /* DCM */
263 2, /* EPM: EQCR in ring mode (FIFO) */ /* EPM */
264 1, /* Dequeued frame data, annotation, and FQ context stashing drop enable */ /* SD */
265 1, /* Dequeued frame data, annotation, and FQ context stashing priority */ /* SP */
266 1, /* Dequeued frame data, annotation, and FQ context stashing enable */ /* SE */
267 1, /* Dequeue response ring (DQRR) entry stashing priority */ /* DP */
268 0, /* Dequeue response ring (DQRR) entry, or cacheable portal area, stashing enable. */ /* DE */
269 0 /* EQCR_CI stashing priority */ /* EP */
270 );
271 /* TODO: Switch to memory-backed mode. */
272 reg &= ~(1 << DPAA2_SWP_CFG_CPBS_SHIFT); /* QMan-backed mode */
273 }
274 dpaa2_swp_write_reg(p, DPAA2_SWP_CINH_CFG, reg);
275 reg = dpaa2_swp_read_reg(p, DPAA2_SWP_CINH_CFG);
276 if (!reg) {
277 free(p, M_DPAA2_SWP);
278 return (DPAA2_SWP_STAT_PORTAL_DISABLED);
279 }
280
281 /*
282 * Static Dequeue Command Register needs to be initialized to 0 when no
283 * channels are being dequeued from or else the QMan HW will indicate an
284 * error. The values that were calculated above will be applied when
285 * dequeues from a specific channel are enabled.
286 */
287 dpaa2_swp_write_reg(p, DPAA2_SWP_CINH_SDQCR, 0);
288
289 p->eqcr.pi_ring_size = 8;
290 /* if ((desc->swp_version & DPAA2_SWP_REV_MASK) >= DPAA2_SWP_REV_5000) */
291 /* p->eqcr.pi_ring_size = 32; */
292
293 for (mask_size = p->eqcr.pi_ring_size; mask_size > 0; mask_size >>= 1)
294 p->eqcr.pi_ci_mask = (p->eqcr.pi_ci_mask << 1) + 1;
295
296 eqcr_pi = dpaa2_swp_read_reg(p, DPAA2_SWP_CINH_EQCR_PI);
297 p->eqcr.pi = eqcr_pi & p->eqcr.pi_ci_mask;
298 p->eqcr.pi_vb = eqcr_pi & DPAA2_SWP_VALID_BIT;
299 p->eqcr.ci = dpaa2_swp_read_reg(p, DPAA2_SWP_CINH_EQCR_CI)
300 & p->eqcr.pi_ci_mask;
301 p->eqcr.available = p->eqcr.pi_ring_size;
302
303 /* Initialize the portal with an IRQ threshold and timeout of 0us. */
304 dpaa2_swp_set_irq_coalescing(p, p->dqrr.ring_size - 1, 0);
305
306 *swp = p;
307
308 return (0);
309 }
310
311 void
312 dpaa2_swp_free_portal(struct dpaa2_swp *swp)
313 {
314 uint16_t flags;
315
316 KASSERT(swp != NULL, ("%s: swp is NULL", __func__));
317
318 DPAA2_SWP_LOCK(swp, &flags);
319 swp->flags |= DPAA2_SWP_DESTROYED;
320 DPAA2_SWP_UNLOCK(swp);
321
322 /* Let threads stop using this portal. */
323 DELAY(DPAA2_SWP_TIMEOUT);
324
325 mtx_destroy(&swp->lock);
326 free(swp, M_DPAA2_SWP);
327 }
328
329 uint32_t
330 dpaa2_swp_set_cfg(uint8_t max_fill, uint8_t wn, uint8_t est, uint8_t rpm,
331 uint8_t dcm, uint8_t epm, int sd, int sp, int se, int dp, int de, int ep)
332 {
333 return (
334 max_fill << DPAA2_SWP_CFG_DQRR_MF_SHIFT |
335 est << DPAA2_SWP_CFG_EST_SHIFT |
336 wn << DPAA2_SWP_CFG_WN_SHIFT |
337 rpm << DPAA2_SWP_CFG_RPM_SHIFT |
338 dcm << DPAA2_SWP_CFG_DCM_SHIFT |
339 epm << DPAA2_SWP_CFG_EPM_SHIFT |
340 sd << DPAA2_SWP_CFG_SD_SHIFT |
341 sp << DPAA2_SWP_CFG_SP_SHIFT |
342 se << DPAA2_SWP_CFG_SE_SHIFT |
343 dp << DPAA2_SWP_CFG_DP_SHIFT |
344 de << DPAA2_SWP_CFG_DE_SHIFT |
345 ep << DPAA2_SWP_CFG_EP_SHIFT
346 );
347 }
348
349 /* Read/write registers of a software portal. */
350
351 void
352 dpaa2_swp_write_reg(struct dpaa2_swp *swp, uint32_t o, uint32_t v)
353 {
354 bus_write_4(swp->cinh_map, o, v);
355 }
356
357 uint32_t
358 dpaa2_swp_read_reg(struct dpaa2_swp *swp, uint32_t o)
359 {
360 return (bus_read_4(swp->cinh_map, o));
361 }
362
363 /* Helper routines. */
364
365 /**
366 * @brief Set enqueue descriptor without Order Point Record ID.
367 *
368 * ed: Enqueue descriptor.
369 * resp_always: Enqueue with response always (1); FD from a rejected enqueue
370 * will be returned on a FQ (0).
371 */
372 void
373 dpaa2_swp_set_ed_norp(struct dpaa2_eq_desc *ed, bool resp_always)
374 {
375 ed->verb &= ~(1 << ENQ_CMD_ORP_ENABLE_SHIFT);
376 if (resp_always)
377 ed->verb |= ENQ_CMD_RESPONSE_ALWAYS;
378 else
379 ed->verb |= ENQ_CMD_REJECTS_TO_FQ;
380 }
381
382 /**
383 * @brief Set FQ of the enqueue descriptor.
384 */
385 void
386 dpaa2_swp_set_ed_fq(struct dpaa2_eq_desc *ed, uint32_t fqid)
387 {
388 ed->verb &= ~(1 << ENQ_CMD_TARGET_TYPE_SHIFT);
389 ed->tgtid = fqid;
390 }
391
392 /**
393 * @brief Enable interrupts for a software portal.
394 */
395 void
396 dpaa2_swp_set_intr_trigger(struct dpaa2_swp *swp, uint32_t mask)
397 {
398 if (swp != NULL)
399 dpaa2_swp_write_reg(swp, DPAA2_SWP_CINH_IER, mask);
400 }
401
402 /**
403 * @brief Return the value in the SWP_IER register.
404 */
405 uint32_t
406 dpaa2_swp_get_intr_trigger(struct dpaa2_swp *swp)
407 {
408 if (swp != NULL)
409 return dpaa2_swp_read_reg(swp, DPAA2_SWP_CINH_IER);
410 return (0);
411 }
412
413 /**
414 * @brief Return the value in the SWP_ISR register.
415 */
416 uint32_t
417 dpaa2_swp_read_intr_status(struct dpaa2_swp *swp)
418 {
419 if (swp != NULL)
420 return dpaa2_swp_read_reg(swp, DPAA2_SWP_CINH_ISR);
421 return (0);
422 }
423
424 /**
425 * @brief Clear SWP_ISR register according to the given mask.
426 */
427 void
428 dpaa2_swp_clear_intr_status(struct dpaa2_swp *swp, uint32_t mask)
429 {
430 if (swp != NULL)
431 dpaa2_swp_write_reg(swp, DPAA2_SWP_CINH_ISR, mask);
432 }
433
434 /**
435 * @brief Enable or disable push dequeue.
436 *
437 * swp: the software portal object
438 * chan_idx: the channel index (0 to 15)
439 * en: enable or disable push dequeue
440 */
441 void
442 dpaa2_swp_set_push_dequeue(struct dpaa2_swp *swp, uint8_t chan_idx, bool en)
443 {
444 uint16_t dqsrc;
445
446 if (swp != NULL) {
447 if (chan_idx > 15u) {
448 device_printf(swp->desc->dpio_dev, "channel index "
449 "should be <= 15: chan_idx=%d\n", chan_idx);
450 return;
451 }
452
453 if (en)
454 swp->sdq |= 1 << chan_idx;
455 else
456 swp->sdq &= ~(1 << chan_idx);
457 /*
458 * Read make the complete src map. If no channels are enabled
459 * the SDQCR must be 0 or else QMan will assert errors.
460 */
461 dqsrc = (swp->sdq >> DPAA2_SDQCR_SRC_SHIFT) &
462 DPAA2_SDQCR_SRC_MASK;
463 dpaa2_swp_write_reg(swp, DPAA2_SWP_CINH_SDQCR, dqsrc != 0
464 ? swp->sdq : 0);
465 }
466 }
467
468 /**
469 * @brief Set new IRQ coalescing values.
470 *
471 * swp: The software portal object.
472 * threshold: Threshold for DQRR interrupt generation. The DQRR interrupt
473 * asserts when the ring contains greater than "threshold" entries.
474 * holdoff: DQRR interrupt holdoff (timeout) period in us.
475 */
476 int dpaa2_swp_set_irq_coalescing(struct dpaa2_swp *swp, uint32_t threshold,
477 uint32_t holdoff)
478 {
479 uint32_t itp; /* Interrupt Timeout Period */
480
481 if (swp == NULL)
482 return (EINVAL);
483
484 /*
485 * Convert "holdoff" value from us to 256 QBMAN clock cycles
486 * increments. This depends on the QBMAN internal frequency.
487 */
488 itp = (holdoff * 1000u) / swp->desc->swp_cycles_ratio;
489 if (itp > DQRR_MAX_ITP)
490 itp = DQRR_MAX_ITP;
491 if (threshold >= swp->dqrr.ring_size)
492 threshold = swp->dqrr.ring_size - 1;
493
494 swp->dqrr.irq_threshold = threshold;
495 swp->dqrr.irq_itp = itp;
496
497 dpaa2_swp_write_reg(swp, DPAA2_SWP_CINH_DQRR_ITR, threshold);
498 dpaa2_swp_write_reg(swp, DPAA2_SWP_CINH_ITPR, itp);
499
500 return (0);
501 }
502
503 /*
504 * Software portal commands.
505 */
506
507 /**
508 * @brief Configure the channel data availability notification (CDAN)
509 * in a particular WQ channel.
510 */
511 int
512 dpaa2_swp_conf_wq_channel(struct dpaa2_swp *swp, uint16_t chan_id,
513 uint8_t we_mask, bool cdan_en, uint64_t ctx)
514 {
515 /* NOTE: 64 bytes command. */
516 struct __packed {
517 uint8_t verb;
518 uint8_t result; /* in response only! */
519 uint16_t chan_id;
520 uint8_t we;
521 uint8_t ctrl;
522 uint16_t _reserved2;
523 uint64_t ctx;
524 uint8_t _reserved3[48];
525 } cmd = {0};
526 struct __packed {
527 uint8_t verb;
528 uint8_t result;
529 uint16_t chan_id;
530 uint8_t _reserved[60];
531 } rsp;
532 int error;
533
534 if (swp == NULL)
535 return (EINVAL);
536
537 cmd.chan_id = chan_id;
538 cmd.we = we_mask;
539 cmd.ctrl = cdan_en ? 1u : 0u;
540 cmd.ctx = ctx;
541
542 error = dpaa2_swp_exec_mgmt_command(swp, (struct dpaa2_swp_cmd *) &cmd,
543 (struct dpaa2_swp_rsp *) &rsp, CMDID_SWP_WQCHAN_CONFIGURE);
544 if (error)
545 return (error);
546
547 if (rsp.result != QBMAN_CMD_RC_OK) {
548 device_printf(swp->desc->dpio_dev, "WQ channel configuration "
549 "error: channel_id=%d, result=0x%02x\n", chan_id,
550 rsp.result);
551 return (EIO);
552 }
553
554 return (0);
555 }
556
557 /**
558 * @brief Query current configuration/state of the buffer pool.
559 */
560 int
561 dpaa2_swp_query_bp(struct dpaa2_swp *swp, uint16_t bpid,
562 struct dpaa2_bp_conf *conf)
563 {
564 /* NOTE: 64 bytes command. */
565 struct __packed {
566 uint8_t verb;
567 uint8_t _reserved1;
568 uint16_t bpid;
569 uint8_t _reserved2[60];
570 } cmd = {0};
571 struct __packed {
572 uint8_t verb;
573 uint8_t result;
574 uint32_t _reserved1;
575 uint8_t bdi;
576 uint8_t state;
577 uint32_t fill;
578 /* TODO: Support the other fields as well. */
579 uint8_t _reserved2[52];
580 } rsp;
581 int error;
582
583 if (swp == NULL || conf == NULL)
584 return (EINVAL);
585
586 cmd.bpid = bpid;
587
588 error = dpaa2_swp_exec_mgmt_command(swp, (struct dpaa2_swp_cmd *) &cmd,
589 (struct dpaa2_swp_rsp *) &rsp, CMDID_SWP_BP_QUERY);
590 if (error)
591 return (error);
592
593 if (rsp.result != QBMAN_CMD_RC_OK) {
594 device_printf(swp->desc->dpio_dev, "BP query error: bpid=%d, "
595 "result=0x%02x\n", bpid, rsp.result);
596 return (EIO);
597 }
598
599 conf->bdi = rsp.bdi;
600 conf->state = rsp.state;
601 conf->free_bufn = rsp.fill;
602
603 return (0);
604 }
605
606 int
607 dpaa2_swp_release_bufs(struct dpaa2_swp *swp, uint16_t bpid, bus_addr_t *buf,
608 uint32_t buf_num)
609 {
610 /* NOTE: 64 bytes command. */
611 struct __packed {
612 uint8_t verb;
613 uint8_t _reserved1;
614 uint16_t bpid;
615 uint32_t _reserved2;
616 uint64_t buf[DPAA2_SWP_BUFS_PER_CMD];
617 } cmd = {0};
618 int error;
619
620 if (swp == NULL || buf == NULL || buf_num == 0u ||
621 buf_num > DPAA2_SWP_BUFS_PER_CMD)
622 return (EINVAL);
623
624 for (uint32_t i = 0; i < buf_num; i++)
625 cmd.buf[i] = buf[i];
626 cmd.bpid = bpid;
627 cmd.verb |= 1 << 5; /* Switch release buffer command to valid. */
628
629 error = dpaa2_swp_exec_br_command(swp, (struct dpaa2_swp_cmd *) &cmd,
630 buf_num);
631 if (error) {
632 device_printf(swp->desc->dpio_dev, "buffers release command "
633 "failed\n");
634 return (error);
635 }
636
637 return (0);
638 }
639
640 int
641 dpaa2_swp_dqrr_next_locked(struct dpaa2_swp *swp, struct dpaa2_dq *dq,
642 uint32_t *idx)
643 {
644 struct resource_map *map = swp->cinh_map;
645 struct dpaa2_swp_rsp *rsp = (struct dpaa2_swp_rsp *) dq;
646 uint32_t verb, pi; /* producer index */
647 uint32_t offset = swp->cfg.mem_backed
648 ? DPAA2_SWP_CENA_DQRR_MEM(swp->dqrr.next_idx)
649 : DPAA2_SWP_CENA_DQRR(swp->dqrr.next_idx);
650
651 if (swp == NULL || dq == NULL)
652 return (EINVAL);
653
654 /*
655 * Before using valid-bit to detect if something is there, we have to
656 * handle the case of the DQRR reset bug...
657 */
658 if (swp->dqrr.reset_bug) {
659 /*
660 * We pick up new entries by cache-inhibited producer index,
661 * which means that a non-coherent mapping would require us to
662 * invalidate and read *only* once that PI has indicated that
663 * there's an entry here. The first trip around the DQRR ring
664 * will be much less efficient than all subsequent trips around
665 * it...
666 */
667 pi = dpaa2_swp_read_reg(swp, DPAA2_SWP_CINH_DQPI) & DQRR_PI_MASK;
668
669 /* There are new entries if pi != next_idx */
670 if (pi == swp->dqrr.next_idx)
671 return (ENOENT);
672
673 /*
674 * If next_idx is/was the last ring index, and 'pi' is
675 * different, we can disable the workaround as all the ring
676 * entries have now been DMA'd to so valid-bit checking is
677 * repaired.
678 *
679 * NOTE: This logic needs to be based on next_idx (which
680 * increments one at a time), rather than on pi (which
681 * can burst and wrap-around between our snapshots of it).
682 */
683 if (swp->dqrr.next_idx == (swp->dqrr.ring_size - 1))
684 swp->dqrr.reset_bug = 0;
685 }
686
687 verb = bus_read_4(map, offset);
688 if ((verb & DPAA2_SWP_VALID_BIT) != swp->dqrr.valid_bit)
689 return (ENOENT);
690
691 /* Read dequeue response message. */
692 for (int i = 0; i < DPAA2_SWP_RSP_PARAMS_N; i++)
693 rsp->params[i] = bus_read_8(map, offset + i * sizeof(uint64_t));
694
695 /* Return index of the current entry (if requested). */
696 if (idx != NULL)
697 *idx = swp->dqrr.next_idx;
698
699 /*
700 * There's something there. Move "next_idx" attention to the next ring
701 * entry before returning what we found.
702 */
703 swp->dqrr.next_idx++;
704 swp->dqrr.next_idx &= swp->dqrr.ring_size - 1; /* wrap around */
705 if (swp->dqrr.next_idx == 0u)
706 swp->dqrr.valid_bit ^= DPAA2_SWP_VALID_BIT;
707
708 return (0);
709 }
710
711 int
712 dpaa2_swp_pull(struct dpaa2_swp *swp, uint16_t chan_id, struct dpaa2_buf *buf,
713 uint32_t frames_n)
714 {
715 /* NOTE: 64 bytes command. */
716 struct __packed {
717 uint8_t verb;
718 uint8_t numf;
719 uint8_t tok;
720 uint8_t _reserved;
721 uint32_t dq_src;
722 uint64_t rsp_addr;
723 uint64_t _reserved1[6];
724 } cmd = {0};
725 struct dpaa2_dq *msg;
726 uint16_t flags;
727 int i, error;
728
729 KASSERT(swp != NULL, ("%s: swp is NULL", __func__));
730 KASSERT(frames_n != 0u, ("%s: cannot pull zero frames", __func__));
731 KASSERT(frames_n <= 16u, ("%s: too much frames to pull", __func__));
732 KASSERT(buf->type == DPAA2_BUF_STORE, ("%s: not channel storage "
733 "buffer", __func__));
734
735 cmd.numf = frames_n - 1;
736 cmd.tok = DPAA2_SWP_VDQCR_TOKEN;
737 cmd.dq_src = chan_id;
738 cmd.rsp_addr = (uint64_t) buf->store.paddr;
739
740 /* Dequeue command type */
741 cmd.verb &= ~(1 << QB_VDQCR_VERB_DCT0_SHIFT);
742 cmd.verb |= (1 << QB_VDQCR_VERB_DCT1_SHIFT);
743 /* Dequeue from a specific software portal channel (ID's in DQ_SRC). */
744 cmd.verb &= ~(1 << QB_VDQCR_VERB_DT0_SHIFT);
745 cmd.verb &= ~(1 << QB_VDQCR_VERB_DT1_SHIFT);
746 /* Write the response to this command into memory (at the RSP_ADDR). */
747 cmd.verb |= (1 << QB_VDQCR_VERB_RLS_SHIFT);
748 /* Response writes won't attempt to allocate into a cache. */
749 cmd.verb &= ~(1 << QB_VDQCR_VERB_WAE_SHIFT);
750 /* Allow the FQ to remain active in the portal after dequeue. */
751 cmd.verb &= ~(1 << QB_VDQCR_VERB_RAD_SHIFT);
752
753 DPAA2_SWP_LOCK(swp, &flags);
754 if (flags & DPAA2_SWP_DESTROYED) {
755 /* Terminate operation if portal is destroyed. */
756 DPAA2_SWP_UNLOCK(swp);
757 return (ENOENT);
758 }
759
760 error = dpaa2_swp_exec_vdc_command_locked(swp,
761 (struct dpaa2_swp_cmd *) &cmd);
762 if (error != 0) {
763 DPAA2_SWP_UNLOCK(swp);
764 return (error);
765 }
766
767 /* Let's sync before reading VDQ response from QBMan. */
768 bus_dmamap_sync(buf->store.dmat, buf->store.dmap, BUS_DMASYNC_POSTREAD);
769
770 /* Read VDQ response from QBMan. */
771 msg = (struct dpaa2_dq *) buf->store.vaddr;
772 for (i = 1; i <= CMD_SPIN_ATTEMPTS; i++) {
773 if ((msg->fdr.desc.stat & DPAA2_DQ_STAT_VOLATILE) &&
774 (msg->fdr.desc.tok == DPAA2_SWP_VDQCR_TOKEN)) {
775 /* Reset token. */
776 msg->fdr.desc.tok = 0;
777 break;
778 }
779 DELAY(CMD_SPIN_TIMEOUT);
780 }
781 DPAA2_SWP_UNLOCK(swp);
782
783 /* Return an error on expired timeout. */
784 return (i > CMD_SPIN_ATTEMPTS ? ETIMEDOUT : 0);
785 }
786
787 /**
788 * @brief Issue a command to enqueue a frame using one enqueue descriptor.
789 *
790 * swp: Software portal used to send this command to.
791 * ed: Enqueue command descriptor.
792 * fd: Frame descriptor to enqueue.
793 */
794 int
795 dpaa2_swp_enq(struct dpaa2_swp *swp, struct dpaa2_eq_desc *ed,
796 struct dpaa2_fd *fd)
797 {
798 uint32_t flags = 0;
799 int rc = dpaa2_swp_enq_mult(swp, ed, fd, &flags, 1);
800
801 return (rc >= 0 ? 0 : EBUSY);
802 }
803
804 /**
805 * @brief Issue a command to enqueue frames using one enqueue descriptor.
806 *
807 * swp: Software portal used to send this command to.
808 * ed: Enqueue command descriptor.
809 * fd: Frame descriptor to enqueue.
810 * flags: Table pointer of QBMAN_ENQUEUE_FLAG_DCA flags, not used if NULL.
811 * frames_n: Number of FDs to enqueue.
812 *
813 * NOTE: Enqueue command (64 bytes): 32 (eq. descriptor) + 32 (frame descriptor).
814 */
815 int
816 dpaa2_swp_enq_mult(struct dpaa2_swp *swp, struct dpaa2_eq_desc *ed,
817 struct dpaa2_fd *fd, uint32_t *flags, int frames_n)
818 {
819 const uint8_t *ed_pdat8 = (const uint8_t *) ed;
820 const uint32_t *ed_pdat32 = (const uint32_t *) ed;
821 const uint64_t *ed_pdat64 = (const uint64_t *) ed;
822 const uint64_t *fd_pdat64 = (const uint64_t *) fd;
823 struct resource_map *map;
824 uint32_t eqcr_ci, eqcr_pi; /* EQCR consumer/producer index */
825 uint32_t half_mask, full_mask, val, ci_offset;
826 uint16_t swp_flags;
827 int num_enq = 0;
828
829 if (swp == NULL || ed == NULL || fd == NULL || flags == NULL ||
830 frames_n == 0)
831 return (EINVAL);
832
833 DPAA2_SWP_LOCK(swp, &swp_flags);
834 if (swp_flags & DPAA2_SWP_DESTROYED) {
835 /* Terminate operation if portal is destroyed. */
836 DPAA2_SWP_UNLOCK(swp);
837 return (ENOENT);
838 }
839
840 map = swp->cfg.writes_cinh ? swp->cinh_map : swp->cena_map;
841 ci_offset = swp->cfg.mem_backed
842 ? DPAA2_SWP_CENA_EQCR_CI_MEMBACK
843 : DPAA2_SWP_CENA_EQCR_CI;
844
845 half_mask = swp->eqcr.pi_ci_mask >> 1;
846 full_mask = swp->eqcr.pi_ci_mask;
847
848 if (swp->eqcr.available == 0) {
849 val = dpaa2_swp_read_reg(swp, ci_offset);
850 eqcr_ci = swp->eqcr.ci;
851 swp->eqcr.ci = val & full_mask;
852
853 swp->eqcr.available = dpaa2_swp_cyc_diff(swp->eqcr.pi_ring_size,
854 eqcr_ci, swp->eqcr.ci);
855
856 if (swp->eqcr.available == 0) {
857 DPAA2_SWP_UNLOCK(swp);
858 return (0);
859 }
860 }
861
862 eqcr_pi = swp->eqcr.pi;
863 num_enq = swp->eqcr.available < frames_n
864 ? swp->eqcr.available : frames_n;
865 swp->eqcr.available -= num_enq;
866
867 KASSERT(num_enq >= 0 && num_enq <= swp->eqcr.pi_ring_size,
868 ("%s: unexpected num_enq=%d", __func__, num_enq));
869 KASSERT(swp->eqcr.available >= 0 &&
870 swp->eqcr.available <= swp->eqcr.pi_ring_size,
871 ("%s: unexpected eqcr.available=%d", __func__, swp->eqcr.available));
872
873 /* Fill in the EQCR ring. */
874 for (int i = 0; i < num_enq; i++) {
875 /* Write enq. desc. without the VERB, DCA, SEQNUM and OPRID. */
876 for (int j = 1; j <= 3; j++)
877 bus_write_8(map,
878 DPAA2_SWP_CENA_EQCR(eqcr_pi & half_mask) +
879 sizeof(uint64_t) * j, ed_pdat64[j]);
880 /* Write OPRID. */
881 bus_write_4(map,
882 DPAA2_SWP_CENA_EQCR(eqcr_pi & half_mask) + sizeof(uint32_t),
883 ed_pdat32[1]);
884 /* Write DCA and SEQNUM without VERB byte. */
885 for (int j = 1; j <= 3; j++)
886 bus_write_1(map,
887 DPAA2_SWP_CENA_EQCR(eqcr_pi & half_mask) +
888 sizeof(uint8_t) * j, ed_pdat8[j]);
889
890 /* Write frame descriptor. */
891 for (int j = 0; j <= 3; j++)
892 bus_write_8(map,
893 DPAA2_SWP_CENA_EQCR(eqcr_pi & half_mask) +
894 ENQ_DESC_FD_OFFSET +
895 sizeof(uint64_t) * j, fd_pdat64[j]);
896 eqcr_pi++;
897 }
898
899 wmb();
900
901 /* Write the VERB byte of enqueue descriptor. */
902 eqcr_pi = swp->eqcr.pi;
903 for (int i = 0; i < num_enq; i++) {
904 bus_write_1(map,
905 DPAA2_SWP_CENA_EQCR(eqcr_pi & half_mask),
906 ed_pdat8[0] | swp->eqcr.pi_vb);
907
908 if (flags && (flags[i] & ENQ_FLAG_DCA)) {
909 /* Update DCA byte. */
910 bus_write_1(map,
911 DPAA2_SWP_CENA_EQCR(eqcr_pi & half_mask) + 1,
912 (1 << ENQ_CMD_DCA_EN_SHIFT) |
913 (flags[i] & ENQ_DCA_IDXMASK));
914 }
915 eqcr_pi++;
916 if (!(eqcr_pi & half_mask))
917 swp->eqcr.pi_vb ^= DPAA2_SWP_VALID_BIT;
918 }
919 swp->eqcr.pi = eqcr_pi & full_mask;
920
921 DPAA2_SWP_UNLOCK(swp);
922
923 return (num_enq);
924 }
925
926 static int
927 dpaa2_swp_cyc_diff(uint8_t ringsize, uint8_t first, uint8_t last)
928 {
929 /* 'first' is included, 'last' is excluded */
930 return ((first <= last)
931 ? (last - first) : ((2 * ringsize) - (first - last)));
932 }
933
934 /**
935 * @brief Execute Buffer Release Command (BRC).
936 */
937 static int
938 dpaa2_swp_exec_br_command(struct dpaa2_swp *swp, struct dpaa2_swp_cmd *cmd,
939 uint32_t buf_num)
940 {
941 struct __packed with_verb {
942 uint8_t verb;
943 uint8_t _reserved[63];
944 } *c;
945 const uint8_t *cmd_pdat8 = (const uint8_t *) cmd->params;
946 const uint32_t *cmd_pdat32 = (const uint32_t *) cmd->params;
947 struct resource_map *map;
948 uint32_t offset, rar; /* Release Array Allocation register */
949 uint16_t flags;
950
951 if (!swp || !cmd)
952 return (EINVAL);
953
954 DPAA2_SWP_LOCK(swp, &flags);
955 if (flags & DPAA2_SWP_DESTROYED) {
956 /* Terminate operation if portal is destroyed. */
957 DPAA2_SWP_UNLOCK(swp);
958 return (ENOENT);
959 }
960
961 rar = dpaa2_swp_read_reg(swp, DPAA2_SWP_CINH_RAR);
962 if (!RAR_SUCCESS(rar)) {
963 DPAA2_SWP_UNLOCK(swp);
964 return (EBUSY);
965 }
966
967 map = swp->cfg.writes_cinh ? swp->cinh_map : swp->cena_map;
968 offset = swp->cfg.mem_backed
969 ? DPAA2_SWP_CENA_RCR_MEM(RAR_IDX(rar))
970 : DPAA2_SWP_CENA_RCR(RAR_IDX(rar));
971 c = (struct with_verb *) cmd;
972
973 /* Write command bytes (without VERB byte). */
974 for (uint32_t i = 1; i < DPAA2_SWP_CMD_PARAMS_N; i++)
975 bus_write_8(map, offset + sizeof(uint64_t) * i, cmd->params[i]);
976 bus_write_4(map, offset + 4, cmd_pdat32[1]);
977 for (uint32_t i = 1; i <= 3; i++)
978 bus_write_1(map, offset + i, cmd_pdat8[i]);
979
980 /* Write VERB byte and trigger command execution. */
981 if (swp->cfg.mem_backed) {
982 bus_write_1(map, offset, c->verb | RAR_VB(rar) | buf_num);
983 wmb();
984 dpaa2_swp_write_reg(swp, DPAA2_SWP_CINH_RCR_AM_RT +
985 RAR_IDX(rar) * 4, DPAA2_SWP_RT_MODE);
986 } else {
987 wmb();
988 bus_write_1(map, offset, c->verb | RAR_VB(rar) | buf_num);
989 }
990
991 DPAA2_SWP_UNLOCK(swp);
992
993 return (0);
994 }
995
996 /**
997 * @brief Execute Volatile Dequeue Command (VDC).
998 *
999 * This command will be executed by QBMan only once in order to deliver requested
1000 * number of frames (1-16 or 1-32 depending on QBMan version) to the driver via
1001 * DQRR or arbitrary DMA-mapped memory.
1002 *
1003 * NOTE: There is a counterpart to the volatile dequeue command called static
1004 * dequeue command (SDQC) which is executed periodically all the time the
1005 * command is present in the SDQCR register.
1006 */
1007 static int
1008 dpaa2_swp_exec_vdc_command_locked(struct dpaa2_swp *swp,
1009 struct dpaa2_swp_cmd *cmd)
1010 {
1011 struct __packed with_verb {
1012 uint8_t verb;
1013 uint8_t _reserved[63];
1014 } *c;
1015 const uint8_t *p8 = (const uint8_t *) cmd->params;
1016 const uint32_t *p32 = (const uint32_t *) cmd->params;
1017 struct resource_map *map;
1018 uint32_t offset;
1019
1020 map = swp->cfg.writes_cinh ? swp->cinh_map : swp->cena_map;
1021 offset = swp->cfg.mem_backed
1022 ? DPAA2_SWP_CENA_VDQCR_MEM : DPAA2_SWP_CENA_VDQCR;
1023 c = (struct with_verb *) cmd;
1024
1025 /* Write command bytes (without VERB byte). */
1026 for (uint32_t i = 1; i < DPAA2_SWP_CMD_PARAMS_N; i++)
1027 bus_write_8(map, offset + sizeof(uint64_t) * i, cmd->params[i]);
1028 bus_write_4(map, offset + 4, p32[1]);
1029 for (uint32_t i = 1; i <= 3; i++)
1030 bus_write_1(map, offset + i, p8[i]);
1031
1032 /* Write VERB byte and trigger command execution. */
1033 if (swp->cfg.mem_backed) {
1034 bus_write_1(map, offset, c->verb | swp->vdq.valid_bit);
1035 swp->vdq.valid_bit ^= DPAA2_SWP_VALID_BIT;
1036 wmb();
1037 dpaa2_swp_write_reg(swp, DPAA2_SWP_CINH_VDQCR_RT,
1038 DPAA2_SWP_RT_MODE);
1039 } else {
1040 wmb();
1041 bus_write_1(map, offset, c->verb | swp->vdq.valid_bit);
1042 swp->vdq.valid_bit ^= DPAA2_SWP_VALID_BIT;
1043 }
1044
1045 return (0);
1046 }
1047
1048 /**
1049 * @brief Execute a QBMan management command.
1050 */
1051 static int
1052 dpaa2_swp_exec_mgmt_command(struct dpaa2_swp *swp, struct dpaa2_swp_cmd *cmd,
1053 struct dpaa2_swp_rsp *rsp, uint8_t cmdid)
1054 {
1055 #if (defined(_KERNEL) && defined(INVARIANTS))
1056 struct __packed with_verb {
1057 uint8_t verb;
1058 uint8_t _reserved[63];
1059 } *r;
1060 #endif
1061 uint16_t flags;
1062 int error;
1063
1064 if (swp == NULL || cmd == NULL || rsp == NULL)
1065 return (EINVAL);
1066
1067 DPAA2_SWP_LOCK(swp, &flags);
1068 if (flags & DPAA2_SWP_DESTROYED) {
1069 /* Terminate operation if portal is destroyed. */
1070 DPAA2_SWP_UNLOCK(swp);
1071 return (ENOENT);
1072 }
1073
1074 /*
1075 * Send a command to QBMan using Management Command register and wait
1076 * for response from the Management Response registers.
1077 */
1078 dpaa2_swp_send_mgmt_command(swp, cmd, cmdid);
1079 error = dpaa2_swp_wait_for_mgmt_response(swp, rsp);
1080 if (error) {
1081 DPAA2_SWP_UNLOCK(swp);
1082 return (error);
1083 }
1084 DPAA2_SWP_UNLOCK(swp);
1085
1086 #if (defined(_KERNEL) && defined(INVARIANTS))
1087 r = (struct with_verb *) rsp;
1088 KASSERT((r->verb & CMD_VERB_MASK) == cmdid,
1089 ("wrong VERB byte in response: resp=0x%02x, expected=0x%02x",
1090 r->verb, cmdid));
1091 #endif
1092
1093 return (0);
1094 }
1095
1096 static int
1097 dpaa2_swp_send_mgmt_command(struct dpaa2_swp *swp, struct dpaa2_swp_cmd *cmd,
1098 uint8_t cmdid)
1099 {
1100 const uint8_t *cmd_pdat8 = (const uint8_t *) cmd->params;
1101 const uint32_t *cmd_pdat32 = (const uint32_t *) cmd->params;
1102 struct resource_map *map;
1103 uint32_t offset;
1104
1105 map = swp->cfg.writes_cinh ? swp->cinh_map : swp->cena_map;
1106 offset = swp->cfg.mem_backed ? DPAA2_SWP_CENA_CR_MEM : DPAA2_SWP_CENA_CR;
1107
1108 /* Write command bytes (without VERB byte). */
1109 for (uint32_t i = 1; i < DPAA2_SWP_CMD_PARAMS_N; i++)
1110 bus_write_8(map, offset + sizeof(uint64_t) * i, cmd->params[i]);
1111 bus_write_4(map, offset + 4, cmd_pdat32[1]);
1112 for (uint32_t i = 1; i <= 3; i++)
1113 bus_write_1(map, offset + i, cmd_pdat8[i]);
1114
1115 /* Write VERB byte and trigger command execution. */
1116 if (swp->cfg.mem_backed) {
1117 bus_write_1(map, offset, cmdid | swp->mr.valid_bit);
1118 wmb();
1119 dpaa2_swp_write_reg(swp, DPAA2_SWP_CINH_CR_RT,
1120 DPAA2_SWP_RT_MODE);
1121 } else {
1122 wmb();
1123 bus_write_1(map, offset, cmdid | swp->mc.valid_bit);
1124 }
1125
1126 return (0);
1127 }
1128
1129 static int
1130 dpaa2_swp_wait_for_mgmt_response(struct dpaa2_swp *swp, struct dpaa2_swp_rsp *rsp)
1131 {
1132 struct resource_map *map = swp->cfg.mem_backed
1133 ? swp->cena_map : swp->cinh_map;
1134 /* Management command response to be read from the only RR or RR0/RR1. */
1135 const uint32_t offset = swp->cfg.mem_backed
1136 ? DPAA2_SWP_CENA_RR_MEM
1137 : DPAA2_SWP_CENA_RR(swp->mc.valid_bit);
1138 uint32_t i, verb, ret;
1139 int rc;
1140
1141 /* Wait for a command response from QBMan. */
1142 for (i = 1; i <= CMD_SPIN_ATTEMPTS; i++) {
1143 if (swp->cfg.mem_backed) {
1144 verb = (uint32_t) (bus_read_4(map, offset) & 0xFFu);
1145 if (swp->mr.valid_bit != (verb & DPAA2_SWP_VALID_BIT))
1146 goto wait;
1147 if (!(verb & ~DPAA2_SWP_VALID_BIT))
1148 goto wait;
1149 swp->mr.valid_bit ^= DPAA2_SWP_VALID_BIT;
1150 } else {
1151 ret = bus_read_4(map, offset);
1152 verb = ret & ~DPAA2_SWP_VALID_BIT; /* remove valid bit */
1153 if (verb == 0u)
1154 goto wait;
1155 swp->mc.valid_bit ^= DPAA2_SWP_VALID_BIT;
1156 }
1157 break;
1158 wait:
1159 DELAY(CMD_SPIN_TIMEOUT);
1160 }
1161 /* Return an error on expired timeout. */
1162 rc = i > CMD_SPIN_ATTEMPTS ? ETIMEDOUT : 0;
1163
1164 /* Read command response. */
1165 for (i = 0; i < DPAA2_SWP_RSP_PARAMS_N; i++)
1166 rsp->params[i] = bus_read_8(map, offset + i * sizeof(uint64_t));
1167
1168 return (rc);
1169 }
Cache object: b958d28f298afc6b126667893bb32c68
|