Re: [Intel-gfx] [RFC v4 19/25] drm/client: Finish the in-kernel client API

2018-04-17 Thread Daniel Vetter
On Mon, Apr 16, 2018 at 05:58:23PM +0200, Noralf Trønnes wrote:
> 
> Den 16.04.2018 10.27, skrev Daniel Vetter:
> > On Sat, Apr 14, 2018 at 01:53:12PM +0200, Noralf Trønnes wrote:
> > > The modesetting code is already present, this adds the rest of the API.
> > Mentioning the TODO in the commit message would be good. Helps readers
> > like me who have an attention span measured in seconds :-)
> > 
> > Just commenting on the create_buffer leak here
> > 
> > > +static struct drm_client_buffer *
> > > +drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 
> > > height, u32 format)
> > > +{
> > > + struct drm_mode_create_dumb dumb_args = { };
> > > + struct drm_prime_handle prime_args = { };
> > > + struct drm_client_buffer *buffer;
> > > + struct dma_buf *dma_buf;
> > > + void *vaddr;
> > > + int ret;
> > > +
> > > + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
> > > + if (!buffer)
> > > + return ERR_PTR(-ENOMEM);
> > > +
> > > + buffer->client = client;
> > > + buffer->width = width;
> > > + buffer->height = height;
> > > + buffer->format = format;
> > > +
> > > + dumb_args.width = buffer->width;
> > > + dumb_args.height = buffer->height;
> > > + dumb_args.bpp = drm_format_plane_cpp(format, 0) * 8;
> > > + ret = drm_mode_create_dumb(client->dev, _args, client->file);
> > > + if (ret)
> > > + goto err_free;
> > > +
> > > + buffer->handle = dumb_args.handle;
> > > + buffer->pitch = dumb_args.pitch;
> > > + buffer->size = dumb_args.size;
> > > +
> > > + prime_args.handle = dumb_args.handle;
> > > + ret = drm_prime_handle_to_fd(client->dev, _args, client->file);
> > > + if (ret)
> > > + goto err_delete;
> > > +
> > > + dma_buf = dma_buf_get(prime_args.fd);
> > > + if (IS_ERR(dma_buf)) {
> > > + ret = PTR_ERR(dma_buf);
> > > + goto err_delete;
> > > + }
> > > +
> > > + /*
> > > +  * If called from a worker the dmabuf fd isn't closed and the ref
> > > +  * doesn't drop to zero on free.
> > > +  * If I use __close_fd() it's all fine, but that function is not 
> > > exported.
> > > +  *
> > > +  * How do I get rid of this fd when in a worker/kernel thread?
> > > +  * The fd isn't used beyond this function.
> > > +  */
> > > +//   WARN_ON(__close_fd(current->files, prime_args.fd));
> > Hm, this isn't 100% what I had in mind as the sequence for generic buffer
> > creation. Pseudo-code:
> > 
> > ret = drm_mode_create_dumb(client->dev, _args, client->file);
> > if (ret)
> > goto err_free;
> > 
> > gem_bo = drm_gem_object_lookup(client->file, dumb_args.handle);
> > 
> > gives you _really_ directly the underlying gem_bo. Of course this doesn't
> > work for non-gem based driver, but reality is that (almost) all of them
> > are. And we will not accept any new drivers which aren't gem based. So
> > ignoring vmwgfx for this drm_client work is imo perfectly fine. We should
> > ofc keep the option in the fb helpers to use non-gem buffers (so that
> > vmwgfx could switch over from their own in-driver fbdev helpers). All we
> > need for that is to keep the fb_probe callback.
> > 
> > Was there any other reason than vmwgfx for using prime buffers instead of
> > just directly using gem?
> 
> The reason for using a prime buffer is that it gives me easy access to a
> dma_buf which I use to get the virtual address (dma_buf_vmap) and for
> mmap (dma_buf_mmap).

Ah yes, I missed that.

Wrt mmap, not sure we should use the dma-buf mmap or the dumb mmap. I
guess in the end it wont matter much really.

> 
> Would this stripped down version of drm_gem_prime_handle_to_fd() work?
> 
> struct dma_buf *drm_gem_to_dmabuf(struct drm_gem_object *obj)
> {
>     struct dma_buf *dmabuf;
> 
>     mutex_lock(>dev->object_name_lock);
>     /* re-export the original imported object */
>     if (obj->import_attach) {
>         dmabuf = obj->import_attach->dmabuf;
>         get_dma_buf(dmabuf);
>         goto out;
>     }
> 
>     if (obj->dma_buf) {
>         dmabuf = obj->dma_buf;
>         get_dma_buf(dmabuf);
>         goto out;
>     }
> 
>     dmabuf = export_and_register_object(obj->dev, obj, 0);
> out:
>     mutex_unlock(>dev->object_name_lock);
> 
>     return dmabuf;
> }
> 
> Now I could do this:
> 
>     ret = drm_mode_create_dumb(dev, _args, file);
> 
>     obj = drm_gem_object_lookup(file, dumb_args.handle);
> 
>     dmabuf = drm_gem_to_dmabuf(obj);
> 
>     vaddr = dma_buf_vmap(dmabuf);

Nah, if we need the dma-buf anyway, I'd try to go directly from the handle
to the dma-buf. So roughly:

ret = drm_mode_create_dumb(dev, _args, file);

dma_buf = drm_gem_prime_handle_to_dmabuf(file, dumb_args.handle);

See my reply to the ioctl wrapper patch for details.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [Intel-gfx] [RFC v4 19/25] drm/client: Finish the in-kernel client API

2018-04-16 Thread Noralf Trønnes


Den 16.04.2018 10.27, skrev Daniel Vetter:

On Sat, Apr 14, 2018 at 01:53:12PM +0200, Noralf Trønnes wrote:

The modesetting code is already present, this adds the rest of the API.

Mentioning the TODO in the commit message would be good. Helps readers
like me who have an attention span measured in seconds :-)

Just commenting on the create_buffer leak here


+static struct drm_client_buffer *
+drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, 
u32 format)
+{
+   struct drm_mode_create_dumb dumb_args = { };
+   struct drm_prime_handle prime_args = { };
+   struct drm_client_buffer *buffer;
+   struct dma_buf *dma_buf;
+   void *vaddr;
+   int ret;
+
+   buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
+   if (!buffer)
+   return ERR_PTR(-ENOMEM);
+
+   buffer->client = client;
+   buffer->width = width;
+   buffer->height = height;
+   buffer->format = format;
+
+   dumb_args.width = buffer->width;
+   dumb_args.height = buffer->height;
+   dumb_args.bpp = drm_format_plane_cpp(format, 0) * 8;
+   ret = drm_mode_create_dumb(client->dev, _args, client->file);
+   if (ret)
+   goto err_free;
+
+   buffer->handle = dumb_args.handle;
+   buffer->pitch = dumb_args.pitch;
+   buffer->size = dumb_args.size;
+
+   prime_args.handle = dumb_args.handle;
+   ret = drm_prime_handle_to_fd(client->dev, _args, client->file);
+   if (ret)
+   goto err_delete;
+
+   dma_buf = dma_buf_get(prime_args.fd);
+   if (IS_ERR(dma_buf)) {
+   ret = PTR_ERR(dma_buf);
+   goto err_delete;
+   }
+
+   /*
+* If called from a worker the dmabuf fd isn't closed and the ref
+* doesn't drop to zero on free.
+* If I use __close_fd() it's all fine, but that function is not 
exported.
+*
+* How do I get rid of this fd when in a worker/kernel thread?
+* The fd isn't used beyond this function.
+*/
+// WARN_ON(__close_fd(current->files, prime_args.fd));

Hm, this isn't 100% what I had in mind as the sequence for generic buffer
creation. Pseudo-code:

ret = drm_mode_create_dumb(client->dev, _args, client->file);
if (ret)
goto err_free;

gem_bo = drm_gem_object_lookup(client->file, dumb_args.handle);

gives you _really_ directly the underlying gem_bo. Of course this doesn't
work for non-gem based driver, but reality is that (almost) all of them
are. And we will not accept any new drivers which aren't gem based. So
ignoring vmwgfx for this drm_client work is imo perfectly fine. We should
ofc keep the option in the fb helpers to use non-gem buffers (so that
vmwgfx could switch over from their own in-driver fbdev helpers). All we
need for that is to keep the fb_probe callback.

Was there any other reason than vmwgfx for using prime buffers instead of
just directly using gem?


The reason for using a prime buffer is that it gives me easy access to a
dma_buf which I use to get the virtual address (dma_buf_vmap) and for
mmap (dma_buf_mmap).

Would this stripped down version of drm_gem_prime_handle_to_fd() work?

struct dma_buf *drm_gem_to_dmabuf(struct drm_gem_object *obj)
{
    struct dma_buf *dmabuf;

    mutex_lock(>dev->object_name_lock);
    /* re-export the original imported object */
    if (obj->import_attach) {
        dmabuf = obj->import_attach->dmabuf;
        get_dma_buf(dmabuf);
        goto out;
    }

    if (obj->dma_buf) {
        dmabuf = obj->dma_buf;
        get_dma_buf(dmabuf);
        goto out;
    }

    dmabuf = export_and_register_object(obj->dev, obj, 0);
out:
    mutex_unlock(>dev->object_name_lock);

    return dmabuf;
}

Now I could do this:

    ret = drm_mode_create_dumb(dev, _args, file);

    obj = drm_gem_object_lookup(file, dumb_args.handle);

    dmabuf = drm_gem_to_dmabuf(obj);

    vaddr = dma_buf_vmap(dmabuf);


Noralf.

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [Intel-gfx] [RFC v4 19/25] drm/client: Finish the in-kernel client API

2018-04-16 Thread Daniel Vetter
On Sat, Apr 14, 2018 at 01:53:12PM +0200, Noralf Trønnes wrote:
> The modesetting code is already present, this adds the rest of the API.

Mentioning the TODO in the commit message would be good. Helps readers
like me who have an attention span measured in seconds :-)

Just commenting on the create_buffer leak here

> +static struct drm_client_buffer *
> +drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 
> height, u32 format)
> +{
> + struct drm_mode_create_dumb dumb_args = { };
> + struct drm_prime_handle prime_args = { };
> + struct drm_client_buffer *buffer;
> + struct dma_buf *dma_buf;
> + void *vaddr;
> + int ret;
> +
> + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
> + if (!buffer)
> + return ERR_PTR(-ENOMEM);
> +
> + buffer->client = client;
> + buffer->width = width;
> + buffer->height = height;
> + buffer->format = format;
> +
> + dumb_args.width = buffer->width;
> + dumb_args.height = buffer->height;
> + dumb_args.bpp = drm_format_plane_cpp(format, 0) * 8;
> + ret = drm_mode_create_dumb(client->dev, _args, client->file);
> + if (ret)
> + goto err_free;
> +
> + buffer->handle = dumb_args.handle;
> + buffer->pitch = dumb_args.pitch;
> + buffer->size = dumb_args.size;
> +
> + prime_args.handle = dumb_args.handle;
> + ret = drm_prime_handle_to_fd(client->dev, _args, client->file);
> + if (ret)
> + goto err_delete;
> +
> + dma_buf = dma_buf_get(prime_args.fd);
> + if (IS_ERR(dma_buf)) {
> + ret = PTR_ERR(dma_buf);
> + goto err_delete;
> + }
> +
> + /*
> +  * If called from a worker the dmabuf fd isn't closed and the ref
> +  * doesn't drop to zero on free.
> +  * If I use __close_fd() it's all fine, but that function is not 
> exported.
> +  *
> +  * How do I get rid of this fd when in a worker/kernel thread?
> +  * The fd isn't used beyond this function.
> +  */
> +//   WARN_ON(__close_fd(current->files, prime_args.fd));

Hm, this isn't 100% what I had in mind as the sequence for generic buffer
creation. Pseudo-code:

ret = drm_mode_create_dumb(client->dev, _args, client->file);
if (ret)
goto err_free;

gem_bo = drm_gem_object_lookup(client->file, dumb_args.handle);

gives you _really_ directly the underlying gem_bo. Of course this doesn't
work for non-gem based driver, but reality is that (almost) all of them
are. And we will not accept any new drivers which aren't gem based. So
ignoring vmwgfx for this drm_client work is imo perfectly fine. We should
ofc keep the option in the fb helpers to use non-gem buffers (so that
vmwgfx could switch over from their own in-driver fbdev helpers). All we
need for that is to keep the fb_probe callback.

Was there any other reason than vmwgfx for using prime buffers instead of
just directly using gem?

Cheers, Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC v4 19/25] drm/client: Finish the in-kernel client API

2018-04-14 Thread Noralf Trønnes
The modesetting code is already present, this adds the rest of the API.

Signed-off-by: Noralf Trønnes 
---
 drivers/gpu/drm/drm_client.c   | 573 +
 drivers/gpu/drm/drm_debugfs.c  |   7 +
 drivers/gpu/drm/drm_drv.c  |  11 +
 drivers/gpu/drm/drm_file.c |   3 +
 drivers/gpu/drm/drm_probe_helper.c |   3 +
 drivers/gpu/drm/drm_sysfs.c|  20 ++
 include/drm/drm_client.h   | 103 +++
 include/drm/drm_device.h   |   4 +
 8 files changed, 724 insertions(+)

diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index bce1630a0db2..760f1795f812 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -8,7 +8,9 @@
  * Copyright (c) 2007 Dave Airlie 
  */
 
+#include 
 #include 
+#include 
 #include 
 
 #include 
@@ -17,14 +19,280 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
+#include "drm_crtc_internal.h"
 #include "drm_internal.h"
 
 struct drm_client_display_offset {
int x, y;
 };
 
+static int drm_client_alloc_file(struct drm_client_dev *client)
+{
+   struct drm_device *dev = client->dev;
+   struct drm_file *file;
+
+   file = drm_file_alloc(dev->primary);
+   if (IS_ERR(file))
+   return PTR_ERR(file);
+
+   drm_dev_get(dev);
+
+   mutex_lock(>filelist_mutex);
+   list_add(>lhead, >filelist_internal);
+   mutex_unlock(>filelist_mutex);
+
+   client->file = file;
+
+   return 0;
+}
+
+static void drm_client_free_file(struct drm_client_dev *client)
+{
+   struct drm_device *dev = client->dev;
+
+   mutex_lock(>filelist_mutex);
+   list_del(>file->lhead);
+   mutex_unlock(>filelist_mutex);
+
+   drm_file_free(client->file);
+   drm_dev_put(dev);
+}
+
+struct drm_client_dev *
+drm_client_new(struct drm_device *dev, const struct drm_client_funcs *funcs)
+{
+   struct drm_client_dev *client;
+   int ret;
+
+   if (WARN_ON(!funcs->name))
+   return ERR_PTR(-EINVAL);
+
+   client = kzalloc(sizeof(*client), GFP_KERNEL);
+   if (!client)
+   return ERR_PTR(-ENOMEM);
+
+   client->dev = dev;
+   client->funcs = funcs;
+
+   ret = drm_client_alloc_file(client);
+   if (ret) {
+   kfree(client);
+   return ERR_PTR(ret);
+   }
+
+   mutex_lock(>clientlist_mutex);
+   list_add(>list, >clientlist);
+   mutex_unlock(>clientlist_mutex);
+
+   return client;
+}
+EXPORT_SYMBOL(drm_client_new);
+
+struct drm_client_dev *
+drm_client_new_from_id(unsigned int dev_id, const struct drm_client_funcs 
*funcs)
+{
+   struct drm_client_dev *client;
+   struct drm_minor *minor;
+
+   minor = drm_minor_acquire(dev_id);
+   if (IS_ERR(minor))
+   return ERR_CAST(minor);
+
+   client = drm_client_new(minor->dev, funcs);
+
+   drm_minor_release(minor);
+
+   return client;
+}
+EXPORT_SYMBOL(drm_client_new_from_id);
+
+/**
+ * drm_client_free - Free DRM client resources
+ * @client: DRM client
+ *
+ * This is called automatically on client removal unless the client returns
+ * non-zero in the _client_funcs->remove callback. The fbdev client does
+ * this when it can't close _file because userspace has an open fd.
+ *
+ * Note:
+ * If the client can't release it's resources on remove, it needs to hold a
+ * reference on the driver module to prevent the code from going away.
+ */
+void drm_client_free(struct drm_client_dev *client)
+{
+   DRM_DEV_DEBUG_KMS(client->dev->dev, "%s\n", client->funcs->name);
+   drm_client_free_file(client);
+   kfree(client);
+}
+EXPORT_SYMBOL(drm_client_free);
+
+static void drm_client_remove_locked(struct drm_client_dev *client)
+{
+   list_del(>list);
+
+   if (!client->funcs->remove || !client->funcs->remove(client))
+   drm_client_free(client);
+}
+
+static void drm_client_remove_safe(struct drm_device *dev,
+  struct drm_client_dev *client)
+{
+   struct drm_client_dev *iter;
+
+   mutex_lock(>clientlist_mutex);
+   list_for_each_entry(iter, >clientlist, list) {
+   if (iter == client) {
+   drm_client_remove_locked(client);
+   break;
+   }
+   }
+   mutex_unlock(>clientlist_mutex);
+}
+
+/**
+ * drm_client_remove - Remove client
+ * @client: Client
+ *
+ * Remove a client.
+ */
+void drm_client_remove(struct drm_client_dev *client)
+{
+   struct drm_device *dev;
+
+   if (!client)
+   return;
+
+   dev = client->dev;
+   drm_dev_get(dev);
+   drm_client_remove_safe(dev, client);
+   drm_dev_put(dev);
+}
+EXPORT_SYMBOL(drm_client_remove);
+
+struct drm_client_remove_defer {
+   struct list_head list;
+   struct drm_device *dev;
+   struct drm_client_dev *client;
+};
+
+static LIST_HEAD(drm_client_remove_defer_list);

[RFC v4 19/25] drm/client: Finish the in-kernel client API

2018-04-13 Thread Noralf Trønnes
The modesetting code is already present, this adds the rest of the API.

Signed-off-by: Noralf Trønnes 
---
 drivers/gpu/drm/drm_client.c   | 573 +
 drivers/gpu/drm/drm_debugfs.c  |   7 +
 drivers/gpu/drm/drm_drv.c  |  11 +
 drivers/gpu/drm/drm_file.c |   3 +
 drivers/gpu/drm/drm_probe_helper.c |   3 +
 drivers/gpu/drm/drm_sysfs.c|  20 ++
 include/drm/drm_client.h   | 103 +++
 include/drm/drm_device.h   |   4 +
 8 files changed, 724 insertions(+)

diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index bce1630a0db2..760f1795f812 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -8,7 +8,9 @@
  * Copyright (c) 2007 Dave Airlie 
  */
 
+#include 
 #include 
+#include 
 #include 
 
 #include 
@@ -17,14 +19,280 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
+#include "drm_crtc_internal.h"
 #include "drm_internal.h"
 
 struct drm_client_display_offset {
int x, y;
 };
 
+static int drm_client_alloc_file(struct drm_client_dev *client)
+{
+   struct drm_device *dev = client->dev;
+   struct drm_file *file;
+
+   file = drm_file_alloc(dev->primary);
+   if (IS_ERR(file))
+   return PTR_ERR(file);
+
+   drm_dev_get(dev);
+
+   mutex_lock(>filelist_mutex);
+   list_add(>lhead, >filelist_internal);
+   mutex_unlock(>filelist_mutex);
+
+   client->file = file;
+
+   return 0;
+}
+
+static void drm_client_free_file(struct drm_client_dev *client)
+{
+   struct drm_device *dev = client->dev;
+
+   mutex_lock(>filelist_mutex);
+   list_del(>file->lhead);
+   mutex_unlock(>filelist_mutex);
+
+   drm_file_free(client->file);
+   drm_dev_put(dev);
+}
+
+struct drm_client_dev *
+drm_client_new(struct drm_device *dev, const struct drm_client_funcs *funcs)
+{
+   struct drm_client_dev *client;
+   int ret;
+
+   if (WARN_ON(!funcs->name))
+   return ERR_PTR(-EINVAL);
+
+   client = kzalloc(sizeof(*client), GFP_KERNEL);
+   if (!client)
+   return ERR_PTR(-ENOMEM);
+
+   client->dev = dev;
+   client->funcs = funcs;
+
+   ret = drm_client_alloc_file(client);
+   if (ret) {
+   kfree(client);
+   return ERR_PTR(ret);
+   }
+
+   mutex_lock(>clientlist_mutex);
+   list_add(>list, >clientlist);
+   mutex_unlock(>clientlist_mutex);
+
+   return client;
+}
+EXPORT_SYMBOL(drm_client_new);
+
+struct drm_client_dev *
+drm_client_new_from_id(unsigned int dev_id, const struct drm_client_funcs 
*funcs)
+{
+   struct drm_client_dev *client;
+   struct drm_minor *minor;
+
+   minor = drm_minor_acquire(dev_id);
+   if (IS_ERR(minor))
+   return ERR_CAST(minor);
+
+   client = drm_client_new(minor->dev, funcs);
+
+   drm_minor_release(minor);
+
+   return client;
+}
+EXPORT_SYMBOL(drm_client_new_from_id);
+
+/**
+ * drm_client_free - Free DRM client resources
+ * @client: DRM client
+ *
+ * This is called automatically on client removal unless the client returns
+ * non-zero in the _client_funcs->remove callback. The fbdev client does
+ * this when it can't close _file because userspace has an open fd.
+ *
+ * Note:
+ * If the client can't release it's resources on remove, it needs to hold a
+ * reference on the driver module to prevent the code from going away.
+ */
+void drm_client_free(struct drm_client_dev *client)
+{
+   DRM_DEV_DEBUG_KMS(client->dev->dev, "%s\n", client->funcs->name);
+   drm_client_free_file(client);
+   kfree(client);
+}
+EXPORT_SYMBOL(drm_client_free);
+
+static void drm_client_remove_locked(struct drm_client_dev *client)
+{
+   list_del(>list);
+
+   if (!client->funcs->remove || !client->funcs->remove(client))
+   drm_client_free(client);
+}
+
+static void drm_client_remove_safe(struct drm_device *dev,
+  struct drm_client_dev *client)
+{
+   struct drm_client_dev *iter;
+
+   mutex_lock(>clientlist_mutex);
+   list_for_each_entry(iter, >clientlist, list) {
+   if (iter == client) {
+   drm_client_remove_locked(client);
+   break;
+   }
+   }
+   mutex_unlock(>clientlist_mutex);
+}
+
+/**
+ * drm_client_remove - Remove client
+ * @client: Client
+ *
+ * Remove a client.
+ */
+void drm_client_remove(struct drm_client_dev *client)
+{
+   struct drm_device *dev;
+
+   if (!client)
+   return;
+
+   dev = client->dev;
+   drm_dev_get(dev);
+   drm_client_remove_safe(dev, client);
+   drm_dev_put(dev);
+}
+EXPORT_SYMBOL(drm_client_remove);
+
+struct drm_client_remove_defer {
+   struct list_head list;
+   struct drm_device *dev;
+   struct drm_client_dev *client;
+};
+
+static LIST_HEAD(drm_client_remove_defer_list);

[RFC v4 19/25] drm/client: Finish the in-kernel client API

2018-04-12 Thread Noralf Trønnes
The modesetting code is already present, this adds the rest of the API.

Signed-off-by: Noralf Trønnes 
---
 drivers/gpu/drm/drm_client.c   | 573 +
 drivers/gpu/drm/drm_debugfs.c  |   7 +
 drivers/gpu/drm/drm_drv.c  |  11 +
 drivers/gpu/drm/drm_file.c |   3 +
 drivers/gpu/drm/drm_probe_helper.c |   3 +
 drivers/gpu/drm/drm_sysfs.c|  20 ++
 include/drm/drm_client.h   | 103 +++
 include/drm/drm_device.h   |   4 +
 8 files changed, 724 insertions(+)

diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index bce1630a0db2..760f1795f812 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -8,7 +8,9 @@
  * Copyright (c) 2007 Dave Airlie 
  */
 
+#include 
 #include 
+#include 
 #include 
 
 #include 
@@ -17,14 +19,280 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
+#include "drm_crtc_internal.h"
 #include "drm_internal.h"
 
 struct drm_client_display_offset {
int x, y;
 };
 
+static int drm_client_alloc_file(struct drm_client_dev *client)
+{
+   struct drm_device *dev = client->dev;
+   struct drm_file *file;
+
+   file = drm_file_alloc(dev->primary);
+   if (IS_ERR(file))
+   return PTR_ERR(file);
+
+   drm_dev_get(dev);
+
+   mutex_lock(>filelist_mutex);
+   list_add(>lhead, >filelist_internal);
+   mutex_unlock(>filelist_mutex);
+
+   client->file = file;
+
+   return 0;
+}
+
+static void drm_client_free_file(struct drm_client_dev *client)
+{
+   struct drm_device *dev = client->dev;
+
+   mutex_lock(>filelist_mutex);
+   list_del(>file->lhead);
+   mutex_unlock(>filelist_mutex);
+
+   drm_file_free(client->file);
+   drm_dev_put(dev);
+}
+
+struct drm_client_dev *
+drm_client_new(struct drm_device *dev, const struct drm_client_funcs *funcs)
+{
+   struct drm_client_dev *client;
+   int ret;
+
+   if (WARN_ON(!funcs->name))
+   return ERR_PTR(-EINVAL);
+
+   client = kzalloc(sizeof(*client), GFP_KERNEL);
+   if (!client)
+   return ERR_PTR(-ENOMEM);
+
+   client->dev = dev;
+   client->funcs = funcs;
+
+   ret = drm_client_alloc_file(client);
+   if (ret) {
+   kfree(client);
+   return ERR_PTR(ret);
+   }
+
+   mutex_lock(>clientlist_mutex);
+   list_add(>list, >clientlist);
+   mutex_unlock(>clientlist_mutex);
+
+   return client;
+}
+EXPORT_SYMBOL(drm_client_new);
+
+struct drm_client_dev *
+drm_client_new_from_id(unsigned int dev_id, const struct drm_client_funcs 
*funcs)
+{
+   struct drm_client_dev *client;
+   struct drm_minor *minor;
+
+   minor = drm_minor_acquire(dev_id);
+   if (IS_ERR(minor))
+   return ERR_CAST(minor);
+
+   client = drm_client_new(minor->dev, funcs);
+
+   drm_minor_release(minor);
+
+   return client;
+}
+EXPORT_SYMBOL(drm_client_new_from_id);
+
+/**
+ * drm_client_free - Free DRM client resources
+ * @client: DRM client
+ *
+ * This is called automatically on client removal unless the client returns
+ * non-zero in the _client_funcs->remove callback. The fbdev client does
+ * this when it can't close _file because userspace has an open fd.
+ *
+ * Note:
+ * If the client can't release it's resources on remove, it needs to hold a
+ * reference on the driver module to prevent the code from going away.
+ */
+void drm_client_free(struct drm_client_dev *client)
+{
+   DRM_DEV_DEBUG_KMS(client->dev->dev, "%s\n", client->funcs->name);
+   drm_client_free_file(client);
+   kfree(client);
+}
+EXPORT_SYMBOL(drm_client_free);
+
+static void drm_client_remove_locked(struct drm_client_dev *client)
+{
+   list_del(>list);
+
+   if (!client->funcs->remove || !client->funcs->remove(client))
+   drm_client_free(client);
+}
+
+static void drm_client_remove_safe(struct drm_device *dev,
+  struct drm_client_dev *client)
+{
+   struct drm_client_dev *iter;
+
+   mutex_lock(>clientlist_mutex);
+   list_for_each_entry(iter, >clientlist, list) {
+   if (iter == client) {
+   drm_client_remove_locked(client);
+   break;
+   }
+   }
+   mutex_unlock(>clientlist_mutex);
+}
+
+/**
+ * drm_client_remove - Remove client
+ * @client: Client
+ *
+ * Remove a client.
+ */
+void drm_client_remove(struct drm_client_dev *client)
+{
+   struct drm_device *dev;
+
+   if (!client)
+   return;
+
+   dev = client->dev;
+   drm_dev_get(dev);
+   drm_client_remove_safe(dev, client);
+   drm_dev_put(dev);
+}
+EXPORT_SYMBOL(drm_client_remove);
+
+struct drm_client_remove_defer {
+   struct list_head list;
+   struct drm_device *dev;
+   struct drm_client_dev *client;
+};
+
+static LIST_HEAD(drm_client_remove_defer_list);