aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h5
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c103
-rw-r--r--drivers/gpu/drm/i915/i915_reset.c8
-rw-r--r--drivers/gpu/drm/i915/i915_timeline.c38
-rw-r--r--drivers/gpu/drm/i915/i915_timeline.h3
-rw-r--r--drivers/gpu/drm/i915/selftests/mock_gem_device.c7
-rw-r--r--drivers/gpu/drm/i915/selftests/mock_timeline.c3
7 files changed, 109 insertions, 58 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 0133d1da3d3c..8a181b455197 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1975,7 +1975,10 @@ struct drm_i915_private {
1975 void (*resume)(struct drm_i915_private *); 1975 void (*resume)(struct drm_i915_private *);
1976 void (*cleanup_engine)(struct intel_engine_cs *engine); 1976 void (*cleanup_engine)(struct intel_engine_cs *engine);
1977 1977
1978 struct list_head timelines; 1978 struct i915_gt_timelines {
1979 struct mutex mutex; /* protects list, tainted by GPU */
1980 struct list_head list;
1981 } timelines;
1979 1982
1980 struct list_head active_rings; 1983 struct list_head active_rings;
1981 struct list_head closed_vma; 1984 struct list_head closed_vma;
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 15acd052da46..761714448ff3 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -3222,33 +3222,6 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
3222 return ret; 3222 return ret;
3223} 3223}
3224 3224
3225static long wait_for_timeline(struct i915_timeline *tl,
3226 unsigned int flags, long timeout)
3227{
3228 struct i915_request *rq;
3229
3230 rq = i915_gem_active_get_unlocked(&tl->last_request);
3231 if (!rq)
3232 return timeout;
3233
3234 /*
3235 * "Race-to-idle".
3236 *
3237 * Switching to the kernel context is often used a synchronous
3238 * step prior to idling, e.g. in suspend for flushing all
3239 * current operations to memory before sleeping. These we
3240 * want to complete as quickly as possible to avoid prolonged
3241 * stalls, so allow the gpu to boost to maximum clocks.
3242 */
3243 if (flags & I915_WAIT_FOR_IDLE_BOOST)
3244 gen6_rps_boost(rq, NULL);
3245
3246 timeout = i915_request_wait(rq, flags, timeout);
3247 i915_request_put(rq);
3248
3249 return timeout;
3250}
3251
3252static int wait_for_engines(struct drm_i915_private *i915) 3225static int wait_for_engines(struct drm_i915_private *i915)
3253{ 3226{
3254 if (wait_for(intel_engines_are_idle(i915), I915_IDLE_ENGINES_TIMEOUT)) { 3227 if (wait_for(intel_engines_are_idle(i915), I915_IDLE_ENGINES_TIMEOUT)) {
@@ -3262,6 +3235,52 @@ static int wait_for_engines(struct drm_i915_private *i915)
3262 return 0; 3235 return 0;
3263} 3236}
3264 3237
3238static long
3239wait_for_timelines(struct drm_i915_private *i915,
3240 unsigned int flags, long timeout)
3241{
3242 struct i915_gt_timelines *gt = &i915->gt.timelines;
3243 struct i915_timeline *tl;
3244
3245 if (!READ_ONCE(i915->gt.active_requests))
3246 return timeout;
3247
3248 mutex_lock(&gt->mutex);
3249 list_for_each_entry(tl, &gt->list, link) {
3250 struct i915_request *rq;
3251
3252 rq = i915_gem_active_get_unlocked(&tl->last_request);
3253 if (!rq)
3254 continue;
3255
3256 mutex_unlock(&gt->mutex);
3257
3258 /*
3259 * "Race-to-idle".
3260 *
3261 * Switching to the kernel context is often used a synchronous
3262 * step prior to idling, e.g. in suspend for flushing all
3263 * current operations to memory before sleeping. These we
3264 * want to complete as quickly as possible to avoid prolonged
3265 * stalls, so allow the gpu to boost to maximum clocks.
3266 */
3267 if (flags & I915_WAIT_FOR_IDLE_BOOST)
3268 gen6_rps_boost(rq, NULL);
3269
3270 timeout = i915_request_wait(rq, flags, timeout);
3271 i915_request_put(rq);
3272 if (timeout < 0)
3273 return timeout;
3274
3275 /* restart after reacquiring the lock */
3276 mutex_lock(&gt->mutex);
3277 tl = list_entry(&gt->list, typeof(*tl), link);
3278 }
3279 mutex_unlock(&gt->mutex);
3280
3281 return timeout;
3282}
3283
3265int i915_gem_wait_for_idle(struct drm_i915_private *i915, 3284int i915_gem_wait_for_idle(struct drm_i915_private *i915,
3266 unsigned int flags, long timeout) 3285 unsigned int flags, long timeout)
3267{ 3286{
@@ -3273,17 +3292,15 @@ int i915_gem_wait_for_idle(struct drm_i915_private *i915,
3273 if (!READ_ONCE(i915->gt.awake)) 3292 if (!READ_ONCE(i915->gt.awake))
3274 return 0; 3293 return 0;
3275 3294
3295 timeout = wait_for_timelines(i915, flags, timeout);
3296 if (timeout < 0)
3297 return timeout;
3298
3276 if (flags & I915_WAIT_LOCKED) { 3299 if (flags & I915_WAIT_LOCKED) {
3277 struct i915_timeline *tl;
3278 int err; 3300 int err;
3279 3301
3280 lockdep_assert_held(&i915->drm.struct_mutex); 3302 lockdep_assert_held(&i915->drm.struct_mutex);
3281 3303
3282 list_for_each_entry(tl, &i915->gt.timelines, link) {
3283 timeout = wait_for_timeline(tl, flags, timeout);
3284 if (timeout < 0)
3285 return timeout;
3286 }
3287 if (GEM_SHOW_DEBUG() && !timeout) { 3304 if (GEM_SHOW_DEBUG() && !timeout) {
3288 /* Presume that timeout was non-zero to begin with! */ 3305 /* Presume that timeout was non-zero to begin with! */
3289 dev_warn(&i915->drm.pdev->dev, 3306 dev_warn(&i915->drm.pdev->dev,
@@ -3297,17 +3314,6 @@ int i915_gem_wait_for_idle(struct drm_i915_private *i915,
3297 3314
3298 i915_retire_requests(i915); 3315 i915_retire_requests(i915);
3299 GEM_BUG_ON(i915->gt.active_requests); 3316 GEM_BUG_ON(i915->gt.active_requests);
3300 } else {
3301 struct intel_engine_cs *engine;
3302 enum intel_engine_id id;
3303
3304 for_each_engine(engine, i915, id) {
3305 struct i915_timeline *tl = &engine->timeline;
3306
3307 timeout = wait_for_timeline(tl, flags, timeout);
3308 if (timeout < 0)
3309 return timeout;
3310 }
3311 } 3317 }
3312 3318
3313 return 0; 3319 return 0;
@@ -5008,6 +5014,8 @@ int i915_gem_init(struct drm_i915_private *dev_priv)
5008 dev_priv->gt.cleanup_engine = intel_engine_cleanup; 5014 dev_priv->gt.cleanup_engine = intel_engine_cleanup;
5009 } 5015 }
5010 5016
5017 i915_timelines_init(dev_priv);
5018
5011 ret = i915_gem_init_userptr(dev_priv); 5019 ret = i915_gem_init_userptr(dev_priv);
5012 if (ret) 5020 if (ret)
5013 return ret; 5021 return ret;
@@ -5130,8 +5138,10 @@ err_unlock:
5130err_uc_misc: 5138err_uc_misc:
5131 intel_uc_fini_misc(dev_priv); 5139 intel_uc_fini_misc(dev_priv);
5132 5140
5133 if (ret != -EIO) 5141 if (ret != -EIO) {
5134 i915_gem_cleanup_userptr(dev_priv); 5142 i915_gem_cleanup_userptr(dev_priv);
5143 i915_timelines_fini(dev_priv);
5144 }
5135 5145
5136 if (ret == -EIO) { 5146 if (ret == -EIO) {
5137 mutex_lock(&dev_priv->drm.struct_mutex); 5147 mutex_lock(&dev_priv->drm.struct_mutex);
@@ -5182,6 +5192,7 @@ void i915_gem_fini(struct drm_i915_private *dev_priv)
5182 5192
5183 intel_uc_fini_misc(dev_priv); 5193 intel_uc_fini_misc(dev_priv);
5184 i915_gem_cleanup_userptr(dev_priv); 5194 i915_gem_cleanup_userptr(dev_priv);
5195 i915_timelines_fini(dev_priv);
5185 5196
5186 i915_gem_drain_freed_objects(dev_priv); 5197 i915_gem_drain_freed_objects(dev_priv);
5187 5198
@@ -5284,7 +5295,6 @@ int i915_gem_init_early(struct drm_i915_private *dev_priv)
5284 if (!dev_priv->priorities) 5295 if (!dev_priv->priorities)
5285 goto err_dependencies; 5296 goto err_dependencies;
5286 5297
5287 INIT_LIST_HEAD(&dev_priv->gt.timelines);
5288 INIT_LIST_HEAD(&dev_priv->gt.active_rings); 5298 INIT_LIST_HEAD(&dev_priv->gt.active_rings);
5289 INIT_LIST_HEAD(&dev_priv->gt.closed_vma); 5299 INIT_LIST_HEAD(&dev_priv->gt.closed_vma);
5290 5300
@@ -5328,7 +5338,6 @@ void i915_gem_cleanup_early(struct drm_i915_private *dev_priv)
5328 GEM_BUG_ON(!llist_empty(&dev_priv->mm.free_list)); 5338 GEM_BUG_ON(!llist_empty(&dev_priv->mm.free_list));
5329 GEM_BUG_ON(atomic_read(&dev_priv->mm.free_count)); 5339 GEM_BUG_ON(atomic_read(&dev_priv->mm.free_count));
5330 WARN_ON(dev_priv->mm.object_count); 5340 WARN_ON(dev_priv->mm.object_count);
5331 WARN_ON(!list_empty(&dev_priv->gt.timelines));
5332 5341
5333 kmem_cache_destroy(dev_priv->priorities); 5342 kmem_cache_destroy(dev_priv->priorities);
5334 kmem_cache_destroy(dev_priv->dependencies); 5343 kmem_cache_destroy(dev_priv->dependencies);
diff --git a/drivers/gpu/drm/i915/i915_reset.c b/drivers/gpu/drm/i915/i915_reset.c
index 99bd3bc336b3..d2dca85a543d 100644
--- a/drivers/gpu/drm/i915/i915_reset.c
+++ b/drivers/gpu/drm/i915/i915_reset.c
@@ -854,7 +854,8 @@ bool i915_gem_unset_wedged(struct drm_i915_private *i915)
854 * 854 *
855 * No more can be submitted until we reset the wedged bit. 855 * No more can be submitted until we reset the wedged bit.
856 */ 856 */
857 list_for_each_entry(tl, &i915->gt.timelines, link) { 857 mutex_lock(&i915->gt.timelines.mutex);
858 list_for_each_entry(tl, &i915->gt.timelines.list, link) {
858 struct i915_request *rq; 859 struct i915_request *rq;
859 long timeout; 860 long timeout;
860 861
@@ -876,9 +877,12 @@ bool i915_gem_unset_wedged(struct drm_i915_private *i915)
876 timeout = dma_fence_default_wait(&rq->fence, true, 877 timeout = dma_fence_default_wait(&rq->fence, true,
877 MAX_SCHEDULE_TIMEOUT); 878 MAX_SCHEDULE_TIMEOUT);
878 i915_request_put(rq); 879 i915_request_put(rq);
879 if (timeout < 0) 880 if (timeout < 0) {
881 mutex_unlock(&i915->gt.timelines.mutex);
880 goto unlock; 882 goto unlock;
883 }
881 } 884 }
885 mutex_unlock(&i915->gt.timelines.mutex);
882 886
883 intel_engines_sanitize(i915, false); 887 intel_engines_sanitize(i915, false);
884 888
diff --git a/drivers/gpu/drm/i915/i915_timeline.c b/drivers/gpu/drm/i915/i915_timeline.c
index 4667cc08c416..84550f17d3df 100644
--- a/drivers/gpu/drm/i915/i915_timeline.c
+++ b/drivers/gpu/drm/i915/i915_timeline.c
@@ -13,7 +13,7 @@ void i915_timeline_init(struct drm_i915_private *i915,
13 struct i915_timeline *timeline, 13 struct i915_timeline *timeline,
14 const char *name) 14 const char *name)
15{ 15{
16 lockdep_assert_held(&i915->drm.struct_mutex); 16 struct i915_gt_timelines *gt = &i915->gt.timelines;
17 17
18 /* 18 /*
19 * Ideally we want a set of engines on a single leaf as we expect 19 * Ideally we want a set of engines on a single leaf as we expect
@@ -23,9 +23,12 @@ void i915_timeline_init(struct drm_i915_private *i915,
23 */ 23 */
24 BUILD_BUG_ON(KSYNCMAP < I915_NUM_ENGINES); 24 BUILD_BUG_ON(KSYNCMAP < I915_NUM_ENGINES);
25 25
26 timeline->i915 = i915;
26 timeline->name = name; 27 timeline->name = name;
27 28
28 list_add(&timeline->link, &i915->gt.timelines); 29 mutex_lock(&gt->mutex);
30 list_add(&timeline->link, &gt->list);
31 mutex_unlock(&gt->mutex);
29 32
30 /* Called during early_init before we know how many engines there are */ 33 /* Called during early_init before we know how many engines there are */
31 34
@@ -39,6 +42,17 @@ void i915_timeline_init(struct drm_i915_private *i915,
39 i915_syncmap_init(&timeline->sync); 42 i915_syncmap_init(&timeline->sync);
40} 43}
41 44
45void i915_timelines_init(struct drm_i915_private *i915)
46{
47 struct i915_gt_timelines *gt = &i915->gt.timelines;
48
49 mutex_init(&gt->mutex);
50 INIT_LIST_HEAD(&gt->list);
51
52 /* via i915_gem_wait_for_idle() */
53 i915_gem_shrinker_taints_mutex(i915, &gt->mutex);
54}
55
42/** 56/**
43 * i915_timelines_park - called when the driver idles 57 * i915_timelines_park - called when the driver idles
44 * @i915: the drm_i915_private device 58 * @i915: the drm_i915_private device
@@ -51,11 +65,11 @@ void i915_timeline_init(struct drm_i915_private *i915,
51 */ 65 */
52void i915_timelines_park(struct drm_i915_private *i915) 66void i915_timelines_park(struct drm_i915_private *i915)
53{ 67{
68 struct i915_gt_timelines *gt = &i915->gt.timelines;
54 struct i915_timeline *timeline; 69 struct i915_timeline *timeline;
55 70
56 lockdep_assert_held(&i915->drm.struct_mutex); 71 mutex_lock(&gt->mutex);
57 72 list_for_each_entry(timeline, &gt->list, link) {
58 list_for_each_entry(timeline, &i915->gt.timelines, link) {
59 /* 73 /*
60 * All known fences are completed so we can scrap 74 * All known fences are completed so we can scrap
61 * the current sync point tracking and start afresh, 75 * the current sync point tracking and start afresh,
@@ -64,15 +78,20 @@ void i915_timelines_park(struct drm_i915_private *i915)
64 */ 78 */
65 i915_syncmap_free(&timeline->sync); 79 i915_syncmap_free(&timeline->sync);
66 } 80 }
81 mutex_unlock(&gt->mutex);
67} 82}
68 83
69void i915_timeline_fini(struct i915_timeline *timeline) 84void i915_timeline_fini(struct i915_timeline *timeline)
70{ 85{
86 struct i915_gt_timelines *gt = &timeline->i915->gt.timelines;
87
71 GEM_BUG_ON(!list_empty(&timeline->requests)); 88 GEM_BUG_ON(!list_empty(&timeline->requests));
72 89
73 i915_syncmap_free(&timeline->sync); 90 i915_syncmap_free(&timeline->sync);
74 91
92 mutex_lock(&gt->mutex);
75 list_del(&timeline->link); 93 list_del(&timeline->link);
94 mutex_unlock(&gt->mutex);
76} 95}
77 96
78struct i915_timeline * 97struct i915_timeline *
@@ -99,6 +118,15 @@ void __i915_timeline_free(struct kref *kref)
99 kfree(timeline); 118 kfree(timeline);
100} 119}
101 120
121void i915_timelines_fini(struct drm_i915_private *i915)
122{
123 struct i915_gt_timelines *gt = &i915->gt.timelines;
124
125 GEM_BUG_ON(!list_empty(&gt->list));
126
127 mutex_destroy(&gt->mutex);
128}
129
102#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) 130#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
103#include "selftests/mock_timeline.c" 131#include "selftests/mock_timeline.c"
104#include "selftests/i915_timeline.c" 132#include "selftests/i915_timeline.c"
diff --git a/drivers/gpu/drm/i915/i915_timeline.h b/drivers/gpu/drm/i915/i915_timeline.h
index 38c1e15e927a..87ad2dd31c20 100644
--- a/drivers/gpu/drm/i915/i915_timeline.h
+++ b/drivers/gpu/drm/i915/i915_timeline.h
@@ -66,6 +66,7 @@ struct i915_timeline {
66 66
67 struct list_head link; 67 struct list_head link;
68 const char *name; 68 const char *name;
69 struct drm_i915_private *i915;
69 70
70 struct kref kref; 71 struct kref kref;
71}; 72};
@@ -134,6 +135,8 @@ static inline bool i915_timeline_sync_is_later(struct i915_timeline *tl,
134 return __i915_timeline_sync_is_later(tl, fence->context, fence->seqno); 135 return __i915_timeline_sync_is_later(tl, fence->context, fence->seqno);
135} 136}
136 137
138void i915_timelines_init(struct drm_i915_private *i915);
137void i915_timelines_park(struct drm_i915_private *i915); 139void i915_timelines_park(struct drm_i915_private *i915);
140void i915_timelines_fini(struct drm_i915_private *i915);
138 141
139#endif 142#endif
diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
index 8ab5a2688a0c..14ae46fda49f 100644
--- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c
+++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
@@ -68,13 +68,14 @@ static void mock_device_release(struct drm_device *dev)
68 i915_gem_contexts_fini(i915); 68 i915_gem_contexts_fini(i915);
69 mutex_unlock(&i915->drm.struct_mutex); 69 mutex_unlock(&i915->drm.struct_mutex);
70 70
71 i915_timelines_fini(i915);
72
71 drain_workqueue(i915->wq); 73 drain_workqueue(i915->wq);
72 i915_gem_drain_freed_objects(i915); 74 i915_gem_drain_freed_objects(i915);
73 75
74 mutex_lock(&i915->drm.struct_mutex); 76 mutex_lock(&i915->drm.struct_mutex);
75 mock_fini_ggtt(&i915->ggtt); 77 mock_fini_ggtt(&i915->ggtt);
76 mutex_unlock(&i915->drm.struct_mutex); 78 mutex_unlock(&i915->drm.struct_mutex);
77 WARN_ON(!list_empty(&i915->gt.timelines));
78 79
79 destroy_workqueue(i915->wq); 80 destroy_workqueue(i915->wq);
80 81
@@ -226,7 +227,8 @@ struct drm_i915_private *mock_gem_device(void)
226 if (!i915->priorities) 227 if (!i915->priorities)
227 goto err_dependencies; 228 goto err_dependencies;
228 229
229 INIT_LIST_HEAD(&i915->gt.timelines); 230 i915_timelines_init(i915);
231
230 INIT_LIST_HEAD(&i915->gt.active_rings); 232 INIT_LIST_HEAD(&i915->gt.active_rings);
231 INIT_LIST_HEAD(&i915->gt.closed_vma); 233 INIT_LIST_HEAD(&i915->gt.closed_vma);
232 234
@@ -253,6 +255,7 @@ err_context:
253 i915_gem_contexts_fini(i915); 255 i915_gem_contexts_fini(i915);
254err_unlock: 256err_unlock:
255 mutex_unlock(&i915->drm.struct_mutex); 257 mutex_unlock(&i915->drm.struct_mutex);
258 i915_timelines_fini(i915);
256 kmem_cache_destroy(i915->priorities); 259 kmem_cache_destroy(i915->priorities);
257err_dependencies: 260err_dependencies:
258 kmem_cache_destroy(i915->dependencies); 261 kmem_cache_destroy(i915->dependencies);
diff --git a/drivers/gpu/drm/i915/selftests/mock_timeline.c b/drivers/gpu/drm/i915/selftests/mock_timeline.c
index dcf3b16f5a07..cf39ccd9fc05 100644
--- a/drivers/gpu/drm/i915/selftests/mock_timeline.c
+++ b/drivers/gpu/drm/i915/selftests/mock_timeline.c
@@ -10,6 +10,7 @@
10 10
11void mock_timeline_init(struct i915_timeline *timeline, u64 context) 11void mock_timeline_init(struct i915_timeline *timeline, u64 context)
12{ 12{
13 timeline->i915 = NULL;
13 timeline->fence_context = context; 14 timeline->fence_context = context;
14 15
15 spin_lock_init(&timeline->lock); 16 spin_lock_init(&timeline->lock);
@@ -24,5 +25,5 @@ void mock_timeline_init(struct i915_timeline *timeline, u64 context)
24 25
25void mock_timeline_fini(struct i915_timeline *timeline) 26void mock_timeline_fini(struct i915_timeline *timeline)
26{ 27{
27 i915_timeline_fini(timeline); 28 i915_syncmap_free(&timeline->sync);
28} 29}