From: Dave Airlie <airlied@xxxxxxxxxx> This adds handle->fd and fd->handle support to i915, this is to allow for offloading of rendering in one direction and outputs in the other. Signed-off-by: Dave Airlie <airlied@xxxxxxxxxx> --- drivers/gpu/drm/i915/Makefile | 3 +- drivers/gpu/drm/i915/i915_drv.c | 8 ++- drivers/gpu/drm/i915/i915_drv.h | 11 +++ drivers/gpu/drm/i915/i915_gem.c | 11 ++- drivers/gpu/drm/i915/i915_gem_dmabuf.c | 149 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_gem_gtt.c | 18 +++- 6 files changed, 193 insertions(+), 7 deletions(-) create mode 100644 drivers/gpu/drm/i915/i915_gem_dmabuf.c diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index ce7fc77..72d1293 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -34,7 +34,8 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \ dvo_ch7017.o \ dvo_ivch.o \ dvo_tfp410.o \ - dvo_sil164.o + dvo_sil164.o \ + i915_gem_dmabuf.o i915-$(CONFIG_COMPAT) += i915_ioc32.o diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index ae8a64f..30b0132 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -901,7 +901,7 @@ static struct drm_driver driver = { */ .driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/ - DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM, + DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM | DRIVER_PRIME, .load = i915_driver_load, .unload = i915_driver_unload, .open = i915_driver_open, @@ -924,6 +924,12 @@ static struct drm_driver driver = { .gem_init_object = i915_gem_init_object, .gem_free_object = i915_gem_free_object, .gem_vm_ops = &i915_gem_vm_ops, + + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .gem_prime_export = i915_gem_prime_export, + .gem_prime_import = i915_gem_prime_import, + .dumb_create = i915_gem_dumb_create, .dumb_map_offset = i915_gem_mmap_gtt, .dumb_destroy = i915_gem_dumb_destroy, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 5fabc6c..a42b1c5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -890,6 +890,8 @@ struct drm_i915_gem_object { struct scatterlist *sg_list; int num_sg; + /* prime dma-buf support */ + struct sg_table *sg_table; /** * Used for performing relocations during execbuffer insertion. */ @@ -1205,6 +1207,8 @@ int __must_check i915_gem_object_unbind(struct drm_i915_gem_object *obj); void i915_gem_release_mmap(struct drm_i915_gem_object *obj); void i915_gem_lastclose(struct drm_device *dev); +int i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj, + gfp_t gfpmask); int __must_check i915_mutex_lock_interruptible(struct drm_device *dev); int __must_check i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj); void i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, @@ -1301,6 +1305,13 @@ i915_gem_get_unfenced_gtt_alignment(struct drm_device *dev, int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, enum i915_cache_level cache_level); +struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev, + struct dma_buf *dma_buf); + +struct dma_buf *i915_gem_prime_export(struct drm_device *dev, + struct drm_gem_object *gem_obj, int flags); + + /* i915_gem_gtt.c */ int __must_check i915_gem_init_aliasing_ppgtt(struct drm_device *dev); void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 0d1e4b7..06ca09b 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -35,6 +35,7 @@ #include <linux/slab.h> #include <linux/swap.h> #include <linux/pci.h> +#include <linux/dma-buf.h> static __must_check int i915_gem_object_flush_gpu_write_domain(struct drm_i915_gem_object *obj); static void i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj); @@ -1374,8 +1375,7 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, return i915_gem_mmap_gtt(file, dev, args->handle, &args->offset); } - -static int +int i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj, gfp_t gfpmask) { @@ -1384,6 +1384,8 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj, struct inode *inode; struct page *page; + if (obj->pages || obj->sg_table) + return 0; /* Get the list of pages out of our struct file. They'll be pinned * at this point until we release them. */ @@ -1425,6 +1427,8 @@ i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj) int page_count = obj->base.size / PAGE_SIZE; int i; + if (!obj->pages) + return; BUG_ON(obj->madv == __I915_MADV_PURGED); if (i915_gem_object_needs_bit17_swizzle(obj)) @@ -3680,6 +3684,9 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj) if (obj->phys_obj) i915_gem_detach_phys_object(dev, obj); + if (gem_obj->import_attach) + drm_prime_gem_destroy(gem_obj, obj->sg_table); + i915_gem_free_object_tail(obj); } diff --git a/drivers/gpu/drm/i915/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/i915_gem_dmabuf.c new file mode 100644 index 0000000..6ee677d --- /dev/null +++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c @@ -0,0 +1,149 @@ +/* + * Copyright 2012 Red Hat Inc + * + * 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. + * + * Authors: + * Dave Airlie <airlied@xxxxxxxxxx> + */ +#include "drmP.h" +#include "i915_drv.h" +#include <linux/dma-buf.h> + +struct sg_table *i915_gem_map_dma_buf(struct dma_buf_attachment *attachment, + enum dma_data_direction dir) +{ + struct drm_i915_gem_object *obj = attachment->dmabuf->priv; + struct drm_device *dev = obj->base.dev; + int npages = obj->base.size / PAGE_SIZE; + struct sg_table *sg = NULL; + int ret; + int nents; + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return NULL; + + if (!obj->pages) { + ret = i915_gem_object_get_pages_gtt(obj, __GFP_NORETRY | __GFP_NOWARN); + if (ret) + goto out; + } + + /* link the pages into an SG then map the sg */ + sg = drm_prime_pages_to_sg(obj->pages, npages); + nents = dma_map_sg(attachment->dev, sg->sgl, sg->nents, dir); +out: + mutex_unlock(&dev->struct_mutex); + return sg; +} + +void i915_gem_unmap_dma_buf(struct dma_buf_attachment *attachment, + struct sg_table *sg, enum dma_data_direction dir) +{ + dma_unmap_sg(attachment->dev, sg->sgl, sg->nents, dir); + sg_free_table(sg); + kfree(sg); +} + +void i915_gem_dmabuf_release(struct dma_buf *dma_buf) +{ + struct drm_i915_gem_object *obj = dma_buf->priv; + + if (obj->base.export_dma_buf == dma_buf) { + /* drop the reference on the export fd holds */ + obj->base.export_dma_buf = NULL; + drm_gem_object_unreference_unlocked(&obj->base); + } +} + +struct dma_buf_ops i915_dmabuf_ops = { + .map_dma_buf = i915_gem_map_dma_buf, + .unmap_dma_buf = i915_gem_unmap_dma_buf, + .release = i915_gem_dmabuf_release, +}; + +struct dma_buf *i915_gem_prime_export(struct drm_device *dev, + struct drm_gem_object *gem_obj, int flags) +{ + struct drm_i915_gem_object *obj = to_intel_bo(gem_obj); + + return dma_buf_export(obj, &i915_dmabuf_ops, + obj->base.size, 0600); +} + +struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev, + struct dma_buf *dma_buf) +{ + struct dma_buf_attachment *attach; + struct sg_table *sg; + struct drm_i915_gem_object *obj; + int npages; + int size; + int ret; + + /* is this one of own objects? */ + if (dma_buf->ops == &i915_dmabuf_ops) { + obj = dma_buf->priv; + /* is it from our device? */ + if (obj->base.dev == dev) { + drm_gem_object_reference(&obj->base); + return &obj->base; + } + } + + /* need to attach */ + attach = dma_buf_attach(dma_buf, dev->dev); + if (IS_ERR(attach)) + return ERR_PTR(-EINVAL); + + sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); + if (IS_ERR(sg)) { + ret = PTR_ERR(sg); + goto fail_detach; + } + + size = dma_buf->size; + npages = size / PAGE_SIZE; + + obj = kzalloc(sizeof(*obj), GFP_KERNEL); + if (obj == NULL) { + ret = -ENOMEM; + goto fail_unmap; + } + + ret = drm_gem_private_object_init(dev, &obj->base, size); + if (ret) { + ret = -ENOMEM; + kfree(obj); + goto fail_unmap; + } + + obj->sg_table = sg; + obj->base.import_attach = attach; + + return &obj->base; + +fail_unmap: + dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL); +fail_detach: + dma_buf_detach(dma_buf, attach); + return ERR_PTR(ret); +} diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index a135c61..f776cc4 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -359,7 +359,12 @@ int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj) unsigned int agp_type = cache_level_to_agp_type(dev, obj->cache_level); int ret; - if (dev_priv->mm.gtt->needs_dmar) { + if (obj->sg_table) { + intel_gtt_insert_sg_entries(obj->sg_table->sgl, + obj->sg_table->nents, + obj->gtt_space->start >> PAGE_SHIFT, + agp_type); + } else if (dev_priv->mm.gtt->needs_dmar) { ret = intel_gtt_map_memory(obj->pages, obj->base.size >> PAGE_SHIFT, &obj->sg_list, @@ -387,7 +392,12 @@ void i915_gem_gtt_rebind_object(struct drm_i915_gem_object *obj, struct drm_i915_private *dev_priv = dev->dev_private; unsigned int agp_type = cache_level_to_agp_type(dev, cache_level); - if (dev_priv->mm.gtt->needs_dmar) { + if (obj->sg_table) { + intel_gtt_insert_sg_entries(obj->sg_table->sgl, + obj->sg_table->nents, + obj->gtt_space->start >> PAGE_SHIFT, + agp_type); + } else if (dev_priv->mm.gtt->needs_dmar) { BUG_ON(!obj->sg_list); intel_gtt_insert_sg_entries(obj->sg_list, @@ -412,7 +422,9 @@ void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj) intel_gtt_clear_range(obj->gtt_space->start >> PAGE_SHIFT, obj->base.size >> PAGE_SHIFT); - if (obj->sg_list) { + if (obj->sg_table) { + intel_gtt_unmap_memory(obj->sg_table->sgl, obj->sg_table->nents); + } else if (obj->sg_list) { intel_gtt_unmap_memory(obj->sg_list, obj->num_sg); obj->sg_list = NULL; } -- 1.7.6 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel