[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