[PATCH 2/4] drm/kms: Send event when atomic commit HW programming is done

Michel Dänzer michel at daenzer.net
Thu Jul 24 16:40:29 UTC 2025


From: Michel Dänzer <mdaenzer at redhat.com>

Also add DRM_CAP_ATOMIC_HW_DONE_EVENT to let user space know it can
use the DRM_MODE_ATOMIC_HW_DONE_EVENT flag.

Signed-off-by: Michel Dänzer <mdaenzer at redhat.com>
---
 drivers/gpu/drm/drm_atomic.c        |  1 +
 drivers/gpu/drm/drm_atomic_helper.c | 23 ++++++++++++++++++
 drivers/gpu/drm/drm_atomic_uapi.c   | 37 +++++++++++++++++++++++++++--
 drivers/gpu/drm/drm_ioctl.c         |  3 +++
 include/drm/drm_atomic.h            | 22 +++++++++++++++++
 include/uapi/drm/drm_mode.h         |  3 ++-
 6 files changed, 86 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 0138cf0b8b63..159894381a45 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -108,6 +108,7 @@ void drm_atomic_state_default_release(struct drm_atomic_state *state)
 	kfree(state->crtcs);
 	kfree(state->planes);
 	kfree(state->private_objs);
+	kfree(state->hw_done_event);
 }
 EXPORT_SYMBOL(drm_atomic_state_default_release);
 
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index ee64ca1b1bec..e55edc42a317 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -2511,6 +2511,27 @@ void drm_atomic_helper_fake_vblank(struct drm_atomic_state *state)
 }
 EXPORT_SYMBOL(drm_atomic_helper_fake_vblank);
 
+static void send_hw_done_event(struct drm_device *dev,
+			       struct drm_pending_atomic_hw_done_event **e,
+			       ktime_t done)
+{
+	struct timespec64 tv;
+	unsigned long irqflags;
+
+	if (!*e)
+		return;
+
+	tv = ktime_to_timespec64(done);
+	(*e)->event.tv_sec = tv.tv_sec;
+	(*e)->event.tv_usec = tv.tv_nsec / 1000;
+
+	spin_lock_irqsave(&dev->event_lock, irqflags);
+	drm_send_event_timestamp_locked(dev, &(*e)->base, done);
+	spin_unlock_irqrestore(&dev->event_lock, irqflags);
+
+	*e = NULL;
+}
+
 /**
  * drm_atomic_helper_commit_hw_done - setup possible nonblocking commit
  * @state: atomic state object being committed
@@ -2533,6 +2554,8 @@ void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *state)
 	struct drm_crtc_commit *commit;
 	int i;
 
+	send_hw_done_event(state->dev, &state->hw_done_event, ktime_get());
+
 	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
 		commit = new_crtc_state->commit;
 		if (!commit)
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
index c2726af6698e..43c16bfe65a9 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -939,6 +939,21 @@ static struct drm_pending_vblank_event *create_vblank_event(
 	return e;
 }
 
+static struct drm_pending_atomic_hw_done_event *create_hw_done_event(uint64_t user_data)
+{
+	struct drm_pending_atomic_hw_done_event *e = NULL;
+
+	e = kzalloc(sizeof *e, GFP_KERNEL);
+	if (!e)
+		return NULL;
+
+	e->event.base.type = DRM_EVENT_ATOMIC_HW_DONE;
+	e->event.base.length = sizeof(e->event);
+	e->event.user_data = user_data;
+
+	return e;
+}
+
 int drm_atomic_connector_commit_dpms(struct drm_atomic_state *state,
 				     struct drm_connector *connector,
 				     int mode)
@@ -1314,6 +1329,24 @@ static int prepare_signaling(struct drm_device *dev,
 		return -EINVAL;
 	}
 
+	if (arg->flags & DRM_MODE_ATOMIC_HW_DONE_EVENT &&
+	    file_priv) {
+		struct drm_pending_atomic_hw_done_event *e;
+
+		e = create_hw_done_event(arg->user_data);
+		if (!e)
+			return -ENOMEM;
+
+		ret = drm_event_reserve_init(dev, file_priv, &e->base,
+					     &e->event.base);
+		if (ret) {
+			kfree(e);
+			return ret;
+		}
+
+		state->hw_done_event = e;
+	}
+
 	return 0;
 }
 
@@ -1431,9 +1464,9 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
 
 	/* can't test and expect an event at the same time. */
 	if ((arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) &&
-			(arg->flags & DRM_MODE_PAGE_FLIP_EVENT)) {
+	    (arg->flags & (DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_HW_DONE_EVENT))) {
 		drm_dbg_atomic(dev,
-			       "commit failed: page-flip event requested with test-only commit\n");
+			       "commit failed: event requested with test-only commit\n");
 		return -EINVAL;
 	}
 
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index f593dc569d31..3b2221748dca 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -304,6 +304,9 @@ static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_
 		req->value = drm_core_check_feature(dev, DRIVER_ATOMIC) &&
 			     dev->mode_config.async_page_flip;
 		break;
+	case DRM_CAP_ATOMIC_HW_DONE_EVENT:
+		req->value = 1;
+		break;
 	default:
 		return -EINVAL;
 	}
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 38636a593c9d..e34c2b08e759 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -29,8 +29,23 @@
 #define DRM_ATOMIC_H_
 
 #include <drm/drm_crtc.h>
+#include <drm/drm_file.h>
 #include <drm/drm_util.h>
 
+/**
+ * struct drm_pending_atomic_hw_done_event - pending atomic HW done event tracking
+ */
+struct drm_pending_atomic_hw_done_event {
+	/**
+	 * @base: Base structure for tracking pending DRM events.
+	 */
+	struct drm_pending_event base;
+	/**
+	 * @event: Actual event which will be sent to userspace.
+	 */
+	struct drm_event_atomic_hw_done event;
+};
+
 /**
  * struct drm_crtc_commit - track modeset commits on a CRTC
  *
@@ -517,6 +532,13 @@ struct drm_atomic_state {
 	 */
 	struct drm_crtc_commit *fake_commit;
 
+	/**
+	 * @hw_done_event:
+	 *
+	 * Used for sending an event to user space when programming a commit to HW is done.
+	 */
+	struct drm_pending_atomic_hw_done_event *hw_done_event;
+
 	/**
 	 * @commit_work:
 	 *
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index d7921e633f1a..463e32919093 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -1156,7 +1156,8 @@ struct drm_mode_destroy_dumb {
 		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_HW_DONE_EVENT)
 
 struct drm_mode_atomic {
 	__u32 flags;
-- 
2.50.0



More information about the amd-gfx mailing list