From patchwork Sat Aug 24 13:38:06 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Chris Wilson X-Patchwork-Id: 11112993 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 086DC14DB for ; Sat, 24 Aug 2019 13:38:21 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id E3E2420679 for ; Sat, 24 Aug 2019 13:38:20 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E3E2420679 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=chris-wilson.co.uk Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 8DA006E0C3; Sat, 24 Aug 2019 13:38:17 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from fireflyinternet.com (mail.fireflyinternet.com [109.228.58.192]) by gabe.freedesktop.org (Postfix) with ESMTPS id 523C96E0C3; Sat, 24 Aug 2019 13:38:15 +0000 (UTC) X-Default-Received-SPF: pass (skip=forwardok (res=PASS)) x-ip-name=78.156.65.138; Received: from haswell.alporthouse.com (unverified [78.156.65.138]) by fireflyinternet.com (Firefly Internet (M1)) with ESMTP id 18250863-1500050 for multiple; Sat, 24 Aug 2019 14:38:09 +0100 From: Chris Wilson To: dri-devel@lists.freedesktop.org Subject: [PATCH] dma-buf: Extend selftests to exercise dma-fence-array Date: Sat, 24 Aug 2019 14:38:06 +0100 Message-Id: <20190824133806.8473-1-chris@chris-wilson.co.uk> X-Mailer: git-send-email 2.23.0 MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: intel-gfx@lists.freedesktop.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" A preliminary set of tests to exercise the basic dma-fence API on top of struct dma_fence_array. Signed-off-by: Chris Wilson --- drivers/dma-buf/Makefile | 3 +- drivers/dma-buf/selftests.h | 1 + drivers/dma-buf/st-dma-fence-array.c | 392 +++++++++++++++++++++++++++ 3 files changed, 395 insertions(+), 1 deletion(-) create mode 100644 drivers/dma-buf/st-dma-fence-array.c diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile index 03479da06422..822fb65b14e4 100644 --- a/drivers/dma-buf/Makefile +++ b/drivers/dma-buf/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_UDMABUF) += udmabuf.o dmabuf_selftests-y := \ selftest.o \ - st-dma-fence.o + st-dma-fence.o \ + st-dma-fence-array.o obj-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o diff --git a/drivers/dma-buf/selftests.h b/drivers/dma-buf/selftests.h index 5320386f02e5..12241b2c03f2 100644 --- a/drivers/dma-buf/selftests.h +++ b/drivers/dma-buf/selftests.h @@ -11,3 +11,4 @@ */ selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */ selftest(dma_fence, dma_fence) +selftest(dma_fence_array, dma_fence_array) diff --git a/drivers/dma-buf/st-dma-fence-array.c b/drivers/dma-buf/st-dma-fence-array.c new file mode 100644 index 000000000000..685a564a2826 --- /dev/null +++ b/drivers/dma-buf/st-dma-fence-array.c @@ -0,0 +1,392 @@ +/* SPDX-License-Identifier: MIT */ + +/* + * Copyright © 2019 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "selftest.h" + +static struct kmem_cache *slab_fences; + +static struct mock_fence { + struct dma_fence base; + struct spinlock lock; +} *to_mock_fence(struct dma_fence *f) { + return container_of(f, struct mock_fence, base); +} + +static const char *mock_name(struct dma_fence *f) +{ + return "mock"; +} + +static void mock_fence_release(struct dma_fence *f) +{ + kmem_cache_free(slab_fences, to_mock_fence(f)); +} + +static const struct dma_fence_ops mock_ops = { + .get_driver_name = mock_name, + .get_timeline_name = mock_name, + .release = mock_fence_release, +}; + +static struct dma_fence *mock_fence(void *arg) +{ + struct mock_fence *f; + + f = kmem_cache_alloc(slab_fences, GFP_KERNEL); + if (!f) + return NULL; + + spin_lock_init(&f->lock); + dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0); + + return &f->base; +} + +static struct dma_fence *stub_fence(void *arg) +{ + return dma_fence_get_stub(); +} + +static struct dma_fence *same_fence(void *arg) +{ + return dma_fence_get(arg); +} + +static int empty(void *arg) +{ + struct dma_fence_array *arr; + int err = 0; + + arr = dma_fence_array_create(0, NULL, 0, 0, false); + if (!arr) + return -ENOMEM; + + if (!dma_fence_is_signaled(&arr->base)) { + pr_err("Empty dma-fence-array is not signaled!\n"); + err = -EINVAL; + } + + dma_fence_put(&arr->base); + return err; +} + +static void free_fences(int count, struct dma_fence **fences) +{ + while (count--) + dma_fence_put(fences[count]); + kfree(fences); +} + +static struct dma_fence ** +create_fences(int count, struct dma_fence *(*ctor)(void *arg), void *arg) +{ + struct dma_fence **fences; + int i; + + fences = kmalloc_array(count, sizeof(*fences), GFP_KERNEL); + if (!fences) + return NULL; + + for (i = 0; i < count; i++) { + fences[i] = ctor(arg); + if (!fences[i]) { + free_fences(i, fences); + return NULL; + } + } + + return fences; +} + +static int stub(void *arg) +{ + struct dma_fence_array *arr; + struct dma_fence **fences; + int err = 0; + + fences = create_fences(1, stub_fence, NULL); + if (!fences) + return -ENOMEM; + + arr = dma_fence_array_create(1, fences, 0, 0, false); + if (!arr) { + free_fences(1, fences); + return -ENOMEM; + } + + dma_fence_enable_sw_signaling(&arr->base); + + if (!dma_fence_is_signaled(&arr->base)) { + pr_err("dma-fence-array(stub) is not signaled!\n"); + err = -EINVAL; + } + + dma_fence_put(&arr->base); + return err; +} + +static int single(void *arg) +{ + struct dma_fence_array *arr; + struct dma_fence **fences; + int err = 0; + + fences = create_fences(1, mock_fence, NULL); + if (!fences) + return -ENOMEM; + + arr = dma_fence_array_create(1, fences, 0, 0, false); + if (!arr) { + free_fences(1, fences); + return -ENOMEM; + } + + dma_fence_enable_sw_signaling(&arr->base); + + if (dma_fence_is_signaled(&arr->base)) { + pr_err("dma-fence-array(single) is signaled upon creation!\n"); + err = -EINVAL; + } + + dma_fence_signal(fences[0]); + + if (!dma_fence_is_signaled(&arr->base)) { + pr_err("dma-fence-array(single) is not signaled\n"); + err = -EINVAL; + } + + dma_fence_put(&arr->base); + return err; +} + +static int pair(void *arg) +{ + struct dma_fence_array *arr; + struct dma_fence **fences; + int err = 0; + + fences = create_fences(2, mock_fence, NULL); + if (!fences) + return -ENOMEM; + + arr = dma_fence_array_create(2, fences, 0, 0, false); + if (!arr) { + free_fences(2, fences); + return -ENOMEM; + } + + dma_fence_enable_sw_signaling(&arr->base); + + if (dma_fence_is_signaled(&arr->base)) { + pr_err("dma-fence-array(pair) is signaled upon creation!\n"); + err = -EINVAL; + } + + dma_fence_signal(fences[0]); + + if (dma_fence_is_signaled(&arr->base)) { + pr_err("dma-fence-array(pair) is signaled after one signal!\n"); + err = -EINVAL; + } + + dma_fence_signal(fences[0]); + + if (dma_fence_is_signaled(&arr->base)) { + pr_err("dma-fence-array(pair) is signaled after a repeated signal!\n"); + err = -EINVAL; + } + + dma_fence_signal(fences[1]); + + if (!dma_fence_is_signaled(&arr->base)) { + pr_err("dma-fence-array(pair) is not signaled\n"); + err = -EINVAL; + } + + dma_fence_put(&arr->base); + return err; +} + +static int repeat(void *arg) +{ + struct dma_fence_array *arr; + struct dma_fence **fences; + struct dma_fence *f; + int err = 0; + + f = mock_fence(NULL); + if (!f) + return -ENOMEM; + + fences = create_fences(2, same_fence, f); + dma_fence_put(f); + if (!fences) + return -ENOMEM; + + arr = dma_fence_array_create(2, fences, 0, 0, false); + if (!arr) { + free_fences(2, fences); + return -ENOMEM; + } + + dma_fence_enable_sw_signaling(&arr->base); + + if (dma_fence_is_signaled(&arr->base)) { + pr_err("dma-fence-array(pair) is signaled upon creation!\n"); + err = -EINVAL; + } + + dma_fence_signal(fences[0]); + + if (!dma_fence_is_signaled(&arr->base)) { + pr_err("dma-fence-array(pair) is not signaled\n"); + err = -EINVAL; + } + + dma_fence_put(&arr->base); + return err; +} + +static struct dma_fence *create_stub_array(void *arg) +{ + struct dma_fence_array *arr; + struct dma_fence **fences; + + fences = create_fences(1, stub_fence, NULL); + if (!fences) + return NULL; + + arr = dma_fence_array_create(1, fences, 0, 0, false); + if (!arr) { + free_fences(1, fences); + return NULL; + } + + return &arr->base; +} + +static int recurse_stub(void *arg) +{ + struct dma_fence_array *arr; + struct dma_fence **fences; + int err = 0; + + fences = create_fences(1, create_stub_array, NULL); + if (!fences) + return -ENOMEM; + + arr = dma_fence_array_create(1, fences, 0, 0, false); + if (!arr) { + free_fences(1, fences); + return -ENOMEM; + } + + dma_fence_enable_sw_signaling(&arr->base); + + if (!dma_fence_is_signaled(&arr->base)) { + pr_err("dma-fence-array(recurse-stub) is not signaled!\n"); + err = -EINVAL; + } + + dma_fence_put(&arr->base); + return err; +} + +static struct dma_fence *create_mock_array(void *arg) +{ + struct dma_fence_array *arr; + struct dma_fence **fences; + + fences = create_fences(1, same_fence, arg); + if (!fences) + return NULL; + + arr = dma_fence_array_create(1, fences, 0, 0, false); + if (!arr) { + free_fences(1, fences); + return NULL; + } + + return &arr->base; +} + +static int recurse_mock(void *arg) +{ + struct dma_fence_array *arr; + struct dma_fence **fences; + struct dma_fence *f; + int err = 0; + + f = mock_fence(NULL); + if (!f) + return -ENOMEM; + + fences = create_fences(1, create_mock_array, f); + if (!fences) { + dma_fence_put(f); + return -ENOMEM; + } + + arr = dma_fence_array_create(1, fences, 0, 0, false); + if (!arr) { + free_fences(1, fences); + dma_fence_put(f); + return -ENOMEM; + } + + dma_fence_enable_sw_signaling(&arr->base); + + if (dma_fence_is_signaled(&arr->base)) { + pr_err("dma-fence-array(recurse-mock) is signaled on construction!\n"); + err = -EINVAL; + } + + dma_fence_signal(f); + + if (!dma_fence_is_signaled(&arr->base)) { + pr_err("dma-fence-array(recurse-mock) is not signaled!\n"); + err = -EINVAL; + } + + dma_fence_put(&arr->base); + dma_fence_put(f); + return err; +} + +int dma_fence_array(void) +{ + static const struct subtest tests[] = { + SUBTEST(empty), + SUBTEST(stub), + SUBTEST(single), + SUBTEST(pair), + SUBTEST(repeat), + SUBTEST(recurse_stub), + SUBTEST(recurse_mock), + }; + int ret; + + slab_fences = KMEM_CACHE(mock_fence, + SLAB_TYPESAFE_BY_RCU | + SLAB_HWCACHE_ALIGN); + if (!slab_fences) + return -ENOMEM; + + ret = subtests(tests, NULL); + + kmem_cache_destroy(slab_fences); + + return ret; +}