From patchwork Wed Aug 1 21:50:23 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ezequiel Garcia X-Patchwork-Id: 10553069 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id AC11A15E2 for ; Wed, 1 Aug 2018 21:50:41 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9B51C2B13B for ; Wed, 1 Aug 2018 21:50:41 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8F27F2B71F; Wed, 1 Aug 2018 21:50:41 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI,UNPARSEABLE_RELAY autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 39D8E2B13B for ; Wed, 1 Aug 2018 21:50:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732524AbeHAXib (ORCPT ); Wed, 1 Aug 2018 19:38:31 -0400 Received: from bhuna.collabora.co.uk ([46.235.227.227]:43314 "EHLO bhuna.collabora.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725956AbeHAXib (ORCPT ); Wed, 1 Aug 2018 19:38:31 -0400 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: ezequiel) with ESMTPSA id CFA1F27E1A0 From: Ezequiel Garcia To: linux-media@vger.kernel.org Cc: Hans Verkuil , kernel@collabora.com, paul.kocialkowski@bootlin.com, maxime.ripard@bootlin.com, Hans Verkuil , Shuah Khan , linux-kselftest@vger.kernel.org, Ezequiel Garcia Subject: [PATCH v3 1/4] v4l2-mem2mem: Avoid v4l2_m2m_prepare_buf from scheduling a job Date: Wed, 1 Aug 2018 18:50:23 -0300 Message-Id: <20180801215026.27809-2-ezequiel@collabora.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180801215026.27809-1-ezequiel@collabora.com> References: <20180801215026.27809-1-ezequiel@collabora.com> Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP There is no need for v4l2_m2m_prepare_buf to try to schedule a job, as it only prepares a buffer, but does not queue or changes the state of the queue. Remove the call to v4l2_m2m_try_schedule from v4l2_m2m_prepare_buf. Signed-off-by: Ezequiel Garcia --- drivers/media/v4l2-core/v4l2-mem2mem.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index 0a93c5b173c2..efae845435c9 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -481,14 +481,9 @@ int v4l2_m2m_prepare_buf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, struct v4l2_buffer *buf) { struct vb2_queue *vq; - int ret; vq = v4l2_m2m_get_vq(m2m_ctx, buf->type); - ret = vb2_prepare_buf(vq, buf); - if (!ret) - v4l2_m2m_try_schedule(m2m_ctx); - - return ret; + return vb2_prepare_buf(vq, buf); } EXPORT_SYMBOL_GPL(v4l2_m2m_prepare_buf); From patchwork Wed Aug 1 21:50:24 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ezequiel Garcia X-Patchwork-Id: 10553073 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D9F891708 for ; Wed, 1 Aug 2018 21:50:44 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C84572B13B for ; Wed, 1 Aug 2018 21:50:44 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id BBAD92B71F; Wed, 1 Aug 2018 21:50:44 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI,UNPARSEABLE_RELAY autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 54CCE2B13B for ; Wed, 1 Aug 2018 21:50:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732527AbeHAXie (ORCPT ); Wed, 1 Aug 2018 19:38:34 -0400 Received: from bhuna.collabora.co.uk ([46.235.227.227]:43326 "EHLO bhuna.collabora.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725956AbeHAXie (ORCPT ); Wed, 1 Aug 2018 19:38:34 -0400 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: ezequiel) with ESMTPSA id 1D0B4260363 From: Ezequiel Garcia To: linux-media@vger.kernel.org Cc: Hans Verkuil , kernel@collabora.com, paul.kocialkowski@bootlin.com, maxime.ripard@bootlin.com, Hans Verkuil , Shuah Khan , linux-kselftest@vger.kernel.org, Sakari Ailus , Ezequiel Garcia Subject: [PATCH v3 2/4] v4l2-mem2mem: Simplify exiting the function in __v4l2_m2m_try_schedule Date: Wed, 1 Aug 2018 18:50:24 -0300 Message-Id: <20180801215026.27809-3-ezequiel@collabora.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180801215026.27809-1-ezequiel@collabora.com> References: <20180801215026.27809-1-ezequiel@collabora.com> Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Sakari Ailus The __v4l2_m2m_try_schedule function acquires and releases multiple spinlocks. Simplify unlocking the job lock by adding labels to unlock the lock and exit the function. Signed-off-by: Sakari Ailus Signed-off-by: Ezequiel Garcia --- drivers/media/v4l2-core/v4l2-mem2mem.c | 29 ++++++++++++-------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index efae845435c9..da82d151dd20 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -279,51 +279,48 @@ static void __v4l2_m2m_try_queue(struct v4l2_m2m_dev *m2m_dev, /* If the context is aborted then don't schedule it */ if (m2m_ctx->job_flags & TRANS_ABORT) { - spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job); dprintk("Aborted context\n"); - return; + goto job_unlock; } if (m2m_ctx->job_flags & TRANS_QUEUED) { - spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job); dprintk("On job queue already\n"); - return; + goto job_unlock; } spin_lock_irqsave(&m2m_ctx->out_q_ctx.rdy_spinlock, flags_out); if (list_empty(&m2m_ctx->out_q_ctx.rdy_queue) && !m2m_ctx->out_q_ctx.buffered) { - spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, - flags_out); - spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job); dprintk("No input buffers available\n"); - return; + goto out_unlock; } spin_lock_irqsave(&m2m_ctx->cap_q_ctx.rdy_spinlock, flags_cap); if (list_empty(&m2m_ctx->cap_q_ctx.rdy_queue) && !m2m_ctx->cap_q_ctx.buffered) { - spin_unlock_irqrestore(&m2m_ctx->cap_q_ctx.rdy_spinlock, - flags_cap); - spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, - flags_out); - spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job); dprintk("No output buffers available\n"); - return; + goto cap_unlock; } spin_unlock_irqrestore(&m2m_ctx->cap_q_ctx.rdy_spinlock, flags_cap); spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, flags_out); if (m2m_dev->m2m_ops->job_ready && (!m2m_dev->m2m_ops->job_ready(m2m_ctx->priv))) { - spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job); dprintk("Driver not ready\n"); - return; + goto job_unlock; } list_add_tail(&m2m_ctx->queue, &m2m_dev->job_queue); m2m_ctx->job_flags |= TRANS_QUEUED; spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job); + return; + +cap_unlock: + spin_unlock_irqrestore(&m2m_ctx->cap_q_ctx.rdy_spinlock, flags_cap); +out_unlock: + spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, flags_out); +job_unlock: + spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job); } /** From patchwork Wed Aug 1 21:50:25 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ezequiel Garcia X-Patchwork-Id: 10553077 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A465F15E2 for ; Wed, 1 Aug 2018 21:50:48 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 955DD2B13B for ; Wed, 1 Aug 2018 21:50:48 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 89C542B75B; Wed, 1 Aug 2018 21:50:48 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI,UNPARSEABLE_RELAY autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 212BE2B13B for ; Wed, 1 Aug 2018 21:50:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732387AbeHAXii (ORCPT ); Wed, 1 Aug 2018 19:38:38 -0400 Received: from bhuna.collabora.co.uk ([46.235.227.227]:43338 "EHLO bhuna.collabora.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725956AbeHAXii (ORCPT ); Wed, 1 Aug 2018 19:38:38 -0400 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: ezequiel) with ESMTPSA id 9494727E1A6 From: Ezequiel Garcia To: linux-media@vger.kernel.org Cc: Hans Verkuil , kernel@collabora.com, paul.kocialkowski@bootlin.com, maxime.ripard@bootlin.com, Hans Verkuil , Shuah Khan , linux-kselftest@vger.kernel.org, Ezequiel Garcia Subject: [PATCH v3 3/4] v4l2-mem2mem: Avoid calling .device_run in v4l2_m2m_job_finish Date: Wed, 1 Aug 2018 18:50:25 -0300 Message-Id: <20180801215026.27809-4-ezequiel@collabora.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180801215026.27809-1-ezequiel@collabora.com> References: <20180801215026.27809-1-ezequiel@collabora.com> Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP v4l2_m2m_job_finish() is typically called in interrupt context. Some implementation of .device_run might sleep, and so it's desirable to avoid calling it directly from v4l2_m2m_job_finish(), thus avoiding .device_run from running in interrupt context. Implement a deferred context that calls v4l2_m2m_try_run, and gets scheduled by v4l2_m2m_job_finish(). Signed-off-by: Ezequiel Garcia --- drivers/media/v4l2-core/v4l2-mem2mem.c | 36 +++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index da82d151dd20..0bf4deefa899 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -69,6 +69,7 @@ static const char * const m2m_entity_name[] = { * @curr_ctx: currently running instance * @job_queue: instances queued to run * @job_spinlock: protects job_queue + * @job_work: worker to run queued jobs. * @m2m_ops: driver callbacks */ struct v4l2_m2m_dev { @@ -85,6 +86,7 @@ struct v4l2_m2m_dev { struct list_head job_queue; spinlock_t job_spinlock; + struct work_struct job_work; const struct v4l2_m2m_ops *m2m_ops; }; @@ -224,10 +226,11 @@ EXPORT_SYMBOL(v4l2_m2m_get_curr_priv); /** * v4l2_m2m_try_run() - select next job to perform and run it if possible * @m2m_dev: per-device context + * @try_lock: indicates if the queue lock should be taken * * Get next transaction (if present) from the waiting jobs list and run it. */ -static void v4l2_m2m_try_run(struct v4l2_m2m_dev *m2m_dev) +static void v4l2_m2m_try_run(struct v4l2_m2m_dev *m2m_dev, bool try_lock) { unsigned long flags; @@ -250,7 +253,20 @@ static void v4l2_m2m_try_run(struct v4l2_m2m_dev *m2m_dev) spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags); dprintk("Running job on m2m_ctx: %p\n", m2m_dev->curr_ctx); + + /* + * A m2m context lock is taken only after a m2m context + * is picked from the queue and marked as running. + * The lock is only needed if v4l2_m2m_try_run is called + * from the async worker. + */ + if (try_lock && m2m_dev->curr_ctx->q_lock) + mutex_lock(m2m_dev->curr_ctx->q_lock); + m2m_dev->m2m_ops->device_run(m2m_dev->curr_ctx->priv); + + if (try_lock && m2m_dev->curr_ctx->q_lock) + mutex_unlock(m2m_dev->curr_ctx->q_lock); } /* @@ -340,10 +356,22 @@ void v4l2_m2m_try_schedule(struct v4l2_m2m_ctx *m2m_ctx) struct v4l2_m2m_dev *m2m_dev = m2m_ctx->m2m_dev; __v4l2_m2m_try_queue(m2m_dev, m2m_ctx); - v4l2_m2m_try_run(m2m_dev); + v4l2_m2m_try_run(m2m_dev, false); } EXPORT_SYMBOL_GPL(v4l2_m2m_try_schedule); +/** + * v4l2_m2m_device_run_work() - run pending jobs for the context + * @work: Work structure used for scheduling the execution of this function. + */ +static void v4l2_m2m_device_run_work(struct work_struct *work) +{ + struct v4l2_m2m_dev *m2m_dev = + container_of(work, struct v4l2_m2m_dev, job_work); + + v4l2_m2m_try_run(m2m_dev, true); +} + /** * v4l2_m2m_cancel_job() - cancel pending jobs for the context * @m2m_ctx: m2m context with jobs to be canceled @@ -403,7 +431,8 @@ void v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev, /* This instance might have more buffers ready, but since we do not * allow more than one job on the job_queue per instance, each has * to be scheduled separately after the previous one finishes. */ - v4l2_m2m_try_schedule(m2m_ctx); + __v4l2_m2m_try_queue(m2m_dev, m2m_ctx); + schedule_work(&m2m_dev->job_work); } EXPORT_SYMBOL(v4l2_m2m_job_finish); @@ -837,6 +866,7 @@ struct v4l2_m2m_dev *v4l2_m2m_init(const struct v4l2_m2m_ops *m2m_ops) m2m_dev->m2m_ops = m2m_ops; INIT_LIST_HEAD(&m2m_dev->job_queue); spin_lock_init(&m2m_dev->job_spinlock); + INIT_WORK(&m2m_dev->job_work, v4l2_m2m_device_run_work); return m2m_dev; } From patchwork Wed Aug 1 21:50:26 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ezequiel Garcia X-Patchwork-Id: 10553083 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 255E61822 for ; Wed, 1 Aug 2018 21:50:56 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 148242B1E7 for ; Wed, 1 Aug 2018 21:50:56 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 082092B75B; Wed, 1 Aug 2018 21:50:56 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI,UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5FA332B1E7 for ; Wed, 1 Aug 2018 21:50:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387395AbeHAXin (ORCPT ); Wed, 1 Aug 2018 19:38:43 -0400 Received: from bhuna.collabora.co.uk ([46.235.227.227]:43348 "EHLO bhuna.collabora.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732533AbeHAXin (ORCPT ); Wed, 1 Aug 2018 19:38:43 -0400 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: ezequiel) with ESMTPSA id BAAFF260363 From: Ezequiel Garcia To: linux-media@vger.kernel.org Cc: Hans Verkuil , kernel@collabora.com, paul.kocialkowski@bootlin.com, maxime.ripard@bootlin.com, Hans Verkuil , Shuah Khan , linux-kselftest@vger.kernel.org, Ezequiel Garcia Subject: [PATCH v3 4/4] selftests: media_tests: Add a memory-to-memory concurrent stress test Date: Wed, 1 Aug 2018 18:50:26 -0300 Message-Id: <20180801215026.27809-5-ezequiel@collabora.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180801215026.27809-1-ezequiel@collabora.com> References: <20180801215026.27809-1-ezequiel@collabora.com> Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add a test for the memory-to-memory framework, to exercise the scheduling of concurrent jobs, using multiple contexts. This test needs to be run using the vim2m virtual driver, and so needs no hardware. While here, rework the media_tests suite in order to make it useful for automatic tools. Those tests that need human intervention are now separated from those that can run automatically, needing only virtual drivers to work. Signed-off-by: Ezequiel Garcia --- .../testing/selftests/media_tests/.gitignore | 1 + tools/testing/selftests/media_tests/Makefile | 5 +- .../selftests/media_tests/m2m_job_test.c | 287 ++++++++++++++++++ .../selftests/media_tests/m2m_job_test.sh | 32 ++ 4 files changed, 324 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/media_tests/m2m_job_test.c create mode 100755 tools/testing/selftests/media_tests/m2m_job_test.sh diff --git a/tools/testing/selftests/media_tests/.gitignore b/tools/testing/selftests/media_tests/.gitignore index 8745eba39012..71c6508348ce 100644 --- a/tools/testing/selftests/media_tests/.gitignore +++ b/tools/testing/selftests/media_tests/.gitignore @@ -1,3 +1,4 @@ media_device_test media_device_open video_device_test +m2m_job_test diff --git a/tools/testing/selftests/media_tests/Makefile b/tools/testing/selftests/media_tests/Makefile index 60826d7d37d4..d25d4c3eb7d2 100644 --- a/tools/testing/selftests/media_tests/Makefile +++ b/tools/testing/selftests/media_tests/Makefile @@ -1,6 +1,9 @@ # SPDX-License-Identifier: GPL-2.0 # CFLAGS += -I../ -I../../../../usr/include/ -TEST_GEN_PROGS := media_device_test media_device_open video_device_test +TEST_GEN_PROGS_EXTENDED := media_device_test media_device_open video_device_test m2m_job_test +TEST_PROGS := m2m_job_test.sh include ../lib.mk + +LDLIBS += -lpthread diff --git a/tools/testing/selftests/media_tests/m2m_job_test.c b/tools/testing/selftests/media_tests/m2m_job_test.c new file mode 100644 index 000000000000..5800269567e6 --- /dev/null +++ b/tools/testing/selftests/media_tests/m2m_job_test.c @@ -0,0 +1,287 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) Collabora, Ltd. + +/* + * This file adds a test for the memory-to-memory + * framework. + * + * This test opens a user specified video device and then + * queues concurrent jobs. The jobs are totally dummy, + * its purpose is only to verify that each of the queued + * jobs is run, and is run only once. + * + * The vim2m driver is needed in order to run the test. + * + * Usage: + * ./m2m-job-test -d /dev/videoX + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../kselftest.h" + +#define V4L2_CID_TRANS_TIME_MSEC (V4L2_CID_USER_BASE + 0x1000) +#define V4L2_CID_TRANS_NUM_BUFS (V4L2_CID_USER_BASE + 0x1001) + +#define MAX_TRANS_TIME_MSEC 500 +#define MAX_COUNT 50 +#define MAX_BUFFERS 5 +#define W 10 +#define H 10 + +#ifndef DEBUG +#define dprintf(fmt, arg...) \ + do { \ + } while (0) +#else +#define dprintf(fmt, arg...) printf(fmt, ## arg) +#endif + +static char video_device[256]; +static int thread_count; + +struct context { + int vfd; + unsigned int width; + unsigned int height; + int buffers; +}; + +static int req_src_buf(struct context *ctx, int buffers) +{ + struct v4l2_requestbuffers reqbuf; + struct v4l2_buffer buf; + int i, ret; + + memset(&reqbuf, 0, sizeof(reqbuf)); + memset(&buf, 0, sizeof(buf)); + + reqbuf.count = buffers; + reqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + reqbuf.memory = V4L2_MEMORY_MMAP; + ret = ioctl(ctx->vfd, VIDIOC_REQBUFS, &reqbuf); + if (ret) + return ret; + + for (i = 0; i < buffers; i++) { + buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = i; + ret = ioctl(ctx->vfd, VIDIOC_QUERYBUF, &buf); + if (ret) + return ret; + buf.bytesused = W*H*2; + ret = ioctl(ctx->vfd, VIDIOC_QBUF, &buf); + if (ret) + return ret; + } + + return 0; +} + +static int req_dst_buf(struct context *ctx, int buffers) +{ + struct v4l2_requestbuffers reqbuf; + struct v4l2_buffer buf; + int i, ret; + + memset(&reqbuf, 0, sizeof(reqbuf)); + memset(&buf, 0, sizeof(buf)); + + reqbuf.count = buffers; + reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + reqbuf.memory = V4L2_MEMORY_MMAP; + + ret = ioctl(ctx->vfd, VIDIOC_REQBUFS, &reqbuf); + if (ret) + return ret; + + for (i = 0; i < buffers; i++) { + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = i; + ret = ioctl(ctx->vfd, VIDIOC_QUERYBUF, &buf); + if (ret) + return ret; + ret = ioctl(ctx->vfd, VIDIOC_QBUF, &buf); + if (ret) + return ret; + } + return 0; +} + +static int streamon(struct context *ctx) +{ + enum v4l2_buf_type type; + int ret; + + type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + ret = ioctl(ctx->vfd, VIDIOC_STREAMON, &type); + if (ret) + return ret; + + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + ret = ioctl(ctx->vfd, VIDIOC_STREAMON, &type); + if (ret) + return ret; + + return ret; +} + +static int dqbuf(struct context *ctx) +{ + struct v4l2_buffer buf; + int i, ret, timeout; + + struct pollfd fds[] = { + { .fd = ctx->vfd, .events = POLLIN }, + }; + + for (i = 0; i < ctx->buffers; i++) { + timeout = (MAX_TRANS_TIME_MSEC + 10) * thread_count * 2; + ret = poll(fds, 1, timeout); + if (-1 == ret) { + if (errno == EINTR) + continue; + return -1; + } + + if (ret == 0) { + dprintf("%s: timeout on %p\n", __func__, ctx); + return -1; + } + + dprintf("%s: event on %p\n", __func__, ctx); + + memset(&buf, 0, sizeof(buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = i; + ret = ioctl(ctx->vfd, VIDIOC_DQBUF, &buf); + if (ret) { + dprintf("%s: VIDIOC_DQBUF failed %p\n", __func__, ctx); + return ret; + } + + memset(&buf, 0, sizeof(buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = i; + ret = ioctl(ctx->vfd, VIDIOC_DQBUF, &buf); + if (ret) { + dprintf("%s: VIDIOC_DQBUF failed %p\n", __func__, ctx); + return ret; + } + } + + return 0; +} + +static void *job(void *arg) +{ + struct context *ctx = (struct context *)arg; + + dprintf("%s: %p running\n", __func__, ctx); + + assert(streamon(ctx) == 0); + assert(dqbuf(ctx) == 0); + assert(dqbuf(ctx) != 0); + close(ctx->vfd); + + dprintf("%s: %p done\n", __func__, ctx); + return NULL; +} + +static void init(struct context *ctx) +{ + struct v4l2_ext_controls ext_ctrls; + struct v4l2_ext_control ctrls[2]; + struct v4l2_capability cap; + int ret, buffers; + + memset(ctx, 0, sizeof(*ctx)); + + ctx->vfd = open(video_device, O_RDWR | O_NONBLOCK, 0); + ctx->width = W; + ctx->height = H; + assert(ctx->vfd >= 0); + + ret = ioctl(ctx->vfd, VIDIOC_QUERYCAP, &cap); + assert(ret == 0); + assert(cap.device_caps & V4L2_CAP_VIDEO_M2M); + if (strcmp((const char *)cap.driver, "vim2m") != 0) + ksft_exit_skip("Please run the test as root - Exiting.\n"); + + ctrls[0].id = V4L2_CID_TRANS_TIME_MSEC; + ctrls[0].value = rand() % MAX_TRANS_TIME_MSEC + 10; + ctrls[1].id = V4L2_CID_TRANS_NUM_BUFS; + ctrls[1].value = 1; + + memset(&ext_ctrls, 0, sizeof(ext_ctrls)); + ext_ctrls.count = 2; + ext_ctrls.controls = ctrls; + ret = ioctl(ctx->vfd, VIDIOC_S_EXT_CTRLS, &ext_ctrls); + assert(ret == 0); + + buffers = rand() % MAX_BUFFERS + 1; + assert(req_src_buf(ctx, buffers) == 0); + assert(req_dst_buf(ctx, buffers) == 0); + ctx->buffers = buffers; +} + +int main(int argc, char * const argv[]) +{ + int i, opt; + + if (argc < 2) { + printf("Usage: %s [-d ]\n", argv[0]); + exit(-1); + } + + /* Process arguments */ + while ((opt = getopt(argc, argv, "d:")) != -1) { + switch (opt) { + case 'd': + strncpy(video_device, optarg, sizeof(video_device) - 1); + video_device[sizeof(video_device)-1] = '\0'; + break; + default: + printf("Usage: %s [-d ]\n", argv[0]); + exit(-1); + } + } + + /* Generate random number of interations */ + srand((unsigned int) time(NULL)); + thread_count = rand() % MAX_COUNT + 1; + + pthread_t in_thread[thread_count]; + struct context ctx[thread_count]; + + printf("Running %d threads\n", thread_count); + + for (i = 0; i < thread_count; i++) + init(&ctx[i]); + + for (i = 0; i < thread_count; i++) + pthread_create(&in_thread[i], NULL, job, &ctx[i]); + + for (i = 0; i < thread_count; i++) + pthread_join(in_thread[i], NULL); + + return 0; +} diff --git a/tools/testing/selftests/media_tests/m2m_job_test.sh b/tools/testing/selftests/media_tests/m2m_job_test.sh new file mode 100755 index 000000000000..59777a7ac7d8 --- /dev/null +++ b/tools/testing/selftests/media_tests/m2m_job_test.sh @@ -0,0 +1,32 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +TCID="media_device" + +# Kselftest framework requirement - SKIP code is 4. +ksft_skip=4 + +echo "-------------------" +echo "running media tests" +echo "-------------------" + +# Not needed, but does not hurt to have it +shopt -s nullglob + +v4l=/sys/class/video4linux + +if [ ! -d $v4l ]; then + echo "$TCID : video4linux support not present" + exit $ksft_skip +fi + +if [ -z `ls $v4l` ]; then + echo "$TCID : no video4linux drivers loaded, vim2m is needed" + exit $ksft_skip +fi + +for f in $v4l/*; do + dev_node=/dev/`basename $f` + if [ -c $dev_node ]; then + ./m2m_job_test -d $dev_node + fi +done