summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2011-12-21 11:23:44 +0000
committerDave Airlie <airlied@redhat.com>2011-12-21 17:18:23 +0000
commit881101f5115825073b910ea6ed40e93dab0480a0 (patch)
treeff9dffa3a41243491d81ee82ff5ec3434218dc7b
parenta136ce65425dc5dc4f4fd9ba9a48a6e0acd0c2a7 (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.c8
-rw-r--r--drivers/gpu/drm/udl/udl_drv.h12
-rw-r--r--drivers/gpu/drm/udl/udl_gem.c114
-rw-r--r--drivers/gpu/drm/udl/udl_main.c25
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);
+}