Commit 09f34a00 authored by Zack Rusin's avatar Zack Rusin

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: default avatarZack Rusin <zack.rusin@broadcom.com>
Fixes: 7b006203 ("drm/vmwgfx: Implement virtual crc generation")
Cc: Zack Rusin <zack.rusin@broadcom.com>
Cc: Broadcom internal kernel review list <bcm-kernel-feedback-list@broadcom.com>
Cc: dri-devel@lists.freedesktop.org
Reviewed-by: default avatarMaaz Mombasawala <maaz.mombasawala@broadcom.com>
Reviewed-by: default avatarMartin Krastev <martin.krastev@broadcom.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240722184313.181318-3-zack.rusin@broadcom.com
parent e5833710
...@@ -76,7 +76,7 @@ vmw_surface_sync(struct vmw_private *vmw, ...@@ -76,7 +76,7 @@ vmw_surface_sync(struct vmw_private *vmw,
return ret; return ret;
} }
static int static void
compute_crc(struct drm_crtc *crtc, compute_crc(struct drm_crtc *crtc,
struct vmw_surface *surf, struct vmw_surface *surf,
u32 *crc) u32 *crc)
...@@ -102,8 +102,6 @@ compute_crc(struct drm_crtc *crtc, ...@@ -102,8 +102,6 @@ compute_crc(struct drm_crtc *crtc,
} }
vmw_bo_unmap(bo); vmw_bo_unmap(bo);
return 0;
} }
static void static void
...@@ -117,7 +115,6 @@ crc_generate_worker(struct work_struct *work) ...@@ -117,7 +115,6 @@ crc_generate_worker(struct work_struct *work)
u64 frame_start, frame_end; u64 frame_start, frame_end;
u32 crc32 = 0; u32 crc32 = 0;
struct vmw_surface *surf = 0; struct vmw_surface *surf = 0;
int ret;
spin_lock_irq(&du->vkms.crc_state_lock); spin_lock_irq(&du->vkms.crc_state_lock);
crc_pending = du->vkms.crc_pending; crc_pending = du->vkms.crc_pending;
...@@ -131,22 +128,24 @@ crc_generate_worker(struct work_struct *work) ...@@ -131,22 +128,24 @@ crc_generate_worker(struct work_struct *work)
return; return;
spin_lock_irq(&du->vkms.crc_state_lock); spin_lock_irq(&du->vkms.crc_state_lock);
surf = du->vkms.surface; surf = vmw_surface_reference(du->vkms.surface);
spin_unlock_irq(&du->vkms.crc_state_lock); spin_unlock_irq(&du->vkms.crc_state_lock);
if (surf) {
if (vmw_surface_sync(vmw, surf)) { if (vmw_surface_sync(vmw, surf)) {
drm_warn(crtc->dev, "CRC worker wasn't able to sync the crc surface!\n"); drm_warn(
crtc->dev,
"CRC worker wasn't able to sync the crc surface!\n");
return; return;
} }
ret = compute_crc(crtc, surf, &crc32); compute_crc(crtc, surf, &crc32);
if (ret) vmw_surface_unreference(&surf);
return; }
spin_lock_irq(&du->vkms.crc_state_lock); spin_lock_irq(&du->vkms.crc_state_lock);
frame_start = du->vkms.frame_start; frame_start = du->vkms.frame_start;
frame_end = du->vkms.frame_end; frame_end = du->vkms.frame_end;
crc_pending = du->vkms.crc_pending;
du->vkms.frame_start = 0; du->vkms.frame_start = 0;
du->vkms.frame_end = 0; du->vkms.frame_end = 0;
du->vkms.crc_pending = false; du->vkms.crc_pending = false;
...@@ -165,7 +164,7 @@ vmw_vkms_vblank_simulate(struct hrtimer *timer) ...@@ -165,7 +164,7 @@ vmw_vkms_vblank_simulate(struct hrtimer *timer)
struct vmw_display_unit *du = container_of(timer, struct vmw_display_unit, vkms.timer); struct vmw_display_unit *du = container_of(timer, struct vmw_display_unit, vkms.timer);
struct drm_crtc *crtc = &du->crtc; struct drm_crtc *crtc = &du->crtc;
struct vmw_private *vmw = vmw_priv(crtc->dev); struct vmw_private *vmw = vmw_priv(crtc->dev);
struct vmw_surface *surf = NULL; bool has_surface = false;
u64 ret_overrun; u64 ret_overrun;
bool locked, ret; bool locked, ret;
...@@ -180,10 +179,10 @@ vmw_vkms_vblank_simulate(struct hrtimer *timer) ...@@ -180,10 +179,10 @@ vmw_vkms_vblank_simulate(struct hrtimer *timer)
WARN_ON(!ret); WARN_ON(!ret);
if (!locked) if (!locked)
return HRTIMER_RESTART; return HRTIMER_RESTART;
surf = du->vkms.surface; has_surface = du->vkms.surface != NULL;
vmw_vkms_unlock(crtc); vmw_vkms_unlock(crtc);
if (du->vkms.crc_enabled && surf) { if (du->vkms.crc_enabled && has_surface) {
u64 frame = drm_crtc_accurate_vblank_count(crtc); u64 frame = drm_crtc_accurate_vblank_count(crtc);
spin_lock(&du->vkms.crc_state_lock); spin_lock(&du->vkms.crc_state_lock);
...@@ -337,6 +336,8 @@ vmw_vkms_crtc_cleanup(struct drm_crtc *crtc) ...@@ -337,6 +336,8 @@ vmw_vkms_crtc_cleanup(struct drm_crtc *crtc)
{ {
struct vmw_display_unit *du = vmw_crtc_to_du(crtc); struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
if (du->vkms.surface)
vmw_surface_unreference(&du->vkms.surface);
WARN_ON(work_pending(&du->vkms.crc_generator_work)); WARN_ON(work_pending(&du->vkms.crc_generator_work));
hrtimer_cancel(&du->vkms.timer); hrtimer_cancel(&du->vkms.timer);
} }
...@@ -498,9 +499,12 @@ vmw_vkms_set_crc_surface(struct drm_crtc *crtc, ...@@ -498,9 +499,12 @@ vmw_vkms_set_crc_surface(struct drm_crtc *crtc,
struct vmw_display_unit *du = vmw_crtc_to_du(crtc); struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
struct vmw_private *vmw = vmw_priv(crtc->dev); struct vmw_private *vmw = vmw_priv(crtc->dev);
if (vmw->vkms_enabled) { if (vmw->vkms_enabled && du->vkms.surface != surf) {
WARN_ON(atomic_read(&du->vkms.atomic_lock) != VMW_VKMS_LOCK_MODESET); WARN_ON(atomic_read(&du->vkms.atomic_lock) != VMW_VKMS_LOCK_MODESET);
du->vkms.surface = surf; if (du->vkms.surface)
vmw_surface_unreference(&du->vkms.surface);
if (surf)
du->vkms.surface = vmw_surface_reference(surf);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment