1*e7ae83daSAntonino Maniscalco // SPDX-License-Identifier: GPL-2.0 2*e7ae83daSAntonino Maniscalco /* Copyright (c) 2018, The Linux Foundation. All rights reserved. */ 3*e7ae83daSAntonino Maniscalco /* Copyright (c) 2023 Collabora, Ltd. */ 4*e7ae83daSAntonino Maniscalco /* Copyright (c) 2024 Valve Corporation */ 5*e7ae83daSAntonino Maniscalco 6*e7ae83daSAntonino Maniscalco #include "msm_gem.h" 7*e7ae83daSAntonino Maniscalco #include "a6xx_gpu.h" 8*e7ae83daSAntonino Maniscalco #include "a6xx_gmu.xml.h" 9*e7ae83daSAntonino Maniscalco #include "msm_mmu.h" 10*e7ae83daSAntonino Maniscalco 11*e7ae83daSAntonino Maniscalco /* 12*e7ae83daSAntonino Maniscalco * Try to transition the preemption state from old to new. Return 13*e7ae83daSAntonino Maniscalco * true on success or false if the original state wasn't 'old' 14*e7ae83daSAntonino Maniscalco */ 15*e7ae83daSAntonino Maniscalco static inline bool try_preempt_state(struct a6xx_gpu *a6xx_gpu, 16*e7ae83daSAntonino Maniscalco enum a6xx_preempt_state old, enum a6xx_preempt_state new) 17*e7ae83daSAntonino Maniscalco { 18*e7ae83daSAntonino Maniscalco enum a6xx_preempt_state cur = atomic_cmpxchg(&a6xx_gpu->preempt_state, 19*e7ae83daSAntonino Maniscalco old, new); 20*e7ae83daSAntonino Maniscalco 21*e7ae83daSAntonino Maniscalco return (cur == old); 22*e7ae83daSAntonino Maniscalco } 23*e7ae83daSAntonino Maniscalco 24*e7ae83daSAntonino Maniscalco /* 25*e7ae83daSAntonino Maniscalco * Force the preemption state to the specified state. This is used in cases 26*e7ae83daSAntonino Maniscalco * where the current state is known and won't change 27*e7ae83daSAntonino Maniscalco */ 28*e7ae83daSAntonino Maniscalco static inline void set_preempt_state(struct a6xx_gpu *gpu, 29*e7ae83daSAntonino Maniscalco enum a6xx_preempt_state new) 30*e7ae83daSAntonino Maniscalco { 31*e7ae83daSAntonino Maniscalco /* 32*e7ae83daSAntonino Maniscalco * preempt_state may be read by other cores trying to trigger a 33*e7ae83daSAntonino Maniscalco * preemption or in the interrupt handler so barriers are needed 34*e7ae83daSAntonino Maniscalco * before... 35*e7ae83daSAntonino Maniscalco */ 36*e7ae83daSAntonino Maniscalco smp_mb__before_atomic(); 37*e7ae83daSAntonino Maniscalco atomic_set(&gpu->preempt_state, new); 38*e7ae83daSAntonino Maniscalco /* ... and after*/ 39*e7ae83daSAntonino Maniscalco smp_mb__after_atomic(); 40*e7ae83daSAntonino Maniscalco } 41*e7ae83daSAntonino Maniscalco 42*e7ae83daSAntonino Maniscalco /* Write the most recent wptr for the given ring into the hardware */ 43*e7ae83daSAntonino Maniscalco static inline void update_wptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring) 44*e7ae83daSAntonino Maniscalco { 45*e7ae83daSAntonino Maniscalco unsigned long flags; 46*e7ae83daSAntonino Maniscalco uint32_t wptr; 47*e7ae83daSAntonino Maniscalco 48*e7ae83daSAntonino Maniscalco spin_lock_irqsave(&ring->preempt_lock, flags); 49*e7ae83daSAntonino Maniscalco 50*e7ae83daSAntonino Maniscalco if (ring->restore_wptr) { 51*e7ae83daSAntonino Maniscalco wptr = get_wptr(ring); 52*e7ae83daSAntonino Maniscalco 53*e7ae83daSAntonino Maniscalco gpu_write(gpu, REG_A6XX_CP_RB_WPTR, wptr); 54*e7ae83daSAntonino Maniscalco 55*e7ae83daSAntonino Maniscalco ring->restore_wptr = false; 56*e7ae83daSAntonino Maniscalco } 57*e7ae83daSAntonino Maniscalco 58*e7ae83daSAntonino Maniscalco spin_unlock_irqrestore(&ring->preempt_lock, flags); 59*e7ae83daSAntonino Maniscalco } 60*e7ae83daSAntonino Maniscalco 61*e7ae83daSAntonino Maniscalco /* Return the highest priority ringbuffer with something in it */ 62*e7ae83daSAntonino Maniscalco static struct msm_ringbuffer *get_next_ring(struct msm_gpu *gpu) 63*e7ae83daSAntonino Maniscalco { 64*e7ae83daSAntonino Maniscalco struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 65*e7ae83daSAntonino Maniscalco struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); 66*e7ae83daSAntonino Maniscalco 67*e7ae83daSAntonino Maniscalco unsigned long flags; 68*e7ae83daSAntonino Maniscalco int i; 69*e7ae83daSAntonino Maniscalco 70*e7ae83daSAntonino Maniscalco for (i = 0; i < gpu->nr_rings; i++) { 71*e7ae83daSAntonino Maniscalco bool empty; 72*e7ae83daSAntonino Maniscalco struct msm_ringbuffer *ring = gpu->rb[i]; 73*e7ae83daSAntonino Maniscalco 74*e7ae83daSAntonino Maniscalco spin_lock_irqsave(&ring->preempt_lock, flags); 75*e7ae83daSAntonino Maniscalco empty = (get_wptr(ring) == gpu->funcs->get_rptr(gpu, ring)); 76*e7ae83daSAntonino Maniscalco if (!empty && ring == a6xx_gpu->cur_ring) 77*e7ae83daSAntonino Maniscalco empty = ring->memptrs->fence == a6xx_gpu->last_seqno[i]; 78*e7ae83daSAntonino Maniscalco spin_unlock_irqrestore(&ring->preempt_lock, flags); 79*e7ae83daSAntonino Maniscalco 80*e7ae83daSAntonino Maniscalco if (!empty) 81*e7ae83daSAntonino Maniscalco return ring; 82*e7ae83daSAntonino Maniscalco } 83*e7ae83daSAntonino Maniscalco 84*e7ae83daSAntonino Maniscalco return NULL; 85*e7ae83daSAntonino Maniscalco } 86*e7ae83daSAntonino Maniscalco 87*e7ae83daSAntonino Maniscalco static void a6xx_preempt_timer(struct timer_list *t) 88*e7ae83daSAntonino Maniscalco { 89*e7ae83daSAntonino Maniscalco struct a6xx_gpu *a6xx_gpu = from_timer(a6xx_gpu, t, preempt_timer); 90*e7ae83daSAntonino Maniscalco struct msm_gpu *gpu = &a6xx_gpu->base.base; 91*e7ae83daSAntonino Maniscalco struct drm_device *dev = gpu->dev; 92*e7ae83daSAntonino Maniscalco 93*e7ae83daSAntonino Maniscalco if (!try_preempt_state(a6xx_gpu, PREEMPT_TRIGGERED, PREEMPT_FAULTED)) 94*e7ae83daSAntonino Maniscalco return; 95*e7ae83daSAntonino Maniscalco 96*e7ae83daSAntonino Maniscalco dev_err(dev->dev, "%s: preemption timed out\n", gpu->name); 97*e7ae83daSAntonino Maniscalco kthread_queue_work(gpu->worker, &gpu->recover_work); 98*e7ae83daSAntonino Maniscalco } 99*e7ae83daSAntonino Maniscalco 100*e7ae83daSAntonino Maniscalco void a6xx_preempt_irq(struct msm_gpu *gpu) 101*e7ae83daSAntonino Maniscalco { 102*e7ae83daSAntonino Maniscalco uint32_t status; 103*e7ae83daSAntonino Maniscalco struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 104*e7ae83daSAntonino Maniscalco struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); 105*e7ae83daSAntonino Maniscalco struct drm_device *dev = gpu->dev; 106*e7ae83daSAntonino Maniscalco 107*e7ae83daSAntonino Maniscalco if (!try_preempt_state(a6xx_gpu, PREEMPT_TRIGGERED, PREEMPT_PENDING)) 108*e7ae83daSAntonino Maniscalco return; 109*e7ae83daSAntonino Maniscalco 110*e7ae83daSAntonino Maniscalco /* Delete the preemption watchdog timer */ 111*e7ae83daSAntonino Maniscalco del_timer(&a6xx_gpu->preempt_timer); 112*e7ae83daSAntonino Maniscalco 113*e7ae83daSAntonino Maniscalco /* 114*e7ae83daSAntonino Maniscalco * The hardware should be setting the stop bit of CP_CONTEXT_SWITCH_CNTL 115*e7ae83daSAntonino Maniscalco * to zero before firing the interrupt, but there is a non zero chance 116*e7ae83daSAntonino Maniscalco * of a hardware condition or a software race that could set it again 117*e7ae83daSAntonino Maniscalco * before we have a chance to finish. If that happens, log and go for 118*e7ae83daSAntonino Maniscalco * recovery 119*e7ae83daSAntonino Maniscalco */ 120*e7ae83daSAntonino Maniscalco status = gpu_read(gpu, REG_A6XX_CP_CONTEXT_SWITCH_CNTL); 121*e7ae83daSAntonino Maniscalco if (unlikely(status & A6XX_CP_CONTEXT_SWITCH_CNTL_STOP)) { 122*e7ae83daSAntonino Maniscalco DRM_DEV_ERROR(&gpu->pdev->dev, 123*e7ae83daSAntonino Maniscalco "!!!!!!!!!!!!!!!! preemption faulted !!!!!!!!!!!!!! irq\n"); 124*e7ae83daSAntonino Maniscalco set_preempt_state(a6xx_gpu, PREEMPT_FAULTED); 125*e7ae83daSAntonino Maniscalco dev_err(dev->dev, "%s: Preemption failed to complete\n", 126*e7ae83daSAntonino Maniscalco gpu->name); 127*e7ae83daSAntonino Maniscalco kthread_queue_work(gpu->worker, &gpu->recover_work); 128*e7ae83daSAntonino Maniscalco return; 129*e7ae83daSAntonino Maniscalco } 130*e7ae83daSAntonino Maniscalco 131*e7ae83daSAntonino Maniscalco a6xx_gpu->cur_ring = a6xx_gpu->next_ring; 132*e7ae83daSAntonino Maniscalco a6xx_gpu->next_ring = NULL; 133*e7ae83daSAntonino Maniscalco 134*e7ae83daSAntonino Maniscalco set_preempt_state(a6xx_gpu, PREEMPT_FINISH); 135*e7ae83daSAntonino Maniscalco 136*e7ae83daSAntonino Maniscalco update_wptr(gpu, a6xx_gpu->cur_ring); 137*e7ae83daSAntonino Maniscalco 138*e7ae83daSAntonino Maniscalco set_preempt_state(a6xx_gpu, PREEMPT_NONE); 139*e7ae83daSAntonino Maniscalco 140*e7ae83daSAntonino Maniscalco /* 141*e7ae83daSAntonino Maniscalco * Retrigger preemption to avoid a deadlock that might occur when preemption 142*e7ae83daSAntonino Maniscalco * is skipped due to it being already in flight when requested. 143*e7ae83daSAntonino Maniscalco */ 144*e7ae83daSAntonino Maniscalco a6xx_preempt_trigger(gpu); 145*e7ae83daSAntonino Maniscalco } 146*e7ae83daSAntonino Maniscalco 147*e7ae83daSAntonino Maniscalco void a6xx_preempt_hw_init(struct msm_gpu *gpu) 148*e7ae83daSAntonino Maniscalco { 149*e7ae83daSAntonino Maniscalco struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 150*e7ae83daSAntonino Maniscalco struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); 151*e7ae83daSAntonino Maniscalco int i; 152*e7ae83daSAntonino Maniscalco 153*e7ae83daSAntonino Maniscalco /* No preemption if we only have one ring */ 154*e7ae83daSAntonino Maniscalco if (gpu->nr_rings == 1) 155*e7ae83daSAntonino Maniscalco return; 156*e7ae83daSAntonino Maniscalco 157*e7ae83daSAntonino Maniscalco for (i = 0; i < gpu->nr_rings; i++) { 158*e7ae83daSAntonino Maniscalco struct a6xx_preempt_record *record_ptr = a6xx_gpu->preempt[i]; 159*e7ae83daSAntonino Maniscalco 160*e7ae83daSAntonino Maniscalco record_ptr->wptr = 0; 161*e7ae83daSAntonino Maniscalco record_ptr->rptr = 0; 162*e7ae83daSAntonino Maniscalco record_ptr->rptr_addr = shadowptr(a6xx_gpu, gpu->rb[i]); 163*e7ae83daSAntonino Maniscalco record_ptr->info = 0; 164*e7ae83daSAntonino Maniscalco record_ptr->data = 0; 165*e7ae83daSAntonino Maniscalco record_ptr->rbase = gpu->rb[i]->iova; 166*e7ae83daSAntonino Maniscalco } 167*e7ae83daSAntonino Maniscalco 168*e7ae83daSAntonino Maniscalco /* Write a 0 to signal that we aren't switching pagetables */ 169*e7ae83daSAntonino Maniscalco gpu_write64(gpu, REG_A6XX_CP_CONTEXT_SWITCH_SMMU_INFO, 0); 170*e7ae83daSAntonino Maniscalco 171*e7ae83daSAntonino Maniscalco /* Enable the GMEM save/restore feature for preemption */ 172*e7ae83daSAntonino Maniscalco gpu_write(gpu, REG_A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE, 0x1); 173*e7ae83daSAntonino Maniscalco 174*e7ae83daSAntonino Maniscalco /* Reset the preemption state */ 175*e7ae83daSAntonino Maniscalco set_preempt_state(a6xx_gpu, PREEMPT_NONE); 176*e7ae83daSAntonino Maniscalco 177*e7ae83daSAntonino Maniscalco spin_lock_init(&a6xx_gpu->eval_lock); 178*e7ae83daSAntonino Maniscalco 179*e7ae83daSAntonino Maniscalco /* Always come up on rb 0 */ 180*e7ae83daSAntonino Maniscalco a6xx_gpu->cur_ring = gpu->rb[0]; 181*e7ae83daSAntonino Maniscalco } 182*e7ae83daSAntonino Maniscalco 183*e7ae83daSAntonino Maniscalco void a6xx_preempt_trigger(struct msm_gpu *gpu) 184*e7ae83daSAntonino Maniscalco { 185*e7ae83daSAntonino Maniscalco struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 186*e7ae83daSAntonino Maniscalco struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); 187*e7ae83daSAntonino Maniscalco unsigned long flags; 188*e7ae83daSAntonino Maniscalco struct msm_ringbuffer *ring; 189*e7ae83daSAntonino Maniscalco unsigned int cntl; 190*e7ae83daSAntonino Maniscalco 191*e7ae83daSAntonino Maniscalco if (gpu->nr_rings == 1) 192*e7ae83daSAntonino Maniscalco return; 193*e7ae83daSAntonino Maniscalco 194*e7ae83daSAntonino Maniscalco /* 195*e7ae83daSAntonino Maniscalco * Lock to make sure another thread attempting preemption doesn't skip it 196*e7ae83daSAntonino Maniscalco * while we are still evaluating the next ring. This makes sure the other 197*e7ae83daSAntonino Maniscalco * thread does start preemption if we abort it and avoids a soft lock. 198*e7ae83daSAntonino Maniscalco */ 199*e7ae83daSAntonino Maniscalco spin_lock_irqsave(&a6xx_gpu->eval_lock, flags); 200*e7ae83daSAntonino Maniscalco 201*e7ae83daSAntonino Maniscalco /* 202*e7ae83daSAntonino Maniscalco * Try to start preemption by moving from NONE to START. If 203*e7ae83daSAntonino Maniscalco * unsuccessful, a preemption is already in flight 204*e7ae83daSAntonino Maniscalco */ 205*e7ae83daSAntonino Maniscalco if (!try_preempt_state(a6xx_gpu, PREEMPT_NONE, PREEMPT_START)) { 206*e7ae83daSAntonino Maniscalco spin_unlock_irqrestore(&a6xx_gpu->eval_lock, flags); 207*e7ae83daSAntonino Maniscalco return; 208*e7ae83daSAntonino Maniscalco } 209*e7ae83daSAntonino Maniscalco 210*e7ae83daSAntonino Maniscalco cntl = A6XX_CP_CONTEXT_SWITCH_CNTL_LEVEL(a6xx_gpu->preempt_level); 211*e7ae83daSAntonino Maniscalco 212*e7ae83daSAntonino Maniscalco if (a6xx_gpu->skip_save_restore) 213*e7ae83daSAntonino Maniscalco cntl |= A6XX_CP_CONTEXT_SWITCH_CNTL_SKIP_SAVE_RESTORE; 214*e7ae83daSAntonino Maniscalco 215*e7ae83daSAntonino Maniscalco if (a6xx_gpu->uses_gmem) 216*e7ae83daSAntonino Maniscalco cntl |= A6XX_CP_CONTEXT_SWITCH_CNTL_USES_GMEM; 217*e7ae83daSAntonino Maniscalco 218*e7ae83daSAntonino Maniscalco cntl |= A6XX_CP_CONTEXT_SWITCH_CNTL_STOP; 219*e7ae83daSAntonino Maniscalco 220*e7ae83daSAntonino Maniscalco /* Get the next ring to preempt to */ 221*e7ae83daSAntonino Maniscalco ring = get_next_ring(gpu); 222*e7ae83daSAntonino Maniscalco 223*e7ae83daSAntonino Maniscalco /* 224*e7ae83daSAntonino Maniscalco * If no ring is populated or the highest priority ring is the current 225*e7ae83daSAntonino Maniscalco * one do nothing except to update the wptr to the latest and greatest 226*e7ae83daSAntonino Maniscalco */ 227*e7ae83daSAntonino Maniscalco if (!ring || (a6xx_gpu->cur_ring == ring)) { 228*e7ae83daSAntonino Maniscalco set_preempt_state(a6xx_gpu, PREEMPT_FINISH); 229*e7ae83daSAntonino Maniscalco update_wptr(gpu, a6xx_gpu->cur_ring); 230*e7ae83daSAntonino Maniscalco set_preempt_state(a6xx_gpu, PREEMPT_NONE); 231*e7ae83daSAntonino Maniscalco spin_unlock_irqrestore(&a6xx_gpu->eval_lock, flags); 232*e7ae83daSAntonino Maniscalco return; 233*e7ae83daSAntonino Maniscalco } 234*e7ae83daSAntonino Maniscalco 235*e7ae83daSAntonino Maniscalco spin_unlock_irqrestore(&a6xx_gpu->eval_lock, flags); 236*e7ae83daSAntonino Maniscalco 237*e7ae83daSAntonino Maniscalco spin_lock_irqsave(&ring->preempt_lock, flags); 238*e7ae83daSAntonino Maniscalco 239*e7ae83daSAntonino Maniscalco struct a7xx_cp_smmu_info *smmu_info_ptr = 240*e7ae83daSAntonino Maniscalco a6xx_gpu->preempt_smmu[ring->id]; 241*e7ae83daSAntonino Maniscalco struct a6xx_preempt_record *record_ptr = a6xx_gpu->preempt[ring->id]; 242*e7ae83daSAntonino Maniscalco u64 ttbr0 = ring->memptrs->ttbr0; 243*e7ae83daSAntonino Maniscalco u32 context_idr = ring->memptrs->context_idr; 244*e7ae83daSAntonino Maniscalco 245*e7ae83daSAntonino Maniscalco smmu_info_ptr->ttbr0 = ttbr0; 246*e7ae83daSAntonino Maniscalco smmu_info_ptr->context_idr = context_idr; 247*e7ae83daSAntonino Maniscalco record_ptr->wptr = get_wptr(ring); 248*e7ae83daSAntonino Maniscalco 249*e7ae83daSAntonino Maniscalco /* 250*e7ae83daSAntonino Maniscalco * The GPU will write the wptr we set above when we preempt. Reset 251*e7ae83daSAntonino Maniscalco * restore_wptr to make sure that we don't write WPTR to the same 252*e7ae83daSAntonino Maniscalco * thing twice. It's still possible subsequent submissions will update 253*e7ae83daSAntonino Maniscalco * wptr again, in which case they will set the flag to true. This has 254*e7ae83daSAntonino Maniscalco * to be protected by the lock for setting the flag and updating wptr 255*e7ae83daSAntonino Maniscalco * to be atomic. 256*e7ae83daSAntonino Maniscalco */ 257*e7ae83daSAntonino Maniscalco ring->restore_wptr = false; 258*e7ae83daSAntonino Maniscalco 259*e7ae83daSAntonino Maniscalco spin_unlock_irqrestore(&ring->preempt_lock, flags); 260*e7ae83daSAntonino Maniscalco 261*e7ae83daSAntonino Maniscalco gpu_write64(gpu, 262*e7ae83daSAntonino Maniscalco REG_A6XX_CP_CONTEXT_SWITCH_SMMU_INFO, 263*e7ae83daSAntonino Maniscalco a6xx_gpu->preempt_smmu_iova[ring->id]); 264*e7ae83daSAntonino Maniscalco 265*e7ae83daSAntonino Maniscalco gpu_write64(gpu, 266*e7ae83daSAntonino Maniscalco REG_A6XX_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR, 267*e7ae83daSAntonino Maniscalco a6xx_gpu->preempt_iova[ring->id]); 268*e7ae83daSAntonino Maniscalco 269*e7ae83daSAntonino Maniscalco a6xx_gpu->next_ring = ring; 270*e7ae83daSAntonino Maniscalco 271*e7ae83daSAntonino Maniscalco /* Start a timer to catch a stuck preemption */ 272*e7ae83daSAntonino Maniscalco mod_timer(&a6xx_gpu->preempt_timer, jiffies + msecs_to_jiffies(10000)); 273*e7ae83daSAntonino Maniscalco 274*e7ae83daSAntonino Maniscalco /* Set the preemption state to triggered */ 275*e7ae83daSAntonino Maniscalco set_preempt_state(a6xx_gpu, PREEMPT_TRIGGERED); 276*e7ae83daSAntonino Maniscalco 277*e7ae83daSAntonino Maniscalco /* Trigger the preemption */ 278*e7ae83daSAntonino Maniscalco gpu_write(gpu, REG_A6XX_CP_CONTEXT_SWITCH_CNTL, cntl); 279*e7ae83daSAntonino Maniscalco } 280*e7ae83daSAntonino Maniscalco 281*e7ae83daSAntonino Maniscalco static int preempt_init_ring(struct a6xx_gpu *a6xx_gpu, 282*e7ae83daSAntonino Maniscalco struct msm_ringbuffer *ring) 283*e7ae83daSAntonino Maniscalco { 284*e7ae83daSAntonino Maniscalco struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; 285*e7ae83daSAntonino Maniscalco struct msm_gpu *gpu = &adreno_gpu->base; 286*e7ae83daSAntonino Maniscalco struct drm_gem_object *bo = NULL; 287*e7ae83daSAntonino Maniscalco phys_addr_t ttbr; 288*e7ae83daSAntonino Maniscalco u64 iova = 0; 289*e7ae83daSAntonino Maniscalco void *ptr; 290*e7ae83daSAntonino Maniscalco int asid; 291*e7ae83daSAntonino Maniscalco 292*e7ae83daSAntonino Maniscalco ptr = msm_gem_kernel_new(gpu->dev, 293*e7ae83daSAntonino Maniscalco PREEMPT_RECORD_SIZE(adreno_gpu), 294*e7ae83daSAntonino Maniscalco MSM_BO_WC | MSM_BO_MAP_PRIV, gpu->aspace, &bo, &iova); 295*e7ae83daSAntonino Maniscalco 296*e7ae83daSAntonino Maniscalco if (IS_ERR(ptr)) 297*e7ae83daSAntonino Maniscalco return PTR_ERR(ptr); 298*e7ae83daSAntonino Maniscalco 299*e7ae83daSAntonino Maniscalco memset(ptr, 0, PREEMPT_RECORD_SIZE(adreno_gpu)); 300*e7ae83daSAntonino Maniscalco 301*e7ae83daSAntonino Maniscalco msm_gem_object_set_name(bo, "preempt_record ring%d", ring->id); 302*e7ae83daSAntonino Maniscalco 303*e7ae83daSAntonino Maniscalco a6xx_gpu->preempt_bo[ring->id] = bo; 304*e7ae83daSAntonino Maniscalco a6xx_gpu->preempt_iova[ring->id] = iova; 305*e7ae83daSAntonino Maniscalco a6xx_gpu->preempt[ring->id] = ptr; 306*e7ae83daSAntonino Maniscalco 307*e7ae83daSAntonino Maniscalco struct a6xx_preempt_record *record_ptr = ptr; 308*e7ae83daSAntonino Maniscalco 309*e7ae83daSAntonino Maniscalco ptr = msm_gem_kernel_new(gpu->dev, 310*e7ae83daSAntonino Maniscalco PREEMPT_SMMU_INFO_SIZE, 311*e7ae83daSAntonino Maniscalco MSM_BO_WC | MSM_BO_MAP_PRIV | MSM_BO_GPU_READONLY, 312*e7ae83daSAntonino Maniscalco gpu->aspace, &bo, &iova); 313*e7ae83daSAntonino Maniscalco 314*e7ae83daSAntonino Maniscalco if (IS_ERR(ptr)) 315*e7ae83daSAntonino Maniscalco return PTR_ERR(ptr); 316*e7ae83daSAntonino Maniscalco 317*e7ae83daSAntonino Maniscalco memset(ptr, 0, PREEMPT_SMMU_INFO_SIZE); 318*e7ae83daSAntonino Maniscalco 319*e7ae83daSAntonino Maniscalco msm_gem_object_set_name(bo, "preempt_smmu_info ring%d", ring->id); 320*e7ae83daSAntonino Maniscalco 321*e7ae83daSAntonino Maniscalco a6xx_gpu->preempt_smmu_bo[ring->id] = bo; 322*e7ae83daSAntonino Maniscalco a6xx_gpu->preempt_smmu_iova[ring->id] = iova; 323*e7ae83daSAntonino Maniscalco a6xx_gpu->preempt_smmu[ring->id] = ptr; 324*e7ae83daSAntonino Maniscalco 325*e7ae83daSAntonino Maniscalco struct a7xx_cp_smmu_info *smmu_info_ptr = ptr; 326*e7ae83daSAntonino Maniscalco 327*e7ae83daSAntonino Maniscalco msm_iommu_pagetable_params(gpu->aspace->mmu, &ttbr, &asid); 328*e7ae83daSAntonino Maniscalco 329*e7ae83daSAntonino Maniscalco smmu_info_ptr->magic = GEN7_CP_SMMU_INFO_MAGIC; 330*e7ae83daSAntonino Maniscalco smmu_info_ptr->ttbr0 = ttbr; 331*e7ae83daSAntonino Maniscalco smmu_info_ptr->asid = 0xdecafbad; 332*e7ae83daSAntonino Maniscalco smmu_info_ptr->context_idr = 0; 333*e7ae83daSAntonino Maniscalco 334*e7ae83daSAntonino Maniscalco /* Set up the defaults on the preemption record */ 335*e7ae83daSAntonino Maniscalco record_ptr->magic = A6XX_PREEMPT_RECORD_MAGIC; 336*e7ae83daSAntonino Maniscalco record_ptr->info = 0; 337*e7ae83daSAntonino Maniscalco record_ptr->data = 0; 338*e7ae83daSAntonino Maniscalco record_ptr->rptr = 0; 339*e7ae83daSAntonino Maniscalco record_ptr->wptr = 0; 340*e7ae83daSAntonino Maniscalco record_ptr->cntl = MSM_GPU_RB_CNTL_DEFAULT; 341*e7ae83daSAntonino Maniscalco record_ptr->rbase = ring->iova; 342*e7ae83daSAntonino Maniscalco record_ptr->counter = 0; 343*e7ae83daSAntonino Maniscalco record_ptr->bv_rptr_addr = rbmemptr(ring, bv_rptr); 344*e7ae83daSAntonino Maniscalco 345*e7ae83daSAntonino Maniscalco return 0; 346*e7ae83daSAntonino Maniscalco } 347*e7ae83daSAntonino Maniscalco 348*e7ae83daSAntonino Maniscalco void a6xx_preempt_fini(struct msm_gpu *gpu) 349*e7ae83daSAntonino Maniscalco { 350*e7ae83daSAntonino Maniscalco struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 351*e7ae83daSAntonino Maniscalco struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); 352*e7ae83daSAntonino Maniscalco int i; 353*e7ae83daSAntonino Maniscalco 354*e7ae83daSAntonino Maniscalco for (i = 0; i < gpu->nr_rings; i++) 355*e7ae83daSAntonino Maniscalco msm_gem_kernel_put(a6xx_gpu->preempt_bo[i], gpu->aspace); 356*e7ae83daSAntonino Maniscalco } 357*e7ae83daSAntonino Maniscalco 358*e7ae83daSAntonino Maniscalco void a6xx_preempt_init(struct msm_gpu *gpu) 359*e7ae83daSAntonino Maniscalco { 360*e7ae83daSAntonino Maniscalco struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 361*e7ae83daSAntonino Maniscalco struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); 362*e7ae83daSAntonino Maniscalco int i; 363*e7ae83daSAntonino Maniscalco 364*e7ae83daSAntonino Maniscalco /* No preemption if we only have one ring */ 365*e7ae83daSAntonino Maniscalco if (gpu->nr_rings <= 1) 366*e7ae83daSAntonino Maniscalco return; 367*e7ae83daSAntonino Maniscalco 368*e7ae83daSAntonino Maniscalco for (i = 0; i < gpu->nr_rings; i++) { 369*e7ae83daSAntonino Maniscalco if (preempt_init_ring(a6xx_gpu, gpu->rb[i])) 370*e7ae83daSAntonino Maniscalco goto fail; 371*e7ae83daSAntonino Maniscalco } 372*e7ae83daSAntonino Maniscalco 373*e7ae83daSAntonino Maniscalco /* TODO: make this configurable? */ 374*e7ae83daSAntonino Maniscalco a6xx_gpu->preempt_level = 1; 375*e7ae83daSAntonino Maniscalco a6xx_gpu->uses_gmem = 1; 376*e7ae83daSAntonino Maniscalco a6xx_gpu->skip_save_restore = 1; 377*e7ae83daSAntonino Maniscalco 378*e7ae83daSAntonino Maniscalco timer_setup(&a6xx_gpu->preempt_timer, a6xx_preempt_timer, 0); 379*e7ae83daSAntonino Maniscalco 380*e7ae83daSAntonino Maniscalco return; 381*e7ae83daSAntonino Maniscalco fail: 382*e7ae83daSAntonino Maniscalco /* 383*e7ae83daSAntonino Maniscalco * On any failure our adventure is over. Clean up and 384*e7ae83daSAntonino Maniscalco * set nr_rings to 1 to force preemption off 385*e7ae83daSAntonino Maniscalco */ 386*e7ae83daSAntonino Maniscalco a6xx_preempt_fini(gpu); 387*e7ae83daSAntonino Maniscalco gpu->nr_rings = 1; 388*e7ae83daSAntonino Maniscalco 389*e7ae83daSAntonino Maniscalco DRM_DEV_ERROR(&gpu->pdev->dev, 390*e7ae83daSAntonino Maniscalco "preemption init failed, disabling preemption\n"); 391*e7ae83daSAntonino Maniscalco 392*e7ae83daSAntonino Maniscalco return; 393*e7ae83daSAntonino Maniscalco } 394