xref: /linux/drivers/gpu/drm/msm/adreno/a6xx_preempt.h (revision fbf5df34a4dbcd09d433dd4f0916bf9b2ddb16de)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /* Copyright (c) 2018, The Linux Foundation. All rights reserved. */
3 /* Copyright (c) 2023 Collabora, Ltd. */
4 /* Copyright (c) 2024 Valve Corporation */
5 /* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */
6 
7 /*
8  * Try to transition the preemption state from old to new. Return
9  * true on success or false if the original state wasn't 'old'
10  */
11 static inline bool try_preempt_state(struct a6xx_gpu *a6xx_gpu,
12 		enum a6xx_preempt_state old, enum a6xx_preempt_state new)
13 {
14 	enum a6xx_preempt_state cur = atomic_cmpxchg(&a6xx_gpu->preempt_state,
15 		old, new);
16 
17 	return (cur == old);
18 }
19 
20 /*
21  * Force the preemption state to the specified state.  This is used in cases
22  * where the current state is known and won't change
23  */
24 static inline void set_preempt_state(struct a6xx_gpu *gpu,
25 		enum a6xx_preempt_state new)
26 {
27 	/*
28 	 * preempt_state may be read by other cores trying to trigger a
29 	 * preemption or in the interrupt handler so barriers are needed
30 	 * before...
31 	 */
32 	smp_mb__before_atomic();
33 	atomic_set(&gpu->preempt_state, new);
34 	/* ... and after */
35 	smp_mb__after_atomic();
36 }
37 
38 /* Write the most recent wptr for the given ring into the hardware */
39 static inline void update_wptr(struct a6xx_gpu *a6xx_gpu, struct msm_ringbuffer *ring)
40 {
41 	unsigned long flags;
42 	uint32_t wptr;
43 
44 	spin_lock_irqsave(&ring->preempt_lock, flags);
45 
46 	if (ring->restore_wptr) {
47 		wptr = get_wptr(ring);
48 
49 		a6xx_fenced_write(a6xx_gpu, REG_A6XX_CP_RB_WPTR, wptr, BIT(0), false);
50 
51 		ring->restore_wptr = false;
52 	}
53 
54 	spin_unlock_irqrestore(&ring->preempt_lock, flags);
55 }
56 
57 /* Return the highest priority ringbuffer with something in it */
58 static inline struct msm_ringbuffer *get_next_ring(struct msm_gpu *gpu)
59 {
60 	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
61 	struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
62 
63 	unsigned long flags;
64 	int i;
65 
66 	for (i = 0; i < gpu->nr_rings; i++) {
67 		bool empty;
68 		struct msm_ringbuffer *ring = gpu->rb[i];
69 
70 		spin_lock_irqsave(&ring->preempt_lock, flags);
71 		empty = (get_wptr(ring) == gpu->funcs->get_rptr(gpu, ring));
72 		if (!empty && ring == a6xx_gpu->cur_ring)
73 			empty = ring->memptrs->fence == a6xx_gpu->last_seqno[i];
74 		spin_unlock_irqrestore(&ring->preempt_lock, flags);
75 
76 		if (!empty)
77 			return ring;
78 	}
79 
80 	return NULL;
81 }
82 
83