LCOV - code coverage report
Current view: top level - drivers/gpu/drm/i915/gt - intel_gt_requests.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 116 0.0 %
Date: 2022-04-01 14:17:54 Functions: 0 14 0.0 %
Branches: 0 52 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * SPDX-License-Identifier: MIT
       3                 :            :  *
       4                 :            :  * Copyright © 2019 Intel Corporation
       5                 :            :  */
       6                 :            : 
       7                 :            : #include <linux/workqueue.h>
       8                 :            : 
       9                 :            : #include "i915_drv.h" /* for_each_engine() */
      10                 :            : #include "i915_request.h"
      11                 :            : #include "intel_engine_heartbeat.h"
      12                 :            : #include "intel_gt.h"
      13                 :            : #include "intel_gt_pm.h"
      14                 :            : #include "intel_gt_requests.h"
      15                 :            : #include "intel_timeline.h"
      16                 :            : 
      17                 :          0 : static bool retire_requests(struct intel_timeline *tl)
      18                 :            : {
      19                 :          0 :         struct i915_request *rq, *rn;
      20                 :            : 
      21         [ #  # ]:          0 :         list_for_each_entry_safe(rq, rn, &tl->requests, link)
      22         [ #  # ]:          0 :                 if (!i915_request_retire(rq))
      23                 :            :                         return false;
      24                 :            : 
      25                 :            :         /* And check nothing new was submitted */
      26                 :          0 :         return !i915_active_fence_isset(&tl->last_request);
      27                 :            : }
      28                 :            : 
      29                 :          0 : static bool flush_submission(struct intel_gt *gt)
      30                 :            : {
      31                 :          0 :         struct intel_engine_cs *engine;
      32                 :          0 :         enum intel_engine_id id;
      33                 :          0 :         bool active = false;
      34                 :            : 
      35         [ #  # ]:          0 :         if (!intel_gt_pm_is_awake(gt))
      36                 :            :                 return false;
      37                 :            : 
      38   [ #  #  #  # ]:          0 :         for_each_engine(engine, gt, id) {
      39                 :          0 :                 intel_engine_flush_submission(engine);
      40                 :          0 :                 active |= flush_work(&engine->retire_work);
      41                 :          0 :                 active |= flush_work(&engine->wakeref.work);
      42                 :            :         }
      43                 :            : 
      44                 :            :         return active;
      45                 :            : }
      46                 :            : 
      47                 :          0 : static void engine_retire(struct work_struct *work)
      48                 :            : {
      49                 :          0 :         struct intel_engine_cs *engine =
      50                 :          0 :                 container_of(work, typeof(*engine), retire_work);
      51                 :          0 :         struct intel_timeline *tl = xchg(&engine->retire, NULL);
      52                 :            : 
      53                 :          0 :         do {
      54                 :          0 :                 struct intel_timeline *next = xchg(&tl->retire, NULL);
      55                 :            : 
      56                 :            :                 /*
      57                 :            :                  * Our goal here is to retire _idle_ timelines as soon as
      58                 :            :                  * possible (as they are idle, we do not expect userspace
      59                 :            :                  * to be cleaning up anytime soon).
      60                 :            :                  *
      61                 :            :                  * If the timeline is currently locked, either it is being
      62                 :            :                  * retired elsewhere or about to be!
      63                 :            :                  */
      64         [ #  # ]:          0 :                 if (mutex_trylock(&tl->mutex)) {
      65                 :          0 :                         retire_requests(tl);
      66                 :          0 :                         mutex_unlock(&tl->mutex);
      67                 :            :                 }
      68                 :          0 :                 intel_timeline_put(tl);
      69                 :            : 
      70                 :          0 :                 GEM_BUG_ON(!next);
      71                 :          0 :                 tl = ptr_mask_bits(next, 1);
      72         [ #  # ]:          0 :         } while (tl);
      73                 :          0 : }
      74                 :            : 
      75                 :          0 : static bool add_retire(struct intel_engine_cs *engine,
      76                 :            :                        struct intel_timeline *tl)
      77                 :            : {
      78                 :            : #define STUB ((struct intel_timeline *)1)
      79                 :          0 :         struct intel_timeline *first;
      80                 :            : 
      81                 :            :         /*
      82                 :            :          * We open-code a llist here to include the additional tag [BIT(0)]
      83                 :            :          * so that we know when the timeline is already on a
      84                 :            :          * retirement queue: either this engine or another.
      85                 :            :          */
      86                 :            : 
      87         [ #  # ]:          0 :         if (cmpxchg(&tl->retire, NULL, STUB)) /* already queued */
      88                 :            :                 return false;
      89                 :            : 
      90                 :          0 :         intel_timeline_get(tl);
      91                 :          0 :         first = READ_ONCE(engine->retire);
      92                 :          0 :         do
      93                 :          0 :                 tl->retire = ptr_pack_bits(first, 1, 1);
      94   [ #  #  #  # ]:          0 :         while (!try_cmpxchg(&engine->retire, &first, tl));
      95                 :            : 
      96                 :          0 :         return !first;
      97                 :            : }
      98                 :            : 
      99                 :          0 : void intel_engine_add_retire(struct intel_engine_cs *engine,
     100                 :            :                              struct intel_timeline *tl)
     101                 :            : {
     102                 :            :         /* We don't deal well with the engine disappearing beneath us */
     103                 :          0 :         GEM_BUG_ON(intel_engine_is_virtual(engine));
     104                 :            : 
     105         [ #  # ]:          0 :         if (add_retire(engine, tl))
     106                 :          0 :                 schedule_work(&engine->retire_work);
     107                 :          0 : }
     108                 :            : 
     109                 :          0 : void intel_engine_init_retire(struct intel_engine_cs *engine)
     110                 :            : {
     111                 :          0 :         INIT_WORK(&engine->retire_work, engine_retire);
     112                 :          0 : }
     113                 :            : 
     114                 :          0 : void intel_engine_fini_retire(struct intel_engine_cs *engine)
     115                 :            : {
     116                 :          0 :         flush_work(&engine->retire_work);
     117                 :          0 :         GEM_BUG_ON(engine->retire);
     118                 :          0 : }
     119                 :            : 
     120                 :          0 : long intel_gt_retire_requests_timeout(struct intel_gt *gt, long timeout)
     121                 :            : {
     122                 :          0 :         struct intel_gt_timelines *timelines = &gt->timelines;
     123                 :          0 :         struct intel_timeline *tl, *tn;
     124                 :          0 :         unsigned long active_count = 0;
     125                 :          0 :         bool interruptible;
     126                 :          0 :         LIST_HEAD(free);
     127                 :            : 
     128                 :          0 :         interruptible = true;
     129         [ #  # ]:          0 :         if (unlikely(timeout < 0))
     130                 :          0 :                 timeout = -timeout, interruptible = false;
     131                 :            : 
     132                 :          0 :         flush_submission(gt); /* kick the ksoftirqd tasklets */
     133                 :          0 :         spin_lock(&timelines->lock);
     134         [ #  # ]:          0 :         list_for_each_entry_safe(tl, tn, &timelines->active_list, link) {
     135         [ #  # ]:          0 :                 if (!mutex_trylock(&tl->mutex)) {
     136                 :          0 :                         active_count++; /* report busy to caller, try again? */
     137                 :          0 :                         continue;
     138                 :            :                 }
     139                 :            : 
     140                 :          0 :                 intel_timeline_get(tl);
     141                 :          0 :                 GEM_BUG_ON(!atomic_read(&tl->active_count));
     142                 :          0 :                 atomic_inc(&tl->active_count); /* pin the list element */
     143                 :          0 :                 spin_unlock(&timelines->lock);
     144                 :            : 
     145         [ #  # ]:          0 :                 if (timeout > 0) {
     146                 :          0 :                         struct dma_fence *fence;
     147                 :            : 
     148                 :          0 :                         fence = i915_active_fence_get(&tl->last_request);
     149         [ #  # ]:          0 :                         if (fence) {
     150                 :          0 :                                 mutex_unlock(&tl->mutex);
     151                 :            : 
     152                 :          0 :                                 timeout = dma_fence_wait_timeout(fence,
     153                 :            :                                                                  interruptible,
     154                 :            :                                                                  timeout);
     155                 :          0 :                                 dma_fence_put(fence);
     156                 :            : 
     157                 :            :                                 /* Retirement is best effort */
     158         [ #  # ]:          0 :                                 if (!mutex_trylock(&tl->mutex)) {
     159                 :          0 :                                         active_count++;
     160                 :          0 :                                         goto out_active;
     161                 :            :                                 }
     162                 :            :                         }
     163                 :            :                 }
     164                 :            : 
     165   [ #  #  #  # ]:          0 :                 if (!retire_requests(tl) || flush_submission(gt))
     166                 :          0 :                         active_count++;
     167                 :          0 :                 mutex_unlock(&tl->mutex);
     168                 :            : 
     169                 :          0 : out_active:     spin_lock(&timelines->lock);
     170                 :            : 
     171                 :            :                 /* Resume list iteration after reacquiring spinlock */
     172                 :          0 :                 list_safe_reset_next(tl, tn, link);
     173         [ #  # ]:          0 :                 if (atomic_dec_and_test(&tl->active_count))
     174                 :          0 :                         list_del(&tl->link);
     175                 :            : 
     176                 :            : 
     177                 :            :                 /* Defer the final release to after the spinlock */
     178         [ #  # ]:          0 :                 if (refcount_dec_and_test(&tl->kref.refcount)) {
     179                 :          0 :                         GEM_BUG_ON(atomic_read(&tl->active_count));
     180                 :          0 :                         list_add(&tl->link, &free);
     181                 :            :                 }
     182                 :            :         }
     183                 :          0 :         spin_unlock(&timelines->lock);
     184                 :            : 
     185         [ #  # ]:          0 :         list_for_each_entry_safe(tl, tn, &free, link)
     186                 :          0 :                 __intel_timeline_free(&tl->kref);
     187                 :            : 
     188         [ #  # ]:          0 :         return active_count ? timeout : 0;
     189                 :            : }
     190                 :            : 
     191                 :          0 : int intel_gt_wait_for_idle(struct intel_gt *gt, long timeout)
     192                 :            : {
     193                 :            :         /* If the device is asleep, we have no requests outstanding */
     194         [ #  # ]:          0 :         if (!intel_gt_pm_is_awake(gt))
     195                 :            :                 return 0;
     196                 :            : 
     197         [ #  # ]:          0 :         while ((timeout = intel_gt_retire_requests_timeout(gt, timeout)) > 0) {
     198                 :          0 :                 cond_resched();
     199         [ #  # ]:          0 :                 if (signal_pending(current))
     200                 :            :                         return -EINTR;
     201                 :            :         }
     202                 :            : 
     203                 :          0 :         return timeout;
     204                 :            : }
     205                 :            : 
     206                 :          0 : static void retire_work_handler(struct work_struct *work)
     207                 :            : {
     208                 :          0 :         struct intel_gt *gt =
     209                 :          0 :                 container_of(work, typeof(*gt), requests.retire_work.work);
     210                 :            : 
     211                 :          0 :         schedule_delayed_work(&gt->requests.retire_work,
     212                 :            :                               round_jiffies_up_relative(HZ));
     213                 :          0 :         intel_gt_retire_requests(gt);
     214                 :          0 : }
     215                 :            : 
     216                 :          0 : void intel_gt_init_requests(struct intel_gt *gt)
     217                 :            : {
     218                 :          0 :         INIT_DELAYED_WORK(&gt->requests.retire_work, retire_work_handler);
     219                 :          0 : }
     220                 :            : 
     221                 :          0 : void intel_gt_park_requests(struct intel_gt *gt)
     222                 :            : {
     223                 :          0 :         cancel_delayed_work(&gt->requests.retire_work);
     224                 :          0 : }
     225                 :            : 
     226                 :          0 : void intel_gt_unpark_requests(struct intel_gt *gt)
     227                 :            : {
     228                 :          0 :         schedule_delayed_work(&gt->requests.retire_work,
     229                 :            :                               round_jiffies_up_relative(HZ));
     230                 :          0 : }
     231                 :            : 
     232                 :          0 : void intel_gt_fini_requests(struct intel_gt *gt)
     233                 :            : {
     234                 :            :         /* Wait until the work is marked as finished before unloading! */
     235                 :          0 :         cancel_delayed_work_sync(&gt->requests.retire_work);
     236                 :          0 : }

Generated by: LCOV version 1.14