diff options
author | Dave Airlie <airlied@redhat.com> | 2011-12-21 11:23:44 +0000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2011-12-21 17:18:23 +0000 |
commit | 881101f5115825073b910ea6ed40e93dab0480a0 (patch) | |
tree | ff9dffa3a41243491d81ee82ff5ec3434218dc7b | |
parent | a136ce65425dc5dc4f4fd9ba9a48a6e0acd0c2a7 (diff) |
udl: add prime fd->handle support.
udl can only be used as an output offload so doesn't need to support
handle->fd direction.
Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r-- | drivers/gpu/drm/udl/udl_drv.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/udl/udl_drv.h | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/udl/udl_gem.c | 114 | ||||
-rw-r--r-- | drivers/gpu/drm/udl/udl_main.c | 25 |
4 files changed, 158 insertions, 1 deletions
diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c index ca26cc819f50..8c886953764d 100644 --- a/drivers/gpu/drm/udl/udl_drv.c +++ b/drivers/gpu/drm/udl/udl_drv.c @@ -31,18 +31,24 @@ static struct vm_operations_struct udl_gem_vm_ops = { }; static struct drm_driver driver = { - .driver_features = DRIVER_MODESET | DRIVER_GEM, + .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME, .load = udl_driver_load, .unload = udl_driver_unload, + .open = udl_driver_open, + .preclose = udl_driver_preclose, + .postclose = udl_driver_postclose, /* gem hooks */ .gem_init_object = udl_gem_init_object, .gem_free_object = udl_gem_free_object, + .gem_close_object = udl_gem_close_object, .gem_vm_ops = &udl_gem_vm_ops, .dumb_create = udl_dumb_create, .dumb_map_offset = udl_gem_mmap, .dumb_destroy = udl_dumb_destroy, + + .prime_fd_to_handle = udl_gem_prime_fd_to_handle, .fops = { .owner = THIS_MODULE, .open = drm_open, diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h index a2fd7c6d8408..93ddee4aad19 100644 --- a/drivers/gpu/drm/udl/udl_drv.h +++ b/drivers/gpu/drm/udl/udl_drv.h @@ -57,6 +57,7 @@ struct udl_gem_object { struct drm_gem_object base; struct page **pages; void *vmapping; + struct sg_table *sg; }; #define to_udl_bo(x) container_of(x, struct udl_gem_object, base) @@ -67,6 +68,10 @@ struct udl_framebuffer { bool active_16; /* active on the 16-bit channel */ }; +struct udl_file_private { + struct drm_prime_file_private prime; +}; + #define to_udl_fb(x) container_of(x, struct udl_framebuffer, base) /* modeset */ @@ -84,6 +89,9 @@ void udl_urb_completion(struct urb *urb); int udl_driver_load(struct drm_device *dev, unsigned long flags); int udl_driver_unload(struct drm_device *dev); +int udl_driver_open(struct drm_device *, struct drm_file *); +void udl_driver_preclose(struct drm_device *dev, struct drm_file *); +void udl_driver_postclose(struct drm_device *dev, struct drm_file *file_priv); int udl_fbdev_init(struct drm_device *dev); void udl_fbdev_cleanup(struct drm_device *dev); @@ -108,8 +116,12 @@ int udl_dumb_destroy(struct drm_file *file_priv, struct drm_device *dev, int udl_gem_init_object(struct drm_gem_object *obj); void udl_gem_free_object(struct drm_gem_object *gem_obj); +void udl_gem_close_object(struct drm_gem_object *gem, struct drm_file *file_priv); struct udl_gem_object *udl_gem_alloc_object(struct drm_device *dev, size_t size); +int udl_gem_prime_fd_to_handle(struct drm_device *dev, + struct drm_file *file, + int prime_fd, uint32_t *handle); int udl_gem_vmap(struct udl_gem_object *obj); void udl_gem_vunmap(struct udl_gem_object *obj); diff --git a/drivers/gpu/drm/udl/udl_gem.c b/drivers/gpu/drm/udl/udl_gem.c index 63888c2f77d1..99f85b32e2c6 100644 --- a/drivers/gpu/drm/udl/udl_gem.c +++ b/drivers/gpu/drm/udl/udl_gem.c @@ -1,6 +1,7 @@ #include "drmP.h" #include "udl_drv.h" #include <linux/shmem_fs.h> +#include <linux/dma-buf.h> struct udl_gem_object *udl_gem_alloc_object(struct drm_device *dev, size_t size) @@ -197,6 +198,12 @@ static void udl_gem_put_pages(struct udl_gem_object *obj) int page_count = obj->base.size / PAGE_SIZE; int i; + if (obj->base.import_attach) { + drm_free_large(obj->pages); + obj->pages = NULL; + return; + } + for (i = 0; i < page_count; i++) { page_cache_release(obj->pages[i]); } @@ -232,6 +239,9 @@ void udl_gem_free_object(struct drm_gem_object *gem_obj) { struct udl_gem_object *obj = to_udl_bo(gem_obj); + if (gem_obj->import_attach) + drm_prime_gem_destroy(gem_obj, obj->sg); + if (obj->vmapping) udl_gem_vunmap(obj); @@ -239,6 +249,15 @@ void udl_gem_free_object(struct drm_gem_object *gem_obj) udl_gem_put_pages(obj); } +void udl_gem_close_object(struct drm_gem_object *gem, struct drm_file *file_priv) +{ + struct udl_file_private *fpriv = file_priv->driver_priv; + + if (gem->import_attach) + drm_prime_remove_fd_handle_mapping(&fpriv->prime, gem->import_attach->dmabuf); + +} + /* the dumb interface doesn't work with the GEM straight MMAP interface, it expects to do MMAP on the drm fd, like normal */ int udl_gem_mmap(struct drm_file *file, struct drm_device *dev, @@ -273,3 +292,98 @@ unlock: mutex_unlock(&dev->struct_mutex); return ret; } + +static int udl_prime_create(struct drm_device *dev, + size_t size, + struct sg_table *sg, + struct udl_gem_object **obj_p) +{ + struct udl_gem_object *obj; + int npages; + int i; + struct scatterlist *iter; + + npages = size / PAGE_SIZE; + + *obj_p = NULL; + obj = udl_gem_alloc_object(dev, npages * PAGE_SIZE); + if (!obj) + return -ENOMEM; + + obj->sg = sg; + obj->pages = drm_malloc_ab(npages, sizeof(struct page *)); + if (obj->pages == NULL) { + DRM_ERROR("obj pages is NULL %d\n", npages); + return -ENOMEM; + } + + for_each_sg(sg->sgl, iter, npages, i) + obj->pages[i] = sg_page(iter); + + *obj_p = obj; + return 0; +} + +int udl_gem_prime_fd_to_handle(struct drm_device *dev, + struct drm_file *file, + int prime_fd, uint32_t *handle) +{ + struct udl_file_private *fpriv = file->driver_priv; + struct dma_buf *dma_buf; + struct dma_buf_attachment *attach; + struct sg_table *sg; + struct udl_gem_object *uobj; + int ret; + + dma_buf = dma_buf_get(prime_fd); + if (IS_ERR(dma_buf)) + return PTR_ERR(dma_buf); + + ret = drm_prime_lookup_fd_handle_mapping(&fpriv->prime, dma_buf, handle); + if (!ret) { + dma_buf_put(dma_buf); + return 0; + } + + /* need to attach */ + attach = dma_buf_attach(dma_buf, dev->dev); + if (IS_ERR(attach)) { + ret = PTR_ERR(attach); + goto fail_put; + } + + sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); + if (IS_ERR(sg)) { + ret = PTR_ERR(sg); + goto fail_detach; + } + + ret = udl_prime_create(dev, dma_buf->size, sg, &uobj); + if (ret) { + goto fail_unmap; + } + + uobj->base.import_attach = attach; + + ret = drm_gem_handle_create(file, &uobj->base, handle); + if (ret) { + drm_gem_object_unreference_unlocked(&uobj->base); + goto fail_unmap; + } + + drm_gem_object_unreference_unlocked(&uobj->base); + + ret = drm_prime_insert_fd_handle_mapping(&fpriv->prime, dma_buf, *handle); + if (ret) { + drm_gem_object_handle_unreference_unlocked(&uobj->base); + goto fail_unmap; + } + return ret; +fail_unmap: + dma_buf_unmap_attachment(attach, sg); +fail_detach: + dma_buf_detach(dma_buf, attach); +fail_put: + dma_buf_put(dma_buf); + return ret; +} diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c index ae0ab74a08da..e9ccaa54a7fb 100644 --- a/drivers/gpu/drm/udl/udl_main.c +++ b/drivers/gpu/drm/udl/udl_main.c @@ -318,3 +318,28 @@ int udl_driver_unload(struct drm_device *dev) kfree(udl); return 0; } + +int udl_driver_open(struct drm_device *dev, struct drm_file *file) +{ + struct udl_file_private *fpriv; + + fpriv= kzalloc(sizeof(*fpriv), GFP_KERNEL); + + if (!fpriv) + return -ENOMEM; + + drm_prime_init_file_private(&fpriv->prime); + return 0; +} + +void udl_driver_preclose(struct drm_device *dev, struct drm_file *file_priv) +{ + struct udl_file_private *fpriv = file_priv->driver_priv; + + drm_prime_destroy_file_private(&fpriv->prime); +} + +void udl_driver_postclose(struct drm_device *dev, struct drm_file *file_priv) +{ + kfree(file_priv->driver_priv); +} |