LCOV - code coverage report
Current view: top level - drivers/gpu/drm/i915/gt - intel_engine_heartbeat.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 119 0.0 %
Date: 2022-03-28 16:04:14 Functions: 0 8 0.0 %
Branches: 0 68 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * SPDX-License-Identifier: MIT
       3                 :            :  *
       4                 :            :  * Copyright © 2019 Intel Corporation
       5                 :            :  */
       6                 :            : 
       7                 :            : #include "i915_request.h"
       8                 :            : 
       9                 :            : #include "intel_context.h"
      10                 :            : #include "intel_engine_heartbeat.h"
      11                 :            : #include "intel_engine_pm.h"
      12                 :            : #include "intel_engine.h"
      13                 :            : #include "intel_gt.h"
      14                 :            : #include "intel_reset.h"
      15                 :            : 
      16                 :            : /*
      17                 :            :  * While the engine is active, we send a periodic pulse along the engine
      18                 :            :  * to check on its health and to flush any idle-barriers. If that request
      19                 :            :  * is stuck, and we fail to preempt it, we declare the engine hung and
      20                 :            :  * issue a reset -- in the hope that restores progress.
      21                 :            :  */
      22                 :            : 
      23                 :          0 : static bool next_heartbeat(struct intel_engine_cs *engine)
      24                 :            : {
      25                 :          0 :         long delay;
      26                 :            : 
      27         [ #  # ]:          0 :         delay = READ_ONCE(engine->props.heartbeat_interval_ms);
      28         [ #  # ]:          0 :         if (!delay)
      29                 :            :                 return false;
      30                 :            : 
      31         [ #  # ]:          0 :         delay = msecs_to_jiffies_timeout(delay);
      32         [ #  # ]:          0 :         if (delay >= HZ)
      33                 :          0 :                 delay = round_jiffies_up_relative(delay);
      34                 :          0 :         schedule_delayed_work(&engine->heartbeat.work, delay);
      35                 :            : 
      36                 :          0 :         return true;
      37                 :            : }
      38                 :            : 
      39                 :          0 : static void idle_pulse(struct intel_engine_cs *engine, struct i915_request *rq)
      40                 :            : {
      41                 :          0 :         engine->wakeref_serial = READ_ONCE(engine->serial) + 1;
      42                 :          0 :         i915_request_add_active_barriers(rq);
      43                 :            : }
      44                 :            : 
      45                 :            : static void show_heartbeat(const struct i915_request *rq,
      46                 :            :                            struct intel_engine_cs *engine)
      47                 :            : {
      48                 :            :         struct drm_printer p = drm_debug_printer("heartbeat");
      49                 :            : 
      50                 :            :         intel_engine_dump(engine, &p,
      51                 :            :                           "%s heartbeat {prio:%d} not ticking\n",
      52                 :            :                           engine->name,
      53                 :            :                           rq->sched.attr.priority);
      54                 :            : }
      55                 :            : 
      56                 :          0 : static void heartbeat(struct work_struct *wrk)
      57                 :            : {
      58                 :          0 :         struct i915_sched_attr attr = {
      59                 :            :                 .priority = I915_USER_PRIORITY(I915_PRIORITY_MIN),
      60                 :            :         };
      61                 :          0 :         struct intel_engine_cs *engine =
      62                 :          0 :                 container_of(wrk, typeof(*engine), heartbeat.work.work);
      63                 :          0 :         struct intel_context *ce = engine->kernel_context;
      64                 :          0 :         struct i915_request *rq;
      65                 :            : 
      66                 :          0 :         rq = engine->heartbeat.systole;
      67   [ #  #  #  # ]:          0 :         if (rq && i915_request_completed(rq)) {
      68                 :          0 :                 i915_request_put(rq);
      69                 :          0 :                 engine->heartbeat.systole = NULL;
      70                 :            :         }
      71                 :            : 
      72         [ #  # ]:          0 :         if (!intel_engine_pm_get_if_awake(engine))
      73                 :          0 :                 return;
      74                 :            : 
      75         [ #  # ]:          0 :         if (intel_gt_is_wedged(engine->gt))
      76                 :          0 :                 goto out;
      77                 :            : 
      78         [ #  # ]:          0 :         if (engine->heartbeat.systole) {
      79         [ #  # ]:          0 :                 if (engine->schedule &&
      80         [ #  # ]:          0 :                     rq->sched.attr.priority < I915_PRIORITY_BARRIER) {
      81                 :            :                         /*
      82                 :            :                          * Gradually raise the priority of the heartbeat to
      83                 :            :                          * give high priority work [which presumably desires
      84                 :            :                          * low latency and no jitter] the chance to naturally
      85                 :            :                          * complete before being preempted.
      86                 :            :                          */
      87                 :          0 :                         attr.priority = I915_PRIORITY_MASK;
      88         [ #  # ]:          0 :                         if (rq->sched.attr.priority >= attr.priority)
      89                 :          0 :                                 attr.priority |= I915_USER_PRIORITY(I915_PRIORITY_HEARTBEAT);
      90         [ #  # ]:          0 :                         if (rq->sched.attr.priority >= attr.priority)
      91                 :          0 :                                 attr.priority = I915_PRIORITY_BARRIER;
      92                 :            : 
      93                 :          0 :                         local_bh_disable();
      94                 :          0 :                         engine->schedule(rq, &attr);
      95                 :          0 :                         local_bh_enable();
      96                 :            :                 } else {
      97                 :          0 :                         if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM))
      98                 :            :                                 show_heartbeat(rq, engine);
      99                 :            : 
     100                 :          0 :                         intel_gt_handle_error(engine->gt, engine->mask,
     101                 :            :                                               I915_ERROR_CAPTURE,
     102                 :            :                                               "stopped heartbeat on %s",
     103                 :          0 :                                               engine->name);
     104                 :            :                 }
     105                 :          0 :                 goto out;
     106                 :            :         }
     107                 :            : 
     108         [ #  # ]:          0 :         if (engine->wakeref_serial == engine->serial)
     109                 :          0 :                 goto out;
     110                 :            : 
     111                 :          0 :         mutex_lock(&ce->timeline->mutex);
     112                 :            : 
     113         [ #  # ]:          0 :         intel_context_enter(ce);
     114                 :          0 :         rq = __i915_request_create(ce, GFP_NOWAIT | __GFP_NOWARN);
     115         [ #  # ]:          0 :         intel_context_exit(ce);
     116         [ #  # ]:          0 :         if (IS_ERR(rq))
     117                 :          0 :                 goto unlock;
     118                 :            : 
     119                 :          0 :         idle_pulse(engine, rq);
     120         [ #  # ]:          0 :         if (i915_modparams.enable_hangcheck)
     121         [ #  # ]:          0 :                 engine->heartbeat.systole = i915_request_get(rq);
     122                 :            : 
     123                 :          0 :         __i915_request_commit(rq);
     124                 :          0 :         __i915_request_queue(rq, &attr);
     125                 :            : 
     126                 :          0 : unlock:
     127                 :          0 :         mutex_unlock(&ce->timeline->mutex);
     128                 :          0 : out:
     129         [ #  # ]:          0 :         if (!next_heartbeat(engine))
     130                 :          0 :                 i915_request_put(fetch_and_zero(&engine->heartbeat.systole));
     131                 :          0 :         intel_engine_pm_put(engine);
     132                 :            : }
     133                 :            : 
     134                 :          0 : void intel_engine_unpark_heartbeat(struct intel_engine_cs *engine)
     135                 :            : {
     136                 :          0 :         if (!IS_ACTIVE(CONFIG_DRM_I915_HEARTBEAT_INTERVAL))
     137                 :            :                 return;
     138                 :            : 
     139                 :          0 :         next_heartbeat(engine);
     140                 :            : }
     141                 :            : 
     142                 :          0 : void intel_engine_park_heartbeat(struct intel_engine_cs *engine)
     143                 :            : {
     144         [ #  # ]:          0 :         if (cancel_delayed_work(&engine->heartbeat.work))
     145                 :          0 :                 i915_request_put(fetch_and_zero(&engine->heartbeat.systole));
     146                 :          0 : }
     147                 :            : 
     148                 :          0 : void intel_engine_init_heartbeat(struct intel_engine_cs *engine)
     149                 :            : {
     150                 :          0 :         INIT_DELAYED_WORK(&engine->heartbeat.work, heartbeat);
     151                 :          0 : }
     152                 :            : 
     153                 :          0 : int intel_engine_set_heartbeat(struct intel_engine_cs *engine,
     154                 :            :                                unsigned long delay)
     155                 :            : {
     156                 :          0 :         int err;
     157                 :            : 
     158                 :            :         /* Send one last pulse before to cleanup persistent hogs */
     159         [ #  # ]:          0 :         if (!delay && IS_ACTIVE(CONFIG_DRM_I915_PREEMPT_TIMEOUT)) {
     160                 :          0 :                 err = intel_engine_pulse(engine);
     161         [ #  # ]:          0 :                 if (err)
     162                 :            :                         return err;
     163                 :            :         }
     164                 :            : 
     165                 :          0 :         WRITE_ONCE(engine->props.heartbeat_interval_ms, delay);
     166                 :            : 
     167         [ #  # ]:          0 :         if (intel_engine_pm_get_if_awake(engine)) {
     168         [ #  # ]:          0 :                 if (delay)
     169                 :          0 :                         intel_engine_unpark_heartbeat(engine);
     170                 :            :                 else
     171                 :          0 :                         intel_engine_park_heartbeat(engine);
     172                 :          0 :                 intel_engine_pm_put(engine);
     173                 :            :         }
     174                 :            : 
     175                 :            :         return 0;
     176                 :            : }
     177                 :            : 
     178                 :          0 : int intel_engine_pulse(struct intel_engine_cs *engine)
     179                 :            : {
     180                 :          0 :         struct i915_sched_attr attr = { .priority = I915_PRIORITY_BARRIER };
     181                 :          0 :         struct intel_context *ce = engine->kernel_context;
     182                 :          0 :         struct i915_request *rq;
     183                 :          0 :         int err = 0;
     184                 :            : 
     185         [ #  # ]:          0 :         if (!intel_engine_has_preemption(engine))
     186                 :            :                 return -ENODEV;
     187                 :            : 
     188         [ #  # ]:          0 :         if (!intel_engine_pm_get_if_awake(engine))
     189                 :            :                 return 0;
     190                 :            : 
     191         [ #  # ]:          0 :         if (mutex_lock_interruptible(&ce->timeline->mutex))
     192                 :          0 :                 goto out_rpm;
     193                 :            : 
     194         [ #  # ]:          0 :         intel_context_enter(ce);
     195                 :          0 :         rq = __i915_request_create(ce, GFP_NOWAIT | __GFP_NOWARN);
     196         [ #  # ]:          0 :         intel_context_exit(ce);
     197         [ #  # ]:          0 :         if (IS_ERR(rq)) {
     198                 :          0 :                 err = PTR_ERR(rq);
     199                 :          0 :                 goto out_unlock;
     200                 :            :         }
     201                 :            : 
     202                 :          0 :         __set_bit(I915_FENCE_FLAG_SENTINEL, &rq->fence.flags);
     203                 :          0 :         idle_pulse(engine, rq);
     204                 :            : 
     205                 :          0 :         __i915_request_commit(rq);
     206                 :          0 :         __i915_request_queue(rq, &attr);
     207                 :            : 
     208                 :          0 : out_unlock:
     209                 :          0 :         mutex_unlock(&ce->timeline->mutex);
     210                 :          0 : out_rpm:
     211                 :          0 :         intel_engine_pm_put(engine);
     212                 :          0 :         return err;
     213                 :            : }
     214                 :            : 
     215                 :          0 : int intel_engine_flush_barriers(struct intel_engine_cs *engine)
     216                 :            : {
     217                 :          0 :         struct i915_request *rq;
     218                 :          0 :         int err = 0;
     219                 :            : 
     220         [ #  # ]:          0 :         if (llist_empty(&engine->barrier_tasks))
     221                 :            :                 return 0;
     222                 :            : 
     223         [ #  # ]:          0 :         if (!intel_engine_pm_get_if_awake(engine))
     224                 :            :                 return 0;
     225                 :            : 
     226                 :          0 :         rq = i915_request_create(engine->kernel_context);
     227         [ #  # ]:          0 :         if (IS_ERR(rq)) {
     228                 :          0 :                 err = PTR_ERR(rq);
     229                 :          0 :                 goto out_rpm;
     230                 :            :         }
     231                 :            : 
     232                 :          0 :         idle_pulse(engine, rq);
     233                 :          0 :         i915_request_add(rq);
     234                 :            : 
     235                 :          0 : out_rpm:
     236                 :          0 :         intel_engine_pm_put(engine);
     237                 :          0 :         return err;
     238                 :            : }
     239                 :            : 
     240                 :            : #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
     241                 :            : #include "selftest_engine_heartbeat.c"
     242                 :            : #endif

Generated by: LCOV version 1.14