Skip to content

Commit

Permalink
drm/vmwgfx: Make sure the screen surface is ref counted
Browse files Browse the repository at this point in the history
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 <zack.rusin@broadcom.com>
Fixes: 7b00620 ("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: Maaz Mombasawala <maaz.mombasawala@broadcom.com>
Reviewed-by: Martin Krastev <martin.krastev@broadcom.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240722184313.181318-3-zack.rusin@broadcom.com
  • Loading branch information
Zack Rusin committed Jul 25, 2024
1 parent e583371 commit 09f34a0
Showing 1 changed file with 22 additions and 18 deletions.
40 changes: 22 additions & 18 deletions drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ vmw_surface_sync(struct vmw_private *vmw,
return ret;
}

static int
static void
compute_crc(struct drm_crtc *crtc,
struct vmw_surface *surf,
u32 *crc)
Expand All @@ -102,8 +102,6 @@ compute_crc(struct drm_crtc *crtc,
}

vmw_bo_unmap(bo);

return 0;
}

static void
Expand All @@ -117,7 +115,6 @@ crc_generate_worker(struct work_struct *work)
u64 frame_start, frame_end;
u32 crc32 = 0;
struct vmw_surface *surf = 0;
int ret;

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

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);

if (vmw_surface_sync(vmw, surf)) {
drm_warn(crtc->dev, "CRC worker wasn't able to sync the crc surface!\n");
return;
}
if (surf) {
if (vmw_surface_sync(vmw, surf)) {
drm_warn(
crtc->dev,
"CRC worker wasn't able to sync the crc surface!\n");
return;
}

ret = compute_crc(crtc, surf, &crc32);
if (ret)
return;
compute_crc(crtc, surf, &crc32);
vmw_surface_unreference(&surf);
}

spin_lock_irq(&du->vkms.crc_state_lock);
frame_start = du->vkms.frame_start;
frame_end = du->vkms.frame_end;
crc_pending = du->vkms.crc_pending;
du->vkms.frame_start = 0;
du->vkms.frame_end = 0;
du->vkms.crc_pending = false;
Expand All @@ -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 drm_crtc *crtc = &du->crtc;
struct vmw_private *vmw = vmw_priv(crtc->dev);
struct vmw_surface *surf = NULL;
bool has_surface = false;
u64 ret_overrun;
bool locked, ret;

Expand All @@ -180,10 +179,10 @@ vmw_vkms_vblank_simulate(struct hrtimer *timer)
WARN_ON(!ret);
if (!locked)
return HRTIMER_RESTART;
surf = du->vkms.surface;
has_surface = du->vkms.surface != NULL;
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);

spin_lock(&du->vkms.crc_state_lock);
Expand Down Expand Up @@ -337,6 +336,8 @@ vmw_vkms_crtc_cleanup(struct drm_crtc *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));
hrtimer_cancel(&du->vkms.timer);
}
Expand Down Expand Up @@ -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_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);
du->vkms.surface = surf;
if (du->vkms.surface)
vmw_surface_unreference(&du->vkms.surface);
if (surf)
du->vkms.surface = vmw_surface_reference(surf);
}
}

Expand Down

0 comments on commit 09f34a0

Please sign in to comment.