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