162306a36Sopenharmony_ci/* Copyright 2008 - 2016 Freescale Semiconductor, Inc. 262306a36Sopenharmony_ci * 362306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 462306a36Sopenharmony_ci * modification, are permitted provided that the following conditions are met: 562306a36Sopenharmony_ci * * Redistributions of source code must retain the above copyright 662306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 762306a36Sopenharmony_ci * * Redistributions in binary form must reproduce the above copyright 862306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 962306a36Sopenharmony_ci * documentation and/or other materials provided with the distribution. 1062306a36Sopenharmony_ci * * Neither the name of Freescale Semiconductor nor the 1162306a36Sopenharmony_ci * names of its contributors may be used to endorse or promote products 1262306a36Sopenharmony_ci * derived from this software without specific prior written permission. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * ALTERNATIVELY, this software may be distributed under the terms of the 1562306a36Sopenharmony_ci * GNU General Public License ("GPL") as published by the Free Software 1662306a36Sopenharmony_ci * Foundation, either version 2 of that License or (at your option) any 1762306a36Sopenharmony_ci * later version. 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY 2062306a36Sopenharmony_ci * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 2162306a36Sopenharmony_ci * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 2262306a36Sopenharmony_ci * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY 2362306a36Sopenharmony_ci * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2462306a36Sopenharmony_ci * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2562306a36Sopenharmony_ci * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 2662306a36Sopenharmony_ci * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2762306a36Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 2862306a36Sopenharmony_ci * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include "qman_test.h" 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define CGR_ID 27 3462306a36Sopenharmony_ci#define POOL_ID 2 3562306a36Sopenharmony_ci#define FQ_FLAGS QMAN_FQ_FLAG_DYNAMIC_FQID 3662306a36Sopenharmony_ci#define NUM_ENQUEUES 10 3762306a36Sopenharmony_ci#define NUM_PARTIAL 4 3862306a36Sopenharmony_ci#define PORTAL_SDQCR (QM_SDQCR_SOURCE_CHANNELS | \ 3962306a36Sopenharmony_ci QM_SDQCR_TYPE_PRIO_QOS | \ 4062306a36Sopenharmony_ci QM_SDQCR_TOKEN_SET(0x98) | \ 4162306a36Sopenharmony_ci QM_SDQCR_CHANNELS_DEDICATED | \ 4262306a36Sopenharmony_ci QM_SDQCR_CHANNELS_POOL(POOL_ID)) 4362306a36Sopenharmony_ci#define PORTAL_OPAQUE ((void *)0xf00dbeef) 4462306a36Sopenharmony_ci#define VDQCR_FLAGS (QMAN_VOLATILE_FLAG_WAIT | QMAN_VOLATILE_FLAG_FINISH) 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic enum qman_cb_dqrr_result cb_dqrr(struct qman_portal *, 4762306a36Sopenharmony_ci struct qman_fq *, 4862306a36Sopenharmony_ci const struct qm_dqrr_entry *, 4962306a36Sopenharmony_ci bool sched_napi); 5062306a36Sopenharmony_cistatic void cb_ern(struct qman_portal *, struct qman_fq *, 5162306a36Sopenharmony_ci const union qm_mr_entry *); 5262306a36Sopenharmony_cistatic void cb_fqs(struct qman_portal *, struct qman_fq *, 5362306a36Sopenharmony_ci const union qm_mr_entry *); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic struct qm_fd fd, fd_dq; 5662306a36Sopenharmony_cistatic struct qman_fq fq_base = { 5762306a36Sopenharmony_ci .cb.dqrr = cb_dqrr, 5862306a36Sopenharmony_ci .cb.ern = cb_ern, 5962306a36Sopenharmony_ci .cb.fqs = cb_fqs 6062306a36Sopenharmony_ci}; 6162306a36Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(waitqueue); 6262306a36Sopenharmony_cistatic int retire_complete, sdqcr_complete; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* Helpers for initialising and "incrementing" a frame descriptor */ 6562306a36Sopenharmony_cistatic void fd_init(struct qm_fd *fd) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci qm_fd_addr_set64(fd, 0xabdeadbeefLLU); 6862306a36Sopenharmony_ci qm_fd_set_contig_big(fd, 0x0000ffff); 6962306a36Sopenharmony_ci fd->cmd = cpu_to_be32(0xfeedf00d); 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic void fd_inc(struct qm_fd *fd) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci u64 t = qm_fd_addr_get64(fd); 7562306a36Sopenharmony_ci int z = t >> 40; 7662306a36Sopenharmony_ci unsigned int len, off; 7762306a36Sopenharmony_ci enum qm_fd_format fmt; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci t <<= 1; 8062306a36Sopenharmony_ci if (z) 8162306a36Sopenharmony_ci t |= 1; 8262306a36Sopenharmony_ci qm_fd_addr_set64(fd, t); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci fmt = qm_fd_get_format(fd); 8562306a36Sopenharmony_ci off = qm_fd_get_offset(fd); 8662306a36Sopenharmony_ci len = qm_fd_get_length(fd); 8762306a36Sopenharmony_ci len--; 8862306a36Sopenharmony_ci qm_fd_set_param(fd, fmt, off, len); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci be32_add_cpu(&fd->cmd, 1); 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci/* The only part of the 'fd' we can't memcmp() is the ppid */ 9462306a36Sopenharmony_cistatic bool fd_neq(const struct qm_fd *a, const struct qm_fd *b) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci bool neq = qm_fd_addr_get64(a) != qm_fd_addr_get64(b); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci neq |= qm_fd_get_format(a) != qm_fd_get_format(b); 9962306a36Sopenharmony_ci neq |= a->cfg != b->cfg; 10062306a36Sopenharmony_ci neq |= a->cmd != b->cmd; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci return neq; 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* test */ 10662306a36Sopenharmony_cistatic int do_enqueues(struct qman_fq *fq) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci unsigned int loop; 10962306a36Sopenharmony_ci int err = 0; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci for (loop = 0; loop < NUM_ENQUEUES; loop++) { 11262306a36Sopenharmony_ci if (qman_enqueue(fq, &fd)) { 11362306a36Sopenharmony_ci pr_crit("qman_enqueue() failed\n"); 11462306a36Sopenharmony_ci err = -EIO; 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci fd_inc(&fd); 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci return err; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ciint qman_test_api(void) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci unsigned int flags, frmcnt; 12562306a36Sopenharmony_ci int err; 12662306a36Sopenharmony_ci struct qman_fq *fq = &fq_base; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci pr_info("%s(): Starting\n", __func__); 12962306a36Sopenharmony_ci fd_init(&fd); 13062306a36Sopenharmony_ci fd_init(&fd_dq); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* Initialise (parked) FQ */ 13362306a36Sopenharmony_ci err = qman_create_fq(0, FQ_FLAGS, fq); 13462306a36Sopenharmony_ci if (err) { 13562306a36Sopenharmony_ci pr_crit("qman_create_fq() failed\n"); 13662306a36Sopenharmony_ci goto failed; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci err = qman_init_fq(fq, QMAN_INITFQ_FLAG_LOCAL, NULL); 13962306a36Sopenharmony_ci if (err) { 14062306a36Sopenharmony_ci pr_crit("qman_init_fq() failed\n"); 14162306a36Sopenharmony_ci goto failed; 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci /* Do enqueues + VDQCR, twice. (Parked FQ) */ 14462306a36Sopenharmony_ci err = do_enqueues(fq); 14562306a36Sopenharmony_ci if (err) 14662306a36Sopenharmony_ci goto failed; 14762306a36Sopenharmony_ci pr_info("VDQCR (till-empty);\n"); 14862306a36Sopenharmony_ci frmcnt = QM_VDQCR_NUMFRAMES_TILLEMPTY; 14962306a36Sopenharmony_ci err = qman_volatile_dequeue(fq, VDQCR_FLAGS, frmcnt); 15062306a36Sopenharmony_ci if (err) { 15162306a36Sopenharmony_ci pr_crit("qman_volatile_dequeue() failed\n"); 15262306a36Sopenharmony_ci goto failed; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci err = do_enqueues(fq); 15562306a36Sopenharmony_ci if (err) 15662306a36Sopenharmony_ci goto failed; 15762306a36Sopenharmony_ci pr_info("VDQCR (%d of %d);\n", NUM_PARTIAL, NUM_ENQUEUES); 15862306a36Sopenharmony_ci frmcnt = QM_VDQCR_NUMFRAMES_SET(NUM_PARTIAL); 15962306a36Sopenharmony_ci err = qman_volatile_dequeue(fq, VDQCR_FLAGS, frmcnt); 16062306a36Sopenharmony_ci if (err) { 16162306a36Sopenharmony_ci pr_crit("qman_volatile_dequeue() failed\n"); 16262306a36Sopenharmony_ci goto failed; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci pr_info("VDQCR (%d of %d);\n", NUM_ENQUEUES - NUM_PARTIAL, 16562306a36Sopenharmony_ci NUM_ENQUEUES); 16662306a36Sopenharmony_ci frmcnt = QM_VDQCR_NUMFRAMES_SET(NUM_ENQUEUES - NUM_PARTIAL); 16762306a36Sopenharmony_ci err = qman_volatile_dequeue(fq, VDQCR_FLAGS, frmcnt); 16862306a36Sopenharmony_ci if (err) { 16962306a36Sopenharmony_ci pr_err("qman_volatile_dequeue() failed\n"); 17062306a36Sopenharmony_ci goto failed; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci err = do_enqueues(fq); 17462306a36Sopenharmony_ci if (err) 17562306a36Sopenharmony_ci goto failed; 17662306a36Sopenharmony_ci pr_info("scheduled dequeue (till-empty)\n"); 17762306a36Sopenharmony_ci err = qman_schedule_fq(fq); 17862306a36Sopenharmony_ci if (err) { 17962306a36Sopenharmony_ci pr_crit("qman_schedule_fq() failed\n"); 18062306a36Sopenharmony_ci goto failed; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci wait_event(waitqueue, sdqcr_complete); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci /* Retire and OOS the FQ */ 18562306a36Sopenharmony_ci err = qman_retire_fq(fq, &flags); 18662306a36Sopenharmony_ci if (err < 0) { 18762306a36Sopenharmony_ci pr_crit("qman_retire_fq() failed\n"); 18862306a36Sopenharmony_ci goto failed; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci wait_event(waitqueue, retire_complete); 19162306a36Sopenharmony_ci if (flags & QMAN_FQ_STATE_BLOCKOOS) { 19262306a36Sopenharmony_ci err = -EIO; 19362306a36Sopenharmony_ci pr_crit("leaking frames\n"); 19462306a36Sopenharmony_ci goto failed; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci err = qman_oos_fq(fq); 19762306a36Sopenharmony_ci if (err) { 19862306a36Sopenharmony_ci pr_crit("qman_oos_fq() failed\n"); 19962306a36Sopenharmony_ci goto failed; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci qman_destroy_fq(fq); 20262306a36Sopenharmony_ci pr_info("%s(): Finished\n", __func__); 20362306a36Sopenharmony_ci return 0; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cifailed: 20662306a36Sopenharmony_ci WARN_ON(1); 20762306a36Sopenharmony_ci return err; 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic enum qman_cb_dqrr_result cb_dqrr(struct qman_portal *p, 21162306a36Sopenharmony_ci struct qman_fq *fq, 21262306a36Sopenharmony_ci const struct qm_dqrr_entry *dq, 21362306a36Sopenharmony_ci bool sched_napi) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci if (WARN_ON(fd_neq(&fd_dq, &dq->fd))) { 21662306a36Sopenharmony_ci pr_err("BADNESS: dequeued frame doesn't match;\n"); 21762306a36Sopenharmony_ci return qman_cb_dqrr_consume; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci fd_inc(&fd_dq); 22062306a36Sopenharmony_ci if (!(dq->stat & QM_DQRR_STAT_UNSCHEDULED) && !fd_neq(&fd_dq, &fd)) { 22162306a36Sopenharmony_ci sdqcr_complete = 1; 22262306a36Sopenharmony_ci wake_up(&waitqueue); 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci return qman_cb_dqrr_consume; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic void cb_ern(struct qman_portal *p, struct qman_fq *fq, 22862306a36Sopenharmony_ci const union qm_mr_entry *msg) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci pr_crit("cb_ern() unimplemented"); 23162306a36Sopenharmony_ci WARN_ON(1); 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic void cb_fqs(struct qman_portal *p, struct qman_fq *fq, 23562306a36Sopenharmony_ci const union qm_mr_entry *msg) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci u8 verb = (msg->verb & QM_MR_VERB_TYPE_MASK); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if ((verb != QM_MR_VERB_FQRN) && (verb != QM_MR_VERB_FQRNI)) { 24062306a36Sopenharmony_ci pr_crit("unexpected FQS message"); 24162306a36Sopenharmony_ci WARN_ON(1); 24262306a36Sopenharmony_ci return; 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci pr_info("Retirement message received\n"); 24562306a36Sopenharmony_ci retire_complete = 1; 24662306a36Sopenharmony_ci wake_up(&waitqueue); 24762306a36Sopenharmony_ci} 248