The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/dpaa2/dpaa2_swp.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.