OSDN Git Service

Merge tag 'dma-fence-deadline' of https://gitlab.freedesktop.org/drm/msm into drm...
authorDaniel Vetter <daniel.vetter@ffwll.ch>
Wed, 29 Mar 2023 13:45:37 +0000 (15:45 +0200)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Wed, 29 Mar 2023 13:45:38 +0000 (15:45 +0200)
This series adds a deadline hint to fences, so realtime deadlines
such as vblank can be communicated to the fence signaller for power/
frequency management decisions.

This is partially inspired by a trick i915 does, but implemented
via dma-fence for a couple of reasons:

1) To continue to be able to use the atomic helpers
2) To support cases where display and gpu are different drivers

See https://patchwork.freedesktop.org/series/93035/

This does not yet add any UAPI, although this will be needed in
a number of cases:

1) Workloads "ping-ponging" between CPU and GPU, where we don't
   want the GPU freq governor to interpret time stalled waiting
   for GPU as "idle" time
2) Cases where the compositor is waiting for fences to be signaled
   before issuing the atomic ioctl, for example to maintain 60fps
   cursor updates even when the GPU is not able to maintain that
   framerate.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
From: Rob Clark <robdclark@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/CAF6AEGt5nDQpa6J86V1oFKPA30YcJzPhAVpmF7N1K1g2N3c=Zg@mail.gmail.com
1  2 
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/scheduler/sched_main.c
include/drm/gpu_scheduler.h

@@@ -1511,6 -1511,41 +1511,41 @@@ void drm_atomic_helper_commit_modeset_e
  }
  EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_enables);
  
+ /*
+  * For atomic updates which touch just a single CRTC, calculate the time of the
+  * next vblank, and inform all the fences of the deadline.
+  */
+ static void set_fence_deadline(struct drm_device *dev,
+                              struct drm_atomic_state *state)
+ {
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *new_crtc_state;
+       struct drm_plane *plane;
+       struct drm_plane_state *new_plane_state;
+       ktime_t vbltime = 0;
+       int i;
+       for_each_new_crtc_in_state (state, crtc, new_crtc_state, i) {
+               ktime_t v;
+               if (drm_crtc_next_vblank_start(crtc, &v))
+                       continue;
+               if (!vbltime || ktime_before(v, vbltime))
+                       vbltime = v;
+       }
+       /* If no CRTCs updated, then nothing to do: */
+       if (!vbltime)
+               return;
+       for_each_new_plane_in_state (state, plane, new_plane_state, i) {
+               if (!new_plane_state->fence)
+                       continue;
+               dma_fence_set_deadline(new_plane_state->fence, vbltime);
+       }
+ }
  /**
   * drm_atomic_helper_wait_for_fences - wait for fences stashed in plane state
   * @dev: DRM device
@@@ -1540,6 -1575,8 +1575,8 @@@ int drm_atomic_helper_wait_for_fences(s
        struct drm_plane_state *new_plane_state;
        int i, ret;
  
+       set_fence_deadline(dev, state);
        for_each_new_plane_in_state(state, plane, new_plane_state, i) {
                if (!new_plane_state->fence)
                        continue;
@@@ -2702,11 -2739,6 +2739,11 @@@ void drm_atomic_helper_commit_planes(st
                        funcs->atomic_disable(plane, old_state);
                } else if (new_plane_state->crtc || disabling) {
                        funcs->atomic_update(plane, old_state);
 +
 +                      if (!disabling && funcs->atomic_enable) {
 +                              if (drm_atomic_plane_enabling(old_plane_state, new_plane_state))
 +                                      funcs->atomic_enable(plane, old_state);
 +                      }
                }
        }
  
@@@ -2767,7 -2799,6 +2804,7 @@@ drm_atomic_helper_commit_planes_on_crtc
                struct drm_plane_state *new_plane_state =
                        drm_atomic_get_new_plane_state(old_state, plane);
                const struct drm_plane_helper_funcs *plane_funcs;
 +              bool disabling;
  
                plane_funcs = plane->helper_private;
  
                WARN_ON(new_plane_state->crtc &&
                        new_plane_state->crtc != crtc);
  
 -              if (drm_atomic_plane_disabling(old_plane_state, new_plane_state) &&
 -                  plane_funcs->atomic_disable)
 +              disabling = drm_atomic_plane_disabling(old_plane_state, new_plane_state);
 +
 +              if (disabling && plane_funcs->atomic_disable) {
                        plane_funcs->atomic_disable(plane, old_state);
 -              else if (new_plane_state->crtc ||
 -                       drm_atomic_plane_disabling(old_plane_state, new_plane_state))
 +              } else if (new_plane_state->crtc || disabling) {
                        plane_funcs->atomic_update(plane, old_state);
 +
 +                      if (!disabling && plane_funcs->atomic_enable) {
 +                              if (drm_atomic_plane_enabling(old_plane_state, new_plane_state))
 +                                      plane_funcs->atomic_enable(plane, old_state);
 +                      }
 +              }
        }
  
        if (crtc_funcs && crtc_funcs->atomic_flush)
@@@ -53,7 -53,6 +53,7 @@@
  
  #include <drm/drm_print.h>
  #include <drm/drm_gem.h>
 +#include <drm/drm_syncobj.h>
  #include <drm/gpu_scheduler.h>
  #include <drm/spsc_queue.h>
  
@@@ -720,34 -719,6 +720,34 @@@ int drm_sched_job_add_dependency(struc
  EXPORT_SYMBOL(drm_sched_job_add_dependency);
  
  /**
 + * drm_sched_job_add_syncobj_dependency - adds a syncobj's fence as a job dependency
 + * @job: scheduler job to add the dependencies to
 + * @file_private: drm file private pointer
 + * @handle: syncobj handle to lookup
 + * @point: timeline point
 + *
 + * This adds the fence matching the given syncobj to @job.
 + *
 + * Returns:
 + * 0 on success, or an error on failing to expand the array.
 + */
 +int drm_sched_job_add_syncobj_dependency(struct drm_sched_job *job,
 +                                       struct drm_file *file,
 +                                       u32 handle,
 +                                       u32 point)
 +{
 +      struct dma_fence *fence;
 +      int ret;
 +
 +      ret = drm_syncobj_find_fence(file, handle, point, 0, &fence);
 +      if (ret)
 +              return ret;
 +
 +      return drm_sched_job_add_dependency(job, fence);
 +}
 +EXPORT_SYMBOL(drm_sched_job_add_syncobj_dependency);
 +
 +/**
   * drm_sched_job_add_resv_dependencies - add all fences from the resv to the job
   * @job: scheduler job to add the dependencies to
   * @resv: the dma_resv object to get the fences from
@@@ -1048,7 -1019,7 +1048,7 @@@ static int drm_sched_main(void *param
                drm_sched_fence_scheduled(s_fence);
  
                if (!IS_ERR_OR_NULL(fence)) {
-                       s_fence->parent = dma_fence_get(fence);
+                       drm_sched_fence_set_parent(s_fence, fence);
                        /* Drop for original kref_init of the fence */
                        dma_fence_put(fence);
  
   */
  #define DRM_SCHED_FENCE_DONT_PIPELINE DMA_FENCE_FLAG_USER_BITS
  
+ /**
+  * DRM_SCHED_FENCE_FLAG_HAS_DEADLINE_BIT - A fence deadline hint has been set
+  *
+  * Because we could have a deadline hint can be set before the backing hw
+  * fence is created, we need to keep track of whether a deadline has already
+  * been set.
+  */
+ #define DRM_SCHED_FENCE_FLAG_HAS_DEADLINE_BIT (DMA_FENCE_FLAG_USER_BITS + 1)
  enum dma_resv_usage;
  struct dma_resv;
  struct drm_gem_object;
@@@ -48,8 -57,6 +57,8 @@@
  struct drm_gpu_scheduler;
  struct drm_sched_rq;
  
 +struct drm_file;
 +
  /* These are often used as an (initial) index
   * to an array, and as such should start at 0.
   */
@@@ -282,6 -289,12 +291,12 @@@ struct drm_sched_fence 
           */
        struct dma_fence                finished;
  
+       /**
+        * @deadline: deadline set on &drm_sched_fence.finished which
+        * potentially needs to be propagated to &drm_sched_fence.parent
+        */
+       ktime_t                         deadline;
          /**
           * @parent: the fence returned by &drm_sched_backend_ops.run_job
           * when scheduling the job on hardware. We signal the
@@@ -524,10 -537,6 +539,10 @@@ int drm_sched_job_init(struct drm_sched
  void drm_sched_job_arm(struct drm_sched_job *job);
  int drm_sched_job_add_dependency(struct drm_sched_job *job,
                                 struct dma_fence *fence);
 +int drm_sched_job_add_syncobj_dependency(struct drm_sched_job *job,
 +                                       struct drm_file *file,
 +                                       u32 handle,
 +                                       u32 point);
  int drm_sched_job_add_resv_dependencies(struct drm_sched_job *job,
                                        struct dma_resv *resv,
                                        enum dma_resv_usage usage);
@@@ -574,6 -583,8 +589,8 @@@ void drm_sched_entity_set_priority(stru
                                   enum drm_sched_priority priority);
  bool drm_sched_entity_is_ready(struct drm_sched_entity *entity);
  
+ void drm_sched_fence_set_parent(struct drm_sched_fence *s_fence,
+                               struct dma_fence *fence);
  struct drm_sched_fence *drm_sched_fence_alloc(
        struct drm_sched_entity *s_entity, void *owner);
  void drm_sched_fence_init(struct drm_sched_fence *fence,