diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index be764b6802b5..816d8817f0b2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -973,24 +973,3 @@ int amdgpu_amdkfd_reset_mes_queue(struct amdgpu_device *adev, return kgd2kfd_reset_mes_queue(adev->kfd.dev, node_id, queue_type, pipe, queue, db); } - -int amdgpu_amdkfd_evict_svm_bo(struct amdgpu_bo *bo) -{ - struct dma_resv_iter cursor; - struct dma_fence *fence; - int r = 0; - - dma_resv_iter_begin(&cursor, bo->tbo.base.resv, DMA_RESV_USAGE_BOOKKEEP); - dma_resv_for_each_fence_unlocked(&cursor, fence) { - struct amdgpu_amdkfd_fence *f = to_amdgpu_amdkfd_fence(fence); - - if (f && f->svm_bo) { - r = svm_range_evict_svm_bo(f->svm_bo); - if (r) - break; - } - } - dma_resv_iter_end(&cursor); - - return r; -} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index b4840ee36f2b..1b7dc0d3963b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -99,7 +99,6 @@ struct amdgpu_amdkfd_fence { struct mm_struct *mm; spinlock_t lock; char timeline_name[TASK_COMM_LEN]; - struct svm_range_bo *svm_bo; uint16_t context_id; }; @@ -194,7 +193,6 @@ int amdgpu_queue_mask_bit_to_set_resource_bit(struct amdgpu_device *adev, struct amdgpu_amdkfd_fence *amdgpu_amdkfd_fence_create(u64 context, struct mm_struct *mm, - struct svm_range_bo *svm_bo, u16 context_id); int amdgpu_amdkfd_drm_client_create(struct amdgpu_device *adev); @@ -286,7 +284,6 @@ int amdgpu_amdkfd_reset_mes_queue(struct amdgpu_device *adev, int queue_type, int pipe, int queue, unsigned int db); -int amdgpu_amdkfd_evict_svm_bo(struct amdgpu_bo *bo); /* Read user wptr from a specified user address space with page fault * disabled. The memory must be pinned and mapped to the hardware when diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c index 553d26c2744e..9b10d015671c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c @@ -62,7 +62,6 @@ static atomic_t fence_seq = ATOMIC_INIT(0); struct amdgpu_amdkfd_fence *amdgpu_amdkfd_fence_create(u64 context, struct mm_struct *mm, - struct svm_range_bo *svm_bo, u16 context_id) { struct amdgpu_amdkfd_fence *fence; @@ -76,7 +75,6 @@ struct amdgpu_amdkfd_fence *amdgpu_amdkfd_fence_create(u64 context, fence->mm = mm; get_task_comm(fence->timeline_name, current); spin_lock_init(&fence->lock); - fence->svm_bo = svm_bo; fence->context_id = context_id; dma_fence_init(&fence->base, &amdkfd_fence_ops, &fence->lock, context, atomic_inc_return(&fence_seq)); @@ -128,14 +126,8 @@ static bool amdkfd_fence_enable_signaling(struct dma_fence *f) if (dma_fence_is_signaled(f)) return true; - /* if fence->svm_bo is NULL, means this fence is created through - * init_kfd_vm() or amdgpu_amdkfd_gpuvm_restore_process_bos(). - * Therefore, this fence is amdgpu_amdkfd_fence->eviction_fence. - */ - if (!fence->svm_bo) { - if (!kgd2kfd_schedule_evict_and_restore_process(fence->mm, fence->context_id, f)) - return true; - } + if (!kgd2kfd_schedule_evict_and_restore_process(fence->mm, fence->context_id, f)) + return true; return false; } @@ -169,7 +161,6 @@ static void amdkfd_fence_release(struct dma_fence *f) * * Check if @mm is same as that of the fence @f, if same return TRUE else * return FALSE. - * For svm bo, which support vram overcommitment, always return FALSE. */ bool amdkfd_fence_check_mm(struct dma_fence *f, struct mm_struct *mm) { @@ -177,7 +168,7 @@ bool amdkfd_fence_check_mm(struct dma_fence *f, struct mm_struct *mm) if (!fence) return false; - else if (fence->mm == mm && !fence->svm_bo) + else if (fence->mm == mm) return true; return false; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index 1217fb516807..34481ee7065a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -1423,7 +1423,7 @@ static int init_kfd_vm(struct amdgpu_vm *vm, void **process_info, info->eviction_fence = amdgpu_amdkfd_fence_create(dma_fence_context_alloc(1), current->mm, - NULL, process->context_id); + process->context_id); if (!info->eviction_fence) { pr_err("Failed to create eviction fence\n"); ret = -ENOMEM; @@ -3093,7 +3093,7 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence __rcu * amdgpu_amdkfd_fence_create( process_info->eviction_fence->base.context, process_info->eviction_fence->mm, - NULL, process_info->context_id); + process_info->context_id); if (!new_fence) { pr_err("Failed to create eviction fence\n"); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c index 9d3b40c385c9..4d21d83451a4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c @@ -34,6 +34,7 @@ #include "amdgpu_xcp.h" #include "amdgpu_xgmi.h" #include "amdgpu_mes.h" +#include "amdgpu_userq.h" #include "mes_userqueue.h" #include "nvd.h" @@ -419,8 +420,8 @@ int amdgpu_gfx_mqd_sw_init(struct amdgpu_device *adev, domain |= AMDGPU_GEM_DOMAIN_VRAM; #endif - /* create MQD for KIQ */ - if (!adev->enable_mes_kiq && !ring->mqd_obj) { + /* create MQD for KIQ (on GFX8+ where we use KIQ) */ + if (adev->asic_type >= CHIP_TOPAZ && !adev->enable_mes_kiq && !ring->mqd_obj) { /* originaly the KIQ MQD is put in GTT domain, but for SRIOV VRAM domain is a must * otherwise hypervisor trigger SAVE_VF fail after driver unloaded which mean MQD * deallocated and gart_unbind, to strict diverage we decide to use VRAM domain for @@ -855,6 +856,59 @@ int amdgpu_gfx_enable_kgq(struct amdgpu_device *adev, int xcc_id) return r; } +/** + * amdgpu_gfx_handle_priv_fault - Handle privileged instruction fault + * + * @adev: amdgpu_device pointer + * @entry: interrupt vector entry containing fault information + * @me_id: micro-engine ID of the faulty ring + * @pipe_id: pipe ID of the faulty ring + * @queue_id: queue ID of the faulty ring + * + * This function handles privileged instruction faults by identifying + * the faulty ring (gfx or compute) and triggering a scheduler fault + */ +void amdgpu_gfx_handle_priv_fault(struct amdgpu_device *adev, + struct amdgpu_iv_entry *entry, + u8 me_id, u8 pipe_id, u8 queue_id) +{ + struct amdgpu_ring *ring; + u32 doorbell_offset; + int i; + + /* + * Try KQ first by ring_id (HW slot is authoritative). The + * KMD compute_hqd_mask contract guarantees KCQ and user queues + * never share a HW slot. + */ + if (!adev->gfx.disable_kq) { + for (i = 0; i < adev->gfx.num_gfx_rings; i++) { + ring = &adev->gfx.gfx_ring[i]; + if (ring->me == me_id && ring->pipe == pipe_id && + ring->queue == queue_id) { + drm_sched_fault(&ring->sched); + return; + } + } + + for (i = 0; i < adev->gfx.num_compute_rings; i++) { + ring = &adev->gfx.compute_ring[i]; + if (ring->me == me_id && ring->pipe == pipe_id && + ring->queue == queue_id) { + drm_sched_fault(&ring->sched); + return; + } + } + } + + doorbell_offset = entry->src_data[0] & AMDGPU_CTXID0_DOORBELL_ID_MASK; + + /* No KQ matched: HW slot is a MES-scheduled user queue. */ + if (adev->enable_mes && doorbell_offset) + amdgpu_userq_process_reset_irq(adev, entry->pasid, + doorbell_offset); +} + static void amdgpu_gfx_do_off_ctrl(struct amdgpu_device *adev, bool enable, bool no_delay) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h index aefd4f03b443..c15f45a7347c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h @@ -620,6 +620,9 @@ bool amdgpu_gfx_is_high_priority_graphics_queue(struct amdgpu_device *adev, struct amdgpu_ring *ring); bool amdgpu_gfx_is_me_queue_enabled(struct amdgpu_device *adev, int me, int pipe, int queue); +void amdgpu_gfx_handle_priv_fault(struct amdgpu_device *adev, + struct amdgpu_iv_entry *entry, + u8 me_id, u8 pipe_id, u8 queue_id); void amdgpu_gfx_off_ctrl(struct amdgpu_device *adev, bool enable); void amdgpu_gfx_off_ctrl_immediate(struct amdgpu_device *adev, bool enable); int amdgpu_get_gfx_off_status(struct amdgpu_device *adev, uint32_t *value); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index d4a9d5e8fb42..5d9d137209b6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -43,6 +43,7 @@ #include "amdgpu_vram_mgr.h" #include "amdgpu_vm.h" #include "amdgpu_dma_buf.h" +#include "kfd_svm.h" /** * DOC: amdgpu_object @@ -93,7 +94,8 @@ static void amdgpu_bo_user_destroy(struct ttm_buffer_object *tbo) bool amdgpu_bo_is_amdgpu_bo(struct ttm_buffer_object *bo) { if (bo->destroy == &amdgpu_bo_destroy || - bo->destroy == &amdgpu_bo_user_destroy) + bo->destroy == &amdgpu_bo_user_destroy || + bo->destroy == &svm_range_bo_destroy) return true; return false; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 91b7bf6e65f5..c4094edbdff1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -60,6 +60,7 @@ #include "amdgpu_atomfirmware.h" #include "amdgpu_res_cursor.h" #include "bif/bif_4_1_d.h" +#include "kfd_svm.h" MODULE_IMPORT_NS("DMA_BUF"); @@ -1499,7 +1500,8 @@ static bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo, return true; abo = ttm_to_amdgpu_bo(bo); - if (abo->flags & AMDGPU_GEM_CREATE_DISCARDABLE) { + if ((abo->flags & AMDGPU_GEM_CREATE_DISCARDABLE) && + bo->destroy == &svm_range_bo_destroy) { /* * SVM BOs are migrated to system memory synchronously in this * TTM eviction context. The migration needs the owning @@ -1509,7 +1511,7 @@ static bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo, * if the eviction fails for any reason, we return false so TTM * skips this BO instead of risking a deadlock. */ - if (amdgpu_amdkfd_evict_svm_bo(abo) < 0) + if (svm_range_evict_svm_bo(abo) < 0) return false; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index aac8ace9d7a6..4c90e88e2e30 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -892,7 +892,12 @@ void amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, amdgpu_ring_patch_cond_exec(ring, patch); - /* the double SWITCH_BUFFER here *cannot* be skipped by COND_EXEC */ + /* + * Sync CE with ME to prevent CE from fetching the next CE IB + * before the context switch is done. This is emitted before + * the first IB of a job submission after a context switch. + * The double SWITCH_BUFFER here *cannot* be skipped by COND_EXEC. + */ if (ring->funcs->emit_switch_buffer) { amdgpu_ring_emit_switch_buffer(ring); amdgpu_ring_emit_switch_buffer(ring); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index 3b203961abb9..9faf31421a15 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -6714,51 +6714,13 @@ static int gfx_v11_0_set_priv_inst_fault_state(struct amdgpu_device *adev, static void gfx_v11_0_handle_priv_fault(struct amdgpu_device *adev, struct amdgpu_iv_entry *entry) { - u32 doorbell_offset = entry->src_data[0] & AMDGPU_CTXID0_DOORBELL_ID_MASK; + u8 me_id, pipe_id, queue_id; - /* - * Try KQ first by ring_id (HW slot is authoritative). The - * KMD compute_hqd_mask contract guarantees KCQ and user queues - * never share a HW slot. - */ - if (!adev->gfx.disable_kq) { - u8 me_id = (entry->ring_id & 0x0c) >> 2; - u8 pipe_id = (entry->ring_id & 0x03) >> 0; - u8 queue_id = (entry->ring_id & 0x70) >> 4; - struct amdgpu_ring *ring; - int i; + me_id = (entry->ring_id & 0x0c) >> 2; + pipe_id = (entry->ring_id & 0x03) >> 0; + queue_id = (entry->ring_id & 0x70) >> 4; - switch (me_id) { - case 0: - for (i = 0; i < adev->gfx.num_gfx_rings; i++) { - ring = &adev->gfx.gfx_ring[i]; - if (ring->me == me_id && ring->pipe == pipe_id && - ring->queue == queue_id) { - drm_sched_fault(&ring->sched); - return; - } - } - break; - case 1: - case 2: - for (i = 0; i < adev->gfx.num_compute_rings; i++) { - ring = &adev->gfx.compute_ring[i]; - if (ring->me == me_id && ring->pipe == pipe_id && - ring->queue == queue_id) { - drm_sched_fault(&ring->sched); - return; - } - } - break; - default: - break; - } - } - - /* No KQ matched: HW slot is a MES-scheduled user queue. */ - if (adev->enable_mes && doorbell_offset) - amdgpu_userq_process_reset_irq(adev, entry->pasid, - doorbell_offset); + amdgpu_gfx_handle_priv_fault(adev, entry, me_id, pipe_id, queue_id); } static int gfx_v11_0_priv_reg_irq(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c index 5f0a24951f4a..45a47078f876 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c @@ -5045,52 +5045,13 @@ static int gfx_v12_0_set_priv_inst_fault_state(struct amdgpu_device *adev, static void gfx_v12_0_handle_priv_fault(struct amdgpu_device *adev, struct amdgpu_iv_entry *entry) { - u32 doorbell_offset = entry->src_data[0] & AMDGPU_CTXID0_DOORBELL_ID_MASK; + u8 me_id, pipe_id, queue_id; - /* - * Try KQ first by ring_id; UQ as fallback. KCQ and UQ never share - * a HW slot (compute_hqd_mask contract). - */ - if (!adev->gfx.disable_kq) { - u8 me_id, pipe_id, queue_id; - struct amdgpu_ring *ring; - int i; + me_id = (entry->ring_id & 0x0c) >> 2; + pipe_id = (entry->ring_id & 0x03) >> 0; + queue_id = (entry->ring_id & 0x70) >> 4; - me_id = (entry->ring_id & 0x0c) >> 2; - pipe_id = (entry->ring_id & 0x03) >> 0; - queue_id = (entry->ring_id & 0x70) >> 4; - - switch (me_id) { - case 0: - for (i = 0; i < adev->gfx.num_gfx_rings; i++) { - ring = &adev->gfx.gfx_ring[i]; - if (ring->me == me_id && ring->pipe == pipe_id && - ring->queue == queue_id) { - drm_sched_fault(&ring->sched); - return; - } - } - break; - case 1: - case 2: - for (i = 0; i < adev->gfx.num_compute_rings; i++) { - ring = &adev->gfx.compute_ring[i]; - if (ring->me == me_id && ring->pipe == pipe_id && - ring->queue == queue_id) { - drm_sched_fault(&ring->sched); - return; - } - } - break; - default: - break; - } - } - - /* No KQ matched: HW slot is a MES-scheduled user queue. */ - if (adev->enable_mes && doorbell_offset) - amdgpu_userq_process_reset_irq(adev, entry->pasid, - doorbell_offset); + amdgpu_gfx_handle_priv_fault(adev, entry, me_id, pipe_id, queue_id); } static int gfx_v12_0_priv_reg_irq(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c index b93bad1d2a6f..5fc19fefca81 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c @@ -2202,12 +2202,6 @@ static void gfx_v7_0_ring_emit_ib_gfx(struct amdgpu_ring *ring, unsigned vmid = AMDGPU_JOB_GET_VMID(job); u32 header, control = 0; - /* insert SWITCH_BUFFER packet before first IB in the ring frame */ - if (flags & AMDGPU_HAVE_CTX_SWITCH) { - amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0)); - amdgpu_ring_write(ring, 0); - } - if (ib->flags & AMDGPU_IB_FLAG_CE) header = PACKET3(PACKET3_INDIRECT_BUFFER_CONST, 2); else @@ -2259,6 +2253,12 @@ static void gfx_v7_0_ring_emit_ib_compute(struct amdgpu_ring *ring, amdgpu_ring_write(ring, control); } +static void gfx_v7_0_ring_emit_sb(struct amdgpu_ring *ring) +{ + amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0)); + amdgpu_ring_write(ring, 0); +} + static void gfx_v7_ring_emit_cntxcntl(struct amdgpu_ring *ring, uint32_t flags) { uint32_t dw2 = 0; @@ -2547,8 +2547,12 @@ static int gfx_v7_0_cp_gfx_resume(struct amdgpu_device *adev) WREG32(mmSCRATCH_ADDR, 0); /* ring 0 - compute and gfx */ - /* Set ring buffer size */ ring = &adev->gfx.gfx_ring[0]; + *ring->wptr_cpu_addr = 0; + *ring->rptr_cpu_addr = 0; + amdgpu_ring_clear_ring(ring); + + /* Set ring buffer size */ rb_bufsz = order_base_2(ring->ring_size / 8); tmp = (order_base_2(AMDGPU_GPU_PAGE_SIZE/8) << 8) | rb_bufsz; #ifdef __BIG_ENDIAN @@ -2560,6 +2564,7 @@ static int gfx_v7_0_cp_gfx_resume(struct amdgpu_device *adev) WREG32(mmCP_RB0_CNTL, tmp | CP_RB0_CNTL__RB_RPTR_WR_ENA_MASK); ring->wptr = 0; WREG32(mmCP_RB0_WPTR, lower_32_bits(ring->wptr)); + WREG32(mmCP_RB0_RPTR, lower_32_bits(ring->wptr)); /* set the wb address whether it's enabled or not */ rptr_addr = ring->rptr_gpu_addr; @@ -2577,7 +2582,10 @@ static int gfx_v7_0_cp_gfx_resume(struct amdgpu_device *adev) WREG32(mmCP_RB0_BASE_HI, upper_32_bits(rb_addr)); /* start the ring */ - gfx_v7_0_cp_gfx_start(adev); + r = gfx_v7_0_cp_gfx_start(adev); + if (r) + return r; + r = amdgpu_ring_test_helper(ring); if (r) return r; @@ -2699,25 +2707,6 @@ static int gfx_v7_0_cp_compute_load_microcode(struct amdgpu_device *adev) return 0; } -/** - * gfx_v7_0_cp_compute_fini - stop the compute queues - * - * @adev: amdgpu_device pointer - * - * Stop the compute queues and tear down the driver queue - * info. - */ -static void gfx_v7_0_cp_compute_fini(struct amdgpu_device *adev) -{ - int i; - - for (i = 0; i < adev->gfx.num_compute_rings; i++) { - struct amdgpu_ring *ring = &adev->gfx.compute_ring[i]; - - amdgpu_bo_free_kernel(&ring->mqd_obj, NULL, NULL); - } -} - static void gfx_v7_0_mec_fini(struct amdgpu_device *adev) { amdgpu_bo_free_kernel(&adev->gfx.mec.hpd_eop_obj, NULL, NULL); @@ -2789,28 +2778,29 @@ static void gfx_v7_0_compute_pipe_init(struct amdgpu_device *adev, mutex_unlock(&adev->srbm_mutex); } -static int gfx_v7_0_mqd_deactivate(struct amdgpu_device *adev) +static int gfx_v7_0_deactivate_hqd(struct amdgpu_device *adev, u32 req) { - int i; + int i, r = 0; /* disable the queue if it's active */ - if (RREG32(mmCP_HQD_ACTIVE) & 1) { - WREG32(mmCP_HQD_DEQUEUE_REQUEST, 1); + if (RREG32(mmCP_HQD_ACTIVE) & CP_HQD_ACTIVE__ACTIVE_MASK) { + WREG32_FIELD(CP_HQD_DEQUEUE_REQUEST, DEQUEUE_REQ, req); for (i = 0; i < adev->usec_timeout; i++) { - if (!(RREG32(mmCP_HQD_ACTIVE) & 1)) + if (!(RREG32(mmCP_HQD_ACTIVE) & CP_HQD_ACTIVE__ACTIVE_MASK)) break; udelay(1); } if (i == adev->usec_timeout) - return -ETIMEDOUT; + r = -ETIMEDOUT; - WREG32(mmCP_HQD_DEQUEUE_REQUEST, 0); - WREG32(mmCP_HQD_PQ_RPTR, 0); - WREG32(mmCP_HQD_PQ_WPTR, 0); } - return 0; + WREG32(mmCP_HQD_DEQUEUE_REQUEST, 0); + WREG32(mmCP_HQD_PQ_RPTR, 0); + WREG32(mmCP_HQD_PQ_WPTR, 0); + + return r; } static void gfx_v7_0_mqd_init(struct amdgpu_device *adev, @@ -2965,31 +2955,42 @@ static int gfx_v7_0_mqd_commit(struct amdgpu_device *adev, struct cik_mqd *mqd) static int gfx_v7_0_compute_queue_init(struct amdgpu_device *adev, int ring_id) { - int r; - u64 mqd_gpu_addr; - struct cik_mqd *mqd; struct amdgpu_ring *ring = &adev->gfx.compute_ring[ring_id]; + struct cik_mqd *mqd = ring->mqd_ptr; + int mqd_idx = ring - &adev->gfx.compute_ring[0]; - r = amdgpu_bo_create_reserved(adev, sizeof(struct cik_mqd), PAGE_SIZE, - AMDGPU_GEM_DOMAIN_GTT, &ring->mqd_obj, - &mqd_gpu_addr, (void **)&mqd); - if (r) { - dev_warn(adev->dev, "(%d) create MQD bo failed\n", r); - return r; + if (!amdgpu_in_reset(adev) && !adev->in_suspend) { + memset((void *)mqd, 0, ring->mqd_size); + mutex_lock(&adev->srbm_mutex); + cik_srbm_select(adev, ring->me, ring->pipe, ring->queue, 0); + gfx_v7_0_mqd_init(adev, mqd, ring->mqd_gpu_addr, ring); + gfx_v7_0_deactivate_hqd(adev, 1); + gfx_v7_0_mqd_commit(adev, mqd); + cik_srbm_select(adev, 0, 0, 0, 0); + mutex_unlock(&adev->srbm_mutex); + + if (adev->gfx.mec.mqd_backup[mqd_idx]) + memcpy(adev->gfx.mec.mqd_backup[mqd_idx], mqd, ring->mqd_size); + } else { + /* restore MQD to a clean status */ + if (adev->gfx.mec.mqd_backup[mqd_idx]) + memcpy(mqd, adev->gfx.mec.mqd_backup[mqd_idx], ring->mqd_size); + + /* Re-commit the restored backup */ + mutex_lock(&adev->srbm_mutex); + cik_srbm_select(adev, ring->me, ring->pipe, ring->queue, 0); + gfx_v7_0_deactivate_hqd(adev, 2); + gfx_v7_0_mqd_commit(adev, mqd); + cik_srbm_select(adev, 0, 0, 0, 0); + mutex_unlock(&adev->srbm_mutex); + + /* reset ring buffer */ + ring->wptr = 0; + atomic64_set((atomic64_t *)ring->wptr_cpu_addr, 0); + atomic64_set((atomic64_t *)ring->rptr_cpu_addr, 0); + amdgpu_ring_clear_ring(ring); } - mutex_lock(&adev->srbm_mutex); - cik_srbm_select(adev, ring->me, ring->pipe, ring->queue, 0); - - gfx_v7_0_mqd_init(adev, mqd, mqd_gpu_addr, ring); - gfx_v7_0_mqd_deactivate(adev); - gfx_v7_0_mqd_commit(adev, mqd); - - cik_srbm_select(adev, 0, 0, 0, 0); - mutex_unlock(&adev->srbm_mutex); - - amdgpu_bo_kunmap(ring->mqd_obj); - amdgpu_bo_unreserve(ring->mqd_obj); return 0; } @@ -3021,20 +3022,20 @@ static int gfx_v7_0_cp_compute_resume(struct amdgpu_device *adev) /* init the queues */ for (i = 0; i < adev->gfx.num_compute_rings; i++) { r = gfx_v7_0_compute_queue_init(adev, i); - if (r) { - gfx_v7_0_cp_compute_fini(adev); + if (r) return r; - } } gfx_v7_0_cp_compute_enable(adev, true); + r = 0; + for (i = 0; i < adev->gfx.num_compute_rings; i++) { ring = &adev->gfx.compute_ring[i]; - amdgpu_ring_test_helper(ring); + r |= amdgpu_ring_test_helper(ring); } - return 0; + return r; } static void gfx_v7_0_cp_enable(struct amdgpu_device *adev, bool enable) @@ -3116,14 +3117,6 @@ static void gfx_v7_0_ring_emit_pipeline_sync(struct amdgpu_ring *ring) amdgpu_ring_write(ring, seq); amdgpu_ring_write(ring, 0xffffffff); amdgpu_ring_write(ring, 4); /* poll interval */ - - if (usepfp) { - /* sync CE with ME to prevent CE fetch CEIB before context switch done */ - amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0)); - amdgpu_ring_write(ring, 0); - amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0)); - amdgpu_ring_write(ring, 0); - } } /* @@ -3165,15 +3158,25 @@ static void gfx_v7_0_ring_emit_vm_flush(struct amdgpu_ring *ring, /* sync PFP to ME, otherwise we might get invalid PFP reads */ amdgpu_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0)); amdgpu_ring_write(ring, 0x0); - - /* synce CE with ME to prevent CE fetch CEIB before context switch done */ - amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0)); - amdgpu_ring_write(ring, 0); - amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0)); - amdgpu_ring_write(ring, 0); } } +static unsigned int gfx_v7_0_ring_emit_init_cond_exec(struct amdgpu_ring *ring, + uint64_t gpu_addr) +{ + unsigned int ret; + + /* Discard following DWs after this packet when gpu_addr==0 */ + amdgpu_ring_write(ring, PACKET3(PACKET3_COND_EXEC, 3)); + amdgpu_ring_write(ring, lower_32_bits(gpu_addr)); + amdgpu_ring_write(ring, upper_32_bits(gpu_addr)); + amdgpu_ring_write(ring, 0); + ret = ring->wptr & ring->buf_mask; + /* patch dummy value later */ + amdgpu_ring_write(ring, 0); + return ret; +} + static void gfx_v7_0_ring_emit_wreg(struct amdgpu_ring *ring, uint32_t reg, uint32_t val) { @@ -3614,21 +3617,6 @@ static void gfx_v7_0_enable_mgcg(struct amdgpu_device *adev, bool enable) } } -static void gfx_v7_0_update_cg(struct amdgpu_device *adev, - bool enable) -{ - gfx_v7_0_enable_gui_idle_interrupt(adev, false); - /* order matters! */ - if (enable) { - gfx_v7_0_enable_mgcg(adev, true); - gfx_v7_0_enable_cgcg(adev, true); - } else { - gfx_v7_0_enable_cgcg(adev, false); - gfx_v7_0_enable_mgcg(adev, false); - } - gfx_v7_0_enable_gui_idle_interrupt(adev, true); -} - static void gfx_v7_0_enable_sclk_slowdown_on_pu(struct amdgpu_device *adev, bool enable) { @@ -4431,6 +4419,11 @@ static int gfx_v7_0_sw_init(struct amdgpu_ip_block *ip_block) } } + /* create MQD for all compute queues */ + r = amdgpu_gfx_mqd_sw_init(adev, sizeof(struct cik_mqd), 0); + if (r) + return r; + adev->gfx.ce_ram_size = 0x8000; gfx_v7_0_gpu_early_init(adev); @@ -4440,6 +4433,11 @@ static int gfx_v7_0_sw_init(struct amdgpu_ip_block *ip_block) adev->gfx.compute_supported_reset = amdgpu_get_soft_full_reset_mask(&adev->gfx.compute_ring[0]); + if (!amdgpu_sriov_vf(adev) && !adev->debug_disable_ip_block_soft_reset) { + adev->gfx.compute_supported_reset |= AMDGPU_RESET_TYPE_IP_BLOCK_SOFT_RESET; + adev->gfx.gfx_supported_reset |= AMDGPU_RESET_TYPE_IP_BLOCK_SOFT_RESET; + } + return r; } @@ -4453,7 +4451,7 @@ static int gfx_v7_0_sw_fini(struct amdgpu_ip_block *ip_block) for (i = 0; i < adev->gfx.num_compute_rings; i++) amdgpu_ring_fini(&adev->gfx.compute_ring[i]); - gfx_v7_0_cp_compute_fini(adev); + amdgpu_gfx_mqd_sw_fini(adev, 0); amdgpu_gfx_rlc_fini(adev); gfx_v7_0_mec_fini(adev); amdgpu_bo_free_kernel(&adev->gfx.rlc.clear_state_obj, @@ -4542,80 +4540,99 @@ static int gfx_v7_0_wait_for_idle(struct amdgpu_ip_block *ip_block) static int gfx_v7_0_soft_reset(struct amdgpu_ip_block *ip_block) { + struct amdgpu_device *adev = ip_block->adev; u32 grbm_soft_reset = 0, srbm_soft_reset = 0; u32 tmp; - struct amdgpu_device *adev = ip_block->adev; + int i; + int r; - /* GRBM_STATUS */ - tmp = RREG32(mmGRBM_STATUS); - if (tmp & (GRBM_STATUS__PA_BUSY_MASK | GRBM_STATUS__SC_BUSY_MASK | - GRBM_STATUS__BCI_BUSY_MASK | GRBM_STATUS__SX_BUSY_MASK | - GRBM_STATUS__TA_BUSY_MASK | GRBM_STATUS__VGT_BUSY_MASK | - GRBM_STATUS__DB_BUSY_MASK | GRBM_STATUS__CB_BUSY_MASK | - GRBM_STATUS__GDS_BUSY_MASK | GRBM_STATUS__SPI_BUSY_MASK | - GRBM_STATUS__IA_BUSY_MASK | GRBM_STATUS__IA_BUSY_NO_DMA_MASK)) - grbm_soft_reset |= GRBM_SOFT_RESET__SOFT_RESET_CP_MASK | - GRBM_SOFT_RESET__SOFT_RESET_GFX_MASK; + grbm_soft_reset = + REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_RLC, 1) | + REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_GFX, 1) | + REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_CP, 1) | + REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_CPF, 1) | + REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_CPC, 1) | + REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_CPG, 1); - if (tmp & (GRBM_STATUS__CP_BUSY_MASK | GRBM_STATUS__CP_COHERENCY_BUSY_MASK)) { - grbm_soft_reset |= GRBM_SOFT_RESET__SOFT_RESET_CP_MASK; - srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_GRBM_MASK; - } + srbm_soft_reset = + REG_SET_FIELD(0, SRBM_SOFT_RESET, SOFT_RESET_GRBM, 1) | + REG_SET_FIELD(0, SRBM_SOFT_RESET, SOFT_RESET_SEM, 1); - /* GRBM_STATUS2 */ - tmp = RREG32(mmGRBM_STATUS2); - if (tmp & GRBM_STATUS2__RLC_BUSY_MASK) - grbm_soft_reset |= GRBM_SOFT_RESET__SOFT_RESET_RLC_MASK; + for (i = 0; i < adev->gfx.num_compute_rings; i++) { + struct amdgpu_ring *ring = &adev->gfx.compute_ring[i]; - /* SRBM_STATUS */ - tmp = RREG32(mmSRBM_STATUS); - if (tmp & SRBM_STATUS__GRBM_RQ_PENDING_MASK) - srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_GRBM_MASK; + mutex_lock(&adev->srbm_mutex); + cik_srbm_select(adev, ring->me, ring->pipe, ring->queue, 0); + gfx_v7_0_deactivate_hqd(adev, 2); + cik_srbm_select(adev, 0, 0, 0, 0); + mutex_unlock(&adev->srbm_mutex); - if (grbm_soft_reset || srbm_soft_reset) { - /* disable CG/PG */ - gfx_v7_0_fini_pg(adev); - gfx_v7_0_update_cg(adev, false); - - /* stop the rlc */ - adev->gfx.rlc.funcs->stop(adev); - - /* Disable GFX parsing/prefetching */ - WREG32(mmCP_ME_CNTL, CP_ME_CNTL__ME_HALT_MASK | CP_ME_CNTL__PFP_HALT_MASK | CP_ME_CNTL__CE_HALT_MASK); - - /* Disable MEC parsing/prefetching */ - WREG32(mmCP_MEC_CNTL, CP_MEC_CNTL__MEC_ME1_HALT_MASK | CP_MEC_CNTL__MEC_ME2_HALT_MASK); - - if (grbm_soft_reset) { - tmp = RREG32(mmGRBM_SOFT_RESET); - tmp |= grbm_soft_reset; - dev_info(adev->dev, "GRBM_SOFT_RESET=0x%08X\n", tmp); - WREG32(mmGRBM_SOFT_RESET, tmp); - tmp = RREG32(mmGRBM_SOFT_RESET); - - udelay(50); - - tmp &= ~grbm_soft_reset; - WREG32(mmGRBM_SOFT_RESET, tmp); - tmp = RREG32(mmGRBM_SOFT_RESET); - } - - if (srbm_soft_reset) { - tmp = RREG32(mmSRBM_SOFT_RESET); - tmp |= srbm_soft_reset; - dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); - WREG32(mmSRBM_SOFT_RESET, tmp); - tmp = RREG32(mmSRBM_SOFT_RESET); - - udelay(50); - - tmp &= ~srbm_soft_reset; - WREG32(mmSRBM_SOFT_RESET, tmp); - tmp = RREG32(mmSRBM_SOFT_RESET); - } - /* Wait a little for things to settle down */ udelay(50); } + + ip_block->version->funcs->set_clockgating_state(ip_block, AMD_CG_STATE_UNGATE); + ip_block->version->funcs->set_powergating_state(ip_block, AMD_PG_STATE_UNGATE); + ip_block->version->funcs->suspend(ip_block); + + if (grbm_soft_reset || srbm_soft_reset) { + tmp = RREG32(mmGMCON_DEBUG); + tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_STALL, 1); + tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_CLEAR, 1); + WREG32(mmGMCON_DEBUG, tmp); + + udelay(100); + } + + if (grbm_soft_reset) { + tmp = RREG32(mmGRBM_SOFT_RESET); + tmp |= grbm_soft_reset; + dev_info(adev->dev, "GRBM_SOFT_RESET=0x%08X\n", tmp); + WREG32(mmGRBM_SOFT_RESET, tmp); + tmp = RREG32(mmGRBM_SOFT_RESET); + + udelay(100); + + tmp &= ~grbm_soft_reset; + WREG32(mmGRBM_SOFT_RESET, tmp); + tmp = RREG32(mmGRBM_SOFT_RESET); + + udelay(100); + } + + if (srbm_soft_reset) { + tmp = RREG32(mmSRBM_SOFT_RESET); + tmp |= srbm_soft_reset; + dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); + WREG32(mmSRBM_SOFT_RESET, tmp); + tmp = RREG32(mmSRBM_SOFT_RESET); + + udelay(100); + + tmp &= ~srbm_soft_reset; + WREG32(mmSRBM_SOFT_RESET, tmp); + tmp = RREG32(mmSRBM_SOFT_RESET); + + udelay(100); + } + + if (grbm_soft_reset || srbm_soft_reset) { + tmp = RREG32(mmGMCON_DEBUG); + tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_STALL, 0); + tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_CLEAR, 0); + WREG32(mmGMCON_DEBUG, tmp); + } + + /* Wait a little for things to settle down */ + udelay(100); + + r = ip_block->version->funcs->resume(ip_block); + r |= ip_block->version->funcs->late_init(ip_block); + if (r) + return r; + + ip_block->version->funcs->set_clockgating_state(ip_block, AMD_CG_STATE_GATE); + ip_block->version->funcs->set_powergating_state(ip_block, AMD_PG_STATE_GATE); + return 0; } @@ -4950,12 +4967,15 @@ static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_gfx = { .get_wptr = gfx_v7_0_ring_get_wptr_gfx, .set_wptr = gfx_v7_0_ring_set_wptr_gfx, .emit_frame_size = + 5 + /* gfx_v7_0_ring_emit_init_cond_exec (from amdgpu_ib_schedule) */ + 5 + /* gfx_v7_0_ring_emit_init_cond_exec (from amdgpu_vm_flush) */ 20 + /* gfx_v7_0_ring_emit_gds_switch */ 7 + /* gfx_v7_0_ring_emit_hdp_flush */ 5 + /* hdp invalidate */ 12 + 12 + 12 + /* gfx_v7_0_ring_emit_fence_gfx x3 for user fence, vm fence */ - 7 + 4 + /* gfx_v7_0_ring_emit_pipeline_sync */ - CIK_FLUSH_GPU_TLB_NUM_WREG * 5 + 7 + 6 + /* gfx_v7_0_ring_emit_vm_flush */ + 7 + /* gfx_v7_0_ring_emit_pipeline_sync */ + CIK_FLUSH_GPU_TLB_NUM_WREG * 5 + 7 + 2 + /* gfx_v7_0_ring_emit_vm_flush */ + 3 * 2 + /* gfx_v7_0_ring_emit_sb x3 (from amdgpu_vm_flush, amdgpu_ib_schedule) */ 3 + 4 + /* gfx_v7_ring_emit_cntxcntl including vgt flush*/ 5, /* SURFACE_SYNC */ .emit_ib_size = 4, /* gfx_v7_0_ring_emit_ib_gfx */ @@ -4969,7 +4989,9 @@ static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_gfx = { .test_ib = gfx_v7_0_ring_test_ib, .insert_nop = amdgpu_ring_insert_nop, .pad_ib = amdgpu_ring_generic_pad_ib, + .emit_switch_buffer = gfx_v7_0_ring_emit_sb, .emit_cntxcntl = gfx_v7_ring_emit_cntxcntl, + .init_cond_exec = gfx_v7_0_ring_emit_init_cond_exec, .emit_wreg = gfx_v7_0_ring_emit_wreg, .soft_recovery = gfx_v7_0_ring_soft_recovery, .emit_mem_sync = gfx_v7_0_emit_mem_sync, @@ -4984,6 +5006,8 @@ static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_compute = { .get_wptr = gfx_v7_0_ring_get_wptr_compute, .set_wptr = gfx_v7_0_ring_set_wptr_compute, .emit_frame_size = + 5 + /* gfx_v7_0_ring_emit_init_cond_exec (from amdgpu_ib_schedule) */ + 5 + /* gfx_v7_0_ring_emit_init_cond_exec (from amdgpu_vm_flush) */ 20 + /* gfx_v7_0_ring_emit_gds_switch */ 7 + /* gfx_v7_0_ring_emit_hdp_flush */ 5 + /* hdp invalidate */ @@ -5002,6 +5026,7 @@ static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_compute = { .test_ib = gfx_v7_0_ring_test_ib, .insert_nop = amdgpu_ring_insert_nop, .pad_ib = amdgpu_ring_generic_pad_ib, + .init_cond_exec = gfx_v7_0_ring_emit_init_cond_exec, .emit_wreg = gfx_v7_0_ring_emit_wreg, .soft_recovery = gfx_v7_0_ring_soft_recovery, .emit_mem_sync = gfx_v7_0_emit_mem_sync_compute, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index ed3649a81332..f5af1dd3b70e 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -954,12 +954,12 @@ static vm_fault_t svm_migrate_to_ram(struct vm_fault *vmf) pr_debug("failed get device page at addr 0x%lx\n", addr); return VM_FAULT_SIGBUS; } - if (!mmget_not_zero(svm_bo->eviction_fence->mm)) { + if (!mmget_not_zero(svm_bo->mm)) { pr_debug("addr 0x%lx of process mm is destroyed\n", addr); return VM_FAULT_SIGBUS; } - mm = svm_bo->eviction_fence->mm; + mm = svm_bo->mm; if (mm != vmf->vma->vm_mm) pr_debug("addr 0x%lx is COW mapping in child process\n", addr); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 4c6700c6e88d..18abef8918ce 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -390,8 +390,10 @@ static bool svm_bo_ref_unless_zero(struct svm_range_bo *svm_bo) static void svm_range_bo_release(struct kref *kref) { struct svm_range_bo *svm_bo; + struct amdgpu_bo *bo; svm_bo = container_of(kref, struct svm_range_bo, kref); + bo = &svm_bo->bo; pr_debug("svm_bo 0x%p\n", svm_bo); spin_lock(&svm_bo->list_lock); @@ -417,12 +419,12 @@ static void svm_range_bo_release(struct kref *kref) } spin_unlock(&svm_bo->list_lock); - if (mmget_not_zero(svm_bo->eviction_fence->mm)) { + if (mmget_not_zero(svm_bo->mm)) { struct kfd_process_device *pdd; struct kfd_process *p; struct mm_struct *mm; - mm = svm_bo->eviction_fence->mm; + mm = svm_bo->mm; /* * The forked child process takes svm_bo device pages ref, svm_bo could be * released after parent process is gone. @@ -431,18 +433,13 @@ static void svm_range_bo_release(struct kref *kref) if (p) { pdd = kfd_get_process_device_data(svm_bo->node, p); if (pdd) - atomic64_sub(amdgpu_bo_size(svm_bo->bo), &pdd->vram_usage); + atomic64_sub(amdgpu_bo_size(bo), &pdd->vram_usage); kfd_unref_process(p); } mmput(mm); } - if (!dma_fence_is_signaled(&svm_bo->eviction_fence->base)) - /* We're not in the eviction worker. Signal the fence. */ - dma_fence_signal(&svm_bo->eviction_fence->base); - dma_fence_put(&svm_bo->eviction_fence->base); - amdgpu_bo_unref(&svm_bo->bo); - kfree(svm_bo); + amdgpu_bo_unref(&bo); } static void svm_range_bo_wq_release(struct work_struct *work) @@ -504,20 +501,11 @@ svm_range_validate_svm_bo(struct kfd_node *node, struct svm_range *prange) return false; } if (READ_ONCE(prange->svm_bo->evicting)) { - struct dma_fence *f; - struct svm_range_bo *svm_bo; /* The BO is getting evicted, * we need to get a new one */ mutex_unlock(&prange->lock); - svm_bo = prange->svm_bo; - f = dma_fence_get(&svm_bo->eviction_fence->base); svm_range_bo_unref(prange->svm_bo); - /* wait for the fence to avoid long spin-loop - * at list_empty_careful - */ - dma_fence_wait(f, false); - dma_fence_put(f); } else { /* The BO was still around and we got * a new reference to it @@ -526,7 +514,7 @@ svm_range_validate_svm_bo(struct kfd_node *node, struct svm_range *prange) pr_debug("reuse old bo svms 0x%p [0x%lx 0x%lx]\n", prange->svms, prange->start, prange->last); - prange->ttm_res = prange->svm_bo->bo->tbo.resource; + prange->ttm_res = prange->svm_bo->bo.tbo.resource; return true; } @@ -545,19 +533,22 @@ svm_range_validate_svm_bo(struct kfd_node *node, struct svm_range *prange) return false; } -static struct svm_range_bo *svm_range_bo_new(void) +#define to_svm_range_bo(bo) container_of((bo), struct svm_range_bo, bo) + +void svm_range_bo_destroy(struct ttm_buffer_object *tbo) { - struct svm_range_bo *svm_bo; + struct amdgpu_bo *bo = ttm_to_amdgpu_bo(tbo); + struct svm_range_bo *svm_bo = to_svm_range_bo(bo); - svm_bo = kzalloc_obj(*svm_bo); - if (!svm_bo) - return NULL; - - kref_init(&svm_bo->kref); - INIT_LIST_HEAD(&svm_bo->range_list); - spin_lock_init(&svm_bo->list_lock); - - return svm_bo; + drm_gem_object_release(&bo->tbo.base); + /* + * svm_bo->mm is only set once the BO is fully created. If + * ttm_bo_init_reserved() fails (e.g. no VRAM could be evicted), it + * calls this destroy callback with mm still NULL, so guard the drop. + */ + if (svm_bo->mm) + mmdrop(svm_bo->mm); + kvfree(svm_bo); } int @@ -567,7 +558,6 @@ svm_range_vram_node_new(struct kfd_node *node, struct svm_range *prange, struct kfd_process_device *pdd; struct amdgpu_bo_param bp; struct svm_range_bo *svm_bo; - struct amdgpu_bo_user *ubo; struct amdgpu_bo *bo; struct kfd_process *p; struct mm_struct *mm; @@ -581,26 +571,16 @@ svm_range_vram_node_new(struct kfd_node *node, struct svm_range *prange, if (svm_range_validate_svm_bo(node, prange)) return 0; - svm_bo = svm_range_bo_new(); - if (!svm_bo) { - pr_debug("failed to alloc svm bo\n"); - return -ENOMEM; - } mm = get_task_mm(p->lead_thread); if (!mm) { pr_debug("failed to get mm\n"); - kfree(svm_bo); return -ESRCH; } - svm_bo->node = node; - svm_bo->eviction_fence = - amdgpu_amdkfd_fence_create(dma_fence_context_alloc(1), - mm, - svm_bo, p->context_id); - mmput(mm); - svm_bo->evicting = 0; + memset(&bp, 0, sizeof(bp)); bp.size = prange->npages * PAGE_SIZE; + bp.bo_ptr_size = sizeof(struct svm_range_bo); + bp.destroy = svm_range_bo_destroy; bp.byte_align = PAGE_SIZE; bp.domain = AMDGPU_GEM_DOMAIN_VRAM; bp.flags = AMDGPU_GEM_CREATE_NO_CPU_ACCESS; @@ -611,12 +591,23 @@ svm_range_vram_node_new(struct kfd_node *node, struct svm_range *prange, if (node->xcp) bp.xcp_id_plus1 = node->xcp->id + 1; - r = amdgpu_bo_create_user(node->adev, &bp, &ubo); + r = amdgpu_bo_create(node->adev, &bp, &bo); if (r) { pr_debug("failed %d to create bo\n", r); + mmput(mm); goto create_bo_failed; } - bo = &ubo->bo; + + svm_bo = to_svm_range_bo(bo); + svm_bo->evicting = 0; + kref_init(&svm_bo->kref); + INIT_LIST_HEAD(&svm_bo->range_list); + spin_lock_init(&svm_bo->list_lock); + + svm_bo->node = node; + svm_bo->mm = mm; + mmgrab(svm_bo->mm); + mmput(mm); pr_debug("alloc bo at offset 0x%lx size 0x%lx on partition %d\n", bo->tbo.resource->start << PAGE_SHIFT, bp.size, @@ -637,16 +628,8 @@ svm_range_vram_node_new(struct kfd_node *node, struct svm_range *prange, } } - r = dma_resv_reserve_fences(bo->tbo.base.resv, TTM_NUM_MOVE_FENCES); - if (r) { - amdgpu_bo_unreserve(bo); - goto reserve_bo_failed; - } - amdgpu_bo_fence(bo, &svm_bo->eviction_fence->base, true); - amdgpu_bo_unreserve(bo); - svm_bo->bo = bo; prange->svm_bo = svm_bo; prange->ttm_res = bo->tbo.resource; prange->offset = 0; @@ -664,9 +647,6 @@ svm_range_vram_node_new(struct kfd_node *node, struct svm_range *prange, reserve_bo_failed: amdgpu_bo_unref(&bo); create_bo_failed: - dma_fence_put(&svm_bo->eviction_fence->base); - kfree(svm_bo); - prange->ttm_res = NULL; return r; } @@ -3640,19 +3620,20 @@ svm_range_trigger_migration(struct mm_struct *mm, struct svm_range *prange, return 0; } -int svm_range_evict_svm_bo(struct svm_range_bo *svm_bo) +int svm_range_evict_svm_bo(struct amdgpu_bo *bo) { + struct svm_range_bo *svm_bo = to_svm_range_bo(bo); struct mm_struct *mm; int r = 0; if (!svm_bo_ref_unless_zero(svm_bo)) return 0; - if (!mmget_not_zero(svm_bo->eviction_fence->mm)) { + if (!mmget_not_zero(svm_bo->mm)) { svm_range_bo_unref(svm_bo); return 0; } - mm = svm_bo->eviction_fence->mm; + mm = svm_bo->mm; /* * Called with the BO reserved; lock order is mmap_lock -> BO @@ -3721,14 +3702,6 @@ int svm_range_evict_svm_bo(struct svm_range_bo *svm_bo) /* Defer mmput: exit_mmap() must not run under the BO reservation. */ mmput_async(mm); - /* - * Only signal the eviction fence once the ranges have been processed. - * On -EBUSY we bailed out without migrating; leave the BO in VRAM and - * let TTM retry later. - */ - if (r != -EBUSY) - dma_fence_signal(&svm_bo->eviction_fence->base); - /* This is the last reference to svm_bo, after svm_range_vram_node_free * has been called in svm_migrate_vram_to_ram */ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h index 4232c47422e6..284c4cd5aa0f 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h @@ -39,11 +39,11 @@ ((adev)->hive ? (void *)(adev)->hive : (void *)(adev)) struct svm_range_bo { - struct amdgpu_bo *bo; + struct amdgpu_bo bo; struct kref kref; struct list_head range_list; /* all svm ranges shared this bo */ spinlock_t list_lock; - struct amdgpu_amdkfd_fence *eviction_fence; + struct mm_struct *mm; uint32_t evicting; struct work_struct release_work; struct kfd_node *node; @@ -168,13 +168,14 @@ struct svm_range *svm_range_from_addr(struct svm_range_list *svms, struct svm_range **parent); struct kfd_node *svm_range_get_node_by_id(struct svm_range *prange, uint32_t gpu_id); +void svm_range_bo_destroy(struct ttm_buffer_object *tbo); int svm_range_vram_node_new(struct kfd_node *node, struct svm_range *prange, bool clear); void svm_range_vram_node_free(struct svm_range *prange); int svm_range_restore_pages(struct amdgpu_device *adev, unsigned int pasid, uint32_t vmid, uint32_t node_id, uint64_t addr, uint64_t ts, bool write_fault); -int svm_range_evict_svm_bo(struct svm_range_bo *svm_bo); +int svm_range_evict_svm_bo(struct amdgpu_bo *bo); void svm_range_add_list_work(struct svm_range_list *svms, struct svm_range *prange, struct mm_struct *mm, @@ -229,7 +230,11 @@ static inline int svm_range_restore_pages(struct amdgpu_device *adev, return -EFAULT; } -static inline int svm_range_evict_svm_bo(struct svm_range_bo *svm_bo) +static inline void svm_range_bo_destroy(struct ttm_buffer_object *tbo) +{ +} + +static inline int svm_range_evict_svm_bo(struct amdgpu_bo *bo) { return 0; } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index f22388e57e98..e421c3c81778 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3576,25 +3576,6 @@ static void remove_stream(struct amdgpu_device *adev, acrtc->enabled = false; } -static void prepare_flip_isr(struct amdgpu_crtc *acrtc) -{ - - assert_spin_locked(&acrtc->base.dev->event_lock); - WARN_ON(acrtc->event); - - acrtc->event = acrtc->base.state->event; - - /* Set the flip status */ - acrtc->pflip_status = AMDGPU_FLIP_SUBMITTED; - - /* Mark this event as consumed */ - acrtc->base.state->event = NULL; - - drm_dbg_state(acrtc->base.dev, - "crtc:%d, pflip_stat:AMDGPU_FLIP_SUBMITTED\n", - acrtc->crtc_id); -} - static void amdgpu_dm_commit_cursors(struct drm_atomic_commit *state) { struct drm_plane *plane; @@ -3740,17 +3721,47 @@ static void dm_arm_vblank_event(struct amdgpu_crtc *acrtc, return; if (pflip_update) { - drm_crtc_vblank_get(&acrtc->base); WARN_ON(acrtc->pflip_status != AMDGPU_FLIP_NONE); - /* Arm flip completion handling and event delivery after programming. */ - prepare_flip_isr(acrtc); + WARN_ON(acrtc->event); + + acrtc->pflip_status = AMDGPU_FLIP_SUBMITTED; + acrtc->event = acrtc->base.state->event; + acrtc->base.state->event = NULL; + + drm_dbg_state(acrtc->base.dev, + "crtc:%d, pflip_stat:AMDGPU_FLIP_SUBMITTED\n", + acrtc->crtc_id); } else if (cursor_update) { - drm_crtc_vblank_get(&acrtc->base); acrtc->event = acrtc->base.state->event; acrtc->base.state->event = NULL; } } +/** + * dm_arm_vblank_event_pre_programming - Prepare for programming + * @acrtc: The amdgpu CRTC to prepare + * @acrtc_state: The new CRTC state + * @pflip_update: Whether a page flip is being programmed + * @cursor_update: Whether a cursor update is being programmed + * + * Grab a reference on the vblank counter if a page flip or cursor update is to + * be programmed. Do this before programming so the HW is not in any + * idle-optimized state (such as PSR). + */ +static void dm_arm_vblank_event_pre_programming(struct amdgpu_crtc *acrtc, + struct dm_crtc_state *acrtc_state, + bool pflip_update, + bool cursor_update) +{ + assert_spin_locked(&acrtc->base.dev->event_lock); + + if (!acrtc->base.state->event || acrtc_state->active_planes == 0) + return; + + if (pflip_update || cursor_update) + drm_crtc_vblank_get(&acrtc->base); +} + static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state, struct drm_device *dev, struct amdgpu_display_manager *dm, @@ -4013,16 +4024,19 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state, } } - /* - * DCE depends on a combination of GRPH_FLIP, VLINE0, and VUPDATE for - * event delivery. Only GRPH_FLIP handler can send pflip events, and it - * only fires if HW latched to the flip. Maintain legacy behavior by - * arming event before programming. - */ - if (amdgpu_ip_version(dm->adev, DCE_HWIP, 0) == 0) { - scoped_guard(spinlock_irqsave, &pcrtc->dev->event_lock) { + scoped_guard(spinlock_irqsave, &pcrtc->dev->event_lock) { + dm_arm_vblank_event_pre_programming(acrtc_attach, acrtc_state, + pflip_present, + cursor_update); + /* + * DCE depends on a combination of GRPH_FLIP, VLINE0, and + * VUPDATE for event delivery. Only GRPH_FLIP handler can send + * pflip events, and it only fires if HW latched to the flip. + * Maintain legacy behavior by arming event before programming. + */ + if (amdgpu_ip_version(dm->adev, DCE_HWIP, 0) == 0) { dm_arm_vblank_event(acrtc_attach, acrtc_state, - pflip_present, cursor_update); + pflip_present, cursor_update); } } diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c index 8f59ea12fe0e..c3688b3b12cc 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c @@ -1183,6 +1183,13 @@ int amdgpu_dpm_dispatch_task(struct amdgpu_device *adev, return ret; } +static bool amdgpu_dpm_is_pp_table_allowed(struct amdgpu_device *adev) +{ + return !amdgpu_sriov_vf(adev) && + !(adev->flags & AMD_IS_APU) && + !adev->scpm_enabled; +} + int amdgpu_dpm_get_pp_table(struct amdgpu_device *adev, char *table, size_t size) { @@ -1193,7 +1200,8 @@ int amdgpu_dpm_get_pp_table(struct amdgpu_device *adev, char *table, if ((!table && size) || (table && !size)) return -EINVAL; - if (amdgpu_sriov_vf(adev) || !pp_funcs->get_pp_table || adev->scpm_enabled) + if (!amdgpu_dpm_is_pp_table_allowed(adev) || + !pp_funcs->get_pp_table) return -EOPNOTSUPP; mutex_lock(&adev->pm.mutex); @@ -1717,7 +1725,8 @@ int amdgpu_dpm_set_pp_table(struct amdgpu_device *adev, if (!buf || !size) return -EINVAL; - if (amdgpu_sriov_vf(adev) || !pp_funcs->set_pp_table || adev->scpm_enabled) + if (!amdgpu_dpm_is_pp_table_allowed(adev) || + !pp_funcs->set_pp_table) return -EOPNOTSUPP; mutex_lock(&adev->pm.mutex);