drm/i915: Filter out spurious execlists context-switch interrupts
Back in commita4b2b01523
("drm/i915: Don't mark an execlists context-switch when idle") we noticed the presence of late context-switch interrupts. We were able to filter those out by looking at whether the ELSP remained active, but in commitbeecec9017
("drm/i915/execlists: Preemption!") that became problematic as we now anticipate receiving a context-switch event for preemption while ELSP may be empty. To restore the spurious interrupt suppression, add a counter for the expected number of pending context-switches and skip if we do not need to handle this interrupt to make forward progress. v2: Don't forget to switch on for preempt. v3: Reduce the counter to a on/off boolean tracker. Declare the HW as active when we first submit, and idle after the final completion event (with which we confirm the HW says it is idle), and track each source of activity separately. With a finite number of sources, it should aide us in debugging which gets stuck. Fixes:beecec9017
("drm/i915/execlists: Preemption!") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Michal Winiarski <michal.winiarski@intel.com> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Cc: Arkadiusz Hiler <arkadiusz.hiler@intel.com> Cc: Mika Kuoppala <mika.kuoppala@intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20171023213237.26536-3-chris@chris-wilson.co.uk Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
This commit is contained in:
@@ -241,9 +241,17 @@ struct intel_engine_execlists {
|
||||
} port[EXECLIST_MAX_PORTS];
|
||||
|
||||
/**
|
||||
* @preempt: are we currently handling a preempting context switch?
|
||||
* @active: is the HW active? We consider the HW as active after
|
||||
* submitting any context for execution and until we have seen the
|
||||
* last context completion event. After that, we do not expect any
|
||||
* more events until we submit, and so can park the HW.
|
||||
*
|
||||
* As we have a small number of different sources from which we feed
|
||||
* the HW, we track the state of each inside a single bitfield.
|
||||
*/
|
||||
bool preempt;
|
||||
unsigned int active;
|
||||
#define EXECLISTS_ACTIVE_USER 0
|
||||
#define EXECLISTS_ACTIVE_PREEMPT 1
|
||||
|
||||
/**
|
||||
* @port_mask: number of execlist ports - 1
|
||||
@@ -525,6 +533,27 @@ struct intel_engine_cs {
|
||||
u32 (*get_cmd_length_mask)(u32 cmd_header);
|
||||
};
|
||||
|
||||
static inline void
|
||||
execlists_set_active(struct intel_engine_execlists *execlists,
|
||||
unsigned int bit)
|
||||
{
|
||||
__set_bit(bit, (unsigned long *)&execlists->active);
|
||||
}
|
||||
|
||||
static inline void
|
||||
execlists_clear_active(struct intel_engine_execlists *execlists,
|
||||
unsigned int bit)
|
||||
{
|
||||
__clear_bit(bit, (unsigned long *)&execlists->active);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
execlists_is_active(const struct intel_engine_execlists *execlists,
|
||||
unsigned int bit)
|
||||
{
|
||||
return test_bit(bit, (unsigned long *)&execlists->active);
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
execlists_num_ports(const struct intel_engine_execlists * const execlists)
|
||||
{
|
||||
@@ -538,6 +567,7 @@ execlists_port_complete(struct intel_engine_execlists * const execlists,
|
||||
const unsigned int m = execlists->port_mask;
|
||||
|
||||
GEM_BUG_ON(port_index(port, execlists) != 0);
|
||||
GEM_BUG_ON(!execlists_is_active(execlists, EXECLISTS_ACTIVE_USER));
|
||||
|
||||
memmove(port, port + 1, m * sizeof(struct execlist_port));
|
||||
memset(port + m, 0, sizeof(struct execlist_port));
|
||||
|
Reference in New Issue
Block a user