Skip to content

Commit 94cfbd0

Browse files
committed
Merge tag 'drm-intel-fixes-2020-12-03' of git://anongit.freedesktop.org/drm/drm-intel into drm-fixes
Fixes for GPU hang, null dereference, suspend-resume, power consumption, and use-after-free. - Program mocs:63 for cache eviction on gen9 (Chris) - Protect context lifetime with RCU (Chris) - Split the breadcrumb spinlock between global and contexts (Chris) - Retain default context state across shrinking (Venkata) - Limit frequency drop to RPe on parking (Chris) - Return earlier from intel_modeset_init() without display (Jani) - Defer initial modeset until after GGTT is initialized (Chris) Signed-off-by: Dave Airlie <airlied@redhat.com> From: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20201203134705.GA1575873@intel.com
2 parents aac0664 + ccc9e67 commit 94cfbd0

9 files changed

Lines changed: 143 additions & 124 deletions

File tree

drivers/gpu/drm/i915/display/intel_display.c

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18021,16 +18021,6 @@ int intel_modeset_init_nogem(struct drm_i915_private *i915)
1802118021
if (!HAS_GMCH(i915))
1802218022
sanitize_watermarks(i915);
1802318023

18024-
/*
18025-
* Force all active planes to recompute their states. So that on
18026-
* mode_setcrtc after probe, all the intel_plane_state variables
18027-
* are already calculated and there is no assert_plane warnings
18028-
* during bootup.
18029-
*/
18030-
ret = intel_initial_commit(dev);
18031-
if (ret)
18032-
drm_dbg_kms(&i915->drm, "Initial commit in probe failed.\n");
18033-
1803418024
return 0;
1803518025
}
1803618026

@@ -18039,11 +18029,21 @@ int intel_modeset_init(struct drm_i915_private *i915)
1803918029
{
1804018030
int ret;
1804118031

18042-
intel_overlay_setup(i915);
18043-
1804418032
if (!HAS_DISPLAY(i915))
1804518033
return 0;
1804618034

18035+
/*
18036+
* Force all active planes to recompute their states. So that on
18037+
* mode_setcrtc after probe, all the intel_plane_state variables
18038+
* are already calculated and there is no assert_plane warnings
18039+
* during bootup.
18040+
*/
18041+
ret = intel_initial_commit(&i915->drm);
18042+
if (ret)
18043+
return ret;
18044+
18045+
intel_overlay_setup(i915);
18046+
1804718047
ret = intel_fbdev_init(&i915->drm);
1804818048
if (ret)
1804918049
return ret;

drivers/gpu/drm/i915/gt/intel_breadcrumbs.c

Lines changed: 74 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -101,18 +101,37 @@ static void __intel_breadcrumbs_disarm_irq(struct intel_breadcrumbs *b)
101101
intel_gt_pm_put_async(b->irq_engine->gt);
102102
}
103103

104+
static void intel_breadcrumbs_disarm_irq(struct intel_breadcrumbs *b)
105+
{
106+
spin_lock(&b->irq_lock);
107+
if (b->irq_armed)
108+
__intel_breadcrumbs_disarm_irq(b);
109+
spin_unlock(&b->irq_lock);
110+
}
111+
104112
static void add_signaling_context(struct intel_breadcrumbs *b,
105113
struct intel_context *ce)
106114
{
107-
intel_context_get(ce);
108-
list_add_tail(&ce->signal_link, &b->signalers);
115+
lockdep_assert_held(&ce->signal_lock);
116+
117+
spin_lock(&b->signalers_lock);
118+
list_add_rcu(&ce->signal_link, &b->signalers);
119+
spin_unlock(&b->signalers_lock);
109120
}
110121

111-
static void remove_signaling_context(struct intel_breadcrumbs *b,
122+
static bool remove_signaling_context(struct intel_breadcrumbs *b,
112123
struct intel_context *ce)
113124
{
114-
list_del(&ce->signal_link);
115-
intel_context_put(ce);
125+
lockdep_assert_held(&ce->signal_lock);
126+
127+
if (!list_empty(&ce->signals))
128+
return false;
129+
130+
spin_lock(&b->signalers_lock);
131+
list_del_rcu(&ce->signal_link);
132+
spin_unlock(&b->signalers_lock);
133+
134+
return true;
116135
}
117136

118137
static inline bool __request_completed(const struct i915_request *rq)
@@ -175,6 +194,8 @@ static void add_retire(struct intel_breadcrumbs *b, struct intel_timeline *tl)
175194

176195
static bool __signal_request(struct i915_request *rq)
177196
{
197+
GEM_BUG_ON(test_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags));
198+
178199
if (!__dma_fence_signal(&rq->fence)) {
179200
i915_request_put(rq);
180201
return false;
@@ -195,15 +216,12 @@ static void signal_irq_work(struct irq_work *work)
195216
struct intel_breadcrumbs *b = container_of(work, typeof(*b), irq_work);
196217
const ktime_t timestamp = ktime_get();
197218
struct llist_node *signal, *sn;
198-
struct intel_context *ce, *cn;
199-
struct list_head *pos, *next;
219+
struct intel_context *ce;
200220

201221
signal = NULL;
202222
if (unlikely(!llist_empty(&b->signaled_requests)))
203223
signal = llist_del_all(&b->signaled_requests);
204224

205-
spin_lock(&b->irq_lock);
206-
207225
/*
208226
* Keep the irq armed until the interrupt after all listeners are gone.
209227
*
@@ -229,47 +247,44 @@ static void signal_irq_work(struct irq_work *work)
229247
* interrupt draw less ire from other users of the system and tools
230248
* like powertop.
231249
*/
232-
if (!signal && b->irq_armed && list_empty(&b->signalers))
233-
__intel_breadcrumbs_disarm_irq(b);
250+
if (!signal && READ_ONCE(b->irq_armed) && list_empty(&b->signalers))
251+
intel_breadcrumbs_disarm_irq(b);
234252

235-
list_for_each_entry_safe(ce, cn, &b->signalers, signal_link) {
236-
GEM_BUG_ON(list_empty(&ce->signals));
253+
rcu_read_lock();
254+
list_for_each_entry_rcu(ce, &b->signalers, signal_link) {
255+
struct i915_request *rq;
237256

238-
list_for_each_safe(pos, next, &ce->signals) {
239-
struct i915_request *rq =
240-
list_entry(pos, typeof(*rq), signal_link);
257+
list_for_each_entry_rcu(rq, &ce->signals, signal_link) {
258+
bool release;
241259

242-
GEM_BUG_ON(!check_signal_order(ce, rq));
243260
if (!__request_completed(rq))
244261
break;
245262

263+
if (!test_and_clear_bit(I915_FENCE_FLAG_SIGNAL,
264+
&rq->fence.flags))
265+
break;
266+
246267
/*
247268
* Queue for execution after dropping the signaling
248269
* spinlock as the callback chain may end up adding
249270
* more signalers to the same context or engine.
250271
*/
251-
clear_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags);
272+
spin_lock(&ce->signal_lock);
273+
list_del_rcu(&rq->signal_link);
274+
release = remove_signaling_context(b, ce);
275+
spin_unlock(&ce->signal_lock);
276+
252277
if (__signal_request(rq))
253278
/* We own signal_node now, xfer to local list */
254279
signal = slist_add(&rq->signal_node, signal);
255-
}
256280

257-
/*
258-
* We process the list deletion in bulk, only using a list_add
259-
* (not list_move) above but keeping the status of
260-
* rq->signal_link known with the I915_FENCE_FLAG_SIGNAL bit.
261-
*/
262-
if (!list_is_first(pos, &ce->signals)) {
263-
/* Advance the list to the first incomplete request */
264-
__list_del_many(&ce->signals, pos);
265-
if (&ce->signals == pos) { /* now empty */
281+
if (release) {
266282
add_retire(b, ce->timeline);
267-
remove_signaling_context(b, ce);
283+
intel_context_put(ce);
268284
}
269285
}
270286
}
271-
272-
spin_unlock(&b->irq_lock);
287+
rcu_read_unlock();
273288

274289
llist_for_each_safe(signal, sn, signal) {
275290
struct i915_request *rq =
@@ -298,14 +313,15 @@ intel_breadcrumbs_create(struct intel_engine_cs *irq_engine)
298313
if (!b)
299314
return NULL;
300315

301-
spin_lock_init(&b->irq_lock);
316+
b->irq_engine = irq_engine;
317+
318+
spin_lock_init(&b->signalers_lock);
302319
INIT_LIST_HEAD(&b->signalers);
303320
init_llist_head(&b->signaled_requests);
304321

322+
spin_lock_init(&b->irq_lock);
305323
init_irq_work(&b->irq_work, signal_irq_work);
306324

307-
b->irq_engine = irq_engine;
308-
309325
return b;
310326
}
311327

@@ -347,9 +363,9 @@ void intel_breadcrumbs_free(struct intel_breadcrumbs *b)
347363
kfree(b);
348364
}
349365

350-
static void insert_breadcrumb(struct i915_request *rq,
351-
struct intel_breadcrumbs *b)
366+
static void insert_breadcrumb(struct i915_request *rq)
352367
{
368+
struct intel_breadcrumbs *b = READ_ONCE(rq->engine)->breadcrumbs;
353369
struct intel_context *ce = rq->context;
354370
struct list_head *pos;
355371

@@ -371,6 +387,7 @@ static void insert_breadcrumb(struct i915_request *rq,
371387
}
372388

373389
if (list_empty(&ce->signals)) {
390+
intel_context_get(ce);
374391
add_signaling_context(b, ce);
375392
pos = &ce->signals;
376393
} else {
@@ -396,8 +413,9 @@ static void insert_breadcrumb(struct i915_request *rq,
396413
break;
397414
}
398415
}
399-
list_add(&rq->signal_link, pos);
416+
list_add_rcu(&rq->signal_link, pos);
400417
GEM_BUG_ON(!check_signal_order(ce, rq));
418+
GEM_BUG_ON(test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &rq->fence.flags));
401419
set_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags);
402420

403421
/*
@@ -410,7 +428,7 @@ static void insert_breadcrumb(struct i915_request *rq,
410428

411429
bool i915_request_enable_breadcrumb(struct i915_request *rq)
412430
{
413-
struct intel_breadcrumbs *b;
431+
struct intel_context *ce = rq->context;
414432

415433
/* Serialises with i915_request_retire() using rq->lock */
416434
if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &rq->fence.flags))
@@ -425,67 +443,30 @@ bool i915_request_enable_breadcrumb(struct i915_request *rq)
425443
if (!test_bit(I915_FENCE_FLAG_ACTIVE, &rq->fence.flags))
426444
return true;
427445

428-
/*
429-
* rq->engine is locked by rq->engine->active.lock. That however
430-
* is not known until after rq->engine has been dereferenced and
431-
* the lock acquired. Hence we acquire the lock and then validate
432-
* that rq->engine still matches the lock we hold for it.
433-
*
434-
* Here, we are using the breadcrumb lock as a proxy for the
435-
* rq->engine->active.lock, and we know that since the breadcrumb
436-
* will be serialised within i915_request_submit/i915_request_unsubmit,
437-
* the engine cannot change while active as long as we hold the
438-
* breadcrumb lock on that engine.
439-
*
440-
* From the dma_fence_enable_signaling() path, we are outside of the
441-
* request submit/unsubmit path, and so we must be more careful to
442-
* acquire the right lock.
443-
*/
444-
b = READ_ONCE(rq->engine)->breadcrumbs;
445-
spin_lock(&b->irq_lock);
446-
while (unlikely(b != READ_ONCE(rq->engine)->breadcrumbs)) {
447-
spin_unlock(&b->irq_lock);
448-
b = READ_ONCE(rq->engine)->breadcrumbs;
449-
spin_lock(&b->irq_lock);
450-
}
451-
452-
/*
453-
* Now that we are finally serialised with request submit/unsubmit,
454-
* [with b->irq_lock] and with i915_request_retire() [via checking
455-
* SIGNALED with rq->lock] confirm the request is indeed active. If
456-
* it is no longer active, the breadcrumb will be attached upon
457-
* i915_request_submit().
458-
*/
446+
spin_lock(&ce->signal_lock);
459447
if (test_bit(I915_FENCE_FLAG_ACTIVE, &rq->fence.flags))
460-
insert_breadcrumb(rq, b);
461-
462-
spin_unlock(&b->irq_lock);
448+
insert_breadcrumb(rq);
449+
spin_unlock(&ce->signal_lock);
463450

464451
return true;
465452
}
466453

467454
void i915_request_cancel_breadcrumb(struct i915_request *rq)
468455
{
469-
struct intel_breadcrumbs *b = rq->engine->breadcrumbs;
456+
struct intel_context *ce = rq->context;
457+
bool release;
470458

471-
/*
472-
* We must wait for b->irq_lock so that we know the interrupt handler
473-
* has released its reference to the intel_context and has completed
474-
* the DMA_FENCE_FLAG_SIGNALED_BIT/I915_FENCE_FLAG_SIGNAL dance (if
475-
* required).
476-
*/
477-
spin_lock(&b->irq_lock);
478-
if (test_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags)) {
479-
struct intel_context *ce = rq->context;
459+
if (!test_and_clear_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags))
460+
return;
480461

481-
list_del(&rq->signal_link);
482-
if (list_empty(&ce->signals))
483-
remove_signaling_context(b, ce);
462+
spin_lock(&ce->signal_lock);
463+
list_del_rcu(&rq->signal_link);
464+
release = remove_signaling_context(rq->engine->breadcrumbs, ce);
465+
spin_unlock(&ce->signal_lock);
466+
if (release)
467+
intel_context_put(ce);
484468

485-
clear_bit(I915_FENCE_FLAG_SIGNAL, &rq->fence.flags);
486-
i915_request_put(rq);
487-
}
488-
spin_unlock(&b->irq_lock);
469+
i915_request_put(rq);
489470
}
490471

491472
static void print_signals(struct intel_breadcrumbs *b, struct drm_printer *p)
@@ -495,18 +476,17 @@ static void print_signals(struct intel_breadcrumbs *b, struct drm_printer *p)
495476

496477
drm_printf(p, "Signals:\n");
497478

498-
spin_lock_irq(&b->irq_lock);
499-
list_for_each_entry(ce, &b->signalers, signal_link) {
500-
list_for_each_entry(rq, &ce->signals, signal_link) {
479+
rcu_read_lock();
480+
list_for_each_entry_rcu(ce, &b->signalers, signal_link) {
481+
list_for_each_entry_rcu(rq, &ce->signals, signal_link)
501482
drm_printf(p, "\t[%llx:%llx%s] @ %dms\n",
502483
rq->fence.context, rq->fence.seqno,
503484
i915_request_completed(rq) ? "!" :
504485
i915_request_started(rq) ? "*" :
505486
"",
506487
jiffies_to_msecs(jiffies - rq->emitted_jiffies));
507-
}
508488
}
509-
spin_unlock_irq(&b->irq_lock);
489+
rcu_read_unlock();
510490
}
511491

512492
void intel_engine_print_breadcrumbs(struct intel_engine_cs *engine,

drivers/gpu/drm/i915/gt/intel_breadcrumbs_types.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,16 @@
2929
* the overhead of waking that client is much preferred.
3030
*/
3131
struct intel_breadcrumbs {
32-
spinlock_t irq_lock; /* protects the lists used in hardirq context */
33-
3432
/* Not all breadcrumbs are attached to physical HW */
3533
struct intel_engine_cs *irq_engine;
3634

35+
spinlock_t signalers_lock; /* protects the list of signalers */
3736
struct list_head signalers;
3837
struct llist_head signaled_requests;
3938

39+
spinlock_t irq_lock; /* protects the interrupt from hardirq context */
4040
struct irq_work irq_work; /* for use from inside irq_lock */
41-
4241
unsigned int irq_enabled;
43-
4442
bool irq_armed;
4543
};
4644

0 commit comments

Comments
 (0)