diff options
25 files changed, 588 insertions, 745 deletions
diff --git a/drivers/gpu/drm/vmwgfx/Kconfig b/drivers/gpu/drm/vmwgfx/Kconfig index c9ce47c448e0..a4fabe208d9f 100644 --- a/drivers/gpu/drm/vmwgfx/Kconfig +++ b/drivers/gpu/drm/vmwgfx/Kconfig @@ -4,6 +4,7 @@ config DRM_VMWGFX depends on DRM && PCI && MMU depends on X86 || ARM64 select DRM_TTM + select DRM_TTM_HELPER select MAPPING_DIRTY_HELPERS # Only needed for the transitional use of drm_crtc_init - can be removed # again once vmwgfx sets up the primary plane itself. diff --git a/drivers/gpu/drm/vmwgfx/Makefile b/drivers/gpu/drm/vmwgfx/Makefile index a2c2a5f5d85e..e9d13f155d8c 100644 --- a/drivers/gpu/drm/vmwgfx/Makefile +++ b/drivers/gpu/drm/vmwgfx/Makefile @@ -9,7 +9,8 @@ vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_hashtab.o vmwgfx_kms.o vmwgfx_d vmwgfx_cotable.o vmwgfx_so.o vmwgfx_binding.o vmwgfx_msg.o \ vmwgfx_simple_resource.o vmwgfx_va.o vmwgfx_blit.o \ vmwgfx_validation.o vmwgfx_page_dirty.o vmwgfx_streamoutput.o \ - vmwgfx_devcaps.o ttm_object.o vmwgfx_system_manager.o + vmwgfx_devcaps.o ttm_object.o vmwgfx_system_manager.o \ + vmwgfx_gem.o vmwgfx-$(CONFIG_DRM_FBDEV_EMULATION) += vmwgfx_fb.o vmwgfx-$(CONFIG_TRANSPARENT_HUGEPAGE) += vmwgfx_thp.o diff --git a/drivers/gpu/drm/vmwgfx/ttm_object.c b/drivers/gpu/drm/vmwgfx/ttm_object.c index 53de59ce30ca..26a55fef1ab5 100644 --- a/drivers/gpu/drm/vmwgfx/ttm_object.c +++ b/drivers/gpu/drm/vmwgfx/ttm_object.c @@ -50,6 +50,7 @@ #include <linux/atomic.h> #include <linux/module.h> #include "ttm_object.h" +#include "vmwgfx_drv.h" MODULE_IMPORT_NS(DMA_BUF); @@ -73,7 +74,7 @@ struct ttm_object_file { struct ttm_object_device *tdev; spinlock_t lock; struct list_head ref_list; - struct vmwgfx_open_hash ref_hash[TTM_REF_NUM]; + struct vmwgfx_open_hash ref_hash; struct kref refcount; }; @@ -124,7 +125,6 @@ struct ttm_ref_object { struct vmwgfx_hash_item hash; struct list_head head; struct kref kref; - enum ttm_ref_type ref_type; struct ttm_base_object *obj; struct ttm_object_file *tfile; }; @@ -160,9 +160,7 @@ int ttm_base_object_init(struct ttm_object_file *tfile, struct ttm_base_object *base, bool shareable, enum ttm_object_type object_type, - void (*refcount_release) (struct ttm_base_object **), - void (*ref_obj_release) (struct ttm_base_object *, - enum ttm_ref_type ref_type)) + void (*refcount_release) (struct ttm_base_object **)) { struct ttm_object_device *tdev = tfile->tdev; int ret; @@ -170,7 +168,6 @@ int ttm_base_object_init(struct ttm_object_file *tfile, base->shareable = shareable; base->tfile = ttm_object_file_ref(tfile); base->refcount_release = refcount_release; - base->ref_obj_release = ref_obj_release; base->object_type = object_type; kref_init(&base->refcount); idr_preload(GFP_KERNEL); @@ -182,7 +179,7 @@ int ttm_base_object_init(struct ttm_object_file *tfile, return ret; base->handle = ret; - ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL, false); + ret = ttm_ref_object_add(tfile, base, NULL, false); if (unlikely(ret != 0)) goto out_err1; @@ -246,7 +243,7 @@ struct ttm_base_object * ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint32_t key) { struct vmwgfx_hash_item *hash; - struct vmwgfx_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE]; + struct vmwgfx_open_hash *ht = &tfile->ref_hash; int ret; rcu_read_lock(); @@ -266,7 +263,7 @@ struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile, { struct ttm_base_object *base = NULL; struct vmwgfx_hash_item *hash; - struct vmwgfx_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE]; + struct vmwgfx_open_hash *ht = &tfile->ref_hash; int ret; rcu_read_lock(); @@ -297,57 +294,12 @@ ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key) return base; } -/** - * ttm_ref_object_exists - Check whether a caller has a valid ref object - * (has opened) a base object. - * - * @tfile: Pointer to a struct ttm_object_file identifying the caller. - * @base: Pointer to a struct base object. - * - * Checks wether the caller identified by @tfile has put a valid USAGE - * reference object on the base object identified by @base. - */ -bool ttm_ref_object_exists(struct ttm_object_file *tfile, - struct ttm_base_object *base) -{ - struct vmwgfx_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE]; - struct vmwgfx_hash_item *hash; - struct ttm_ref_object *ref; - - rcu_read_lock(); - if (unlikely(vmwgfx_ht_find_item_rcu(ht, base->handle, &hash) != 0)) - goto out_false; - - /* - * Verify that the ref object is really pointing to our base object. - * Our base object could actually be dead, and the ref object pointing - * to another base object with the same handle. - */ - ref = drm_hash_entry(hash, struct ttm_ref_object, hash); - if (unlikely(base != ref->obj)) - goto out_false; - - /* - * Verify that the ref->obj pointer was actually valid! - */ - rmb(); - if (unlikely(kref_read(&ref->kref) == 0)) - goto out_false; - - rcu_read_unlock(); - return true; - - out_false: - rcu_read_unlock(); - return false; -} - int ttm_ref_object_add(struct ttm_object_file *tfile, struct ttm_base_object *base, - enum ttm_ref_type ref_type, bool *existed, + bool *existed, bool require_existed) { - struct vmwgfx_open_hash *ht = &tfile->ref_hash[ref_type]; + struct vmwgfx_open_hash *ht = &tfile->ref_hash; struct ttm_ref_object *ref; struct vmwgfx_hash_item *hash; int ret = -EINVAL; @@ -382,7 +334,6 @@ int ttm_ref_object_add(struct ttm_object_file *tfile, ref->hash.key = base->handle; ref->obj = base; ref->tfile = tfile; - ref->ref_type = ref_type; kref_init(&ref->kref); spin_lock(&tfile->lock); @@ -411,27 +362,23 @@ ttm_ref_object_release(struct kref *kref) { struct ttm_ref_object *ref = container_of(kref, struct ttm_ref_object, kref); - struct ttm_base_object *base = ref->obj; struct ttm_object_file *tfile = ref->tfile; struct vmwgfx_open_hash *ht; - ht = &tfile->ref_hash[ref->ref_type]; + ht = &tfile->ref_hash; (void)vmwgfx_ht_remove_item_rcu(ht, &ref->hash); list_del(&ref->head); spin_unlock(&tfile->lock); - if (ref->ref_type != TTM_REF_USAGE && base->ref_obj_release) - base->ref_obj_release(base, ref->ref_type); - ttm_base_object_unref(&ref->obj); kfree_rcu(ref, rcu_head); spin_lock(&tfile->lock); } int ttm_ref_object_base_unref(struct ttm_object_file *tfile, - unsigned long key, enum ttm_ref_type ref_type) + unsigned long key) { - struct vmwgfx_open_hash *ht = &tfile->ref_hash[ref_type]; + struct vmwgfx_open_hash *ht = &tfile->ref_hash; struct ttm_ref_object *ref; struct vmwgfx_hash_item *hash; int ret; @@ -452,7 +399,6 @@ void ttm_object_file_release(struct ttm_object_file **p_tfile) { struct ttm_ref_object *ref; struct list_head *list; - unsigned int i; struct ttm_object_file *tfile = *p_tfile; *p_tfile = NULL; @@ -470,8 +416,7 @@ void ttm_object_file_release(struct ttm_object_file **p_tfile) } spin_unlock(&tfile->lock); - for (i = 0; i < TTM_REF_NUM; ++i) - vmwgfx_ht_remove(&tfile->ref_hash[i]); + vmwgfx_ht_remove(&tfile->ref_hash); ttm_object_file_unref(&tfile); } @@ -480,8 +425,6 @@ struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev, unsigned int hash_order) { struct ttm_object_file *tfile = kmalloc(sizeof(*tfile), GFP_KERNEL); - unsigned int i; - unsigned int j = 0; int ret; if (unlikely(tfile == NULL)) @@ -492,18 +435,13 @@ struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev, kref_init(&tfile->refcount); INIT_LIST_HEAD(&tfile->ref_list); - for (i = 0; i < TTM_REF_NUM; ++i) { - ret = vmwgfx_ht_create(&tfile->ref_hash[i], hash_order); - if (ret) { - j = i; - goto out_err; - } - } + ret = vmwgfx_ht_create(&tfile->ref_hash, hash_order); + if (ret) + goto out_err; return tfile; out_err: - for (i = 0; i < j; ++i) - vmwgfx_ht_remove(&tfile->ref_hash[i]); + vmwgfx_ht_remove(&tfile->ref_hash); kfree(tfile); @@ -526,7 +464,15 @@ ttm_object_device_init(unsigned int hash_order, if (ret != 0) goto out_no_object_hash; - idr_init_base(&tdev->idr, 1); + /* + * Our base is at VMWGFX_NUM_MOB + 1 because we want to create + * a seperate namespace for GEM handles (which are + * 1..VMWGFX_NUM_MOB) and the surface handles. Some ioctl's + * can take either handle as an argument so we want to + * easily be able to tell whether the handle refers to a + * GEM buffer or a surface. + */ + idr_init_base(&tdev->idr, VMWGFX_NUM_MOB + 1); tdev->ops = *ops; tdev->dmabuf_release = tdev->ops.release; tdev->ops.release = ttm_prime_dmabuf_release; @@ -647,7 +593,7 @@ int ttm_prime_fd_to_handle(struct ttm_object_file *tfile, prime = (struct ttm_prime_object *) dma_buf->priv; base = &prime->base; *handle = base->handle; - ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL, false); + ret = ttm_ref_object_add(tfile, base, NULL, false); dma_buf_put(dma_buf); @@ -741,7 +687,6 @@ out_unref: * @shareable: See ttm_base_object_init * @type: See ttm_base_object_init * @refcount_release: See ttm_base_object_init - * @ref_obj_release: See ttm_base_object_init * * Initializes an object which is compatible with the drm_prime model * for data sharing between processes and devices. @@ -749,9 +694,7 @@ out_unref: int ttm_prime_object_init(struct ttm_object_file *tfile, size_t size, struct ttm_prime_object *prime, bool shareable, enum ttm_object_type type, - void (*refcount_release) (struct ttm_base_object **), - void (*ref_obj_release) (struct ttm_base_object *, - enum ttm_ref_type ref_type)) + void (*refcount_release) (struct ttm_base_object **)) { mutex_init(&prime->mutex); prime->size = PAGE_ALIGN(size); @@ -760,6 +703,5 @@ int ttm_prime_object_init(struct ttm_object_file *tfile, size_t size, prime->refcount_release = refcount_release; return ttm_base_object_init(tfile, &prime->base, shareable, ttm_prime_type, - ttm_prime_refcount_release, - ref_obj_release); + ttm_prime_refcount_release); } diff --git a/drivers/gpu/drm/vmwgfx/ttm_object.h b/drivers/gpu/drm/vmwgfx/ttm_object.h index a0f2da1012ba..4c8700027c6d 100644 --- a/drivers/gpu/drm/vmwgfx/ttm_object.h +++ b/drivers/gpu/drm/vmwgfx/ttm_object.h @@ -45,28 +45,6 @@ #include "vmwgfx_hashtab.h" /** - * enum ttm_ref_type - * - * Describes what type of reference a ref object holds. - * - * TTM_REF_USAGE is a simple refcount on a base object. - * - * TTM_REF_SYNCCPU_READ is a SYNCCPU_READ reference on a - * buffer object. - * - * TTM_REF_SYNCCPU_WRITE is a SYNCCPU_WRITE reference on a - * buffer object. - * - */ - -enum ttm_ref_type { - TTM_REF_USAGE, - TTM_REF_SYNCCPU_READ, - TTM_REF_SYNCCPU_WRITE, - TTM_REF_NUM -}; - -/** * enum ttm_object_type * * One entry per ttm object type. @@ -76,7 +54,6 @@ enum ttm_ref_type { enum ttm_object_type { ttm_fence_type, - ttm_buffer_type, ttm_lock_type, ttm_prime_type, ttm_driver_type0 = 256, @@ -127,8 +104,6 @@ struct ttm_base_object { struct ttm_object_file *tfile; struct kref refcount; void (*refcount_release) (struct ttm_base_object **base); - void (*ref_obj_release) (struct ttm_base_object *base, - enum ttm_ref_type ref_type); u32 handle; enum ttm_object_type object_type; u32 shareable; @@ -177,11 +152,7 @@ extern int ttm_base_object_init(struct ttm_object_file *tfile, bool shareable, enum ttm_object_type type, void (*refcount_release) (struct ttm_base_object - **), - void (*ref_obj_release) (struct ttm_base_object - *, - enum ttm_ref_type - ref_type)); + **)); /** * ttm_base_object_lookup @@ -245,12 +216,9 @@ extern void ttm_base_object_unref(struct ttm_base_object **p_base); */ extern int ttm_ref_object_add(struct ttm_object_file *tfile, struct ttm_base_object *base, - enum ttm_ref_type ref_type, bool *existed, + bool *existed, bool require_existed); -extern bool ttm_ref_object_exists(struct ttm_object_file *tfile, - struct ttm_base_object *base); - /** * ttm_ref_object_base_unref * @@ -263,8 +231,7 @@ extern bool ttm_ref_object_exists(struct ttm_object_file *tfile, * will be unreferenced. */ extern int ttm_ref_object_base_unref(struct ttm_object_file *tfile, - unsigned long key, - enum ttm_ref_type ref_type); + unsigned long key); /** * ttm_object_file_init - initialize a struct ttm_object file @@ -328,10 +295,7 @@ extern int ttm_prime_object_init(struct ttm_object_file *tfile, bool shareable, enum ttm_object_type type, void (*refcount_release) - (struct ttm_base_object **), - void (*ref_obj_release) - (struct ttm_base_object *, - enum ttm_ref_type ref_type)); + (struct ttm_base_object **)); static inline enum ttm_object_type ttm_base_object_type(struct ttm_base_object *base) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c index bf9e9ff3be73..15fead85450c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c @@ -33,18 +33,6 @@ /** - * struct vmw_user_buffer_object - User-space-visible buffer object - * - * @prime: The prime object providing user visibility. - * @vbo: The struct vmw_buffer_object - */ -struct vmw_user_buffer_object { - struct ttm_prime_object prime; - struct vmw_buffer_object vbo; -}; - - -/** * vmw_buffer_object - Convert a struct ttm_buffer_object to a struct * vmw_buffer_object. * @@ -60,23 +48,6 @@ vmw_buffer_object(struct ttm_buffer_object *bo) /** - * vmw_user_buffer_object - Convert a struct ttm_buffer_object to a struct - * vmw_user_buffer_object. - * - * @bo: Pointer to the TTM buffer object. - * Return: Pointer to the struct vmw_buffer_object embedding the TTM buffer - * object. - */ -static struct vmw_user_buffer_object * -vmw_user_buffer_object(struct ttm_buffer_object *bo) -{ - struct vmw_buffer_object *vmw_bo = vmw_buffer_object(bo); - - return container_of(vmw_bo, struct vmw_user_buffer_object, vbo); -} - - -/** * vmw_bo_pin_in_placement - Validate a buffer to placement. * * @dev_priv: Driver private. @@ -403,27 +374,10 @@ void vmw_bo_bo_free(struct ttm_buffer_object *bo) WARN_ON(vmw_bo->dirty); WARN_ON(!RB_EMPTY_ROOT(&vmw_bo->res_tree)); vmw_bo_unmap(vmw_bo); - dma_resv_fini(&bo->base._resv); + drm_gem_object_release(&bo->base); kfree(vmw_bo); } - -/** - * vmw_user_bo_destroy - vmw buffer object destructor - * - * @bo: Pointer to the embedded struct ttm_buffer_object - */ -static void vmw_user_bo_destroy(struct ttm_buffer_object *bo) -{ - struct vmw_user_buffer_object *vmw_user_bo = vmw_user_buffer_object(bo); - struct vmw_buffer_object *vbo = &vmw_user_bo->vbo; - - WARN_ON(vbo->dirty); - WARN_ON(!RB_EMPTY_ROOT(&vbo->res_tree)); - vmw_bo_unmap(vbo); - ttm_prime_object_kfree(vmw_user_bo, prime); -} - /** * vmw_bo_create_kernel - Create a pinned BO for internal kernel use. * @@ -443,15 +397,16 @@ int vmw_bo_create_kernel(struct vmw_private *dev_priv, unsigned long size, .no_wait_gpu = false }; struct ttm_buffer_object *bo; + struct drm_device *vdev = &dev_priv->drm; int ret; bo = kzalloc(sizeof(*bo), GFP_KERNEL); if (unlikely(!bo)) return -ENOMEM; - bo->base.size = size; - dma_resv_init(&bo->base._resv); - drm_vma_node_reset(&bo->base.vma_node); + size = ALIGN(size, PAGE_SIZE); + + drm_gem_private_object_init(vdev, &bo->base, size); ret = ttm_bo_init_reserved(&dev_priv->bdev, bo, size, ttm_bo_type_kernel, placement, 0, @@ -470,6 +425,33 @@ error_free: return ret; } +int vmw_bo_create(struct vmw_private *vmw, + size_t size, struct ttm_placement *placement, + bool interruptible, bool pin, + void (*bo_free)(struct ttm_buffer_object *bo), + struct vmw_buffer_object **p_bo) +{ + int ret; + + *p_bo = kmalloc(sizeof(**p_bo), GFP_KERNEL); + if (unlikely(!*p_bo)) { + DRM_ERROR("Failed to allocate a buffer.\n"); + return -ENOMEM; + } + + ret = vmw_bo_init(vmw, *p_bo, size, + placement, interruptible, pin, + bo_free); + if (unlikely(ret != 0)) + goto out_error; + + return ret; +out_error: + kfree(*p_bo); + *p_bo = NULL; + return ret; +} + /** * vmw_bo_init - Initialize a vmw buffer object * @@ -495,22 +477,21 @@ int vmw_bo_init(struct vmw_private *dev_priv, .no_wait_gpu = false }; struct ttm_device *bdev = &dev_priv->bdev; + struct drm_device *vdev = &dev_priv->drm; int ret; - bool user = (bo_free == &vmw_user_bo_destroy); - WARN_ON_ONCE(!bo_free && (!user && (bo_free != vmw_bo_bo_free))); + WARN_ON_ONCE(!bo_free); memset(vmw_bo, 0, sizeof(*vmw_bo)); BUILD_BUG_ON(TTM_MAX_BO_PRIORITY <= 3); vmw_bo->base.priority = 3; vmw_bo->res_tree = RB_ROOT; - - vmw_bo->base.base.size = size; - dma_resv_init(&vmw_bo->base.base._resv); - drm_vma_node_reset(&vmw_bo->base.base.vma_node); + size = ALIGN(size, PAGE_SIZE); + drm_gem_private_object_init(vdev, &vmw_bo->base.base, size); ret = ttm_bo_init_reserved(bdev, &vmw_bo->base, size, - ttm_bo_type_device, placement, + ttm_bo_type_device, + placement, 0, &ctx, NULL, NULL, bo_free); if (unlikely(ret)) { return ret; @@ -519,159 +500,16 @@ int vmw_bo_init(struct vmw_private *dev_priv, if (pin) ttm_bo_pin(&vmw_bo->base); ttm_bo_unreserve(&vmw_bo->base); - return 0; -} - - -/** - * vmw_user_bo_release - TTM reference base object release callback for - * vmw user buffer objects - * - * @p_base: The TTM base object pointer about to be unreferenced. - * - * Clears the TTM base object pointer and drops the reference the - * base object has on the underlying struct vmw_buffer_object. - */ -static void vmw_user_bo_release(struct ttm_base_object **p_base) -{ - struct vmw_user_buffer_object *vmw_user_bo; - struct ttm_base_object *base = *p_base; - - *p_base = NULL; - - if (unlikely(base == NULL)) - return; - - vmw_user_bo = container_of(base, struct vmw_user_buffer_object, - prime.base); - ttm_bo_put(&vmw_user_bo->vbo.base); -} - - -/** - * vmw_user_bo_ref_obj_release - TTM synccpu reference object release callback - * for vmw user buffer objects - * - * @base: Pointer to the TTM base object - * @ref_type: Reference type of the reference reaching zero. - * - * Called when user-space drops its last synccpu reference on the buffer - * object, Either explicitly or as part of a cleanup file close. - */ -static void vmw_user_bo_ref_obj_release(struct ttm_base_object *base, - enum ttm_ref_type ref_type) -{ - struct vmw_user_buffer_object *user_bo; - - user_bo = container_of(base, struct vmw_user_buffer_object, prime.base); - - switch (ref_type) { - case TTM_REF_SYNCCPU_WRITE: - atomic_dec(&user_bo->vbo.cpu_writers); - break; - default: - WARN_ONCE(true, "Undefined buffer object reference release.\n"); - } -} - - -/** - * vmw_user_bo_alloc - Allocate a user buffer object - * - * @dev_priv: Pointer to a struct device private. - * @tfile: Pointer to a struct ttm_object_file on which to register the user - * object. - * @size: Size of the buffer object. - * @shareable: Boolean whether the buffer is shareable with other open files. - * @handle: Pointer to where the handle value should be assigned. - * @p_vbo: Pointer to where the refcounted struct vmw_buffer_object pointer - * should be assigned. - * @p_base: The TTM base object pointer about to be allocated. - * Return: Zero on success, negative error code on error. - */ -int vmw_user_bo_alloc(struct vmw_private *dev_priv, - struct ttm_object_file *tfile, - uint32_t size, - bool shareable, - uint32_t *handle, - struct vmw_buffer_object **p_vbo, - struct ttm_base_object **p_base) -{ - struct vmw_user_buffer_object *user_bo; - int ret; - - user_bo = kzalloc(sizeof(*user_bo), GFP_KERNEL); - if (unlikely(!user_bo)) { - DRM_ERROR("Failed to allocate a buffer.\n"); - return -ENOMEM; - } - - ret = vmw_bo_init(dev_priv, &user_bo->vbo, size, - (dev_priv->has_mob) ? - &vmw_sys_placement : - &vmw_vram_sys_placement, true, false, - &vmw_user_bo_destroy); - if (unlikely(ret != 0)) - return ret; - - ttm_bo_get(&user_bo->vbo.base); - ret = ttm_prime_object_init(tfile, - size, - &user_bo->prime, - shareable, - ttm_buffer_type, - &vmw_user_bo_release, - &vmw_user_bo_ref_obj_release); - if (unlikely(ret != 0)) { - ttm_bo_put(&user_bo->vbo.base); - goto out_no_base_object; - } - - *p_vbo = &user_bo->vbo; - if (p_base) { - *p_base = &user_bo->prime.base; - kref_get(&(*p_base)->refcount); - } - *handle = user_bo->prime.base.handle; - -out_no_base_object: - return ret; -} - - -/** - * vmw_user_bo_verify_access - verify access permissions on this - * buffer object. - * - * @bo: Pointer to the buffer object being accessed - * @tfile: Identifying the caller. - */ -int vmw_user_bo_verify_access(struct ttm_buffer_object *bo, - struct ttm_object_file *tfile) -{ - struct vmw_user_buffer_object *vmw_user_bo; - - if (unlikely(bo->destroy != vmw_user_bo_destroy)) - return -EPERM; - vmw_user_bo = vmw_user_buffer_object(bo); - - /* Check that the caller has opened the object. */ - if (likely(ttm_ref_object_exists(tfile, &vmw_user_bo->prime.base))) - return 0; - - DRM_ERROR("Could not grant buffer access.\n"); - return -EPERM; + return 0; } - /** - * vmw_user_bo_synccpu_grab - Grab a struct vmw_user_buffer_object for cpu + * vmw_user_bo_synccpu_grab - Grab a struct vmw_buffer_object for cpu * access, idling previous GPU operations on the buffer and optionally * blocking it for further command submissions. * - * @user_bo: Pointer to the buffer object being grabbed for CPU access - * @tfile: Identifying the caller. + * @vmw_bo: Pointer to the buffer object being grabbed for CPU access * @flags: Flags indicating how the grab should be performed. * Return: Zero on success, Negative error code on error. In particular, * -EBUSY will be returned if a dontblock operation is requested and the @@ -680,13 +518,11 @@ int vmw_user_bo_verify_access(struct ttm_buffer_object *bo, * * A blocking grab will be automatically released when @tfile is closed. */ -static int vmw_user_bo_synccpu_grab(struct vmw_user_buffer_object *user_bo, - struct ttm_object_file *tfile, +static int vmw_user_bo_synccpu_grab(struct vmw_buffer_object *vmw_bo, uint32_t flags) { bool nonblock = !!(flags & drm_vmw_synccpu_dontblock); - struct ttm_buffer_object *bo = &user_bo->vbo.base; - bool existed; + struct ttm_buffer_object *bo = &vmw_bo->base; int ret; if (flags & drm_vmw_synccpu_allow_cs) { @@ -708,17 +544,12 @@ static int vmw_user_bo_synccpu_grab(struct vmw_user_buffer_object *user_bo, ret = ttm_bo_wait(bo, true, nonblock); if (likely(ret == 0)) - atomic_inc(&user_bo->vbo.cpu_writers); + atomic_inc(&vmw_bo->cpu_writers); ttm_bo_unreserve(bo); if (unlikely(ret != 0)) return ret; - ret = ttm_ref_object_add(tfile, &user_bo->prime.base, - TTM_REF_SYNCCPU_WRITE, &existed, false); - if (ret != 0 || existed) - atomic_dec(&user_bo->vbo.cpu_writers); - return ret; } @@ -726,19 +557,23 @@ static int vmw_user_bo_synccpu_grab(struct vmw_user_buffer_object *user_bo, * vmw_user_bo_synccpu_release - Release a previous grab for CPU access, * and unblock command submission on the buffer if blocked. * + * @filp: Identifying the caller. * @handle: Handle identifying the buffer object. - * @tfile: Identifying the caller. * @flags: Flags indicating the type of release. */ -static int vmw_user_bo_synccpu_release(uint32_t handle, - struct ttm_object_file *tfile, - uint32_t flags) +static int vmw_user_bo_synccpu_release(struct drm_file *filp, + uint32_t handle, + uint32_t flags) { - if (!(flags & drm_vmw_synccpu_allow_cs)) - return ttm_ref_object_base_unref(tfile, handle, - TTM_REF_SYNCCPU_WRITE); + struct vmw_buffer_object *vmw_bo; + int ret = vmw_user_bo_lookup(filp, handle, &vmw_bo); - return 0; + if (!(flags & drm_vmw_synccpu_allow_cs)) { + atomic_dec(&vmw_bo->cpu_writers); + } + ttm_bo_put(&vmw_bo->base); + + return ret; } @@ -760,9 +595,6 @@ int vmw_user_bo_synccpu_ioctl(struct drm_device *dev, void *data, struct drm_vmw_synccpu_arg *arg = (struct drm_vmw_synccpu_arg *) data; struct vmw_buffer_object *vbo; - struct vmw_user_buffer_object *user_bo; - struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; - struct ttm_base_object *buffer_base; int ret; if ((arg->flags & (drm_vmw_synccpu_read | drm_vmw_synccpu_write)) == 0 @@ -775,16 +607,12 @@ int vmw_user_bo_synccpu_ioctl(struct drm_device *dev, void *data, switch (arg->op) { case drm_vmw_synccpu_grab: - ret = vmw_user_bo_lookup(tfile, arg->handle, &vbo, - &buffer_base); + ret = vmw_user_bo_lookup(file_priv, arg->handle, &vbo); if (unlikely(ret != 0)) return ret; - user_bo = container_of(vbo, struct vmw_user_buffer_object, - vbo); - ret = vmw_user_bo_synccpu_grab(user_bo, tfile, arg->flags); + ret = vmw_user_bo_synccpu_grab(vbo, arg->flags); vmw_bo_unreference(&vbo); - ttm_base_object_unref(&buffer_base); if (unlikely(ret != 0 && ret != -ERESTARTSYS && ret != -EBUSY)) { DRM_ERROR("Failed synccpu grab on handle 0x%08x.\n", @@ -793,7 +621,8 @@ int vmw_user_bo_synccpu_ioctl(struct drm_device *dev, void *data, } break; case drm_vmw_synccpu_release: - ret = vmw_user_bo_synccpu_release(arg->handle, tfile, + ret = vmw_user_bo_synccpu_release(file_priv, + arg->handle, arg->flags); if (unlikely(ret != 0)) { DRM_ERROR("Failed synccpu release on handle 0x%08x.\n", @@ -809,50 +638,6 @@ int vmw_user_bo_synccpu_ioctl(struct drm_device *dev, void *data, return 0; } - -/** - * vmw_bo_alloc_ioctl - ioctl function implementing the buffer object - * allocation functionality. - * - * @dev: Identifies the drm device. - * @data: Pointer to the ioctl argument. - * @file_priv: Identifies the caller. - * Return: Zero on success, negative error code on error. - * - * This function checks the ioctl arguments for validity and allocates a - * struct vmw_user_buffer_object bo. - */ -int vmw_bo_alloc_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct vmw_private *dev_priv = vmw_priv(dev); - union drm_vmw_alloc_dmabuf_arg *arg = - (union drm_vmw_alloc_dmabuf_arg *)data; - struct drm_vmw_alloc_dmabuf_req *req = &arg->req; - struct drm_vmw_dmabuf_rep *rep = &arg->rep; - struct vmw_buffer_object *vbo; - uint32_t handle; - int ret; - - ret = vmw_user_bo_alloc(dev_priv, vmw_fpriv(file_priv)->tfile, - req->size, false, &handle, &vbo, - NULL); - if (unlikely(ret != 0)) - goto out_no_bo; - - rep->handle = handle; - rep->map_handle = drm_vma_node_offset_addr(&vbo->base.base.vma_node); - rep->cur_gmr_id = handle; - rep->cur_gmr_offset = 0; - - vmw_bo_unreference(&vbo); - -out_no_bo: - - return ret; -} - - /** * vmw_bo_unref_ioctl - Generic handle close ioctl. * @@ -870,65 +655,48 @@ int vmw_bo_unref_ioctl(struct drm_device *dev, void *data, struct drm_vmw_unref_dmabuf_arg *arg = (struct drm_vmw_unref_dmabuf_arg *)data; - return ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile, - arg->handle, - TTM_REF_USAGE); + drm_gem_handle_delete(file_priv, arg->handle); + return 0; } /** * vmw_user_bo_lookup - Look up a vmw user buffer object from a handle. * - * @tfile: The TTM object file the handle is registered with. + * @filp: The file the handle is registered with. * @handle: The user buffer object handle * @out: Pointer to a where a pointer to the embedded * struct vmw_buffer_object should be placed. - * @p_base: Pointer to where a pointer to the TTM base object should be - * placed, or NULL if no such pointer is required. * Return: Zero on success, Negative error code on error. * - * Both the output base object pointer and the vmw buffer object pointer - * will be refcounted. + * The vmw buffer object pointer will be refcounted. */ -int vmw_user_bo_lookup(struct ttm_object_file *tfile, - uint32_t handle, struct vmw_buffer_object **out, - struct ttm_base_object **p_base) +int vmw_user_bo_lookup(struct drm_file *filp, + uint32_t handle, + struct vmw_buffer_object **out) { - struct vmw_user_buffer_object *vmw_user_bo; - struct ttm_base_object *base; + struct drm_gem_object *gobj; - base = ttm_base_object_lookup(tfile, handle); - if (unlikely(base == NULL)) { + gobj = drm_gem_object_lookup(filp, handle); + if (!gobj) { DRM_ERROR("Invalid buffer object handle 0x%08lx.\n", (unsigned long)handle); return -ESRCH; } - if (unlikely(ttm_base_object_type(base) != ttm_buffer_type)) { - ttm_base_object_unref(&base); - DRM_ERROR("Invalid buffer object handle 0x%08lx.\n", - (unsigned long)handle); - return -EINVAL; - } - - vmw_user_bo = container_of(base, struct vmw_user_buffer_object, - prime.base); - ttm_bo_get(&vmw_user_bo->vbo.base); - if (p_base) - *p_base = base; - else - ttm_base_object_unref(&base); - *out = &vmw_user_bo->vbo; + *out = gem_to_vmw_bo(gobj); + ttm_bo_get(&(*out)->base); + drm_gem_object_put(gobj); return 0; } /** * vmw_user_bo_noref_lookup - Look up a vmw user buffer object without reference - * @tfile: The TTM object file the handle is registered with. + * @filp: The TTM object file the handle is registered with. * @handle: The user buffer object handle. * - * This function looks up a struct vmw_user_bo and returns a pointer to the + * This function looks up a struct vmw_bo and returns a pointer to the * struct vmw_buffer_object it derives from without refcounting the pointer. * The returned pointer is only valid until vmw_user_bo_noref_release() is * called, and the object pointed to by the returned pointer may be doomed. @@ -941,52 +709,23 @@ int vmw_user_bo_lookup(struct ttm_object_file *tfile, * error pointer on failure. */ struct vmw_buffer_object * -vmw_user_bo_noref_lookup(struct ttm_object_file *tfile, u32 handle) +vmw_user_bo_noref_lookup(struct drm_file *filp, u32 handle) { - struct vmw_user_buffer_object *vmw_user_bo; - struct ttm_base_object *base; + struct vmw_buffer_object *vmw_bo; + struct ttm_buffer_object *bo; + struct drm_gem_object *gobj = drm_gem_object_lookup(filp, handle); - base = ttm_base_object_noref_lookup(tfile, handle); - if (!base) { + if (!gobj) { DRM_ERROR("Invalid buffer object handle 0x%08lx.\n", (unsigned long)handle); return ERR_PTR(-ESRCH); } + vmw_bo = gem_to_vmw_bo(gobj); + bo = ttm_bo_get_unless_zero(&vmw_bo->base); + vmw_bo = vmw_buffer_object(bo); + drm_gem_object_put(gobj); - if (unlikely(ttm_base_object_type(base) != ttm_buffer_type)) { - ttm_base_object_noref_release(); - DRM_ERROR("Invalid buffer object handle 0x%08lx.\n", - (unsigned long)handle); - return ERR_PTR(-EINVAL); - } - - vmw_user_bo = container_of(base, struct vmw_user_buffer_object, - prime.base); - return &vmw_user_bo->vbo; -} - -/** - * vmw_user_bo_reference - Open a handle to a vmw user buffer object. - * - * @tfile: The TTM object file to register the handle with. - * @vbo: The embedded vmw buffer object. - * @handle: Pointer to where the new handle should be placed. - * Return: Zero on success, Negative error code on error. - */ -int vmw_user_bo_reference(struct ttm_object_file *tfile, - struct vmw_buffer_object *vbo, - uint32_t *handle) -{ - struct vmw_user_buffer_object *user_bo; - - if (vbo->base.destroy != vmw_user_bo_destroy) - return -EINVAL; - - user_bo = container_of(vbo, struct vmw_user_buffer_object, vbo); - - *handle = user_bo->prime.base.handle; - return ttm_ref_object_add(tfile, &user_bo->prime.base, - TTM_REF_USAGE, NULL, false); + return vmw_bo; } @@ -1040,68 +779,15 @@ int vmw_dumb_create(struct drm_file *file_priv, int ret; args->pitch = args->width * ((args->bpp + 7) / 8); - args->size = args->pitch * args->height; + args->size = ALIGN(args->pitch * args->height, PAGE_SIZE); - ret = vmw_user_bo_alloc(dev_priv, vmw_fpriv(file_priv)->tfile, - args->size, false, &args->handle, - &vbo, NULL); - if (unlikely(ret != 0)) - goto out_no_bo; + ret = vmw_gem_object_create_with_handle(dev_priv, file_priv, + args->size, &args->handle, + &vbo); - vmw_bo_unreference(&vbo); -out_no_bo: return ret; } - -/** - * vmw_dumb_map_offset - Return the address space offset of a dumb buffer - * - * @file_priv: Pointer to a struct drm_file identifying the caller. - * @dev: Pointer to the drm device. - * @handle: Handle identifying the dumb buffer. - * @offset: The address space offset returned. - * Return: Zero on success, negative error code on failure. - * - * This is a driver callback for the core drm dumb_map_offset functionality. - */ -int vmw_dumb_map_offset(struct drm_file *file_priv, - struct drm_device *dev, uint32_t handle, - uint64_t *offset) -{ - struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; - struct vmw_buffer_object *out_buf; - int ret; - - ret = vmw_user_bo_lookup(tfile, handle, &out_buf, NULL); - if (ret != 0) - return -EINVAL; - - *offset = drm_vma_node_offset_addr(&out_buf->base.base.vma_node); - vmw_bo_unreference(&out_buf); - return 0; -} - - -/** - * vmw_dumb_destroy - Destroy a dumb boffer - * - * @file_priv: Pointer to a struct drm_file identifying the caller. - * @dev: Pointer to the drm device. - * @handle: Handle identifying the dumb buffer. - * Return: Zero on success, negative error code on failure. - * - * This is a driver callback for the core drm dumb_destroy functionality. - */ -int vmw_dumb_destroy(struct drm_file *file_priv, - struct drm_device *dev, - uint32_t handle) -{ - return ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile, - handle, TTM_REF_USAGE); -} - - /** * vmw_bo_swap_notify - swapout notify callback. * @@ -1110,8 +796,7 @@ int vmw_dumb_destroy(struct drm_file *file_priv, void vmw_bo_swap_notify(struct ttm_buffer_object *bo) { /* Is @bo embedded in a struct vmw_buffer_object? */ - if (bo->destroy != vmw_bo_bo_free && - bo->destroy != vmw_user_bo_destroy) + if (vmw_bo_is_vmw_bo(bo)) return; /* Kill any cached kernel maps before swapout */ @@ -1135,8 +820,7 @@ void vmw_bo_move_notify(struct ttm_buffer_object *bo, struct vmw_buffer_object *vbo; /* Make sure @bo is embedded in a struct vmw_buffer_object? */ - if (bo->destroy != vmw_bo_bo_free && - bo->destroy != vmw_user_bo_destroy) + if (vmw_bo_is_vmw_bo(bo)) return; vbo = container_of(bo, struct vmw_buffer_object, base); @@ -1157,3 +841,22 @@ void vmw_bo_move_notify(struct ttm_buffer_object *bo, if (mem->mem_type != VMW_PL_MOB && bo->resource->mem_type == VMW_PL_MOB) vmw_resource_unbind_list(vbo); } + +/** + * vmw_bo_is_vmw_bo - check if the buffer object is a &vmw_buffer_object + * @bo: buffer object to be checked + * + * Uses destroy function associated with the object to determine if this is + * a &vmw_buffer_object. + * + * Returns: + * true if the object is of &vmw_buffer_object type, false if not. + */ +bool vmw_bo_is_vmw_bo(struct ttm_buffer_object *bo) +{ + if (bo->destroy == &vmw_bo_bo_free || + bo->destroy == &vmw_gem_destroy) + return true; + + return false; +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c index 713321d0c2c6..e0f48cd9529b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c @@ -715,7 +715,7 @@ int vmw_context_destroy_ioctl(struct drm_device *dev, void *data, struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data; struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; - return ttm_ref_object_base_unref(tfile, arg->cid, TTM_REF_USAGE); + return ttm_ref_object_base_unref(tfile, arg->cid); } static int vmw_context_define(struct drm_device *dev, void *data, @@ -754,7 +754,7 @@ static int vmw_context_define(struct drm_device *dev, void *data, tmp = vmw_resource_reference(&ctx->res); ret = ttm_base_object_init(tfile, &ctx->base, false, VMW_RES_CONTEXT, - &vmw_user_context_base_release, NULL); + &vmw_user_context_base_release); if (unlikely(ret != 0)) { vmw_resource_unreference(&tmp); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c index 7bdd52678362..16f986b6cbea 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c @@ -407,12 +407,8 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size) * for the new COTable. Initially pin the buffer object to make sure * we can use tryreserve without failure. */ - buf = kzalloc(sizeof(*buf), GFP_KERNEL); - if (!buf) - return -ENOMEM; - - ret = vmw_bo_init(dev_priv, buf, new_size, &vmw_mob_placement, - true, true, vmw_bo_bo_free); + ret = vmw_bo_create(dev_priv, new_size, &vmw_mob_placement, + true, true, vmw_bo_bo_free, &buf); if (ret) { DRM_ERROR("Failed initializing new cotable MOB.\n"); return ret; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index acdd0c9d7750..71b6b1219ce1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -34,6 +34,7 @@ #include <drm/drm_drv.h> #include <drm/drm_ioctl.h> #include <drm/drm_sysfs.h> +#include <drm/drm_gem_ttm_helper.h> #include <drm/ttm/ttm_bo_driver.h> #include <drm/ttm/ttm_range_manager.h> #include <drm/ttm/ttm_placement.h> @@ -162,7 +163,7 @@ static const struct drm_ioctl_desc vmw_ioctls[] = { DRM_IOCTL_DEF_DRV(VMW_GET_PARAM, vmw_getparam_ioctl, DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(VMW_ALLOC_DMABUF, vmw_bo_alloc_ioctl, + DRM_IOCTL_DEF_DRV(VMW_ALLOC_DMABUF, vmw_gem_object_create_ioctl, DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(VMW_UNREF_DMABUF, vmw_bo_unref_ioctl, DRM_RENDER_ALLOW), @@ -396,13 +397,9 @@ static int vmw_dummy_query_bo_create(struct vmw_private *dev_priv) * immediately succeed. This is because we're the only * user of the bo currently. */ - vbo = kzalloc(sizeof(*vbo), GFP_KERNEL); - if (!vbo) - return -ENOMEM; - - ret = vmw_bo_init(dev_priv, vbo, PAGE_SIZE, - &vmw_sys_placement, false, true, - &vmw_bo_bo_free); + ret = vmw_bo_create(dev_priv, PAGE_SIZE, + &vmw_sys_placement, false, true, + &vmw_bo_bo_free, &vbo); if (unlikely(ret != 0)) return ret; @@ -1578,7 +1575,7 @@ static const struct file_operations vmwgfx_driver_fops = { static const struct drm_driver driver = { .driver_features = - DRIVER_MODESET | DRIVER_RENDER | DRIVER_ATOMIC, + DRIVER_MODESET | DRIVER_RENDER | DRIVER_ATOMIC | DRIVER_GEM, .ioctls = vmw_ioctls, .num_ioctls = ARRAY_SIZE(vmw_ioctls), .master_set = vmw_master_set, @@ -1587,8 +1584,7 @@ static const struct drm_driver driver = { .postclose = vmw_postclose, .dumb_create = vmw_dumb_create, - .dumb_map_offset = vmw_dumb_map_offset, - .dumb_destroy = vmw_dumb_destroy, + .dumb_map_offset = drm_gem_ttm_dumb_map_offset, .prime_fd_to_handle = vmw_prime_fd_to_handle, .prime_handle_to_fd = vmw_prime_handle_to_fd, @@ -1642,6 +1638,8 @@ static int vmw_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret) goto out_unload; + vmw_debugfs_gem_init(vmw); + return 0; out_unload: vmw_driver_unload(&vmw->drm); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 5599894534cf..daa4501d17ec 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -361,6 +361,19 @@ struct vmw_piter { dma_addr_t (*dma_address)(struct vmw_piter *); }; + +struct vmw_ttm_tt { + struct ttm_tt dma_ttm; + struct vmw_private *dev_priv; + int gmr_id; + struct vmw_mob *mob; + int mem_type; + struct sg_table sgt; + struct vmw_sg_table vsgt; + bool mapped; + bool bound; +}; + /* * enum vmw_display_unit_type - Describes the display unit */ @@ -411,6 +424,7 @@ struct vmw_sw_context{ bool res_ht_initialized; bool kernel; struct vmw_fpriv *fp; + struct drm_file *filp; uint32_t *cmd_bounce; uint32_t cmd_bounce_size; struct vmw_buffer_object *cur_query_bo; @@ -643,6 +657,11 @@ struct vmw_private { #endif }; +static inline struct vmw_buffer_object *gem_to_vmw_bo(struct drm_gem_object *gobj) +{ + return container_of((gobj), struct vmw_buffer_object, base.base); +} + static inline struct vmw_surface *vmw_res_to_srf(struct vmw_resource *res) { return container_of(res, struct vmw_surface, res); @@ -765,7 +784,7 @@ extern int vmw_resource_reserve(struct vmw_resource *res, bool interruptible, bool no_backup); extern bool vmw_resource_needs_backup(const struct vmw_resource *res); extern int vmw_user_lookup_handle(struct vmw_private *dev_priv, - struct ttm_object_file *tfile, + struct drm_file *filp, uint32_t handle, struct vmw_surface **out_surf, struct vmw_buffer_object **out_buf); @@ -831,6 +850,7 @@ static inline void vmw_user_resource_noref_release(void) /** * Buffer object helper functions - vmwgfx_bo.c */ +extern bool vmw_bo_is_vmw_bo(struct ttm_buffer_object *bo); extern int vmw_bo_pin_in_placement(struct vmw_private *vmw_priv, struct vmw_buffer_object *bo, struct ttm_placement *placement, @@ -855,32 +875,23 @@ extern int vmw_bo_create_kernel(struct vmw_private *dev_priv, unsigned long size, struct ttm_placement *placement, struct ttm_buffer_object **p_bo); +extern int vmw_bo_create(struct vmw_private *dev_priv, + size_t size, struct ttm_placement *placement, + bool interruptible, bool pin, + void (*bo_free)(struct ttm_buffer_object *bo), + struct vmw_buffer_object **p_bo); extern int vmw_bo_init(struct vmw_private *dev_priv, struct vmw_buffer_object *vmw_bo, size_t size, struct ttm_placement *placement, bool interruptible, bool pin, void (*bo_free)(struct ttm_buffer_object *bo)); -extern int vmw_user_bo_verify_access(struct ttm_buffer_object *bo, - struct ttm_object_file *tfile); -extern int vmw_user_bo_alloc(struct vmw_private *dev_priv, - struct ttm_object_file *tfile, - uint32_t size, - bool shareable, - uint32_t *handle, - struct vmw_buffer_object **p_dma_buf, - struct ttm_base_object **p_base); -extern int vmw_user_bo_reference(struct ttm_object_file *tfile, - struct vmw_buffer_object *dma_buf, - uint32_t *handle); -extern int vmw_bo_alloc_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); extern int vmw_bo_unref_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int vmw_user_bo_synccpu_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int vmw_user_bo_lookup(struct ttm_object_file *tfile, - uint32_t id, struct vmw_buffer_object **out, - struct ttm_base_object **base); +extern int vmw_user_bo_lookup(struct drm_file *filp, + uint32_t handle, + struct vmw_buffer_object **out); extern void vmw_bo_fence_single(struct ttm_buffer_object *bo, struct vmw_fence_obj *fence); extern void *vmw_bo_map_and_cache(struct vmw_buffer_object *vbo); @@ -889,16 +900,7 @@ extern void vmw_bo_move_notify(struct ttm_buffer_object *bo, struct ttm_resource *mem); extern void vmw_bo_swap_notify(struct ttm_buffer_object *bo); extern struct vmw_buffer_object * -vmw_user_bo_noref_lookup(struct ttm_object_file *tfile, u32 handle); - -/** - * vmw_user_bo_noref_release - release a buffer object pointer looked up - * without reference - */ -static inline void vmw_user_bo_noref_release(void) -{ - ttm_base_object_noref_release(); -} +vmw_user_bo_noref_lookup(struct drm_file *filp, u32 handle); /** * vmw_bo_adjust_prio - Adjust the buffer object eviction priority @@ -950,6 +952,19 @@ static inline void vmw_bo_prio_del(struct vmw_buffer_object *vbo, int prio) } /** + * GEM related functionality - vmwgfx_gem.c + */ +extern int vmw_gem_object_create_with_handle(struct vmw_private *dev_priv, + struct drm_file *filp, + uint32_t size, + uint32_t *handle, + struct vmw_buffer_object **p_vbo); +extern int vmw_gem_object_create_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp); +extern void vmw_gem_destroy(struct ttm_buffer_object *bo); +extern void vmw_debugfs_gem_init(struct vmw_private *vdev); + +/** * Misc Ioctl functionality - vmwgfx_ioctl.c */ @@ -1212,13 +1227,6 @@ void vmw_kms_lost_device(struct drm_device *dev); int vmw_dumb_create(struct drm_file *file_priv, struct drm_device *dev, struct drm_mode_create_dumb *args); - -int vmw_dumb_map_offset(struct drm_file *file_priv, - struct drm_device *dev, uint32_t handle, - uint64_t *offset); -int vmw_dumb_destroy(struct drm_file *file_priv, - struct drm_device *dev, - uint32_t handle); extern int vmw_resource_pin(struct vmw_resource *res, bool interruptible); extern void vmw_resource_unpin(struct vmw_resource *res); extern enum vmw_res_type vmw_res_type(const struct vmw_resource *res); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index cfe3edcf2cf2..fde26360e066 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -1171,14 +1171,13 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv, int ret; vmw_validation_preload_bo(sw_context->ctx); - vmw_bo = vmw_user_bo_noref_lookup(sw_context->fp->tfile, handle); - if (IS_ERR(vmw_bo)) { + vmw_bo = vmw_user_bo_noref_lookup(sw_context->filp, handle); + if (IS_ERR_OR_NULL(vmw_bo)) { VMW_DEBUG_USER("Could not find or use MOB buffer.\n"); return PTR_ERR(vmw_bo); } - ret = vmw_validation_add_bo(sw_context->ctx, vmw_bo, true, false); - vmw_user_bo_noref_release(); + ttm_bo_put(&vmw_bo->base); if (unlikely(ret != 0)) return ret; @@ -1226,14 +1225,13 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv, int ret; vmw_validation_preload_bo(sw_context->ctx); - vmw_bo = vmw_user_bo_noref_lookup(sw_context->fp->tfile, handle); - if (IS_ERR(vmw_bo)) { + vmw_bo = vmw_user_bo_noref_lookup(sw_context->filp, handle); + if (IS_ERR_OR_NULL(vmw_bo)) { VMW_DEBUG_USER("Could not find or use GMR region.\n"); return PTR_ERR(vmw_bo); } - ret = vmw_validation_add_bo(sw_context->ctx, vmw_bo, false, false); - vmw_user_bo_noref_release(); + ttm_bo_put(&vmw_bo->base); if (unlikely(ret != 0)) return ret; @@ -3869,8 +3867,7 @@ vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv, fence_rep.fd = -1; } - ttm_ref_object_base_unref(vmw_fp->tfile, fence_handle, - TTM_REF_USAGE); + ttm_ref_object_base_unref(vmw_fp->tfile, fence_handle); VMW_DEBUG_USER("Fence copy error. Syncing.\n"); (void) vmw_fence_obj_wait(fence, false, false, VMW_FENCE_WAIT_TIMEOUT); @@ -4099,6 +4096,7 @@ int vmw_execbuf_process(struct drm_file *file_priv, sw_context->kernel = true; } + sw_context->filp = file_priv; sw_context->fp = vmw_fpriv(file_priv); INIT_LIST_HEAD(&sw_context->ctx_list); sw_context->cur_query_bo = dev_priv->pinned_bo; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index d18c6a56e3dc..8ee34576c7d0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -394,22 +394,15 @@ static int vmw_fb_create_bo(struct vmw_private *vmw_priv, struct vmw_buffer_object *vmw_bo; int ret; - vmw_bo = kmalloc(sizeof(*vmw_bo), GFP_KERNEL); - if (!vmw_bo) { - ret = -ENOMEM; - goto err_unlock; - } - - ret = vmw_bo_init(vmw_priv, vmw_bo, size, + ret = vmw_bo_create(vmw_priv, size, &vmw_sys_placement, false, false, - &vmw_bo_bo_free); + &vmw_bo_bo_free, &vmw_bo); if (unlikely(ret != 0)) - goto err_unlock; /* init frees the buffer on failure */ + return ret; *out = vmw_bo; -err_unlock: return ret; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c index c9afd070c11b..c60d395f9e2e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c @@ -596,9 +596,10 @@ int vmw_user_fence_create(struct drm_file *file_priv, * vmw_user_fence_base_release. */ tmp = vmw_fence_obj_reference(&ufence->fence); + ret = ttm_base_object_init(tfile, &ufence->base, false, VMW_RES_FENCE, - &vmw_user_fence_base_release, NULL); + &vmw_user_fence_base_release); if (unlikely(ret != 0)) { @@ -801,8 +802,7 @@ out: */ if (ret == 0 && (arg->wait_options & DRM_VMW_WAIT_OPTION_UNREF)) - return ttm_ref_object_base_unref(tfile, arg->handle, - TTM_REF_USAGE); + return ttm_ref_object_base_unref(tfile, arg->handle); return ret; } @@ -844,8 +844,7 @@ int vmw_fence_obj_unref_ioctl(struct drm_device *dev, void *data, (struct drm_vmw_fence_arg *) data; return ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile, - arg->handle, - TTM_REF_USAGE); + arg->handle); } /** @@ -1091,7 +1090,7 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data, if (user_fence_rep != NULL) { ret = ttm_ref_object_add(vmw_fp->tfile, base, - TTM_REF_USAGE, NULL, false); + NULL, false); if (unlikely(ret != 0)) { DRM_ERROR("Failed to reference a fence " "object.\n"); @@ -1134,7 +1133,7 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data, return 0; out_no_create: if (user_fence_rep != NULL) - ttm_ref_object_base_unref(tfile, handle, TTM_REF_USAGE); + ttm_ref_object_base_unref(tfile, handle); out_no_ref_obj: vmw_fence_obj_unreference(&fence); return ret; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gem.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gem.c new file mode 100644 index 000000000000..c016c434b6cb --- /dev/null +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gem.c @@ -0,0 +1,294 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ +/* + * Copyright 2021 VMware, Inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include "vmwgfx_drv.h" + +#include "drm/drm_prime.h" +#include "drm/drm_gem_ttm_helper.h" + +/** + * vmw_buffer_object - Convert a struct ttm_buffer_object to a struct + * vmw_buffer_object. + * + * @bo: Pointer to the TTM buffer object. + * Return: Pointer to the struct vmw_buffer_object embedding the + * TTM buffer object. + */ +static struct vmw_buffer_object * +vmw_buffer_object(struct ttm_buffer_object *bo) +{ + return container_of(bo, struct vmw_buffer_object, base); +} + +static void vmw_gem_object_free(struct drm_gem_object *gobj) +{ + struct ttm_buffer_object *bo = drm_gem_ttm_of_gem(gobj); + if (bo) { + ttm_bo_put(bo); + } +} + +static int vmw_gem_object_open(struct drm_gem_object *obj, + struct drm_file *file_priv) +{ + return 0; +} + +static void vmw_gem_object_close(struct drm_gem_object *obj, + struct drm_file *file_priv) +{ +} + +static int vmw_gem_pin_private(struct drm_gem_object *obj, bool do_pin) +{ + struct ttm_buffer_object *bo = drm_gem_ttm_of_gem(obj); + struct vmw_buffer_object *vbo = vmw_buffer_object(bo); + int ret; + + ret = ttm_bo_reserve(bo, false, false, NULL); + if (unlikely(ret != 0)) + goto err; + + vmw_bo_pin_reserved(vbo, do_pin); + + ttm_bo_unreserve(bo); + +err: + return ret; +} + + +static int vmw_gem_object_pin(struct drm_gem_object *obj) +{ + return vmw_gem_pin_private(obj, true); +} + +static void vmw_gem_object_unpin(struct drm_gem_object *obj) +{ + vmw_gem_pin_private(obj, false); +} + +static struct sg_table *vmw_gem_object_get_sg_table(struct drm_gem_object *obj) +{ + struct ttm_buffer_object *bo = drm_gem_ttm_of_gem(obj); + struct vmw_ttm_tt *vmw_tt = + container_of(bo->ttm, struct vmw_ttm_tt, dma_ttm); + + if (vmw_tt->vsgt.sgt) + return vmw_tt->vsgt.sgt; + + return drm_prime_pages_to_sg(obj->dev, vmw_tt->dma_ttm.pages, vmw_tt->dma_ttm.num_pages); +} + + +static const struct drm_gem_object_funcs vmw_gem_object_funcs = { + .free = vmw_gem_object_free, + .open = vmw_gem_object_open, + .close = vmw_gem_object_close, + .print_info = drm_gem_ttm_print_info, + .pin = vmw_gem_object_pin, + .unpin = vmw_gem_object_unpin, + .get_sg_table = vmw_gem_object_get_sg_table, + .vmap = drm_gem_ttm_vmap, + .vunmap = drm_gem_ttm_vunmap, + .mmap = drm_gem_ttm_mmap, +}; + +/** + * vmw_gem_destroy - vmw buffer object destructor + * + * @bo: Pointer to the embedded struct ttm_buffer_object + */ +void vmw_gem_destroy(struct ttm_buffer_object *bo) +{ + struct vmw_buffer_object *vbo = vmw_buffer_object(bo); + + WARN_ON(vbo->dirty); + WARN_ON(!RB_EMPTY_ROOT(&vbo->res_tree)); + vmw_bo_unmap(vbo); + drm_gem_object_release(&vbo->base.base); + kfree(vbo); +} + +int vmw_gem_object_create_with_handle(struct vmw_private *dev_priv, + struct drm_file *filp, + uint32_t size, + uint32_t *handle, + struct vmw_buffer_object **p_vbo) +{ + int ret; + + ret = vmw_bo_create(dev_priv, size, + (dev_priv->has_mob) ? + &vmw_sys_placement : + &vmw_vram_sys_placement, + true, false, &vmw_gem_destroy, p_vbo); + + (*p_vbo)->base.base.funcs = &vmw_gem_object_funcs; + if (ret != 0) + goto out_no_bo; + + ret = drm_gem_handle_create(filp, &(*p_vbo)->base.base, handle); + /* drop reference from allocate - handle holds it now */ + drm_gem_object_put(&(*p_vbo)->base.base); +out_no_bo: + return ret; +} + + +int vmw_gem_object_create_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + union drm_vmw_alloc_dmabuf_arg *arg = + (union drm_vmw_alloc_dmabuf_arg *)data; + struct drm_vmw_alloc_dmabuf_req *req = &arg->req; + struct drm_vmw_dmabuf_rep *rep = &arg->rep; + struct vmw_buffer_object *vbo; + uint32_t handle; + int ret; + + ret = vmw_gem_object_create_with_handle(dev_priv, filp, + req->size, &handle, &vbo); + if (ret) + goto out_no_bo; + + rep->handle = handle; + rep->map_handle = drm_vma_node_offset_addr(&vbo->base.base.vma_node); + rep->cur_gmr_id = handle; + rep->cur_gmr_offset = 0; +out_no_bo: + return ret; +} + +#if defined(CONFIG_DEBUG_FS) + +static void vmw_bo_print_info(int id, struct vmw_buffer_object *bo, struct seq_file *m) +{ + const char *placement; + const char *type; + + switch (bo->base.resource->mem_type) { + case TTM_PL_SYSTEM: + placement = " CPU"; + break; + case VMW_PL_GMR: + placement = " GMR"; + break; + case VMW_PL_MOB: + placement = " MOB"; + break; + case VMW_PL_SYSTEM: + placement = "VCPU"; + break; + case TTM_PL_VRAM: + placement = "VRAM"; + break; + default: + placement = "None"; + break; + } + + switch (bo->base.type) { + case ttm_bo_type_device: + type = "device"; + break; + case ttm_bo_type_kernel: + type = "kernel"; + break; + case ttm_bo_type_sg: + type = "sg "; + break; + default: + type = "none "; + break; + } + + seq_printf(m, "\t\t0x%08x: %12ld bytes %s, type = %s", + id, bo->base.base.size, placement, type); + seq_printf(m, ", priority = %u, pin_count = %u, GEM refs = %d, TTM refs = %d", + bo->base.priority, + bo->base.pin_count, + kref_read(&bo->base.base.refcount), + kref_read(&bo->base.kref)); + seq_puts(m, "\n"); +} + +static int vmw_debugfs_gem_info_show(struct seq_file *m, void *unused) +{ + struct vmw_private *vdev = (struct vmw_private *)m->private; + struct drm_device *dev = &vdev->drm; + struct drm_file *file; + int r; + + r = mutex_lock_interruptible(&dev->filelist_mutex); + if (r) + return r; + + list_for_each_entry(file, &dev->filelist, lhead) { + struct task_struct *task; + struct drm_gem_object *gobj; + int id; + + /* + * Although we have a valid reference on file->pid, that does + * not guarantee that the task_struct who called get_pid() is + * still alive (e.g. get_pid(current) => fork() => exit()). + * Therefore, we need to protect this ->comm access using RCU. + */ + rcu_read_lock(); + task = pid_task(file->pid, PIDTYPE_PID); + seq_printf(m, "pid %8d command %s:\n", pid_nr(file->pid), + task ? task->comm : "<unknown>"); + rcu_read_unlock(); + + spin_lock(&file->table_lock); + idr_for_each_entry(&file->object_idr, gobj, id) { + struct vmw_buffer_object *bo = gem_to_vmw_bo(gobj); + + vmw_bo_print_info(id, bo, m); + } + spin_unlock(&file->table_lock); + } + + mutex_unlock(&dev->filelist_mutex); + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(vmw_debugfs_gem_info); + +#endif + +void vmw_debugfs_gem_init(struct vmw_private *vdev) +{ +#if defined(CONFIG_DEBUG_FS) + struct drm_minor *minor = vdev->drm.primary; + struct dentry *root = minor->debugfs_root; + + debugfs_create_file("vmwgfx_gem_info", 0444, root, vdev, + &vmw_debugfs_gem_info_fops); +#endif +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 40dc99337d5b..b4bbb5c47bdd 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -843,8 +843,6 @@ static void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer) drm_framebuffer_cleanup(framebuffer); vmw_surface_unreference(&vfbs->surface); - if (vfbs->base.user_obj) - ttm_base_object_unref(&vfbs->base.user_obj); kfree(vfbs); } @@ -996,8 +994,6 @@ static void vmw_framebuffer_bo_destroy(struct drm_framebuffer *framebuffer) drm_framebuffer_cleanup(framebuffer); vmw_bo_unreference(&vfbd->buffer); - if (vfbd->base.user_obj) - ttm_base_object_unref(&vfbd->base.user_obj); kfree(vfbd); } @@ -1251,6 +1247,7 @@ static int vmw_kms_new_framebuffer_bo(struct vmw_private *dev_priv, goto out_err1; } + vfbd->base.base.obj[0] = &bo->base.base; drm_helper_mode_fill_fb_struct(dev, &vfbd->base.base, mode_cmd); vfbd->base.bo = true; vfbd->buffer = vmw_bo_reference(bo); @@ -1368,34 +1365,13 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd) { struct vmw_private *dev_priv = vmw_priv(dev); - struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; struct vmw_framebuffer *vfb = NULL; struct vmw_surface *surface = NULL; struct vmw_buffer_object *bo = NULL; - struct ttm_base_object *user_obj; int ret; - /* - * Take a reference on the user object of the resource - * backing the kms fb. This ensures that user-space handle - * lookups on that resource will always work as long as - * it's registered with a kms framebuffer. This is important, - * since vmw_execbuf_process identifies resources in the - * command stream using user-space handles. - */ - - user_obj = ttm_base_object_lookup(tfile, mode_cmd->handles[0]); - if (unlikely(user_obj == NULL)) { - DRM_ERROR("Could not locate requested kms frame buffer.\n"); - return ERR_PTR(-ENOENT); - } - - /** - * End conditioned code. - */ - /* returns either a bo or surface */ - ret = vmw_user_lookup_handle(dev_priv, tfile, + ret = vmw_user_lookup_handle(dev_priv, file_priv, mode_cmd->handles[0], &surface, &bo); if (ret) @@ -1428,10 +1404,8 @@ err_out: if (ret) { DRM_ERROR("failed to create vmw_framebuffer: %i\n", ret); - ttm_base_object_unref(&user_obj); return ERR_PTR(ret); - } else - vfb->user_obj = user_obj; + } return &vfb->base; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index bbc809f7bd8a..4d36e8507380 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -219,7 +219,6 @@ struct vmw_framebuffer { int (*pin)(struct vmw_framebuffer *fb); int (*unpin)(struct vmw_framebuffer *fb); bool bo; - struct ttm_base_object *user_obj; uint32_t user_handle; }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c index 54c5d16eb3b7..e9f5c89b4ca6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c @@ -451,7 +451,7 @@ int vmw_overlay_ioctl(struct drm_device *dev, void *data, goto out_unlock; } - ret = vmw_user_bo_lookup(tfile, arg->handle, &buf, NULL); + ret = vmw_user_bo_lookup(file_priv, arg->handle, &buf); if (ret) goto out_unlock; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_prime.c b/drivers/gpu/drm/vmwgfx/vmwgfx_prime.c index d9552a1efd13..2d72a5ee7c0c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_prime.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_prime.c @@ -85,6 +85,5 @@ int vmw_prime_handle_to_fd(struct drm_device *dev, int *prime_fd) { struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; - return ttm_prime_handle_to_fd(tfile, handle, flags, prime_fd); } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 8d1e869cc196..708899ba2102 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -320,11 +320,12 @@ vmw_user_resource_noref_lookup_handle(struct vmw_private *dev_priv, * The pointer this pointed at by out_surf and out_buf needs to be null. */ int vmw_user_lookup_handle(struct vmw_private *dev_priv, - struct ttm_object_file *tfile, + struct drm_file *filp, uint32_t handle, struct vmw_surface **out_surf, struct vmw_buffer_object **out_buf) { + struct ttm_object_file *tfile = vmw_fpriv(filp)->tfile; struct vmw_resource *res; int ret; @@ -339,7 +340,7 @@ int vmw_user_lookup_handle(struct vmw_private *dev_priv, } *out_surf = NULL; - ret = vmw_user_bo_lookup(tfile, handle, out_buf, NULL); + ret = vmw_user_bo_lookup(filp, handle, out_buf); return ret; } @@ -362,14 +363,10 @@ static int vmw_resource_buf_alloc(struct vmw_resource *res, return 0; } - backup = kzalloc(sizeof(*backup), GFP_KERNEL); - if (unlikely(!backup)) - return -ENOMEM; - - ret = vmw_bo_init(res->dev_priv, backup, res->backup_size, - res->func->backup_placement, - interruptible, false, - &vmw_bo_bo_free); + ret = vmw_bo_create(res->dev_priv, res->backup_size, + res->func->backup_placement, + interruptible, false, + &vmw_bo_bo_free, &backup); if (unlikely(ret != 0)) goto out_no_bo; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index bd157fb21b45..3004c7a719e9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -442,19 +442,15 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane, vps->bo_size = 0; } - vps->bo = kzalloc(sizeof(*vps->bo), GFP_KERNEL); - if (!vps->bo) - return -ENOMEM; - vmw_svga_enable(dev_priv); /* After we have alloced the backing store might not be able to * resume the overlays, this is preferred to failing to alloc. */ vmw_overlay_pause_all(dev_priv); - ret = vmw_bo_init(dev_priv, vps->bo, size, - &vmw_vram_placement, - false, true, &vmw_bo_bo_free); + ret = vmw_bo_create(dev_priv, size, + &vmw_vram_placement, + false, true, &vmw_bo_bo_free, &vps->bo); vmw_overlay_resume_all(dev_priv); if (ret) { vps->bo = NULL; /* vmw_bo_init frees on error */ diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c index a1e47f39a60b..108a496b5d18 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c @@ -676,8 +676,7 @@ int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data, struct drm_vmw_shader_arg *arg = (struct drm_vmw_shader_arg *)data; struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; - return ttm_ref_object_base_unref(tfile, arg->handle, - TTM_REF_USAGE); + return ttm_ref_object_base_unref(tfile, arg->handle); } static int vmw_user_shader_alloc(struct vmw_private *dev_priv, @@ -718,7 +717,7 @@ static int vmw_user_shader_alloc(struct vmw_private *dev_priv, tmp = vmw_resource_reference(res); ret = ttm_base_object_init(tfile, &ushader->base, false, VMW_RES_SHADER, - &vmw_user_shader_base_release, NULL); + &vmw_user_shader_base_release); if (unlikely(ret != 0)) { vmw_resource_unreference(&tmp); @@ -777,8 +776,7 @@ static int vmw_shader_define(struct drm_device *dev, struct drm_file *file_priv, int ret; if (buffer_handle != SVGA3D_INVALID_ID) { - ret = vmw_user_bo_lookup(tfile, buffer_handle, - &buffer, NULL); + ret = vmw_user_bo_lookup(file_priv, buffer_handle, &buffer); if (unlikely(ret != 0)) { VMW_DEBUG_USER("Couldn't find buffer for shader creation.\n"); return ret; @@ -894,13 +892,8 @@ int vmw_compat_shader_add(struct vmw_private *dev_priv, if (!vmw_shader_id_ok(user_key, shader_type)) return -EINVAL; - /* Allocate and pin a DMA buffer */ - buf = kzalloc(sizeof(*buf), GFP_KERNEL); - if (unlikely(!buf)) - return -ENOMEM; - - ret = vmw_bo_init(dev_priv, buf, size, &vmw_sys_placement, - true, true, vmw_bo_bo_free); + ret = vmw_bo_create(dev_priv, size, &vmw_sys_placement, + true, true, vmw_bo_bo_free, &buf); if (unlikely(ret != 0)) goto out; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_simple_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_simple_resource.c index 76473d434f52..483ad544ea54 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_simple_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_simple_resource.c @@ -172,7 +172,7 @@ vmw_simple_resource_create_ioctl(struct drm_device *dev, void *data, tmp = vmw_resource_reference(res); ret = ttm_base_object_init(tfile, &usimple->base, false, func->ttm_res_type, - &vmw_simple_resource_base_release, NULL); + &vmw_simple_resource_base_release); if (ret) { vmw_resource_unreference(&tmp); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index ab207de64c31..00e8e27e4884 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -46,13 +46,11 @@ * @base: The TTM base object handling user-space visibility. * @srf: The surface metadata. * @master: Master of the creating client. Used for security check. - * @backup_base: The TTM base object of the backup buffer. */ struct vmw_user_surface { struct ttm_prime_object prime; struct vmw_surface srf; struct drm_master *master; - struct ttm_base_object *backup_base; }; /** @@ -686,8 +684,6 @@ static void vmw_user_surface_base_release(struct ttm_base_object **p_base) struct vmw_resource *res = &user_srf->srf.res; *p_base = NULL; - if (user_srf->backup_base) - ttm_base_object_unref(&user_srf->backup_base); vmw_resource_unreference(&res); } @@ -705,7 +701,7 @@ int vmw_surface_destroy_ioctl(struct drm_device *dev, void *data, struct drm_vmw_surface_arg *arg = (struct drm_vmw_surface_arg *)data; struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; - return ttm_ref_object_base_unref(tfile, arg->sid, TTM_REF_USAGE); + return ttm_ref_object_base_unref(tfile, arg->sid); } /** @@ -851,22 +847,22 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, if (dev_priv->has_mob && req->shareable) { uint32_t backup_handle; - ret = vmw_user_bo_alloc(dev_priv, tfile, - res->backup_size, - true, - &backup_handle, - &res->backup, - &user_srf->backup_base); + ret = vmw_gem_object_create_with_handle(dev_priv, + file_priv, + res->backup_size, + &backup_handle, + &res->backup); if (unlikely(ret != 0)) { vmw_resource_unreference(&res); goto out_unlock; } + vmw_bo_reference(res->backup); } tmp = vmw_resource_reference(&srf->res); ret = ttm_prime_object_init(tfile, res->backup_size, &user_srf->prime, req->shareable, VMW_RES_SURFACE, - &vmw_user_surface_base_release, NULL); + &vmw_user_surface_base_release); if (unlikely(ret != 0)) { vmw_resource_unreference(&tmp); @@ -921,7 +917,6 @@ vmw_surface_handle_reference(struct vmw_private *dev_priv, VMW_DEBUG_USER("Referenced object is not a surface.\n"); goto out_bad_resource; } - if (handle_type != DRM_VMW_HANDLE_PRIME) { bool require_exist = false; @@ -946,8 +941,7 @@ vmw_surface_handle_reference(struct vmw_private *dev_priv, if (unlikely(drm_is_render_client(file_priv))) require_exist = true; - ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL, - require_exist); + ret = ttm_ref_object_add(tfile, base, NULL, require_exist); if (unlikely(ret != 0)) { DRM_ERROR("Could not add a reference to a surface.\n"); goto out_bad_resource; @@ -961,7 +955,7 @@ out_bad_resource: ttm_base_object_unref(&base); out_no_lookup: if (handle_type == DRM_VMW_HANDLE_PRIME) - (void) ttm_ref_object_base_unref(tfile, handle, TTM_REF_USAGE); + (void) ttm_ref_object_base_unref(tfile, handle); return ret; } @@ -1011,7 +1005,7 @@ int vmw_surface_reference_ioctl(struct drm_device *dev, void *data, if (unlikely(ret != 0)) { VMW_DEBUG_USER("copy_to_user failed %p %u\n", user_sizes, srf->metadata.num_sizes); - ttm_ref_object_base_unref(tfile, base->handle, TTM_REF_USAGE); + ttm_ref_object_base_unref(tfile, base->handle); ret = -EFAULT; } @@ -1498,9 +1492,8 @@ vmw_gb_surface_define_internal(struct drm_device *dev, res = &user_srf->srf.res; if (req->base.buffer_handle != SVGA3D_INVALID_ID) { - ret = vmw_user_bo_lookup(tfile, req->base.buffer_handle, - &res->backup, - &user_srf->backup_base); + ret = vmw_user_bo_lookup(file_priv, req->base.buffer_handle, + &res->backup); if (ret == 0) { if (res->backup->base.base.size < res->backup_size) { VMW_DEBUG_USER("Surface backup buffer too small.\n"); @@ -1513,14 +1506,15 @@ vmw_gb_surface_define_internal(struct drm_device *dev, } } else if (req->base.drm_surface_flags & (drm_vmw_surface_flag_create_buffer | - drm_vmw_surface_flag_coherent)) - ret = vmw_user_bo_alloc(dev_priv, tfile, - res->backup_size, - req->base.drm_surface_flags & - drm_vmw_surface_flag_shareable, - &backup_handle, - &res->backup, - &user_srf->backup_base); + drm_vmw_surface_flag_coherent)) { + ret = vmw_gem_object_create_with_handle(dev_priv, file_priv, + res->backup_size, + &backup_handle, + &res->backup); + if (ret == 0) + vmw_bo_reference(res->backup); + + } if (unlikely(ret != 0)) { vmw_resource_unreference(&res); @@ -1552,7 +1546,7 @@ vmw_gb_surface_define_internal(struct drm_device *dev, req->base.drm_surface_flags & drm_vmw_surface_flag_shareable, VMW_RES_SURFACE, - &vmw_user_surface_base_release, NULL); + &vmw_user_surface_base_release); if (unlikely(ret != 0)) { vmw_resource_unreference(&tmp); @@ -1572,7 +1566,6 @@ vmw_gb_surface_define_internal(struct drm_device *dev, rep->buffer_size = 0; rep->buffer_handle = SVGA3D_INVALID_ID; } - vmw_resource_unreference(&res); out_unlock: @@ -1595,12 +1588,11 @@ vmw_gb_surface_reference_internal(struct drm_device *dev, struct drm_file *file_priv) { struct vmw_private *dev_priv = vmw_priv(dev); - struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; struct vmw_surface *srf; struct vmw_user_surface *user_srf; struct vmw_surface_metadata *metadata; struct ttm_base_object *base; - uint32_t backup_handle; + u32 backup_handle; int ret; ret = vmw_surface_handle_reference(dev_priv, file_priv, req->sid, @@ -1617,14 +1609,12 @@ vmw_gb_surface_reference_internal(struct drm_device *dev, metadata = &srf->metadata; mutex_lock(&dev_priv->cmdbuf_mutex); /* Protect res->backup */ - ret = vmw_user_bo_reference(tfile, srf->res.backup, &backup_handle); + ret = drm_gem_handle_create(file_priv, &srf->res.backup->base.base, + &backup_handle); mutex_unlock(&dev_priv->cmdbuf_mutex); - - if (unlikely(ret != 0)) { - DRM_ERROR("Could not add a reference to a GB surface " - "backup buffer.\n"); - (void) ttm_ref_object_base_unref(tfile, base->handle, - TTM_REF_USAGE); + if (ret != 0) { + drm_err(dev, "Wasn't able to create a backing handle for surface sid = %u.\n", + req->sid); goto out_bad_resource; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c index a3d39e6b62b8..20f752ff6168 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c @@ -167,18 +167,6 @@ struct ttm_placement vmw_nonfixed_placement = { .busy_placement = &sys_placement_flags }; -struct vmw_ttm_tt { - struct ttm_tt dma_ttm; - struct vmw_private *dev_priv; - int gmr_id; - struct vmw_mob *mob; - int mem_type; - struct sg_table sgt; - struct vmw_sg_table vsgt; - bool mapped; - bool bound; -}; - const size_t vmw_tt_size = sizeof(struct vmw_ttm_tt); /** @@ -311,11 +299,12 @@ static int vmw_ttm_map_dma(struct vmw_ttm_tt *vmw_tt) vsgt->pages = vmw_tt->dma_ttm.pages; vsgt->num_pages = vmw_tt->dma_ttm.num_pages; vsgt->addrs = vmw_tt->dma_ttm.dma_address; - vsgt->sgt = &vmw_tt->sgt; + vsgt->sgt = NULL; switch (dev_priv->map_mode) { case vmw_dma_map_bind: case vmw_dma_map_populate: + vsgt->sgt = &vmw_tt->sgt; ret = sg_alloc_table_from_pages_segment( &vmw_tt->sgt, vsgt->pages, vsgt->num_pages, 0, (unsigned long)vsgt->num_pages << PAGE_SHIFT, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c index 98459db70962..265f7c48d856 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c @@ -27,30 +27,44 @@ #include "vmwgfx_drv.h" -static struct ttm_buffer_object *vmw_bo_vm_lookup(struct ttm_device *bdev, - unsigned long offset, - unsigned long pages) +static int vmw_bo_vm_lookup(struct ttm_device *bdev, + struct drm_file *filp, + unsigned long offset, + unsigned long pages, + struct ttm_buffer_object **p_bo) { struct vmw_private *dev_priv = container_of(bdev, struct vmw_private, bdev); struct drm_device *drm = &dev_priv->drm; struct drm_vma_offset_node *node; - struct ttm_buffer_object *bo = NULL; + int ret; + + *p_bo = NULL; drm_vma_offset_lock_lookup(bdev->vma_manager); node = drm_vma_offset_lookup_locked(bdev->vma_manager, offset, pages); if (likely(node)) { - bo = container_of(node, struct ttm_buffer_object, + *p_bo = container_of(node, struct ttm_buffer_object, base.vma_node); - bo = ttm_bo_get_unless_zero(bo); + *p_bo = ttm_bo_get_unless_zero(*p_bo); } drm_vma_offset_unlock_lookup(bdev->vma_manager); - if (!bo) + if (!*p_bo) { drm_err(drm, "Could not find buffer object to map\n"); + return -EINVAL; + } + + if (!drm_vma_node_is_allowed(node, filp)) { + ret = -EACCES; + goto out_no_access; + } - return bo; + return 0; +out_no_access: + ttm_bo_put(*p_bo); + return ret; } int vmw_mmap(struct file *filp, struct vm_area_struct *vma) @@ -64,7 +78,6 @@ int vmw_mmap(struct file *filp, struct vm_area_struct *vma) }; struct drm_file *file_priv = filp->private_data; struct vmw_private *dev_priv = vmw_priv(file_priv->minor->dev); - struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; struct ttm_device *bdev = &dev_priv->bdev; struct ttm_buffer_object *bo; int ret; @@ -72,13 +85,9 @@ int vmw_mmap(struct file *filp, struct vm_area_struct *vma) if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET_START)) return -EINVAL; - bo = vmw_bo_vm_lookup(bdev, vma->vm_pgoff, vma_pages(vma)); - if (unlikely(!bo)) - return -EINVAL; - - ret = vmw_user_bo_verify_access(bo, tfile); + ret = vmw_bo_vm_lookup(bdev, file_priv, vma->vm_pgoff, vma_pages(vma), &bo); if (unlikely(ret != 0)) - goto out_unref; + return ret; ret = ttm_bo_mmap_obj(vma, bo); if (unlikely(ret != 0)) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_va.c b/drivers/gpu/drm/vmwgfx/vmwgfx_va.c index ebc1d83c34b4..6ad744ae07f5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_va.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_va.c @@ -117,7 +117,7 @@ int vmw_stream_unref_ioctl(struct drm_device *dev, void *data, struct drm_vmw_stream_arg *arg = (struct drm_vmw_stream_arg *)data; return ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile, - arg->stream_id, TTM_REF_USAGE); + arg->stream_id); } /** |