Back to home page

OSCL-LXR

 
 

    


0001 /* Copyright 2008 - 2016 Freescale Semiconductor, Inc.
0002  *
0003  * Redistribution and use in source and binary forms, with or without
0004  * modification, are permitted provided that the following conditions are met:
0005  *     * Redistributions of source code must retain the above copyright
0006  *   notice, this list of conditions and the following disclaimer.
0007  *     * Redistributions in binary form must reproduce the above copyright
0008  *   notice, this list of conditions and the following disclaimer in the
0009  *   documentation and/or other materials provided with the distribution.
0010  *     * Neither the name of Freescale Semiconductor nor the
0011  *   names of its contributors may be used to endorse or promote products
0012  *   derived from this software without specific prior written permission.
0013  *
0014  * ALTERNATIVELY, this software may be distributed under the terms of the
0015  * GNU General Public License ("GPL") as published by the Free Software
0016  * Foundation, either version 2 of that License or (at your option) any
0017  * later version.
0018  *
0019  * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
0020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
0021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0022  * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
0023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
0024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
0025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0029  */
0030 
0031 #include "qman_test.h"
0032 
0033 #define CGR_ID      27
0034 #define POOL_ID     2
0035 #define FQ_FLAGS    QMAN_FQ_FLAG_DYNAMIC_FQID
0036 #define NUM_ENQUEUES    10
0037 #define NUM_PARTIAL 4
0038 #define PORTAL_SDQCR    (QM_SDQCR_SOURCE_CHANNELS | \
0039             QM_SDQCR_TYPE_PRIO_QOS | \
0040             QM_SDQCR_TOKEN_SET(0x98) | \
0041             QM_SDQCR_CHANNELS_DEDICATED | \
0042             QM_SDQCR_CHANNELS_POOL(POOL_ID))
0043 #define PORTAL_OPAQUE   ((void *)0xf00dbeef)
0044 #define VDQCR_FLAGS (QMAN_VOLATILE_FLAG_WAIT | QMAN_VOLATILE_FLAG_FINISH)
0045 
0046 static enum qman_cb_dqrr_result cb_dqrr(struct qman_portal *,
0047                     struct qman_fq *,
0048                     const struct qm_dqrr_entry *,
0049                     bool sched_napi);
0050 static void cb_ern(struct qman_portal *, struct qman_fq *,
0051            const union qm_mr_entry *);
0052 static void cb_fqs(struct qman_portal *, struct qman_fq *,
0053            const union qm_mr_entry *);
0054 
0055 static struct qm_fd fd, fd_dq;
0056 static struct qman_fq fq_base = {
0057     .cb.dqrr = cb_dqrr,
0058     .cb.ern = cb_ern,
0059     .cb.fqs = cb_fqs
0060 };
0061 static DECLARE_WAIT_QUEUE_HEAD(waitqueue);
0062 static int retire_complete, sdqcr_complete;
0063 
0064 /* Helpers for initialising and "incrementing" a frame descriptor */
0065 static void fd_init(struct qm_fd *fd)
0066 {
0067     qm_fd_addr_set64(fd, 0xabdeadbeefLLU);
0068     qm_fd_set_contig_big(fd, 0x0000ffff);
0069     fd->cmd = cpu_to_be32(0xfeedf00d);
0070 }
0071 
0072 static void fd_inc(struct qm_fd *fd)
0073 {
0074     u64 t = qm_fd_addr_get64(fd);
0075     int z = t >> 40;
0076     unsigned int len, off;
0077     enum qm_fd_format fmt;
0078 
0079     t <<= 1;
0080     if (z)
0081         t |= 1;
0082     qm_fd_addr_set64(fd, t);
0083 
0084     fmt = qm_fd_get_format(fd);
0085     off = qm_fd_get_offset(fd);
0086     len = qm_fd_get_length(fd);
0087     len--;
0088     qm_fd_set_param(fd, fmt, off, len);
0089 
0090     be32_add_cpu(&fd->cmd, 1);
0091 }
0092 
0093 /* The only part of the 'fd' we can't memcmp() is the ppid */
0094 static bool fd_neq(const struct qm_fd *a, const struct qm_fd *b)
0095 {
0096     bool neq = qm_fd_addr_get64(a) != qm_fd_addr_get64(b);
0097 
0098     neq |= qm_fd_get_format(a) != qm_fd_get_format(b);
0099     neq |= a->cfg != b->cfg;
0100     neq |= a->cmd != b->cmd;
0101 
0102     return neq;
0103 }
0104 
0105 /* test */
0106 static int do_enqueues(struct qman_fq *fq)
0107 {
0108     unsigned int loop;
0109     int err = 0;
0110 
0111     for (loop = 0; loop < NUM_ENQUEUES; loop++) {
0112         if (qman_enqueue(fq, &fd)) {
0113             pr_crit("qman_enqueue() failed\n");
0114             err = -EIO;
0115         }
0116         fd_inc(&fd);
0117     }
0118 
0119     return err;
0120 }
0121 
0122 int qman_test_api(void)
0123 {
0124     unsigned int flags, frmcnt;
0125     int err;
0126     struct qman_fq *fq = &fq_base;
0127 
0128     pr_info("%s(): Starting\n", __func__);
0129     fd_init(&fd);
0130     fd_init(&fd_dq);
0131 
0132     /* Initialise (parked) FQ */
0133     err = qman_create_fq(0, FQ_FLAGS, fq);
0134     if (err) {
0135         pr_crit("qman_create_fq() failed\n");
0136         goto failed;
0137     }
0138     err = qman_init_fq(fq, QMAN_INITFQ_FLAG_LOCAL, NULL);
0139     if (err) {
0140         pr_crit("qman_init_fq() failed\n");
0141         goto failed;
0142     }
0143     /* Do enqueues + VDQCR, twice. (Parked FQ) */
0144     err = do_enqueues(fq);
0145     if (err)
0146         goto failed;
0147     pr_info("VDQCR (till-empty);\n");
0148     frmcnt = QM_VDQCR_NUMFRAMES_TILLEMPTY;
0149     err = qman_volatile_dequeue(fq, VDQCR_FLAGS, frmcnt);
0150     if (err) {
0151         pr_crit("qman_volatile_dequeue() failed\n");
0152         goto failed;
0153     }
0154     err = do_enqueues(fq);
0155     if (err)
0156         goto failed;
0157     pr_info("VDQCR (%d of %d);\n", NUM_PARTIAL, NUM_ENQUEUES);
0158     frmcnt = QM_VDQCR_NUMFRAMES_SET(NUM_PARTIAL);
0159     err = qman_volatile_dequeue(fq, VDQCR_FLAGS, frmcnt);
0160     if (err) {
0161         pr_crit("qman_volatile_dequeue() failed\n");
0162         goto failed;
0163     }
0164     pr_info("VDQCR (%d of %d);\n", NUM_ENQUEUES - NUM_PARTIAL,
0165         NUM_ENQUEUES);
0166     frmcnt = QM_VDQCR_NUMFRAMES_SET(NUM_ENQUEUES - NUM_PARTIAL);
0167     err = qman_volatile_dequeue(fq, VDQCR_FLAGS, frmcnt);
0168     if (err) {
0169         pr_err("qman_volatile_dequeue() failed\n");
0170         goto failed;
0171     }
0172 
0173     err = do_enqueues(fq);
0174     if (err)
0175         goto failed;
0176     pr_info("scheduled dequeue (till-empty)\n");
0177     err = qman_schedule_fq(fq);
0178     if (err) {
0179         pr_crit("qman_schedule_fq() failed\n");
0180         goto failed;
0181     }
0182     wait_event(waitqueue, sdqcr_complete);
0183 
0184     /* Retire and OOS the FQ */
0185     err = qman_retire_fq(fq, &flags);
0186     if (err < 0) {
0187         pr_crit("qman_retire_fq() failed\n");
0188         goto failed;
0189     }
0190     wait_event(waitqueue, retire_complete);
0191     if (flags & QMAN_FQ_STATE_BLOCKOOS) {
0192         err = -EIO;
0193         pr_crit("leaking frames\n");
0194         goto failed;
0195     }
0196     err = qman_oos_fq(fq);
0197     if (err) {
0198         pr_crit("qman_oos_fq() failed\n");
0199         goto failed;
0200     }
0201     qman_destroy_fq(fq);
0202     pr_info("%s(): Finished\n", __func__);
0203     return 0;
0204 
0205 failed:
0206     WARN_ON(1);
0207     return err;
0208 }
0209 
0210 static enum qman_cb_dqrr_result cb_dqrr(struct qman_portal *p,
0211                     struct qman_fq *fq,
0212                     const struct qm_dqrr_entry *dq,
0213                     bool sched_napi)
0214 {
0215     if (WARN_ON(fd_neq(&fd_dq, &dq->fd))) {
0216         pr_err("BADNESS: dequeued frame doesn't match;\n");
0217         return qman_cb_dqrr_consume;
0218     }
0219     fd_inc(&fd_dq);
0220     if (!(dq->stat & QM_DQRR_STAT_UNSCHEDULED) && !fd_neq(&fd_dq, &fd)) {
0221         sdqcr_complete = 1;
0222         wake_up(&waitqueue);
0223     }
0224     return qman_cb_dqrr_consume;
0225 }
0226 
0227 static void cb_ern(struct qman_portal *p, struct qman_fq *fq,
0228            const union qm_mr_entry *msg)
0229 {
0230     pr_crit("cb_ern() unimplemented");
0231     WARN_ON(1);
0232 }
0233 
0234 static void cb_fqs(struct qman_portal *p, struct qman_fq *fq,
0235            const union qm_mr_entry *msg)
0236 {
0237     u8 verb = (msg->verb & QM_MR_VERB_TYPE_MASK);
0238 
0239     if ((verb != QM_MR_VERB_FQRN) && (verb != QM_MR_VERB_FQRNI)) {
0240         pr_crit("unexpected FQS message");
0241         WARN_ON(1);
0242         return;
0243     }
0244     pr_info("Retirement message received\n");
0245     retire_complete = 1;
0246     wake_up(&waitqueue);
0247 }