接前一篇文章:DRM全解析 ------ CREATE_DUMB(3)
本文参考以下博文:
特此致谢!
上一回讲解了Intel i915、AMD Raedon和AMDGPU三类显卡驱动中的dumb_create函数指针所指向的实际函数,最终聚焦到drm_gem_handle_create函数。本回就来讲解一下这个函数。
drm_gem_handle_create函数在drivers/gpu/drm/drm_gem.c中,代码如下:
cpp
/**
* drm_gem_handle_create - create a gem handle for an object
* @file_priv: drm file-private structure to register the handle for
* @obj: object to register
* @handlep: pointer to return the created handle to the caller
*
* Create a handle for this object. This adds a handle reference to the object,
* which includes a regular reference count. Callers will likely want to
* dereference the object afterwards.
*
* Since this publishes @obj to userspace it must be fully set up by this point,
* drivers must call this last in their buffer object creation callbacks.
*/
int drm_gem_handle_create(struct drm_file *file_priv,
struct drm_gem_object *obj,
u32 *handlep)
{
mutex_lock(&obj->dev->object_name_lock);
return drm_gem_handle_create_tail(file_priv, obj, handlep);
}
EXPORT_SYMBOL(drm_gem_handle_create);
此函数比较简单,在加互斥锁后,把实际的工作交给了drm_gem_handle_create_tail函数。drm_gem_handle_create_tail函数就在它的上边,代码如下:
cpp
/**
* drm_gem_handle_create_tail - internal functions to create a handle
* @file_priv: drm file-private structure to register the handle for
* @obj: object to register
* @handlep: pointer to return the created handle to the caller
*
* This expects the &drm_device.object_name_lock to be held already and will
* drop it before returning. Used to avoid races in establishing new handles
* when importing an object from either an flink name or a dma-buf.
*
* Handles must be release again through drm_gem_handle_delete(). This is done
* when userspace closes @file_priv for all attached handles, or through the
* GEM_CLOSE ioctl for individual handles.
*/
int
drm_gem_handle_create_tail(struct drm_file *file_priv,
struct drm_gem_object *obj,
u32 *handlep)
{
struct drm_device *dev = obj->dev;
u32 handle;
int ret;
WARN_ON(!mutex_is_locked(&dev->object_name_lock));
if (obj->handle_count++ == 0)
drm_gem_object_get(obj);
/*
* Get the user-visible handle using idr. Preload and perform
* allocation under our spinlock.
*/
idr_preload(GFP_KERNEL);
spin_lock(&file_priv->table_lock);
ret = idr_alloc(&file_priv->object_idr, obj, 1, 0, GFP_NOWAIT);
spin_unlock(&file_priv->table_lock);
idr_preload_end();
mutex_unlock(&dev->object_name_lock);
if (ret < 0)
goto err_unref;
handle = ret;
ret = drm_vma_node_allow(&obj->vma_node, file_priv);
if (ret)
goto err_remove;
if (obj->funcs->open) {
ret = obj->funcs->open(obj, file_priv);
if (ret)
goto err_revoke;
}
*handlep = handle;
return 0;
err_revoke:
drm_vma_node_revoke(&obj->vma_node, file_priv);
err_remove:
spin_lock(&file_priv->table_lock);
idr_remove(&file_priv->object_idr, handle);
spin_unlock(&file_priv->table_lock);
err_unref:
drm_gem_object_handle_put_unlocked(obj);
return ret;
}
drm_gem_handle_create_tail主要是使用idr_alloc将drm_gem_object对象添加到file_priv->object_idr,并返回handle。
这里顺带提一下idr_alloc函数,其在lib/idr.c中,代码如下:
cpp
/**
* idr_alloc() - Allocate an ID.
* @idr: IDR handle.
* @ptr: Pointer to be associated with the new ID.
* @start: The minimum ID (inclusive).
* @end: The maximum ID (exclusive).
* @gfp: Memory allocation flags.
*
* Allocates an unused ID in the range specified by @start and @end. If
* @end is <= 0, it is treated as one larger than %INT_MAX. This allows
* callers to use @start + N as @end as long as N is within integer range.
*
* The caller should provide their own locking to ensure that two
* concurrent modifications to the IDR are not possible. Read-only
* accesses to the IDR may be done under the RCU read lock or may
* exclude simultaneous writers.
*
* Return: The newly allocated ID, -ENOMEM if memory allocation failed,
* or -ENOSPC if no free IDs could be found.
*/
int idr_alloc(struct idr *idr, void *ptr, int start, int end, gfp_t gfp)
{
u32 id = start;
int ret;
if (WARN_ON_ONCE(start < 0))
return -EINVAL;
ret = idr_alloc_u32(idr, ptr, &id, end > 0 ? end - 1 : INT_MAX, gfp);
if (ret)
return ret;
return id;
}
EXPORT_SYMBOL_GPL(idr_alloc);
为了便于理解,再看一下调用代码片段:
cpp
ret = idr_alloc(&file_priv->object_idr, obj, 1, 0, GFP_NOWAIT);
idr_alloc函数的作用是使用一个id与一个obj绑定,这样就可以通过id找到对应obj。这里将handle与分配的gem_object进行绑定,后面通过handle就可以找到gem_object进而找到对应的物理地址或者虚拟地址了。
至此,整个CREATE_DUMB流程就基本分析完了。