diff options
Diffstat (limited to 'drivers/gpu/drm/vkms/vkms_crtc.c')
-rw-r--r-- | drivers/gpu/drm/vkms/vkms_crtc.c | 100 |
1 files changed, 78 insertions, 22 deletions
diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c index 4d11292bc6f3..927dafaebc76 100644 --- a/drivers/gpu/drm/vkms/vkms_crtc.c +++ b/drivers/gpu/drm/vkms/vkms_crtc.c @@ -1,15 +1,18 @@ // SPDX-License-Identifier: GPL-2.0+ -#include "vkms_drv.h" +#include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_probe_helper.h> +#include <drm/drm_vblank.h> + +#include "vkms_drv.h" static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer) { struct vkms_output *output = container_of(timer, struct vkms_output, vblank_hrtimer); struct drm_crtc *crtc = &output->crtc; - struct vkms_crtc_state *state = to_vkms_crtc_state(crtc->state); + struct vkms_crtc_state *state; u64 ret_overrun; bool ret; @@ -23,20 +26,26 @@ static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer) if (!ret) DRM_ERROR("vkms failure on handling vblank"); - if (state && output->crc_enabled) { + state = output->composer_state; + if (state && output->composer_enabled) { u64 frame = drm_crtc_accurate_vblank_count(crtc); - /* update frame_start only if a queued vkms_crc_work_handle() + /* update frame_start only if a queued vkms_composer_worker() * has read the data */ - spin_lock(&output->state_lock); - if (!state->frame_start) + spin_lock(&output->composer_lock); + if (!state->crc_pending) state->frame_start = frame; - spin_unlock(&output->state_lock); + else + DRM_DEBUG_DRIVER("crc worker falling behind, frame_start: %llu, frame_end: %llu\n", + state->frame_start, frame); + state->frame_end = frame; + state->crc_pending = true; + spin_unlock(&output->composer_lock); - ret = queue_work(output->crc_workq, &state->crc_work); + ret = queue_work(output->composer_workq, &state->composer_work); if (!ret) - DRM_WARN("failed to queue vkms_crc_work_handle"); + DRM_DEBUG_DRIVER("Composer worker already queued\n"); } spin_unlock(&output->lock); @@ -107,7 +116,7 @@ vkms_atomic_crtc_duplicate_state(struct drm_crtc *crtc) __drm_atomic_helper_crtc_duplicate_state(crtc, &vkms_state->base); - INIT_WORK(&vkms_state->crc_work, vkms_crc_work_handle); + INIT_WORK(&vkms_state->composer_work, vkms_composer_worker); return &vkms_state->base; } @@ -119,10 +128,9 @@ static void vkms_atomic_crtc_destroy_state(struct drm_crtc *crtc, __drm_atomic_helper_crtc_destroy_state(state); - if (vkms_state) { - flush_work(&vkms_state->crc_work); - kfree(vkms_state); - } + WARN_ON(work_pending(&vkms_state->composer_work)); + kfree(vkms_state->active_planes); + kfree(vkms_state); } static void vkms_atomic_crtc_reset(struct drm_crtc *crtc) @@ -135,7 +143,7 @@ static void vkms_atomic_crtc_reset(struct drm_crtc *crtc) __drm_atomic_helper_crtc_reset(crtc, &vkms_state->base); if (vkms_state) - INIT_WORK(&vkms_state->crc_work, vkms_crc_work_handle); + INIT_WORK(&vkms_state->composer_work, vkms_composer_worker); } static const struct drm_crtc_funcs vkms_crtc_funcs = { @@ -152,6 +160,52 @@ static const struct drm_crtc_funcs vkms_crtc_funcs = { .verify_crc_source = vkms_verify_crc_source, }; +static int vkms_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct vkms_crtc_state *vkms_state = to_vkms_crtc_state(state); + struct drm_plane *plane; + struct drm_plane_state *plane_state; + int i = 0, ret; + + if (vkms_state->active_planes) + return 0; + + ret = drm_atomic_add_affected_planes(state->state, crtc); + if (ret < 0) + return ret; + + drm_for_each_plane_mask(plane, crtc->dev, state->plane_mask) { + plane_state = drm_atomic_get_existing_plane_state(state->state, + plane); + WARN_ON(!plane_state); + + if (!plane_state->visible) + continue; + + i++; + } + + vkms_state->active_planes = kcalloc(i, sizeof(plane), GFP_KERNEL); + if (!vkms_state->active_planes) + return -ENOMEM; + vkms_state->num_active_planes = i; + + i = 0; + drm_for_each_plane_mask(plane, crtc->dev, state->plane_mask) { + plane_state = drm_atomic_get_existing_plane_state(state->state, + plane); + + if (!plane_state->visible) + continue; + + vkms_state->active_planes[i++] = + to_vkms_plane_state(plane_state); + } + + return 0; +} + static void vkms_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { @@ -170,7 +224,7 @@ static void vkms_crtc_atomic_begin(struct drm_crtc *crtc, struct vkms_output *vkms_output = drm_crtc_to_vkms_output(crtc); /* This lock is held across the atomic commit to block vblank timer - * from scheduling vkms_crc_work_handle until the crc_data is updated + * from scheduling vkms_composer_worker until the composer is updated */ spin_lock_irq(&vkms_output->lock); } @@ -179,25 +233,27 @@ static void vkms_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { struct vkms_output *vkms_output = drm_crtc_to_vkms_output(crtc); - unsigned long flags; if (crtc->state->event) { - spin_lock_irqsave(&crtc->dev->event_lock, flags); + spin_lock(&crtc->dev->event_lock); if (drm_crtc_vblank_get(crtc) != 0) drm_crtc_send_vblank_event(crtc, crtc->state->event); else drm_crtc_arm_vblank_event(crtc, crtc->state->event); - spin_unlock_irqrestore(&crtc->dev->event_lock, flags); + spin_unlock(&crtc->dev->event_lock); crtc->state->event = NULL; } + vkms_output->composer_state = to_vkms_crtc_state(crtc->state); + spin_unlock_irq(&vkms_output->lock); } static const struct drm_crtc_helper_funcs vkms_crtc_helper_funcs = { + .atomic_check = vkms_crtc_atomic_check, .atomic_begin = vkms_crtc_atomic_begin, .atomic_flush = vkms_crtc_atomic_flush, .atomic_enable = vkms_crtc_atomic_enable, @@ -220,10 +276,10 @@ int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, drm_crtc_helper_add(crtc, &vkms_crtc_helper_funcs); spin_lock_init(&vkms_out->lock); - spin_lock_init(&vkms_out->state_lock); + spin_lock_init(&vkms_out->composer_lock); - vkms_out->crc_workq = alloc_ordered_workqueue("vkms_crc_workq", 0); - if (!vkms_out->crc_workq) + vkms_out->composer_workq = alloc_ordered_workqueue("vkms_composer", 0); + if (!vkms_out->composer_workq) return -ENOMEM; return ret; |