| From acc5a75bfb266766e6fbea725bb6be295a45a683 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Mon, 21 Oct 2024 02:08:03 +0300 |
| Subject: drm/virtio: New fence for every plane update |
| |
| From: Dongwon Kim <dongwon.kim@intel.com> |
| |
| [ Upstream commit d3c55b8ab6fe5fa2e7ab02efd36d09c39ee5022f ] |
| |
| Having a fence linked to a virtio_gpu_framebuffer in the plane update |
| sequence would cause conflict when several planes referencing the same |
| framebuffer (e.g. Xorg screen covering multi-displays configured for an |
| extended mode) and those planes are updated concurrently. So it is needed |
| to allocate a fence for every plane state instead of the framebuffer. |
| |
| Signed-off-by: Dongwon Kim <dongwon.kim@intel.com> |
| [dmitry.osipenko@collabora.com: rebase, fix up, edit commit message] |
| Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com> |
| Acked-by: Vivek Kasireddy <vivek.kasireddy@intel.com> |
| Reviewed-by: Rob Clark <robdclark@gmail.com> |
| Link: https://patchwork.freedesktop.org/patch/msgid/20241020230803.247419-2-dmitry.osipenko@collabora.com |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/gpu/drm/virtio/virtgpu_drv.h | 7 ++++ |
| drivers/gpu/drm/virtio/virtgpu_plane.c | 58 +++++++++++++++++--------- |
| 2 files changed, 46 insertions(+), 19 deletions(-) |
| |
| diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h |
| index 64c236169db88..5dc8eeaf7123c 100644 |
| --- a/drivers/gpu/drm/virtio/virtgpu_drv.h |
| +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h |
| @@ -194,6 +194,13 @@ struct virtio_gpu_framebuffer { |
| #define to_virtio_gpu_framebuffer(x) \ |
| container_of(x, struct virtio_gpu_framebuffer, base) |
| |
| +struct virtio_gpu_plane_state { |
| + struct drm_plane_state base; |
| + struct virtio_gpu_fence *fence; |
| +}; |
| +#define to_virtio_gpu_plane_state(x) \ |
| + container_of(x, struct virtio_gpu_plane_state, base) |
| + |
| struct virtio_gpu_queue { |
| struct virtqueue *vq; |
| spinlock_t qlock; |
| diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c |
| index a72a2dbda031c..7acd38b962c62 100644 |
| --- a/drivers/gpu/drm/virtio/virtgpu_plane.c |
| +++ b/drivers/gpu/drm/virtio/virtgpu_plane.c |
| @@ -66,11 +66,28 @@ uint32_t virtio_gpu_translate_format(uint32_t drm_fourcc) |
| return format; |
| } |
| |
| +static struct |
| +drm_plane_state *virtio_gpu_plane_duplicate_state(struct drm_plane *plane) |
| +{ |
| + struct virtio_gpu_plane_state *new; |
| + |
| + if (WARN_ON(!plane->state)) |
| + return NULL; |
| + |
| + new = kzalloc(sizeof(*new), GFP_KERNEL); |
| + if (!new) |
| + return NULL; |
| + |
| + __drm_atomic_helper_plane_duplicate_state(plane, &new->base); |
| + |
| + return &new->base; |
| +} |
| + |
| static const struct drm_plane_funcs virtio_gpu_plane_funcs = { |
| .update_plane = drm_atomic_helper_update_plane, |
| .disable_plane = drm_atomic_helper_disable_plane, |
| .reset = drm_atomic_helper_plane_reset, |
| - .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, |
| + .atomic_duplicate_state = virtio_gpu_plane_duplicate_state, |
| .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, |
| }; |
| |
| @@ -138,11 +155,13 @@ static void virtio_gpu_resource_flush(struct drm_plane *plane, |
| struct drm_device *dev = plane->dev; |
| struct virtio_gpu_device *vgdev = dev->dev_private; |
| struct virtio_gpu_framebuffer *vgfb; |
| + struct virtio_gpu_plane_state *vgplane_st; |
| struct virtio_gpu_object *bo; |
| |
| vgfb = to_virtio_gpu_framebuffer(plane->state->fb); |
| + vgplane_st = to_virtio_gpu_plane_state(plane->state); |
| bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]); |
| - if (vgfb->fence) { |
| + if (vgplane_st->fence) { |
| struct virtio_gpu_object_array *objs; |
| |
| objs = virtio_gpu_array_alloc(1); |
| @@ -151,13 +170,11 @@ static void virtio_gpu_resource_flush(struct drm_plane *plane, |
| virtio_gpu_array_add_obj(objs, vgfb->base.obj[0]); |
| virtio_gpu_array_lock_resv(objs); |
| virtio_gpu_cmd_resource_flush(vgdev, bo->hw_res_handle, x, y, |
| - width, height, objs, vgfb->fence); |
| + width, height, objs, |
| + vgplane_st->fence); |
| virtio_gpu_notify(vgdev); |
| - |
| - dma_fence_wait_timeout(&vgfb->fence->f, true, |
| + dma_fence_wait_timeout(&vgplane_st->fence->f, true, |
| msecs_to_jiffies(50)); |
| - dma_fence_put(&vgfb->fence->f); |
| - vgfb->fence = NULL; |
| } else { |
| virtio_gpu_cmd_resource_flush(vgdev, bo->hw_res_handle, x, y, |
| width, height, NULL, NULL); |
| @@ -247,20 +264,23 @@ static int virtio_gpu_plane_prepare_fb(struct drm_plane *plane, |
| struct drm_device *dev = plane->dev; |
| struct virtio_gpu_device *vgdev = dev->dev_private; |
| struct virtio_gpu_framebuffer *vgfb; |
| + struct virtio_gpu_plane_state *vgplane_st; |
| struct virtio_gpu_object *bo; |
| |
| if (!new_state->fb) |
| return 0; |
| |
| vgfb = to_virtio_gpu_framebuffer(new_state->fb); |
| + vgplane_st = to_virtio_gpu_plane_state(new_state); |
| bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]); |
| if (!bo || (plane->type == DRM_PLANE_TYPE_PRIMARY && !bo->guest_blob)) |
| return 0; |
| |
| - if (bo->dumb && (plane->state->fb != new_state->fb)) { |
| - vgfb->fence = virtio_gpu_fence_alloc(vgdev, vgdev->fence_drv.context, |
| + if (bo->dumb) { |
| + vgplane_st->fence = virtio_gpu_fence_alloc(vgdev, |
| + vgdev->fence_drv.context, |
| 0); |
| - if (!vgfb->fence) |
| + if (!vgplane_st->fence) |
| return -ENOMEM; |
| } |
| |
| @@ -270,15 +290,15 @@ static int virtio_gpu_plane_prepare_fb(struct drm_plane *plane, |
| static void virtio_gpu_plane_cleanup_fb(struct drm_plane *plane, |
| struct drm_plane_state *state) |
| { |
| - struct virtio_gpu_framebuffer *vgfb; |
| + struct virtio_gpu_plane_state *vgplane_st; |
| |
| if (!state->fb) |
| return; |
| |
| - vgfb = to_virtio_gpu_framebuffer(state->fb); |
| - if (vgfb->fence) { |
| - dma_fence_put(&vgfb->fence->f); |
| - vgfb->fence = NULL; |
| + vgplane_st = to_virtio_gpu_plane_state(state); |
| + if (vgplane_st->fence) { |
| + dma_fence_put(&vgplane_st->fence->f); |
| + vgplane_st->fence = NULL; |
| } |
| } |
| |
| @@ -291,6 +311,7 @@ static void virtio_gpu_cursor_plane_update(struct drm_plane *plane, |
| struct virtio_gpu_device *vgdev = dev->dev_private; |
| struct virtio_gpu_output *output = NULL; |
| struct virtio_gpu_framebuffer *vgfb; |
| + struct virtio_gpu_plane_state *vgplane_st; |
| struct virtio_gpu_object *bo = NULL; |
| uint32_t handle; |
| |
| @@ -303,6 +324,7 @@ static void virtio_gpu_cursor_plane_update(struct drm_plane *plane, |
| |
| if (plane->state->fb) { |
| vgfb = to_virtio_gpu_framebuffer(plane->state->fb); |
| + vgplane_st = to_virtio_gpu_plane_state(plane->state); |
| bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]); |
| handle = bo->hw_res_handle; |
| } else { |
| @@ -322,11 +344,9 @@ static void virtio_gpu_cursor_plane_update(struct drm_plane *plane, |
| (vgdev, 0, |
| plane->state->crtc_w, |
| plane->state->crtc_h, |
| - 0, 0, objs, vgfb->fence); |
| + 0, 0, objs, vgplane_st->fence); |
| virtio_gpu_notify(vgdev); |
| - dma_fence_wait(&vgfb->fence->f, true); |
| - dma_fence_put(&vgfb->fence->f); |
| - vgfb->fence = NULL; |
| + dma_fence_wait(&vgplane_st->fence->f, true); |
| } |
| |
| if (plane->state->fb != old_state->fb) { |
| -- |
| 2.39.5 |
| |