DRM full analysis - ADD_FB (3)

Continuing from the previous article: Full analysis of DRM - ADD_FB (2)

This article refers to the following blog posts:

ADD_FB of DRM driver (4)

Thanks!

This chapter begins with the analysis of the drm_mode_addfb function. For ease of understanding, the code is posted again, in drivers/gpu/drm/drm_framebuffer.c, as follows:

/**
 * 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);
}

Let’s look at the first step and first function: drm_core_check_feature. The corresponding code snippet is:

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

The drm_core_check_feature function is in include/drm/drm_drv.h. The code is as follows:

/**
 * 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);
}

As you can see, the actual work is done by the drm_core_check_all_features function. The drm_core_check_all_features function is above, the code is as follows:

/**
 * 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;
}

The function of the function is to first AND the driver_features in the struct drm_driver *driver (driver instance) corresponding to the struct drm_device *dev (device instance) with the driver_features of the struct drm_device *dev (device instance) itself, to obtain the feature space limited to the device itself. Several items. Then see if any of these items support features. If features themselves are non-zero and supported, return true; otherwise return false. Once false is returned, the drm_core_check_feature function finally returns -EOPNOTSUPP (defined in include/uapi/asm-generic/errno.h), which means "Operation not supported on transport endpoint", that is, the operation is not supported on the transport endpoint.

Follow up in depth to the specific details of the call. DRIVER_MODESET is a macro, defined in include/drm/drm_drv.h, as follows:

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

The features passed into the drm_core_check_all_features function here are DRIVER_MODESET (value is 2), which represents support for the KMS (Kernel Mode Setting) interface (or not).

Focus on dev->driver->driver_features. As mentioned when talking about CREATE_DUMB, the actual code of dev->driver (refer to the full analysis of DRM - CREATE_DUMB (3) ), its meaning is the drm driver corresponding to the drm device. In fact, dev->driver corresponds to different struct drm_driver instances for different graphics card drivers. Here we still take the two graphics cards Intel and AMD that the author has actually come into contact with as examples.

  • Intel i915

The struct drm_driver initialization code corresponding to the Intel i915 graphics driver is in drivers/gpu/drm/i915/i915_driver.c, as follows:

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,
};

As can be seen from the code, for the i915 graphics card driver, its supported features are:

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

There are two drivers for AMD graphics cards: Raedon and AMDGPU.

Let’s talk about the Raedon driver first. The struct drm_driver initialization code corresponding to the Raedon graphics driver is in drivers/gpu/drm/radeon/radeon_drv.c, as follows:

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,
};

As can be seen from the code, for the AMD Raedon graphics driver, the features it supports are:

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

Let’s look at the AMDGPU driver. The struct drm_driver initialization code corresponding to the AMDGPU graphics driver is in drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c, as follows:

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,
};

As can be seen from the code, for the AMD AMDGPU graphics card driver, its supported features are:

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

For dev->driver_features, which is the driver_features of the device instance, it is not as obvious as dev->driver->driver_features, which is the driver_features of the driver instance. Under the DRM, that is, the kernel source code path, there are several related places, as follows:

1) In the drm_dev_init function of drivers/gpu/drm/drm_drv.c:

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) In the vduse_dev_reset function of drivers/vdpa/vdpa_user/vduse_dev.c:

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) In the vduse_vdpa_set_driver_features function of drivers/vdpa/vdpa_user/vduse_dev.c:

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;
}

So far, the first step in the drm_mode_addfb function: the drm_core_check_feature function is analyzed. The remaining steps and functions will continue to be analyzed in the next article.

Guess you like

Origin blog.csdn.net/phmatthaus/article/details/132649953