Merge "drm/msm: Fix race condition in the submit path"
This commit is contained in:
commit
17273e1577
2 changed files with 20 additions and 3 deletions
|
@ -70,6 +70,8 @@ struct a5xx_gpu {
|
||||||
* PREEMPT_NONE - no preemption in progress. Next state START.
|
* PREEMPT_NONE - no preemption in progress. Next state START.
|
||||||
* PREEMPT_START - The trigger is evaulating if preemption is possible. Next
|
* PREEMPT_START - The trigger is evaulating if preemption is possible. Next
|
||||||
* states: TRIGGERED, NONE
|
* states: TRIGGERED, NONE
|
||||||
|
* PREEMPT_ABORT - An intermediate state before moving back to NONE. Next
|
||||||
|
* state: NONE.
|
||||||
* PREEMPT_TRIGGERED: A preemption has been executed on the hardware. Next
|
* PREEMPT_TRIGGERED: A preemption has been executed on the hardware. Next
|
||||||
* states: FAULTED, PENDING
|
* states: FAULTED, PENDING
|
||||||
* PREEMPT_FAULTED: A preemption timed out (never completed). This will trigger
|
* PREEMPT_FAULTED: A preemption timed out (never completed). This will trigger
|
||||||
|
@ -81,6 +83,7 @@ struct a5xx_gpu {
|
||||||
enum preempt_state {
|
enum preempt_state {
|
||||||
PREEMPT_NONE = 0,
|
PREEMPT_NONE = 0,
|
||||||
PREEMPT_START,
|
PREEMPT_START,
|
||||||
|
PREEMPT_ABORT,
|
||||||
PREEMPT_TRIGGERED,
|
PREEMPT_TRIGGERED,
|
||||||
PREEMPT_FAULTED,
|
PREEMPT_FAULTED,
|
||||||
PREEMPT_PENDING,
|
PREEMPT_PENDING,
|
||||||
|
@ -184,7 +187,10 @@ int a5xx_snapshot(struct msm_gpu *gpu, struct msm_snapshot *snapshot);
|
||||||
/* Return true if we are in a preempt state */
|
/* Return true if we are in a preempt state */
|
||||||
static inline bool a5xx_in_preempt(struct a5xx_gpu *a5xx_gpu)
|
static inline bool a5xx_in_preempt(struct a5xx_gpu *a5xx_gpu)
|
||||||
{
|
{
|
||||||
return !(atomic_read(&a5xx_gpu->preempt_state) == PREEMPT_NONE);
|
int preempt_state = atomic_read(&a5xx_gpu->preempt_state);
|
||||||
|
|
||||||
|
return !(preempt_state == PREEMPT_NONE ||
|
||||||
|
preempt_state == PREEMPT_ABORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
int a5xx_counters_init(struct adreno_gpu *adreno_gpu);
|
int a5xx_counters_init(struct adreno_gpu *adreno_gpu);
|
||||||
|
|
|
@ -128,9 +128,20 @@ void a5xx_preempt_trigger(struct msm_gpu *gpu)
|
||||||
* one do nothing except to update the wptr to the latest and greatest
|
* one do nothing except to update the wptr to the latest and greatest
|
||||||
*/
|
*/
|
||||||
if (!ring || (a5xx_gpu->cur_ring == ring)) {
|
if (!ring || (a5xx_gpu->cur_ring == ring)) {
|
||||||
update_wptr(gpu, ring);
|
/*
|
||||||
|
* Its possible that while a preemption request is in progress
|
||||||
|
* from an irq context, a user context trying to submit might
|
||||||
|
* fail to update the write pointer, because it determines
|
||||||
|
* that the preempt state is not PREEMPT_NONE.
|
||||||
|
*
|
||||||
|
* Close the race by introducing an intermediate
|
||||||
|
* state PREEMPT_ABORT to let the submit path
|
||||||
|
* know that the ringbuffer is not going to change
|
||||||
|
* and can safely update the write pointer.
|
||||||
|
*/
|
||||||
|
|
||||||
/* Set the state back to NONE */
|
set_preempt_state(a5xx_gpu, PREEMPT_ABORT);
|
||||||
|
update_wptr(gpu, a5xx_gpu->cur_ring);
|
||||||
set_preempt_state(a5xx_gpu, PREEMPT_NONE);
|
set_preempt_state(a5xx_gpu, PREEMPT_NONE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue