[PATCH 1/2] drm/vmwgfx: Update last_read_seqno under the fence lock
Maaz Mombasawala
maaz.mombasawala at broadcom.com
Thu Apr 10 22:38:58 UTC 2025
On 4/10/25 12:55, Ian Forbes wrote:
> There was a possible race in vmw_update_seqno. Because of this race it
> was possible for last_read_seqno to go backwards. Remove this function
> and replace it with vmw_update_fences which now sets and returns the
> last_read_seqno while holding the fence lock. This serialization via the
> fence lock ensures that last_read_seqno is monotonic again.
>
> Signed-off-by: Ian Forbes <ian.forbes at broadcom.com>
> ---
> drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c | 2 +-
> drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 1 -
> drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 3 +--
> drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 18 +++++++++---------
> drivers/gpu/drm/vmwgfx/vmwgfx_fence.h | 2 +-
> drivers/gpu/drm/vmwgfx/vmwgfx_irq.c | 12 +-----------
> 6 files changed, 13 insertions(+), 25 deletions(-)
>
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c
> index dd4ca6a9c690..8fe02131a6c4 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c
> @@ -544,7 +544,7 @@ int vmw_cmd_send_fence(struct vmw_private *dev_priv, uint32_t *seqno)
> cmd_fence = (struct svga_fifo_cmd_fence *) fm;
> cmd_fence->fence = *seqno;
> vmw_cmd_commit_flush(dev_priv, bytes);
> - vmw_update_seqno(dev_priv);
> + vmw_fences_update(dev_priv->fman);
>
> out_err:
> return ret;
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
> index 594af8eb04c6..6d4a68f0ae37 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
> @@ -1006,7 +1006,6 @@ extern int vmw_fallback_wait(struct vmw_private *dev_priv,
> uint32_t seqno,
> bool interruptible,
> unsigned long timeout);
> -extern void vmw_update_seqno(struct vmw_private *dev_priv);
> extern void vmw_seqno_waiter_add(struct vmw_private *dev_priv);
> extern void vmw_seqno_waiter_remove(struct vmw_private *dev_priv);
> extern void vmw_goal_waiter_add(struct vmw_private *dev_priv);
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
> index e831e324e737..90ce5372343b 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
> @@ -3878,8 +3878,7 @@ vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
>
> fence_rep.handle = fence_handle;
> fence_rep.seqno = fence->base.seqno;
> - vmw_update_seqno(dev_priv);
> - fence_rep.passed_seqno = dev_priv->last_read_seqno;
> + fence_rep.passed_seqno = vmw_fences_update(dev_priv->fman);
> }
>
> /*
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
> index 588d50ababf6..9d1465558839 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
> @@ -172,7 +172,7 @@ vmwgfx_wait_cb(struct dma_fence *fence, struct dma_fence_cb *cb)
> wake_up_process(wait->task);
> }
>
> -static void __vmw_fences_update(struct vmw_fence_manager *fman);
> +static u32 __vmw_fences_update(struct vmw_fence_manager *fman);
>
> static long vmw_fence_wait(struct dma_fence *f, bool intr, signed long timeout)
> {
> @@ -457,7 +457,7 @@ static bool vmw_fence_goal_check_locked(struct vmw_fence_obj *fence)
> return true;
> }
>
> -static void __vmw_fences_update(struct vmw_fence_manager *fman)
> +static u32 __vmw_fences_update(struct vmw_fence_manager *fman)
> {
> struct vmw_fence_obj *fence, *next_fence;
> struct list_head action_list;
> @@ -495,13 +495,16 @@ static void __vmw_fences_update(struct vmw_fence_manager *fman)
>
> if (!list_empty(&fman->cleanup_list))
> (void) schedule_work(&fman->work);
> + return (fman->dev_priv->last_read_seqno = seqno);
Should this be WRITE_ONCE(fman->dev_priv->last_read_seqno) = seqno ?
> }
>
> -void vmw_fences_update(struct vmw_fence_manager *fman)
> +u32 vmw_fences_update(struct vmw_fence_manager *fman)
> {
> + u32 seqno;
> spin_lock(&fman->lock);
> - __vmw_fences_update(fman);
> + seqno = __vmw_fences_update(fman);
> spin_unlock(&fman->lock);
> + return seqno;
> }
>
> bool vmw_fence_obj_signaled(struct vmw_fence_obj *fence)
> @@ -778,7 +781,6 @@ int vmw_fence_obj_signaled_ioctl(struct drm_device *dev, void *data,
> (struct drm_vmw_fence_signaled_arg *) data;
> struct ttm_base_object *base;
> struct vmw_fence_obj *fence;
> - struct vmw_fence_manager *fman;
> struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
> struct vmw_private *dev_priv = vmw_priv(dev);
>
> @@ -787,14 +789,12 @@ int vmw_fence_obj_signaled_ioctl(struct drm_device *dev, void *data,
> return PTR_ERR(base);
>
> fence = &(container_of(base, struct vmw_user_fence, base)->fence);
> - fman = fman_from_fence(fence);
>
> arg->signaled = vmw_fence_obj_signaled(fence);
>
> arg->signaled_flags = arg->flags;
> - spin_lock(&fman->lock);
> - arg->passed_seqno = dev_priv->last_read_seqno;
> - spin_unlock(&fman->lock);
> + arg->passed_seqno = READ_ONCE(dev_priv->last_read_seqno);
> +
>
> ttm_base_object_unref(&base);
>
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h
> index a7eee579c76a..10264dab5f6a 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h
> @@ -86,7 +86,7 @@ vmw_fence_obj_reference(struct vmw_fence_obj *fence)
> return fence;
> }
>
> -extern void vmw_fences_update(struct vmw_fence_manager *fman);
> +u32 vmw_fences_update(struct vmw_fence_manager *fman);
>
> extern bool vmw_fence_obj_signaled(struct vmw_fence_obj *fence);
>
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
> index 086e69a130d4..548ef2f86508 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
> @@ -123,16 +123,6 @@ static bool vmw_fifo_idle(struct vmw_private *dev_priv, uint32_t seqno)
> return (vmw_read(dev_priv, SVGA_REG_BUSY) == 0);
> }
>
> -void vmw_update_seqno(struct vmw_private *dev_priv)
> -{
> - uint32_t seqno = vmw_fence_read(dev_priv);
> -
> - if (dev_priv->last_read_seqno != seqno) {
> - dev_priv->last_read_seqno = seqno;
> - vmw_fences_update(dev_priv->fman);
> - }
> -}
> -
> bool vmw_seqno_passed(struct vmw_private *dev_priv,
> uint32_t seqno)
> {
> @@ -141,7 +131,7 @@ bool vmw_seqno_passed(struct vmw_private *dev_priv,
> if (likely(dev_priv->last_read_seqno - seqno < VMW_FENCE_WRAP))
> return true;
>
> - vmw_update_seqno(dev_priv);
> + vmw_fences_update(dev_priv->fman);
> if (likely(dev_priv->last_read_seqno - seqno < VMW_FENCE_WRAP))
> return true;
>
--
Maaz Mombasawala <maaz.mombasawala at broadcom.com>
More information about the dri-devel
mailing list