[03/59] drm/prime: Update docs
diff mbox series

Message ID 20190614203615.12639-4-daniel.vetter@ffwll.ch
State New
Headers show
Series
  • prime doc polish and ... a few cleanups
Related show

Commit Message

Daniel Vetter June 14, 2019, 8:35 p.m. UTC
Yes this is a bit a big patch, but since it's essentially a complete
rewrite of all the prime docs I didn't see how to better split it up.

Changes:
- Consistently point to drm_gem_object_funcs as the preferred hooks,
  where applicable.

- Reorder all the functions in drm_prime.[hc] into three groups: core,
  export helpers, import helpers.

- Document all the hooks in &drm_driver that lacked kerneldoc.

- Completely new overview section, which now also includes the cleaned
  up lifetime/reference counting subchapter. I also mentioned the weak
  references in there due to the lookup caches.

- Completely rewritten helper intro section, highlight the
  import/export related functionality.

- Polish for all the functions and more cross references.

I also sprinkled a bunch of todos all over.

Most important: 0 code changes in here. The cleanup motivated by
reading and improving all this will follow later on.

v2: Actually update the prime helper docs. Plus add a few FIXMEs that
I won't address right away in subsequent cleanup patches.

Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
---
 Documentation/gpu/drm-mm.rst |  40 +-
 drivers/gpu/drm/drm_prime.c  | 851 ++++++++++++++++++-----------------
 include/drm/drm_drv.h        | 104 ++++-
 include/drm/drm_gem.h        |  18 +-
 include/drm/drm_prime.h      |  42 +-
 5 files changed, 576 insertions(+), 479 deletions(-)

Comments

Sam Ravnborg June 15, 2019, 11:41 a.m. UTC | #1
Hi Daniel

Better and more consistent docs - good!
With relevant comments addressed:
Reviewed-by: Sam Ravnborg <sam@ravnborg.org>

> +/**
> + * DOC: overview and lifetime rules
> + *
> + * Similar to GEM global names, PRIME file descriptors are also used to share
> + * buffer objects across processes. They offer additional security: as file
> + * descriptors must be explicitly sent over UNIX domain sockets to be shared
> + * between applications, they can't be guessed like the globally unique GEM
> + * names.
For a newbie like me the above does not really help to understand what
PRIME is.
Yes, it is file descriptors used to share buffer objects across
processes.
But the text say "also used ..", so the main usage of PRIME is something
else.

But as said, newbie so it may be fine for most readers.

> + *
> + * Drivers that support the PRIME API must set the DRIVER_PRIME bit in the
> + * &drm_driver.driver_features field, and implement the
> + * &drm_driver.prime_handle_to_fd and &drm_driver.prime_fd_to_handle operations.

> + * GEM based drivers must use drm_gem_prime_handle_to_fd() an
> + * drm_gem_prime_fd_to_handle() to implement these.
an => and in the above.

> + * drm_gem_prime_fd_to_handle - PRIME import function for GEM drivers
> + * @dev: dev to export the buffer from
> + * @file_priv: drm file-private structure
> + * @prime_fd: fd id of the dma-buf which should be imported
> + * @handle: pointer to storage for the handle of the imported buffer object
>   *
> + * This is the PRIME import function which must be used mandatorily by GEM
> + * drivers to ensure correct lifetime management of the underlying GEM object.
> + * The actual importing of GEM object from the dma-buf is done through the
> + * &drm_driver.gem_import_export driver callback.
Here maybe add a description of the return result.
If I read the code correct:
Returns 0 on success or negative error code on failure.

>   */
> -void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf)
> +int drm_gem_prime_fd_to_handle(struct drm_device *dev,
> +			       struct drm_file *file_priv, int prime_fd,
> +			       uint32_t *handle)
>  {
> -	struct drm_gem_object *obj = dma_buf->priv;
> -	void *vaddr;
> +	struct dma_buf *dma_buf;
> +	struct drm_gem_object *obj;
> +	int ret;
>  
> -	vaddr = drm_gem_vmap(obj);
> -	if (IS_ERR(vaddr))
> -		vaddr = NULL;
> +	dma_buf = dma_buf_get(prime_fd);
> +	if (IS_ERR(dma_buf))
> +		return PTR_ERR(dma_buf);
>  
> +	mutex_lock(&file_priv->prime.lock);
>  
> +	ret = drm_prime_lookup_buf_handle(&file_priv->prime,
> +			dma_buf, handle);
> +	if (ret == 0)
> +		goto out_put;
>  
> +	/* never seen this one, need to import */
> +	mutex_lock(&dev->object_name_lock);
> +	if (dev->driver->gem_prime_import)
> +		obj = dev->driver->gem_prime_import(dev, dma_buf);
> +	else
> +		obj = drm_gem_prime_import(dev, dma_buf);
> +	if (IS_ERR(obj)) {
> +		ret = PTR_ERR(obj);
> +		goto out_unlock;
> +	}
> +	if (obj->dma_buf) {
> +		WARN_ON(obj->dma_buf != dma_buf);
> +	} else {
> +		obj->dma_buf = dma_buf;
> +		get_dma_buf(dma_buf);
> +	}
>  
> +	/* _handle_create_tail unconditionally unlocks dev->object_name_lock. */
> +	ret = drm_gem_handle_create_tail(file_priv, obj, handle);
> +	drm_gem_object_put_unlocked(obj);
> +	if (ret)
> +		goto out_put;
>  
> +	ret = drm_prime_add_buf_handle(&file_priv->prime,
> +			dma_buf, *handle);
> +	mutex_unlock(&file_priv->prime.lock);
> +	if (ret)
> +		goto fail;
> +	dma_buf_put(dma_buf);
>  
> +	return 0;
>  
> +fail:
> +	/* hmm, if driver attached, we are relying on the free-object path
> +	 * to detach.. which seems ok..
> +	 */
> +	drm_gem_handle_delete(file_priv, *handle);
> +	dma_buf_put(dma_buf);
> +	return ret;
> +
> +out_unlock:
> +	mutex_unlock(&dev->object_name_lock);
> +out_put:
> +	mutex_unlock(&file_priv->prime.lock);
> +	dma_buf_put(dma_buf);
> +	return ret;
> +}
> +EXPORT_SYMBOL(drm_gem_prime_fd_to_handle);
> +
> +
> +/**
> + * DOC: PRIME Helpers
> + *
> + * Drivers can implement &drm_gem_object_funcs.export and
> + * &drm_driver.gem_prime_import in terms of simpler APIs by using the helper
> + * functions drm_gem_prime_export() and drm_gem_prime_import().  These functions
> + * implement dma-buf support in terms of some lower-level helpers, which are
> + * again exported for drivers to use individually:
> + *
> + * Exporting buffers
> + * ~~~~~~~~~~~~~~~~~
> + *
> + * Optional pinning of buffers is handled at dma-buf attach and detach time in
> + * drm_gem_map_attach() and drm_gem_map_detach(). Backing storage itself is
> + * handled by drm_gem_map_dma_buf() and drm_gem_unmap_dma_buf(), which relies on
> + * &drm_gem_object_funcs.get_sg_table.
> + *
> + * For kernel-internal access there's drm_gem_dmabuf_vmap() and
> + * drm_gem_dmabuf_vunmap(). Userspace mmap support is provided by
> + * drm_gem_dmabuf_mmap().
> + *
> + * Note that these export helpers can only be used if the underlying backing
> + * storage is fully coherent and either permanently pinned, or it is safe to pin
> + * it indefinitely.
> + *
> + * FIXME: The underlying helper functions are named rather inconsistently.
> + *
> + * Exporting buffers
> + * ~~~~~~~~~~~~~~~~~
> + *
> + * Importing dma-bufs using drm_gem_prime_import() relies on
> + * &drm_driver.gem_prime_import_sg_table.
> + *
> + * Note that similarly to the export helpers this permanently pins the
> + * underlying backing storage. Which is ok for scanout, but is not the best
> + * option for sharing lots of buffers for rendering.
> + */
> +
> +/**
> + * drm_gem_map_attach - dma_buf attach implementation for GEM
> + * @dma_buf: buffer to attach device to
> + * @attach: buffer attachment data
> + *
> + * Calls &drm_gem_object_funcs.pin for device specific handling. This can be
> + * used as the &dma_buf_ops.attach callback. Must be used together with
> + * drm_gem_map_detach().
> + *
> + * Returns 0 on success, negative error code on failure.
> + */
> +int drm_gem_map_attach(struct dma_buf *dma_buf,
> +		       struct dma_buf_attachment *attach)
> +{
> +	struct drm_gem_object *obj = dma_buf->priv;
> +
> +	return drm_gem_pin(obj);
> +}
> +EXPORT_SYMBOL(drm_gem_map_attach);
> +
> +/**
> + * drm_gem_map_detach - dma_buf detach implementation for GEM
> + * @dma_buf: buffer to detach from
> + * @attach: attachment to be detached
> + *
> + * Calls &drm_gem_object_funcs.pin for device specific handling.  Cleans up
> + * &dma_buf_attachment from drm_gem_map_attach(). This can be used as the
> + * &dma_buf_ops.detach callback.
> + */
> +void drm_gem_map_detach(struct dma_buf *dma_buf,
> +			struct dma_buf_attachment *attach)
> +{
> +	struct drm_gem_object *obj = dma_buf->priv;
> +
> +	drm_gem_unpin(obj);
> +}
> +EXPORT_SYMBOL(drm_gem_map_detach);
> +
> +/**
> + * drm_gem_map_dma_buf - map_dma_buf implementation for GEM
> + * @attach: attachment whose scatterlist is to be returned
> + * @dir: direction of DMA transfer
> + *
> + * Calls &drm_gem_object_funcs.get_sg_table and then maps the scatterlist. This
> + * can be used as the &dma_buf_ops.map_dma_buf callback. Should be used together
> + * with drm_gem_unmap_dma_buf().
> + *
> + * Returns:sg_table containing the scatterlist to be returned; returns ERR_PTR
> + * on error. May return -EINTR if it is interrupted by a signal.
> + */
Nit - add space after ':'

> +
> +/**
> + * drm_gem_dmabuf_vmap - dma_buf vmap implementation for GEM
> + * @dma_buf: buffer to be mapped
> + *
> + * Sets up a kernel virtual mapping. This can be used as the &dma_buf_ops.vmap
> + * callback. Calls into &drm_gem_object_funcs.vmap for device specific handling.
> + *
> + * Returns the kernel virtual address.
or NULL if failed to setup virtual mapping.

> + */
> +void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf)
> +{
> +	struct drm_gem_object *obj = dma_buf->priv;
> +	void *vaddr;
> +
> +	vaddr = drm_gem_vmap(obj);
> +	if (IS_ERR(vaddr))
> +		vaddr = NULL;
> +
> +	return vaddr;
> +}
> +EXPORT_SYMBOL(drm_gem_dmabuf_vmap);


>  /**
>   * drm_gem_prime_import_dev - core implementation of the import callback
>   * @dev: drm_device to import into
>   * @dma_buf: dma-buf object to import
>   * @attach_dev: struct device to dma_buf attach
>   *
> - * This is the core of drm_gem_prime_import. It's designed to be called by
> - * drivers who want to use a different device structure than dev->dev for
> - * attaching via dma_buf.
> + * This is the core of drm_gem_prime_import(). It's designed to be called by
> + * drivers who want to use a different device structure than &drm_device.dev for
> + * attaching via dma_buf. This function calls
> + * &drm_driver.gem_prime_import_sg_table internally.
> + *
> + * Drivers must arrange to call drm_prime_gem_destroy() from their
> + * &drm_gem_object_funcs.free hook when using this function.
>   */
>  struct drm_gem_object *drm_gem_prime_import_dev(struct drm_device *dev,
>  					    struct dma_buf *dma_buf,
> @@ -728,7 +923,11 @@ EXPORT_SYMBOL(drm_gem_prime_import_dev);
>   * @dma_buf: dma-buf object to import
>   *
>   * This is the implementation of the gem_prime_import functions for GEM drivers
> - * using the PRIME helpers.
> + * using the PRIME helpers. Drivers can use this as their
> + * &drm_driver.gem_prime_import implementation.
> + *
> + * Drivers must arrange to call drm_prime_gem_destroy() from their
> + * &drm_gem_object_funcs.free hook when using this function.

Could we here document what function we provide as the default
&drm_gem_object_funcs.free hook, which do the drm_prime_gem_destroy()
call.
I read the above that drivers have to provide their own implementation
of a .free hook, and I do not think this is right.


> +++ b/include/drm/drm_drv.h
> @@ -505,21 +505,25 @@ struct drm_driver {
>  	 * @gem_free_object: deconstructor for drm_gem_objects
>  	 *
>  	 * This is deprecated and should not be used by new drivers. Use
> -	 * @gem_free_object_unlocked instead.
> +	 * &drm_gem_object_funcs.free instead.
>  	 */
>  	void (*gem_free_object) (struct drm_gem_object *obj);
>  
>  	/**
>  	 * @gem_free_object_unlocked: deconstructor for drm_gem_objects
>  	 *
> -	 * This is for drivers which are not encumbered with &drm_device.struct_mutex
> -	 * legacy locking schemes. Use this hook instead of @gem_free_object.
> +	 * This is deprecated and should not be used by new drivers. Use
> +	 * &drm_gem_object_funcs.free instead.
> +	 * Compared to @gem_free_object this is not encumbered with
> +	 * &drm_device.struct_mutex legacy locking schemes.
>  	 */
It is confusing why the above comment refer to another callback.
Is this the right wording?
	* Compared to @gem_free_object_unlocked this is not encumbered with
	* &drm_device.struct_mutex legacy locking schemes.

Do gem_free_object() warrant a similar comment?


> @@ -548,56 +557,120 @@ struct drm_driver {
>  	/**
>  	 * @gem_create_object: constructor for gem objects
>  	 *
> -	 * Hook for allocating the GEM object struct, for use by core
> -	 * helpers.
> +	 * Hook for allocating the GEM object struct, for use by the CMA and
> +	 * SHMEM GEM helpers.
>  	 */
>  	struct drm_gem_object *(*gem_create_object)(struct drm_device *dev,
>  						    size_t size);
Nit: In some places we do:
	int (foo) (int bar);
other:
	int (foo)(int bar);

No preference here, but it hurts my OCD a little that it is
inconsistent.

> -
> -	/* prime: */
>  	/**
>  	 * @prime_handle_to_fd:
>  	 *
> -	 * export handle -> fd (see drm_gem_prime_handle_to_fd() helper)
> +	 * Main PRIME export function. Should be implented with
s/implented/implemented/

> +	 * drm_gem_prime_handle_to_fd() for GEM based drivers.
> +	 *
> +	 * For an in-depth discussion see :ref:`PRIME buffer sharing
> +	 * documentation <prime_buffer_sharing>`.
>  	 */
>  	int (*prime_handle_to_fd)(struct drm_device *dev, struct drm_file *file_priv,
>  				uint32_t handle, uint32_t flags, int *prime_fd);
>  	/**
>  	 * @prime_fd_to_handle:
>  	 *
> -	 * import fd -> handle (see drm_gem_prime_fd_to_handle() helper)
> +	 * Main PRIME import function. Should be implented with
s/implented/implemented/

> +	 * drm_gem_prime_fd_to_handle() for GEM based drivers.
> +	 *
> +	 * For an in-depth discussion see :ref:`PRIME buffer sharing
> +	 * documentation <prime_buffer_sharing>`.
>  	 */
>  	int (*prime_fd_to_handle)(struct drm_device *dev, struct drm_file *file_priv,
>  				int prime_fd, uint32_t *handle);
>  	/**
>  	 * @gem_prime_export:
>  	 *
> -	 * export GEM -> dmabuf
> -	 *
> -	 * This defaults to drm_gem_prime_export() if not set.
> +	 * Export hook for GEM drivers. Deprecated in favour of
> +	 * &drm_gem_object_funcs.export.
>  	 */
>  	struct dma_buf * (*gem_prime_export)(struct drm_device *dev,
>  				struct drm_gem_object *obj, int flags);
>  	/**
>  	 * @gem_prime_import:
>  	 *
> -	 * import dmabuf -> GEM
> +	 * Import hook for GEM drivers.
>  	 *
>  	 * This defaults to drm_gem_prime_import() if not set.
>  	 */
>  	struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev,
>  				struct dma_buf *dma_buf);
> +
> +	/**
> +	 * @gem_prime_pin:
> +	 *
> +	 * Deprecated hook in favour of &drm_gem_object_funcs.pin.
> +	 */
>  	int (*gem_prime_pin)(struct drm_gem_object *obj);
> +
> +	/**
> +	 * @gem_prime_unpin:
> +	 *
> +	 * Deprecated hook in favour of &drm_gem_object_funcs.unpin.
> +	 */
>  	void (*gem_prime_unpin)(struct drm_gem_object *obj);
> +
> +
> +	/**
> +	 * @gem_prime_get_sg_table:
> +	 *
> +	 * Deprecated hook in favour of &drm_gem_object_funcs.get_sg_table.
> +	 */
> +	struct sg_table *(*gem_prime_get_sg_table)(struct drm_gem_object *obj);
> +
> +	/**
> +	 * @gem_prime_res_obj:
> +	 *
> +	 * Optional hook to look up the &reservation_object for an buffer when
> +	 * exporting it.
> +	 *
> +	 * FIXME: This hook is deprecated. User of this hook should be replaced
User => Users?

> +	 * by setting &drm_gem_object.resv instead.
> +	 */
>  	struct reservation_object * (*gem_prime_res_obj)(
>  				struct drm_gem_object *obj);
> -	struct sg_table *(*gem_prime_get_sg_table)(struct drm_gem_object *obj);
> +
> +	/**
> +	 * @gem_prime_import_sg_table:
> +	 *
> +	 * Optional hook used by the PRIME helper functions
> +	 * drm_gem_prime_import() respectively drm_gem_prime_import_dev().
> +	 */
>  	struct drm_gem_object *(*gem_prime_import_sg_table)(
>  				struct drm_device *dev,
>  				struct dma_buf_attachment *attach,
>  				struct sg_table *sgt);
> +	/**
> +	 * @gem_prime_vmap:
> +	 *
> +	 * Deprecated vmap hook for GEM drivers. Please use
> +	 * &drm_gem_object_funcs.vmap instead.
Or?
	 * Deprecated hook in favour of &drm_gem_object_funcs.vmap.

(Same wording as a few functions up)

> +	 */
>  	void *(*gem_prime_vmap)(struct drm_gem_object *obj);
> +
> +	/**
> +	 * @gem_prime_vunmap:
> +	 *
> +	 * Deprecated vunmap hook for GEM drivers. Please use
> +	 * &drm_gem_object_funcs.vunmap instead.
Or?
Y	 * Deprecated hook in favour of &drm_gem_object_funcs.vunmap.

> +	 */
>  	void (*gem_prime_vunmap)(struct drm_gem_object *obj, void *vaddr);
> +
> +	/**
> +	 * @gem_prime_mmap:
> +	 *
> +	 * mmap hook for GEM drivers, used to implement dma-buf mmap in the
> +	 * PRIME helpers.
> +	 *
> +	 * FIXME: There's way too much duplication going on here, and also moved
> +	 * to &drm_gem_object_funcs.
> +	 */
>  	int (*gem_prime_mmap)(struct drm_gem_object *obj,
>  				struct vm_area_struct *vma);
>  
> @@ -665,6 +738,9 @@ struct drm_driver {
>  
>  	/**
>  	 * @gem_vm_ops: Driver private ops for this object
> +	 *
> +	 * For GEM driver this is deprecated in favour of
> +	 * &drm_gem_object_funcs.vm_ops.
Or?
	 * Deprecated hook in favour of &drm_gem_object_funcs.vm_ops.
>  	 */
>  	const struct vm_operations_struct *gem_vm_ops;
>  

	Sam
Daniel Vetter June 17, 2019, 4:38 p.m. UTC | #2
On Sat, Jun 15, 2019 at 01:41:53PM +0200, Sam Ravnborg wrote:
> Hi Daniel
> 
> Better and more consistent docs - good!
> With relevant comments addressed:
> Reviewed-by: Sam Ravnborg <sam@ravnborg.org>
> 
> > +/**
> > + * DOC: overview and lifetime rules
> > + *
> > + * Similar to GEM global names, PRIME file descriptors are also used to share
> > + * buffer objects across processes. They offer additional security: as file
> > + * descriptors must be explicitly sent over UNIX domain sockets to be shared
> > + * between applications, they can't be guessed like the globally unique GEM
> > + * names.
> For a newbie like me the above does not really help to understand what
> PRIME is.
> Yes, it is file descriptors used to share buffer objects across
> processes.
> But the text say "also used ..", so the main usage of PRIME is something
> else.

No, what's mean here is that prime file descriptors are used like gem
global names, for buffer sharing. That's what the "also" means here.
There's no other use for prime fd than sharing buffers.

Not really clear why this is unclear ...

> But as said, newbie so it may be fine for most readers.
> 
> > + *
> > + * Drivers that support the PRIME API must set the DRIVER_PRIME bit in the
> > + * &drm_driver.driver_features field, and implement the
> > + * &drm_driver.prime_handle_to_fd and &drm_driver.prime_fd_to_handle operations.
> 
> > + * GEM based drivers must use drm_gem_prime_handle_to_fd() an
> > + * drm_gem_prime_fd_to_handle() to implement these.
> an => and in the above.
> 
> > + * drm_gem_prime_fd_to_handle - PRIME import function for GEM drivers
> > + * @dev: dev to export the buffer from
> > + * @file_priv: drm file-private structure
> > + * @prime_fd: fd id of the dma-buf which should be imported
> > + * @handle: pointer to storage for the handle of the imported buffer object
> >   *
> > + * This is the PRIME import function which must be used mandatorily by GEM
> > + * drivers to ensure correct lifetime management of the underlying GEM object.
> > + * The actual importing of GEM object from the dma-buf is done through the
> > + * &drm_driver.gem_import_export driver callback.
> Here maybe add a description of the return result.
> If I read the code correct:
> Returns 0 on success or negative error code on failure.
> 
> >   */
> > -void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf)
> > +int drm_gem_prime_fd_to_handle(struct drm_device *dev,
> > +			       struct drm_file *file_priv, int prime_fd,
> > +			       uint32_t *handle)
> >  {
> > -	struct drm_gem_object *obj = dma_buf->priv;
> > -	void *vaddr;
> > +	struct dma_buf *dma_buf;
> > +	struct drm_gem_object *obj;
> > +	int ret;
> >  
> > -	vaddr = drm_gem_vmap(obj);
> > -	if (IS_ERR(vaddr))
> > -		vaddr = NULL;
> > +	dma_buf = dma_buf_get(prime_fd);
> > +	if (IS_ERR(dma_buf))
> > +		return PTR_ERR(dma_buf);
> >  
> > +	mutex_lock(&file_priv->prime.lock);
> >  
> > +	ret = drm_prime_lookup_buf_handle(&file_priv->prime,
> > +			dma_buf, handle);
> > +	if (ret == 0)
> > +		goto out_put;
> >  
> > +	/* never seen this one, need to import */
> > +	mutex_lock(&dev->object_name_lock);
> > +	if (dev->driver->gem_prime_import)
> > +		obj = dev->driver->gem_prime_import(dev, dma_buf);
> > +	else
> > +		obj = drm_gem_prime_import(dev, dma_buf);
> > +	if (IS_ERR(obj)) {
> > +		ret = PTR_ERR(obj);
> > +		goto out_unlock;
> > +	}
> > +	if (obj->dma_buf) {
> > +		WARN_ON(obj->dma_buf != dma_buf);
> > +	} else {
> > +		obj->dma_buf = dma_buf;
> > +		get_dma_buf(dma_buf);
> > +	}
> >  
> > +	/* _handle_create_tail unconditionally unlocks dev->object_name_lock. */
> > +	ret = drm_gem_handle_create_tail(file_priv, obj, handle);
> > +	drm_gem_object_put_unlocked(obj);
> > +	if (ret)
> > +		goto out_put;
> >  
> > +	ret = drm_prime_add_buf_handle(&file_priv->prime,
> > +			dma_buf, *handle);
> > +	mutex_unlock(&file_priv->prime.lock);
> > +	if (ret)
> > +		goto fail;
> > +	dma_buf_put(dma_buf);
> >  
> > +	return 0;
> >  
> > +fail:
> > +	/* hmm, if driver attached, we are relying on the free-object path
> > +	 * to detach.. which seems ok..
> > +	 */
> > +	drm_gem_handle_delete(file_priv, *handle);
> > +	dma_buf_put(dma_buf);
> > +	return ret;
> > +
> > +out_unlock:
> > +	mutex_unlock(&dev->object_name_lock);
> > +out_put:
> > +	mutex_unlock(&file_priv->prime.lock);
> > +	dma_buf_put(dma_buf);
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL(drm_gem_prime_fd_to_handle);
> > +
> > +
> > +/**
> > + * DOC: PRIME Helpers
> > + *
> > + * Drivers can implement &drm_gem_object_funcs.export and
> > + * &drm_driver.gem_prime_import in terms of simpler APIs by using the helper
> > + * functions drm_gem_prime_export() and drm_gem_prime_import().  These functions
> > + * implement dma-buf support in terms of some lower-level helpers, which are
> > + * again exported for drivers to use individually:
> > + *
> > + * Exporting buffers
> > + * ~~~~~~~~~~~~~~~~~
> > + *
> > + * Optional pinning of buffers is handled at dma-buf attach and detach time in
> > + * drm_gem_map_attach() and drm_gem_map_detach(). Backing storage itself is
> > + * handled by drm_gem_map_dma_buf() and drm_gem_unmap_dma_buf(), which relies on
> > + * &drm_gem_object_funcs.get_sg_table.
> > + *
> > + * For kernel-internal access there's drm_gem_dmabuf_vmap() and
> > + * drm_gem_dmabuf_vunmap(). Userspace mmap support is provided by
> > + * drm_gem_dmabuf_mmap().
> > + *
> > + * Note that these export helpers can only be used if the underlying backing
> > + * storage is fully coherent and either permanently pinned, or it is safe to pin
> > + * it indefinitely.
> > + *
> > + * FIXME: The underlying helper functions are named rather inconsistently.
> > + *
> > + * Exporting buffers
> > + * ~~~~~~~~~~~~~~~~~
> > + *
> > + * Importing dma-bufs using drm_gem_prime_import() relies on
> > + * &drm_driver.gem_prime_import_sg_table.
> > + *
> > + * Note that similarly to the export helpers this permanently pins the
> > + * underlying backing storage. Which is ok for scanout, but is not the best
> > + * option for sharing lots of buffers for rendering.
> > + */
> > +
> > +/**
> > + * drm_gem_map_attach - dma_buf attach implementation for GEM
> > + * @dma_buf: buffer to attach device to
> > + * @attach: buffer attachment data
> > + *
> > + * Calls &drm_gem_object_funcs.pin for device specific handling. This can be
> > + * used as the &dma_buf_ops.attach callback. Must be used together with
> > + * drm_gem_map_detach().
> > + *
> > + * Returns 0 on success, negative error code on failure.
> > + */
> > +int drm_gem_map_attach(struct dma_buf *dma_buf,
> > +		       struct dma_buf_attachment *attach)
> > +{
> > +	struct drm_gem_object *obj = dma_buf->priv;
> > +
> > +	return drm_gem_pin(obj);
> > +}
> > +EXPORT_SYMBOL(drm_gem_map_attach);
> > +
> > +/**
> > + * drm_gem_map_detach - dma_buf detach implementation for GEM
> > + * @dma_buf: buffer to detach from
> > + * @attach: attachment to be detached
> > + *
> > + * Calls &drm_gem_object_funcs.pin for device specific handling.  Cleans up
> > + * &dma_buf_attachment from drm_gem_map_attach(). This can be used as the
> > + * &dma_buf_ops.detach callback.
> > + */
> > +void drm_gem_map_detach(struct dma_buf *dma_buf,
> > +			struct dma_buf_attachment *attach)
> > +{
> > +	struct drm_gem_object *obj = dma_buf->priv;
> > +
> > +	drm_gem_unpin(obj);
> > +}
> > +EXPORT_SYMBOL(drm_gem_map_detach);
> > +
> > +/**
> > + * drm_gem_map_dma_buf - map_dma_buf implementation for GEM
> > + * @attach: attachment whose scatterlist is to be returned
> > + * @dir: direction of DMA transfer
> > + *
> > + * Calls &drm_gem_object_funcs.get_sg_table and then maps the scatterlist. This
> > + * can be used as the &dma_buf_ops.map_dma_buf callback. Should be used together
> > + * with drm_gem_unmap_dma_buf().
> > + *
> > + * Returns:sg_table containing the scatterlist to be returned; returns ERR_PTR
> > + * on error. May return -EINTR if it is interrupted by a signal.
> > + */
> Nit - add space after ':'
> 
> > +
> > +/**
> > + * drm_gem_dmabuf_vmap - dma_buf vmap implementation for GEM
> > + * @dma_buf: buffer to be mapped
> > + *
> > + * Sets up a kernel virtual mapping. This can be used as the &dma_buf_ops.vmap
> > + * callback. Calls into &drm_gem_object_funcs.vmap for device specific handling.
> > + *
> > + * Returns the kernel virtual address.
> or NULL if failed to setup virtual mapping.
> 
> > + */
> > +void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf)
> > +{
> > +	struct drm_gem_object *obj = dma_buf->priv;
> > +	void *vaddr;
> > +
> > +	vaddr = drm_gem_vmap(obj);
> > +	if (IS_ERR(vaddr))
> > +		vaddr = NULL;
> > +
> > +	return vaddr;
> > +}
> > +EXPORT_SYMBOL(drm_gem_dmabuf_vmap);
> 
> 
> >  /**
> >   * drm_gem_prime_import_dev - core implementation of the import callback
> >   * @dev: drm_device to import into
> >   * @dma_buf: dma-buf object to import
> >   * @attach_dev: struct device to dma_buf attach
> >   *
> > - * This is the core of drm_gem_prime_import. It's designed to be called by
> > - * drivers who want to use a different device structure than dev->dev for
> > - * attaching via dma_buf.
> > + * This is the core of drm_gem_prime_import(). It's designed to be called by
> > + * drivers who want to use a different device structure than &drm_device.dev for
> > + * attaching via dma_buf. This function calls
> > + * &drm_driver.gem_prime_import_sg_table internally.
> > + *
> > + * Drivers must arrange to call drm_prime_gem_destroy() from their
> > + * &drm_gem_object_funcs.free hook when using this function.
> >   */
> >  struct drm_gem_object *drm_gem_prime_import_dev(struct drm_device *dev,
> >  					    struct dma_buf *dma_buf,
> > @@ -728,7 +923,11 @@ EXPORT_SYMBOL(drm_gem_prime_import_dev);
> >   * @dma_buf: dma-buf object to import
> >   *
> >   * This is the implementation of the gem_prime_import functions for GEM drivers
> > - * using the PRIME helpers.
> > + * using the PRIME helpers. Drivers can use this as their
> > + * &drm_driver.gem_prime_import implementation.
> > + *
> > + * Drivers must arrange to call drm_prime_gem_destroy() from their
> > + * &drm_gem_object_funcs.free hook when using this function.
> 
> Could we here document what function we provide as the default
> &drm_gem_object_funcs.free hook, which do the drm_prime_gem_destroy()
> call.
> I read the above that drivers have to provide their own implementation
> of a .free hook, and I do not think this is right.

There's no default implementation of the free hook at all, so not sure
what you mean. You do kinda have to provide a free hook, otherwise your
driver will leak badly.

> > +++ b/include/drm/drm_drv.h
> > @@ -505,21 +505,25 @@ struct drm_driver {
> >  	 * @gem_free_object: deconstructor for drm_gem_objects
> >  	 *
> >  	 * This is deprecated and should not be used by new drivers. Use
> > -	 * @gem_free_object_unlocked instead.
> > +	 * &drm_gem_object_funcs.free instead.
> >  	 */
> >  	void (*gem_free_object) (struct drm_gem_object *obj);
> >  
> >  	/**
> >  	 * @gem_free_object_unlocked: deconstructor for drm_gem_objects
> >  	 *
> > -	 * This is for drivers which are not encumbered with &drm_device.struct_mutex
> > -	 * legacy locking schemes. Use this hook instead of @gem_free_object.
> > +	 * This is deprecated and should not be used by new drivers. Use
> > +	 * &drm_gem_object_funcs.free instead.
> > +	 * Compared to @gem_free_object this is not encumbered with
> > +	 * &drm_device.struct_mutex legacy locking schemes.
> >  	 */
> It is confusing why the above comment refer to another callback.
> Is this the right wording?
> 	* Compared to @gem_free_object_unlocked this is not encumbered with
> 	* &drm_device.struct_mutex legacy locking schemes.
> 
> Do gem_free_object() warrant a similar comment?

I'm confused ... @gem_free_object is exactly the callback I want to refer
to. Because that one _is_ encumbered with the legacy struct_mutex locking
scheme. Unlike the .free callback, or the gem_free_object_unlocked
callback.

> > @@ -548,56 +557,120 @@ struct drm_driver {
> >  	/**
> >  	 * @gem_create_object: constructor for gem objects
> >  	 *
> > -	 * Hook for allocating the GEM object struct, for use by core
> > -	 * helpers.
> > +	 * Hook for allocating the GEM object struct, for use by the CMA and
> > +	 * SHMEM GEM helpers.
> >  	 */
> >  	struct drm_gem_object *(*gem_create_object)(struct drm_device *dev,
> >  						    size_t size);
> Nit: In some places we do:
> 	int (foo) (int bar);
> other:
> 	int (foo)(int bar);
> 
> No preference here, but it hurts my OCD a little that it is
> inconsistent.

I guess we could try to ocd fix that, but separate patch.

> 
> > -
> > -	/* prime: */
> >  	/**
> >  	 * @prime_handle_to_fd:
> >  	 *
> > -	 * export handle -> fd (see drm_gem_prime_handle_to_fd() helper)
> > +	 * Main PRIME export function. Should be implented with
> s/implented/implemented/
> 
> > +	 * drm_gem_prime_handle_to_fd() for GEM based drivers.
> > +	 *
> > +	 * For an in-depth discussion see :ref:`PRIME buffer sharing
> > +	 * documentation <prime_buffer_sharing>`.
> >  	 */
> >  	int (*prime_handle_to_fd)(struct drm_device *dev, struct drm_file *file_priv,
> >  				uint32_t handle, uint32_t flags, int *prime_fd);
> >  	/**
> >  	 * @prime_fd_to_handle:
> >  	 *
> > -	 * import fd -> handle (see drm_gem_prime_fd_to_handle() helper)
> > +	 * Main PRIME import function. Should be implented with
> s/implented/implemented/
> 
> > +	 * drm_gem_prime_fd_to_handle() for GEM based drivers.
> > +	 *
> > +	 * For an in-depth discussion see :ref:`PRIME buffer sharing
> > +	 * documentation <prime_buffer_sharing>`.
> >  	 */
> >  	int (*prime_fd_to_handle)(struct drm_device *dev, struct drm_file *file_priv,
> >  				int prime_fd, uint32_t *handle);
> >  	/**
> >  	 * @gem_prime_export:
> >  	 *
> > -	 * export GEM -> dmabuf
> > -	 *
> > -	 * This defaults to drm_gem_prime_export() if not set.
> > +	 * Export hook for GEM drivers. Deprecated in favour of
> > +	 * &drm_gem_object_funcs.export.
> >  	 */
> >  	struct dma_buf * (*gem_prime_export)(struct drm_device *dev,
> >  				struct drm_gem_object *obj, int flags);
> >  	/**
> >  	 * @gem_prime_import:
> >  	 *
> > -	 * import dmabuf -> GEM
> > +	 * Import hook for GEM drivers.
> >  	 *
> >  	 * This defaults to drm_gem_prime_import() if not set.
> >  	 */
> >  	struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev,
> >  				struct dma_buf *dma_buf);
> > +
> > +	/**
> > +	 * @gem_prime_pin:
> > +	 *
> > +	 * Deprecated hook in favour of &drm_gem_object_funcs.pin.
> > +	 */
> >  	int (*gem_prime_pin)(struct drm_gem_object *obj);
> > +
> > +	/**
> > +	 * @gem_prime_unpin:
> > +	 *
> > +	 * Deprecated hook in favour of &drm_gem_object_funcs.unpin.
> > +	 */
> >  	void (*gem_prime_unpin)(struct drm_gem_object *obj);
> > +
> > +
> > +	/**
> > +	 * @gem_prime_get_sg_table:
> > +	 *
> > +	 * Deprecated hook in favour of &drm_gem_object_funcs.get_sg_table.
> > +	 */
> > +	struct sg_table *(*gem_prime_get_sg_table)(struct drm_gem_object *obj);
> > +
> > +	/**
> > +	 * @gem_prime_res_obj:
> > +	 *
> > +	 * Optional hook to look up the &reservation_object for an buffer when
> > +	 * exporting it.
> > +	 *
> > +	 * FIXME: This hook is deprecated. User of this hook should be replaced
> User => Users?
> 
> > +	 * by setting &drm_gem_object.resv instead.
> > +	 */
> >  	struct reservation_object * (*gem_prime_res_obj)(
> >  				struct drm_gem_object *obj);
> > -	struct sg_table *(*gem_prime_get_sg_table)(struct drm_gem_object *obj);
> > +
> > +	/**
> > +	 * @gem_prime_import_sg_table:
> > +	 *
> > +	 * Optional hook used by the PRIME helper functions
> > +	 * drm_gem_prime_import() respectively drm_gem_prime_import_dev().
> > +	 */
> >  	struct drm_gem_object *(*gem_prime_import_sg_table)(
> >  				struct drm_device *dev,
> >  				struct dma_buf_attachment *attach,
> >  				struct sg_table *sgt);
> > +	/**
> > +	 * @gem_prime_vmap:
> > +	 *
> > +	 * Deprecated vmap hook for GEM drivers. Please use
> > +	 * &drm_gem_object_funcs.vmap instead.
> Or?
> 	 * Deprecated hook in favour of &drm_gem_object_funcs.vmap.
> 
> (Same wording as a few functions up)

Hm we're not super consistent with these deprecation notices even in
existing kerneldoc. Maybe something for a separate patch.

> 
> > +	 */
> >  	void *(*gem_prime_vmap)(struct drm_gem_object *obj);
> > +
> > +	/**
> > +	 * @gem_prime_vunmap:
> > +	 *
> > +	 * Deprecated vunmap hook for GEM drivers. Please use
> > +	 * &drm_gem_object_funcs.vunmap instead.
> Or?
> Y	 * Deprecated hook in favour of &drm_gem_object_funcs.vunmap.
> 
> > +	 */
> >  	void (*gem_prime_vunmap)(struct drm_gem_object *obj, void *vaddr);
> > +
> > +	/**
> > +	 * @gem_prime_mmap:
> > +	 *
> > +	 * mmap hook for GEM drivers, used to implement dma-buf mmap in the
> > +	 * PRIME helpers.
> > +	 *
> > +	 * FIXME: There's way too much duplication going on here, and also moved
> > +	 * to &drm_gem_object_funcs.
> > +	 */
> >  	int (*gem_prime_mmap)(struct drm_gem_object *obj,
> >  				struct vm_area_struct *vma);
> >  
> > @@ -665,6 +738,9 @@ struct drm_driver {
> >  
> >  	/**
> >  	 * @gem_vm_ops: Driver private ops for this object
> > +	 *
> > +	 * For GEM driver this is deprecated in favour of
> > +	 * &drm_gem_object_funcs.vm_ops.
> Or?
> 	 * Deprecated hook in favour of &drm_gem_object_funcs.vm_ops.
> >  	 */
> >  	const struct vm_operations_struct *gem_vm_ops;
> >  

I've taken in all your other suggestions, thanks for taking a look.
-Daniel
Sam Ravnborg June 17, 2019, 5:01 p.m. UTC | #3
Hi Daniel.

> > > +/**
> > > + * DOC: overview and lifetime rules
> > > + *
> > > + * Similar to GEM global names, PRIME file descriptors are also used to share
> > > + * buffer objects across processes. They offer additional security: as file
> > > + * descriptors must be explicitly sent over UNIX domain sockets to be shared
> > > + * between applications, they can't be guessed like the globally unique GEM
> > > + * names.
> > For a newbie like me the above does not really help to understand what
> > PRIME is.
> > Yes, it is file descriptors used to share buffer objects across
> > processes.
> > But the text say "also used ..", so the main usage of PRIME is something
> > else.
> 
> No, what's mean here is that prime file descriptors are used like gem
> global names, for buffer sharing. That's what the "also" means here.
> There's no other use for prime fd than sharing buffers.
> 
> Not really clear why this is unclear ...
Re-reading it, things makes a bit more sense to me now.
When I wrote my comment I somehow read it:
"PRIME file descriptors are also used to share ..."
(Notice that I missed the first part).


> > > @@ -728,7 +923,11 @@ EXPORT_SYMBOL(drm_gem_prime_import_dev);
> > >   * @dma_buf: dma-buf object to import
> > >   *
> > >   * This is the implementation of the gem_prime_import functions for GEM drivers
> > > - * using the PRIME helpers.
> > > + * using the PRIME helpers. Drivers can use this as their
> > > + * &drm_driver.gem_prime_import implementation.
> > > + *
> > > + * Drivers must arrange to call drm_prime_gem_destroy() from their
> > > + * &drm_gem_object_funcs.free hook when using this function.
> > 
> > Could we here document what function we provide as the default
> > &drm_gem_object_funcs.free hook, which do the drm_prime_gem_destroy()
> > call.
> > I read the above that drivers have to provide their own implementation
> > of a .free hook, and I do not think this is right.
> 
> There's no default implementation of the free hook at all, so not sure
> what you mean.
I had expected there was a default implementation.
As there is no such thing my comment it irrelevant.

> > >  	/**
> > >  	 * @gem_free_object_unlocked: deconstructor for drm_gem_objects
> > >  	 *
> > > -	 * This is for drivers which are not encumbered with &drm_device.struct_mutex
> > > -	 * legacy locking schemes. Use this hook instead of @gem_free_object.
> > > +	 * This is deprecated and should not be used by new drivers. Use
> > > +	 * &drm_gem_object_funcs.free instead.
> > > +	 * Compared to @gem_free_object this is not encumbered with
> > > +	 * &drm_device.struct_mutex legacy locking schemes.
> > >  	 */
> > It is confusing why the above comment refer to another callback.
> > Is this the right wording?
> > 	* Compared to @gem_free_object_unlocked this is not encumbered with
> > 	* &drm_device.struct_mutex legacy locking schemes.
> > 
> > Do gem_free_object() warrant a similar comment?
> 
> I'm confused ... @gem_free_object is exactly the callback I want to refer
> to. Because that one _is_ encumbered with the legacy struct_mutex locking
> scheme. Unlike the .free callback, or the gem_free_object_unlocked
> callback.
I see now, OK.

Thanks for the clarifications.

	Sam
Emil Velikov June 17, 2019, 5:47 p.m. UTC | #4
On 2019/06/14, Daniel Vetter wrote:
> Yes this is a bit a big patch, but since it's essentially a complete
> rewrite of all the prime docs I didn't see how to better split it up.
> 
> Changes:
> - Consistently point to drm_gem_object_funcs as the preferred hooks,
>   where applicable.
> 
> - Reorder all the functions in drm_prime.[hc] into three groups: core,
>   export helpers, import helpers.
> 
> - Document all the hooks in &drm_driver that lacked kerneldoc.
> 
> - Completely new overview section, which now also includes the cleaned
>   up lifetime/reference counting subchapter. I also mentioned the weak
>   references in there due to the lookup caches.
> 
> - Completely rewritten helper intro section, highlight the
>   import/export related functionality.
> 
> - Polish for all the functions and more cross references.
> 
> I also sprinkled a bunch of todos all over.
> 
> Most important: 0 code changes in here. The cleanup motivated by
> reading and improving all this will follow later on.
> 
> v2: Actually update the prime helper docs. Plus add a few FIXMEs that
> I won't address right away in subsequent cleanup patches.
> 
> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
> ---
>  Documentation/gpu/drm-mm.rst |  40 +-
>  drivers/gpu/drm/drm_prime.c  | 851 ++++++++++++++++++-----------------
>  include/drm/drm_drv.h        | 104 ++++-
>  include/drm/drm_gem.h        |  18 +-
>  include/drm/drm_prime.h      |  42 +-
>  5 files changed, 576 insertions(+), 479 deletions(-)
> 
Resuffle is ok. Currently the commit summary says "comments" and we have
851 +/- for a ~960 loc file - not the example we want to set for others.

Can we get this into more managable hunks?

-Emil

Patch
diff mbox series

diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst
index c8ebd4f66a6a..b664f054c259 100644
--- a/Documentation/gpu/drm-mm.rst
+++ b/Documentation/gpu/drm-mm.rst
@@ -433,43 +433,11 @@  PRIME is the cross device buffer sharing framework in drm, originally
 created for the OPTIMUS range of multi-gpu platforms. To userspace PRIME
 buffers are dma-buf based file descriptors.
 
-Overview and Driver Interface
------------------------------
+Overview and Lifetime Rules
+---------------------------
 
-Similar to GEM global names, PRIME file descriptors are also used to
-share buffer objects across processes. They offer additional security:
-as file descriptors must be explicitly sent over UNIX domain sockets to
-be shared between applications, they can't be guessed like the globally
-unique GEM names.
-
-Drivers that support the PRIME API must set the DRIVER_PRIME bit in the
-struct :c:type:`struct drm_driver <drm_driver>`
-driver_features field, and implement the prime_handle_to_fd and
-prime_fd_to_handle operations.
-
-int (\*prime_handle_to_fd)(struct drm_device \*dev, struct drm_file
-\*file_priv, uint32_t handle, uint32_t flags, int \*prime_fd); int
-(\*prime_fd_to_handle)(struct drm_device \*dev, struct drm_file
-\*file_priv, int prime_fd, uint32_t \*handle); Those two operations
-convert a handle to a PRIME file descriptor and vice versa. Drivers must
-use the kernel dma-buf buffer sharing framework to manage the PRIME file
-descriptors. Similar to the mode setting API PRIME is agnostic to the
-underlying buffer object manager, as long as handles are 32bit unsigned
-integers.
-
-While non-GEM drivers must implement the operations themselves, GEM
-drivers must use the :c:func:`drm_gem_prime_handle_to_fd()` and
-:c:func:`drm_gem_prime_fd_to_handle()` helper functions. Those
-helpers rely on the driver gem_prime_export and gem_prime_import
-operations to create a dma-buf instance from a GEM object (dma-buf
-exporter role) and to create a GEM object from a dma-buf instance
-(dma-buf importer role).
-
-struct dma_buf \* (\*gem_prime_export)(struct drm_device \*dev,
-struct drm_gem_object \*obj, int flags); struct drm_gem_object \*
-(\*gem_prime_import)(struct drm_device \*dev, struct dma_buf
-\*dma_buf); These two operations are mandatory for GEM drivers that
-support PRIME.
+.. kernel-doc:: drivers/gpu/drm/drm_prime.c
+   :doc: overview and lifetime rules
 
 PRIME Helper Functions
 ----------------------
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index d0c01318076b..f08159a8b03a 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -38,47 +38,53 @@ 
 
 #include "drm_internal.h"
 
-/*
- * DMA-BUF/GEM Object references and lifetime overview:
- *
- * On the export the dma_buf holds a reference to the exporting GEM
- * object. It takes this reference in handle_to_fd_ioctl, when it
- * first calls .prime_export and stores the exporting GEM object in
- * the dma_buf priv. This reference needs to be released when the
- * final reference to the &dma_buf itself is dropped and its
- * &dma_buf_ops.release function is called. For GEM-based drivers,
- * the dma_buf should be exported using drm_gem_dmabuf_export() and
- * then released by drm_gem_dmabuf_release().
- *
- * On the import the importing GEM object holds a reference to the
- * dma_buf (which in turn holds a ref to the exporting GEM object).
- * It takes that reference in the fd_to_handle ioctl.
- * It calls dma_buf_get, creates an attachment to it and stores the
- * attachment in the GEM object. When this attachment is destroyed
- * when the imported object is destroyed, we remove the attachment
- * and drop the reference to the dma_buf.
- *
- * When all the references to the &dma_buf are dropped, i.e. when
- * userspace has closed both handles to the imported GEM object (through the
- * FD_TO_HANDLE IOCTL) and closed the file descriptor of the exported
- * (through the HANDLE_TO_FD IOCTL) dma_buf, and all kernel-internal references
- * are also gone, then the dma_buf gets destroyed.  This can also happen as a
- * part of the clean up procedure in the drm_release() function if userspace
- * fails to properly clean up.  Note that both the kernel and userspace (by
- * keeeping the PRIME file descriptors open) can hold references onto a
- * &dma_buf.
- *
- * Thus the chain of references always flows in one direction
- * (avoiding loops): importing_gem -> dmabuf -> exporting_gem
- *
- * Self-importing: if userspace is using PRIME as a replacement for flink
- * then it will get a fd->handle request for a GEM object that it created.
- * Drivers should detect this situation and return back the gem object
- * from the dma-buf private.  Prime will do this automatically for drivers that
- * use the drm_gem_prime_{import,export} helpers.
- *
- * GEM struct &dma_buf_ops symbols are now exported. They can be resued by
- * drivers which implement GEM interface.
+/**
+ * DOC: overview and lifetime rules
+ *
+ * Similar to GEM global names, PRIME file descriptors are also used to share
+ * buffer objects across processes. They offer additional security: as file
+ * descriptors must be explicitly sent over UNIX domain sockets to be shared
+ * between applications, they can't be guessed like the globally unique GEM
+ * names.
+ *
+ * Drivers that support the PRIME API must set the DRIVER_PRIME bit in the
+ * &drm_driver.driver_features field, and implement the
+ * &drm_driver.prime_handle_to_fd and &drm_driver.prime_fd_to_handle operations.
+ * GEM based drivers must use drm_gem_prime_handle_to_fd() an
+ * drm_gem_prime_fd_to_handle() to implement these. For GEM based drivers the
+ * actual driver interfaces is provided through the &drm_gem_object_funcs.export
+ * and &drm_driver.gem_prime_import hooks.
+ *
+ * &dma_buf_ops implementations for GEM drivers are all individually exported
+ * for drivers which need to overwrite or reimplement some of them.
+ *
+ * Reference Counting for GEM Drivers
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * On the export the &dma_buf holds a reference to the exported buffer object,
+ * usually a &drm_gem_object. It takes this reference in the PRIME_HANDLE_TO_FD
+ * IOCTL, when it first calls &drm_gem_object_funcs.export
+ * and stores the exporting GEM object in the &dma_buf.priv field. This
+ * reference needs to be released when the final reference to the &dma_buf
+ * itself is dropped and its &dma_buf_ops.release function is called.  For
+ * GEM-based drivers, the &dma_buf should be exported using
+ * drm_gem_dmabuf_export() and then released by drm_gem_dmabuf_release().
+ *
+ * Thus the chain of references always flows in one direction, avoiding loops:
+ * importing GEM object -> dma-buf -> exported GEM bo. A further complication
+ * are the lookup caches for import and export. These are required to guarantee
+ * that any given object will always have only one uniqe userspace handle. This
+ * is required to allow userspace to detect duplicated imports, since some GEM
+ * drivers do fail command submissions if a given buffer object is listed more
+ * than once. These import and export caches in &drm_prime_file_private only
+ * retain a weak reference, which is cleaned up when the corresponding object is
+ * released.
+ *
+ * Self-importing: If userspace is using PRIME as a replacement for flink then
+ * it will get a fd->handle request for a GEM object that it created.  Drivers
+ * should detect this situation and return back the underlying object from the
+ * dma-buf private. For GEM based drivers this is handled in
+ * drm_gem_prime_import() already.
  */
 
 struct drm_prime_member {
@@ -181,42 +187,6 @@  static int drm_prime_lookup_buf_handle(struct drm_prime_file_private *prime_fpri
 	return -ENOENT;
 }
 
-/**
- * drm_gem_map_attach - dma_buf attach implementation for GEM
- * @dma_buf: buffer to attach device to
- * @attach: buffer attachment data
- *
- * Calls &drm_driver.gem_prime_pin for device specific handling. This can be
- * used as the &dma_buf_ops.attach callback.
- *
- * Returns 0 on success, negative error code on failure.
- */
-int drm_gem_map_attach(struct dma_buf *dma_buf,
-		       struct dma_buf_attachment *attach)
-{
-	struct drm_gem_object *obj = dma_buf->priv;
-
-	return drm_gem_pin(obj);
-}
-EXPORT_SYMBOL(drm_gem_map_attach);
-
-/**
- * drm_gem_map_detach - dma_buf detach implementation for GEM
- * @dma_buf: buffer to detach from
- * @attach: attachment to be detached
- *
- * Cleans up &dma_buf_attachment. This can be used as the &dma_buf_ops.detach
- * callback.
- */
-void drm_gem_map_detach(struct dma_buf *dma_buf,
-			struct dma_buf_attachment *attach)
-{
-	struct drm_gem_object *obj = dma_buf->priv;
-
-	drm_gem_unpin(obj);
-}
-EXPORT_SYMBOL(drm_gem_map_detach);
-
 void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpriv,
 					struct dma_buf *dma_buf)
 {
@@ -242,67 +212,21 @@  void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpr
 	}
 }
 
-/**
- * drm_gem_map_dma_buf - map_dma_buf implementation for GEM
- * @attach: attachment whose scatterlist is to be returned
- * @dir: direction of DMA transfer
- *
- * Calls &drm_driver.gem_prime_get_sg_table and then maps the scatterlist. This
- * can be used as the &dma_buf_ops.map_dma_buf callback.
- *
- * Returns sg_table containing the scatterlist to be returned; returns ERR_PTR
- * on error. May return -EINTR if it is interrupted by a signal.
- */
-
-struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach,
-				     enum dma_data_direction dir)
+void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv)
 {
-	struct drm_gem_object *obj = attach->dmabuf->priv;
-	struct sg_table *sgt;
-
-	if (WARN_ON(dir == DMA_NONE))
-		return ERR_PTR(-EINVAL);
-
-	if (obj->funcs)
-		sgt = obj->funcs->get_sg_table(obj);
-	else
-		sgt = obj->dev->driver->gem_prime_get_sg_table(obj);
-
-	if (!dma_map_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir,
-			      DMA_ATTR_SKIP_CPU_SYNC)) {
-		sg_free_table(sgt);
-		kfree(sgt);
-		sgt = ERR_PTR(-ENOMEM);
-	}
-
-	return sgt;
+	mutex_init(&prime_fpriv->lock);
+	prime_fpriv->dmabufs = RB_ROOT;
+	prime_fpriv->handles = RB_ROOT;
 }
-EXPORT_SYMBOL(drm_gem_map_dma_buf);
 
-/**
- * drm_gem_unmap_dma_buf - unmap_dma_buf implementation for GEM
- * @attach: attachment to unmap buffer from
- * @sgt: scatterlist info of the buffer to unmap
- * @dir: direction of DMA transfer
- *
- * This can be used as the &dma_buf_ops.unmap_dma_buf callback.
- */
-void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach,
-			   struct sg_table *sgt,
-			   enum dma_data_direction dir)
+void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv)
 {
-	if (!sgt)
-		return;
-
-	dma_unmap_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir,
-			   DMA_ATTR_SKIP_CPU_SYNC);
-	sg_free_table(sgt);
-	kfree(sgt);
+	/* by now drm_gem_release should've made sure the list is empty */
+	WARN_ON(!RB_EMPTY_ROOT(&prime_fpriv->dmabufs));
 }
-EXPORT_SYMBOL(drm_gem_unmap_dma_buf);
 
 /**
- * drm_gem_dmabuf_export - dma_buf export implementation for GEM
+ * drm_gem_dmabuf_export - &dma_buf export implementation for GEM
  * @dev: parent device for the exported dmabuf
  * @exp_info: the export information used by dma_buf_export()
  *
@@ -330,11 +254,11 @@  struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev,
 EXPORT_SYMBOL(drm_gem_dmabuf_export);
 
 /**
- * drm_gem_dmabuf_release - dma_buf release implementation for GEM
+ * drm_gem_dmabuf_release - &dma_buf release implementation for GEM
  * @dma_buf: buffer to be released
  *
  * Generic release function for dma_bufs exported as PRIME buffers. GEM drivers
- * must use this in their dma_buf ops structure as the release callback.
+ * must use this in their &dma_buf_ops structure as the release callback.
  * drm_gem_dmabuf_release() should be used in conjunction with
  * drm_gem_dmabuf_export().
  */
@@ -351,128 +275,101 @@  void drm_gem_dmabuf_release(struct dma_buf *dma_buf)
 EXPORT_SYMBOL(drm_gem_dmabuf_release);
 
 /**
- * drm_gem_dmabuf_vmap - dma_buf vmap implementation for GEM
- * @dma_buf: buffer to be mapped
- *
- * Sets up a kernel virtual mapping. This can be used as the &dma_buf_ops.vmap
- * callback.
+ * drm_gem_prime_fd_to_handle - PRIME import function for GEM drivers
+ * @dev: dev to export the buffer from
+ * @file_priv: drm file-private structure
+ * @prime_fd: fd id of the dma-buf which should be imported
+ * @handle: pointer to storage for the handle of the imported buffer object
  *
- * Returns the kernel virtual address.
+ * This is the PRIME import function which must be used mandatorily by GEM
+ * drivers to ensure correct lifetime management of the underlying GEM object.
+ * The actual importing of GEM object from the dma-buf is done through the
+ * &drm_driver.gem_import_export driver callback.
  */
-void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf)
+int drm_gem_prime_fd_to_handle(struct drm_device *dev,
+			       struct drm_file *file_priv, int prime_fd,
+			       uint32_t *handle)
 {
-	struct drm_gem_object *obj = dma_buf->priv;
-	void *vaddr;
+	struct dma_buf *dma_buf;
+	struct drm_gem_object *obj;
+	int ret;
 
-	vaddr = drm_gem_vmap(obj);
-	if (IS_ERR(vaddr))
-		vaddr = NULL;
+	dma_buf = dma_buf_get(prime_fd);
+	if (IS_ERR(dma_buf))
+		return PTR_ERR(dma_buf);
 
-	return vaddr;
-}
-EXPORT_SYMBOL(drm_gem_dmabuf_vmap);
+	mutex_lock(&file_priv->prime.lock);
 
-/**
- * drm_gem_dmabuf_vunmap - dma_buf vunmap implementation for GEM
- * @dma_buf: buffer to be unmapped
- * @vaddr: the virtual address of the buffer
- *
- * Releases a kernel virtual mapping. This can be used as the
- * &dma_buf_ops.vunmap callback.
- */
-void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr)
-{
-	struct drm_gem_object *obj = dma_buf->priv;
+	ret = drm_prime_lookup_buf_handle(&file_priv->prime,
+			dma_buf, handle);
+	if (ret == 0)
+		goto out_put;
 
-	drm_gem_vunmap(obj, vaddr);
-}
-EXPORT_SYMBOL(drm_gem_dmabuf_vunmap);
+	/* never seen this one, need to import */
+	mutex_lock(&dev->object_name_lock);
+	if (dev->driver->gem_prime_import)
+		obj = dev->driver->gem_prime_import(dev, dma_buf);
+	else
+		obj = drm_gem_prime_import(dev, dma_buf);
+	if (IS_ERR(obj)) {
+		ret = PTR_ERR(obj);
+		goto out_unlock;
+	}
 
-/**
- * drm_gem_dmabuf_mmap - dma_buf mmap implementation for GEM
- * @dma_buf: buffer to be mapped
- * @vma: virtual address range
- *
- * Provides memory mapping for the buffer. This can be used as the
- * &dma_buf_ops.mmap callback.
- *
- * Returns 0 on success or a negative error code on failure.
- */
-int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma)
-{
-	struct drm_gem_object *obj = dma_buf->priv;
-	struct drm_device *dev = obj->dev;
+	if (obj->dma_buf) {
+		WARN_ON(obj->dma_buf != dma_buf);
+	} else {
+		obj->dma_buf = dma_buf;
+		get_dma_buf(dma_buf);
+	}
 
-	if (!dev->driver->gem_prime_mmap)
-		return -ENOSYS;
+	/* _handle_create_tail unconditionally unlocks dev->object_name_lock. */
+	ret = drm_gem_handle_create_tail(file_priv, obj, handle);
+	drm_gem_object_put_unlocked(obj);
+	if (ret)
+		goto out_put;
 
-	return dev->driver->gem_prime_mmap(obj, vma);
-}
-EXPORT_SYMBOL(drm_gem_dmabuf_mmap);
+	ret = drm_prime_add_buf_handle(&file_priv->prime,
+			dma_buf, *handle);
+	mutex_unlock(&file_priv->prime.lock);
+	if (ret)
+		goto fail;
 
-static const struct dma_buf_ops drm_gem_prime_dmabuf_ops =  {
-	.cache_sgt_mapping = true,
-	.attach = drm_gem_map_attach,
-	.detach = drm_gem_map_detach,
-	.map_dma_buf = drm_gem_map_dma_buf,
-	.unmap_dma_buf = drm_gem_unmap_dma_buf,
-	.release = drm_gem_dmabuf_release,
-	.mmap = drm_gem_dmabuf_mmap,
-	.vmap = drm_gem_dmabuf_vmap,
-	.vunmap = drm_gem_dmabuf_vunmap,
-};
+	dma_buf_put(dma_buf);
 
-/**
- * DOC: PRIME Helpers
- *
- * Drivers can implement @gem_prime_export and @gem_prime_import in terms of
- * simpler APIs by using the helper functions @drm_gem_prime_export and
- * @drm_gem_prime_import.  These functions implement dma-buf support in terms of
- * six lower-level driver callbacks:
- *
- * Export callbacks:
- *
- *  * @gem_prime_pin (optional): prepare a GEM object for exporting
- *  * @gem_prime_get_sg_table: provide a scatter/gather table of pinned pages
- *  * @gem_prime_vmap: vmap a buffer exported by your driver
- *  * @gem_prime_vunmap: vunmap a buffer exported by your driver
- *  * @gem_prime_mmap (optional): mmap a buffer exported by your driver
- *
- * Import callback:
- *
- *  * @gem_prime_import_sg_table (import): produce a GEM object from another
- *    driver's scatter/gather table
- */
+	return 0;
 
-/**
- * drm_gem_prime_export - helper library implementation of the export callback
- * @dev: drm_device to export from
- * @obj: GEM object to export
- * @flags: flags like DRM_CLOEXEC and DRM_RDWR
- *
- * This is the implementation of the gem_prime_export functions for GEM drivers
- * using the PRIME helpers.
- */
-struct dma_buf *drm_gem_prime_export(struct drm_device *dev,
-				     struct drm_gem_object *obj,
-				     int flags)
+fail:
+	/* hmm, if driver attached, we are relying on the free-object path
+	 * to detach.. which seems ok..
+	 */
+	drm_gem_handle_delete(file_priv, *handle);
+	dma_buf_put(dma_buf);
+	return ret;
+
+out_unlock:
+	mutex_unlock(&dev->object_name_lock);
+out_put:
+	mutex_unlock(&file_priv->prime.lock);
+	dma_buf_put(dma_buf);
+	return ret;
+}
+EXPORT_SYMBOL(drm_gem_prime_fd_to_handle);
+
+int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data,
+				 struct drm_file *file_priv)
 {
-	struct dma_buf_export_info exp_info = {
-		.exp_name = KBUILD_MODNAME, /* white lie for debug */
-		.owner = dev->driver->fops->owner,
-		.ops = &drm_gem_prime_dmabuf_ops,
-		.size = obj->size,
-		.flags = flags,
-		.priv = obj,
-		.resv = obj->resv,
-	};
+	struct drm_prime_handle *args = data;
 
-	if (dev->driver->gem_prime_res_obj)
-		exp_info.resv = dev->driver->gem_prime_res_obj(obj);
+	if (!drm_core_check_feature(dev, DRIVER_PRIME))
+		return -EOPNOTSUPP;
 
-	return drm_gem_dmabuf_export(dev, &exp_info);
+	if (!dev->driver->prime_fd_to_handle)
+		return -ENOSYS;
+
+	return dev->driver->prime_fd_to_handle(dev, file_priv,
+			args->fd, &args->handle);
 }
-EXPORT_SYMBOL(drm_gem_prime_export);
 
 static struct dma_buf *export_and_register_object(struct drm_device *dev,
 						  struct drm_gem_object *obj,
@@ -521,7 +418,7 @@  static struct dma_buf *export_and_register_object(struct drm_device *dev,
  * This is the PRIME export function which must be used mandatorily by GEM
  * drivers to ensure correct lifetime management of the underlying GEM object.
  * The actual exporting from GEM object to a dma-buf is done through the
- * gem_prime_export driver callback.
+ * &drm_driver.gem_prime_export driver callback.
  */
 int drm_gem_prime_handle_to_fd(struct drm_device *dev,
 			       struct drm_file *file_priv, uint32_t handle,
@@ -610,6 +507,198 @@  int drm_gem_prime_handle_to_fd(struct drm_device *dev,
 }
 EXPORT_SYMBOL(drm_gem_prime_handle_to_fd);
 
+int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
+				 struct drm_file *file_priv)
+{
+	struct drm_prime_handle *args = data;
+
+	if (!drm_core_check_feature(dev, DRIVER_PRIME))
+		return -EOPNOTSUPP;
+
+	if (!dev->driver->prime_handle_to_fd)
+		return -ENOSYS;
+
+	/* check flags are valid */
+	if (args->flags & ~(DRM_CLOEXEC | DRM_RDWR))
+		return -EINVAL;
+
+	return dev->driver->prime_handle_to_fd(dev, file_priv,
+			args->handle, args->flags, &args->fd);
+}
+
+/**
+ * DOC: PRIME Helpers
+ *
+ * Drivers can implement &drm_gem_object_funcs.export and
+ * &drm_driver.gem_prime_import in terms of simpler APIs by using the helper
+ * functions drm_gem_prime_export() and drm_gem_prime_import().  These functions
+ * implement dma-buf support in terms of some lower-level helpers, which are
+ * again exported for drivers to use individually:
+ *
+ * Exporting buffers
+ * ~~~~~~~~~~~~~~~~~
+ *
+ * Optional pinning of buffers is handled at dma-buf attach and detach time in
+ * drm_gem_map_attach() and drm_gem_map_detach(). Backing storage itself is
+ * handled by drm_gem_map_dma_buf() and drm_gem_unmap_dma_buf(), which relies on
+ * &drm_gem_object_funcs.get_sg_table.
+ *
+ * For kernel-internal access there's drm_gem_dmabuf_vmap() and
+ * drm_gem_dmabuf_vunmap(). Userspace mmap support is provided by
+ * drm_gem_dmabuf_mmap().
+ *
+ * Note that these export helpers can only be used if the underlying backing
+ * storage is fully coherent and either permanently pinned, or it is safe to pin
+ * it indefinitely.
+ *
+ * FIXME: The underlying helper functions are named rather inconsistently.
+ *
+ * Exporting buffers
+ * ~~~~~~~~~~~~~~~~~
+ *
+ * Importing dma-bufs using drm_gem_prime_import() relies on
+ * &drm_driver.gem_prime_import_sg_table.
+ *
+ * Note that similarly to the export helpers this permanently pins the
+ * underlying backing storage. Which is ok for scanout, but is not the best
+ * option for sharing lots of buffers for rendering.
+ */
+
+/**
+ * drm_gem_map_attach - dma_buf attach implementation for GEM
+ * @dma_buf: buffer to attach device to
+ * @attach: buffer attachment data
+ *
+ * Calls &drm_gem_object_funcs.pin for device specific handling. This can be
+ * used as the &dma_buf_ops.attach callback. Must be used together with
+ * drm_gem_map_detach().
+ *
+ * Returns 0 on success, negative error code on failure.
+ */
+int drm_gem_map_attach(struct dma_buf *dma_buf,
+		       struct dma_buf_attachment *attach)
+{
+	struct drm_gem_object *obj = dma_buf->priv;
+
+	return drm_gem_pin(obj);
+}
+EXPORT_SYMBOL(drm_gem_map_attach);
+
+/**
+ * drm_gem_map_detach - dma_buf detach implementation for GEM
+ * @dma_buf: buffer to detach from
+ * @attach: attachment to be detached
+ *
+ * Calls &drm_gem_object_funcs.pin for device specific handling.  Cleans up
+ * &dma_buf_attachment from drm_gem_map_attach(). This can be used as the
+ * &dma_buf_ops.detach callback.
+ */
+void drm_gem_map_detach(struct dma_buf *dma_buf,
+			struct dma_buf_attachment *attach)
+{
+	struct drm_gem_object *obj = dma_buf->priv;
+
+	drm_gem_unpin(obj);
+}
+EXPORT_SYMBOL(drm_gem_map_detach);
+
+/**
+ * drm_gem_map_dma_buf - map_dma_buf implementation for GEM
+ * @attach: attachment whose scatterlist is to be returned
+ * @dir: direction of DMA transfer
+ *
+ * Calls &drm_gem_object_funcs.get_sg_table and then maps the scatterlist. This
+ * can be used as the &dma_buf_ops.map_dma_buf callback. Should be used together
+ * with drm_gem_unmap_dma_buf().
+ *
+ * Returns:sg_table containing the scatterlist to be returned; returns ERR_PTR
+ * on error. May return -EINTR if it is interrupted by a signal.
+ */
+struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach,
+				     enum dma_data_direction dir)
+{
+	struct drm_gem_object *obj = attach->dmabuf->priv;
+	struct sg_table *sgt;
+
+	if (WARN_ON(dir == DMA_NONE))
+		return ERR_PTR(-EINVAL);
+
+	if (obj->funcs)
+		sgt = obj->funcs->get_sg_table(obj);
+	else
+		sgt = obj->dev->driver->gem_prime_get_sg_table(obj);
+
+	if (!dma_map_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir,
+			      DMA_ATTR_SKIP_CPU_SYNC)) {
+		sg_free_table(sgt);
+		kfree(sgt);
+		sgt = ERR_PTR(-ENOMEM);
+	}
+
+	return sgt;
+}
+EXPORT_SYMBOL(drm_gem_map_dma_buf);
+
+/**
+ * drm_gem_unmap_dma_buf - unmap_dma_buf implementation for GEM
+ * @attach: attachment to unmap buffer from
+ * @sgt: scatterlist info of the buffer to unmap
+ * @dir: direction of DMA transfer
+ *
+ * This can be used as the &dma_buf_ops.unmap_dma_buf callback.
+ */
+void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach,
+			   struct sg_table *sgt,
+			   enum dma_data_direction dir)
+{
+	if (!sgt)
+		return;
+
+	dma_unmap_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir,
+			   DMA_ATTR_SKIP_CPU_SYNC);
+	sg_free_table(sgt);
+	kfree(sgt);
+}
+EXPORT_SYMBOL(drm_gem_unmap_dma_buf);
+
+/**
+ * drm_gem_dmabuf_vmap - dma_buf vmap implementation for GEM
+ * @dma_buf: buffer to be mapped
+ *
+ * Sets up a kernel virtual mapping. This can be used as the &dma_buf_ops.vmap
+ * callback. Calls into &drm_gem_object_funcs.vmap for device specific handling.
+ *
+ * Returns the kernel virtual address.
+ */
+void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf)
+{
+	struct drm_gem_object *obj = dma_buf->priv;
+	void *vaddr;
+
+	vaddr = drm_gem_vmap(obj);
+	if (IS_ERR(vaddr))
+		vaddr = NULL;
+
+	return vaddr;
+}
+EXPORT_SYMBOL(drm_gem_dmabuf_vmap);
+
+/**
+ * drm_gem_dmabuf_vunmap - dma_buf vunmap implementation for GEM
+ * @dma_buf: buffer to be unmapped
+ * @vaddr: the virtual address of the buffer
+ *
+ * Releases a kernel virtual mapping. This can be used as the
+ * &dma_buf_ops.vunmap callback. Calls into &drm_gem_object_funcs.vunmap for device specific handling.
+ */
+void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr)
+{
+	struct drm_gem_object *obj = dma_buf->priv;
+
+	drm_gem_vunmap(obj, vaddr);
+}
+EXPORT_SYMBOL(drm_gem_dmabuf_vunmap);
+
 /**
  * drm_gem_prime_mmap - PRIME mmap function for GEM drivers
  * @obj: GEM object
@@ -656,15 +745,121 @@  int drm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
 }
 EXPORT_SYMBOL(drm_gem_prime_mmap);
 
+/**
+ * drm_gem_dmabuf_mmap - dma_buf mmap implementation for GEM
+ * @dma_buf: buffer to be mapped
+ * @vma: virtual address range
+ *
+ * Provides memory mapping for the buffer. This can be used as the
+ * &dma_buf_ops.mmap callback. It just forwards to &drm_driver.gem_prime_mmap,
+ * which should be set to drm_gem_prime_mmap().
+ *
+ * FIXME: There's really no point to this wrapper, drivers which need anything
+ * else but drm_gem_prime_mmap can roll their own &dma_buf_ops.mmap callback.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma)
+{
+	struct drm_gem_object *obj = dma_buf->priv;
+	struct drm_device *dev = obj->dev;
+
+	if (!dev->driver->gem_prime_mmap)
+		return -ENOSYS;
+
+	return dev->driver->gem_prime_mmap(obj, vma);
+}
+EXPORT_SYMBOL(drm_gem_dmabuf_mmap);
+
+static const struct dma_buf_ops drm_gem_prime_dmabuf_ops =  {
+	.cache_sgt_mapping = true,
+	.attach = drm_gem_map_attach,
+	.detach = drm_gem_map_detach,
+	.map_dma_buf = drm_gem_map_dma_buf,
+	.unmap_dma_buf = drm_gem_unmap_dma_buf,
+	.release = drm_gem_dmabuf_release,
+	.mmap = drm_gem_dmabuf_mmap,
+	.vmap = drm_gem_dmabuf_vmap,
+	.vunmap = drm_gem_dmabuf_vunmap,
+};
+
+/**
+ * drm_prime_pages_to_sg - converts a page array into an sg list
+ * @pages: pointer to the array of page pointers to convert
+ * @nr_pages: length of the page vector
+ *
+ * This helper creates an sg table object from a set of pages
+ * the driver is responsible for mapping the pages into the
+ * importers address space for use with dma_buf itself.
+ *
+ * This is useful for implementing &drm_gem_object_funcs.get_sg_table.
+ */
+struct sg_table *drm_prime_pages_to_sg(struct page **pages, unsigned int nr_pages)
+{
+	struct sg_table *sg = NULL;
+	int ret;
+
+	sg = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
+	if (!sg) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = sg_alloc_table_from_pages(sg, pages, nr_pages, 0,
+				nr_pages << PAGE_SHIFT, GFP_KERNEL);
+	if (ret)
+		goto out;
+
+	return sg;
+out:
+	kfree(sg);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(drm_prime_pages_to_sg);
+
+/**
+ * drm_gem_prime_export - helper library implementation of the export callback
+ * @dev: drm_device to export from
+ * @obj: GEM object to export
+ * @flags: flags like DRM_CLOEXEC and DRM_RDWR
+ *
+ * This is the implementation of the &drm_gem_object_funcs.export functions for GEM drivers
+ * using the PRIME helpers.
+ */
+struct dma_buf *drm_gem_prime_export(struct drm_device *dev,
+				     struct drm_gem_object *obj,
+				     int flags)
+{
+	struct dma_buf_export_info exp_info = {
+		.exp_name = KBUILD_MODNAME, /* white lie for debug */
+		.owner = dev->driver->fops->owner,
+		.ops = &drm_gem_prime_dmabuf_ops,
+		.size = obj->size,
+		.flags = flags,
+		.priv = obj,
+		.resv = obj->resv,
+	};
+
+	if (dev->driver->gem_prime_res_obj)
+		exp_info.resv = dev->driver->gem_prime_res_obj(obj);
+
+	return drm_gem_dmabuf_export(dev, &exp_info);
+}
+EXPORT_SYMBOL(drm_gem_prime_export);
+
 /**
  * drm_gem_prime_import_dev - core implementation of the import callback
  * @dev: drm_device to import into
  * @dma_buf: dma-buf object to import
  * @attach_dev: struct device to dma_buf attach
  *
- * This is the core of drm_gem_prime_import. It's designed to be called by
- * drivers who want to use a different device structure than dev->dev for
- * attaching via dma_buf.
+ * This is the core of drm_gem_prime_import(). It's designed to be called by
+ * drivers who want to use a different device structure than &drm_device.dev for
+ * attaching via dma_buf. This function calls
+ * &drm_driver.gem_prime_import_sg_table internally.
+ *
+ * Drivers must arrange to call drm_prime_gem_destroy() from their
+ * &drm_gem_object_funcs.free hook when using this function.
  */
 struct drm_gem_object *drm_gem_prime_import_dev(struct drm_device *dev,
 					    struct dma_buf *dma_buf,
@@ -728,7 +923,11 @@  EXPORT_SYMBOL(drm_gem_prime_import_dev);
  * @dma_buf: dma-buf object to import
  *
  * This is the implementation of the gem_prime_import functions for GEM drivers
- * using the PRIME helpers.
+ * using the PRIME helpers. Drivers can use this as their
+ * &drm_driver.gem_prime_import implementation.
+ *
+ * Drivers must arrange to call drm_prime_gem_destroy() from their
+ * &drm_gem_object_funcs.free hook when using this function.
  */
 struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
 					    struct dma_buf *dma_buf)
@@ -737,154 +936,6 @@  struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
 }
 EXPORT_SYMBOL(drm_gem_prime_import);
 
-/**
- * drm_gem_prime_fd_to_handle - PRIME import function for GEM drivers
- * @dev: dev to export the buffer from
- * @file_priv: drm file-private structure
- * @prime_fd: fd id of the dma-buf which should be imported
- * @handle: pointer to storage for the handle of the imported buffer object
- *
- * This is the PRIME import function which must be used mandatorily by GEM
- * drivers to ensure correct lifetime management of the underlying GEM object.
- * The actual importing of GEM object from the dma-buf is done through the
- * gem_import_export driver callback.
- */
-int drm_gem_prime_fd_to_handle(struct drm_device *dev,
-			       struct drm_file *file_priv, int prime_fd,
-			       uint32_t *handle)
-{
-	struct dma_buf *dma_buf;
-	struct drm_gem_object *obj;
-	int ret;
-
-	dma_buf = dma_buf_get(prime_fd);
-	if (IS_ERR(dma_buf))
-		return PTR_ERR(dma_buf);
-
-	mutex_lock(&file_priv->prime.lock);
-
-	ret = drm_prime_lookup_buf_handle(&file_priv->prime,
-			dma_buf, handle);
-	if (ret == 0)
-		goto out_put;
-
-	/* never seen this one, need to import */
-	mutex_lock(&dev->object_name_lock);
-	if (dev->driver->gem_prime_import)
-		obj = dev->driver->gem_prime_import(dev, dma_buf);
-	else
-		obj = drm_gem_prime_import(dev, dma_buf);
-	if (IS_ERR(obj)) {
-		ret = PTR_ERR(obj);
-		goto out_unlock;
-	}
-
-	if (obj->dma_buf) {
-		WARN_ON(obj->dma_buf != dma_buf);
-	} else {
-		obj->dma_buf = dma_buf;
-		get_dma_buf(dma_buf);
-	}
-
-	/* _handle_create_tail unconditionally unlocks dev->object_name_lock. */
-	ret = drm_gem_handle_create_tail(file_priv, obj, handle);
-	drm_gem_object_put_unlocked(obj);
-	if (ret)
-		goto out_put;
-
-	ret = drm_prime_add_buf_handle(&file_priv->prime,
-			dma_buf, *handle);
-	mutex_unlock(&file_priv->prime.lock);
-	if (ret)
-		goto fail;
-
-	dma_buf_put(dma_buf);
-
-	return 0;
-
-fail:
-	/* hmm, if driver attached, we are relying on the free-object path
-	 * to detach.. which seems ok..
-	 */
-	drm_gem_handle_delete(file_priv, *handle);
-	dma_buf_put(dma_buf);
-	return ret;
-
-out_unlock:
-	mutex_unlock(&dev->object_name_lock);
-out_put:
-	mutex_unlock(&file_priv->prime.lock);
-	dma_buf_put(dma_buf);
-	return ret;
-}
-EXPORT_SYMBOL(drm_gem_prime_fd_to_handle);
-
-int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
-				 struct drm_file *file_priv)
-{
-	struct drm_prime_handle *args = data;
-
-	if (!drm_core_check_feature(dev, DRIVER_PRIME))
-		return -EOPNOTSUPP;
-
-	if (!dev->driver->prime_handle_to_fd)
-		return -ENOSYS;
-
-	/* check flags are valid */
-	if (args->flags & ~(DRM_CLOEXEC | DRM_RDWR))
-		return -EINVAL;
-
-	return dev->driver->prime_handle_to_fd(dev, file_priv,
-			args->handle, args->flags, &args->fd);
-}
-
-int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data,
-				 struct drm_file *file_priv)
-{
-	struct drm_prime_handle *args = data;
-
-	if (!drm_core_check_feature(dev, DRIVER_PRIME))
-		return -EOPNOTSUPP;
-
-	if (!dev->driver->prime_fd_to_handle)
-		return -ENOSYS;
-
-	return dev->driver->prime_fd_to_handle(dev, file_priv,
-			args->fd, &args->handle);
-}
-
-/**
- * drm_prime_pages_to_sg - converts a page array into an sg list
- * @pages: pointer to the array of page pointers to convert
- * @nr_pages: length of the page vector
- *
- * This helper creates an sg table object from a set of pages
- * the driver is responsible for mapping the pages into the
- * importers address space for use with dma_buf itself.
- */
-struct sg_table *drm_prime_pages_to_sg(struct page **pages, unsigned int nr_pages)
-{
-	struct sg_table *sg = NULL;
-	int ret;
-
-	sg = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
-	if (!sg) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	ret = sg_alloc_table_from_pages(sg, pages, nr_pages, 0,
-				nr_pages << PAGE_SHIFT, GFP_KERNEL);
-	if (ret)
-		goto out;
-
-	return sg;
-out:
-	kfree(sg);
-	return ERR_PTR(ret);
-}
-EXPORT_SYMBOL(drm_prime_pages_to_sg);
-
 /**
  * drm_prime_sg_to_page_addr_arrays - convert an sg table into a page array
  * @sgt: scatter-gather table to convert
@@ -894,6 +945,9 @@  EXPORT_SYMBOL(drm_prime_pages_to_sg);
  *
  * Exports an sg table into an array of pages and addresses. This is currently
  * required by the TTM driver in order to do correct fault handling.
+ *
+ * Drivers can use this in their &drm_driver.gem_prime_import_sg_table
+ * implementation.
  */
 int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages,
 				     dma_addr_t *addrs, int max_entries)
@@ -934,7 +988,7 @@  EXPORT_SYMBOL(drm_prime_sg_to_page_addr_arrays);
  * @sg: the sg-table which was pinned at import time
  *
  * This is the cleanup functions which GEM drivers need to call when they use
- * @drm_gem_prime_import to import dma-bufs.
+ * drm_gem_prime_import() or drm_gem_prime_import_dev() to import dma-bufs.
  */
 void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg)
 {
@@ -949,16 +1003,3 @@  void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg)
 	dma_buf_put(dma_buf);
 }
 EXPORT_SYMBOL(drm_prime_gem_destroy);
-
-void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv)
-{
-	mutex_init(&prime_fpriv->lock);
-	prime_fpriv->dmabufs = RB_ROOT;
-	prime_fpriv->handles = RB_ROOT;
-}
-
-void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv)
-{
-	/* by now drm_gem_release should've made sure the list is empty */
-	WARN_ON(!RB_EMPTY_ROOT(&prime_fpriv->dmabufs));
-}
diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h
index 5c4fc0ddc863..5e1ba16d19c6 100644
--- a/include/drm/drm_drv.h
+++ b/include/drm/drm_drv.h
@@ -505,21 +505,25 @@  struct drm_driver {
 	 * @gem_free_object: deconstructor for drm_gem_objects
 	 *
 	 * This is deprecated and should not be used by new drivers. Use
-	 * @gem_free_object_unlocked instead.
+	 * &drm_gem_object_funcs.free instead.
 	 */
 	void (*gem_free_object) (struct drm_gem_object *obj);
 
 	/**
 	 * @gem_free_object_unlocked: deconstructor for drm_gem_objects
 	 *
-	 * This is for drivers which are not encumbered with &drm_device.struct_mutex
-	 * legacy locking schemes. Use this hook instead of @gem_free_object.
+	 * This is deprecated and should not be used by new drivers. Use
+	 * &drm_gem_object_funcs.free instead.
+	 * Compared to @gem_free_object this is not encumbered with
+	 * &drm_device.struct_mutex legacy locking schemes.
 	 */
 	void (*gem_free_object_unlocked) (struct drm_gem_object *obj);
 
 	/**
 	 * @gem_open_object:
 	 *
+	 * This callback is deprecated in favour of &drm_gem_object_funcs.open.
+	 *
 	 * Driver hook called upon gem handle creation
 	 */
 	int (*gem_open_object) (struct drm_gem_object *, struct drm_file *);
@@ -527,6 +531,8 @@  struct drm_driver {
 	/**
 	 * @gem_close_object:
 	 *
+	 * This callback is deprecated in favour of &drm_gem_object_funcs.close.
+	 *
 	 * Driver hook called upon gem handle release
 	 */
 	void (*gem_close_object) (struct drm_gem_object *, struct drm_file *);
@@ -534,6 +540,9 @@  struct drm_driver {
 	/**
 	 * @gem_print_info:
 	 *
+	 * This callback is deprecated in favour of
+	 * &drm_gem_object_funcs.print_info.
+	 *
 	 * If driver subclasses struct &drm_gem_object, it can implement this
 	 * optional hook for printing additional driver specific info.
 	 *
@@ -548,56 +557,120 @@  struct drm_driver {
 	/**
 	 * @gem_create_object: constructor for gem objects
 	 *
-	 * Hook for allocating the GEM object struct, for use by core
-	 * helpers.
+	 * Hook for allocating the GEM object struct, for use by the CMA and
+	 * SHMEM GEM helpers.
 	 */
 	struct drm_gem_object *(*gem_create_object)(struct drm_device *dev,
 						    size_t size);
-
-	/* prime: */
 	/**
 	 * @prime_handle_to_fd:
 	 *
-	 * export handle -> fd (see drm_gem_prime_handle_to_fd() helper)
+	 * Main PRIME export function. Should be implented with
+	 * drm_gem_prime_handle_to_fd() for GEM based drivers.
+	 *
+	 * For an in-depth discussion see :ref:`PRIME buffer sharing
+	 * documentation <prime_buffer_sharing>`.
 	 */
 	int (*prime_handle_to_fd)(struct drm_device *dev, struct drm_file *file_priv,
 				uint32_t handle, uint32_t flags, int *prime_fd);
 	/**
 	 * @prime_fd_to_handle:
 	 *
-	 * import fd -> handle (see drm_gem_prime_fd_to_handle() helper)
+	 * Main PRIME import function. Should be implented with
+	 * drm_gem_prime_fd_to_handle() for GEM based drivers.
+	 *
+	 * For an in-depth discussion see :ref:`PRIME buffer sharing
+	 * documentation <prime_buffer_sharing>`.
 	 */
 	int (*prime_fd_to_handle)(struct drm_device *dev, struct drm_file *file_priv,
 				int prime_fd, uint32_t *handle);
 	/**
 	 * @gem_prime_export:
 	 *
-	 * export GEM -> dmabuf
-	 *
-	 * This defaults to drm_gem_prime_export() if not set.
+	 * Export hook for GEM drivers. Deprecated in favour of
+	 * &drm_gem_object_funcs.export.
 	 */
 	struct dma_buf * (*gem_prime_export)(struct drm_device *dev,
 				struct drm_gem_object *obj, int flags);
 	/**
 	 * @gem_prime_import:
 	 *
-	 * import dmabuf -> GEM
+	 * Import hook for GEM drivers.
 	 *
 	 * This defaults to drm_gem_prime_import() if not set.
 	 */
 	struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev,
 				struct dma_buf *dma_buf);
+
+	/**
+	 * @gem_prime_pin:
+	 *
+	 * Deprecated hook in favour of &drm_gem_object_funcs.pin.
+	 */
 	int (*gem_prime_pin)(struct drm_gem_object *obj);
+
+	/**
+	 * @gem_prime_unpin:
+	 *
+	 * Deprecated hook in favour of &drm_gem_object_funcs.unpin.
+	 */
 	void (*gem_prime_unpin)(struct drm_gem_object *obj);
+
+
+	/**
+	 * @gem_prime_get_sg_table:
+	 *
+	 * Deprecated hook in favour of &drm_gem_object_funcs.get_sg_table.
+	 */
+	struct sg_table *(*gem_prime_get_sg_table)(struct drm_gem_object *obj);
+
+	/**
+	 * @gem_prime_res_obj:
+	 *
+	 * Optional hook to look up the &reservation_object for an buffer when
+	 * exporting it.
+	 *
+	 * FIXME: This hook is deprecated. User of this hook should be replaced
+	 * by setting &drm_gem_object.resv instead.
+	 */
 	struct reservation_object * (*gem_prime_res_obj)(
 				struct drm_gem_object *obj);
-	struct sg_table *(*gem_prime_get_sg_table)(struct drm_gem_object *obj);
+
+	/**
+	 * @gem_prime_import_sg_table:
+	 *
+	 * Optional hook used by the PRIME helper functions
+	 * drm_gem_prime_import() respectively drm_gem_prime_import_dev().
+	 */
 	struct drm_gem_object *(*gem_prime_import_sg_table)(
 				struct drm_device *dev,
 				struct dma_buf_attachment *attach,
 				struct sg_table *sgt);
+	/**
+	 * @gem_prime_vmap:
+	 *
+	 * Deprecated vmap hook for GEM drivers. Please use
+	 * &drm_gem_object_funcs.vmap instead.
+	 */
 	void *(*gem_prime_vmap)(struct drm_gem_object *obj);
+
+	/**
+	 * @gem_prime_vunmap:
+	 *
+	 * Deprecated vunmap hook for GEM drivers. Please use
+	 * &drm_gem_object_funcs.vunmap instead.
+	 */
 	void (*gem_prime_vunmap)(struct drm_gem_object *obj, void *vaddr);
+
+	/**
+	 * @gem_prime_mmap:
+	 *
+	 * mmap hook for GEM drivers, used to implement dma-buf mmap in the
+	 * PRIME helpers.
+	 *
+	 * FIXME: There's way too much duplication going on here, and also moved
+	 * to &drm_gem_object_funcs.
+	 */
 	int (*gem_prime_mmap)(struct drm_gem_object *obj,
 				struct vm_area_struct *vma);
 
@@ -665,6 +738,9 @@  struct drm_driver {
 
 	/**
 	 * @gem_vm_ops: Driver private ops for this object
+	 *
+	 * For GEM driver this is deprecated in favour of
+	 * &drm_gem_object_funcs.vm_ops.
 	 */
 	const struct vm_operations_struct *gem_vm_ops;
 
diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
index a9121fe66ea2..9af88238ee5c 100644
--- a/include/drm/drm_gem.h
+++ b/include/drm/drm_gem.h
@@ -101,7 +101,7 @@  struct drm_gem_object_funcs {
 	/**
 	 * @pin:
 	 *
-	 * Pin backing buffer in memory.
+	 * Pin backing buffer in memory. Used by the drm_gem_map_attach helper.
 	 *
 	 * This callback is optional.
 	 */
@@ -110,7 +110,7 @@  struct drm_gem_object_funcs {
 	/**
 	 * @unpin:
 	 *
-	 * Unpin backing buffer.
+	 * Unpin backing buffer. Used by the drm_gem_map_detach() helper.
 	 *
 	 * This callback is optional.
 	 */
@@ -120,16 +120,21 @@  struct drm_gem_object_funcs {
 	 * @get_sg_table:
 	 *
 	 * Returns a Scatter-Gather table representation of the buffer.
-	 * Used when exporting a buffer.
+	 * Used when exporting a buffer by the drm_gem_map_dma_buf() helper.
+	 * Releasing is done by calling dma_unmap_sg_attrs() and sg_free_table()
+	 * in drm_gem_unmap_buf(), therefore these helpers and this callback
+	 * here cannot be used for sg tables pointing at driver private memory
+	 * ranges.
 	 *
-	 * This callback is mandatory if buffer export is supported.
+	 * See also drm_prime_pages_to_sg().
 	 */
 	struct sg_table *(*get_sg_table)(struct drm_gem_object *obj);
 
 	/**
 	 * @vmap:
 	 *
-	 * Returns a virtual address for the buffer.
+	 * Returns a virtual address for the buffer. Used by the
+	 * drm_gem_dmabuf_vmap() helper.
 	 *
 	 * This callback is optional.
 	 */
@@ -138,7 +143,8 @@  struct drm_gem_object_funcs {
 	/**
 	 * @vunmap:
 	 *
-	 * Releases the the address previously returned by @vmap.
+	 * Releases the the address previously returned by @vmap. Used by the
+	 * drm_gem_dmabuf_vunmap() helper.
 	 *
 	 * This callback is optional.
 	 */
diff --git a/include/drm/drm_prime.h b/include/drm/drm_prime.h
index b03731a3f079..ee32b07f3eb0 100644
--- a/include/drm/drm_prime.h
+++ b/include/drm/drm_prime.h
@@ -42,7 +42,6 @@ 
  * This just contains the internal &struct dma_buf and handle caches for each
  * &struct drm_file used by the PRIME core code.
  */
-
 struct drm_prime_file_private {
 /* private: */
 	struct mutex lock;
@@ -64,25 +63,18 @@  struct drm_file;
 
 struct device;
 
-struct dma_buf *drm_gem_prime_export(struct drm_device *dev,
-				     struct drm_gem_object *obj,
-				     int flags);
+/* core prime functions */
+struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev,
+				      struct dma_buf_export_info *exp_info);
+void drm_gem_dmabuf_release(struct dma_buf *dma_buf);
+
+int drm_gem_prime_fd_to_handle(struct drm_device *dev,
+			       struct drm_file *file_priv, int prime_fd, uint32_t *handle);
 int drm_gem_prime_handle_to_fd(struct drm_device *dev,
 			       struct drm_file *file_priv, uint32_t handle, uint32_t flags,
 			       int *prime_fd);
-int drm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma);
-struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
-					    struct dma_buf *dma_buf);
-
-struct drm_gem_object *drm_gem_prime_import_dev(struct drm_device *dev,
-						struct dma_buf *dma_buf,
-						struct device *attach_dev);
 
-int drm_gem_prime_fd_to_handle(struct drm_device *dev,
-			       struct drm_file *file_priv, int prime_fd, uint32_t *handle);
-struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev,
-				      struct dma_buf_export_info *exp_info);
-void drm_gem_dmabuf_release(struct dma_buf *dma_buf);
+/* helper functions for exporting */
 int drm_gem_map_attach(struct dma_buf *dma_buf,
 		       struct dma_buf_attachment *attach);
 void drm_gem_map_detach(struct dma_buf *dma_buf,
@@ -94,12 +86,26 @@  void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach,
 			   enum dma_data_direction dir);
 void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf);
 void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr);
+
+int drm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma);
 int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma);
 
-int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages,
-				     dma_addr_t *addrs, int max_pages);
 struct sg_table *drm_prime_pages_to_sg(struct page **pages, unsigned int nr_pages);
+struct dma_buf *drm_gem_prime_export(struct drm_device *dev,
+				     struct drm_gem_object *obj,
+				     int flags);
+
+/* helper functions for importing */
+struct drm_gem_object *drm_gem_prime_import_dev(struct drm_device *dev,
+						struct dma_buf *dma_buf,
+						struct device *attach_dev);
+struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
+					    struct dma_buf *dma_buf);
+
 void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg);
 
+int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages,
+				     dma_addr_t *addrs, int max_pages);
+
 
 #endif /* __DRM_PRIME_H__ */