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