lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20240905123418.3139-1-jose.exposito89@gmail.com>
Date: Thu,  5 Sep 2024 14:34:18 +0200
From: José Expósito <jose.exposito89@...il.com>
To: louis.chauvet@...tlin.com
Cc: airlied@...il.com,
	arthurgrillo@...eup.net,
	daniel@...ll.ch,
	dri-devel@...ts.freedesktop.org,
	hamohammed.sa@...il.com,
	jeremie.dautheribes@...tlin.com,
	linux-kernel@...r.kernel.org,
	maarten.lankhorst@...ux.intel.com,
	mairacanal@...eup.net,
	melissa.srw@...il.com,
	miquel.raynal@...tlin.com,
	mripard@...nel.org,
	nicolejadeyee@...gle.com,
	rodrigosiqueiramelo@...il.com,
	seanpaul@...gle.com,
	thomas.petazzoni@...tlin.com,
	tzimmermann@...e.de
Subject: [PATCH RFC 12/15] drm/vkms: Add configuration for CRTCs and encoders

> The current VKMS driver can only uses one CRTC and one encoder. This patch
> introduce in the same time CRTC and encoders as they are tighly linked.
> 
> Signed-off-by: Louis Chauvet <louis.chauvet@...tlin.com>
> ---
>  drivers/gpu/drm/vkms/vkms_config.c | 266 +++++++++++++++++++++++++++++++++----
>  drivers/gpu/drm/vkms/vkms_config.h | 102 +++++++++++++-
>  drivers/gpu/drm/vkms/vkms_crtc.c   |  20 ++-
>  drivers/gpu/drm/vkms/vkms_crtc.h   |   3 +-
>  drivers/gpu/drm/vkms/vkms_drv.c    |  87 ++++++------
>  5 files changed, 405 insertions(+), 73 deletions(-)
> 
> diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
> index e9e30974523a..fcd4a128c21b 100644
> --- a/drivers/gpu/drm/vkms/vkms_config.c
> +++ b/drivers/gpu/drm/vkms/vkms_config.c
> @@ -14,6 +14,8 @@ struct vkms_config *vkms_config_create(void)
>  		return ERR_PTR(-ENOMEM);
>  
>  	INIT_LIST_HEAD(&config->planes);
> +	INIT_LIST_HEAD(&config->crtcs);
> +	INIT_LIST_HEAD(&config->encoders);
>  
>  	return config;
>  }
> @@ -22,12 +24,24 @@ struct vkms_config *vkms_config_alloc_default(bool enable_writeback, bool enable
>  					      bool enable_cursor)
>  {
>  	struct vkms_config_plane *plane;
> +	struct vkms_config_encoder *encoder;
> +	struct vkms_config_crtc *crtc;
>  	struct vkms_config *vkms_config = vkms_config_create();
>  
>  	if (IS_ERR(vkms_config))
>  		return vkms_config;
>  
> -	vkms_config->writeback = enable_writeback;
> +	crtc = vkms_config_create_crtc(vkms_config);
> +	if (!crtc)
> +		goto err_alloc;
> +	crtc->writeback = enable_writeback;
> +
> +	encoder = vkms_config_create_encoder(vkms_config);
> +	if (!encoder)
> +		goto err_alloc;
> +
> +	if (vkms_config_encoder_attach_crtc(encoder, crtc))
> +		goto err_alloc;
>  
>  	plane = vkms_config_create_plane(vkms_config);
>  	if (!plane)
> @@ -39,6 +53,9 @@ struct vkms_config *vkms_config_alloc_default(bool enable_writeback, bool enable
>  		goto err_alloc;
>  	sprintf(plane->name, "primary");
>  
> +	if (vkms_config_plane_attach_crtc(plane, crtc))
> +		goto err_alloc;
> +
>  	if (enable_overlay) {
>  		for (int i = 0; i < NUM_OVERLAY_PLANES; i++) {
>  			plane = vkms_config_create_plane(vkms_config);
> @@ -49,6 +66,9 @@ struct vkms_config *vkms_config_alloc_default(bool enable_writeback, bool enable
>  			if (!plane->name)
>  				goto err_alloc;
>  			snprintf(plane->name, 10, "plane-%d", i);
> +
> +			if (vkms_config_plane_attach_crtc(plane, crtc))
> +				goto err_alloc;
>  		}
>  	}
>  	if (enable_cursor) {
> @@ -60,6 +80,9 @@ struct vkms_config *vkms_config_alloc_default(bool enable_writeback, bool enable
>  		if (!plane->name)
>  			goto err_alloc;
>  		sprintf(plane->name, "cursor");
> +
> +		if (vkms_config_plane_attach_crtc(plane, crtc))
> +			goto err_alloc;
>  	}
>  
>  	return vkms_config;
> @@ -89,38 +112,196 @@ struct vkms_config_plane *vkms_config_create_plane(struct vkms_config *vkms_conf
>  	vkms_config_overlay->supported_color_range = BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
>  						     BIT(DRM_COLOR_YCBCR_FULL_RANGE);
>  	vkms_config_overlay->default_color_range = DRM_COLOR_YCBCR_FULL_RANGE;
> +	xa_init_flags(&vkms_config_overlay->possible_crtcs, XA_FLAGS_ALLOC);
>  
>  	list_add(&vkms_config_overlay->link, &vkms_config->planes);
>  
>  	return vkms_config_overlay;
>  }
>  
> -void vkms_config_delete_plane(struct vkms_config_plane *vkms_config_overlay)
> +struct vkms_config_crtc *vkms_config_create_crtc(struct vkms_config *vkms_config)
>  {
> -	if (!vkms_config_overlay)
> +	if (!vkms_config)
> +		return NULL;
> +
> +	struct vkms_config_crtc *vkms_config_crtc = kzalloc(sizeof(*vkms_config_crtc),
> +							    GFP_KERNEL);
> +
> +	if (!vkms_config_crtc)
> +		return NULL;
> +
> +	list_add(&vkms_config_crtc->link, &vkms_config->crtcs);
> +	xa_init_flags(&vkms_config_crtc->possible_planes, XA_FLAGS_ALLOC);
> +	xa_init_flags(&vkms_config_crtc->possible_encoders, XA_FLAGS_ALLOC);
> +
> +	return vkms_config_crtc;
> +}
> +
> +struct vkms_config_encoder *vkms_config_create_encoder(struct vkms_config *vkms_config)
> +{
> +	if (!vkms_config)
> +		return NULL;
> +
> +	struct vkms_config_encoder *vkms_config_encoder = kzalloc(sizeof(*vkms_config_encoder),
> +								  GFP_KERNEL);
> +
> +	if (!vkms_config_encoder)
> +		return NULL;
> +
> +	list_add(&vkms_config_encoder->link, &vkms_config->encoders);
> +	xa_init_flags(&vkms_config_encoder->possible_crtcs, XA_FLAGS_ALLOC);
> +
> +	return vkms_config_encoder;
> +}
> +
> +void vkms_config_delete_plane(struct vkms_config_plane *vkms_config_plane,
> +			      struct vkms_config *vkms_config)
> +{
> +	struct vkms_config_crtc *crtc_config;
> +	struct vkms_config_plane *plane;
> +
> +	if (!vkms_config_plane)
> +		return;
> +	list_del(&vkms_config_plane->link);
> +	xa_destroy(&vkms_config_plane->possible_crtcs);
> +
> +	list_for_each_entry(crtc_config, &vkms_config->crtcs, link) {
> +		unsigned long idx = 0;
> +
> +		xa_for_each(&crtc_config->possible_planes, idx, plane) {
> +			if (plane == vkms_config_plane)
> +				xa_erase(&crtc_config->possible_planes, idx);
> +		}
> +	}
> +
> +	kfree(vkms_config_plane->name);
> +	kfree(vkms_config_plane);
> +}
> +
> +void vkms_config_delete_crtc(struct vkms_config_crtc *vkms_config_crtc,
> +			     struct vkms_config *vkms_config)
> +{
> +	struct vkms_config_crtc *crtc_config;
> +	struct vkms_config_plane *plane_config;
> +	struct vkms_config_encoder *encoder_config;
> +
> +	if (!vkms_config_crtc)
> +		return;
> +	list_del(&vkms_config_crtc->link);
> +	xa_destroy(&vkms_config_crtc->possible_planes);
> +	xa_destroy(&vkms_config_crtc->possible_encoders);
> +
> +	list_for_each_entry(plane_config, &vkms_config->planes, link) {
> +		unsigned long idx = 0;
> +
> +		xa_for_each(&plane_config->possible_crtcs, idx, crtc_config) {
> +			if (crtc_config == vkms_config_crtc)
> +				xa_erase(&plane_config->possible_crtcs, idx);
> +		}
> +	}
> +
> +	list_for_each_entry(encoder_config, &vkms_config->encoders, link) {
> +		unsigned long idx = 0;
> +
> +		xa_for_each(&encoder_config->possible_crtcs, idx, crtc_config) {
> +			if (crtc_config == vkms_config_crtc)
> +				xa_erase(&encoder_config->possible_crtcs, idx);
> +		}
> +	}
> +
> +	kfree(vkms_config_crtc);
> +}
> +
> +void vkms_config_delete_encoder(struct vkms_config_encoder *vkms_config_encoder,
> +				struct vkms_config *vkms_config)
> +{
> +	if (!vkms_config_encoder)
>  		return;
> -	list_del(&vkms_config_overlay->link);
> -	kfree(vkms_config_overlay->name);
> -	kfree(vkms_config_overlay);
> +	list_del(&vkms_config_encoder->link);
> +	xa_destroy(&vkms_config_encoder->possible_crtcs);
> +
> +	struct vkms_config_crtc *crtc_config;
> +	struct vkms_config_encoder *encoder;
> +
> +	list_for_each_entry(crtc_config, &vkms_config->crtcs, link) {
> +		unsigned long idx = 0;
> +
> +		xa_for_each(&crtc_config->possible_encoders, idx, encoder) {
> +			if (encoder == vkms_config_encoder)
> +				xa_erase(&crtc_config->possible_encoders, idx);
> +		}
> +	}
> +
> +	kfree(vkms_config_encoder);
>  }
>  
>  void vkms_config_destroy(struct vkms_config *config)
>  {
>  	struct vkms_config_plane *vkms_config_plane, *tmp_plane;
> +	struct vkms_config_encoder *vkms_config_encoder, *tmp_encoder;
> +	struct vkms_config_crtc *vkms_config_crtc, *tmp_crtc;
> +
>  
>  	list_for_each_entry_safe(vkms_config_plane, tmp_plane, &config->planes, link) {
> -		vkms_config_delete_plane(vkms_config_plane);
> +		vkms_config_delete_plane(vkms_config_plane, config);
> +	}
> +	list_for_each_entry_safe(vkms_config_encoder, tmp_encoder, &config->encoders, link) {
> +		vkms_config_delete_encoder(vkms_config_encoder, config);
> +	}
> +	list_for_each_entry_safe(vkms_config_crtc, tmp_crtc, &config->crtcs, link) {
> +		vkms_config_delete_crtc(vkms_config_crtc, config);
>  	}
>  
>  	kfree(config);
>  }
>  
> +int __must_check vkms_config_plane_attach_crtc(struct vkms_config_plane *vkms_config_plane,
> +					       struct vkms_config_crtc *vkms_config_crtc)
> +{
> +	u32 crtc_idx, encoder_idx;
> +	int ret;
> +
> +	ret = xa_alloc(&vkms_config_plane->possible_crtcs, &crtc_idx, vkms_config_crtc,
> +		       xa_limit_32b, GFP_KERNEL);
> +	if (ret)
> +		return ret;
> +
> +	ret = xa_alloc(&vkms_config_crtc->possible_planes, &encoder_idx, vkms_config_plane,
> +		       xa_limit_32b, GFP_KERNEL);
> +	if (ret) {
> +		xa_erase(&vkms_config_plane->possible_crtcs, crtc_idx);
> +		return ret;
> +	}
> +
> +	return ret;
> +}
> +
> +int __must_check vkms_config_encoder_attach_crtc(struct vkms_config_encoder *vkms_config_encoder,
> +						 struct vkms_config_crtc *vkms_config_crtc)
> +{
> +	u32 crtc_idx, encoder_idx;
> +	int ret;
> +
> +	ret = xa_alloc(&vkms_config_encoder->possible_crtcs, &crtc_idx, vkms_config_crtc,
> +		       xa_limit_32b, GFP_KERNEL);
> +	if (ret)
> +		return ret;
> +
> +	ret = xa_alloc(&vkms_config_crtc->possible_encoders, &encoder_idx, vkms_config_encoder,
> +		       xa_limit_32b, GFP_KERNEL);
> +	if (ret) {
> +		xa_erase(&vkms_config_encoder->possible_crtcs, crtc_idx);
> +		return ret;
> +	}
> +
> +	return ret;
> +}
> +
>  bool vkms_config_is_valid(struct vkms_config *config)

I still need to look into the xa_* code in more detail, but I think
that it is a great solution for the problem I had handling possible_crtcs
and possible_encoders.

About the validation, If I undertood the docs correctly:

  "All drivers should provide one primary plane per CRTC"
  https://www.kernel.org/doc/html/v4.17/gpu/drm-kms.html#plane-abstraction

We'd need to check that the number of primary planes is equal to the number
of CRTCs and that a configuration to assing one primary plane to each CRTC
is available.

To illustrate it with an example, this is a valid config:

  CRTC 0
  CRTC 1
  Primary Plane 0: possible_crtcs -> CRTC 0 and CRTC 1
  Primary Plane 1: possible_crtcs -> CRTC 0

But this is not a valid config because there are no compatible planes with
CRTC 1:

  CRTC 0
  CRTC 1
  Primary Plane 0: possible_crtcs -> CRTC 0
  Primary Plane 1: possible_crtcs -> CRTC 0

I think that your code would fail in the first example because of:

  // Multiple primary planes for only one CRTC
  if (has_primary)
    return false;

Also, we'd need to check that the number of CRTCs and encoders is <= 32.

>  {
>  	struct vkms_config_plane *config_plane;
> -
> -	bool has_cursor = false;
> -	bool has_primary = false;
> +	struct vkms_config_crtc *config_crtc;
> +	struct vkms_config_encoder *config_encoder;
>  
>  	list_for_each_entry(config_plane, &config->planes, link) {
>  		// Default rotation not in supported rotations
> @@ -141,22 +322,47 @@ bool vkms_config_is_valid(struct vkms_config *config)
>  		    BIT(config_plane->default_color_range))
>  			return false;
>  
> -		if (config_plane->type == DRM_PLANE_TYPE_PRIMARY) {
> -			// Multiple primary planes for only one CRTC
> -			if (has_primary)
> -				return false;
> -			has_primary = true;
> -		}
> -		if (config_plane->type == DRM_PLANE_TYPE_CURSOR) {
> -			// Multiple cursor planes for only one CRTC
> -			if (has_cursor)
> -				return false;
> -			has_cursor = true;
> -		}
> +		// No CRTC linked to this plane
> +		if (xa_empty(&config_plane->possible_crtcs))
> +			return false;
> +	}
> +
> +	list_for_each_entry(config_encoder, &config->encoders, link) {
> +		// No CRTC linked to this encoder
> +		if (xa_empty(&config_encoder->possible_crtcs))
> +			return false;
>  	}
>  
> -	if (!has_primary)
> -		return false;
> +	list_for_each_entry(config_crtc, &config->crtcs, link) {
> +		bool has_primary = false;
> +		bool has_cursor = false;
> +		unsigned long idx = 0;
> +
> +		// No encoder attached to this CRTC
> +		if (xa_empty(&config_crtc->possible_encoders))
> +			return false;
> +
> +		xa_for_each(&config_crtc->possible_planes, idx, config_plane) {
> +			if (config_plane->type == DRM_PLANE_TYPE_PRIMARY) {
> +				// Multiple primary planes for only one CRTC
> +				if (has_primary)
> +					return false;
> +
> +				has_primary = true;
> +			}
> +			if (config_plane->type == DRM_PLANE_TYPE_CURSOR) {
> +				// Multiple cursor planes for only one CRTC
> +				if (has_cursor)
> +					return false;
> +
> +				has_cursor = true;
> +			}
> +		}
> +
> +		// No primary plane for this CRTC
> +		if (!has_primary)
> +			return false;
> +	}
>  
>  	return true;
>  }
> @@ -167,8 +373,9 @@ static int vkms_config_show(struct seq_file *m, void *data)
>  	struct drm_device *dev = entry->dev;
>  	struct vkms_device *vkmsdev = drm_device_to_vkms_device(dev);
>  	struct vkms_config_plane *config_plane;
> +	struct vkms_config_crtc *config_crtc;
> +	struct vkms_config_encoder *config_encoder;
>  
> -	seq_printf(m, "writeback=%d\n", vkmsdev->config->writeback);
>  	list_for_each_entry(config_plane, &vkmsdev->config->planes, link) {
>  		seq_puts(m, "plane:\n");
>  		seq_printf(m, "\tname: %s\n", config_plane->name);
> @@ -185,6 +392,15 @@ static int vkms_config_show(struct seq_file *m, void *data)
>  			   config_plane->default_color_range);
>  	}
>  
> +	list_for_each_entry(config_encoder, &vkmsdev->config->encoders, link) {
> +		seq_puts(m, "encoder:\n");
> +	}
> +
> +	list_for_each_entry(config_crtc, &vkmsdev->config->crtcs, link) {
> +		seq_puts(m, "crtc:\n");
> +		seq_printf(m, "\twriteback: %d\n", config_crtc->writeback);
> +	}
> +
>  	return 0;
>  }
>  
> diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
> index d668aeab9d26..8f247fc09373 100644
> --- a/drivers/gpu/drm/vkms/vkms_config.h
> +++ b/drivers/gpu/drm/vkms/vkms_config.h
> @@ -9,16 +9,59 @@
>  /**
>   * struct vkms_config - General configuration for VKMS driver
>   *
> - * @writeback: If true, a writeback buffer can be attached to the CRTC
>   * @planes: List of planes configured for this device. They are created by the function
>   *          vkms_config_create_plane().
> + * @crtcs: List of crtcs configured for this device. They are created by the function
> + *         vkms_config_create_crtc().
> + * @encoders: List of encoders configured for this device. They are created by the function
> + *            vkms_config_create_encoder().
>   * @dev: Used to store the current vkms device. Only set when the device is instancied.
>   */
>  struct vkms_config {
> -	bool writeback;
>  	struct vkms_device *dev;
>  
>  	struct list_head planes;
> +	struct list_head crtcs;
> +	struct list_head encoders;
> +};
> +
> +/**
> + * struct vkms_config_crtc
> + *
> + * @link: Link to the others CRTCs
> + * @possible_planes: List of planes that can be used with this CRTC
> + * @possible_encoders: List of encoders that can be used with this CRTC
> + * @crtc: Internal usage. This pointer should never be considered as valid. It can be used to
> + *         store a temporary reference to a vkms crtc during device creation. This pointer is
> + *         not managed by the configuration and must be managed by other means.
> + */
> +struct vkms_config_crtc {
> +	struct list_head link;
> +
> +	bool writeback;
> +	struct xarray possible_planes;
> +	struct xarray possible_encoders;
> +
> +	/* Internal usage */
> +	struct vkms_crtc *crtc;
> +};
> +
> +/**
> + * struct vkms_config_encoder
> + *
> + * @link: Link to the others encoders
> + * @possible_crtcs: List of CRTC that can be used with this encoder
> + * @encoder: Internal usage. This pointer should never be considered as valid. It can be used to
> + *         store a temporary reference to a vkms encoder during device creation. This pointer is
> + *         not managed by the configuration and must be managed by other means.
> + */
> +struct vkms_config_encoder {
> +	struct list_head link;
> +
> +	struct xarray possible_crtcs;
> +
> +	/* Internal usage */
> +	struct drm_encoder *encoder;
>  };
>  
>  /**
> @@ -34,6 +77,7 @@ struct vkms_config {
>   * @supported_color_encoding: Color encoding that this plane will support
>   * @default_color_range: Default color range that should be used by this plane
>   * @supported_color_range: Color range that this plane will support
> + * @possible_crtcs: List of CRTC that can be used with this plane.
>   * @plane: Internal usage. This pointer should never be considered as valid. It can be used to
>   *         store a temporary reference to a vkms plane during device creation. This pointer is
>   *         not managed by the configuration and must be managed by other means.
> @@ -50,6 +94,7 @@ struct vkms_config_plane {
>  	enum drm_color_range default_color_range;
>  	unsigned int supported_color_range;
>  
> +	struct xarray possible_crtcs;
>  	/* Internal usage */
>  	struct vkms_plane *plane;
>  };
> @@ -84,14 +129,63 @@ bool vkms_config_is_valid(struct vkms_config *vkms_config);
>   */
>  struct vkms_config_plane *vkms_config_create_plane(struct vkms_config *vkms_config);
>  
> +/**
> + * vkms_config_create_crtc() - Create a crtc configuration
> + *
> + * This will allocate and add a new crtc configuration to @vkms_config.
> + * @vkms_config: Configuration where to insert new crtc configuration
> + */
> +struct vkms_config_crtc *vkms_config_create_crtc(struct vkms_config *vkms_config);
> +
> +/**
> + * vkms_config_create_encoder() - Create an encoder configuration
> + *
> + * This will allocate and add a new encoder configuration to @vkms_config.
> + * @vkms_config: Configuration where to insert new encoder configuration
> + */
> +struct vkms_config_encoder *vkms_config_create_encoder(struct vkms_config *vkms_config);
> +
> +int __must_check vkms_config_plane_attach_crtc(struct vkms_config_plane *vkms_config_plane,
> +					       struct vkms_config_crtc *vkms_config_crtc);
> +int __must_check vkms_config_encoder_attach_crtc(struct vkms_config_encoder *vkms_config_encoder,
> +						 struct vkms_config_crtc *vkms_config_crtc);
> +
>  /**
>   * vkms_config_delete_plane() - Remove a plane configuration and frees its memory
>   *
>   * This will delete a plane configuration from the parent configuration. This will NOT
> - * cleanup and frees the vkms_plane that can be stored in @vkms_config_plane.
> + * cleanup and frees the vkms_plane that can be stored in @vkms_config_plane. It will also remove
> + * any reference to this plane in @vkms_config.
> + *
>   * @vkms_config_plane: Plane configuration to cleanup
> + * @vkms_config: Parent configuration
> + */
> +void vkms_config_delete_plane(struct vkms_config_plane *vkms_config_plane,
> +			      struct vkms_config *vkms_config);
> +/**
> + * vkms_config_delete_crtc() - Remove a CRTC configuration and frees its memory
> + *
> + * This will delete a CRTC configuration from the parent configuration. This will NOT
> + * cleanup and frees the vkms_crtc that can be stored in @vkms_config_crtc. It will also remove
> + * any reference to this CRTC in @vkms_config.
> + *
> + * @vkms_config_crtc: Plane configuration to cleanup
> + * @vkms_config: Parent configuration
> + */
> +void vkms_config_delete_crtc(struct vkms_config_crtc *vkms_config_crtc,
> +			     struct vkms_config *vkms_config);
> +/**
> + * vkms_config_delete_encoder() - Remove an encoder configuration and frees its memory
> + *
> + * This will delete an encoder configuration from the parent configuration. This will NOT
> + * cleanup and frees the vkms_encoder that can be stored in @vkms_config_encoder. It will also
> + * remove any reference to this CRTC in @vkms_config.
> + *
> + * @vkms_config_encoder: Plane configuration to cleanup
> + * @vkms_config: Parent configuration
>   */
> -void vkms_config_delete_plane(struct vkms_config_plane *vkms_config_plane);
> +void vkms_config_delete_encoder(struct vkms_config_encoder *vkms_config_encoder,
> +				struct vkms_config *vkms_config);
>  
>  /**
>   * vkms_config_alloc_default() - Allocate the configuration for the default device
> diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c
> index 6f6d3118b2f2..654238dbba7f 100644
> --- a/drivers/gpu/drm/vkms/vkms_crtc.c
> +++ b/drivers/gpu/drm/vkms/vkms_crtc.c
> @@ -281,9 +281,17 @@ static void vkms_crtc_destroy_workqueue(struct drm_device *dev, void *raw_vkms_c
>  	destroy_workqueue(vkms_crtc->composer_workq);
>  }
>  
> +static void vkms_crtc_cleanup_writeback_connector(struct drm_device *dev, void *data)
> +{
> +	struct vkms_crtc *vkms_crtc = data;
> +
> +	drm_writeback_connector_cleanup(&vkms_crtc->wb_connector);
> +}
> +
>  struct vkms_crtc *vkms_crtc_init(struct vkms_device *vkmsdev,
>  				 struct drm_plane *primary,
> -				 struct drm_plane *cursor)
> +				 struct drm_plane *cursor,
> +				 struct vkms_config_crtc *config)
>  {
>  	struct drm_device *dev = &vkmsdev->drm;
>  	struct vkms_crtc *vkms_crtc;
> @@ -317,5 +325,15 @@ struct vkms_crtc *vkms_crtc_init(struct vkms_device *vkmsdev,
>  	if (ret)
>  		return ERR_PTR(ret);
>  
> +	if (config->writeback) {
> +		ret = vkms_enable_writeback_connector(vkmsdev, vkms_crtc);
> +		if (ret)
> +			return ERR_PTR(ret);
> +		ret = drmm_add_action_or_reset(&vkmsdev->drm, vkms_crtc_cleanup_writeback_connector,
> +					       vkms_crtc);
> +		if (ret)
> +			return ERR_PTR(ret);
> +	}
> +
>  	return vkms_crtc;
>  }
> diff --git a/drivers/gpu/drm/vkms/vkms_crtc.h b/drivers/gpu/drm/vkms/vkms_crtc.h
> index dde28884a0a5..a271e95f1cfe 100644
> --- a/drivers/gpu/drm/vkms/vkms_crtc.h
> +++ b/drivers/gpu/drm/vkms/vkms_crtc.h
> @@ -86,5 +86,6 @@ struct vkms_crtc {
>   */
>  struct vkms_crtc *vkms_crtc_init(struct vkms_device *vkmsdev,
>  				 struct drm_plane *primary,
> -				 struct drm_plane *cursor);
> +				 struct drm_plane *cursor,
> +				 struct vkms_config_crtc *config);
>  #endif //_VKMS_CRTC_H
> diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
> index 403006a0bb61..6deff5099322 100644
> --- a/drivers/gpu/drm/vkms/vkms_drv.c
> +++ b/drivers/gpu/drm/vkms/vkms_drv.c
> @@ -153,13 +153,12 @@ static const struct drm_connector_helper_funcs vkms_conn_helper_funcs = {
>  
>  static int vkms_output_init(struct vkms_device *vkmsdev)
>  {
> -	struct vkms_config_plane *config_plane;
> +	struct vkms_config_encoder *config_encoder;
>  	struct drm_device *dev = &vkmsdev->drm;
> +	struct vkms_config_plane *config_plane;
> +	struct vkms_config_crtc *config_crtc;
>  	struct drm_connector *connector;
> -	struct drm_encoder *encoder;
> -	struct vkms_crtc *crtc;
> -	struct drm_plane *plane;
> -	struct vkms_plane *primary, *cursor = NULL;
> +	unsigned long idx;
>  	int ret;
>  	int writeback;
>  
> @@ -169,22 +168,30 @@ static int vkms_output_init(struct vkms_device *vkmsdev)
>  			ret = PTR_ERR(config_plane->plane);
>  			return ret;
>  		}
> -
> -		if (config_plane->type == DRM_PLANE_TYPE_PRIMARY)
> -			primary = config_plane->plane;
> -		else if (config_plane->type == DRM_PLANE_TYPE_CURSOR)
> -			cursor = config_plane->plane;
>  	}
>  
> -	/* [1]: Initialize the crtc component */
> -	crtc = vkms_crtc_init(vkmsdev, &primary->base,
> -			      cursor ? &cursor->base : NULL);
> -	if (IS_ERR(crtc))
> -		return PTR_ERR(crtc);
> +	list_for_each_entry(config_crtc, &vkmsdev->config->crtcs, link) {
> +		struct drm_plane *primary = NULL, *cursor = NULL;
> +
> +		xa_for_each(&config_crtc->possible_planes, idx, config_plane) {
> +			if (config_plane->type == DRM_PLANE_TYPE_PRIMARY)
> +				primary = &config_plane->plane->base;
> +			else if (config_plane->type == DRM_PLANE_TYPE_CURSOR)
> +				cursor = &config_plane->plane->base;
> +		}
> +
> +		config_crtc->crtc = vkms_crtc_init(vkmsdev, primary, cursor, config_crtc);
>  
> -	/* Enable the output's CRTC for all the planes */
> -	drm_for_each_plane(plane, &vkmsdev->drm) {
> -		plane->possible_crtcs |= drm_crtc_mask(&crtc->base);
> +		if (IS_ERR(config_crtc->crtc)) {
> +			ret = PTR_ERR(config_crtc->crtc);
> +			return ret;
> +		}
> +	}
> +
> +	list_for_each_entry(config_crtc, &vkmsdev->config->crtcs, link) {
> +		xa_for_each(&config_crtc->possible_planes, idx, config_plane) {
> +			config_plane->plane->base.possible_crtcs |= drm_crtc_mask(&config_crtc->crtc->base);
> +		}
>  	}
>  
>  	/* Initialize the connector component */
> @@ -201,32 +208,28 @@ static int vkms_output_init(struct vkms_device *vkmsdev)
>  
>  	drm_connector_helper_add(connector, &vkms_conn_helper_funcs);
>  
> -	/* Initialize the encoder component */
> -	encoder = drmm_kzalloc(&vkmsdev->drm, sizeof(*encoder), GFP_KERNEL);
> -	if (!encoder)
> -		return -ENOMEM;
> -
> -	ret = drmm_encoder_init(dev, encoder, &vkms_encoder_funcs,
> -				DRM_MODE_ENCODER_VIRTUAL, NULL);
> -	if (ret) {
> -		DRM_ERROR("Failed to init encoder\n");
> -		return ret;
> -	}
> -
> -	encoder->possible_crtcs = drm_crtc_mask(&crtc->base);
>  
> -	/* Attach the encoder and the connector */
> -	ret = drm_connector_attach_encoder(connector, encoder);
> -	if (ret) {
> -		DRM_ERROR("Failed to attach connector to encoder\n");
> -		return ret;
> -	}
> +	list_for_each_entry(config_encoder, &vkmsdev->config->encoders, link) {
> +		config_encoder->encoder = drmm_kzalloc(&vkmsdev->drm,
> +						       sizeof(*config_encoder->encoder),
> +						       GFP_KERNEL);
> +		if (!config_encoder->encoder)
> +			return -ENOMEM;
> +		ret = drmm_encoder_init(dev, config_encoder->encoder, &vkms_encoder_funcs,
> +					DRM_MODE_ENCODER_VIRTUAL, NULL);
> +		if (ret) {
> +			DRM_ERROR("Failed to init encoder\n");
> +			return ret;
> +		}
>  
> -	/* Initialize the writeback component */
> -	if (vkmsdev->config->writeback) {
> -		writeback = vkms_enable_writeback_connector(vkmsdev, crtc);
> -		if (writeback)
> -			DRM_ERROR("Failed to init writeback connector\n");
> +		xa_for_each(&config_encoder->possible_crtcs, idx, config_crtc) {
> +			config_encoder->encoder->possible_crtcs |= drm_crtc_mask(&config_crtc->crtc->base);
> +		}
> +		if (IS_ERR(config_encoder->encoder))
> +			return PTR_ERR(config_encoder->encoder);
> +		ret = drm_connector_attach_encoder(connector, config_encoder->encoder);
> +		if (ret)
> +			return ret;
>  	}
>  
>  	drm_mode_config_reset(dev);
> 

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ