1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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 *);
49static void cb_ern(struct qman_portal *, struct qman_fq *,
50 const union qm_mr_entry *);
51static void cb_fqs(struct qman_portal *, struct qman_fq *,
52 const union qm_mr_entry *);
53
54static struct qm_fd fd, fd_dq;
55static struct qman_fq fq_base = {
56 .cb.dqrr = cb_dqrr,
57 .cb.ern = cb_ern,
58 .cb.fqs = cb_fqs
59};
60static DECLARE_WAIT_QUEUE_HEAD(waitqueue);
61static int retire_complete, sdqcr_complete;
62
63
64static void fd_init(struct qm_fd *fd)
65{
66 qm_fd_addr_set64(fd, 0xabdeadbeefLLU);
67 qm_fd_set_contig_big(fd, 0x0000ffff);
68 fd->cmd = 0xfeedf00d;
69}
70
71static void fd_inc(struct qm_fd *fd)
72{
73 u64 t = qm_fd_addr_get64(fd);
74 int z = t >> 40;
75 unsigned int len, off;
76 enum qm_fd_format fmt;
77
78 t <<= 1;
79 if (z)
80 t |= 1;
81 qm_fd_addr_set64(fd, t);
82
83 fmt = qm_fd_get_format(fd);
84 off = qm_fd_get_offset(fd);
85 len = qm_fd_get_length(fd);
86 len--;
87 qm_fd_set_param(fd, fmt, off, len);
88
89 fd->cmd++;
90}
91
92
93static int fd_cmp(const struct qm_fd *a, const struct qm_fd *b)
94{
95 int r = (qm_fd_addr_get64(a) == qm_fd_addr_get64(b)) ? 0 : -1;
96
97 if (!r) {
98 enum qm_fd_format fmt_a, fmt_b;
99
100 fmt_a = qm_fd_get_format(a);
101 fmt_b = qm_fd_get_format(b);
102 r = fmt_a - fmt_b;
103 }
104 if (!r)
105 r = a->cfg - b->cfg;
106 if (!r)
107 r = a->cmd - b->cmd;
108 return r;
109}
110
111
112static int do_enqueues(struct qman_fq *fq)
113{
114 unsigned int loop;
115 int err = 0;
116
117 for (loop = 0; loop < NUM_ENQUEUES; loop++) {
118 if (qman_enqueue(fq, &fd)) {
119 pr_crit("qman_enqueue() failed\n");
120 err = -EIO;
121 }
122 fd_inc(&fd);
123 }
124
125 return err;
126}
127
128int qman_test_api(void)
129{
130 unsigned int flags, frmcnt;
131 int err;
132 struct qman_fq *fq = &fq_base;
133
134 pr_info("%s(): Starting\n", __func__);
135 fd_init(&fd);
136 fd_init(&fd_dq);
137
138
139 err = qman_create_fq(0, FQ_FLAGS, fq);
140 if (err) {
141 pr_crit("qman_create_fq() failed\n");
142 goto failed;
143 }
144 err = qman_init_fq(fq, QMAN_INITFQ_FLAG_LOCAL, NULL);
145 if (err) {
146 pr_crit("qman_init_fq() failed\n");
147 goto failed;
148 }
149
150 err = do_enqueues(fq);
151 if (err)
152 goto failed;
153 pr_info("VDQCR (till-empty);\n");
154 frmcnt = QM_VDQCR_NUMFRAMES_TILLEMPTY;
155 err = qman_volatile_dequeue(fq, VDQCR_FLAGS, frmcnt);
156 if (err) {
157 pr_crit("qman_volatile_dequeue() failed\n");
158 goto failed;
159 }
160 err = do_enqueues(fq);
161 if (err)
162 goto failed;
163 pr_info("VDQCR (%d of %d);\n", NUM_PARTIAL, NUM_ENQUEUES);
164 frmcnt = QM_VDQCR_NUMFRAMES_SET(NUM_PARTIAL);
165 err = qman_volatile_dequeue(fq, VDQCR_FLAGS, frmcnt);
166 if (err) {
167 pr_crit("qman_volatile_dequeue() failed\n");
168 goto failed;
169 }
170 pr_info("VDQCR (%d of %d);\n", NUM_ENQUEUES - NUM_PARTIAL,
171 NUM_ENQUEUES);
172 frmcnt = QM_VDQCR_NUMFRAMES_SET(NUM_ENQUEUES - NUM_PARTIAL);
173 err = qman_volatile_dequeue(fq, VDQCR_FLAGS, frmcnt);
174 if (err) {
175 pr_err("qman_volatile_dequeue() failed\n");
176 goto failed;
177 }
178
179 err = do_enqueues(fq);
180 if (err)
181 goto failed;
182 pr_info("scheduled dequeue (till-empty)\n");
183 err = qman_schedule_fq(fq);
184 if (err) {
185 pr_crit("qman_schedule_fq() failed\n");
186 goto failed;
187 }
188 wait_event(waitqueue, sdqcr_complete);
189
190
191 err = qman_retire_fq(fq, &flags);
192 if (err < 0) {
193 pr_crit("qman_retire_fq() failed\n");
194 goto failed;
195 }
196 wait_event(waitqueue, retire_complete);
197 if (flags & QMAN_FQ_STATE_BLOCKOOS) {
198 err = -EIO;
199 pr_crit("leaking frames\n");
200 goto failed;
201 }
202 err = qman_oos_fq(fq);
203 if (err) {
204 pr_crit("qman_oos_fq() failed\n");
205 goto failed;
206 }
207 qman_destroy_fq(fq);
208 pr_info("%s(): Finished\n", __func__);
209 return 0;
210
211failed:
212 WARN_ON(1);
213 return err;
214}
215
216static enum qman_cb_dqrr_result cb_dqrr(struct qman_portal *p,
217 struct qman_fq *fq,
218 const struct qm_dqrr_entry *dq)
219{
220 if (WARN_ON(fd_cmp(&fd_dq, &dq->fd))) {
221 pr_err("BADNESS: dequeued frame doesn't match;\n");
222 return qman_cb_dqrr_consume;
223 }
224 fd_inc(&fd_dq);
225 if (!(dq->stat & QM_DQRR_STAT_UNSCHEDULED) && !fd_cmp(&fd_dq, &fd)) {
226 sdqcr_complete = 1;
227 wake_up(&waitqueue);
228 }
229 return qman_cb_dqrr_consume;
230}
231
232static void cb_ern(struct qman_portal *p, struct qman_fq *fq,
233 const union qm_mr_entry *msg)
234{
235 pr_crit("cb_ern() unimplemented");
236 WARN_ON(1);
237}
238
239static void cb_fqs(struct qman_portal *p, struct qman_fq *fq,
240 const union qm_mr_entry *msg)
241{
242 u8 verb = (msg->verb & QM_MR_VERB_TYPE_MASK);
243
244 if ((verb != QM_MR_VERB_FQRN) && (verb != QM_MR_VERB_FQRNI)) {
245 pr_crit("unexpected FQS message");
246 WARN_ON(1);
247 return;
248 }
249 pr_info("Retirement message received\n");
250 retire_complete = 1;
251 wake_up(&waitqueue);
252}
253