Commit 6cca22ed authored by Chris Wilson's avatar Chris Wilson

drm/i915: Add some mock tests for dmabuf interop

Check that we can create both dmabuf and objects from dmabuf.

v2: Cleanups, correct include, fix unpin on dead path and prevent
explosion on dmabuf init failure
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: default avatarMatthew Auld <matthew.auld@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20170213171558.20942-25-chris@chris-wilson.co.uk
parent a8fb2bad
......@@ -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
/*
* 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;
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);
i915_gem_object_put(obj);
if (IS_ERR(dmabuf)) {
pr_err("i915_gem_prime_export failed with err=%d\n",
(int)PTR_ERR(dmabuf));
return PTR_ERR(dmabuf);
}
dma_buf_put(dmabuf);
return 0;
}
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 out;
}
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 out_dmabuf;
}
if (import != &obj->base) {
pr_err("i915_gem_prime_import created a new object!\n");
err = -EINVAL;
goto out_import;
}
err = 0;
out_import:
i915_gem_object_put(to_intel_bo(import));
out_dmabuf:
dma_buf_put(dmabuf);
out:
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);
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 out_dmabuf;
}
if (obj->base.dev != &i915->drm) {
pr_err("i915_gem_prime_import created a non-i915 object!\n");
err = -EINVAL;
goto out_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 out_obj;
}
dma_map = dma_buf_vmap(dmabuf);
if (!dma_map) {
pr_err("dma_buf_vmap failed\n");
err = -ENOMEM;
goto out_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 out_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 out_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 out_dma_map;
}
}
i915_gem_object_unpin_map(obj);
}
err = 0;
out_dma_map:
dma_buf_vunmap(dmabuf, dma_map);
out_obj:
i915_gem_object_put(obj);
out_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 out_obj;
}
err = 0;
i915_gem_object_unpin_pages(obj);
out_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 out;
}
if (memchr_inv(ptr, 0, dmabuf->size)) {
pr_err("Exported object not initialiased to zero!\n");
err = -EINVAL;
goto out;
}
memset(ptr, 0xc5, dmabuf->size);
err = 0;
dma_buf_vunmap(dmabuf, ptr);
out:
dma_buf_put(dmabuf);
return err;
err_obj:
i915_gem_object_put(obj);
return err;
}
int i915_gem_dmabuf_mock_selftests(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;
}
......@@ -14,3 +14,4 @@ selftest(uncore, intel_uncore_mock_selftests)
selftest(breadcrumbs, intel_breadcrumbs_mock_selftests)
selftest(requests, i915_gem_request_mock_selftests)
selftest(objects, i915_gem_object_mock_selftests)
selftest(dmabuf, i915_gem_dmabuf_mock_selftests)
/*
* 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 ERR_PTR(-ENOMEM);
}
/*
* 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 <linux/dma-buf.h>
struct mock_dmabuf {
int npages;
struct page *pages[];
};
static struct mock_dmabuf *to_mock(struct dma_buf *buf)
{
return buf->priv;
}
#endif /* !__MOCK_DMABUF_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment