diff options
Diffstat (limited to 'drivers/gpu/drm/drm_prime.c')
| -rw-r--r-- | drivers/gpu/drm/drm_prime.c | 848 | 
1 files changed, 442 insertions, 406 deletions
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index d0c01318076b..0a2316e0e812 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -30,6 +30,7 @@  #include <linux/dma-buf.h>  #include <linux/rbtree.h> +#include <drm/drm.h>  #include <drm/drm_drv.h>  #include <drm/drm_file.h>  #include <drm/drm_framebuffer.h> @@ -38,47 +39,52 @@  #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 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() and + * 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,100 @@ 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 + * 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   * - * Sets up a kernel virtual mapping. This can be used as the &dma_buf_ops.vmap - * callback. + * 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_prime_import driver callback.   * - * Returns the kernel virtual address. + * Returns 0 on success or a 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); -	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 (!dev->driver->prime_fd_to_handle) +		return -ENOSYS; -	return drm_gem_dmabuf_export(dev, &exp_info); +	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, @@ -489,9 +385,9 @@ static struct dma_buf *export_and_register_object(struct drm_device *dev,  	if (obj->funcs && obj->funcs->export)  		dmabuf = obj->funcs->export(obj, flags);  	else if (dev->driver->gem_prime_export) -		dmabuf = dev->driver->gem_prime_export(dev, obj, flags); +		dmabuf = dev->driver->gem_prime_export(obj, flags);  	else -		dmabuf = drm_gem_prime_export(dev, obj, flags); +		dmabuf = drm_gem_prime_export(obj, flags);  	if (IS_ERR(dmabuf)) {  		/* normally the created dma-buf takes ownership of the ref,  		 * but if that fails then drop the ref @@ -521,7 +417,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 +506,195 @@ out_unlock:  }  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 (!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 or NULL on failure. + */ +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 @@ -657,14 +742,117 @@ out:  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 + * @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. It is used as the default in + * drm_gem_prime_handle_to_fd(). + */ +struct dma_buf *drm_gem_prime_export(struct drm_gem_object *obj, +				     int flags) +{ +	struct drm_device *dev = obj->dev; +	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, +	}; + +	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, @@ -709,6 +897,7 @@ struct drm_gem_object *drm_gem_prime_import_dev(struct drm_device *dev,  	}  	obj->import_attach = attach; +	obj->resv = dma_buf->resv;  	return obj; @@ -728,7 +917,12 @@ 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. It is used as the default + * implementation in drm_gem_prime_fd_to_handle(). + * + * 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) @@ -738,154 +932,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   * @pages: optional array of page pointers to store the page array in @@ -894,6 +940,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 +983,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 +998,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)); -}  |