DRM全解析 —— ADD_FB(3)

news/2024/7/20 11:58:47 标签: DRM, Linux内核, libdrm

接前一篇文章:DRM全解析 —— ADD_FB(2)

本文参考以下博文:

DRM驱动(四)之ADD_FB

特此致谢!

本回开始对于drm_mode_addfb函数进行解析。为了便于理解,再次贴出其代码,在drivers/gpu/drm/drm_framebuffer.c中,如下:

/**
 * drm_mode_addfb - add an FB to the graphics configuration
 * @dev: drm device for the ioctl
 * @or: pointer to request structure
 * @file_priv: drm file
 *
 * Add a new FB to the specified CRTC, given a user request. This is the
 * original addfb ioctl which only supported RGB formats.
 *
 * Called by the user via ioctl, or by an in-kernel client.
 *
 * Returns:
 * Zero on success, negative errno on failure.
 */
int drm_mode_addfb(struct drm_device *dev, struct drm_mode_fb_cmd *or,
		   struct drm_file *file_priv)
{
	struct drm_mode_fb_cmd2 r = {};
	int ret;

	if (!drm_core_check_feature(dev, DRIVER_MODESET))
		return -EOPNOTSUPP;

	r.pixel_format = drm_driver_legacy_fb_format(dev, or->bpp, or->depth);
	if (r.pixel_format == DRM_FORMAT_INVALID) {
		drm_dbg_kms(dev, "bad {bpp:%d, depth:%d}\n", or->bpp, or->depth);
		return -EINVAL;
	}

	/* convert to new format and call new ioctl */
	r.fb_id = or->fb_id;
	r.width = or->width;
	r.height = or->height;
	r.pitches[0] = or->pitch;
	r.handles[0] = or->handle;

	ret = drm_mode_addfb2(dev, &r, file_priv);
	if (ret)
		return ret;

	or->fb_id = r.fb_id;

	return 0;
}

int drm_mode_addfb_ioctl(struct drm_device *dev,
			 void *data, struct drm_file *file_priv)
{
	return drm_mode_addfb(dev, data, file_priv);
}

先来看第一步暨第一个函数:drm_core_check_feature。对应的代码片段为:

    if (!drm_core_check_feature(dev, DRIVER_MODESET))
		return -EOPNOTSUPP;

drm_core_check_feature函数在include/drm/drm_drv.h中,代码如下:

/**
 * drm_core_check_feature - check driver feature flags
 * @dev: DRM device to check
 * @feature: feature flag
 *
 * This checks @dev for driver features, see &drm_driver.driver_features,
 * &drm_device.driver_features, and the various &enum drm_driver_feature flags.
 *
 * Returns true if the @feature is supported, false otherwise.
 */
static inline bool drm_core_check_feature(const struct drm_device *dev,
					  enum drm_driver_feature feature)
{
	return drm_core_check_all_features(dev, feature);
}

可以看到,实际的工作drm_core_check_all_features函数完成的。drm_core_check_all_features函数就在上边,代码如下:

/**
 * drm_core_check_all_features - check driver feature flags mask
 * @dev: DRM device to check
 * @features: feature flag(s) mask
 *
 * This checks @dev for driver features, see &drm_driver.driver_features,
 * &drm_device.driver_features, and the various &enum drm_driver_feature flags.
 *
 * Returns true if all features in the @features mask are supported, false
 * otherwise.
 */
static inline bool drm_core_check_all_features(const struct drm_device *dev,
					       u32 features)
{
	u32 supported = dev->driver->driver_features & dev->driver_features;

	return features && (supported & features) == features;
}

函数的功能是先将struct drm_device *dev(设备实例)对应的struct drm_driver *driver(驱动实例)中的driver_features与struct drm_device *dev(设备实例)自身的driver_features相与,得到仅限于设备自身特性空间的几项。然后看这几项中是否支持features特性。如果features本身不为0并且支持,则返回真(true);否则返回假(false)。

DRIVER_MODESET是一个宏,在include/drm/drm_drv.h中定义,如下:

    /**
	 * @DRIVER_MODESET:
	 *
	 * Driver supports mode setting interfaces (KMS).
	 */
	DRIVER_MODESET			= BIT(1),

在此传入drm_core_check_all_features函数的features为DRIVER_MODESET(值为2),代表支持KMS(Kernel Mode Setting)接口(与否)。

重点看一下dev->driver->driver_features。在讲CREATE_DUMB的时候讲到过,dev->driver的实际代码(参考DRM全解析 —— CREATE_DUMB(3)),其意义就是drm设备对应的drm驱动。实际上dev->driver对于不同的显卡驱动,是对应不同的struct drm_driver实例的。这里仍以笔者实际接触过的两款显卡Intel和AMD为例进行说明。

  • Intel i915

Intel i915显卡驱动对应的struct drm_driver初始化代码在drivers/gpu/drm/i915/i915_driver.c中,如下:

static const struct drm_driver i915_drm_driver = {
	/* Don't use MTRRs here; the Xserver or userspace app should
	 * deal with them for Intel hardware.
	 */
	.driver_features =
	    DRIVER_GEM |
	    DRIVER_RENDER | DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_SYNCOBJ |
	    DRIVER_SYNCOBJ_TIMELINE,
	.release = i915_driver_release,
	.open = i915_driver_open,
	.lastclose = i915_driver_lastclose,
	.postclose = i915_driver_postclose,
 
	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
	.gem_prime_import = i915_gem_prime_import,
 
	.dumb_create = i915_gem_dumb_create,
	.dumb_map_offset = i915_gem_dumb_mmap_offset,
 
	.ioctls = i915_ioctls,
	.num_ioctls = ARRAY_SIZE(i915_ioctls),
	.fops = &i915_driver_fops,
	.name = DRIVER_NAME,
	.desc = DRIVER_DESC,
	.date = DRIVER_DATE,
	.major = DRIVER_MAJOR,
	.minor = DRIVER_MINOR,
	.patchlevel = DRIVER_PATCHLEVEL,
};

由代码可见,对于i915显卡驱动来说,其支持的特性为:

    .driver_features =
	    DRIVER_GEM |
	    DRIVER_RENDER | DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_SYNCOBJ |
	    DRIVER_SYNCOBJ_TIMELINE,
  • AMD Raedon

AMD显卡有两款驱动:Raedon和AMDGPU。

先说Raedon驱动。Raedon显卡驱动对应的struct drm_driver初始化代码在drivers/gpu/drm/radeon/radeon_drv.c中,如下:

static const struct drm_driver kms_driver = {
	.driver_features =
	    DRIVER_GEM | DRIVER_RENDER | DRIVER_MODESET,
	.load = radeon_driver_load_kms,
	.open = radeon_driver_open_kms,
	.postclose = radeon_driver_postclose_kms,
	.lastclose = radeon_driver_lastclose_kms,
	.unload = radeon_driver_unload_kms,
	.ioctls = radeon_ioctls_kms,
	.num_ioctls = ARRAY_SIZE(radeon_ioctls_kms),
	.dumb_create = radeon_mode_dumb_create,
	.dumb_map_offset = radeon_mode_dumb_mmap,
	.fops = &radeon_driver_kms_fops,
 
	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
	.gem_prime_import_sg_table = radeon_gem_prime_import_sg_table,
	.gem_prime_mmap = drm_gem_prime_mmap,
 
	.name = DRIVER_NAME,
	.desc = DRIVER_DESC,
	.date = DRIVER_DATE,
	.major = KMS_DRIVER_MAJOR,
	.minor = KMS_DRIVER_MINOR,
	.patchlevel = KMS_DRIVER_PATCHLEVEL,
};

由代码可见,对于AMD Raedon显卡驱动来说,其支持的特性为:

    .driver_features =
	    DRIVER_GEM | DRIVER_RENDER | DRIVER_MODESET,
  • AMD AMDGPU

再来看AMDGPU驱动。AMDGPU显卡驱动对应的struct drm_driver初始化代码在drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c中,如下:

static const struct drm_driver amdgpu_kms_driver = {
	.driver_features =
	    DRIVER_ATOMIC |
	    DRIVER_GEM |
	    DRIVER_RENDER | DRIVER_MODESET | DRIVER_SYNCOBJ |
	    DRIVER_SYNCOBJ_TIMELINE,
	.open = amdgpu_driver_open_kms,
	.postclose = amdgpu_driver_postclose_kms,
	.lastclose = amdgpu_driver_lastclose_kms,
	.ioctls = amdgpu_ioctls_kms,
	.num_ioctls = ARRAY_SIZE(amdgpu_ioctls_kms),
	.dumb_create = amdgpu_mode_dumb_create,
	.dumb_map_offset = amdgpu_mode_dumb_mmap,
	.fops = &amdgpu_driver_kms_fops,
	.release = &amdgpu_driver_release_kms,
 
	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
	.gem_prime_import = amdgpu_gem_prime_import,
	.gem_prime_mmap = drm_gem_prime_mmap,
 
	.name = DRIVER_NAME,
	.desc = DRIVER_DESC,
	.date = DRIVER_DATE,
	.major = KMS_DRIVER_MAJOR,
	.minor = KMS_DRIVER_MINOR,
	.patchlevel = KMS_DRIVER_PATCHLEVEL,
};

由代码可见,对于AMD AMDGPU显卡驱动来说,其支持的特性为:

    .driver_features =
	    DRIVER_ATOMIC |
	    DRIVER_GEM |
	    DRIVER_RENDER | DRIVER_MODESET | DRIVER_SYNCOBJ |
	    DRIVER_SYNCOBJ_TIMELINE,

而对于dev->driver_features即设备实例的driver_features,就不像dev->driver->driver_features即驱动实例的driver_features那样明显了。在DRM即内核源码路径下,共有几处相关,分别如下:

1)drivers/gpu/drm/drm_drv.c的drm_dev_init函数中:

static int drm_dev_init(struct drm_device *dev,
			const struct drm_driver *driver,
			struct device *parent)
{
	struct inode *inode;
	int ret;

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

2)drivers/vdpa/vdpa_user/vduse_dev.c的vduse_dev_reset函数中:

static void vduse_dev_reset(struct vduse_dev *dev)
{
	int i;
	struct vduse_iova_domain *domain = dev->domain;

	/* The coherent mappings are handled in vduse_dev_free_coherent() */
	if (domain->bounce_map)
		vduse_domain_reset_bounce_map(domain);

	down_write(&dev->rwsem);

	dev->status = 0;
	dev->driver_features = 0;
	dev->generation++;
	spin_lock(&dev->irq_lock);
	dev->config_cb.callback = NULL;
	dev->config_cb.private = NULL;
	spin_unlock(&dev->irq_lock);
	flush_work(&dev->inject);

    ……
}

3)drivers/vdpa/vdpa_user/vduse_dev.c的vduse_vdpa_set_driver_features函数中:

static int vduse_vdpa_set_driver_features(struct vdpa_device *vdpa, u64 features)
{
	struct vduse_dev *dev = vdpa_to_vduse(vdpa);

	dev->driver_features = features;
	return 0;
}

至此,drm_mode_addfb函数中的第一步:drm_core_check_feature函数就分析完了。余下的步骤和函数在接下来的文章中继续进行解析。


http://www.niftyadmin.cn/n/4997407.html

相关文章

unity2022版本 实现json读取保存 list自定义对象的读取与保存

1.序列化对象 通过unity自带的JsonUtility中的ToJson方法来序列化对象 public static string ToJson(object obj, bool prettyPrint) ToJson返回一个序列化后的json字符串, 参数一 要序列化的对象 参数二 设置是否返回结果是否带有可读性 默认是false就是不带…

Lesson5-1:OpenCV视频操作---视频读写

学习目标 掌握读取视频文件,显示视频,保存视频文件的方法 1 从文件中读取视频并播放 在OpenCV中我们要获取一个视频,需要创建一个VideoCapture对象,指定你要读取的视频文件: 创建读取视频的对象 cap cv.VideoCapt…

高数刷题笔记

常见等价无穷小 注意讨论 第二个等价无穷小 夹逼定理!!! 递归数列可以尝试用关系式法 通常用到夹逼定理的时候都会用到放缩构造出一大一小两个函数,将原函数夹在中间,然后使得两端函数极限相同则可推出原函数的极限&am…

开开心心带你学习MySQL数据库之第三篇上

学校的项目组有必要加入吗? 看你的初心. ~~如果初心是通过这个经历能够提高自己的技术水平 ~~是可以考虑的 ~~如果初心是通过这个经历提高自己找工作的概率 ~~这个是不靠谱的,啥用没有 ~~如果初心是通过这个体验更美好的大学生活 ~~靠谱的 秋招,应届生,找工作是非常容易的!!! …

如何使用『Nginx』配置后端『HTTPS』协议访问

前言 本篇博客主要讲解如何使用 Nginx 部署后端应用接口 SSL 证书,从而实现 HTTPS 协议访问接口(本文使用公网 IP 部署,读者可以自行替换为域名) 申请证书 须知 请在您的云服务平台申请 SSL 证书,一般来说证书期限…

CYEZ 模拟赛 1

前言 抽象。打不过暴力老哥,确实萌新。 A 人类基因 萌萌题。代码。 B Bribing Friends O ( n 4 ) O(n^4) O(n4) 做法:代码。 正解:确定选择奶牛方案时,让甜筒优先作用于 x x x 较小的奶牛。那么按 x x x 排序后&#xff0c…

python 包迁移方案

文章目录 pip 参数说明1、pip freeze2 、pipreqs3、 pdm 复制整个文件夹 python 包迁移方案 pip 参数说明 --no-index # 表示不从PyPI(Python Package Index)上下载包。即使你在本地没有找到需要安装的依赖包,也会跳过从PyPI上下载该依赖…

ASIC-WORLD Verilog(15)存储单元

写在前面 在自己准备写一些简单的verilog教程之前,参考了许多资料----Asic-World网站的这套verilog教程即是其一。这套教程写得极好,奈何没有中文,在下只好斗胆翻译过来(加点自己的理解)分享给大家。 这是网站原文&…