All of lore.kernel.org
 help / color / mirror / Atom feed
From: Haneen Mohammed <hamohammed.sa@gmail.com>
To: dri-devel@lists.freedesktop.org
Cc: seanpaul@chromium.org, rodrigosiqueiramelo@gmail.com,
	hamohammed.sa@gmail.com
Subject: [PATCH v2] drm/vkms: Fix race condition around accessing frame number
Date: Tue, 4 Sep 2018 00:18:17 +0300	[thread overview]
Message-ID: <20180903211743.GA2773@haneenDRM> (raw)

crtc_state is accessed by both vblank_handle() and the ordered
work_struct handle vkms_crc_work_handle() to retrieve and or update
the frame number for computed CRC.

Since work_struct can fail, add frame_end to account for missing frame
numbers.

Use (frame_[start/end]) for synchronization between hrtimer callback
and ordered work_struct handle.

This patch passes the following subtests from igt kms_pipe_crc_basic test:
bad-source, read-crc-pipe-A, read-crc-pipe-A-frame-sequence,
nonblocking-crc-pipe-A, nonblocking-crc-pipe-A-frame-sequence

Signed-off-by: Haneen Mohammed <hamohammed.sa@gmail.com>
---
v2:
- use u64 with spinlock instead of atomic_t
- add out label for common exit routine @vkms_crc_work_handle()

 drivers/gpu/drm/vkms/vkms_crc.c  | 36 ++++++++++++++++++++++++++++++--
 drivers/gpu/drm/vkms/vkms_crtc.c | 16 ++++++++++++--
 drivers/gpu/drm/vkms/vkms_drv.h  |  8 +++++--
 3 files changed, 54 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_crc.c b/drivers/gpu/drm/vkms/vkms_crc.c
index ed47d67cecd6..68db42f15086 100644
--- a/drivers/gpu/drm/vkms/vkms_crc.c
+++ b/drivers/gpu/drm/vkms/vkms_crc.c
@@ -34,6 +34,15 @@ static uint32_t _vkms_get_crc(struct vkms_crc_data *crc_data)
 	return crc;
 }
 
+/**
+ * vkms_crc_work_handle - ordered work_struct to compute CRC
+ *
+ * @work: work_struct
+ *
+ * Work handler for computing CRCs. work_struct scheduled in
+ * an ordered workqueue that's periodically scheduled to run by
+ * _vblank_handle() and flushed at vkms_atomic_crtc_destroy_state().
+ */
 void vkms_crc_work_handle(struct work_struct *work)
 {
 	struct vkms_crtc_state *crtc_state = container_of(work,
@@ -45,8 +54,18 @@ void vkms_crc_work_handle(struct work_struct *work)
 						output);
 	struct vkms_crc_data *primary_crc = NULL;
 	struct drm_plane *plane;
-
 	u32 crc32 = 0;
+	u64 frame_start, frame_end;
+	unsigned long flags;
+
+	spin_lock_irqsave(&out->state_lock, flags);
+	frame_start = crtc_state->frame_start;
+	frame_end = crtc_state->frame_end;
+	spin_unlock_irqrestore(&out->state_lock, flags);
+
+	/* _vblank_handle() hasn't updated frame_start yet */
+	if (!frame_start || frame_start == frame_end)
+		goto out;
 
 	drm_for_each_plane(plane, &vdev->drm) {
 		struct vkms_plane_state *vplane_state;
@@ -67,7 +86,20 @@ void vkms_crc_work_handle(struct work_struct *work)
 	if (primary_crc)
 		crc32 = _vkms_get_crc(primary_crc);
 
-	drm_crtc_add_crc_entry(crtc, true, crtc_state->n_frame, &crc32);
+	frame_end = drm_crtc_accurate_vblank_count(crtc);
+
+	/* queue_work can fail to schedule crc_work; add crc for
+	 * missing frames
+	 */
+	while (frame_start <= frame_end)
+		drm_crtc_add_crc_entry(crtc, true, frame_start++, &crc32);
+
+out:
+	/* to avoid using the same value for frame number again */
+	spin_lock_irqsave(&out->state_lock, flags);
+	crtc_state->frame_end = frame_end;
+	crtc_state->frame_start = 0;
+	spin_unlock_irqrestore(&out->state_lock, flags);
 }
 
 static int vkms_crc_parse_source(const char *src_name, bool *enabled)
diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c
index 9d0b1a325a78..177bbcb38306 100644
--- a/drivers/gpu/drm/vkms/vkms_crtc.c
+++ b/drivers/gpu/drm/vkms/vkms_crtc.c
@@ -22,8 +22,19 @@ static void _vblank_handle(struct vkms_output *output)
 		DRM_ERROR("vkms failure on handling vblank");
 
 	if (state && output->crc_enabled) {
-		state->n_frame = drm_crtc_accurate_vblank_count(crtc);
-		queue_work(output->crc_workq, &state->crc_work);
+		u64 frame = drm_crtc_accurate_vblank_count(crtc);
+
+		/* update frame_start only if a queued vkms_crc_work_handle()
+		 * has read the data
+		 */
+		spin_lock(&output->state_lock);
+		if (!state->frame_start)
+			state->frame_start = frame;
+		spin_unlock(&output->state_lock);
+
+		ret = queue_work(output->crc_workq, &state->crc_work);
+		if (!ret)
+			DRM_WARN("failed to queue vkms_crc_work_handle");
 	}
 
 	spin_unlock(&output->lock);
@@ -211,6 +222,7 @@ 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);
+	spin_lock_init(&vkms_out->state_lock);
 
 	vkms_out->crc_workq = alloc_ordered_workqueue("vkms_crc_workq", 0);
 
diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
index 2017a2ccc43d..80af6d3a65e7 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.h
+++ b/drivers/gpu/drm/vkms/vkms_drv.h
@@ -39,12 +39,14 @@ struct vkms_plane_state {
  * vkms_crtc_state - Driver specific CRTC state
  * @base: base CRTC state
  * @crc_work: work struct to compute and add CRC entries
- * @n_frame: frame number for computed CRC
+ * @n_frame_start: start frame number for computed CRC
+ * @n_frame_end: end frame number for computed CRC
  */
 struct vkms_crtc_state {
 	struct drm_crtc_state base;
 	struct work_struct crc_work;
-	unsigned int n_frame;
+	u64 frame_start;
+	u64 frame_end;
 };
 
 struct vkms_output {
@@ -59,6 +61,8 @@ struct vkms_output {
 	struct workqueue_struct *crc_workq;
 	/* protects concurrent access to crc_data */
 	spinlock_t lock;
+	/* protects concurrent access to crtc_state */
+	spinlock_t state_lock;
 };
 
 struct vkms_device {
-- 
2.17.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

             reply	other threads:[~2018-09-03 21:18 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-09-03 21:18 Haneen Mohammed [this message]
2018-09-05 14:03 ` [PATCH v2] drm/vkms: Fix race condition around accessing frame number Daniel Vetter
2018-09-05 14:24   ` Haneen Mohammed

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=20180903211743.GA2773@haneenDRM \
    --to=hamohammed.sa@gmail.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=rodrigosiqueiramelo@gmail.com \
    --cc=seanpaul@chromium.org \
    /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.