2019-10-24 11:03:44 +01:00
/*
* SPDX - License - Identifier : MIT
*
* Copyright © 2019 Intel Corporation
*/
# ifndef INTEL_RING_H
# define INTEL_RING_H
# include "i915_gem.h" /* GEM_BUG_ON */
# include "i915_request.h"
# include "intel_ring_types.h"
struct intel_engine_cs ;
struct intel_ring *
intel_engine_create_ring ( struct intel_engine_cs * engine , int size ) ;
u32 * intel_ring_begin ( struct i915_request * rq , unsigned int num_dwords ) ;
int intel_ring_cacheline_align ( struct i915_request * rq ) ;
unsigned int intel_ring_update_space ( struct intel_ring * ring ) ;
int intel_ring_pin ( struct intel_ring * ring ) ;
void intel_ring_unpin ( struct intel_ring * ring ) ;
void intel_ring_reset ( struct intel_ring * ring , u32 tail ) ;
void intel_ring_free ( struct kref * ref ) ;
static inline struct intel_ring * intel_ring_get ( struct intel_ring * ring )
{
kref_get ( & ring - > ref ) ;
return ring ;
}
static inline void intel_ring_put ( struct intel_ring * ring )
{
kref_put ( & ring - > ref , intel_ring_free ) ;
}
static inline void intel_ring_advance ( struct i915_request * rq , u32 * cs )
{
/* Dummy function.
*
* This serves as a placeholder in the code so that the reader
* can compare against the preceding intel_ring_begin ( ) and
* check that the number of dwords emitted matches the space
* reserved for the command packet ( i . e . the value passed to
* intel_ring_begin ( ) ) .
*/
GEM_BUG_ON ( ( rq - > ring - > vaddr + rq - > ring - > emit ) ! = cs ) ;
}
static inline u32 intel_ring_wrap ( const struct intel_ring * ring , u32 pos )
{
return pos & ( ring - > size - 1 ) ;
}
drm/i915/execlists: Always force a context reload when rewinding RING_TAIL
If we rewind the RING_TAIL on a context, due to a preemption event, we
must force the context restore for the RING_TAIL update to be properly
handled. Rather than note which preemption events may cause us to rewind
the tail, compare the new request's tail with the previously submitted
RING_TAIL, as it turns out that timeslicing was causing unexpected
rewinds.
<idle>-0 0d.s2 1280851190us : __execlists_submission_tasklet: 0000:00:02.0 rcs0: expired last=130:4698, prio=3, hint=3
<idle>-0 0d.s2 1280851192us : __i915_request_unsubmit: 0000:00:02.0 rcs0: fence 66:119966, current 119964
<idle>-0 0d.s2 1280851195us : __i915_request_unsubmit: 0000:00:02.0 rcs0: fence 130:4698, current 4695
<idle>-0 0d.s2 1280851198us : __i915_request_unsubmit: 0000:00:02.0 rcs0: fence 130:4696, current 4695
^---- Note we unwind 2 requests from the same context
<idle>-0 0d.s2 1280851208us : __i915_request_submit: 0000:00:02.0 rcs0: fence 130:4696, current 4695
<idle>-0 0d.s2 1280851213us : __i915_request_submit: 0000:00:02.0 rcs0: fence 134:1508, current 1506
^---- But to apply the new timeslice, we have to replay the first request
before the new client can start -- the unexpected RING_TAIL rewind
<idle>-0 0d.s2 1280851219us : trace_ports: 0000:00:02.0 rcs0: submit { 130:4696*, 134:1508 }
synmark2-5425 2..s. 1280851239us : process_csb: 0000:00:02.0 rcs0: cs-irq head=5, tail=0
synmark2-5425 2..s. 1280851240us : process_csb: 0000:00:02.0 rcs0: csb[0]: status=0x00008002:0x00000000
^---- Preemption event for the ELSP update; note the lite-restore
synmark2-5425 2..s. 1280851243us : trace_ports: 0000:00:02.0 rcs0: preempted { 130:4698, 66:119966 }
synmark2-5425 2..s. 1280851246us : trace_ports: 0000:00:02.0 rcs0: promote { 130:4696*, 134:1508 }
synmark2-5425 2.... 1280851462us : __i915_request_commit: 0000:00:02.0 rcs0: fence 130:4700, current 4695
synmark2-5425 2.... 1280852111us : __i915_request_commit: 0000:00:02.0 rcs0: fence 130:4702, current 4695
synmark2-5425 2.Ns1 1280852296us : process_csb: 0000:00:02.0 rcs0: cs-irq head=0, tail=2
synmark2-5425 2.Ns1 1280852297us : process_csb: 0000:00:02.0 rcs0: csb[1]: status=0x00000814:0x00000000
synmark2-5425 2.Ns1 1280852299us : trace_ports: 0000:00:02.0 rcs0: completed { 130:4696!, 134:1508 }
synmark2-5425 2.Ns1 1280852301us : process_csb: 0000:00:02.0 rcs0: csb[2]: status=0x00000818:0x00000040
synmark2-5425 2.Ns1 1280852302us : trace_ports: 0000:00:02.0 rcs0: completed { 134:1508, 0:0 }
synmark2-5425 2.Ns1 1280852313us : process_csb: process_csb:2336 GEM_BUG_ON(!i915_request_completed(*execlists->active) && !reset_in_progress(execlists))
Fixes: 8ee36e048c98 ("drm/i915/execlists: Minimalistic timeslicing")
Referenecs: 82c69bf58650 ("drm/i915/gt: Detect if we miss WaIdleLiteRestore")
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Cc: <stable@vger.kernel.org> # v5.4+
Link: https://patchwork.freedesktop.org/patch/msgid/20200207211452.2860634-1-chris@chris-wilson.co.uk
2020-02-07 21:14:52 +00:00
static inline int intel_ring_direction ( const struct intel_ring * ring ,
u32 next , u32 prev )
{
typecheck ( typeof ( ring - > size ) , next ) ;
typecheck ( typeof ( ring - > size ) , prev ) ;
return ( next - prev ) < < ring - > wrap ;
}
2019-10-24 11:03:44 +01:00
static inline bool
intel_ring_offset_valid ( const struct intel_ring * ring ,
unsigned int pos )
{
if ( pos & - ring - > size ) /* must be strictly within the ring */
return false ;
if ( ! IS_ALIGNED ( pos , 8 ) ) /* must be qword aligned */
return false ;
return true ;
}
static inline u32 intel_ring_offset ( const struct i915_request * rq , void * addr )
{
/* Don't write ring->size (equivalent to 0) as that hangs some GPUs. */
u32 offset = addr - rq - > ring - > vaddr ;
GEM_BUG_ON ( offset > rq - > ring - > size ) ;
return intel_ring_wrap ( rq - > ring , offset ) ;
}
static inline void
assert_ring_tail_valid ( const struct intel_ring * ring , unsigned int tail )
{
2020-04-07 23:18:32 +01:00
unsigned int head = READ_ONCE ( ring - > head ) ;
2019-10-24 11:03:44 +01:00
GEM_BUG_ON ( ! intel_ring_offset_valid ( ring , tail ) ) ;
/*
* " Ring Buffer Use "
* Gen2 BSpec " 1. Programming Environment " / 1.4 .4 .6
* Gen3 BSpec " 1c Memory Interface Functions " / 2.3 .4 .5
* Gen4 + BSpec " 1c Memory Interface and Command Stream " / 5.3 .4 .5
* " If the Ring Buffer Head Pointer and the Tail Pointer are on the
* same cacheline , the Head Pointer must not be greater than the Tail
* Pointer . "
*
* We use ring - > head as the last known location of the actual RING_HEAD ,
* it may have advanced but in the worst case it is equally the same
* as ring - > head and so we should never program RING_TAIL to advance
* into the same cacheline as ring - > head .
*/
# define cacheline(a) round_down(a, CACHELINE_BYTES)
2020-04-07 23:18:32 +01:00
GEM_BUG_ON ( cacheline ( tail ) = = cacheline ( head ) & & tail < head ) ;
2019-10-24 11:03:44 +01:00
# undef cacheline
}
static inline unsigned int
intel_ring_set_tail ( struct intel_ring * ring , unsigned int tail )
{
/* Whilst writes to the tail are strictly order, there is no
* serialisation between readers and the writers . The tail may be
* read by i915_request_retire ( ) just as it is being updated
* by execlists , as although the breadcrumb is complete , the context
* switch hasn ' t been seen .
*/
assert_ring_tail_valid ( ring , tail ) ;
ring - > tail = tail ;
return tail ;
}
static inline unsigned int
__intel_ring_space ( unsigned int head , unsigned int tail , unsigned int size )
{
/*
* " If the Ring Buffer Head Pointer and the Tail Pointer are on the
* same cacheline , the Head Pointer must not be greater than the Tail
* Pointer . "
*/
GEM_BUG_ON ( ! is_power_of_2 ( size ) ) ;
return ( head - tail - CACHELINE_BYTES ) & ( size - 1 ) ;
}
# endif /* INTEL_RING_H */