0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
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
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
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
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
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
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
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 }