当前位置: 首页 > article >正文

DRM系列四:初始化drm设备--drm_dev_init

本系列文章基于linux 5.15

一、drm_dev_alloc

用于分配并初始化一个新的 DRM 设备(即drm_device),初始化主要调用drm_dev_init函数

1.1drm_dev_init

drm_device的初始化操作,但是并不会注册,函数定义在drivers/gpu/drm/drm_drv.c
其主要的作用:

  • 对应成员变量的简单初始化
  • 检测 drm_driver 的 driver_features 标志位是否设置 DRIVER_RENDER , 有则创建对应的设备
    dev/dri/enderD(128 - 192)
  • 创建一个 DRM_MINOR_PRIMARY 子设备, 每个 drm_device 必须有一个默认的 DRM_MINOR_PRIMARY 设备dev/dri/card(0 - 64)
  • 检测drm_device的 drm_driver 的 driver_features 标志位是否设置 DRIVER_GEM ,如果设置了则会为我们分配并创建一个默认的起始偏移地址为 DRM_FILE_PAGE_OFFSET_START内存大小为 DRM_FILE_PAGE_OFFSET_SIZE的 vma_offset_manager
  • 将父设备名称用作 DRM 设备的唯一标识符 unique(drm_device的成员变量),没有父设备则使用驱动程序名称作为 unique唯一标识符.
static int drm_dev_init(struct drm_device *dev,
			const struct drm_driver *driver,
			struct device *parent)
{
	int ret;

	if (!drm_core_init_complete) {
		DRM_ERROR("DRM core is not initialized\n");
		return -ENODEV;
	}

	if (WARN_ON(!parent))
		return -EINVAL;

	kref_init(&dev->ref);
	dev->dev = get_device(parent);
	dev->driver = driver;

	INIT_LIST_HEAD(&dev->managed.resources);
	spin_lock_init(&dev->managed.lock);

	/* no per-device feature limits by default */
	dev->driver_features = ~0u;

	drm_legacy_init_members(dev);
	INIT_LIST_HEAD(&dev->filelist);
	INIT_LIST_HEAD(&dev->filelist_internal);
	INIT_LIST_HEAD(&dev->clientlist);
	INIT_LIST_HEAD(&dev->vblank_event_list);

	spin_lock_init(&dev->event_lock);
	mutex_init(&dev->struct_mutex);
	mutex_init(&dev->filelist_mutex);
	mutex_init(&dev->clientlist_mutex);
	mutex_init(&dev->master_mutex);

	ret = drmm_add_action(dev, drm_dev_init_release, NULL);
	if (ret)
		return ret;

	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;
	}
	/*检测 drm_driver 的 driver_features 标志位是否设置 DRIVER_RENDER , 有则创建对应的设备
   dev/dri/enderD(128 - 192)*/
	if (drm_core_check_feature(dev, DRIVER_RENDER)) {
		ret = drm_minor_alloc(dev, DRM_MINOR_RENDER);
		if (ret)
			goto err;
	}
	/*创建一个 DRM_MINOR_PRIMARY 子设备, 每个 drm_device 必须有一个默认的 DRM_MINOR_PRIMARY 设备dev/dri/card(0 - 64)*/
	ret = drm_minor_alloc(dev, DRM_MINOR_PRIMARY);
	if (ret)
		goto err;

	ret = drm_legacy_create_map_hash(dev);
	if (ret)
		goto err;

	drm_legacy_ctxbitmap_init(dev);
/*检测drm_device的 drm_driver 的 driver_features 标志位是否设置 DRIVER_GEM ,
如果设置了则会为我们分配并创建一个默认的起始偏移地址为 DRM_FILE_PAGE_OFFSET_START内存大小为 DRM_FILE_PAGE_OFFSET_SIZE的 vma_offset_manager*/
	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;
		}
	}

	ret = drm_dev_set_unique(dev, dev_name(parent));
	if (ret)
		goto err;

	return 0;

err:
	drm_managed_release(dev);

	return ret;
}

1.1.1drm_minor_alloc

根据传入的 type 在 drm_minors_idr 链表中申请一个可用的 id, 并且使用这个 id 作为次设备号, 创建对应的 minor 设备.

  • DRM_MINOR_PRIMARY id 范围 0 - 64 ==> dev/dri/card0 - dev/dri/card64
  • DRM_MINOR_RENDER id 范围 128 - 192 ==> dev/dri/enderD128 - dev/dri/enderD192
static int drm_minor_alloc(struct drm_device *dev, unsigned int type)
{
	struct drm_minor *minor;
	unsigned long flags;
	int r;

	minor = drmm_kzalloc(dev, sizeof(*minor), GFP_KERNEL);
	if (!minor)
		return -ENOMEM;

	minor->type = type;
	minor->dev = dev;

	idr_preload(GFP_KERNEL);
	spin_lock_irqsave(&drm_minor_lock, flags);
	r = idr_alloc(&drm_minors_idr,
		      NULL,
		      64 * type,
		      64 * (type + 1),
		      GFP_NOWAIT);
	spin_unlock_irqrestore(&drm_minor_lock, flags);
	idr_preload_end();

	if (r < 0)
		return r;

	minor->index = r;

	r = drmm_add_action_or_reset(dev, drm_minor_alloc_release, minor);
	if (r)
		return r;

	minor->kdev = drm_sysfs_minor_alloc(minor);
	if (IS_ERR(minor->kdev))
		return PTR_ERR(minor->kdev);

	*drm_minor_get_slot(dev, type) = minor;
	return 0;
}
1.1.1.1drm_sysfs_minor_alloc

用于为 DRM minor 分配并初始化一个 struct device,其作用如下:

struct device *drm_sysfs_minor_alloc(struct drm_minor *minor)
{
	const char *minor_str;
	struct device *kdev;
	int r;
/*根据 minor->type 的值,选择对应的设备名称格式字符串: 
   a.如果是渲染节点(DRM_MINOR_RENDER),则使用
   b. "renderD%d"。 如果是普通节点(DRM_MINOR_PRIMARY),则使用 "card%d"。*/
	if (minor->type == DRM_MINOR_RENDER)
		minor_str = "renderD%d";
	else
		minor_str = "card%d";

	kdev = kzalloc(sizeof(*kdev), GFP_KERNEL);
	if (!kdev)
		return ERR_PTR(-ENOMEM);
	/*设置设备属性*/
	device_initialize(kdev);
	/*通过 MKDEV 宏将主设备号 DRM_MAJOR 和次设备号 minor->index 组合成设备号*/
	kdev->devt = MKDEV(DRM_MAJOR, minor->index);
	kdev->class = drm_class;
	kdev->type = &drm_sysfs_device_minor;
	kdev->parent = minor->dev->dev;
	kdev->release = drm_sysfs_release;
	dev_set_drvdata(kdev, minor);
	/*使用 dev_set_name 设置设备名称,格式为 "renderD%d" 或 "card%d",其中 %d 是 minor->index。*/
	r = dev_set_name(kdev, minor_str, minor->index);
	if (r < 0)
		goto err_free;

	return kdev;

err_free:
	put_device(kdev);
	return ERR_PTR(r);
}

http://www.kler.cn/a/529249.html

相关文章:

  • OpenAI o3-mini全面解析:最新免费推理模型重磅发布
  • JVM方法区
  • 代码随想录34 动态规划
  • C#方法(练习)
  • 合并2个排序的链表
  • 初二回娘家
  • Linux+Docer 容器化部署之 Shell 语法入门篇 【Shell基本运算符】
  • 深度学习之“向量范数和距离度量”
  • 【VMware】VMware安装ubuntu-22.04虚拟机
  • 一觉醒来全球编码能力下降100000倍,新手小白的我决定科普C语言——函数
  • Clock Controller of RH850/F1KH-D8, RH850/F1KM-S4, RH850/F1KM-S2
  • 15JavaWeb——Maven高级篇
  • 深入剖析 HTML5 新特性:语义化标签和表单控件完全指南
  • 78-《磨盘草》
  • 代码随想录算法训练营第四十一天-动态规划-股票-123.买卖股票的最佳时机III
  • 帝国CMS8.0终极栏目转换或批量改顺序成功后不能返回地址的解决方案
  • Linux 基础2
  • Java线程池与Future_优化并发任务执行
  • DeepSeek-R1论文研读:通过强化学习激励LLM中的推理能力
  • Unity安装教学与相关问题
  • 蓝桥杯python基础算法(2-2)——基础算法(A)——枚举
  • Python 梯度下降法(六):Nadam Optimize
  • yes镜像站群/PHP驱动的镜像站群架构实践
  • 数据库安全管理中的用户和角色管理:打造安全高效的数据环境
  • 什么是Rust?它有什么特点?为什么要学习Rust?
  • 微信小程序实战0 设置