All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sean Paul <seanpaul@chromium.org>
To: Haneen Mohammed <hamohammed.sa@gmail.com>
Cc: rodrigosiqueiramelo@gmail.com, dri-devel@lists.freedesktop.org
Subject: Re: [PATCH v3 5/5] drm/vkms: Implement CRC debugfs API
Date: Mon, 23 Jul 2018 10:05:53 -0400	[thread overview]
Message-ID: <20180723140553.GG20359@art_vandelay> (raw)
In-Reply-To: <f7400b0db272566f135adbb1f777d487765ff2a0.1531955948.git.hamohammed.sa@gmail.com>

On Thu, Jul 19, 2018 at 03:22:16AM +0300, Haneen Mohammed wrote:
> Implement the set_crc_source() callback.
> Compute CRC using crc32 on the visible part of the framebuffer.
> Use ordered workqueue to compute and add CRC at the end of a vblank.
> 
> Use appropriate synchronization methods since the CRC computation must
> be atomic wrt the generated vblank event for a given atomic update, by
> using spinlock across atomic_begin and atomic_flush to wrap the event
> handling code completely and match the flip event with the CRC.
> 
> Signed-off-by: Haneen Mohammed <hamohammed.sa@gmail.com>
> ---
> Changes in v3:
> - flush work item instead of workqueue
> - include missing vkms_crc.c file
> 
>  drivers/gpu/drm/vkms/Makefile     |  2 +-
>  drivers/gpu/drm/vkms/vkms_crc.c   | 66 +++++++++++++++++++++++++++++++
>  drivers/gpu/drm/vkms/vkms_crtc.c  | 58 ++++++++++++++++++++++-----
>  drivers/gpu/drm/vkms/vkms_drv.c   |  1 +
>  drivers/gpu/drm/vkms/vkms_drv.h   | 21 ++++++++++
>  drivers/gpu/drm/vkms/vkms_plane.c | 10 +++++
>  6 files changed, 148 insertions(+), 10 deletions(-)
>  create mode 100644 drivers/gpu/drm/vkms/vkms_crc.c
> 
> diff --git a/drivers/gpu/drm/vkms/Makefile b/drivers/gpu/drm/vkms/Makefile
> index 986297da51bf..37966914f70b 100644
> --- a/drivers/gpu/drm/vkms/Makefile
> +++ b/drivers/gpu/drm/vkms/Makefile
> @@ -1,3 +1,3 @@
> -vkms-y := vkms_drv.o vkms_plane.o vkms_output.o vkms_crtc.o vkms_gem.o
> +vkms-y := vkms_drv.o vkms_plane.o vkms_output.o vkms_crtc.o vkms_gem.o vkms_crc.o
>  
>  obj-$(CONFIG_DRM_VKMS) += vkms.o
> diff --git a/drivers/gpu/drm/vkms/vkms_crc.c b/drivers/gpu/drm/vkms/vkms_crc.c
> new file mode 100644
> index 000000000000..9e8bb5c7fc80
> --- /dev/null
> +++ b/drivers/gpu/drm/vkms/vkms_crc.c
> @@ -0,0 +1,66 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include "vkms_drv.h"
> +#include <linux/crc32.h>
> +#include <drm/drm_gem_framebuffer_helper.h>
> +
> +static uint32_t _vkms_get_crc(struct vkms_crc_data *crc_data)
> +{
> +	struct drm_framebuffer *fb = &crc_data->fb;
> +	struct drm_gem_object *gem_obj = drm_gem_fb_get_obj(fb, 0);
> +	struct vkms_gem_object *vkms_obj = drm_gem_to_vkms_gem(gem_obj);
> +	u32 crc = 0;
> +	int i = 0;
> +	unsigned int x = crc_data->src.x1 >> 16;
> +	unsigned int y = crc_data->src.y1 >> 16;
> +	unsigned int height = drm_rect_height(&crc_data->src) >> 16;
> +	unsigned int width = drm_rect_width(&crc_data->src) >> 16;
> +	unsigned int cpp = fb->format->cpp[0];
> +	unsigned int src_offset;
> +	unsigned int size_byte = width * cpp;
> +	void *vaddr = vkms_obj->vaddr;

You should hold the lock when copying the data from crc_data.

> +
> +	if (WARN_ON(!vaddr))
> +		return crc;
> +
> +	for (i = y; i < y + height; i++) {
> +		src_offset = fb->offsets[0] + (i * fb->pitches[0]) + (x * cpp);
> +		crc = crc32_le(crc, vaddr + src_offset, size_byte);
> +	}
> +
> +	return crc;
> +}
> +
> +void vkms_crc_work_handle(struct work_struct *work)
> +{
> +	struct vkms_crtc_state *crtc_state = container_of(work,
> +						struct vkms_crtc_state,
> +						crc_work);
> +	struct drm_crtc *crtc = crtc_state->base.crtc;
> +	struct vkms_output *out = drm_crtc_to_vkms_output(crtc);
> +
> +	if (crtc_state && out->crc_enabled) {
> +		u32 crc32 = _vkms_get_crc(&crtc_state->data);
> +		unsigned int n_frame = crtc_state->n_frame;
> +
> +		drm_crtc_add_crc_entry(crtc, true, n_frame, &crc32);
> +	}
> +}
> +
> +int vkms_set_crc_source(struct drm_crtc *crtc, const char *src_name,
> +			size_t *values_cnt)
> +{
> +	struct vkms_output *out = drm_crtc_to_vkms_output(crtc);
> +

You should hold the lock when changing this value.

> +	if (!src_name) {
> +		out->crc_enabled = false;
> +	} else if (strcmp(src_name, "auto") == 0) {
> +		out->crc_enabled = true;
> +	} else {
> +		out->crc_enabled = false;
> +		return -EINVAL;
> +	}
> +
> +	*values_cnt = 1;
> +
> +	return 0;
> +}
> diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c
> index 26babb85ca77..a7b39627b581 100644
> --- a/drivers/gpu/drm/vkms/vkms_crtc.c
> +++ b/drivers/gpu/drm/vkms/vkms_crtc.c
> @@ -10,17 +10,32 @@
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_crtc_helper.h>
>  
> -static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer)
> +static void _vblank_handle(struct vkms_output *output)
>  {
> -	struct vkms_output *output = container_of(timer, struct vkms_output,
> -						  vblank_hrtimer);
>  	struct drm_crtc *crtc = &output->crtc;
> -	int ret_overrun;
> +	struct vkms_crtc_state *state = to_vkms_crtc_state(crtc->state);
>  	bool ret;
>  
> +	spin_lock(&output->lock);
>  	ret = drm_crtc_handle_vblank(crtc);
>  	if (!ret)
> -		DRM_ERROR("vkms failure on handling vblank");
> +		DRM_ERROR("vkms failure on handling vblank\n");
> +
> +	if (state && output->crc_enabled) {
> +		state->n_frame = drm_crtc_accurate_vblank_count(crtc);
> +		queue_work(output->crc_workq, &state->crc_work);
> +	}
> +
> +	spin_unlock(&output->lock);
> +}
> +
> +static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer)
> +{
> +	struct vkms_output *output = container_of(timer, struct vkms_output,
> +						  vblank_hrtimer);
> +	int ret_overrun;
> +
> +	_vblank_handle(output);
>  
>  	ret_overrun = hrtimer_forward_now(&output->vblank_hrtimer,
>  					  output->period_ns);
> @@ -97,6 +112,8 @@ vkms_atomic_crtc_duplicate_state(struct drm_crtc *crtc)
>  
>  	__drm_atomic_helper_crtc_duplicate_state(crtc, &vkms_state->base);
>  
> +	INIT_WORK(&vkms_state->crc_work, vkms_crc_work_handle);
> +
>  	return &vkms_state->base;
>  }
>  
> @@ -108,7 +125,13 @@ static void vkms_atomic_crtc_destroy_state(struct drm_crtc *crtc,
>  	vkms_state = to_vkms_crtc_state(state);
>  
>  	__drm_atomic_helper_crtc_destroy_state(state);
> -	kfree(vkms_state);
> +
> +	if (vkms_state) {
> +		flush_work(&vkms_state->crc_work);
> +		drm_framebuffer_put(&vkms_state->data.fb);

It'd be nice to leave a breadcrumb explaining where this reference is acquired.
ie: /* dropping the reference we acquired in vkms_primary_plane_update() */

> +		memset(&vkms_state->data, 0, sizeof(struct vkms_crc_data));
> +		kfree(vkms_state);
> +	}
>  }
>  
>  static const struct drm_crtc_funcs vkms_crtc_funcs = {
> @@ -120,6 +143,7 @@ static const struct drm_crtc_funcs vkms_crtc_funcs = {
>  	.atomic_destroy_state   = vkms_atomic_crtc_destroy_state,
>  	.enable_vblank		= vkms_enable_vblank,
>  	.disable_vblank		= vkms_disable_vblank,
> +	.set_crc_source		= vkms_set_crc_source,
>  };
>  
>  static void vkms_crtc_atomic_enable(struct drm_crtc *crtc,
> @@ -134,26 +158,37 @@ static void vkms_crtc_atomic_disable(struct drm_crtc *crtc,
>  	drm_crtc_vblank_off(crtc);
>  }
>  
> +static void vkms_crtc_atomic_begin(struct drm_crtc *crtc,
> +				   struct drm_crtc_state *old_crtc_state)
> +{
> +	struct vkms_output *vkms_output = drm_crtc_to_vkms_output(crtc);
> +
> +	spin_lock_irq(&vkms_output->lock);

Can you please add a comment explaining that we're holding this across the
commit to block the vblank timer, and why.

> +}
> +
>  static void vkms_crtc_atomic_flush(struct drm_crtc *crtc,
>  				   struct drm_crtc_state *old_crtc_state)
>  {
> -	unsigned long flags;
> +	struct vkms_output *vkms_output = drm_crtc_to_vkms_output(crtc);
>  
>  	if (crtc->state->event) {
> -		spin_lock_irqsave(&crtc->dev->event_lock, flags);
> +		spin_lock(&crtc->dev->event_lock);

Either don't change this (since it's always safe to call _irqsave), or add a
comment explaining why you don't need to.

>  
>  		if (drm_crtc_vblank_get(crtc) != 0)
>  			drm_crtc_send_vblank_event(crtc, crtc->state->event);
>  		else
>  			drm_crtc_arm_vblank_event(crtc, crtc->state->event);
>  
> -		spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
> +		spin_unlock(&crtc->dev->event_lock);
>  
>  		crtc->state->event = NULL;
>  	}
> +
> +	spin_unlock_irq(&vkms_output->lock);
>  }
>  
>  static const struct drm_crtc_helper_funcs vkms_crtc_helper_funcs = {
> +	.atomic_begin	= vkms_crtc_atomic_begin,
>  	.atomic_flush	= vkms_crtc_atomic_flush,
>  	.atomic_enable	= vkms_crtc_atomic_enable,
>  	.atomic_disable	= vkms_crtc_atomic_disable,
> @@ -162,6 +197,7 @@ static const struct drm_crtc_helper_funcs vkms_crtc_helper_funcs = {
>  int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
>  		   struct drm_plane *primary, struct drm_plane *cursor)
>  {
> +	struct vkms_output *vkms_out = drm_crtc_to_vkms_output(crtc);
>  	int ret;
>  
>  	ret = drm_crtc_init_with_planes(dev, crtc, primary, cursor,
> @@ -173,5 +209,9 @@ int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
>  
>  	drm_crtc_helper_add(crtc, &vkms_crtc_helper_funcs);
>  
> +	spin_lock_init(&vkms_out->lock);
> +
> +	vkms_out->crc_workq = alloc_ordered_workqueue("vkms_crc_workq", 0);
> +
>  	return ret;
>  }
> diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
> index 37aa2ef33b21..5d78bd97e69c 100644
> --- a/drivers/gpu/drm/vkms/vkms_drv.c
> +++ b/drivers/gpu/drm/vkms/vkms_drv.c
> @@ -46,6 +46,7 @@ static void vkms_release(struct drm_device *dev)
>  	platform_device_unregister(vkms->platform);
>  	drm_mode_config_cleanup(&vkms->drm);
>  	drm_dev_fini(&vkms->drm);
> +	destroy_workqueue(vkms->output.crc_workq);
>  }
>  
>  static struct drm_driver vkms_driver = {
> diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
> index 75e52d61e65d..a80281a12010 100644
> --- a/drivers/gpu/drm/vkms/vkms_drv.h
> +++ b/drivers/gpu/drm/vkms/vkms_drv.h
> @@ -20,12 +20,23 @@ static const u32 vkms_formats[] = {
>  	DRM_FORMAT_XRGB8888,
>  };
>  
> +struct vkms_crc_data {
> +	struct drm_rect src;
> +	struct drm_framebuffer fb;
> +};
> +
>  /**
>   * vkms_crtc_state - Driver specific CRTC state
>   * @base: base CRTC state
> + * @crc_work: work struct to compute and add CRC entries
> + * @data: data required for CRC computation
> + * @n_frame: frame number for computed CRC
>   */
>  struct vkms_crtc_state {
>  	struct drm_crtc_state base;
> +	struct work_struct crc_work;
> +	struct vkms_crc_data data;
> +	unsigned int n_frame;
>  };
>  
>  struct vkms_output {
> @@ -35,6 +46,11 @@ struct vkms_output {
>  	struct hrtimer vblank_hrtimer;
>  	ktime_t period_ns;
>  	struct drm_pending_vblank_event *event;
> +	bool crc_enabled;
> +	/* ordered wq for crc_work */
> +	struct workqueue_struct *crc_workq;
> +	/* protects concurrent access to crc_data */
> +	spinlock_t lock;
>  };
>  
>  struct vkms_device {
> @@ -95,4 +111,9 @@ int vkms_gem_vmap(struct drm_gem_object *obj);
>  
>  void vkms_gem_vunmap(struct drm_gem_object *obj);
>  
> +/* CRC Support */
> +int vkms_set_crc_source(struct drm_crtc *crtc, const char *src_name,
> +			size_t *values_cnt);
> +void vkms_crc_work_handle(struct work_struct *work);
> +
>  #endif /* _VKMS_DRV_H_ */
> diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c
> index 5b7c5d59f103..b316b2af88ee 100644
> --- a/drivers/gpu/drm/vkms/vkms_plane.c
> +++ b/drivers/gpu/drm/vkms/vkms_plane.c
> @@ -24,6 +24,16 @@ static const struct drm_plane_funcs vkms_plane_funcs = {
>  static void vkms_primary_plane_update(struct drm_plane *plane,
>  				      struct drm_plane_state *old_state)
>  {
> +	struct vkms_crtc_state *state;
> +
> +	if (!plane->state->crtc || !plane->state->fb)
> +		return;
> +
> +	state = to_vkms_crtc_state(plane->state->crtc->state);
> +	memcpy(&state->data.src, &plane->state->src, sizeof(struct drm_rect));
> +	memcpy(&state->data.fb, plane->state->fb,
> +	       sizeof(struct drm_framebuffer));
> +	drm_framebuffer_get(&state->data.fb);

Similarly to above, a comment explaining this is released in state_destroy would
be helpful.

>  }
>  
>  static int vkms_plane_atomic_check(struct drm_plane *plane,
> -- 
> 2.17.1
> 

-- 
Sean Paul, Software Engineer, Google / Chromium OS
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

      reply	other threads:[~2018-07-23 14:05 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-07-19  0:17 [PATCH v3 0/5] Implement CRC and Add necessary infrastructure Haneen Mohammed
2018-07-19  0:18 ` [PATCH v3 1/5] drm/vkms: Add functions to map/unmap GEM backing storage Haneen Mohammed
2018-07-23 13:51   ` Sean Paul
2018-07-19  0:18 ` [PATCH v3 2/5] drm/vkms: map/unmap buffers in [prepare/cleanup]_fb hooks Haneen Mohammed
2018-07-23 13:54   ` Sean Paul
2018-07-19  0:20 ` [PATCH v3 3/5] drm/vkms: Add atomic_helper_check_plane_state Haneen Mohammed
2018-07-19  0:21 ` [PATCH v3 4/5] drm/vkms: subclass CRTC state Haneen Mohammed
2018-07-19  0:22 ` [PATCH v3 5/5] drm/vkms: Implement CRC debugfs API Haneen Mohammed
2018-07-23 14:05   ` Sean Paul [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180723140553.GG20359@art_vandelay \
    --to=seanpaul@chromium.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=hamohammed.sa@gmail.com \
    --cc=rodrigosiqueiramelo@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.