[Intel-gfx] [RFCv2 17/19] drm/i915: Add some mock tests for dmabuf interop
Matthew Auld
matthew.william.auld at gmail.com
Tue Jan 10 19:12:35 UTC 2017
On 20 December 2016 at 13:08, Chris Wilson <chris at chris-wilson.co.uk> wrote:
> Check that we can create both dmabuf and objects from dmabuf.
>
> Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
> ---
> drivers/gpu/drm/i915/i915_gem_dmabuf.c | 5 +
> drivers/gpu/drm/i915/selftests/i915_gem_dmabuf.c | 297 +++++++++++++++++++++
> .../gpu/drm/i915/selftests/i915_mock_selftests.h | 1 +
> drivers/gpu/drm/i915/selftests/mock_dmabuf.c | 176 ++++++++++++
> drivers/gpu/drm/i915/selftests/mock_dmabuf.h | 43 +++
> 5 files changed, 522 insertions(+)
> create mode 100644 drivers/gpu/drm/i915/selftests/i915_gem_dmabuf.c
> create mode 100644 drivers/gpu/drm/i915/selftests/mock_dmabuf.c
> create mode 100644 drivers/gpu/drm/i915/selftests/mock_dmabuf.h
>
> diff --git a/drivers/gpu/drm/i915/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
> index d037adcda6f2..3e276eee0450 100644
> --- a/drivers/gpu/drm/i915/i915_gem_dmabuf.c
> +++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
> @@ -307,3 +307,8 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
>
> return ERR_PTR(ret);
> }
> +
> +#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
> +#include "selftests/mock_dmabuf.c"
> +#include "selftests/i915_gem_dmabuf.c"
> +#endif
> diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/selftests/i915_gem_dmabuf.c
> new file mode 100644
> index 000000000000..115c477978f7
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/selftests/i915_gem_dmabuf.c
> @@ -0,0 +1,297 @@
> +/*
> + * Copyright © 2016 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + */
> +
> +#include "i915_selftest.h"
> +
> +#include "mock_gem_device.h"
> +#include "mock_dmabuf.h"
> +
> +static int igt_dmabuf_export(void *arg)
> +{
> + struct drm_i915_private *i915 = arg;
> + struct drm_i915_gem_object *obj;
> + struct dma_buf *dmabuf;
> + int err;
> +
> + obj = i915_gem_object_create(i915, PAGE_SIZE);
> + if (IS_ERR(obj))
> + return PTR_ERR(obj);
> +
> + dmabuf = i915_gem_prime_export(&i915->drm, &obj->base, 0);
> + if (IS_ERR(dmabuf)) {
> + pr_err("i915_gem_prime_export failed with err=%d\n",
> + (int)PTR_ERR(dmabuf));
> + err = PTR_ERR(dmabuf);
> + goto err;
> + }
> +
> + err = 0;
> + dma_buf_put(dmabuf);
> +err:
> + i915_gem_object_put(obj);
> + return err;
> +}
> +
> +static int igt_dmabuf_import_self(void *arg)
> +{
> + struct drm_i915_private *i915 = arg;
> + struct drm_i915_gem_object *obj;
> + struct drm_gem_object *import;
> + struct dma_buf *dmabuf;
> + int err;
> +
> + obj = i915_gem_object_create(i915, PAGE_SIZE);
> + if (IS_ERR(obj))
> + return PTR_ERR(obj);
> +
> + dmabuf = i915_gem_prime_export(&i915->drm, &obj->base, 0);
> + if (IS_ERR(dmabuf)) {
> + pr_err("i915_gem_prime_export failed with err=%d\n",
> + (int)PTR_ERR(dmabuf));
> + err = PTR_ERR(dmabuf);
> + goto err;
> + }
> +
> + import = i915_gem_prime_import(&i915->drm, dmabuf);
> + if (IS_ERR(import)) {
> + pr_err("i915_gem_prime_import failed with err=%d\n",
> + (int)PTR_ERR(import));
> + err = PTR_ERR(import);
> + goto err_dmabuf;
> + }
> +
> + if (import != &obj->base) {
> + pr_err("i915_gem_prime_import created a new object!\n");
> + err = -EINVAL;
> + goto err_import;
> + }
> +
> + err = 0;
> +err_import:
> + i915_gem_object_put(to_intel_bo(import));
> +err_dmabuf:
> + dma_buf_put(dmabuf);
> +err:
> + i915_gem_object_put(obj);
> + return err;
> +}
> +
> +static int igt_dmabuf_import(void *arg)
> +{
> + struct drm_i915_private *i915 = arg;
> + struct drm_i915_gem_object *obj;
> + struct dma_buf *dmabuf;
> + void *obj_map, *dma_map;
> + u32 pattern[] = { 0, 0xaa, 0xcc, 0x55, 0xff };
> + int err, i;
> +
> + dmabuf = mock_dmabuf(1);
This looks like it's going to blow up if it returns NULL, which it
can. See the other call site too.
> + if (IS_ERR(dmabuf))
> + return PTR_ERR(dmabuf);
> +
> + obj = to_intel_bo(i915_gem_prime_import(&i915->drm, dmabuf));
> + if (IS_ERR(obj)) {
> + pr_err("i915_gem_prime_import failed with err=%d\n",
> + (int)PTR_ERR(obj));
> + err = PTR_ERR(obj);
> + goto err_dmabuf;
> + }
> +
> + if (obj->base.dev != &i915->drm) {
> + pr_err("i915_gem_prime_import created a non-i915 object!\n");
> + err = -EINVAL;
> + goto err_obj;
> + }
> +
> + if (obj->base.size != PAGE_SIZE) {
> + pr_err("i915_gem_prime_import is wrong size found %lld, expected %ld\n",
> + (long long)obj->base.size, PAGE_SIZE);
> + err = -EINVAL;
> + goto err_obj;
> + }
> +
> + dma_map = dma_buf_vmap(dmabuf);
> + if (!dma_map) {
> + pr_err("dma_buf_vmap failed\n");
> + err = -ENOMEM;
> + goto err_obj;
> + }
> +
> + if (0) {
> + /* Can not yet map dmabuf */
> + obj_map = i915_gem_object_pin_map(obj, I915_MAP_WB);
> + if (IS_ERR(obj_map)) {
> + err = PTR_ERR(obj_map);
> + pr_err("i915_gem_object_pin_map failed with err=%d\n", err);
> + goto err_dma_map;
> + }
> +
> + for (i = 0; i < ARRAY_SIZE(pattern); i++) {
> + memset(dma_map, pattern[i], PAGE_SIZE);
> + if (memchr_inv(obj_map, pattern[i], PAGE_SIZE)) {
> + err = -EINVAL;
> + pr_err("imported vmap not all set to %x!\n", pattern[i]);
> + i915_gem_object_unpin_map(obj);
> + goto err_dma_map;
> + }
> + }
> +
> + for (i = 0; i < ARRAY_SIZE(pattern); i++) {
> + memset(obj_map, pattern[i], PAGE_SIZE);
> + if (memchr_inv(dma_map, pattern[i], PAGE_SIZE)) {
> + err = -EINVAL;
> + pr_err("exported vmap not all set to %x!\n", pattern[i]);
> + i915_gem_object_unpin_map(obj);
> + goto err_dma_map;
> + }
> + }
i915_gem_object_unpin_map(obj);
> + }
> +
> + err = 0;
> +err_dma_map:
> + dma_buf_vunmap(dmabuf, dma_map);
> +err_obj:
> + i915_gem_object_put(obj);
> +err_dmabuf:
> + dma_buf_put(dmabuf);
> + return err;
> +}
> +
> +static int igt_dmabuf_import_ownership(void *arg)
> +{
> + struct drm_i915_private *i915 = arg;
> + struct drm_i915_gem_object *obj;
> + struct dma_buf *dmabuf;
> + void *ptr;
> + int err;
> +
> + dmabuf = mock_dmabuf(1);
> + if (IS_ERR(dmabuf))
> + return PTR_ERR(dmabuf);
> +
> + ptr = dma_buf_vmap(dmabuf);
> + if (!ptr) {
> + pr_err("dma_buf_vmap failed\n");
> + err = -ENOMEM;
> + goto err_dmabuf;
> + }
> +
> + memset(ptr, 0xc5, PAGE_SIZE);
> + dma_buf_vunmap(dmabuf, ptr);
> +
> + obj = to_intel_bo(i915_gem_prime_import(&i915->drm, dmabuf));
> + if (IS_ERR(obj)) {
> + pr_err("i915_gem_prime_import failed with err=%d\n",
> + (int)PTR_ERR(obj));
> + err = PTR_ERR(obj);
> + goto err_dmabuf;
> + }
> +
> + dma_buf_put(dmabuf);
> +
> + err = i915_gem_object_pin_pages(obj);
> + if (err) {
> + pr_err("i915_gem_object_pin_pages failed with err=%d\n", err);
> + goto err_obj;
> + }
> +
> + err = 0;
> + i915_gem_object_unpin_pages(obj);
> +err_obj:
> + i915_gem_object_put(obj);
> + return err;
> +
> +err_dmabuf:
> + dma_buf_put(dmabuf);
> + return err;
> +}
> +
> +static int igt_dmabuf_export_vmap(void *arg)
> +{
> + struct drm_i915_private *i915 = arg;
> + struct drm_i915_gem_object *obj;
> + struct dma_buf *dmabuf;
> + void *ptr;
> + int err;
> +
> + obj = i915_gem_object_create(i915, PAGE_SIZE);
> + if (IS_ERR(obj))
> + return PTR_ERR(obj);
> +
> + dmabuf = i915_gem_prime_export(&i915->drm, &obj->base, 0);
> + if (IS_ERR(dmabuf)) {
> + pr_err("i915_gem_prime_export failed with err=%d\n",
> + (int)PTR_ERR(dmabuf));
> + err = PTR_ERR(dmabuf);
> + goto err_obj;
> + }
> + i915_gem_object_put(obj);
> +
> + ptr = dma_buf_vmap(dmabuf);
> + if (IS_ERR(ptr)) {
> + err = PTR_ERR(ptr);
> + pr_err("dma_buf_vmap failed with err=%d\n", err);
> + goto err;
> + }
> +
> + if(memchr_inv(ptr, 0, dmabuf->size)) {
> + pr_err("Exported object no initialiased to zero!\n");
s/no initialiased/not initialised/
> + err = -EINVAL;
> + goto err;
> + }
> +
> + memset(ptr, 0xc5, dmabuf->size);
> +
> + err = 0;
> + dma_buf_vunmap(dmabuf, ptr);
> +err:
> + dma_buf_put(dmabuf);
> + return err;
> +
> +err_obj:
> + i915_gem_object_put(obj);
> + return err;
> +}
> +
> +int i915_gem_dmabuf_selftest(void)
> +{
> + static const struct i915_subtest tests[] = {
> + SUBTEST(igt_dmabuf_export),
> + SUBTEST(igt_dmabuf_import_self),
> + SUBTEST(igt_dmabuf_import),
> + SUBTEST(igt_dmabuf_import_ownership),
> + SUBTEST(igt_dmabuf_export_vmap),
> + };
> + struct drm_i915_private *i915;
> + int err;
> +
> + i915 = mock_gem_device();
> + if (!i915)
> + return -ENOMEM;
> +
> + err = i915_subtests(tests, i915);
> +
> + drm_dev_unref(&i915->drm);
> + return err;
> +}
> diff --git a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
> index 390af5cd895e..417bcfa3cdba 100644
> --- a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
> +++ b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
> @@ -14,3 +14,4 @@ selftest(uncore, intel_uncore_mock_selftests)
> selftest(breadcrumbs, intel_breadcrumbs_selftest)
> selftest(requests, i915_gem_request_selftest)
> selftest(objects, i915_gem_object_selftests)
> +selftest(dmabuf, i915_gem_dmabuf_selftest)
> diff --git a/drivers/gpu/drm/i915/selftests/mock_dmabuf.c b/drivers/gpu/drm/i915/selftests/mock_dmabuf.c
> new file mode 100644
> index 000000000000..515691779540
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/selftests/mock_dmabuf.c
> @@ -0,0 +1,176 @@
> +/*
> + * Copyright © 2016 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + */
> +
> +#include "mock_dmabuf.h"
> +
> +static struct sg_table *mock_map_dma_buf(struct dma_buf_attachment *attachment,
> + enum dma_data_direction dir)
> +{
> + struct mock_dmabuf *mock = to_mock(attachment->dmabuf);
> + struct sg_table *st;
> + struct scatterlist *sg;
> + int i, err;
> +
> + st = kmalloc(sizeof(*st), GFP_KERNEL);
> + if (!st)
> + return ERR_PTR(-ENOMEM);
> +
> + err = sg_alloc_table(st, mock->npages, GFP_KERNEL);
> + if (err)
> + goto err_free;
> +
> + sg = st->sgl;
> + for (i = 0; i < mock->npages; i++) {
> + sg_set_page(sg, mock->pages[i], PAGE_SIZE, 0);
> + sg = sg_next(sg);
> + }
> +
> + if (!dma_map_sg(attachment->dev, st->sgl, st->nents, dir)) {
> + err = -ENOMEM;
> + goto err_st;
> + }
> +
> + return st;
> +
> +err_st:
> + sg_free_table(st);
> +err_free:
> + kfree(st);
> + return ERR_PTR(err);
> +}
> +
> +static void mock_unmap_dma_buf(struct dma_buf_attachment *attachment,
> + struct sg_table *st,
> + enum dma_data_direction dir)
> +{
> + dma_unmap_sg(attachment->dev, st->sgl, st->nents, dir);
> + sg_free_table(st);
> + kfree(st);
> +}
> +
> +static void mock_dmabuf_release(struct dma_buf *dma_buf)
> +{
> + struct mock_dmabuf *mock = to_mock(dma_buf);
> + int i;
> +
> + for (i = 0; i < mock->npages; i++)
> + put_page(mock->pages[i]);
> +
> + kfree(mock);
> +}
> +
> +static void *mock_dmabuf_vmap(struct dma_buf *dma_buf)
> +{
> + struct mock_dmabuf *mock = to_mock(dma_buf);
> +
> + return vm_map_ram(mock->pages, mock->npages, 0, PAGE_KERNEL);
> +}
> +
> +static void mock_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr)
> +{
> + struct mock_dmabuf *mock = to_mock(dma_buf);
> +
> + vm_unmap_ram(vaddr, mock->npages);
> +}
> +
> +static void *mock_dmabuf_kmap_atomic(struct dma_buf *dma_buf, unsigned long page_num)
> +{
> + struct mock_dmabuf *mock = to_mock(dma_buf);
> +
> + return kmap_atomic(mock->pages[page_num]);
> +}
> +
> +static void mock_dmabuf_kunmap_atomic(struct dma_buf *dma_buf, unsigned long page_num, void *addr)
> +{
> + kunmap_atomic(addr);
> +}
> +
> +static void *mock_dmabuf_kmap(struct dma_buf *dma_buf, unsigned long page_num)
> +{
> + struct mock_dmabuf *mock = to_mock(dma_buf);
> +
> + return kmap(mock->pages[page_num]);
> +}
> +
> +static void mock_dmabuf_kunmap(struct dma_buf *dma_buf, unsigned long page_num, void *addr)
> +{
> + struct mock_dmabuf *mock = to_mock(dma_buf);
> +
> + return kunmap(mock->pages[page_num]);
> +}
> +
> +static int mock_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma)
> +{
> + return -ENODEV;
> +}
> +
> +static const struct dma_buf_ops mock_dmabuf_ops = {
> + .map_dma_buf = mock_map_dma_buf,
> + .unmap_dma_buf = mock_unmap_dma_buf,
> + .release = mock_dmabuf_release,
> + .kmap = mock_dmabuf_kmap,
> + .kmap_atomic = mock_dmabuf_kmap_atomic,
> + .kunmap = mock_dmabuf_kunmap,
> + .kunmap_atomic = mock_dmabuf_kunmap_atomic,
> + .mmap = mock_dmabuf_mmap,
> + .vmap = mock_dmabuf_vmap,
> + .vunmap = mock_dmabuf_vunmap,
> +};
> +
> +static struct dma_buf *mock_dmabuf(int npages)
> +{
> + struct mock_dmabuf *mock;
> + DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
> + struct dma_buf *dmabuf;
> + int i;
> +
> + mock = kmalloc(sizeof(*mock) + npages * sizeof(struct page *),
> + GFP_KERNEL);
> + if (!mock)
> + return ERR_PTR(-ENOMEM);
> +
> + mock->npages = npages;
> + for (i = 0; i < npages; i++) {
> + mock->pages[i] = alloc_page(GFP_KERNEL);
> + if (!mock->pages[i])
> + goto err;
> + }
> +
> + exp_info.ops = &mock_dmabuf_ops;
> + exp_info.size = npages * PAGE_SIZE;
> + exp_info.flags = O_CLOEXEC;
> + exp_info.priv = mock;
> +
> + dmabuf = dma_buf_export(&exp_info);
> + if (IS_ERR(dmabuf))
> + goto err;
> +
> + return dmabuf;
> +
> +err:
> + while (i--)
> + put_page(mock->pages[i]);
> + kfree(mock);
> + return NULL;
> +}
> diff --git a/drivers/gpu/drm/i915/selftests/mock_dmabuf.h b/drivers/gpu/drm/i915/selftests/mock_dmabuf.h
> new file mode 100644
> index 000000000000..bb5aaebcc80e
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/selftests/mock_dmabuf.h
> @@ -0,0 +1,43 @@
> +
> +/*
> + * Copyright © 2016 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + */
> +
> +#ifndef __MOCK_DMABUF_H__
> +#define __MOCK_DMABUF_H__
> +
> +#include "mock_dmabuf.h"
> +
> +struct dma_buf;
> +
> +struct mock_dmabuf {
> + int npages;
> + struct page *pages[];
> +};
> +
> +static struct mock_dmabuf *to_mock(struct dma_buf *buf)
> +{
> + return buf->priv;
We forward declare struct dma_buf, and yet we can access the priv member here ?
Otherwise:
Reviewed-by: Matthew Auld <matthew.auld at intel.com>
More information about the Intel-gfx
mailing list