linux/drivers/soc/fsl/qbman/qman_test_api.c
<<
>>
Prefs
   1/* Copyright 2008 - 2016 Freescale Semiconductor, Inc.
   2 *
   3 * Redistribution and use in source and binary forms, with or without
   4 * modification, are permitted provided that the following conditions are met:
   5 *     * Redistributions of source code must retain the above copyright
   6 *       notice, this list of conditions and the following disclaimer.
   7 *     * Redistributions in binary form must reproduce the above copyright
   8 *       notice, this list of conditions and the following disclaimer in the
   9 *       documentation and/or other materials provided with the distribution.
  10 *     * Neither the name of Freescale Semiconductor nor the
  11 *       names of its contributors may be used to endorse or promote products
  12 *       derived from this software without specific prior written permission.
  13 *
  14 * ALTERNATIVELY, this software may be distributed under the terms of the
  15 * GNU General Public License ("GPL") as published by the Free Software
  16 * Foundation, either version 2 of that License or (at your option) any
  17 * later version.
  18 *
  19 * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
  20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  22 * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
  23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29 */
  30
  31#include "qman_test.h"
  32
  33#define CGR_ID          27
  34#define POOL_ID         2
  35#define FQ_FLAGS        QMAN_FQ_FLAG_DYNAMIC_FQID
  36#define NUM_ENQUEUES    10
  37#define NUM_PARTIAL     4
  38#define PORTAL_SDQCR    (QM_SDQCR_SOURCE_CHANNELS | \
  39                        QM_SDQCR_TYPE_PRIO_QOS | \
  40                        QM_SDQCR_TOKEN_SET(0x98) | \
  41                        QM_SDQCR_CHANNELS_DEDICATED | \
  42                        QM_SDQCR_CHANNELS_POOL(POOL_ID))
  43#define PORTAL_OPAQUE   ((void *)0xf00dbeef)
  44#define VDQCR_FLAGS     (QMAN_VOLATILE_FLAG_WAIT | QMAN_VOLATILE_FLAG_FINISH)
  45
  46static enum qman_cb_dqrr_result cb_dqrr(struct qman_portal *,
  47                                        struct qman_fq *,
  48                                        const struct qm_dqrr_entry *,
  49                                        bool sched_napi);
  50static void cb_ern(struct qman_portal *, struct qman_fq *,
  51                   const union qm_mr_entry *);
  52static void cb_fqs(struct qman_portal *, struct qman_fq *,
  53                   const union qm_mr_entry *);
  54
  55static struct qm_fd fd, fd_dq;
  56static struct qman_fq fq_base = {
  57        .cb.dqrr = cb_dqrr,
  58        .cb.ern = cb_ern,
  59        .cb.fqs = cb_fqs
  60};
  61static DECLARE_WAIT_QUEUE_HEAD(waitqueue);
  62static int retire_complete, sdqcr_complete;
  63
  64/* Helpers for initialising and "incrementing" a frame descriptor */
  65static void fd_init(struct qm_fd *fd)
  66{
  67        qm_fd_addr_set64(fd, 0xabdeadbeefLLU);
  68        qm_fd_set_contig_big(fd, 0x0000ffff);
  69        fd->cmd = cpu_to_be32(0xfeedf00d);
  70}
  71
  72static void fd_inc(struct qm_fd *fd)
  73{
  74        u64 t = qm_fd_addr_get64(fd);
  75        int z = t >> 40;
  76        unsigned int len, off;
  77        enum qm_fd_format fmt;
  78
  79        t <<= 1;
  80        if (z)
  81                t |= 1;
  82        qm_fd_addr_set64(fd, t);
  83
  84        fmt = qm_fd_get_format(fd);
  85        off = qm_fd_get_offset(fd);
  86        len = qm_fd_get_length(fd);
  87        len--;
  88        qm_fd_set_param(fd, fmt, off, len);
  89
  90        be32_add_cpu(&fd->cmd, 1);
  91}
  92
  93/* The only part of the 'fd' we can't memcmp() is the ppid */
  94static bool fd_neq(const struct qm_fd *a, const struct qm_fd *b)
  95{
  96        bool neq = qm_fd_addr_get64(a) != qm_fd_addr_get64(b);
  97
  98        neq |= qm_fd_get_format(a) != qm_fd_get_format(b);
  99        neq |= a->cfg != b->cfg;
 100        neq |= a->cmd != b->cmd;
 101
 102        return neq;
 103}
 104
 105/* test */
 106static int do_enqueues(struct qman_fq *fq)
 107{
 108        unsigned int loop;
 109        int err = 0;
 110
 111        for (loop = 0; loop < NUM_ENQUEUES; loop++) {
 112                if (qman_enqueue(fq, &fd)) {
 113                        pr_crit("qman_enqueue() failed\n");
 114                        err = -EIO;
 115                }
 116                fd_inc(&fd);
 117        }
 118
 119        return err;
 120}
 121
 122int qman_test_api(void)
 123{
 124        unsigned int flags, frmcnt;
 125        int err;
 126        struct qman_fq *fq = &fq_base;
 127
 128        pr_info("%s(): Starting\n", __func__);
 129        fd_init(&fd);
 130        fd_init(&fd_dq);
 131
 132        /* Initialise (parked) FQ */
 133        err = qman_create_fq(0, FQ_FLAGS, fq);
 134        if (err) {
 135                pr_crit("qman_create_fq() failed\n");
 136                goto failed;
 137        }
 138        err = qman_init_fq(fq, QMAN_INITFQ_FLAG_LOCAL, NULL);
 139        if (err) {
 140                pr_crit("qman_init_fq() failed\n");
 141                goto failed;
 142        }
 143        /* Do enqueues + VDQCR, twice. (Parked FQ) */
 144        err = do_enqueues(fq);
 145        if (err)
 146                goto failed;
 147        pr_info("VDQCR (till-empty);\n");
 148        frmcnt = QM_VDQCR_NUMFRAMES_TILLEMPTY;
 149        err = qman_volatile_dequeue(fq, VDQCR_FLAGS, frmcnt);
 150        if (err) {
 151                pr_crit("qman_volatile_dequeue() failed\n");
 152                goto failed;
 153        }
 154        err = do_enqueues(fq);
 155        if (err)
 156                goto failed;
 157        pr_info("VDQCR (%d of %d);\n", NUM_PARTIAL, NUM_ENQUEUES);
 158        frmcnt = QM_VDQCR_NUMFRAMES_SET(NUM_PARTIAL);
 159        err = qman_volatile_dequeue(fq, VDQCR_FLAGS, frmcnt);
 160        if (err) {
 161                pr_crit("qman_volatile_dequeue() failed\n");
 162                goto failed;
 163        }
 164        pr_info("VDQCR (%d of %d);\n", NUM_ENQUEUES - NUM_PARTIAL,
 165                NUM_ENQUEUES);
 166        frmcnt = QM_VDQCR_NUMFRAMES_SET(NUM_ENQUEUES - NUM_PARTIAL);
 167        err = qman_volatile_dequeue(fq, VDQCR_FLAGS, frmcnt);
 168        if (err) {
 169                pr_err("qman_volatile_dequeue() failed\n");
 170                goto failed;
 171        }
 172
 173        err = do_enqueues(fq);
 174        if (err)
 175                goto failed;
 176        pr_info("scheduled dequeue (till-empty)\n");
 177        err = qman_schedule_fq(fq);
 178        if (err) {
 179                pr_crit("qman_schedule_fq() failed\n");
 180                goto failed;
 181        }
 182        wait_event(waitqueue, sdqcr_complete);
 183
 184        /* Retire and OOS the FQ */
 185        err = qman_retire_fq(fq, &flags);
 186        if (err < 0) {
 187                pr_crit("qman_retire_fq() failed\n");
 188                goto failed;
 189        }
 190        wait_event(waitqueue, retire_complete);
 191        if (flags & QMAN_FQ_STATE_BLOCKOOS) {
 192                err = -EIO;
 193                pr_crit("leaking frames\n");
 194                goto failed;
 195        }
 196        err = qman_oos_fq(fq);
 197        if (err) {
 198                pr_crit("qman_oos_fq() failed\n");
 199                goto failed;
 200        }
 201        qman_destroy_fq(fq);
 202        pr_info("%s(): Finished\n", __func__);
 203        return 0;
 204
 205failed:
 206        WARN_ON(1);
 207        return err;
 208}
 209
 210static enum qman_cb_dqrr_result cb_dqrr(struct qman_portal *p,
 211                                        struct qman_fq *fq,
 212                                        const struct qm_dqrr_entry *dq,
 213                                        bool sched_napi)
 214{
 215        if (WARN_ON(fd_neq(&fd_dq, &dq->fd))) {
 216                pr_err("BADNESS: dequeued frame doesn't match;\n");
 217                return qman_cb_dqrr_consume;
 218        }
 219        fd_inc(&fd_dq);
 220        if (!(dq->stat & QM_DQRR_STAT_UNSCHEDULED) && !fd_neq(&fd_dq, &fd)) {
 221                sdqcr_complete = 1;
 222                wake_up(&waitqueue);
 223        }
 224        return qman_cb_dqrr_consume;
 225}
 226
 227static void cb_ern(struct qman_portal *p, struct qman_fq *fq,
 228                   const union qm_mr_entry *msg)
 229{
 230        pr_crit("cb_ern() unimplemented");
 231        WARN_ON(1);
 232}
 233
 234static void cb_fqs(struct qman_portal *p, struct qman_fq *fq,
 235                   const union qm_mr_entry *msg)
 236{
 237        u8 verb = (msg->verb & QM_MR_VERB_TYPE_MASK);
 238
 239        if ((verb != QM_MR_VERB_FQRN) && (verb != QM_MR_VERB_FQRNI)) {
 240                pr_crit("unexpected FQS message");
 241                WARN_ON(1);
 242                return;
 243        }
 244        pr_info("Retirement message received\n");
 245        retire_complete = 1;
 246        wake_up(&waitqueue);
 247}
 248