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