On Wed, Feb 22, 2012 at 2:29 PM, Ben Widawsky <ben at bwidawsk.net> wrote: > From: Dave Airlie <airlied at redhat.com> > > --- > ?drivers/gpu/drm/Makefile ? ?| ? ?2 +- > ?drivers/gpu/drm/drm_drv.c ? | ? ?3 + > ?drivers/gpu/drm/drm_gem.c ? | ? ?3 +- > ?drivers/gpu/drm/drm_prime.c | ?126 > +++++++++++++++++++++++++++++++++++++++++++ > ?include/drm/drm.h ? ? ? ? ? | ? 10 +++- > ?include/drm/drmP.h ? ? ? ? ?| ? 35 ++++++++++++ > ?6 files changed, 176 insertions(+), 3 deletions(-) > ?create mode 100644 drivers/gpu/drm/drm_prime.c > > diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile > index 0cde1b8..202f650 100644 > --- a/drivers/gpu/drm/Makefile > +++ b/drivers/gpu/drm/Makefile > @@ -12,7 +12,7 @@ drm-y ? ? ? := ? ? ? ?drm_auth.o drm_buffer.o drm_bufs.o > drm_cache.o \ > ? ? ? ? ? ? ? ?drm_platform.o drm_sysfs.o drm_hashtab.o drm_mm.o \ > ? ? ? ? ? ? ? ?drm_crtc.o drm_modes.o drm_edid.o \ > ? ? ? ? ? ? ? ?drm_info.o drm_debugfs.o drm_encoder_slave.o \ > - ? ? ? ? ? ? ? drm_trace_points.o drm_global.o drm_usb.o > + ? ? ? ? ? ? ? drm_trace_points.o drm_global.o drm_usb.o drm_prime.o > > ?drm-$(CONFIG_COMPAT) += drm_ioc32.o > > diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c > index ebf7d3f..786b134 100644 > --- a/drivers/gpu/drm/drm_drv.c > +++ b/drivers/gpu/drm/drm_drv.c > @@ -135,6 +135,9 @@ static struct drm_ioctl_desc drm_ioctls[] = { > ? ? ? ?DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, > DRM_AUTH|DRM_UNLOCKED), > ? ? ? ?DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, > DRM_AUTH|DRM_UNLOCKED), > > + ? ? ? DRM_IOCTL_DEF(DRM_IOCTL_PRIME_HANDLE_TO_FD, > drm_prime_handle_to_fd_ioctl, DRM_AUTH|DRM_UNLOCKED), > + ? ? ? DRM_IOCTL_DEF(DRM_IOCTL_PRIME_FD_TO_HANDLE, > drm_prime_fd_to_handle_ioctl, DRM_AUTH|DRM_UNLOCKED), > + > ? ? ? ?DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, > DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), > ? ? ? ?DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_getplane_res, > DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), > ? ? ? ?DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, > DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), > diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c > index f8625e2..e19a958 100644 > --- a/drivers/gpu/drm/drm_gem.c > +++ b/drivers/gpu/drm/drm_gem.c > @@ -145,6 +145,7 @@ int drm_gem_object_init(struct drm_device *dev, > ? ? ? ?kref_init(&obj->refcount); > ? ? ? ?atomic_set(&obj->handle_count, 0); > ? ? ? ?obj->size = size; > + ? ? ? obj->prime_fd = -1; > > ? ? ? ?return 0; > ?} > @@ -166,7 +167,7 @@ int drm_gem_private_object_init(struct drm_device *dev, > ? ? ? ?kref_init(&obj->refcount); > ? ? ? ?atomic_set(&obj->handle_count, 0); > ? ? ? ?obj->size = size; > - > + ? ? ? obj->prime_fd = -1; > ? ? ? ?return 0; > ?} > ?EXPORT_SYMBOL(drm_gem_private_object_init); > diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c > new file mode 100644 > index 0000000..11f142f > --- /dev/null > +++ b/drivers/gpu/drm/drm_prime.c > @@ -0,0 +1,126 @@ > +#include <linux/export.h> > +#include <linux/dma-buf.h> > +#include "drmP.h" > + > +struct drm_prime_member { > + ? ? ? struct list_head entry; > + ? ? ? struct dma_buf *dma_buf; > + ? ? ? uint32_t 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 -EINVAL; > + > + ? ? ? return dev->driver->prime_handle_to_fd(dev, file_priv, args->handle, > &args->fd);
We need a way to pass flags to this so we can pass DRM_PRIME_CLOEXEC (or whatever, but not O_CLOEXEC) to create the fd in close-on-exec mode, and it needs to be available in the libdrm API. See man epoll_create1 for an example where we had to add a new brown-bag syscall to allow this. > +} > + > +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; > + > + ? ? ? return dev->driver->prime_fd_to_handle(dev, file_priv, args->fd, > &args->handle); > +} > + > +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); > + ? ? ? 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); > + > +/* helper function to cleanup a GEM/prime object */ > +void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg) > +{ > + ? ? ? struct dma_buf_attachment *attach; > + > + ? ? ? attach = obj->import_attach; > + ? ? ? if (sg) > + ? ? ? ? ? ? ? dma_buf_unmap_attachment(attach, sg); > + ? ? ? dma_buf_detach(attach->dmabuf, attach); > +} > +EXPORT_SYMBOL(drm_prime_gem_destroy); > + > +void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv) > +{ > + ? ? ? INIT_LIST_HEAD(&prime_fpriv->head); > +} > +EXPORT_SYMBOL(drm_prime_init_file_private); > + > +void drm_prime_destroy_file_private(struct drm_prime_file_private > *prime_fpriv) > +{ > + ? ? ? struct drm_prime_member *member, *safe; > + ? ? ? list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) { > + ? ? ? ? ? ? ? list_del(&member->entry); > + ? ? ? ? ? ? ? kfree(member); > + ? ? ? } > +} > +EXPORT_SYMBOL(drm_prime_destroy_file_private); > + > +int drm_prime_insert_fd_handle_mapping(struct drm_prime_file_private > *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle) > +{ > + ? ? ? struct drm_prime_member *member; > + > + ? ? ? member = kmalloc(sizeof(*member), GFP_KERNEL); > + ? ? ? if (!member) > + ? ? ? ? ? ? ? return -ENOMEM; > + > + ? ? ? member->dma_buf = dma_buf; > + ? ? ? member->handle = handle; > + ? ? ? list_add(&member->entry, &prime_fpriv->head); > + ? ? ? return 0; > +} > +EXPORT_SYMBOL(drm_prime_insert_fd_handle_mapping); > + > +int drm_prime_lookup_fd_handle_mapping(struct drm_prime_file_private > *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle) > +{ > + ? ? ? struct drm_prime_member *member; > + > + ? ? ? list_for_each_entry(member, &prime_fpriv->head, entry) { > + ? ? ? ? ? ? ? if (member->dma_buf == dma_buf) { > + ? ? ? ? ? ? ? ? ? ? ? *handle = member->handle; > + ? ? ? ? ? ? ? ? ? ? ? return 0; > + ? ? ? ? ? ? ? } > + ? ? ? } > + ? ? ? return -ENOENT; > +} > +EXPORT_SYMBOL(drm_prime_lookup_fd_handle_mapping); > + > +void drm_prime_remove_fd_handle_mapping(struct drm_prime_file_private > *prime_fpriv, struct dma_buf *dma_buf) > +{ > + ? ? ? struct drm_prime_member *member, *safe; > + > + ? ? ? list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) { > + ? ? ? ? ? ? ? if (member->dma_buf == dma_buf) { > + ? ? ? ? ? ? ? ? ? ? ? list_del(&member->entry); > + ? ? ? ? ? ? ? ? ? ? ? kfree(member); > + ? ? ? ? ? ? ? } > + ? ? ? } > +} > +EXPORT_SYMBOL(drm_prime_remove_fd_handle_mapping); > diff --git a/include/drm/drm.h b/include/drm/drm.h > index 49d94ed..3dcae79 100644 > --- a/include/drm/drm.h > +++ b/include/drm/drm.h > @@ -617,6 +617,13 @@ struct drm_get_cap { > ? ? ? ?__u64 value; > ?}; > > +struct drm_prime_handle { > + ? ? ? __u32 handle; > + > + ? ? ? /* returned fd for prime */ > + ? ? ? __s32 fd; __u32 flags; > +}; > + > ?#include "drm_mode.h" > > ?#define DRM_IOCTL_BASE ? ? ? ? ? ? ? ? 'd' > @@ -673,7 +680,8 @@ struct drm_get_cap { > ?#define DRM_IOCTL_UNLOCK ? ? ? ? ? ? ? DRM_IOW( 0x2b, struct drm_lock) > ?#define DRM_IOCTL_FINISH ? ? ? ? ? ? ? DRM_IOW( 0x2c, struct drm_lock) > > -#define DRM_IOCTL_GEM_PRIME_OPEN ? ? ? ?DRM_IOWR(0x2e, struct drm_gem_open) > +#define DRM_IOCTL_PRIME_HANDLE_TO_FD ? ?DRM_IOWR(0x2d, struct > drm_prime_handle) > +#define DRM_IOCTL_PRIME_FD_TO_HANDLE ? ?DRM_IOWR(0x2e, struct > drm_prime_handle) > #define DRM_PRIME_CLOEXEC 0x01 > ?#define DRM_IOCTL_AGP_ACQUIRE ? ? ? ? ?DRM_IO( ?0x30) > ?#define DRM_IOCTL_AGP_RELEASE ? ? ? ? ?DRM_IO( ?0x31) > diff --git a/include/drm/drmP.h b/include/drm/drmP.h > index 92f0981..9558111 100644 > --- a/include/drm/drmP.h > +++ b/include/drm/drmP.h > @@ -150,6 +150,7 @@ int drm_err(const char *func, const char *format, ...); > ?#define DRIVER_IRQ_VBL2 ? ?0x800 > ?#define DRIVER_GEM ? ? ? ? 0x1000 > ?#define DRIVER_MODESET ? ? 0x2000 > +#define DRIVER_PRIME ? ? ? 0x4000 > > ?#define DRIVER_BUS_PCI 0x1 > ?#define DRIVER_BUS_PLATFORM 0x2 > @@ -652,6 +653,19 @@ struct drm_gem_object { > ? ? ? ?uint32_t pending_write_domain; > > ? ? ? ?void *driver_private; > + > + ? ? ? /* prime fd exporting this object, -1 for no fd */ > + ? ? ? int prime_fd; > + ? ? ? /* dma buf exported from this GEM object */ > + ? ? ? struct dma_buf *export_dma_buf; > + > + ? ? ? /* dma buf attachment backing this object */ > + ? ? ? struct dma_buf_attachment *import_attach; > +}; > + > +/* initial implementaton using a linked list - todo hashtab */ > +struct drm_prime_file_private { > + ? ? ? struct list_head head; > ?}; > > ?#include "drm_crtc.h" > @@ -890,6 +904,13 @@ struct drm_driver { > ? ? ? ?int (*gem_open_object) (struct drm_gem_object *, struct drm_file *); > ? ? ? ?void (*gem_close_object) (struct drm_gem_object *, struct drm_file *); > > + ? ? ? /* prime */ > + ? ? ? int (*prime_handle_to_fd)(struct drm_device *dev, struct drm_file > *file_priv, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? uint32_t handle, int *prime_fd); > + > + ? ? ? int (*prime_fd_to_handle)(struct drm_device *dev, struct drm_file > *file_priv, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int prime_fd, uint32_t *handle); > + > ? ? ? ?/* vga arb irq handler */ > ? ? ? ?void (*vgaarb_irq)(struct drm_device *dev, bool state); > > @@ -1502,6 +1523,20 @@ extern int drm_vblank_info(struct seq_file *m, void > *data); > ?extern int drm_clients_info(struct seq_file *m, void* data); > ?extern int drm_gem_name_info(struct seq_file *m, void *data); > > +extern int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct drm_file *file_priv); > +extern int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct drm_file *file_priv); > + > +extern struct sg_table *drm_prime_pages_to_sg(struct page **pages, int > nr_pages); > +extern void drm_prime_gem_destroy(struct drm_gem_object *obj, struct > sg_table *sg); > + > +void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv); > +void drm_prime_destroy_file_private(struct drm_prime_file_private > *prime_fpriv); > +int drm_prime_insert_fd_handle_mapping(struct drm_prime_file_private > *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle); > +int drm_prime_lookup_fd_handle_mapping(struct drm_prime_file_private > *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle); > +void drm_prime_remove_fd_handle_mapping(struct drm_prime_file_private > *prime_fpriv, struct dma_buf *dma_buf); > + > ?#if DRM_DEBUG_CODE > ?extern int drm_vma_info(struct seq_file *m, void *data); > ?#endif > -- > 1.7.9.1 > > _______________________________________________ > dri-devel mailing list > dri-devel at lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/dri-devel