[Freedreno] [PATCH 5/6] drm/msm/Adreno: Refactor some preemption code

Sharat Masetty smasetty at codeaurora.org
Thu Mar 8 06:06:24 UTC 2018


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 at codeaurora.org>
---
 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



More information about the Freedreno mailing list