diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index eb5dcd84fea7aa22d48cc581dc5cfab1644e702c..9b0df08836c3aeb48b31efb15eb1913fc92db08e 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -947,10 +947,18 @@ int drm_atomic_helper_check(struct drm_device *dev, if (ret) return ret; + /* + * If amend was explicitly requested, but it is not possible, + * return error instead of falling back to a normal commit. + */ + if (state->amend_update) + return drm_atomic_helper_amend_check(dev, state); + + /* Legacy mode falls back to a normal commit if amend isn't possible. */ if (state->legacy_cursor_update) state->amend_update = !drm_atomic_helper_amend_check(dev, state); - return ret; + return 0; } EXPORT_SYMBOL(drm_atomic_helper_check); @@ -1574,12 +1582,20 @@ static void commit_work(struct work_struct *work) * The amend feature provides a way to perform 1000 updates to be applied as * soon as possible without waiting for 1000 vblanks. - * Currently, only the legacy cursor update uses amend mode, where historically, + * Legacy cursor update uses amend mode, where historically, * userspace performs several updates before the next vblank and don't want to * see a delay in the cursor's movement. * If amend is not supported, legacy cursor falls back to a normal sync update. * - * To implement the legacy cursor update, drivers should provide + * Amend can also be performed through the atomic API using the flag + * DRM_MODE_ATOMIC_AMEND. The atomic commit will fail if this flag is set but + * the driver doesn't support it. + * Amend can't perform modeset, thus atomic API will fail if + * DRM_MODE_ATOMIC_AMEND is used in conjunction with + * DRM_MODE_ATOMIC_ALLOW_MODESET flag. + * + * To implement the legacy cursor update and amend mode through atomic, drivers + * should provide: * &drm_plane_helper_funcs.atomic_amend_check() and * &drm_plane_helper_funcs.atomic_amend_update() * @@ -1601,16 +1617,21 @@ static void commit_work(struct work_struct *work) * * Notes / highlights: * - * - amend update is performed on legacy cursor updates. + * - amend update is performed on legacy cursor updates, but it will fallback to + * a normal commit if amend is not possible. However, if amend was requested + * through atomic, the ioctl will fail instead of fall back if it can't be + * amended. + * + * - atomic api will reject amend if DRM_MODE_ATOMIC_ALLOW_MODESET flag is used. + * + * - If DRM_MODE_PAGE_FLIP_ASYNC is set, then the DRM_MODE_ATOMIC_AMEND flag + * will be ignored. * * - amend update won't happen if there is an outstanding commit modifying the * same plane. * * - amend update won't happen if atomic_amend_check() returns false. * - * - if atomic_amend_check() fails, it falls back to a normal synchronous - * update. - * * - if userspace wants to ensure an asynchronous page flip, i.e. change hw * state immediately, see DRM_MODE_PAGE_FLIP_ASYNC flag * (asynchronous page flip maintains the amend property by definition). @@ -1673,6 +1694,10 @@ int drm_atomic_helper_amend_check(struct drm_device *dev, if (new_plane_state->fence) return -EINVAL; + /* Only allow amend update for cursor type planes. */ + if (plane->type != DRM_PLANE_TYPE_CURSOR) + return -EINVAL; + /* * Don't do an amend update if there is an outstanding commit modifying * the plane. diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 4eb81f10bc54fcedbbe94420c53572b3269410a5..d1962cdea60292d5298f8779b91e7c81b45d8668 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -28,6 +28,7 @@ #include <drm/drm_atomic_uapi.h> #include <drm/drm_atomic.h> +#include <drm/drm_atomic_uapi.h> #include <drm/drm_print.h> #include <drm/drm_drv.h> #include <drm/drm_writeback.h> @@ -1300,6 +1301,10 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, (arg->flags & DRM_MODE_PAGE_FLIP_EVENT)) return -EINVAL; + if ((arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET) && + (arg->flags & DRM_MODE_ATOMIC_AMEND)) + return -EINVAL; + state = drm_atomic_state_alloc(dev); if (!state) return -ENOMEM; @@ -1307,6 +1312,9 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE); state->acquire_ctx = &ctx; state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET); + /* async takes precedence over amend */ + state->amend_update = arg->flags & DRM_MODE_PAGE_FLIP_ASYNC ? 0 : + !!(arg->flags & DRM_MODE_ATOMIC_AMEND); retry: copied_objs = 0; diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index 88ef2cf04d13935b9163deb85ea949d07f57142f..3831d04f3b38ef63048f41e4dee1280067d8052b 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -743,19 +743,26 @@ struct drm_mode_destroy_dumb { * * DRM_MODE_ATOMIC_ALLOW_MODESET * Indicates whether a full modeset is acceptable or not. + * + * DRM_MODE_ATOMIC_AMEND + * Used to perform an atomic amend. See "DOC: amend mode atomic commit" in + * drm_atomic_helper.c for more details. + * This flag can't be used with DRM_MODE_ATOMIC_ALLOW_MODESET. */ /* */ #define DRM_MODE_ATOMIC_TEST_ONLY 0x0100 #define DRM_MODE_ATOMIC_NONBLOCK 0x0200 #define DRM_MODE_ATOMIC_ALLOW_MODESET 0x0400 +#define DRM_MODE_ATOMIC_AMEND 0x0800 #define DRM_MODE_ATOMIC_FLAGS (\ DRM_MODE_PAGE_FLIP_EVENT |\ DRM_MODE_PAGE_FLIP_ASYNC |\ DRM_MODE_ATOMIC_TEST_ONLY |\ DRM_MODE_ATOMIC_NONBLOCK |\ - DRM_MODE_ATOMIC_ALLOW_MODESET) + DRM_MODE_ATOMIC_ALLOW_MODESET |\ + DRM_MODE_ATOMIC_AMEND) struct drm_mode_atomic { __u32 flags;