cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

qman_test_api.c (6906B)


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