diff mbox series

drm/i915: Don't disable interrupts independently of the lock

Message ID 20191010160640.6472-1-bigeasy@linutronix.de (mailing list archive)
State New, archived
Headers show
Series drm/i915: Don't disable interrupts independently of the lock | expand

Commit Message

Sebastian Andrzej Siewior Oct. 10, 2019, 4:06 p.m. UTC
The locks (active.lock and rq->lock) need to be taken with disabled
interrupts. This is done in i915_request_retire() by disabling the
interrupts independently of the locks itself.
While local_irq_disable()+spin_lock() equals spin_lock_irq() on vanilla
it does not on PREEMPT_RT. Also, it is not obvious if there is a special reason
to why the interrupts are disabled independently of the lock.

Enable/disable interrupts as part of the locking instruction.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
 drivers/gpu/drm/i915/i915_request.c |    8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

Comments

Chris Wilson Oct. 10, 2019, 6:11 p.m. UTC | #1
Quoting Sebastian Andrzej Siewior (2019-10-10 17:06:40)
> The locks (active.lock and rq->lock) need to be taken with disabled
> interrupts. This is done in i915_request_retire() by disabling the
> interrupts independently of the locks itself.
> While local_irq_disable()+spin_lock() equals spin_lock_irq() on vanilla
> it does not on PREEMPT_RT. Also, it is not obvious if there is a special reason
> to why the interrupts are disabled independently of the lock.
> 
> Enable/disable interrupts as part of the locking instruction.
> 
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> ---
>  drivers/gpu/drm/i915/i915_request.c |    8 ++------
>  1 file changed, 2 insertions(+), 6 deletions(-)
> 
> --- a/drivers/gpu/drm/i915/i915_request.c
> +++ b/drivers/gpu/drm/i915/i915_request.c
> @@ -251,15 +251,13 @@ static bool i915_request_retire(struct i
>                 active->retire(active, rq);
>         }
>  
> -       local_irq_disable();
> -
>         /*
>          * We only loosely track inflight requests across preemption,
>          * and so we may find ourselves attempting to retire a _completed_
>          * request that we have removed from the HW and put back on a run
>          * queue.
>          */
> -       spin_lock(&rq->engine->active.lock);
> +       spin_lock_irq(&rq->engine->active.lock);
>         list_del(&rq->sched.link);
>         spin_unlock(&rq->engine->active.lock);
>  
> @@ -278,9 +276,7 @@ static bool i915_request_retire(struct i
>                 __notify_execute_cb(rq);
>         }
>         GEM_BUG_ON(!list_empty(&rq->execute_cb));
> -       spin_unlock(&rq->lock);
> -
> -       local_irq_enable();
> +       spin_unlock_irq(&rq->lock);

Nothing screams about the imbalance? irq off from one lock to the other?
-Chris
Sebastian Andrzej Siewior Oct. 10, 2019, 6:26 p.m. UTC | #2
On 2019-10-10 19:11:27 [+0100], Chris Wilson wrote:
> > --- a/drivers/gpu/drm/i915/i915_request.c
> > +++ b/drivers/gpu/drm/i915/i915_request.c
> > @@ -251,15 +251,13 @@ static bool i915_request_retire(struct i
> >                 active->retire(active, rq);
> >         }
> >  
> > -       local_irq_disable();
> > -
> >         /*
> >          * We only loosely track inflight requests across preemption,
> >          * and so we may find ourselves attempting to retire a _completed_
> >          * request that we have removed from the HW and put back on a run
> >          * queue.
> >          */
> > -       spin_lock(&rq->engine->active.lock);
> > +       spin_lock_irq(&rq->engine->active.lock);
> >         list_del(&rq->sched.link);
> >         spin_unlock(&rq->engine->active.lock);
> >  
> > @@ -278,9 +276,7 @@ static bool i915_request_retire(struct i
> >                 __notify_execute_cb(rq);
> >         }
> >         GEM_BUG_ON(!list_empty(&rq->execute_cb));
> > -       spin_unlock(&rq->lock);
> > -
> > -       local_irq_enable();
> > +       spin_unlock_irq(&rq->lock);
> 
> Nothing screams about the imbalance? irq off from one lock to the other?

There is no imbalance, is there? Interrupts are disabled as part of
acquiring the first lock and enabled again as part of releasing the
second lock.
It may not look beautiful. 

I'm just not sure if this

|         spin_lock_irq(&rq->engine->active.lock);
|         list_del(&rq->sched.link);
|         spin_unlock_irq(&rq->engine->active.lock);
| 
|         spin_lock_irq(&rq->lock);
|         i915_request_mark_complete(rq);
…
|         spin_unlock_irq(&rq->lock);

has been avoided because an interrupt here could change something or if
this is just an optimisation.

> -Chris

Sebastian
Chris Wilson Oct. 10, 2019, 8:30 p.m. UTC | #3
Quoting Sebastian Andrzej Siewior (2019-10-10 19:26:10)
> On 2019-10-10 19:11:27 [+0100], Chris Wilson wrote:
> > > --- a/drivers/gpu/drm/i915/i915_request.c
> > > +++ b/drivers/gpu/drm/i915/i915_request.c
> > > @@ -251,15 +251,13 @@ static bool i915_request_retire(struct i
> > >                 active->retire(active, rq);
> > >         }
> > >  
> > > -       local_irq_disable();
> > > -
> > >         /*
> > >          * We only loosely track inflight requests across preemption,
> > >          * and so we may find ourselves attempting to retire a _completed_
> > >          * request that we have removed from the HW and put back on a run
> > >          * queue.
> > >          */
> > > -       spin_lock(&rq->engine->active.lock);
> > > +       spin_lock_irq(&rq->engine->active.lock);
> > >         list_del(&rq->sched.link);
> > >         spin_unlock(&rq->engine->active.lock);
> > >  
> > > @@ -278,9 +276,7 @@ static bool i915_request_retire(struct i
> > >                 __notify_execute_cb(rq);
> > >         }
> > >         GEM_BUG_ON(!list_empty(&rq->execute_cb));
> > > -       spin_unlock(&rq->lock);
> > > -
> > > -       local_irq_enable();
> > > +       spin_unlock_irq(&rq->lock);
> > 
> > Nothing screams about the imbalance? irq off from one lock to the other?
> 
> There is no imbalance, is there? Interrupts are disabled as part of
> acquiring the first lock and enabled again as part of releasing the
> second lock.
> It may not look beautiful. 

Sure, it's at the same scope, I just expect at some point lockdep to
complain :)
 
> I'm just not sure if this
> 
> |         spin_lock_irq(&rq->engine->active.lock);
> |         list_del(&rq->sched.link);
> |         spin_unlock_irq(&rq->engine->active.lock);
> | 
> |         spin_lock_irq(&rq->lock);
> |         i915_request_mark_complete(rq);
> …
> |         spin_unlock_irq(&rq->lock);
> 
> has been avoided because an interrupt here could change something or if
> this is just an optimisation.

Just avoiding the back-to-back enable/disable.
-Chris
Sebastian Andrzej Siewior Oct. 14, 2019, 4:10 p.m. UTC | #4
On 2019-10-10 21:30:35 [+0100], Chris Wilson wrote:
> > |         spin_lock_irq(&rq->engine->active.lock);
> > |         list_del(&rq->sched.link);
> > |         spin_unlock_irq(&rq->engine->active.lock);
> > | 
> > |         spin_lock_irq(&rq->lock);
> > |         i915_request_mark_complete(rq);
> > …
> > |         spin_unlock_irq(&rq->lock);
> > 
> > has been avoided because an interrupt here could change something or if
> > this is just an optimisation.
> 
> Just avoiding the back-to-back enable/disable.

as I assumed. Is the patch okay?

> -Chris

Sebastian
diff mbox series

Patch

--- a/drivers/gpu/drm/i915/i915_request.c
+++ b/drivers/gpu/drm/i915/i915_request.c
@@ -251,15 +251,13 @@  static bool i915_request_retire(struct i
 		active->retire(active, rq);
 	}
 
-	local_irq_disable();
-
 	/*
 	 * We only loosely track inflight requests across preemption,
 	 * and so we may find ourselves attempting to retire a _completed_
 	 * request that we have removed from the HW and put back on a run
 	 * queue.
 	 */
-	spin_lock(&rq->engine->active.lock);
+	spin_lock_irq(&rq->engine->active.lock);
 	list_del(&rq->sched.link);
 	spin_unlock(&rq->engine->active.lock);
 
@@ -278,9 +276,7 @@  static bool i915_request_retire(struct i
 		__notify_execute_cb(rq);
 	}
 	GEM_BUG_ON(!list_empty(&rq->execute_cb));
-	spin_unlock(&rq->lock);
-
-	local_irq_enable();
+	spin_unlock_irq(&rq->lock);
 
 	remove_from_client(rq);
 	list_del(&rq->link);