The preemption state machine related code is same across Adreno targets, so move the common code to a common header file to avoid code duplication. Signed-off-by: Sharat Masetty <smasetty@xxxxxxxxxxxxxx> --- drivers/gpu/drm/msm/adreno/a5xx_gpu.h | 26 --------------- drivers/gpu/drm/msm/adreno/a5xx_preempt.c | 55 +++++++++---------------------- drivers/gpu/drm/msm/adreno/a6xx_gpu.h | 26 --------------- drivers/gpu/drm/msm/adreno/a6xx_preempt.c | 55 +++++++++---------------------- drivers/gpu/drm/msm/adreno/adreno_gpu.h | 54 ++++++++++++++++++++++++++++++ 5 files changed, 84 insertions(+), 132 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h index 7d71860..45535f7 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h @@ -54,32 +54,6 @@ struct a5xx_gpu { #endif /* - * In order to do lockless preemption we use a simple state machine to progress - * through the process. - * - * PREEMPT_NONE - no preemption in progress. Next state START. - * PREEMPT_START - The trigger is evaulating if preemption is possible. Next - * 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 - * states: FAULTED, PENDING - * PREEMPT_FAULTED: A preemption timed out (never completed). This will trigger - * recovery. Next state: N/A - * PREEMPT_PENDING: Preemption complete interrupt fired - the callback is - * checking the success of the operation. Next state: FAULTED, NONE. - */ - -enum preempt_state { - PREEMPT_NONE = 0, - PREEMPT_START, - PREEMPT_ABORT, - PREEMPT_TRIGGERED, - PREEMPT_FAULTED, - PREEMPT_PENDING, -}; - -/* * struct a5xx_preempt_record is a shared buffer between the microcode and the * CPU to store the state for preemption. The record itself is much larger * (64k) but most of that is used by the CP for storage. diff --git a/drivers/gpu/drm/msm/adreno/a5xx_preempt.c b/drivers/gpu/drm/msm/adreno/a5xx_preempt.c index 40f4840..faf844b 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_preempt.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_preempt.c @@ -14,37 +14,6 @@ #include "msm_gem.h" #include "a5xx_gpu.h" -/* - * Try to transition the preemption state from old to new. Return - * true on success or false if the original state wasn't 'old' - */ -static inline bool try_preempt_state(struct a5xx_gpu *a5xx_gpu, - enum preempt_state old, enum preempt_state new) -{ - enum preempt_state cur = atomic_cmpxchg(&a5xx_gpu->preempt_state, - old, new); - - return (cur == old); -} - -/* - * Force the preemption state to the specified state. This is used in cases - * where the current state is known and won't change - */ -static inline void set_preempt_state(struct a5xx_gpu *gpu, - enum preempt_state new) -{ - /* - * preempt_state may be read by other cores trying to trigger a - * preemption or in the interrupt handler so barriers are needed - * before... - */ - smp_mb__before_atomic(); - atomic_set(&gpu->preempt_state, new); - /* ... and after*/ - smp_mb__after_atomic(); -} - /* Write the most recent wptr for the given ring into the hardware */ static inline void update_wptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring) { @@ -89,7 +58,8 @@ static void a5xx_preempt_timer(unsigned long data) struct drm_device *dev = gpu->dev; struct msm_drm_private *priv = dev->dev_private; - if (!try_preempt_state(a5xx_gpu, PREEMPT_TRIGGERED, PREEMPT_FAULTED)) + if (!adreno_try_preempt_state(&a5xx_gpu->preempt_state, + PREEMPT_TRIGGERED, PREEMPT_FAULTED)) return; dev_err(dev->dev, "%s: preemption timed out\n", gpu->name); @@ -111,7 +81,8 @@ void a5xx_preempt_trigger(struct msm_gpu *gpu) * Try to start preemption by moving from NONE to START. If * unsuccessful, a preemption is already in flight */ - if (!try_preempt_state(a5xx_gpu, PREEMPT_NONE, PREEMPT_START)) + if (!adreno_try_preempt_state(&a5xx_gpu->preempt_state, + PREEMPT_NONE, PREEMPT_START)) return; /* Get the next ring to preempt to */ @@ -134,9 +105,11 @@ void a5xx_preempt_trigger(struct msm_gpu *gpu) * and can safely update the write pointer. */ - set_preempt_state(a5xx_gpu, PREEMPT_ABORT); + adreno_set_preempt_state(&a5xx_gpu->preempt_state, + PREEMPT_ABORT); update_wptr(gpu, a5xx_gpu->cur_ring); - set_preempt_state(a5xx_gpu, PREEMPT_NONE); + adreno_set_preempt_state(&a5xx_gpu->preempt_state, + PREEMPT_NONE); return; } @@ -156,7 +129,7 @@ void a5xx_preempt_trigger(struct msm_gpu *gpu) mod_timer(&a5xx_gpu->preempt_timer, jiffies + msecs_to_jiffies(10000)); /* Set the preemption state to triggered */ - set_preempt_state(a5xx_gpu, PREEMPT_TRIGGERED); + adreno_set_preempt_state(&a5xx_gpu->preempt_state, PREEMPT_TRIGGERED); /* Make sure everything is written before hitting the button */ wmb(); @@ -173,7 +146,8 @@ void a5xx_preempt_irq(struct msm_gpu *gpu) struct drm_device *dev = gpu->dev; struct msm_drm_private *priv = dev->dev_private; - if (!try_preempt_state(a5xx_gpu, PREEMPT_TRIGGERED, PREEMPT_PENDING)) + if (!adreno_try_preempt_state(&a5xx_gpu->preempt_state, + PREEMPT_TRIGGERED, PREEMPT_PENDING)) return; /* Delete the preemption watchdog timer */ @@ -187,7 +161,8 @@ void a5xx_preempt_irq(struct msm_gpu *gpu) */ status = gpu_read(gpu, REG_A5XX_CP_CONTEXT_SWITCH_CNTL); if (unlikely(status)) { - set_preempt_state(a5xx_gpu, PREEMPT_FAULTED); + adreno_set_preempt_state(&a5xx_gpu->preempt_state, + PREEMPT_FAULTED); dev_err(dev->dev, "%s: Preemption failed to complete\n", gpu->name); queue_work(priv->wq, &gpu->recover_work); @@ -199,7 +174,7 @@ void a5xx_preempt_irq(struct msm_gpu *gpu) update_wptr(gpu, a5xx_gpu->cur_ring); - set_preempt_state(a5xx_gpu, PREEMPT_NONE); + adreno_set_preempt_state(&a5xx_gpu->preempt_state, PREEMPT_NONE); } void a5xx_preempt_hw_init(struct msm_gpu *gpu) @@ -219,7 +194,7 @@ void a5xx_preempt_hw_init(struct msm_gpu *gpu) REG_A5XX_CP_CONTEXT_SWITCH_SMMU_INFO_HI, 0); /* Reset the preemption state */ - set_preempt_state(a5xx_gpu, PREEMPT_NONE); + adreno_set_preempt_state(&a5xx_gpu->preempt_state, PREEMPT_NONE); /* Always come up on rb 0 */ a5xx_gpu->cur_ring = gpu->rb[0]; diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h index aca1d7d..21ab701 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h @@ -54,32 +54,6 @@ struct a6xx_gpu { (a6xx_gpu->scratch_iova + (ring_id * sizeof(uint64_t))) /* - * In order to do lockless preemption we use a simple state machine to progress - * through the process. - * - * PREEMPT_NONE - no preemption in progress. Next state START. - * PREEMPT_START - The trigger is evaluating if preemption is possible. Next - * 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 - * states: FAULTED, PENDING - * PREEMPT_FAULTED: A preemption timed out (never completed). This will trigger - * recovery. Next state: N/A - * PREEMPT_PENDING: Preemption complete interrupt fired - the callback is - * checking the success of the operation. Next state: FAULTED, NONE. - */ - -enum a6xx_preempt_state { - PREEMPT_NONE = 0, - PREEMPT_START, - PREEMPT_ABORT, - PREEMPT_TRIGGERED, - PREEMPT_FAULTED, - PREEMPT_PENDING, -}; - -/* * ID values used by SET_PSEUDO_REG PM4 command. These determine which of the * various internal CP registers to write to. Used in the save/restore * preemption sequence. diff --git a/drivers/gpu/drm/msm/adreno/a6xx_preempt.c b/drivers/gpu/drm/msm/adreno/a6xx_preempt.c index 60df6c5..0d2b612 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_preempt.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_preempt.c @@ -5,37 +5,6 @@ #include "a6xx_gpu.h" #include "a6xx_gmu.xml.h" -/* - * Try to transition the preemption state from old to new. Return - * true on success or false if the original state wasn't 'old' - */ -static inline bool try_preempt_state(struct a6xx_gpu *a6xx_gpu, - enum a6xx_preempt_state old, enum a6xx_preempt_state new) -{ - enum a6xx_preempt_state cur = atomic_cmpxchg(&a6xx_gpu->preempt_state, - old, new); - - return (cur == old); -} - -/* - * Force the preemption state to the specified state. This is used in cases - * where the current state is known and won't change - */ -static inline void set_preempt_state(struct a6xx_gpu *gpu, - enum a6xx_preempt_state new) -{ - /* - * preempt_state may be read by other cores trying to trigger a - * preemption or in the interrupt handler so barriers are needed - * before... - */ - smp_mb__before_atomic(); - atomic_set(&gpu->preempt_state, new); - /* ... and after*/ - smp_mb__after_atomic(); -} - /* Write the most recent wptr for the given ring into the hardware */ static inline void update_wptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring) { @@ -80,7 +49,8 @@ static void a6xx_preempt_timer(unsigned long data) struct drm_device *dev = gpu->dev; struct msm_drm_private *priv = dev->dev_private; - if (!try_preempt_state(a6xx_gpu, PREEMPT_TRIGGERED, PREEMPT_FAULTED)) + if (!adreno_try_preempt_state(&a6xx_gpu->preempt_state, + PREEMPT_TRIGGERED, PREEMPT_FAULTED)) return; dev_err(dev->dev, "%s: preemption timed out\n", gpu->name); @@ -95,7 +65,8 @@ void a6xx_preempt_irq(struct msm_gpu *gpu) struct drm_device *dev = gpu->dev; struct msm_drm_private *priv = dev->dev_private; - if (!try_preempt_state(a6xx_gpu, PREEMPT_TRIGGERED, PREEMPT_PENDING)) + if (!adreno_try_preempt_state(&a6xx_gpu->preempt_state, + PREEMPT_TRIGGERED, PREEMPT_PENDING)) return; /* Delete the preemption watchdog timer */ @@ -110,7 +81,8 @@ void a6xx_preempt_irq(struct msm_gpu *gpu) */ status = gpu_read(gpu, REG_A6XX_CP_CONTEXT_SWITCH_CNTL); if (unlikely(status & 0x1)) { - set_preempt_state(a6xx_gpu, PREEMPT_FAULTED); + adreno_set_preempt_state(&a6xx_gpu->preempt_state, + PREEMPT_FAULTED); dev_err(dev->dev, "%s: Preemption failed to complete\n", gpu->name); queue_work(priv->wq, &gpu->recover_work); @@ -122,7 +94,7 @@ void a6xx_preempt_irq(struct msm_gpu *gpu) update_wptr(gpu, a6xx_gpu->cur_ring); - set_preempt_state(a6xx_gpu, PREEMPT_NONE); + adreno_set_preempt_state(&a6xx_gpu->preempt_state, PREEMPT_NONE); } void a6xx_preempt_hw_init(struct msm_gpu *gpu) @@ -151,7 +123,7 @@ void a6xx_preempt_hw_init(struct msm_gpu *gpu) gpu_write(gpu, REG_A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE, 0x1); /* Reset the preemption state */ - set_preempt_state(a6xx_gpu, PREEMPT_NONE); + adreno_set_preempt_state(&a6xx_gpu->preempt_state, PREEMPT_NONE); /* Always come up on rb 0 */ a6xx_gpu->cur_ring = gpu->rb[0]; @@ -175,7 +147,8 @@ void a6xx_preempt_trigger(struct msm_gpu *gpu) * Try to start preemption by moving from NONE to START. If * unsuccessful, a preemption is already in flight */ - if (!try_preempt_state(a6xx_gpu, PREEMPT_NONE, PREEMPT_START)) + if (!adreno_try_preempt_state(&a6xx_gpu->preempt_state, + PREEMPT_NONE, PREEMPT_START)) return; cntl = (((a6xx_gpu->preempt_level << 6) & 0xC0) | @@ -190,9 +163,11 @@ void a6xx_preempt_trigger(struct msm_gpu *gpu) * one do nothing except to update the wptr to the latest and greatest */ if (!ring || (a6xx_gpu->cur_ring == ring)) { - set_preempt_state(a6xx_gpu, PREEMPT_ABORT); + adreno_set_preempt_state(&a6xx_gpu->preempt_state, + PREEMPT_ABORT); update_wptr(gpu, a6xx_gpu->cur_ring); - set_preempt_state(a6xx_gpu, PREEMPT_NONE); + adreno_set_preempt_state(&a6xx_gpu->preempt_state, + PREEMPT_NONE); return; } @@ -243,7 +218,7 @@ void a6xx_preempt_trigger(struct msm_gpu *gpu) mod_timer(&a6xx_gpu->preempt_timer, jiffies + msecs_to_jiffies(10000)); /* Set the preemption state to triggered */ - set_preempt_state(a6xx_gpu, PREEMPT_TRIGGERED); + adreno_set_preempt_state(&a6xx_gpu->preempt_state, PREEMPT_TRIGGERED); /* Make sure everything is written before hitting the button */ wmb(); diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 94764d0..bb9affd 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -368,4 +368,58 @@ static inline uint32_t get_wptr(struct msm_ringbuffer *ring) ((1 << 29) \ ((ilog2((_len)) & 0x1F) << 24) | (((_reg) << 2) & 0xFFFFF)) +/* + * In order to do lockless preemption we use a simple state machine to progress + * through the process. + * + * PREEMPT_NONE - no preemption in progress. Next state START. + * PREEMPT_START - The trigger is evaluating if preemption is possible. Next + * 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 + * states: FAULTED, PENDING + * PREEMPT_FAULTED: A preemption timed out (never completed). This will trigger + * recovery. Next state: N/A + * PREEMPT_PENDING: Preemption complete interrupt fired - the callback is + * checking the success of the operation. Next state: FAULTED, NONE. + */ +enum adreno_preempt_state { + PREEMPT_NONE = 0, + PREEMPT_START, + PREEMPT_ABORT, + PREEMPT_TRIGGERED, + PREEMPT_FAULTED, + PREEMPT_PENDING, +}; + +/* + * Try to transition the preemption state from old to new. Return + * true on success or false if the original state wasn't 'old' + */ +static inline bool adreno_try_preempt_state(atomic_t *preempt_state, + enum adreno_preempt_state old, enum adreno_preempt_state new) +{ + enum adreno_preempt_state cur = atomic_cmpxchg(preempt_state, old, new); + + return (cur == old); +} + +/* + * Force the preemption state to the specified state. This is used in cases + * where the current state is known and won't change + */ +static inline void adreno_set_preempt_state(atomic_t *preempt_state, + enum adreno_preempt_state new) +{ + /* + * adreno_preempt_state may be read by other cores trying to trigger a + * preemption or in the interrupt handler so barriers are needed + * before... + */ + smp_mb__before_atomic(); + atomic_set(preempt_state, new); + /* ... and after*/ + smp_mb__after_atomic(); +} #endif /* __ADRENO_GPU_H__ */ -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html