前回の記事:DRMの完全解析 - ADD_FB (2)の続きです。
この記事は次のブログ投稿を参照しています。
ありがとう!
この章は、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 の AND 演算を行い、機能スペースはデバイス自体に制限されています。いくつかのアイテム。次に、これらの項目のいずれかが機能をサポートしているかどうかを確認します。機能自体がゼロ以外でサポートされている場合は true を返し、それ以外の場合は false を返します。false が返されると、drm_core_check_feature 関数は最終的に -EOPNOTSUPP (include/uapi/asm-generic/errno.h で定義) を返します。これは、「トランスポート エンドポイントでサポートされていない操作」、つまり、その操作がトランスポートでサポートされていないことを意味します。終点。
通話の具体的な詳細を徹底的にフォローアップします。DRIVER_MODESET は、次のように include/drm/drm_drv.h で定義されるマクロです。
/**
* @DRIVER_MODESET:
*
* Driver supports mode setting interfaces (KMS).
*/
DRIVER_MODESET = BIT(1),
ここで drm_core_check_all_features 関数に渡される機能は DRIVER_MODESET (値は 2) で、これは KMS (カーネル モード設定) インターフェイスのサポート (または非サポート) を表します。
dev -> driver -> driver_features に焦点を当てます。CREATE_DUMB について説明したときに述べたように、dev->driver の実際のコード ( DRM の完全な分析 - CREATE_DUMB (3)を参照)、その意味は drm デバイスに対応する drm ドライバーです。実際、dev->driver は、異なるグラフィックス カード ドライバーの異なる struct drm_driver インスタンスに対応します。ここでも、著者が実際に接触したIntelとAMDの2つのグラフィックスカードを例として取り上げます。
- インテル 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レイドン
AMD グラフィックス カードには、Raedon と AMDGPU の 2 つのドライバーがあります。
まず、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,
デバイス インスタンスの driver_features である dev->driver_features については、ドライバー インスタンスの driver_features である dev->driver->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 関数が分析されました。残りの手順と機能については、次の記事で分析します。