Skip to content

Commit 09f34a0

Browse files
committed
drm/vmwgfx: Make sure the screen surface is ref counted
Fix races issues in virtual crc generation by making sure the surface the code uses for crc computation is properly ref counted. Crc generation was trying to be too clever by allowing the surfaces to go in and out of scope, with the hope of always having some kind of screen present. That's not always the code, in particular during atomic disable, so to make sure the surface, when present, is not being actively destroyed at the same time, hold a reference to it. Signed-off-by: Zack Rusin <[email protected]> Fixes: 7b00620 ("drm/vmwgfx: Implement virtual crc generation") Cc: Zack Rusin <[email protected]> Cc: Broadcom internal kernel review list <[email protected]> Cc: [email protected] Reviewed-by: Maaz Mombasawala <[email protected]> Reviewed-by: Martin Krastev <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent e583371 commit 09f34a0

File tree

1 file changed

+22
-18
lines changed

1 file changed

+22
-18
lines changed

drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ vmw_surface_sync(struct vmw_private *vmw,
7676
return ret;
7777
}
7878

79-
static int
79+
static void
8080
compute_crc(struct drm_crtc *crtc,
8181
struct vmw_surface *surf,
8282
u32 *crc)
@@ -102,8 +102,6 @@ compute_crc(struct drm_crtc *crtc,
102102
}
103103

104104
vmw_bo_unmap(bo);
105-
106-
return 0;
107105
}
108106

109107
static void
@@ -117,7 +115,6 @@ crc_generate_worker(struct work_struct *work)
117115
u64 frame_start, frame_end;
118116
u32 crc32 = 0;
119117
struct vmw_surface *surf = 0;
120-
int ret;
121118

122119
spin_lock_irq(&du->vkms.crc_state_lock);
123120
crc_pending = du->vkms.crc_pending;
@@ -131,22 +128,24 @@ crc_generate_worker(struct work_struct *work)
131128
return;
132129

133130
spin_lock_irq(&du->vkms.crc_state_lock);
134-
surf = du->vkms.surface;
131+
surf = vmw_surface_reference(du->vkms.surface);
135132
spin_unlock_irq(&du->vkms.crc_state_lock);
136133

137-
if (vmw_surface_sync(vmw, surf)) {
138-
drm_warn(crtc->dev, "CRC worker wasn't able to sync the crc surface!\n");
139-
return;
140-
}
134+
if (surf) {
135+
if (vmw_surface_sync(vmw, surf)) {
136+
drm_warn(
137+
crtc->dev,
138+
"CRC worker wasn't able to sync the crc surface!\n");
139+
return;
140+
}
141141

142-
ret = compute_crc(crtc, surf, &crc32);
143-
if (ret)
144-
return;
142+
compute_crc(crtc, surf, &crc32);
143+
vmw_surface_unreference(&surf);
144+
}
145145

146146
spin_lock_irq(&du->vkms.crc_state_lock);
147147
frame_start = du->vkms.frame_start;
148148
frame_end = du->vkms.frame_end;
149-
crc_pending = du->vkms.crc_pending;
150149
du->vkms.frame_start = 0;
151150
du->vkms.frame_end = 0;
152151
du->vkms.crc_pending = false;
@@ -165,7 +164,7 @@ vmw_vkms_vblank_simulate(struct hrtimer *timer)
165164
struct vmw_display_unit *du = container_of(timer, struct vmw_display_unit, vkms.timer);
166165
struct drm_crtc *crtc = &du->crtc;
167166
struct vmw_private *vmw = vmw_priv(crtc->dev);
168-
struct vmw_surface *surf = NULL;
167+
bool has_surface = false;
169168
u64 ret_overrun;
170169
bool locked, ret;
171170

@@ -180,10 +179,10 @@ vmw_vkms_vblank_simulate(struct hrtimer *timer)
180179
WARN_ON(!ret);
181180
if (!locked)
182181
return HRTIMER_RESTART;
183-
surf = du->vkms.surface;
182+
has_surface = du->vkms.surface != NULL;
184183
vmw_vkms_unlock(crtc);
185184

186-
if (du->vkms.crc_enabled && surf) {
185+
if (du->vkms.crc_enabled && has_surface) {
187186
u64 frame = drm_crtc_accurate_vblank_count(crtc);
188187

189188
spin_lock(&du->vkms.crc_state_lock);
@@ -337,6 +336,8 @@ vmw_vkms_crtc_cleanup(struct drm_crtc *crtc)
337336
{
338337
struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
339338

339+
if (du->vkms.surface)
340+
vmw_surface_unreference(&du->vkms.surface);
340341
WARN_ON(work_pending(&du->vkms.crc_generator_work));
341342
hrtimer_cancel(&du->vkms.timer);
342343
}
@@ -498,9 +499,12 @@ vmw_vkms_set_crc_surface(struct drm_crtc *crtc,
498499
struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
499500
struct vmw_private *vmw = vmw_priv(crtc->dev);
500501

501-
if (vmw->vkms_enabled) {
502+
if (vmw->vkms_enabled && du->vkms.surface != surf) {
502503
WARN_ON(atomic_read(&du->vkms.atomic_lock) != VMW_VKMS_LOCK_MODESET);
503-
du->vkms.surface = surf;
504+
if (du->vkms.surface)
505+
vmw_surface_unreference(&du->vkms.surface);
506+
if (surf)
507+
du->vkms.surface = vmw_surface_reference(surf);
504508
}
505509
}
506510

0 commit comments

Comments
 (0)