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