mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 10:04:04 +02:00
drm/fb-helper: Synchronize dirty worker with vblank
Before updating the display from the console's shadow buffer, the dirty worker now waits for a vblank. This allows several screen updates to pile up and acts as a rate limiter. If a DRM master is present, it could interfere with the vblank. Don't wait in this case. v4: * share code with WAITFORVSYNC ioctl (Emil) * use lock guard v3: * add back helper->lock * acquire DRM master status while waiting for vblank v2: * don't hold helper->lock while waiting for vblank Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de> Acked-by: Sam Ravnborg <sam@ravnborg.org> Link: https://lore.kernel.org/r/20250829091447.46719-1-tzimmermann@suse.de
This commit is contained in:
parent
cf207ea2c3
commit
d8c4bddcd8
|
|
@ -1293,6 +1293,50 @@ int drm_client_modeset_dpms(struct drm_client_dev *client, int mode)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(drm_client_modeset_dpms);
|
EXPORT_SYMBOL(drm_client_modeset_dpms);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* drm_client_modeset_wait_for_vblank() - Wait for the next VBLANK to occur
|
||||||
|
* @client: DRM client
|
||||||
|
* @crtc_index: The ndex of the CRTC to wait on
|
||||||
|
*
|
||||||
|
* Block the caller until the given CRTC has seen a VBLANK. Do nothing
|
||||||
|
* if the CRTC is disabled. If there's another DRM master present, fail
|
||||||
|
* with -EBUSY.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 on success, or negative error code otherwise.
|
||||||
|
*/
|
||||||
|
int drm_client_modeset_wait_for_vblank(struct drm_client_dev *client, unsigned int crtc_index)
|
||||||
|
{
|
||||||
|
struct drm_device *dev = client->dev;
|
||||||
|
struct drm_crtc *crtc;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Rate-limit update frequency to vblank. If there's a DRM master
|
||||||
|
* present, it could interfere while we're waiting for the vblank
|
||||||
|
* event. Don't wait in this case.
|
||||||
|
*/
|
||||||
|
if (!drm_master_internal_acquire(dev))
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
crtc = client->modesets[crtc_index].crtc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only wait for a vblank event if the CRTC is enabled, otherwise
|
||||||
|
* just don't do anything, not even report an error.
|
||||||
|
*/
|
||||||
|
ret = drm_crtc_vblank_get(crtc);
|
||||||
|
if (!ret) {
|
||||||
|
drm_crtc_wait_one_vblank(crtc);
|
||||||
|
drm_crtc_vblank_put(crtc);
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_master_internal_release(dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(drm_client_modeset_wait_for_vblank);
|
||||||
|
|
||||||
#ifdef CONFIG_DRM_KUNIT_TEST
|
#ifdef CONFIG_DRM_KUNIT_TEST
|
||||||
#include "tests/drm_client_modeset_test.c"
|
#include "tests/drm_client_modeset_test.c"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -368,6 +368,10 @@ static void drm_fb_helper_fb_dirty(struct drm_fb_helper *helper)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
mutex_lock(&helper->lock);
|
||||||
|
drm_client_modeset_wait_for_vblank(&helper->client, 0);
|
||||||
|
mutex_unlock(&helper->lock);
|
||||||
|
|
||||||
if (drm_WARN_ON_ONCE(dev, !helper->funcs->fb_dirty))
|
if (drm_WARN_ON_ONCE(dev, !helper->funcs->fb_dirty))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -1068,15 +1072,9 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
|
||||||
unsigned long arg)
|
unsigned long arg)
|
||||||
{
|
{
|
||||||
struct drm_fb_helper *fb_helper = info->par;
|
struct drm_fb_helper *fb_helper = info->par;
|
||||||
struct drm_device *dev = fb_helper->dev;
|
|
||||||
struct drm_crtc *crtc;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
mutex_lock(&fb_helper->lock);
|
guard(mutex)(&fb_helper->lock);
|
||||||
if (!drm_master_internal_acquire(dev)) {
|
|
||||||
ret = -EBUSY;
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case FBIO_WAITFORVSYNC:
|
case FBIO_WAITFORVSYNC:
|
||||||
|
|
@ -1096,28 +1094,12 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
|
||||||
* make. If we're not smart enough here, one should
|
* make. If we're not smart enough here, one should
|
||||||
* just consider switch the userspace to KMS.
|
* just consider switch the userspace to KMS.
|
||||||
*/
|
*/
|
||||||
crtc = fb_helper->client.modesets[0].crtc;
|
ret = drm_client_modeset_wait_for_vblank(&fb_helper->client, 0);
|
||||||
|
|
||||||
/*
|
|
||||||
* Only wait for a vblank event if the CRTC is
|
|
||||||
* enabled, otherwise just don't do anythintg,
|
|
||||||
* not even report an error.
|
|
||||||
*/
|
|
||||||
ret = drm_crtc_vblank_get(crtc);
|
|
||||||
if (!ret) {
|
|
||||||
drm_crtc_wait_one_vblank(crtc);
|
|
||||||
drm_crtc_vblank_put(crtc);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -ENOTTY;
|
ret = -ENOTTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
drm_master_internal_release(dev);
|
|
||||||
unlock:
|
|
||||||
mutex_unlock(&fb_helper->lock);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(drm_fb_helper_ioctl);
|
EXPORT_SYMBOL(drm_fb_helper_ioctl);
|
||||||
|
|
|
||||||
|
|
@ -220,6 +220,7 @@ int drm_client_modeset_check(struct drm_client_dev *client);
|
||||||
int drm_client_modeset_commit_locked(struct drm_client_dev *client);
|
int drm_client_modeset_commit_locked(struct drm_client_dev *client);
|
||||||
int drm_client_modeset_commit(struct drm_client_dev *client);
|
int drm_client_modeset_commit(struct drm_client_dev *client);
|
||||||
int drm_client_modeset_dpms(struct drm_client_dev *client, int mode);
|
int drm_client_modeset_dpms(struct drm_client_dev *client, int mode);
|
||||||
|
int drm_client_modeset_wait_for_vblank(struct drm_client_dev *client, unsigned int crtc_index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* drm_client_for_each_modeset() - Iterate over client modesets
|
* drm_client_for_each_modeset() - Iterate over client modesets
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user