[Intel-gfx] [PATCH v2 1/2] drm/i915: signal first fence from irq handler if complete
Tvrtko Ursulin
tvrtko.ursulin at linux.intel.com
Fri Feb 24 10:47:29 UTC 2017
On 24/02/2017 10:19, Chris Wilson wrote:
> On Fri, Feb 24, 2017 at 10:04:23AM +0000, Tvrtko Ursulin wrote:
>>
>> On 23/02/2017 15:42, Chris Wilson wrote:
>>> diff --git a/drivers/gpu/drm/i915/i915_gem_request.h b/drivers/gpu/drm/i915/i915_gem_request.h
>>> index 5f73d8c0a38a..0efee879df23 100644
>>> --- a/drivers/gpu/drm/i915/i915_gem_request.h
>>> +++ b/drivers/gpu/drm/i915/i915_gem_request.h
>>> @@ -32,10 +32,12 @@
>>>
>>> struct drm_file;
>>> struct drm_i915_gem_object;
>>> +struct drm_i915_gem_request;
>>>
>>> struct intel_wait {
>>> struct rb_node node;
>>> struct task_struct *tsk;
>>> + struct drm_i915_gem_request *request;
>>> u32 seqno;
>>
>> Hm, do we now have a situation where both waiters and signallers
>> hold a reference to the request so could drop the seqno field from
>> here?
>
> Keeping the seqno field helps with the lowlevel testcase that works
> without requests. Not scientific, but it was one less pointer for the
> irq handler.
Ok.
>>> };
>>>
>>> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
>>> index bc70e2c451b2..3c79753edf0e 100644
>>> --- a/drivers/gpu/drm/i915/i915_irq.c
>>> +++ b/drivers/gpu/drm/i915/i915_irq.c
>>> @@ -1033,12 +1033,41 @@ static void ironlake_rps_change_irq_handler(struct drm_i915_private *dev_priv)
>>>
>>> static void notify_ring(struct intel_engine_cs *engine)
>>> {
>>> - bool waiters;
>>> + struct drm_i915_gem_request *rq = NULL;
>>> + struct intel_wait *wait;
>>> +
>>> + if (!intel_engine_has_waiter(engine))
>>> + return;
>>
>> I think we need the tracepoint before the bail out.
>>
>>>
>>> atomic_inc(&engine->irq_count);
>>
>> And the increment as well.
>>
>>> set_bit(ENGINE_IRQ_BREADCRUMB, &engine->irq_posted);
>>> - waiters = intel_engine_wakeup(engine);
>>> - trace_intel_engine_notify(engine, waiters);
>>> +
>>> + spin_lock(&engine->breadcrumbs.lock);
>>> + wait = engine->breadcrumbs.first_wait;
>>> + if (wait) {
>>> + /* We use a callback from the dma-fence to submit
>>> + * requests after waiting on our own requests. To
>>> + * ensure minimum delay in queuing the next request to
>>> + * hardware, signal the fence now rather than wait for
>>> + * the signaler to be woken up. We still wake up the
>>> + * waiter in order to handle the irq-seqno coherency
>>> + * issues (we may receive the interrupt before the
>>> + * seqno is written, see __i915_request_irq_complete())
>>> + * and to handle coalescing of multiple seqno updates
>>> + * and many waiters.
>>> + */
>>> + if (i915_seqno_passed(intel_engine_get_seqno(engine),
>>> + wait->seqno))
>>> + rq = wait->request;
>>> +
>>> + wake_up_process(wait->tsk);
>>> + }
>>> + spin_unlock(&engine->breadcrumbs.lock);
>>> +
>>> + if (rq) /* rq is protected by RCU, so safe from hard-irq context */
>>> + dma_fence_signal(&rq->fence);
>>> +
>>> + trace_intel_engine_notify(engine, wait);
>
> Hmm, I put the trace here for access to wait. I guess we only need a
> READ_ONCE(engine->breadcrumbs.first_wait) for tracking?
So far I don't think I even used that field from the tracepoint, but I
think we just agreed it was an useful thing to have.
Tracepoint itself is useful for deducing individual request boundaries
with coalescing which is why I don't think it being conditional on
waiters is correct. But I do agree that might be questionable since it
is not reliable until the GuC scheduling backend and GuC becoming a
default, and at that point it will make no difference where the exact
tracepoint site is.
> Note in the next patch, it's different again. And yeah I should massage
> it such that it doesn't introduce a fluctuation.
Yes would be better. :)
>>> }
>>>
>>> static void vlv_c0_read(struct drm_i915_private *dev_priv,
>>> diff --git a/drivers/gpu/drm/i915/intel_breadcrumbs.c b/drivers/gpu/drm/i915/intel_breadcrumbs.c
>>> index 027c93e34c97..5f2665aa817c 100644
>>> --- a/drivers/gpu/drm/i915/intel_breadcrumbs.c
>>> +++ b/drivers/gpu/drm/i915/intel_breadcrumbs.c
>>> @@ -81,8 +81,11 @@ static void intel_breadcrumbs_fake_irq(unsigned long data)
>>> * every jiffie in order to kick the oldest waiter to do the
>>> * coherent seqno check.
>>> */
>>> - if (intel_engine_wakeup(engine))
>>> - mod_timer(&engine->breadcrumbs.fake_irq, jiffies + 1);
>>> + if (!intel_engine_has_waiter(engine))
>>> + return;
>>> +
>>> + intel_engine_wakeup(engine);
>>> + mod_timer(&engine->breadcrumbs.fake_irq, jiffies + 1);
>>
>> Not sure it is worth splitting this in two instead of just leaving
>> it as it was.
>
> The problem with the previous code was the timer stopped if the waiter
> was running at that moment. I am still playing to find something that
> doesn't look horrible. Just going back to the bool intel_engine_wakeup,
> which is now far too large to be an inline for an unimportant function.
[thread merge]
> Ah, found the complication. Here we want intel_engine_wakeup() to
> report if there was a waiter, but in intel_breadcrumbs_hangcheck, we
> want to know if we failed to wakeup the waiter.
>
> Just grin and bear it for the moment. :|
I've missed that detail. Makes sense.
Regards,
Tvrtko
More information about the Intel-gfx
mailing list