summaryrefslogblamecommitdiffstats
path: root/linux/drivers/soc/fsl/qbman/bman_test_thresh.c
blob: c0f045be591824d673af8edaff7202a66f621d4f (plain) (tree)























































































































































































































                                                                                
#include <machine/rtems-bsd-kernel-space.h>

#include <rtems/bsd/local/opt_dpaa.h>

/* Copyright 2010 - 2015 Freescale Semiconductor, Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *	 notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *	 notice, this list of conditions and the following disclaimer in the
 *	 documentation and/or other materials provided with the distribution.
 *     * Neither the name of Freescale Semiconductor nor the
 *	 names of its contributors may be used to endorse or promote products
 *	 derived from this software without specific prior written permission.
 *
 * ALTERNATIVELY, this software may be distributed under the terms of the
 * GNU General Public License ("GPL") as published by the Free Software
 * Foundation, either version 2 of that License or (at your option) any
 * later version.
 *
 * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "bman_test.h"

/* Test constants */
#define TEST_NUMBUFS	129728
#define TEST_EXIT	129536
#define TEST_ENTRY	129024

struct affine_test_data {
	struct task_struct *t;
	int cpu;
#ifndef __rtems__
	int expect_affinity;
#endif /* __rtems__ */
	int drain;
	int num_enter;
	int num_exit;
	struct list_head node;
	struct completion wakethread;
	struct completion wakeparent;
};

static void cb_depletion(struct bman_portal *portal,
			struct bman_pool *pool,
			void *opaque,
			int depleted)
{
	struct affine_test_data *data = opaque;
	int c = smp_processor_id();

	pr_info("%s(): bpid=%d, depleted=%d, cpu=%d, original=%d\n", __func__,
		bman_get_params(pool)->bpid, !!depleted, c, data->cpu);
	/* We should be executing on the CPU of the thread that owns the pool if
	 * and that CPU has an affine portal (ie. it isn't slaved). */
#ifndef __rtems__
	BUG_ON((c != data->cpu) && data->expect_affinity);
	BUG_ON((c == data->cpu) && !data->expect_affinity);
#endif /* __rtems__ */
	if (depleted)
		data->num_enter++;
	else
		data->num_exit++;
}

/* Params used to set up a pool, this also dynamically allocates a BPID */
static const struct bman_pool_params params_nocb = {
	.flags = BMAN_POOL_FLAG_DYNAMIC_BPID | BMAN_POOL_FLAG_THRESH,
	.thresholds = { TEST_ENTRY, TEST_EXIT, 0, 0 }
};

/* Params used to set up each cpu's pool with callbacks enabled */
static struct bman_pool_params params_cb = {
	.bpid = 0, /* will be replaced to match pool_nocb */
	.flags = BMAN_POOL_FLAG_DEPLETION,
	.cb = cb_depletion
};

static struct bman_pool *pool_nocb;
static LIST_HEAD(threads);

static int affine_test(void *__data)
{
	struct bman_pool *pool;
	struct affine_test_data *data = __data;
	struct bman_pool_params my_params = params_cb;

	pr_info("Thread %d: starting\n", data->cpu);
	/* create the pool */
	my_params.cb_ctx = data;
	pool = bman_new_pool(&my_params);
	BUG_ON(!pool);
	complete(&data->wakeparent);
	wait_for_completion(&data->wakethread);
	init_completion(&data->wakethread);

	/* if we're the drainer, we get signalled for that */
	if (data->drain) {
		struct bm_buffer buf;
		int ret;

		pr_info("Thread %d: draining...\n", data->cpu);
		do {
			ret = bman_acquire(pool, &buf, 1, 0);
		} while (ret > 0);
		pr_info("Thread %d: draining done.\n", data->cpu);
		complete(&data->wakeparent);
		wait_for_completion(&data->wakethread);
		init_completion(&data->wakethread);
	}

	/* cleanup */
	bman_free_pool(pool);
	while (!kthread_should_stop())
		cpu_relax();
	pr_info("Thread %d: exiting\n", data->cpu);
	return 0;
}

static struct affine_test_data *start_affine_test(int cpu, int drain)
{
	struct affine_test_data *data = kmalloc(sizeof(*data), GFP_KERNEL);

	if (!data)
		return NULL;
	data->cpu = cpu;
#ifndef __rtems__
	data->expect_affinity = cpumask_test_cpu(cpu, bman_affine_cpus());
#endif /* __rtems__ */
	data->drain = drain;
	data->num_enter = 0;
	data->num_exit = 0;
	init_completion(&data->wakethread);
	init_completion(&data->wakeparent);
	list_add_tail(&data->node, &threads);
	data->t = kthread_create(affine_test, data, "threshtest%d", cpu);
#ifndef __rtems__
	BUG_ON(IS_ERR(data->t));
#else /* __rtems__ */
	BUG_ON(data->t == NULL);
#endif /* __rtems__ */
	kthread_bind(data->t, cpu);
	wake_up_process(data->t);
	return data;
}

void bman_test_thresh(void)
{
	int loop = TEST_NUMBUFS;
	int ret, num_cpus = 0;
	struct affine_test_data *data, *drainer = NULL;

	pr_info("%s(): Start\n", __func__);

	/* allocate a BPID and seed it */
	pool_nocb = bman_new_pool(&params_nocb);
	BUG_ON(!pool_nocb);
	while (loop--) {
		struct bm_buffer buf;

		bm_buffer_set64(&buf, 0x0badbeef + loop);
		ret = bman_release(pool_nocb, &buf, 1,
					BMAN_RELEASE_FLAG_WAIT);
		BUG_ON(ret);
	}
	while (!bman_rcr_is_empty())
		cpu_relax();
	pr_info("%s(): Buffers are in\n", __func__);

	/* create threads and wait for them to create pools */
	params_cb.bpid = bman_get_params(pool_nocb)->bpid;
#ifndef __rtems__
	for_each_cpu(loop, cpu_online_mask) {
#else /* __rtems__ */
	for (loop = 0; loop < rtems_get_processor_count(); ++loop) {
#endif /* __rtems__ */
		data = start_affine_test(loop, drainer ? 0 : 1);
		BUG_ON(!data);
		if (!drainer)
			drainer = data;
		num_cpus++;
		wait_for_completion(&data->wakeparent);
	}

	/* signal the drainer to start draining */
	complete(&drainer->wakethread);
	wait_for_completion(&drainer->wakeparent);
	init_completion(&drainer->wakeparent);

	/* tear down */
	list_for_each_entry_safe(data, drainer, &threads, node) {
		complete(&data->wakethread);
		ret = kthread_stop(data->t);
		BUG_ON(ret);
		list_del(&data->node);
		/* check that we get the expected callbacks (and no others) */
		BUG_ON(data->num_enter != 1);
		BUG_ON(data->num_exit != 0);
		kfree(data);
	}
	bman_free_pool(pool_nocb);

	pr_info("%s(): Done\n", __func__);
}