Most drivers have refcounting done in gem, so lets get rid of another refcounting layer. ;) It has been confusing to keep track of 2 refcounts, so lets just let the driver worry about refcounting, and keep it hidden from ttm entirely. The core doesn't need to know about the refcounting anywhere. Vmwgfx has 1 bo that doesn't use vmw_dma_buffer, but instead ttm_bo_create. Converting this call makes every bo use vmw_dma_buffer as base, which means I can simply add refcount to vmw_dma_buffer. Mostly meant as a RFC, so I only took effort into converting vmwgfx, radeon, nouveau. Thoughts? I've only done some very basic smoke testing btw, I know nouveau and radeon boot. No idea about vmwgfx. --- diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index af0b868a9dfd..9fcf38a7923a 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -449,26 +449,13 @@ int ast_dumb_create(struct drm_file *file, return 0; } -void ast_bo_unref(struct ast_bo **bo) -{ - struct ttm_buffer_object *tbo; - - if ((*bo) == NULL) - return; - - tbo = &((*bo)->bo); - ttm_bo_unref(&tbo); - if (tbo == NULL) - *bo = NULL; - -} void ast_gem_free_object(struct drm_gem_object *obj) { struct ast_bo *ast_bo = gem_to_ast_bo(obj); if (!ast_bo) return; - ast_bo_unref(&ast_bo); + ttm_bo_release(&ast_bo->bo); } diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c index 78e76f24343d..f4d3fd5be1e7 100644 --- a/drivers/gpu/drm/cirrus/cirrus_main.c +++ b/drivers/gpu/drm/cirrus/cirrus_main.c @@ -255,27 +255,13 @@ int cirrus_dumb_create(struct drm_file *file, return 0; } -void cirrus_bo_unref(struct cirrus_bo **bo) -{ - struct ttm_buffer_object *tbo; - - if ((*bo) == NULL) - return; - - tbo = &((*bo)->bo); - ttm_bo_unref(&tbo); - if (tbo == NULL) - *bo = NULL; - -} - void cirrus_gem_free_object(struct drm_gem_object *obj) { struct cirrus_bo *cirrus_bo = gem_to_cirrus_bo(obj); if (!cirrus_bo) return; - cirrus_bo_unref(&cirrus_bo); + ttm_bo_release(&cirrus_bo->bo); } diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 4761adedad2a..511b4e97a093 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -848,9 +848,14 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) if (!node) { mutex_unlock(&dev->struct_mutex); return drm_mmap(filp, vma); - } else if (!drm_vma_node_is_allowed(node, filp)) { - mutex_unlock(&dev->struct_mutex); - return -EACCES; + } else { + read_lock(&node->vm_lock); + ret = drm_vma_node_verify_access(node, filp); + read_unlock(&node->vm_lock); + if (ret) { + mutex_unlock(&dev->struct_mutex); + return ret; + } } obj = container_of(node, struct drm_gem_object, vma_node); diff --git a/drivers/gpu/drm/drm_vma_manager.c b/drivers/gpu/drm/drm_vma_manager.c index 63b471205072..482b9c996217 100644 --- a/drivers/gpu/drm/drm_vma_manager.c +++ b/drivers/gpu/drm/drm_vma_manager.c @@ -405,7 +405,7 @@ EXPORT_SYMBOL(drm_vma_node_revoke); * Search the list in @node whether @filp is currently on the list of allowed * open-files (see drm_vma_node_allow()). * - * This is locked against concurrent access internally. + * This call requires the vm_lock to be held. * * RETURNS: * true iff @filp is on the list @@ -416,8 +416,6 @@ bool drm_vma_node_is_allowed(struct drm_vma_offset_node *node, struct drm_vma_offset_file *entry; struct rb_node *iter; - read_lock(&node->vm_lock); - iter = node->vm_files.rb_node; while (likely(iter)) { entry = rb_entry(iter, struct drm_vma_offset_file, vm_rb); @@ -429,8 +427,6 @@ bool drm_vma_node_is_allowed(struct drm_vma_offset_node *node, iter = iter->rb_left; } - read_unlock(&node->vm_lock); - return iter; } EXPORT_SYMBOL(drm_vma_node_is_allowed); diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c index b1120cb1db6d..ca8367505742 100644 --- a/drivers/gpu/drm/mgag200/mgag200_main.c +++ b/drivers/gpu/drm/mgag200/mgag200_main.c @@ -310,27 +310,13 @@ int mgag200_dumb_create(struct drm_file *file, return 0; } -void mgag200_bo_unref(struct mgag200_bo **bo) -{ - struct ttm_buffer_object *tbo; - - if ((*bo) == NULL) - return; - - tbo = &((*bo)->bo); - ttm_bo_unref(&tbo); - if (tbo == NULL) - *bo = NULL; - -} - void mgag200_gem_free_object(struct drm_gem_object *obj) { struct mgag200_bo *mgag200_bo = gem_to_mga_bo(obj); if (!mgag200_bo) return; - mgag200_bo_unref(&mgag200_bo); + ttm_bo_release(&mgag200_bo->bo); } diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 29cc32f976f8..1ba8b90db8b5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -146,8 +146,6 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo) struct drm_device *dev = drm->dev; struct nouveau_bo *nvbo = nouveau_bo(bo); - if (unlikely(nvbo->gem.filp)) - DRM_ERROR("bo %p still attached to GEM object\n", bo); WARN_ON(nvbo->pin_refcnt > 0); nv10_bo_put_tile_region(dev, nvbo->tile, NULL); kfree(nvbo); @@ -246,6 +244,7 @@ nouveau_bo_new(struct drm_device *dev, int size, int align, /* ttm will call nouveau_bo_del_ttm if it fails.. */ return ret; } + drm_gem_private_object_init(dev, &nvbo->gem, size); *pnvbo = nvbo; return 0; @@ -1249,14 +1248,6 @@ out: } static int -nouveau_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp) -{ - struct nouveau_bo *nvbo = nouveau_bo(bo); - - return drm_vma_node_verify_access(&nvbo->gem.vma_node, filp); -} - -static int nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) { struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; @@ -1513,7 +1504,6 @@ struct ttm_bo_driver nouveau_bo_driver = { .evict_flags = nouveau_bo_evict_flags, .move_notify = nouveau_bo_move_ntfy, .move = nouveau_bo_move, - .verify_access = nouveau_bo_verify_access, .sync_obj_signaled = nouveau_bo_fence_signalled, .sync_obj_wait = nouveau_bo_fence_wait, .sync_obj_flush = nouveau_bo_fence_flush, diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.h b/drivers/gpu/drm/nouveau/nouveau_bo.h index ff17c1f432fc..abbd8b83351f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.h +++ b/drivers/gpu/drm/nouveau/nouveau_bo.h @@ -51,14 +51,15 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pnvbo) if (!pnvbo) return -EINVAL; - prev = *pnvbo; - - *pnvbo = ref ? nouveau_bo(ttm_bo_reference(&ref->bo)) : NULL; - if (prev) { - struct ttm_buffer_object *bo = &prev->bo; - ttm_bo_unref(&bo); + prev = *pnvbo; + if (ref != prev) { + if (ref) + drm_gem_object_reference(&ref->gem); + if (prev) + drm_gem_object_unreference_unlocked(&prev->gem); } + *pnvbo = ref; return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 091753f29554..2c4aecbd8544 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -38,7 +38,6 @@ void nouveau_gem_object_del(struct drm_gem_object *gem) { struct nouveau_bo *nvbo = nouveau_gem_object(gem); - struct ttm_buffer_object *bo = &nvbo->bo; if (gem->import_attach) drm_prime_gem_destroy(gem, nvbo->bo.sg); @@ -47,7 +46,7 @@ nouveau_gem_object_del(struct drm_gem_object *gem) /* reset filp so nouveau_bo_del_ttm() can test for it */ gem->filp = NULL; - ttm_bo_unref(&bo); + ttm_bo_release(&nvbo->bo); } int diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index 19e3757291fb..48c9277d41da 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -277,16 +277,58 @@ const struct ttm_mem_type_manager_func nv04_gart_manager = { nv04_gart_manager_debug }; +static void nouveau_bo_vm_open(struct vm_area_struct *vma) +{ + struct nouveau_bo *bo = nouveau_bo(vma->vm_private_data); + + drm_gem_object_reference(&bo->gem); +} + +static void nouveau_bo_vm_close(struct vm_area_struct *vma) +{ + struct nouveau_bo *bo = nouveau_bo(vma->vm_private_data); + + drm_gem_object_unreference_unlocked(&bo->gem); + vma->vm_private_data = NULL; +} + +static const struct vm_operations_struct nouveau_bo_vm_ops = { + .fault = ttm_bo_vm_fault, + .open = nouveau_bo_vm_open, + .close = nouveau_bo_vm_close +}; + int nouveau_ttm_mmap(struct file *filp, struct vm_area_struct *vma) { struct drm_file *file_priv = filp->private_data; struct nouveau_drm *drm = nouveau_drm(file_priv->minor->dev); + struct drm_vma_offset_node *node; + struct nouveau_bo *bo; + int ret; if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) return drm_mmap(filp, vma); - return ttm_bo_mmap(filp, vma, &drm->ttm.bdev); + drm_vma_offset_lock_lookup(&drm->ttm.bdev.vma_manager); + node = drm_vma_offset_lookup_locked(&drm->ttm.bdev.vma_manager, + vma->vm_pgoff, vma_pages(vma)); + if (node) { + bo = container_of(node, struct nouveau_bo, bo.vma_node); + ret = drm_vma_node_verify_access(&nvbo->gem.vma_node, filp); + + if (!ret && !kref_get_unless_zero(&bo->gem.refcount)) + ret = -EINVAL; + } else + ret = -EINVAL; + drm_vma_offset_unlock_lookup(&drm->ttm.bdev.vma_manager); + + if (!ret) { + vma->vm_private_data = &bo->bo; + vma->vm_flags |= VM_IO | VM_MIXEDMAP | VM_DONTEXPAND | VM_DONTDUMP; + vma->vm_ops = &nouveau_bo_vm_ops; + } + return ret; } static int diff --git a/drivers/gpu/drm/qxl/qxl_gem.c b/drivers/gpu/drm/qxl/qxl_gem.c index b96f0c9d89b2..48c39dc04931 100644 --- a/drivers/gpu/drm/qxl/qxl_gem.c +++ b/drivers/gpu/drm/qxl/qxl_gem.c @@ -33,7 +33,7 @@ void qxl_gem_object_free(struct drm_gem_object *gobj) struct qxl_bo *qobj = gem_to_qxl_bo(gobj); if (qobj) - qxl_bo_unref(&qobj); + ttm_bo_release(&qobj->tbo); } int qxl_gem_object_create(struct qxl_device *qdev, int size, diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c index 8691c76c5ef0..d644a7c7384a 100644 --- a/drivers/gpu/drm/qxl/qxl_object.c +++ b/drivers/gpu/drm/qxl/qxl_object.c @@ -209,19 +209,14 @@ void qxl_bo_kunmap_atomic_page(struct qxl_device *qdev, void qxl_bo_unref(struct qxl_bo **bo) { - struct ttm_buffer_object *tbo; - - if ((*bo) == NULL) - return; - tbo = &((*bo)->tbo); - ttm_bo_unref(&tbo); - if (tbo == NULL) - *bo = NULL; + if (*bo) + drm_gem_object_unreference_unlocked(&(*bo)->gem_base); + *bo = NULL; } struct qxl_bo *qxl_bo_ref(struct qxl_bo *bo) { - ttm_bo_reference(&bo->tbo); + drm_gem_object_reference(&bo->gem_base); return bo; } diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index 805c5e566b9a..79d95c76ead6 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -34,9 +34,13 @@ void radeon_gem_object_free(struct drm_gem_object *gobj) struct radeon_bo *robj = gem_to_radeon_bo(gobj); if (robj) { + struct radeon_device *rdev = robj->rdev; if (robj->gem_base.import_attach) drm_prime_gem_destroy(&robj->gem_base, robj->tbo.sg); - radeon_bo_unref(&robj); + + down_read(&rdev->pm.mclk_lock); + ttm_bo_release(&robj->tbo); + up_read(&rdev->pm.mclk_lock); } } diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index a3b92bfbe81b..d31b522b8b90 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -196,18 +196,10 @@ void radeon_bo_kunmap(struct radeon_bo *bo) void radeon_bo_unref(struct radeon_bo **bo) { - struct ttm_buffer_object *tbo; - struct radeon_device *rdev; - if ((*bo) == NULL) return; - rdev = (*bo)->rdev; - tbo = &((*bo)->tbo); - down_read(&rdev->pm.mclk_lock); - ttm_bo_unref(&tbo); - up_read(&rdev->pm.mclk_lock); - if (tbo == NULL) - *bo = NULL; + drm_gem_object_unreference_unlocked(&(*bo)->gem_base); + *bo = NULL; } int radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, u64 max_offset, @@ -386,12 +378,6 @@ int radeon_bo_list_validate(struct ww_acquire_ctx *ticket, return 0; } -int radeon_bo_fbdev_mmap(struct radeon_bo *bo, - struct vm_area_struct *vma) -{ - return ttm_fbdev_mmap(vma, &bo->tbo); -} - int radeon_bo_get_surface_reg(struct radeon_bo *bo) { struct radeon_device *rdev = bo->rdev; diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h index 209b11150263..9685c6e1637b 100644 --- a/drivers/gpu/drm/radeon/radeon_object.h +++ b/drivers/gpu/drm/radeon/radeon_object.h @@ -142,8 +142,6 @@ extern void radeon_bo_list_add_object(struct radeon_bo_list *lobj, struct list_head *head); extern int radeon_bo_list_validate(struct ww_acquire_ctx *ticket, struct list_head *head, int ring); -extern int radeon_bo_fbdev_mmap(struct radeon_bo *bo, - struct vm_area_struct *vma); extern int radeon_bo_set_tiling_flags(struct radeon_bo *bo, u32 tiling_flags, u32 pitch); extern void radeon_bo_get_tiling_flags(struct radeon_bo *bo, diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 71245d6f34a2..eb1a697a7349 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -201,13 +201,6 @@ static void radeon_evict_flags(struct ttm_buffer_object *bo, *placement = rbo->placement; } -static int radeon_verify_access(struct ttm_buffer_object *bo, struct file *filp) -{ - struct radeon_bo *rbo = container_of(bo, struct radeon_bo, tbo); - - return drm_vma_node_verify_access(&rbo->gem_base.vma_node, filp); -} - static void radeon_move_null(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem) { @@ -676,7 +669,6 @@ static struct ttm_bo_driver radeon_bo_driver = { .init_mem_type = &radeon_init_mem_type, .evict_flags = &radeon_evict_flags, .move = &radeon_bo_move, - .verify_access = &radeon_verify_access, .sync_obj_signaled = &radeon_sync_obj_signaled, .sync_obj_wait = &radeon_sync_obj_wait, .sync_obj_flush = &radeon_sync_obj_flush, @@ -784,52 +776,77 @@ void radeon_ttm_set_active_vram_size(struct radeon_device *rdev, u64 size) man->size = size >> PAGE_SHIFT; } -static struct vm_operations_struct radeon_ttm_vm_ops; -static const struct vm_operations_struct *ttm_vm_ops = NULL; - static int radeon_ttm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { - struct ttm_buffer_object *bo; - struct radeon_device *rdev; + struct ttm_buffer_object *bo = (struct ttm_buffer_object *)vma->vm_private_data; + struct radeon_device *rdev = radeon_get_rdev(bo->bdev); int r; - bo = (struct ttm_buffer_object *)vma->vm_private_data; - if (bo == NULL) { - return VM_FAULT_NOPAGE; - } - rdev = radeon_get_rdev(bo->bdev); down_read(&rdev->pm.mclk_lock); - r = ttm_vm_ops->fault(vma, vmf); + r = ttm_bo_vm_fault(vma, vmf); up_read(&rdev->pm.mclk_lock); return r; } +static void radeon_bo_vm_open(struct vm_area_struct *vma) +{ + struct radeon_bo *bo = container_of(vma->vm_private_data, + struct radeon_bo, tbo); + + drm_gem_object_reference(&bo->gem_base); +} + +static void radeon_bo_vm_close(struct vm_area_struct *vma) +{ + struct radeon_bo *bo = container_of(vma->vm_private_data, + struct radeon_bo, tbo); + + drm_gem_object_unreference_unlocked(&bo->gem_base); + vma->vm_private_data = NULL; +} + +static const struct vm_operations_struct radeon_ttm_vm_ops = { + .fault = radeon_ttm_fault, + .open = radeon_bo_vm_open, + .close = radeon_bo_vm_close +}; + int radeon_mmap(struct file *filp, struct vm_area_struct *vma) { - struct drm_file *file_priv; + struct drm_file *file_priv = filp->private_data; struct radeon_device *rdev; - int r; + struct drm_vma_offset_node *node; + struct radeon_bo *bo; + int ret; if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) { return drm_mmap(filp, vma); } - file_priv = filp->private_data; rdev = file_priv->minor->dev->dev_private; if (rdev == NULL) { return -EINVAL; } - r = ttm_bo_mmap(filp, vma, &rdev->mman.bdev); - if (unlikely(r != 0)) { - return r; - } - if (unlikely(ttm_vm_ops == NULL)) { - ttm_vm_ops = vma->vm_ops; - radeon_ttm_vm_ops = *ttm_vm_ops; - radeon_ttm_vm_ops.fault = &radeon_ttm_fault; + + drm_vma_offset_lock_lookup(&rdev->mman.bdev.vma_manager); + node = drm_vma_offset_lookup_locked(&rdev->mman.bdev.vma_manager, + vma->vm_pgoff, vma_pages(vma)); + if (node) { + bo = container_of(node, struct radeon_bo, tbo.vma_node); + ret = drm_vma_node_verify_access(&bo->gem_base.vma_node, filp); + + if (!ret && !kref_get_unless_zero(&bo->gem_base.refcount)) + ret = -EINVAL; + } else + ret = -EINVAL; + drm_vma_offset_unlock_lookup(&rdev->mman.bdev.vma_manager); + + if (!ret) { + vma->vm_private_data = &bo->tbo; + vma->vm_flags |= VM_IO | VM_MIXEDMAP | VM_DONTEXPAND | VM_DONTDUMP; + vma->vm_ops = &radeon_ttm_vm_ops; } - vma->vm_ops = &radeon_ttm_vm_ops; - return 0; + return ret; } diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 8d5a646ebe6a..d5ba8c56c131 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -139,7 +139,6 @@ static void ttm_bo_release_list(struct kref *list_kref) size_t acc_size = bo->acc_size; BUG_ON(atomic_read(&bo->list_kref.refcount)); - BUG_ON(atomic_read(&bo->kref.refcount)); BUG_ON(atomic_read(&bo->cpu_writers)); BUG_ON(bo->sync_obj != NULL); BUG_ON(bo->mem.mm_node != NULL); @@ -619,10 +618,8 @@ static void ttm_bo_delayed_workqueue(struct work_struct *work) } } -static void ttm_bo_release(struct kref *kref) +void ttm_bo_release(struct ttm_buffer_object *bo) { - struct ttm_buffer_object *bo = - container_of(kref, struct ttm_buffer_object, kref); struct ttm_bo_device *bdev = bo->bdev; struct ttm_mem_type_manager *man = &bdev->man[bo->mem.mem_type]; @@ -633,15 +630,7 @@ static void ttm_bo_release(struct kref *kref) ttm_bo_cleanup_refs_or_queue(bo); kref_put(&bo->list_kref, ttm_bo_release_list); } - -void ttm_bo_unref(struct ttm_buffer_object **p_bo) -{ - struct ttm_buffer_object *bo = *p_bo; - - *p_bo = NULL; - kref_put(&bo->kref, ttm_bo_release); -} -EXPORT_SYMBOL(ttm_bo_unref); +EXPORT_SYMBOL(ttm_bo_release); int ttm_bo_lock_delayed_workqueue(struct ttm_bo_device *bdev) { @@ -1116,7 +1105,6 @@ int ttm_bo_init(struct ttm_bo_device *bdev, } bo->destroy = destroy; - kref_init(&bo->kref); kref_init(&bo->list_kref); atomic_set(&bo->cpu_writers, 0); INIT_LIST_HEAD(&bo->lru); @@ -1165,7 +1153,7 @@ int ttm_bo_init(struct ttm_bo_device *bdev, ttm_bo_unreserve(bo); if (unlikely(ret)) - ttm_bo_unref(&bo); + ttm_bo_release(bo); return ret; } @@ -1200,34 +1188,6 @@ size_t ttm_bo_dma_acc_size(struct ttm_bo_device *bdev, } EXPORT_SYMBOL(ttm_bo_dma_acc_size); -int ttm_bo_create(struct ttm_bo_device *bdev, - unsigned long size, - enum ttm_bo_type type, - struct ttm_placement *placement, - uint32_t page_alignment, - bool interruptible, - struct file *persistent_swap_storage, - struct ttm_buffer_object **p_bo) -{ - struct ttm_buffer_object *bo; - size_t acc_size; - int ret; - - bo = kzalloc(sizeof(*bo), GFP_KERNEL); - if (unlikely(bo == NULL)) - return -ENOMEM; - - acc_size = ttm_bo_acc_size(bdev, size, sizeof(struct ttm_buffer_object)); - ret = ttm_bo_init(bdev, bo, size, type, placement, page_alignment, - interruptible, persistent_swap_storage, acc_size, - NULL, NULL); - if (likely(ret == 0)) - *p_bo = bo; - - return ret; -} -EXPORT_SYMBOL(ttm_bo_create); - static int ttm_bo_force_list_clean(struct ttm_bo_device *bdev, unsigned mem_type, bool allow_errors) { diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index 4834c463c38b..9a39373676d5 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -469,7 +469,6 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo, fbo->sync_obj = NULL; spin_unlock(&bdev->fence_lock); kref_init(&fbo->list_kref); - kref_init(&fbo->kref); fbo->destroy = &ttm_transfered_destroy; fbo->acc_size = 0; fbo->resv = &fbo->ttm_resv; @@ -704,7 +703,7 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, bo->ttm = NULL; ttm_bo_unreserve(ghost_obj); - ttm_bo_unref(&ghost_obj); + ttm_bo_release(ghost_obj); } *old_mem = *new_mem; diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index c87d686ff8cf..acb7c1348154 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -86,7 +86,7 @@ out_unlock: return ret; } -static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct ttm_buffer_object *bo = (struct ttm_buffer_object *) vma->vm_private_data; @@ -232,97 +232,4 @@ out_unlock: ttm_bo_unreserve(bo); return retval; } - -static void ttm_bo_vm_open(struct vm_area_struct *vma) -{ - struct ttm_buffer_object *bo = - (struct ttm_buffer_object *)vma->vm_private_data; - - (void)ttm_bo_reference(bo); -} - -static void ttm_bo_vm_close(struct vm_area_struct *vma) -{ - struct ttm_buffer_object *bo = (struct ttm_buffer_object *)vma->vm_private_data; - - ttm_bo_unref(&bo); - vma->vm_private_data = NULL; -} - -static const struct vm_operations_struct ttm_bo_vm_ops = { - .fault = ttm_bo_vm_fault, - .open = ttm_bo_vm_open, - .close = ttm_bo_vm_close -}; - -static struct ttm_buffer_object *ttm_bo_vm_lookup(struct ttm_bo_device *bdev, - unsigned long offset, - unsigned long pages) -{ - struct drm_vma_offset_node *node; - struct ttm_buffer_object *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, vma_node); - if (!kref_get_unless_zero(&bo->kref)) - bo = NULL; - } - - drm_vma_offset_unlock_lookup(&bdev->vma_manager); - - if (!bo) - pr_err("Could not find buffer object to map\n"); - - return bo; -} - -int ttm_bo_mmap(struct file *filp, struct vm_area_struct *vma, - struct ttm_bo_device *bdev) -{ - struct ttm_bo_driver *driver; - struct ttm_buffer_object *bo; - int ret; - - bo = ttm_bo_vm_lookup(bdev, vma->vm_pgoff, vma_pages(vma)); - if (unlikely(!bo)) - return -EINVAL; - - driver = bo->bdev->driver; - if (unlikely(!driver->verify_access)) { - ret = -EPERM; - goto out_unref; - } - ret = driver->verify_access(bo, filp); - if (unlikely(ret != 0)) - goto out_unref; - - vma->vm_ops = &ttm_bo_vm_ops; - - /* - * Note: We're transferring the bo reference to - * vma->vm_private_data here. - */ - - vma->vm_private_data = bo; - vma->vm_flags |= VM_IO | VM_MIXEDMAP | VM_DONTEXPAND | VM_DONTDUMP; - return 0; -out_unref: - ttm_bo_unref(&bo); - return ret; -} -EXPORT_SYMBOL(ttm_bo_mmap); - -int ttm_fbdev_mmap(struct vm_area_struct *vma, struct ttm_buffer_object *bo) -{ - if (vma->vm_pgoff != 0) - return -EACCES; - - vma->vm_ops = &ttm_bo_vm_ops; - vma->vm_private_data = ttm_bo_reference(bo); - vma->vm_flags |= VM_IO | VM_MIXEDMAP | VM_DONTEXPAND; - return 0; -} -EXPORT_SYMBOL(ttm_fbdev_mmap); +EXPORT_SYMBOL(ttm_bo_vm_fault); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c index 7776e6f0aef6..2503c65c274f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c @@ -593,14 +593,6 @@ void vmw_evict_flags(struct ttm_buffer_object *bo, *placement = vmw_sys_placement; } -static int vmw_verify_access(struct ttm_buffer_object *bo, struct file *filp) -{ - struct ttm_object_file *tfile = - vmw_fpriv((struct drm_file *)filp->private_data)->tfile; - - return vmw_user_dmabuf_verify_access(bo, tfile); -} - static int vmw_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) { struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; @@ -683,7 +675,6 @@ struct ttm_bo_driver vmw_bo_driver = { .init_mem_type = vmw_init_mem_type, .evict_flags = vmw_evict_flags, .move = NULL, - .verify_access = vmw_verify_access, .sync_obj_signaled = vmw_sync_obj_signaled, .sync_obj_wait = vmw_sync_obj_wait, .sync_obj_flush = vmw_sync_obj_flush, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 814665b7a117..65a95b71e5d5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -299,14 +299,19 @@ static void vmw_dummy_query_bo_prepare(struct vmw_private *dev_priv) */ static int vmw_dummy_query_bo_create(struct vmw_private *dev_priv) { - return ttm_bo_create(&dev_priv->bdev, - PAGE_SIZE, - ttm_bo_type_device, - &vmw_vram_sys_placement, - 0, false, NULL, - &dev_priv->dummy_query_bo); -} + struct vmw_dma_buffer *vmw_bo = kzalloc(sizeof(*vmw_bo), GFP_KERNEL); + int ret; + + if (!vmw_bo) + return -ENOMEM; + ret = vmw_dmabuf_init(dev_priv, vmw_bo, PAGE_SIZE, + &vmw_vram_sys_placement, false, + &vmw_dmabuf_bo_free); + if (!ret) + dev_priv->dummy_query_bo = &vmw_bo->base; + return ret; +} static int vmw_request_device(struct vmw_private *dev_priv) { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index e401d5dbcb96..e9fea03b1899 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -67,6 +67,7 @@ struct vmw_fpriv { struct vmw_dma_buffer { struct ttm_buffer_object base; + struct kref refcount; struct list_head res_list; }; @@ -511,6 +512,7 @@ extern int vmw_surface_check(struct vmw_private *dev_priv, uint32_t handle, int *id); extern int vmw_surface_validate(struct vmw_private *dev_priv, struct vmw_surface *srf); +extern void vmw_dmabuf_bo_release(struct kref *refcount); extern void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo); extern int vmw_dmabuf_init(struct vmw_private *dev_priv, struct vmw_dma_buffer *vmw_bo, @@ -842,18 +844,34 @@ static inline void vmw_dmabuf_unreference(struct vmw_dma_buffer **buf) struct vmw_dma_buffer *tmp_buf = *buf; *buf = NULL; - if (tmp_buf != NULL) { - struct ttm_buffer_object *bo = &tmp_buf->base; - - ttm_bo_unref(&bo); - } + if (tmp_buf != NULL) + kref_put(&tmp_buf->refcount, &vmw_dmabuf_bo_release); } static inline struct vmw_dma_buffer *vmw_dmabuf_reference(struct vmw_dma_buffer *buf) { - if (ttm_bo_reference(&buf->base)) - return buf; - return NULL; + kref_get(&buf->refcount); + return buf; +} + +static inline void ttm_bo_unref(struct ttm_buffer_object **bo) +{ + struct vmw_dma_buffer *buf; + + if (!*bo) + return; + + buf = container_of(*bo, struct vmw_dma_buffer, base); + *bo = NULL; + kref_put(&buf->refcount, &vmw_dmabuf_bo_release); +} + +static inline struct ttm_buffer_object *ttm_bo_reference(struct ttm_buffer_object *bo) +{ + struct vmw_dma_buffer *vmw_bo; + + vmw_bo = container_of(bo, struct vmw_dma_buffer, base); + return &vmw_dmabuf_reference(vmw_bo)->base; } static inline struct ttm_mem_global *vmw_mem_glob(struct vmw_private *dev_priv) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index d568432bec22..ecc162b788aa 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -357,6 +357,14 @@ void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo) kfree(vmw_bo); } +void vmw_dmabuf_bo_release(struct kref *refcount) +{ + struct vmw_dma_buffer *vmw_bo; + + vmw_bo = container_of(refcount, struct vmw_dma_buffer, refcount);; + ttm_bo_release(&vmw_bo->base); +} + int vmw_dmabuf_init(struct vmw_private *dev_priv, struct vmw_dma_buffer *vmw_bo, size_t size, struct ttm_placement *placement, @@ -373,6 +381,7 @@ int vmw_dmabuf_init(struct vmw_private *dev_priv, memset(vmw_bo, 0, sizeof(*vmw_bo)); INIT_LIST_HEAD(&vmw_bo->res_list); + kref_init(&vmw_bo->refcount); ret = ttm_bo_init(bdev, &vmw_bo->base, size, ttm_bo_type_device, placement, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c index 98d6bfb3a997..abba9b341e5a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c @@ -28,21 +28,71 @@ #include <drm/drmP.h> #include "vmwgfx_drv.h" +static void vmw_bo_vm_open(struct vm_area_struct *vma) +{ + struct vmw_dma_buffer *vmw_bo; + + vmw_bo = container_of(vma->vm_private_data, + struct vmw_dma_buffer, base); + + vmw_dmabuf_reference(vmw_bo); +} + +static void vmw_bo_vm_close(struct vm_area_struct *vma) +{ + struct vmw_dma_buffer *vmw_bo; + + vmw_bo = container_of(vma->vm_private_data, + struct vmw_dma_buffer, base); + + vmw_dmabuf_unreference(&vmw_bo); + vma->vm_private_data = NULL; +} + +static const struct vm_operations_struct vmw_ttm_vm_ops = { + .fault = ttm_bo_vm_fault, + .open = vmw_bo_vm_open, + .close = vmw_bo_vm_close +}; + int vmw_mmap(struct file *filp, struct vm_area_struct *vma) { - struct drm_file *file_priv; - struct vmw_private *dev_priv; + struct drm_file *file_priv = filp->private_data; + struct vmw_private *dev_priv = vmw_priv(file_priv->minor->dev); + struct drm_vma_offset_node *node; + struct vmw_dma_buffer *vmw_bo; + int ret; if (unlikely(vma->vm_pgoff < VMWGFX_FILE_PAGE_OFFSET)) { DRM_ERROR("Illegal attempt to mmap old fifo space.\n"); return -EINVAL; } - file_priv = filp->private_data; - dev_priv = vmw_priv(file_priv->minor->dev); - return ttm_bo_mmap(filp, vma, &dev_priv->bdev); -} + drm_vma_offset_lock_lookup(&dev_priv->bdev.vma_manager); + node = drm_vma_offset_lookup_locked(&dev_priv->bdev.vma_manager, + vma->vm_pgoff, vma_pages(vma)); + if (node) { + struct ttm_object_file *tfile = + vmw_fpriv((struct drm_file *)filp->private_data)->tfile; + + vmw_bo = container_of(vma->vm_private_data, + struct vmw_dma_buffer, base.vma_node); + + ret = vmw_user_dmabuf_verify_access(&vmw_bo->base, tfile); + if (!ret && !kref_get_unless_zero(&vmw_bo->refcount)) + ret = -EINVAL; + } else + ret = -EINVAL; + drm_vma_offset_unlock_lookup(&dev_priv->bdev.vma_manager); + + if (!ret) { + vma->vm_private_data = &vmw_bo->base; + vma->vm_flags |= VM_IO | VM_MIXEDMAP | VM_DONTEXPAND | VM_DONTDUMP; + vma->vm_ops = &vmw_ttm_vm_ops; + } + return ret; +} static int vmw_ttm_mem_global_init(struct drm_global_reference *ref) { DRM_INFO("global init.\n"); diff --git a/include/drm/drm_vma_manager.h b/include/drm/drm_vma_manager.h index c18a593d1744..905b052705e6 100644 --- a/include/drm/drm_vma_manager.h +++ b/include/drm/drm_vma_manager.h @@ -245,6 +245,8 @@ static inline void drm_vma_node_unmap(struct drm_vma_offset_node *node, * drm_vma_node_is_allowed() but suitable as drop-in helper for TTM * verify_access() callbacks. * + * This call requires the vm_lock to be held. + * * RETURNS: * 0 if access is granted, -EACCES otherwise. */ diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h index 751eaffbf0d5..07725c293a9b 100644 --- a/include/drm/ttm/ttm_bo_api.h +++ b/include/drm/ttm/ttm_bo_api.h @@ -197,8 +197,6 @@ struct ttm_buffer_object { /** * Members not needing protection. */ - - struct kref kref; struct kref list_kref; /** @@ -279,21 +277,6 @@ struct ttm_bo_kmap_obj { }; /** - * ttm_bo_reference - reference a struct ttm_buffer_object - * - * @bo: The buffer object. - * - * Returns a refcounted pointer to a buffer object. - */ - -static inline struct ttm_buffer_object * -ttm_bo_reference(struct ttm_buffer_object *bo) -{ - kref_get(&bo->kref); - return bo; -} - -/** * ttm_bo_wait - wait for buffer idle. * * @bo: The buffer object. @@ -331,13 +314,13 @@ extern int ttm_bo_validate(struct ttm_buffer_object *bo, bool no_wait_gpu); /** - * ttm_bo_unref + * ttm_bo_release * * @bo: The buffer object. * - * Unreference and clear a pointer to a buffer object. + * Release and destroy a buffer object. */ -extern void ttm_bo_unref(struct ttm_buffer_object **bo); +extern void ttm_bo_release(struct ttm_buffer_object *bo); /** @@ -483,41 +466,6 @@ extern int ttm_bo_init(struct ttm_bo_device *bdev, void (*destroy) (struct ttm_buffer_object *)); /** - * ttm_bo_synccpu_object_init - * - * @bdev: Pointer to a ttm_bo_device struct. - * @bo: Pointer to a ttm_buffer_object to be initialized. - * @size: Requested size of buffer object. - * @type: Requested type of buffer object. - * @flags: Initial placement flags. - * @page_alignment: Data alignment in pages. - * @interruptible: If needing to sleep while waiting for GPU resources, - * sleep interruptible. - * @persistent_swap_storage: Usually the swap storage is deleted for buffers - * pinned in physical memory. If this behaviour is not desired, this member - * holds a pointer to a persistent shmem object. Typically, this would - * point to the shmem object backing a GEM object if TTM is used to back a - * GEM user interface. - * @p_bo: On successful completion *p_bo points to the created object. - * - * This function allocates a ttm_buffer_object, and then calls ttm_bo_init - * on that object. The destroy function is set to kfree(). - * Returns - * -ENOMEM: Out of memory. - * -EINVAL: Invalid placement flags. - * -ERESTARTSYS: Interrupted by signal while waiting for resources. - */ - -extern int ttm_bo_create(struct ttm_bo_device *bdev, - unsigned long size, - enum ttm_bo_type type, - struct ttm_placement *placement, - uint32_t page_alignment, - bool interruptible, - struct file *persistent_swap_storage, - struct ttm_buffer_object **p_bo); - -/** * ttm_bo_check_placement * * @bo: the buffer object. @@ -649,57 +597,16 @@ extern int ttm_bo_kmap(struct ttm_buffer_object *bo, unsigned long start_page, extern void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map); /** - * ttm_fbdev_mmap - mmap fbdev memory backed by a ttm buffer object. + * ttm_bo_vm_fault - fault handler for mmap * - * @vma: vma as input from the fbdev mmap method. - * @bo: The bo backing the address space. The address space will - * have the same size as the bo, and start at offset 0. - * - * This function is intended to be called by the fbdev mmap method - * if the fbdev address space is to be backed by a bo. - */ - -extern int ttm_fbdev_mmap(struct vm_area_struct *vma, - struct ttm_buffer_object *bo); - -/** - * ttm_bo_mmap - mmap out of the ttm device address space. - * - * @filp: filp as input from the mmap method. * @vma: vma as input from the mmap method. - * @bdev: Pointer to the ttm_bo_device with the address space manager. + * @vm_fault: passed by the mmap fault handler * - * This function is intended to be called by the device mmap method. - * if the device address space is to be backed by the bo manager. - */ - -extern int ttm_bo_mmap(struct file *filp, struct vm_area_struct *vma, - struct ttm_bo_device *bdev); - -/** - * ttm_bo_io - * - * @bdev: Pointer to the struct ttm_bo_device. - * @filp: Pointer to the struct file attempting to read / write. - * @wbuf: User-space pointer to address of buffer to write. NULL on read. - * @rbuf: User-space pointer to address of buffer to read into. - * Null on write. - * @count: Number of bytes to read / write. - * @f_pos: Pointer to current file position. - * @write: 1 for read, 0 for write. - * - * This function implements read / write into ttm buffer objects, and is - * intended to - * be called from the fops::read and fops::write method. - * Returns: - * See man (2) write, man(2) read. In particular, - * the function may return -ERESTARTSYS if - * interrupted by a signal. + * This function is intended to be called by the mmap fault method. + * With vma->vm_private set to the faulting bo */ -extern ssize_t ttm_bo_io(struct ttm_bo_device *bdev, struct file *filp, - const char __user *wbuf, char __user *rbuf, - size_t count, loff_t *f_pos, bool write); +int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf); extern void ttm_bo_swapout_all(struct ttm_bo_device *bdev); diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h index 8639c85d61c4..02581f10ca3e 100644 --- a/include/drm/ttm/ttm_bo_driver.h +++ b/include/drm/ttm/ttm_bo_driver.h @@ -401,21 +401,6 @@ struct ttm_bo_driver { struct ttm_mem_reg *new_mem); /** - * struct ttm_bo_driver_member verify_access - * - * @bo: Pointer to a buffer object. - * @filp: Pointer to a struct file trying to access the object. - * - * Called from the map / write / read methods to verify that the - * caller is permitted to access the buffer object. - * This member may be set to NULL, which will refuse this kind of - * access for all buffer objects. - * This function should return 0 if access is granted, -EPERM otherwise. - */ - int (*verify_access) (struct ttm_buffer_object *bo, - struct file *filp); - - /** * In case a driver writer dislikes the TTM fence objects, * the driver writer can replace those with sync objects of * his / her own. If it turns out that no driver writer is @@ -875,8 +860,6 @@ static inline int ttm_bo_reserve(struct ttm_buffer_object *bo, { int ret; - WARN_ON(!atomic_read(&bo->kref.refcount)); - ret = ttm_bo_reserve_nolru(bo, interruptible, no_wait, use_ticket, ticket); if (likely(ret == 0)) @@ -901,8 +884,6 @@ static inline int ttm_bo_reserve_slowpath(struct ttm_buffer_object *bo, { int ret = 0; - WARN_ON(!atomic_read(&bo->kref.refcount)); - if (interruptible) ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock, ticket); _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel