From: Rob Clark <robdcl...@chromium.org>

This will allow us to more easily switch scheduling rules based on what
userspace wants.

Signed-off-by: Rob Clark <robdcl...@chromium.org>
---
 drivers/gpu/drm/drm_atomic_helper.c | 13 ++++++++----
 include/drm/drm_atomic.h            | 31 +++++++++++++++++++++++++++++
 2 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c 
b/drivers/gpu/drm/drm_atomic_helper.c
index 9e1ad493e689..75eeec5e7b10 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1659,11 +1659,11 @@ static void commit_tail(struct drm_atomic_state 
*old_state)
        drm_atomic_state_put(old_state);
 }
 
-static void commit_work(struct work_struct *work)
+static void commit_work(struct kthread_work *work)
 {
        struct drm_atomic_state *state = container_of(work,
                                                      struct drm_atomic_state,
-                                                     commit_work);
+                                                     commit_kwork);
        commit_tail(state);
 }
 
@@ -1797,6 +1797,7 @@ int drm_atomic_helper_commit(struct drm_device *dev,
                             struct drm_atomic_state *state,
                             bool nonblock)
 {
+       struct kthread_worker *worker = NULL;
        int ret;
 
        if (state->async_update) {
@@ -1814,7 +1815,7 @@ int drm_atomic_helper_commit(struct drm_device *dev,
        if (ret)
                return ret;
 
-       INIT_WORK(&state->commit_work, commit_work);
+       kthread_init_work(&state->commit_kwork, commit_work);
 
        ret = drm_atomic_helper_prepare_planes(dev, state);
        if (ret)
@@ -1857,8 +1858,12 @@ int drm_atomic_helper_commit(struct drm_device *dev,
         */
 
        drm_atomic_state_get(state);
+
        if (nonblock)
-               queue_work(system_unbound_wq, &state->commit_work);
+               worker = drm_atomic_pick_worker(state);
+
+       if (worker)
+               kthread_queue_work(worker, &state->commit_kwork);
        else
                commit_tail(state);
 
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index d07c851d255b..8d0ee19953df 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -373,8 +373,18 @@ struct drm_atomic_state {
         *
         * Work item which can be used by the driver or helpers to execute the
         * commit without blocking.
+        *
+        * This is deprecated, use commit_kwork.
         */
        struct work_struct commit_work;
+
+       /**
+        * @commit_kwork:
+        *
+        * Work item which can be used by the driver or helpers to execute the
+        * commit without blocking.
+        */
+       struct kthread_work commit_kwork;
 };
 
 void __drm_crtc_commit_free(struct kref *kref);
@@ -954,6 +964,27 @@ void drm_state_dump(struct drm_device *dev, struct 
drm_printer *p);
                      (new_obj_state) = (__state)->private_objs[__i].new_state, 
1); \
             (__i)++)
 
+/**
+ * drm_atomic_pick_worker - helper to get kworker to use for nonblocking commit
+ * @state: the &drm_atomic_state for the commit
+ *
+ * Pick an appropriate worker for a given atomic update.  The first CRTC
+ * invovled in the atomic update is used to pick the worker, to prevent
+ * serializing multiple pageflips / atomic-updates on indenpendent CRTCs.
+ */
+static inline struct kthread_worker *
+drm_atomic_pick_worker(const struct drm_atomic_state *state)
+{
+       struct drm_crtc_state *crtc_state;
+       struct drm_crtc *crtc;
+       unsigned i;
+
+       for_each_new_crtc_in_state(state, crtc, crtc_state, i)
+               return crtc->worker;
+
+       return NULL;
+}
+
 /**
  * drm_atomic_crtc_needs_modeset - compute combined modeset need
  * @state: &drm_crtc_state for the CRTC
-- 
2.26.2

Reply via email to