18c2ecf20Sopenharmony_ci/* Copyright 2008 - 2016 Freescale Semiconductor, Inc.
28c2ecf20Sopenharmony_ci *
38c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
48c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions are met:
58c2ecf20Sopenharmony_ci *     * Redistributions of source code must retain the above copyright
68c2ecf20Sopenharmony_ci *	 notice, this list of conditions and the following disclaimer.
78c2ecf20Sopenharmony_ci *     * Redistributions in binary form must reproduce the above copyright
88c2ecf20Sopenharmony_ci *	 notice, this list of conditions and the following disclaimer in the
98c2ecf20Sopenharmony_ci *	 documentation and/or other materials provided with the distribution.
108c2ecf20Sopenharmony_ci *     * Neither the name of Freescale Semiconductor nor the
118c2ecf20Sopenharmony_ci *	 names of its contributors may be used to endorse or promote products
128c2ecf20Sopenharmony_ci *	 derived from this software without specific prior written permission.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * ALTERNATIVELY, this software may be distributed under the terms of the
158c2ecf20Sopenharmony_ci * GNU General Public License ("GPL") as published by the Free Software
168c2ecf20Sopenharmony_ci * Foundation, either version 2 of that License or (at your option) any
178c2ecf20Sopenharmony_ci * later version.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
208c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
218c2ecf20Sopenharmony_ci * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
228c2ecf20Sopenharmony_ci * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
238c2ecf20Sopenharmony_ci * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
248c2ecf20Sopenharmony_ci * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
258c2ecf20Sopenharmony_ci * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
268c2ecf20Sopenharmony_ci * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
278c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
288c2ecf20Sopenharmony_ci * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
298c2ecf20Sopenharmony_ci */
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#include "qman_test.h"
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define CGR_ID		27
348c2ecf20Sopenharmony_ci#define POOL_ID		2
358c2ecf20Sopenharmony_ci#define FQ_FLAGS	QMAN_FQ_FLAG_DYNAMIC_FQID
368c2ecf20Sopenharmony_ci#define NUM_ENQUEUES	10
378c2ecf20Sopenharmony_ci#define NUM_PARTIAL	4
388c2ecf20Sopenharmony_ci#define PORTAL_SDQCR	(QM_SDQCR_SOURCE_CHANNELS | \
398c2ecf20Sopenharmony_ci			QM_SDQCR_TYPE_PRIO_QOS | \
408c2ecf20Sopenharmony_ci			QM_SDQCR_TOKEN_SET(0x98) | \
418c2ecf20Sopenharmony_ci			QM_SDQCR_CHANNELS_DEDICATED | \
428c2ecf20Sopenharmony_ci			QM_SDQCR_CHANNELS_POOL(POOL_ID))
438c2ecf20Sopenharmony_ci#define PORTAL_OPAQUE	((void *)0xf00dbeef)
448c2ecf20Sopenharmony_ci#define VDQCR_FLAGS	(QMAN_VOLATILE_FLAG_WAIT | QMAN_VOLATILE_FLAG_FINISH)
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic enum qman_cb_dqrr_result cb_dqrr(struct qman_portal *,
478c2ecf20Sopenharmony_ci					struct qman_fq *,
488c2ecf20Sopenharmony_ci					const struct qm_dqrr_entry *);
498c2ecf20Sopenharmony_cistatic void cb_ern(struct qman_portal *, struct qman_fq *,
508c2ecf20Sopenharmony_ci		   const union qm_mr_entry *);
518c2ecf20Sopenharmony_cistatic void cb_fqs(struct qman_portal *, struct qman_fq *,
528c2ecf20Sopenharmony_ci		   const union qm_mr_entry *);
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic struct qm_fd fd, fd_dq;
558c2ecf20Sopenharmony_cistatic struct qman_fq fq_base = {
568c2ecf20Sopenharmony_ci	.cb.dqrr = cb_dqrr,
578c2ecf20Sopenharmony_ci	.cb.ern = cb_ern,
588c2ecf20Sopenharmony_ci	.cb.fqs = cb_fqs
598c2ecf20Sopenharmony_ci};
608c2ecf20Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(waitqueue);
618c2ecf20Sopenharmony_cistatic int retire_complete, sdqcr_complete;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/* Helpers for initialising and "incrementing" a frame descriptor */
648c2ecf20Sopenharmony_cistatic void fd_init(struct qm_fd *fd)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	qm_fd_addr_set64(fd, 0xabdeadbeefLLU);
678c2ecf20Sopenharmony_ci	qm_fd_set_contig_big(fd, 0x0000ffff);
688c2ecf20Sopenharmony_ci	fd->cmd = cpu_to_be32(0xfeedf00d);
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic void fd_inc(struct qm_fd *fd)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	u64 t = qm_fd_addr_get64(fd);
748c2ecf20Sopenharmony_ci	int z = t >> 40;
758c2ecf20Sopenharmony_ci	unsigned int len, off;
768c2ecf20Sopenharmony_ci	enum qm_fd_format fmt;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	t <<= 1;
798c2ecf20Sopenharmony_ci	if (z)
808c2ecf20Sopenharmony_ci		t |= 1;
818c2ecf20Sopenharmony_ci	qm_fd_addr_set64(fd, t);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	fmt = qm_fd_get_format(fd);
848c2ecf20Sopenharmony_ci	off = qm_fd_get_offset(fd);
858c2ecf20Sopenharmony_ci	len = qm_fd_get_length(fd);
868c2ecf20Sopenharmony_ci	len--;
878c2ecf20Sopenharmony_ci	qm_fd_set_param(fd, fmt, off, len);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	be32_add_cpu(&fd->cmd, 1);
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci/* The only part of the 'fd' we can't memcmp() is the ppid */
938c2ecf20Sopenharmony_cistatic bool fd_neq(const struct qm_fd *a, const struct qm_fd *b)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	bool neq = qm_fd_addr_get64(a) != qm_fd_addr_get64(b);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	neq |= qm_fd_get_format(a) != qm_fd_get_format(b);
988c2ecf20Sopenharmony_ci	neq |= a->cfg != b->cfg;
998c2ecf20Sopenharmony_ci	neq |= a->cmd != b->cmd;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	return neq;
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci/* test */
1058c2ecf20Sopenharmony_cistatic int do_enqueues(struct qman_fq *fq)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	unsigned int loop;
1088c2ecf20Sopenharmony_ci	int err = 0;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	for (loop = 0; loop < NUM_ENQUEUES; loop++) {
1118c2ecf20Sopenharmony_ci		if (qman_enqueue(fq, &fd)) {
1128c2ecf20Sopenharmony_ci			pr_crit("qman_enqueue() failed\n");
1138c2ecf20Sopenharmony_ci			err = -EIO;
1148c2ecf20Sopenharmony_ci		}
1158c2ecf20Sopenharmony_ci		fd_inc(&fd);
1168c2ecf20Sopenharmony_ci	}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	return err;
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ciint qman_test_api(void)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	unsigned int flags, frmcnt;
1248c2ecf20Sopenharmony_ci	int err;
1258c2ecf20Sopenharmony_ci	struct qman_fq *fq = &fq_base;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	pr_info("%s(): Starting\n", __func__);
1288c2ecf20Sopenharmony_ci	fd_init(&fd);
1298c2ecf20Sopenharmony_ci	fd_init(&fd_dq);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	/* Initialise (parked) FQ */
1328c2ecf20Sopenharmony_ci	err = qman_create_fq(0, FQ_FLAGS, fq);
1338c2ecf20Sopenharmony_ci	if (err) {
1348c2ecf20Sopenharmony_ci		pr_crit("qman_create_fq() failed\n");
1358c2ecf20Sopenharmony_ci		goto failed;
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci	err = qman_init_fq(fq, QMAN_INITFQ_FLAG_LOCAL, NULL);
1388c2ecf20Sopenharmony_ci	if (err) {
1398c2ecf20Sopenharmony_ci		pr_crit("qman_init_fq() failed\n");
1408c2ecf20Sopenharmony_ci		goto failed;
1418c2ecf20Sopenharmony_ci	}
1428c2ecf20Sopenharmony_ci	/* Do enqueues + VDQCR, twice. (Parked FQ) */
1438c2ecf20Sopenharmony_ci	err = do_enqueues(fq);
1448c2ecf20Sopenharmony_ci	if (err)
1458c2ecf20Sopenharmony_ci		goto failed;
1468c2ecf20Sopenharmony_ci	pr_info("VDQCR (till-empty);\n");
1478c2ecf20Sopenharmony_ci	frmcnt = QM_VDQCR_NUMFRAMES_TILLEMPTY;
1488c2ecf20Sopenharmony_ci	err = qman_volatile_dequeue(fq, VDQCR_FLAGS, frmcnt);
1498c2ecf20Sopenharmony_ci	if (err) {
1508c2ecf20Sopenharmony_ci		pr_crit("qman_volatile_dequeue() failed\n");
1518c2ecf20Sopenharmony_ci		goto failed;
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci	err = do_enqueues(fq);
1548c2ecf20Sopenharmony_ci	if (err)
1558c2ecf20Sopenharmony_ci		goto failed;
1568c2ecf20Sopenharmony_ci	pr_info("VDQCR (%d of %d);\n", NUM_PARTIAL, NUM_ENQUEUES);
1578c2ecf20Sopenharmony_ci	frmcnt = QM_VDQCR_NUMFRAMES_SET(NUM_PARTIAL);
1588c2ecf20Sopenharmony_ci	err = qman_volatile_dequeue(fq, VDQCR_FLAGS, frmcnt);
1598c2ecf20Sopenharmony_ci	if (err) {
1608c2ecf20Sopenharmony_ci		pr_crit("qman_volatile_dequeue() failed\n");
1618c2ecf20Sopenharmony_ci		goto failed;
1628c2ecf20Sopenharmony_ci	}
1638c2ecf20Sopenharmony_ci	pr_info("VDQCR (%d of %d);\n", NUM_ENQUEUES - NUM_PARTIAL,
1648c2ecf20Sopenharmony_ci		NUM_ENQUEUES);
1658c2ecf20Sopenharmony_ci	frmcnt = QM_VDQCR_NUMFRAMES_SET(NUM_ENQUEUES - NUM_PARTIAL);
1668c2ecf20Sopenharmony_ci	err = qman_volatile_dequeue(fq, VDQCR_FLAGS, frmcnt);
1678c2ecf20Sopenharmony_ci	if (err) {
1688c2ecf20Sopenharmony_ci		pr_err("qman_volatile_dequeue() failed\n");
1698c2ecf20Sopenharmony_ci		goto failed;
1708c2ecf20Sopenharmony_ci	}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	err = do_enqueues(fq);
1738c2ecf20Sopenharmony_ci	if (err)
1748c2ecf20Sopenharmony_ci		goto failed;
1758c2ecf20Sopenharmony_ci	pr_info("scheduled dequeue (till-empty)\n");
1768c2ecf20Sopenharmony_ci	err = qman_schedule_fq(fq);
1778c2ecf20Sopenharmony_ci	if (err) {
1788c2ecf20Sopenharmony_ci		pr_crit("qman_schedule_fq() failed\n");
1798c2ecf20Sopenharmony_ci		goto failed;
1808c2ecf20Sopenharmony_ci	}
1818c2ecf20Sopenharmony_ci	wait_event(waitqueue, sdqcr_complete);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	/* Retire and OOS the FQ */
1848c2ecf20Sopenharmony_ci	err = qman_retire_fq(fq, &flags);
1858c2ecf20Sopenharmony_ci	if (err < 0) {
1868c2ecf20Sopenharmony_ci		pr_crit("qman_retire_fq() failed\n");
1878c2ecf20Sopenharmony_ci		goto failed;
1888c2ecf20Sopenharmony_ci	}
1898c2ecf20Sopenharmony_ci	wait_event(waitqueue, retire_complete);
1908c2ecf20Sopenharmony_ci	if (flags & QMAN_FQ_STATE_BLOCKOOS) {
1918c2ecf20Sopenharmony_ci		err = -EIO;
1928c2ecf20Sopenharmony_ci		pr_crit("leaking frames\n");
1938c2ecf20Sopenharmony_ci		goto failed;
1948c2ecf20Sopenharmony_ci	}
1958c2ecf20Sopenharmony_ci	err = qman_oos_fq(fq);
1968c2ecf20Sopenharmony_ci	if (err) {
1978c2ecf20Sopenharmony_ci		pr_crit("qman_oos_fq() failed\n");
1988c2ecf20Sopenharmony_ci		goto failed;
1998c2ecf20Sopenharmony_ci	}
2008c2ecf20Sopenharmony_ci	qman_destroy_fq(fq);
2018c2ecf20Sopenharmony_ci	pr_info("%s(): Finished\n", __func__);
2028c2ecf20Sopenharmony_ci	return 0;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cifailed:
2058c2ecf20Sopenharmony_ci	WARN_ON(1);
2068c2ecf20Sopenharmony_ci	return err;
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_cistatic enum qman_cb_dqrr_result cb_dqrr(struct qman_portal *p,
2108c2ecf20Sopenharmony_ci					struct qman_fq *fq,
2118c2ecf20Sopenharmony_ci					const struct qm_dqrr_entry *dq)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	if (WARN_ON(fd_neq(&fd_dq, &dq->fd))) {
2148c2ecf20Sopenharmony_ci		pr_err("BADNESS: dequeued frame doesn't match;\n");
2158c2ecf20Sopenharmony_ci		return qman_cb_dqrr_consume;
2168c2ecf20Sopenharmony_ci	}
2178c2ecf20Sopenharmony_ci	fd_inc(&fd_dq);
2188c2ecf20Sopenharmony_ci	if (!(dq->stat & QM_DQRR_STAT_UNSCHEDULED) && !fd_neq(&fd_dq, &fd)) {
2198c2ecf20Sopenharmony_ci		sdqcr_complete = 1;
2208c2ecf20Sopenharmony_ci		wake_up(&waitqueue);
2218c2ecf20Sopenharmony_ci	}
2228c2ecf20Sopenharmony_ci	return qman_cb_dqrr_consume;
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_cistatic void cb_ern(struct qman_portal *p, struct qman_fq *fq,
2268c2ecf20Sopenharmony_ci		   const union qm_mr_entry *msg)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	pr_crit("cb_ern() unimplemented");
2298c2ecf20Sopenharmony_ci	WARN_ON(1);
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistatic void cb_fqs(struct qman_portal *p, struct qman_fq *fq,
2338c2ecf20Sopenharmony_ci		   const union qm_mr_entry *msg)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	u8 verb = (msg->verb & QM_MR_VERB_TYPE_MASK);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	if ((verb != QM_MR_VERB_FQRN) && (verb != QM_MR_VERB_FQRNI)) {
2388c2ecf20Sopenharmony_ci		pr_crit("unexpected FQS message");
2398c2ecf20Sopenharmony_ci		WARN_ON(1);
2408c2ecf20Sopenharmony_ci		return;
2418c2ecf20Sopenharmony_ci	}
2428c2ecf20Sopenharmony_ci	pr_info("Retirement message received\n");
2438c2ecf20Sopenharmony_ci	retire_complete = 1;
2448c2ecf20Sopenharmony_ci	wake_up(&waitqueue);
2458c2ecf20Sopenharmony_ci}
246