diff options
-rw-r--r-- | drivers/gpu/drm/vkms/vkms_crc.c | 36 | ||||
-rw-r--r-- | drivers/gpu/drm/vkms/vkms_crtc.c | 16 | ||||
-rw-r--r-- | 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 @@ out: | |||
34 | return crc; | 34 | return crc; |
35 | } | 35 | } |
36 | 36 | ||
37 | /** | ||
38 | * vkms_crc_work_handle - ordered work_struct to compute CRC | ||
39 | * | ||
40 | * @work: work_struct | ||
41 | * | ||
42 | * Work handler for computing CRCs. work_struct scheduled in | ||
43 | * an ordered workqueue that's periodically scheduled to run by | ||
44 | * _vblank_handle() and flushed at vkms_atomic_crtc_destroy_state(). | ||
45 | */ | ||
37 | void vkms_crc_work_handle(struct work_struct *work) | 46 | void vkms_crc_work_handle(struct work_struct *work) |
38 | { | 47 | { |
39 | struct vkms_crtc_state *crtc_state = container_of(work, | 48 | struct vkms_crtc_state *crtc_state = container_of(work, |
@@ -45,8 +54,18 @@ void vkms_crc_work_handle(struct work_struct *work) | |||
45 | output); | 54 | output); |
46 | struct vkms_crc_data *primary_crc = NULL; | 55 | struct vkms_crc_data *primary_crc = NULL; |
47 | struct drm_plane *plane; | 56 | struct drm_plane *plane; |
48 | |||
49 | u32 crc32 = 0; | 57 | u32 crc32 = 0; |
58 | u64 frame_start, frame_end; | ||
59 | unsigned long flags; | ||
60 | |||
61 | spin_lock_irqsave(&out->state_lock, flags); | ||
62 | frame_start = crtc_state->frame_start; | ||
63 | frame_end = crtc_state->frame_end; | ||
64 | spin_unlock_irqrestore(&out->state_lock, flags); | ||
65 | |||
66 | /* _vblank_handle() hasn't updated frame_start yet */ | ||
67 | if (!frame_start || frame_start == frame_end) | ||
68 | goto out; | ||
50 | 69 | ||
51 | drm_for_each_plane(plane, &vdev->drm) { | 70 | drm_for_each_plane(plane, &vdev->drm) { |
52 | struct vkms_plane_state *vplane_state; | 71 | struct vkms_plane_state *vplane_state; |
@@ -67,7 +86,20 @@ void vkms_crc_work_handle(struct work_struct *work) | |||
67 | if (primary_crc) | 86 | if (primary_crc) |
68 | crc32 = _vkms_get_crc(primary_crc); | 87 | crc32 = _vkms_get_crc(primary_crc); |
69 | 88 | ||
70 | drm_crtc_add_crc_entry(crtc, true, crtc_state->n_frame, &crc32); | 89 | frame_end = drm_crtc_accurate_vblank_count(crtc); |
90 | |||
91 | /* queue_work can fail to schedule crc_work; add crc for | ||
92 | * missing frames | ||
93 | */ | ||
94 | while (frame_start <= frame_end) | ||
95 | drm_crtc_add_crc_entry(crtc, true, frame_start++, &crc32); | ||
96 | |||
97 | out: | ||
98 | /* to avoid using the same value for frame number again */ | ||
99 | spin_lock_irqsave(&out->state_lock, flags); | ||
100 | crtc_state->frame_end = frame_end; | ||
101 | crtc_state->frame_start = 0; | ||
102 | spin_unlock_irqrestore(&out->state_lock, flags); | ||
71 | } | 103 | } |
72 | 104 | ||
73 | static int vkms_crc_parse_source(const char *src_name, bool *enabled) | 105 | 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) | |||
22 | DRM_ERROR("vkms failure on handling vblank"); | 22 | DRM_ERROR("vkms failure on handling vblank"); |
23 | 23 | ||
24 | if (state && output->crc_enabled) { | 24 | if (state && output->crc_enabled) { |
25 | state->n_frame = drm_crtc_accurate_vblank_count(crtc); | 25 | u64 frame = drm_crtc_accurate_vblank_count(crtc); |
26 | queue_work(output->crc_workq, &state->crc_work); | 26 | |
27 | /* update frame_start only if a queued vkms_crc_work_handle() | ||
28 | * has read the data | ||
29 | */ | ||
30 | spin_lock(&output->state_lock); | ||
31 | if (!state->frame_start) | ||
32 | state->frame_start = frame; | ||
33 | spin_unlock(&output->state_lock); | ||
34 | |||
35 | ret = queue_work(output->crc_workq, &state->crc_work); | ||
36 | if (!ret) | ||
37 | DRM_WARN("failed to queue vkms_crc_work_handle"); | ||
27 | } | 38 | } |
28 | 39 | ||
29 | spin_unlock(&output->lock); | 40 | spin_unlock(&output->lock); |
@@ -211,6 +222,7 @@ int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, | |||
211 | drm_crtc_helper_add(crtc, &vkms_crtc_helper_funcs); | 222 | drm_crtc_helper_add(crtc, &vkms_crtc_helper_funcs); |
212 | 223 | ||
213 | spin_lock_init(&vkms_out->lock); | 224 | spin_lock_init(&vkms_out->lock); |
225 | spin_lock_init(&vkms_out->state_lock); | ||
214 | 226 | ||
215 | vkms_out->crc_workq = alloc_ordered_workqueue("vkms_crc_workq", 0); | 227 | vkms_out->crc_workq = alloc_ordered_workqueue("vkms_crc_workq", 0); |
216 | 228 | ||
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 { | |||
39 | * vkms_crtc_state - Driver specific CRTC state | 39 | * vkms_crtc_state - Driver specific CRTC state |
40 | * @base: base CRTC state | 40 | * @base: base CRTC state |
41 | * @crc_work: work struct to compute and add CRC entries | 41 | * @crc_work: work struct to compute and add CRC entries |
42 | * @n_frame: frame number for computed CRC | 42 | * @n_frame_start: start frame number for computed CRC |
43 | * @n_frame_end: end frame number for computed CRC | ||
43 | */ | 44 | */ |
44 | struct vkms_crtc_state { | 45 | struct vkms_crtc_state { |
45 | struct drm_crtc_state base; | 46 | struct drm_crtc_state base; |
46 | struct work_struct crc_work; | 47 | struct work_struct crc_work; |
47 | unsigned int n_frame; | 48 | u64 frame_start; |
49 | u64 frame_end; | ||
48 | }; | 50 | }; |
49 | 51 | ||
50 | struct vkms_output { | 52 | struct vkms_output { |
@@ -59,6 +61,8 @@ struct vkms_output { | |||
59 | struct workqueue_struct *crc_workq; | 61 | struct workqueue_struct *crc_workq; |
60 | /* protects concurrent access to crc_data */ | 62 | /* protects concurrent access to crc_data */ |
61 | spinlock_t lock; | 63 | spinlock_t lock; |
64 | /* protects concurrent access to crtc_state */ | ||
65 | spinlock_t state_lock; | ||
62 | }; | 66 | }; |
63 | 67 | ||
64 | struct vkms_device { | 68 | struct vkms_device { |