Use a vblank timer to simulate the vblank interrupt. The DRM vblank
helpers provide an implementation on top of Linux' hrtimer. Bochs
enables and disables the timer as part of the CRTC. The atomic_flush
callback sets up the event. Like vblank interrupts, the vblank timer
fires at the rate of the display refresh.

Most userspace limits its page flip rate according to the DRM vblank
event. Bochs' virtual hardware does not provide vblank interrupts, so
DRM sends each event ASAP. With the fast access time of virtual display
memory, the event rate is much higher than the display mode's refresh
rate; creating the next page flip almost immediately. This leads to
excessive CPU overhead from even small display updates, such as moving
the mouse pointer.

This problem affects bochs and all other virtual displays. See [1] for
a discussion in the context of hypervdrm.

Signed-off-by: Thomas Zimmermann <[email protected]>
Link: 
https://lore.kernel.org/dri-devel/sn6pr02mb415702b00d6d52b0ee962c98d4...@sn6pr02mb4157.namprd02.prod.outlook.com/
 # [1]
---
 drivers/gpu/drm/tiny/bochs.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/gpu/drm/tiny/bochs.c b/drivers/gpu/drm/tiny/bochs.c
index d2d5e9f1269f..71e874c19610 100644
--- a/drivers/gpu/drm/tiny/bochs.c
+++ b/drivers/gpu/drm/tiny/bochs.c
@@ -22,6 +22,8 @@
 #include <drm/drm_panic.h>
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_probe_helper.h>
+#include <drm/drm_vblank.h>
+#include <drm/drm_vblank_helper.h>
 
 #include <video/vga.h>
 
@@ -526,6 +528,7 @@ static void bochs_crtc_helper_atomic_enable(struct drm_crtc 
*crtc,
        struct bochs_device *bochs = to_bochs_device(crtc->dev);
 
        bochs_hw_blank(bochs, false);
+       drm_crtc_vblank_on(crtc);
 }
 
 static void bochs_crtc_helper_atomic_disable(struct drm_crtc *crtc,
@@ -533,12 +536,14 @@ static void bochs_crtc_helper_atomic_disable(struct 
drm_crtc *crtc,
 {
        struct bochs_device *bochs = to_bochs_device(crtc->dev);
 
+       drm_crtc_vblank_off(crtc);
        bochs_hw_blank(bochs, true);
 }
 
 static const struct drm_crtc_helper_funcs bochs_crtc_helper_funcs = {
        .mode_set_nofb = bochs_crtc_helper_mode_set_nofb,
        .atomic_check = bochs_crtc_helper_atomic_check,
+       .atomic_flush = drm_crtc_vblank_atomic_flush,
        .atomic_enable = bochs_crtc_helper_atomic_enable,
        .atomic_disable = bochs_crtc_helper_atomic_disable,
 };
@@ -550,6 +555,7 @@ static const struct drm_crtc_funcs bochs_crtc_funcs = {
        .page_flip = drm_atomic_helper_page_flip,
        .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
        .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+       DRM_CRTC_VBLANK_TIMER_FUNCS,
 };
 
 static const struct drm_encoder_funcs bochs_encoder_funcs = {
@@ -670,6 +676,10 @@ static int bochs_kms_init(struct bochs_device *bochs)
        drm_connector_attach_edid_property(connector);
        drm_connector_attach_encoder(connector, encoder);
 
+       ret = drm_vblank_init(dev, 1);
+       if (ret)
+               return ret;
+
        drm_mode_config_reset(dev);
 
        return 0;
-- 
2.51.0

Reply via email to