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