[PATCH] drm: base prime/dma-buf support
Ville Syrjälä
ville.syrjala at linux.intel.com
Mon Mar 26 09:32:15 PDT 2012
On Mon, Mar 26, 2012 at 04:02:55PM +0100, Dave Airlie wrote:
<snip>
> +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)
> +{
> + struct drm_gem_object *obj;
> +
> + obj = drm_gem_object_lookup(dev, file_priv, handle);
> + if (!obj)
> + return -ENOENT;
> +
> + /* don't allow imported buffers to be re-exported */
> + if (obj->import_attach) {
> + drm_gem_object_unreference_unlocked(obj);
> + return -EINVAL;
> + }
> +
> + if (obj->export_dma_buf) {
> + get_file(obj->export_dma_buf->file);
> + *prime_fd = dma_buf_fd(obj->export_dma_buf, flags);
> + drm_gem_object_unreference_unlocked(obj);
> + } else {
> + obj->export_dma_buf =
> + dev->driver->gem_prime_export(dev, obj, flags);
> + if (IS_ERR_OR_NULL(obj->export_dma_buf)) {
> + /* normally the created dma-buf takes ownership of the ref,
> + * but if that fails then drop the ref
> + */
> + drm_gem_object_unreference_unlocked(obj);
> + return PTR_ERR(obj->export_dma_buf);
PTR_ERR(NULL) seems like a bad idea. Also, you're accessing 'obj' after
dropping the reference.
> + }
> + *prime_fd = dma_buf_fd(obj->export_dma_buf, flags);
> + }
> + return 0;
> +}
> +EXPORT_SYMBOL(drm_gem_prime_handle_to_fd);
> +
> +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);
> +
> + ret = drm_prime_lookup_fd_handle_mapping(&file_priv->prime,
> + dma_buf, handle);
> + if (!ret) {
> + dma_buf_put(dma_buf);
> + return 0;
> + }
> +
> + /* never seen this one, need to import */
> + obj = dev->driver->gem_prime_import(dev, dma_buf);
> + if (IS_ERR_OR_NULL(obj)) {
> + ret = PTR_ERR(obj);
PTR_ERR(NULL) again.
> + goto fail_put;
> + }
> +
> + ret = drm_gem_handle_create(file_priv, obj, handle);
> + drm_gem_object_unreference_unlocked(obj);
> + if (ret)
> + goto fail_put;
> +
> + ret = drm_prime_insert_fd_handle_mapping(&file_priv->prime,
> + dma_buf, *handle);
> + if (ret)
> + goto fail;
> +
> + return 0;
> +
> +fail:
> + /* hmm, if driver attached, we are relying on the free-object path
> + * to detach.. which seems ok..
> + */
> + drm_gem_object_handle_unreference_unlocked(obj);
> +fail_put:
> + 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;
> + uint32_t flags;
> +
> + if (!drm_core_check_feature(dev, DRIVER_PRIME))
> + return -EINVAL;
> +
> + if (!dev->driver->prime_handle_to_fd)
> + return -ENOSYS;
> +
> + /* we only want to pass DRM_CLOEXEC which is == O_CLOEXEC */
> + flags = args->flags & DRM_CLOEXEC;
Check that the unused flags are 0? If you allow broken userspace to
pass uninitialized 'flags' to the kernel, you may have compatibility
problems if/when you want to add more flags.
> +
> + return dev->driver->prime_handle_to_fd(dev, file_priv,
> + args->handle, 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 -EINVAL;
> +
> + 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
> + *
> + * 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
> + */
> +struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages)
> +{
> + struct sg_table *sg = NULL;
> + struct scatterlist *iter;
> + int i;
> + int ret;
> +
> + sg = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
kmalloc() would be enough. sg_alloc_table() already does a memset().
> + if (!sg)
> + goto out;
> +
> + ret = sg_alloc_table(sg, nr_pages, GFP_KERNEL);
> + if (ret)
> + goto out;
> +
> + for_each_sg(sg->sgl, iter, nr_pages, i)
> + sg_set_page(iter, pages[i], PAGE_SIZE, 0);
> +
> + return sg;
> +out:
> + kfree(sg);
> + return NULL;
> +}
> +EXPORT_SYMBOL(drm_prime_pages_to_sg);
--
Ville Syrjälä
Intel OTC
More information about the dri-devel
mailing list