From: Nikita Shubin Date: Fri, 14 Jun 2024 07:28:26 +0000 (+0300) Subject: [DRAFT] mailbox: Add pingpong lat measure X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=refs%2Fheads%2Fnshubin%2Fqemu-mbox;p=linux.git [DRAFT] mailbox: Add pingpong lat measure Add pingpong latency measuring test for mailbox. Only qemu-mailbox with tx_done interrupt supported. Signed-off-by: Nikita Shubin --- diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index 020f32e85aa49..5d46a74945574 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -164,6 +164,14 @@ config MAILBOX_TEST Test client to help with testing new Controller driver implementations. +config MAILBOX_PINGPONG + tristate "Mailbox Ping Pong Test Client" + depends on QEMU_MBOX + depends on HAS_IOMEM + help + Test client to help with testing new Controller driver + implementations. + config POLARFIRE_SOC_MAILBOX tristate "PolarFire SoC (MPFS) Mailbox" depends on HAS_IOMEM diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index d99cc632ff459..e065b7f1db15d 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -5,6 +5,8 @@ obj-$(CONFIG_MAILBOX) += mailbox.o obj-$(CONFIG_MAILBOX_TEST) += mailbox-test.o +obj-$(CONFIG_MAILBOX_PINGPONG) += mailbox-pingpong.o + obj-$(CONFIG_ARM_MHU) += arm_mhu.o arm_mhu_db.o obj-$(CONFIG_ARM_MHU_V2) += arm_mhuv2.o diff --git a/drivers/mailbox/mailbox-pingpong.c b/drivers/mailbox/mailbox-pingpong.c new file mode 100644 index 0000000000000..c15e88498dad9 --- /dev/null +++ b/drivers/mailbox/mailbox-pingpong.c @@ -0,0 +1,306 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Author: Nikita Shubin + * derived: drivers/dma/dmatest.c + */ +#define DEBUG +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static unsigned int iterations = 5000; +module_param(iterations, uint, 0644); +MODULE_PARM_DESC(iterations, + "Iterations before stopping test (default: 5000)"); + +static int timeout = 3000; +module_param(timeout, int, 0644); +MODULE_PARM_DESC(timeout, "Transfer Timeout in msec (default: 3000), " + "Pass -1 for infinite timeout"); + +/* TODO: pass as parameter */ +#define MAX_RX_TIMEOUT (msecs_to_jiffies(3000)) + +struct mbox_pp_params { + unsigned int iterations; + int timeout; +}; + +enum mbox_pp_error { + MBOX_PP_OK, + MBOX_PP_TX_DONE_ERR, + MBOX_PP_MBOX_SEND_ERR, +}; + +static struct mbox_pp_info { + /* Test parameters */ + struct mbox_pp_params params; + + /* Internal state */ + struct mbox_client client; + struct mutex lock; + struct mbox_chan *chan; + struct task_struct *task; + struct completion tx_done; + unsigned int iter; + ktime_t latency; + int last_error; + atomic_t running; + bool did_init; + bool pending; +} test_info = { + .lock = __MUTEX_INITIALIZER(test_info.lock), +}; + +static int mbox_pp_run_set(const char *val, const struct kernel_param *kp); +static int mbox_pp_run_get(char *val, const struct kernel_param *kp); +static const struct kernel_param_ops run_ops = { + .set = mbox_pp_run_set, + .get = mbox_pp_run_get, +}; +static bool mbox_pp_run; +module_param_cb(run, &run_ops, &mbox_pp_run, 0644); +MODULE_PARM_DESC(run, "Run the test (default: false)"); + +static DECLARE_WAIT_QUEUE_HEAD(thread_wait); +static bool wait; + +static bool is_threaded_test_run(struct mbox_pp_info *info) +{ + return false; +} + +static bool is_threaded_test_pending(struct mbox_pp_info *info) +{ + return false; +} + +static void run_pending_test(struct mbox_pp_info *info) +{ + wake_up_process(info->task); +} + +static void stop_threaded_test(struct mbox_pp_info *info) +{ + mbox_free_channel(info->chan); +} + +static void start_threaded_tests(struct mbox_pp_info *info) +{ + /* we might be called early to set run=, defer running until all + * parameters have been evaluated + */ + if (!info->did_init) + return; + + run_pending_test(info); +} + +static int mbox_pp_run_get(char *val, const struct kernel_param *kp) +{ + struct mbox_pp_info *info = &test_info; + + mutex_lock(&info->lock); + if (is_threaded_test_run(info)) { + mbox_pp_run = true; + } else { + if (!is_threaded_test_pending(info)) + stop_threaded_test(info); + mbox_pp_run = false; + } + mutex_unlock(&info->lock); + + return param_get_bool(val, kp); +} + +static int mbox_pp_func(void *data) +{ + struct mbox_pp_info *info = data; + u32 message = 1; + u64 stop_at, now = 0; + int ret; + + info->iter = 0; + info->latency = ktime_get(); + info->last_error = 0; + atomic_set(&info->running, 1); + + pr_debug("mbox_pp: started...\n"); + if (info->params.timeout) { + now = ktime_get_real_fast_ns(); + stop_at = now + info->params.timeout * NSEC_PER_MSEC; + } else + stop_at = -1; + + pr_debug("mbox_pp: now %llu stop at %llu\n", now, stop_at); + while (ktime_get_real_fast_ns() < stop_at) { + ret = mbox_send_message(info->chan, &message); + if (ret < 0) { + pr_err("mbox_pp: started failed on send_message: %d\n", ret); + ret = -EIO; + goto fail; + } + + if (!wait_for_completion_timeout(&info->tx_done, + MAX_RX_TIMEOUT)) { + pr_err("%s: send msg timeout\n", __func__); + ret = -ETIMEDOUT; + goto fail; + } + + trace_printk("TX_DONE=%llu\n", ktime_get_raw_fast_ns()); + + reinit_completion(&info->tx_done); + if (info->last_error) { + pr_info("mbox_pp: test finished with error: %d\n", info->last_error); + ret = -EIO; + goto fail; + } + + info->iter++; + if (info->iter >= info->params.iterations) { + info->last_error = MBOX_PP_OK; + break; + } + + if (!atomic_read(&info->running)) + break; + } + + if (info->last_error) + pr_info("mbox_pp: test finished with error: %d\n", info->last_error); + + info->latency = ktime_sub(ktime_get(), info->latency); + pr_info("mbox_pp: made %u iterations, lasted %llu usecs\n", + info->iter, ktime_to_us(info->latency)); + + if (info->iter) + info->latency = ns_to_ktime(ktime_divns(info->latency, info->iter)); + + pr_info("mbox_pp: latency %llu us (%llu ns)\n", + ktime_to_us(info->latency), ktime_to_ns(info->latency)); + + return 0; + +fail: + atomic_set(&info->running, 0); + return ret; +} + +static void add_threaded_test(struct mbox_pp_info *info) +{ + struct mbox_pp_params *params = &info->params; + + info->task = kthread_create(mbox_pp_func, info, "mbox_pp_thread"); + if (IS_ERR(info->task)) { + pr_warn("Failed to create thread\n"); + return; + } + + params->iterations = iterations; + params->timeout = timeout; + + info->pending = true; +} + +static int mbox_pp_run_set(const char *val, const struct kernel_param *kp) +{ + struct mbox_pp_info *info = &test_info; + int ret; + + mutex_lock(&info->lock); + ret = param_set_bool(val, kp); + if (ret) { + mutex_unlock(&info->lock); + return ret; + } else if (mbox_pp_run) { + add_threaded_test(info); + start_threaded_tests(info); + } else { + stop_threaded_test(info); + } + + mutex_unlock(&info->lock); + + return ret; +} + +static void mbox_pp_tx_done(struct mbox_client *cl, void *msg, int ret) +{ + struct mbox_pp_info *info = &test_info; + if (unlikely(ret)) { + info->last_error = MBOX_PP_TX_DONE_ERR; + return; + } + + complete(&info->tx_done); +} + +static int __init mbox_pp_init(void) +{ + struct mbox_pp_info *info = &test_info; + struct mbox_pp_params *params = &info->params; + struct mbox_client *cl = &info->client; + struct mbox_chan *chan; + + /* Request mailbox channel */ + cl->tx_done = mbox_pp_tx_done; + cl->tx_block = false; + cl->tx_tout = test_info.params.timeout; + cl->knows_txdone = false; + + /* find channel */ + chan = qemu_mbox_request_channel(&info->client); + if (IS_ERR(chan)) + pr_err("failed to acquire mailbox channel: %ld\n", PTR_ERR(chan)); + + info->chan = chan; + init_completion(&info->tx_done); + + if (mbox_pp_run) { + mutex_lock(&info->lock); + add_threaded_test(info); + run_pending_test(info); + mutex_unlock(&info->lock); + } + + if (params->iterations && wait) + wait_event(thread_wait, !is_threaded_test_run(info)); + + /* module parameters are stable, inittime tests are started, + * let userspace take over 'run' control + */ + info->did_init = true; + + return 0; +} +/* when compiled-in wait for drivers to load first */ +late_initcall(mbox_pp_init); + +static void __exit mbox_pp_exit(void) +{ + struct mbox_pp_info *info = &test_info; + + mutex_lock(&info->lock); + stop_threaded_test(info); + mutex_unlock(&info->lock); +} +module_exit(mbox_pp_exit); + +MODULE_DESCRIPTION("Pingpong Mailbox Testing Facility"); +MODULE_AUTHOR("Nikita Shubin "); +MODULE_LICENSE("GPL v2");