int ttm_vt_lock(struct ttm_lock *lock, bool interruptible, struct ttm_object_file *tfile) { int ret = 0; if (interruptible) { ret = wait_event_interruptible(lock->queue, __ttm_vt_lock(lock)); if (unlikely(ret != 0)) { spin_lock(&lock->lock); lock->flags &= ~TTM_VT_LOCK_PENDING; wake_up_all(&lock->queue); spin_unlock(&lock->lock); return ret; } } else wait_event(lock->queue, __ttm_vt_lock(lock)); /* */ ret = ttm_base_object_init(tfile, &lock->base, false, ttm_lock_type, &ttm_vt_lock_remove, NULL); if (ret) (void)__ttm_vt_unlock(lock); else lock->vt_holder = tfile; return ret; }
int ttm_vt_lock(struct ttm_lock *lock, bool interruptible, struct ttm_object_file *tfile) { int ret = 0; if (interruptible) { ret = wait_event_interruptible(lock->queue, __ttm_vt_lock(lock)); if (unlikely(ret != 0)) { spin_lock(&lock->lock); lock->flags &= ~TTM_VT_LOCK_PENDING; wake_up_all(&lock->queue); spin_unlock(&lock->lock); return ret; } } else wait_event(lock->queue, __ttm_vt_lock(lock)); /* * Add a base-object, the destructor of which will * make sure the lock is released if the client dies * while holding it. */ ret = ttm_base_object_init(tfile, &lock->base, false, ttm_lock_type, &ttm_vt_lock_remove, NULL); if (ret) (void)__ttm_vt_unlock(lock); else lock->vt_holder = tfile; return ret; }
int ttm_vt_lock(struct ttm_lock *lock, bool interruptible, struct ttm_object_file *tfile) { const char *wmsg; int flags, ret; ret = 0; if (interruptible) { flags = PCATCH; wmsg = "ttmwi"; } else { flags = 0; wmsg = "ttmw"; } mtx_lock(&lock->lock); while (!__ttm_vt_lock(lock)) { ret = msleep(lock, &lock->lock, flags, wmsg, 0); if (ret == EINTR) ret = ERESTARTSYS; if (interruptible && ret != 0) { lock->flags &= ~TTM_VT_LOCK_PENDING; wakeup(lock); break; } } /* * Add a base-object, the destructor of which will * make sure the lock is released if the client dies * while holding it. */ ret = ttm_base_object_init(tfile, &lock->base, false, ttm_lock_type, &ttm_vt_lock_remove, NULL); if (ret) (void)__ttm_vt_unlock(lock); else lock->vt_holder = tfile; return (-ret); }
int ttm_pl_ub_create_ioctl(struct ttm_object_file *tfile, struct ttm_bo_device *bdev, struct ttm_lock *lock, void *data) { union ttm_pl_create_ub_arg *arg = data; struct ttm_pl_create_ub_req *req = &arg->req; struct ttm_pl_rep *rep = &arg->rep; struct ttm_buffer_object *bo; struct ttm_buffer_object *tmp; struct ttm_bo_user_object *user_bo; uint32_t flags; int ret = 0; struct ttm_mem_global *mem_glob = bdev->glob->mem_glob; struct ttm_placement placement = default_placement; #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0)) size_t acc_size = ttm_pl_size(bdev, (req->size + PAGE_SIZE - 1) >> PAGE_SHIFT); #else size_t acc_size = ttm_bo_acc_size(bdev, req->size, sizeof(struct ttm_buffer_object)); #endif if (req->user_address & ~PAGE_MASK) { printk(KERN_ERR "User pointer buffer need page alignment\n"); return -EFAULT; } ret = ttm_mem_global_alloc(mem_glob, acc_size, false, false); if (unlikely(ret != 0)) return ret; flags = req->placement; user_bo = kzalloc(sizeof(*user_bo), GFP_KERNEL); if (unlikely(user_bo == NULL)) { ttm_mem_global_free(mem_glob, acc_size); return -ENOMEM; } ret = ttm_read_lock(lock, true); if (unlikely(ret != 0)) { ttm_mem_global_free(mem_glob, acc_size); kfree(user_bo); return ret; } bo = &user_bo->bo; placement.num_placement = 1; placement.placement = &flags; #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0)) /* For kernel 3.0, use the desired type. */ #define TTM_HACK_WORKAROUND_ttm_bo_type_user ttm_bo_type_user #else /* TTM_HACK_WORKAROUND_ttm_bo_type_user -- Hack for porting, as ttm_bo_type_user is no longer implemented. This will not result in working code. FIXME - to be removed. */ #warning warning: ttm_bo_type_user no longer supported /* For kernel 3.3+, use the wrong type, which will compile but not work. */ #define TTM_HACK_WORKAROUND_ttm_bo_type_user ttm_bo_type_kernel #endif #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 3, 0)) /* Handle frame buffer allocated in user space, Convert user space virtual address into pages list */ unsigned int page_nr = 0; struct vm_area_struct *vma = NULL; struct sg_table *sg = NULL; unsigned long num_pages = 0; struct page **pages = 0; num_pages = (req->size + PAGE_SIZE - 1) >> PAGE_SHIFT; pages = kzalloc(num_pages * sizeof(struct page *), GFP_KERNEL); if (unlikely(pages == NULL)) { printk(KERN_ERR "kzalloc pages failed\n"); return -ENOMEM; } down_read(¤t->mm->mmap_sem); vma = find_vma(current->mm, req->user_address); if (unlikely(vma == NULL)) { up_read(¤t->mm->mmap_sem); kfree(pages); printk(KERN_ERR "find_vma failed\n"); return -EFAULT; } unsigned long before_flags = vma->vm_flags; if (vma->vm_flags & (VM_IO | VM_PFNMAP)) vma->vm_flags = vma->vm_flags & ((~VM_IO) & (~VM_PFNMAP)); page_nr = get_user_pages(current, current->mm, req->user_address, (int)(num_pages), 1, 0, pages, NULL); vma->vm_flags = before_flags; up_read(¤t->mm->mmap_sem); /* can be written by caller, not forced */ if (unlikely(page_nr < num_pages)) { kfree(pages); pages = 0; printk(KERN_ERR "get_user_pages err.\n"); return -ENOMEM; } sg = drm_prime_pages_to_sg(pages, num_pages); if (unlikely(sg == NULL)) { kfree(pages); printk(KERN_ERR "drm_prime_pages_to_sg err.\n"); return -ENOMEM; } kfree(pages); #endif #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)) ret = ttm_bo_init(bdev, bo, req->size, TTM_HACK_WORKAROUND_ttm_bo_type_user, &placement, req->page_alignment, req->user_address, true, NULL, acc_size, NULL, &ttm_bo_user_destroy); #elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) ret = ttm_bo_init(bdev, bo, req->size, ttm_bo_type_sg, &placement, req->page_alignment, req->user_address, true, NULL, acc_size, sg, &ttm_ub_bo_user_destroy); #else ret = ttm_bo_init(bdev, bo, req->size, ttm_bo_type_sg, &placement, req->page_alignment, true, NULL, acc_size, sg, &ttm_ub_bo_user_destroy); #endif /* * Note that the ttm_buffer_object_init function * would've called the destroy function on failure!! */ ttm_read_unlock(lock); if (unlikely(ret != 0)) goto out; tmp = ttm_bo_reference(bo); ret = ttm_base_object_init(tfile, &user_bo->base, flags & TTM_PL_FLAG_SHARED, ttm_buffer_type, &ttm_bo_user_release, &ttm_bo_user_ref_release); if (unlikely(ret != 0)) goto out_err; ret = ttm_bo_reserve(bo, true, false, false, 0); if (unlikely(ret != 0)) goto out_err; ttm_pl_fill_rep(bo, rep); ttm_bo_unreserve(bo); ttm_bo_unref(&bo); out: return 0; out_err: ttm_bo_unref(&tmp); ttm_bo_unref(&bo); return ret; }
int ttm_pl_create_ioctl(struct ttm_object_file *tfile, struct ttm_bo_device *bdev, struct ttm_lock *lock, void *data) { union ttm_pl_create_arg *arg = data; struct ttm_pl_create_req *req = &arg->req; struct ttm_pl_rep *rep = &arg->rep; struct ttm_buffer_object *bo; struct ttm_buffer_object *tmp; struct ttm_bo_user_object *user_bo; uint32_t flags; int ret = 0; struct ttm_mem_global *mem_glob = bdev->glob->mem_glob; struct ttm_placement placement = default_placement; #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0)) size_t acc_size = ttm_pl_size(bdev, (req->size + PAGE_SIZE - 1) >> PAGE_SHIFT); #else size_t acc_size = ttm_bo_acc_size(bdev, req->size, sizeof(struct ttm_buffer_object)); #endif ret = ttm_mem_global_alloc(mem_glob, acc_size, false, false); if (unlikely(ret != 0)) return ret; flags = req->placement; user_bo = kzalloc(sizeof(*user_bo), GFP_KERNEL); if (unlikely(user_bo == NULL)) { ttm_mem_global_free(mem_glob, acc_size); return -ENOMEM; } bo = &user_bo->bo; ret = ttm_read_lock(lock, true); if (unlikely(ret != 0)) { ttm_mem_global_free(mem_glob, acc_size); kfree(user_bo); return ret; } placement.num_placement = 1; placement.placement = &flags; if ((flags & TTM_PL_MASK_CACHING) == 0) flags |= TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED; #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) ret = ttm_bo_init(bdev, bo, req->size, ttm_bo_type_device, &placement, req->page_alignment, 0, true, NULL, acc_size, NULL, &ttm_bo_user_destroy); #else ret = ttm_bo_init(bdev, bo, req->size, ttm_bo_type_device, &placement, req->page_alignment, true, NULL, acc_size, NULL, &ttm_bo_user_destroy); #endif ttm_read_unlock(lock); /* * Note that the ttm_buffer_object_init function * would've called the destroy function on failure!! */ if (unlikely(ret != 0)) goto out; tmp = ttm_bo_reference(bo); ret = ttm_base_object_init(tfile, &user_bo->base, flags & TTM_PL_FLAG_SHARED, ttm_buffer_type, &ttm_bo_user_release, &ttm_bo_user_ref_release); if (unlikely(ret != 0)) goto out_err; ret = ttm_bo_reserve(bo, true, false, false, 0); if (unlikely(ret != 0)) goto out_err; ttm_pl_fill_rep(bo, rep); ttm_bo_unreserve(bo); ttm_bo_unref(&bo); out: return 0; out_err: ttm_bo_unref(&tmp); ttm_bo_unref(&bo); return ret; }
/** * vmw_simple_resource_create_ioctl - Helper to set up an ioctl function to * create a struct vmw_simple_resource. * * @dev: Pointer to a struct drm device. * @data: Ioctl argument. * @file_priv: Pointer to a struct drm_file identifying the caller. * @func: Pointer to a struct vmw_simple_resource_func identifying the * simple resource type. * * Returns: * 0 if success, * Negative error value on error. */ int vmw_simple_resource_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv, const struct vmw_simple_resource_func *func) { struct vmw_private *dev_priv = vmw_priv(dev); struct vmw_user_simple_resource *usimple; struct vmw_resource *res; struct vmw_resource *tmp; struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; struct ttm_operation_ctx ctx = { .interruptible = true, .no_wait_gpu = false }; size_t alloc_size; size_t account_size; int ret; alloc_size = offsetof(struct vmw_user_simple_resource, simple) + func->size; account_size = ttm_round_pot(alloc_size) + VMW_IDA_ACC_SIZE + TTM_OBJ_EXTRA_SIZE; ret = ttm_read_lock(&dev_priv->reservation_sem, true); if (ret) return ret; ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), account_size, &ctx); ttm_read_unlock(&dev_priv->reservation_sem); if (ret) { if (ret != -ERESTARTSYS) DRM_ERROR("Out of graphics memory for %s" " creation.\n", func->res_func.type_name); goto out_ret; } usimple = kzalloc(alloc_size, GFP_KERNEL); if (!usimple) { ttm_mem_global_free(vmw_mem_glob(dev_priv), account_size); ret = -ENOMEM; goto out_ret; } usimple->simple.func = func; usimple->account_size = account_size; res = &usimple->simple.res; usimple->base.shareable = false; usimple->base.tfile = NULL; /* * From here on, the destructor takes over resource freeing. */ ret = vmw_simple_resource_init(dev_priv, &usimple->simple, data, vmw_simple_resource_free); if (ret) goto out_ret; tmp = vmw_resource_reference(res); ret = ttm_base_object_init(tfile, &usimple->base, false, func->ttm_res_type, &vmw_simple_resource_base_release, NULL); if (ret) { vmw_resource_unreference(&tmp); goto out_err; } func->set_arg_handle(data, usimple->base.handle); out_err: vmw_resource_unreference(&res); out_ret: return ret; } /** * vmw_simple_resource_lookup - Look up a simple resource from its user-space * handle. * * @tfile: struct ttm_object_file identifying the caller. * @handle: The user-space handle. * @func: The struct vmw_simple_resource_func identifying the simple resource * type. * * Returns: Refcounted pointer to the embedded struct vmw_resource if * successfule. Error pointer otherwise. */ struct vmw_resource * vmw_simple_resource_lookup(struct ttm_object_file *tfile, uint32_t handle, const struct vmw_simple_resource_func *func) { struct vmw_user_simple_resource *usimple; struct ttm_base_object *base; struct vmw_resource *res; base = ttm_base_object_lookup(tfile, handle); if (!base) { DRM_ERROR("Invalid %s handle 0x%08lx.\n", func->res_func.type_name, (unsigned long) handle); return ERR_PTR(-ESRCH); } if (ttm_base_object_type(base) != func->ttm_res_type) { ttm_base_object_unref(&base); DRM_ERROR("Invalid type of %s handle 0x%08lx.\n", func->res_func.type_name, (unsigned long) handle); return ERR_PTR(-EINVAL); } usimple = container_of(base, typeof(*usimple), base); res = vmw_resource_reference(&usimple->simple.res); ttm_base_object_unref(&base); return res; }