linux内核radeon gpu源码解析4 —— drm_get_pci_dev函数详解1
上一篇讲到了drm_get_pci_dev函数,这是一个比较关键的函数,其中调用了几个函数,现在一一进行详细说明。再把函数的完整代码贴出来,在drivers/gpu/drm/drm_pci.c中:
/**
* drm_get_pci_dev - Register a PCI device with the DRM subsystem
* @pdev: PCI device
* @ent: entry from the PCI ID table that matches @pdev
* @driver: DRM device driver
*
* Attempt to gets inter module "drm" information. If we are first
* then register the character device and inter module information.
* Try and register, if we fail to register, backout previous work.
*
* NOTE: This function is deprecated, please use drm_dev_alloc() and
* drm_dev_register() instead and remove your &drm_driver.load callback.
*
* Return: 0 on success or a negative error code on failure.
*/
int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
struct drm_driver *driver)
{
struct drm_device *dev;
int ret;
DRM_DEBUG("\n");
dev = drm_dev_alloc(driver, &pdev->dev);
if (IS_ERR(dev))
return PTR_ERR(dev);
ret = pci_enable_device(pdev);
if (ret)
goto err_free;
dev->pdev = pdev;
#ifdef __alpha__
dev->hose = pdev->sysdata;
#endif
if (drm_core_check_feature(dev, DRIVER_MODESET))
pci_set_drvdata(pdev, dev);
drm_pci_agp_init(dev);
ret = drm_dev_register(dev, ent->driver_data);
if (ret)
goto err_agp;
/* No locking needed since shadow-attach is single-threaded since it may
* only be called from the per-driver module init hook. */
if (drm_core_check_feature(dev, DRIVER_LEGACY))
list_add_tail(&dev->legacy_dev_list, &driver->legacy_dev_list);
return 0;
err_agp:
drm_pci_agp_destroy(dev);
pci_disable_device(pdev);
err_free:
drm_dev_put(dev);
return ret;
}
EXPORT_SYMBOL(drm_get_pci_dev);
先说第1个函数:drm_dev_alloc。
调用处:dev = drm_dev_alloc(driver, &pdev->dev);
源码如下:
drivers/gpu/drm/drm_drv.c
/**
* drm_dev_alloc - Allocate new DRM device
* @driver: DRM driver to allocate device for
* @parent: Parent device object
*
* Allocate and initialize a new DRM device. No device registration is done.
* Call drm_dev_register() to advertice the device to user space and register it
* with other core subsystems. This should be done last in the device
* initialization sequence to make sure userspace can't access an inconsistent
* state.
*
* The initial ref-count of the object is 1. Use drm_dev_get() and
* drm_dev_put() to take and drop further ref-counts.
*
* Note that for purely virtual devices @parent can be NULL.
*
* Drivers that wish to subclass or embed &struct drm_device into their
* own struct should look at using drm_dev_init() instead.
*
* RETURNS:
* Pointer to new DRM device, or ERR_PTR on failure.
*/
struct drm_device *drm_dev_alloc(struct drm_driver *driver,
struct device *parent)
{
struct drm_device *dev;
int ret;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return ERR_PTR(-ENOMEM);
ret = drm_dev_init(dev, driver, parent);
if (ret) {
kfree(dev);
return ERR_PTR(ret);
}
return dev;
}
EXPORT_SYMBOL(drm_dev_alloc);
这个函数的参数struct drm_driver *driver其实就是指向了kms_driver。
函数完成的事情也挺好理解,就是先分配了一个struct drm_device 结构,并使用dev指向这个结构,其实就是新建了一个drm设备。
接下来调用drm_dev_init函数对于这个新建的设备进行初始化。代码如下:
drivers/gpu/drm/drm_drv.c:
/**
* drm_dev_init - Initialise new DRM device
* @dev: DRM device
* @driver: DRM driver
* @parent: Parent device object
*
* Initialize a new DRM device. No device registration is done.
* Call drm_dev_register() to advertice the device to user space and register it
* with other core subsystems. This should be done last in the device
* initialization sequence to make sure userspace can't access an inconsistent
* state.
*
* The initial ref-count of the object is 1. Use drm_dev_get() and
* drm_dev_put() to take and drop further ref-counts.
*
* Note that for purely virtual devices @parent can be NULL.
*
* Drivers that do not want to allocate their own device struct
* embedding &struct drm_device can call drm_dev_alloc() instead. For drivers
* that do embed &struct drm_device it must be placed first in the overall
* structure, and the overall structure must be allocated using kmalloc(): The
* drm core's release function unconditionally calls kfree() on the @dev pointer
* when the final reference is released. To override this behaviour, and so
* allow embedding of the drm_device inside the driver's device struct at an
* arbitrary offset, you must supply a &drm_driver.release callback and control
* the finalization explicitly.
*
* RETURNS:
* 0 on success, or error code on failure.
*/
int drm_dev_init(struct drm_device *dev,
struct drm_driver *driver,
struct device *parent)
{
int ret;
if (!drm_core_init_complete) {
DRM_ERROR("DRM core is not initialized\n");
return -ENODEV;
}
kref_init(&dev->ref);
dev->dev = get_device(parent);
dev->driver = driver;
INIT_LIST_HEAD(&dev->filelist);
INIT_LIST_HEAD(&dev->filelist_internal);
INIT_LIST_HEAD(&dev->clientlist);
INIT_LIST_HEAD(&dev->ctxlist);
INIT_LIST_HEAD(&dev->vmalist);
INIT_LIST_HEAD(&dev->maplist);
INIT_LIST_HEAD(&dev->vblank_event_list);
spin_lock_init(&dev->buf_lock);
spin_lock_init(&dev->event_lock);
mutex_init(&dev->struct_mutex);
mutex_init(&dev->filelist_mutex);
mutex_init(&dev->clientlist_mutex);
mutex_init(&dev->ctxlist_mutex);
mutex_init(&dev->master_mutex);
dev->anon_inode = drm_fs_inode_new();
if (IS_ERR(dev->anon_inode)) {
ret = PTR_ERR(dev->anon_inode);
DRM_ERROR("Cannot allocate anonymous inode: %d\n", ret);
goto err_free;
}
if (drm_core_check_feature(dev, DRIVER_RENDER)) {
ret = drm_minor_alloc(dev, DRM_MINOR_RENDER);
if (ret)
goto err_minors;
}
ret = drm_minor_alloc(dev, DRM_MINOR_PRIMARY);
if (ret)
goto err_minors;
ret = drm_ht_create(&dev->map_hash, 12);
if (ret)
goto err_minors;
drm_legacy_ctxbitmap_init(dev);
if (drm_core_check_feature(dev, DRIVER_GEM)) {
ret = drm_gem_init(dev);
if (ret) {
DRM_ERROR("Cannot initialize graphics execution manager (GEM)\n");
goto err_ctxbitmap;
}
}
/* Use the parent device name as DRM device unique identifier, but fall
* back to the driver name for virtual devices like vgem. */
ret = drm_dev_set_unique(dev, parent ? dev_name(parent) : driver->name);
if (ret)
goto err_setunique;
return 0;
err_setunique:
if (drm_core_check_feature(dev, DRIVER_GEM))
drm_gem_destroy(dev);
err_ctxbitmap:
drm_legacy_ctxbitmap_cleanup(dev);
drm_ht_remove(&dev->map_hash);
err_minors:
drm_minor_free(dev, DRM_MINOR_PRIMARY);
drm_minor_free(dev, DRM_MINOR_RENDER);
drm_fs_inode_free(dev->anon_inode);
err_free:
put_device(dev->dev);
mutex_destroy(&dev->master_mutex);
mutex_destroy(&dev->ctxlist_mutex);
mutex_destroy(&dev->clientlist_mutex);
mutex_destroy(&dev->filelist_mutex);
mutex_destroy(&dev->struct_mutex);
return ret;
}
EXPORT_SYMBOL(drm_dev_init);
函数说明已经说得很清楚了,drm_dev_init函数初始化了一个新的DRM设备。其实就是给上边新分配的struct drm_device *dev赋值。
传入的参数在这两句程序中用到:
dev->dev = get_device(parent);
dev->driver = driver;
其余的注意事项在函数注释中也已经说得很清楚了,直接看函数注释就好,这里就不再翻译成中文了。
通过drm_dev_alloc函数中的drm_dev_init函数和drm_get_pci_dev 函数中的drm_dev_register函数,DRM框架为我们做了如下事情:
- 创建设备节点:/dev/dri/card0
- 创建sysfs节点:/sys/class/drm/card0
- 创建debugfs节点:/sys/kernel/debug/dri/0
参考资料:
DRM驱动程序开发(VKMS)(DRM 驱动程序开发(VKMS)_何小龙的博客-CSDN博客_/dev/dri/card0)
相关文章
- [Linux] Linux软连接和硬链接
- linux驱动开发--copy_to_user 、copy_from_user函数实现内核空间数据与用户空间数据的相互访问
- 【华为云技术分享】Linux内核补丁源码分析(1)
- 【华为云技术分享】Linux内核源码结构(1)
- Linux探秘之用户态与内核态
- 【Linux 内核 内存管理】物理分配页 ⑦ ( __alloc_pages_slowpath 慢速路径调用函数源码分析 | 判断页阶数 | 读取 mems_allowed | 分配标志位转换 )
- 【Linux 内核 内存管理】munmap 系统调用源码分析 ① ( munmap 系统调用函数执行流程 | munmap 函数源码 | vm_munmap 函数源码 )
- 【Linux 内核 内存管理】内存管理系统调用 ⑤ ( 代码示例 | 多进程共享 mmap 内存映射示例 )
- 【Linux 内核 内存管理】内存映射相关数据结构 ③ ( vm_area_struct 结构体成员分析 | shared 成员 | anon_vma_chain 成员 | anon_vma 成员 )
- 【Linux 内核 内存管理】内存映射原理 ② ( 内存映射概念 | 文件映射 | 匿名映射 | 内存映射原理 | 分配虚拟内存页 | 产生缺页异常 | 分配物理内存页 | 共享内存 | 进程内存 )
- 【Linux 内核 内存管理】虚拟地址空间布局架构 ② ( 用户虚拟地址空间组成 | 内存描述符 mm_struct 结构体源码 )
- 【Linux 内核 内存管理】Linux 内核堆内存管理 ② ( 动态分配堆内存方式 | brk 系统调用 | mmap 系统调用 | brk 系统调用源码介绍 )
- 【Linux 内核】实时调度类 ⑦ ( 实时调度类核心函数源码分析 | dequeue_task_rt 函数 | 从执行队列中移除进程 )
- 【Linux 内核】实时调度类 ③ ( 实时调度类 rt_sched_class 源码 | 调度类 sched_class 源码 )
- 【Linux 内核】调度器 ② ( sched_class 调度类结构体源码 | 源码路径 linux-5.6.18kernelschedsched.h )
- 【Linux 内核】进程管理 ( 系统调用简介 | 进程相关系统调用源码 )
- 【Linux 内核】编译 Linux 内核 ① ( 下载指定版本的 Linux 内核源码 | Linux 内核版本号含义 | 主版本号 | 次版本号 | 小版本号 | 稳定版本 )
- 【Linux 内核】宏内核与微内核架构 ( 操作系统需要满足的要素 | 宏内核 | 微内核 | Linux 内核动态加载机制 )
- L82.linux命令每日一练 -- 第11章 Linux系统管理命令 -- dmidecode和lspci
- L58.linux命令每日一练 -- 第九章 Linux进程管理命令 -- pgrep和kill
- linux内核radeon gpu源码解析7 —— radeon_driver_load_kms函数详解2
- Linux【实操篇】—— 用户管理、linux系统root密码找回方式
- linux内核radeon gpu源码解析3 —— Radeon初始化
- 嵌入式Linux开发,USB声卡驱动,内核配置
- Linux内核源码介绍