diff options
Diffstat (limited to 'drivers/gpu')
183 files changed, 6639 insertions, 1909 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index e023cc734ebc..0dab267eb382 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -768,9 +768,8 @@ err: void amdgpu_amdkfd_set_compute_idle(struct amdgpu_device *adev, bool idle) { enum amd_powergating_state state = idle ? AMD_PG_STATE_GATE : AMD_PG_STATE_UNGATE; - if ((IP_VERSION_MAJ(amdgpu_ip_version(adev, GC_HWIP, 0)) == 11 && - ((adev->mes.kiq_version & AMDGPU_MES_VERSION_MASK) <= 64)) || - (IP_VERSION_MAJ(amdgpu_ip_version(adev, GC_HWIP, 0)) == 12)) { + if (IP_VERSION_MAJ(amdgpu_ip_version(adev, GC_HWIP, 0)) == 11 && + ((adev->mes.kiq_version & AMDGPU_MES_VERSION_MASK) <= 64)) { pr_debug("GFXOFF is %s\n", idle ? "enabled" : "disabled"); amdgpu_gfx_off_ctrl(adev, idle); } else if ((IP_VERSION_MAJ(amdgpu_ip_version(adev, GC_HWIP, 0)) == 9) && diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v11.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v11.c index 04fab30ab5dd..96a308b94646 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v11.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v11.c @@ -747,13 +747,9 @@ static uint32_t kgd_gfx_v11_set_address_watch(struct amdgpu_device *adev, uint32_t debug_vmid, uint32_t inst) { - uint32_t watch_address_high; - uint32_t watch_address_low; uint32_t watch_address_cntl; watch_address_cntl = 0; - watch_address_low = lower_32_bits(watch_address); - watch_address_high = upper_32_bits(watch_address) & 0xffff; watch_address_cntl = REG_SET_FIELD(watch_address_cntl, TCP_WATCH0_CNTL, @@ -770,14 +766,6 @@ static uint32_t kgd_gfx_v11_set_address_watch(struct amdgpu_device *adev, VALID, 1); - WREG32_RLC((SOC15_REG_OFFSET(GC, 0, regTCP_WATCH0_ADDR_H) + - (watch_id * TCP_WATCH_STRIDE)), - watch_address_high); - - WREG32_RLC((SOC15_REG_OFFSET(GC, 0, regTCP_WATCH0_ADDR_L) + - (watch_id * TCP_WATCH_STRIDE)), - watch_address_low); - return watch_address_cntl; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12.c index 62b9db64368e..004d0253f60d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12.c @@ -322,13 +322,9 @@ static uint32_t kgd_gfx_v12_set_address_watch(struct amdgpu_device *adev, uint32_t debug_vmid, uint32_t inst) { - uint32_t watch_address_high; - uint32_t watch_address_low; uint32_t watch_address_cntl; watch_address_cntl = 0; - watch_address_low = lower_32_bits(watch_address); - watch_address_high = upper_32_bits(watch_address) & 0xffff; watch_address_cntl = REG_SET_FIELD(watch_address_cntl, TCP_WATCH0_CNTL, @@ -345,14 +341,6 @@ static uint32_t kgd_gfx_v12_set_address_watch(struct amdgpu_device *adev, VALID, 1); - WREG32_RLC((SOC15_REG_OFFSET(GC, 0, regTCP_WATCH0_ADDR_H) + - (watch_id * TCP_WATCH_STRIDE)), - watch_address_high); - - WREG32_RLC((SOC15_REG_OFFSET(GC, 0, regTCP_WATCH0_ADDR_L) + - (watch_id * TCP_WATCH_STRIDE)), - watch_address_low); - return watch_address_cntl; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12_1.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12_1.c index ec095003667f..ddd1140b6e5d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12_1.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12_1.c @@ -331,13 +331,9 @@ static uint32_t kgd_gfx_v12_1_set_address_watch(struct amdgpu_device *adev, uint32_t debug_vmid, uint32_t inst) { - uint32_t watch_address_high; - uint32_t watch_address_low; uint32_t watch_address_cntl; watch_address_cntl = 0; - watch_address_low = lower_32_bits(watch_address); - watch_address_high = upper_32_bits(watch_address) & 0x1ffffff; watch_address_cntl = REG_SET_FIELD(watch_address_cntl, TCP_WATCH0_CNTL, @@ -354,14 +350,6 @@ static uint32_t kgd_gfx_v12_1_set_address_watch(struct amdgpu_device *adev, VALID, 1); - WREG32_XCC((SOC15_REG_OFFSET(GC, GET_INST(GC, inst), regTCP_WATCH0_ADDR_H) + - (watch_id * TCP_WATCH_STRIDE)), - watch_address_high, inst); - - WREG32_XCC((SOC15_REG_OFFSET(GC, GET_INST(GC, inst), regTCP_WATCH0_ADDR_L) + - (watch_id * TCP_WATCH_STRIDE)), - watch_address_low, inst); - return watch_address_cntl; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index a0ca93ffb00c..ab82ecc9e854 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -2853,6 +2853,7 @@ static void amdgpu_amdkfd_restore_userptr_worker(struct work_struct *work) struct task_struct *usertask; struct mm_struct *mm; uint32_t evicted_bos; + int ret; mutex_lock(&process_info->notifier_lock); evicted_bos = process_info->evicted_bos; @@ -2872,14 +2873,16 @@ static void amdgpu_amdkfd_restore_userptr_worker(struct work_struct *work) mutex_lock(&process_info->lock); - if (update_invalid_user_pages(process_info, mm)) + ret = update_invalid_user_pages(process_info, mm); + if (ret) goto unlock_out; /* userptr_inval_list can be empty if all evicted userptr BOs * have been freed. In that case there is nothing to validate * and we can just restart the queues. */ if (!list_empty(&process_info->userptr_inval_list)) { - if (validate_invalid_user_pages(process_info)) + ret = validate_invalid_user_pages(process_info); + if (ret) goto unlock_out; } /* Final check for concurrent evicton and atomic update. If @@ -2888,11 +2891,14 @@ static void amdgpu_amdkfd_restore_userptr_worker(struct work_struct *work) * reference counting inside KFD will handle this case. */ mutex_lock(&process_info->notifier_lock); - if (process_info->evicted_bos != evicted_bos) + if (process_info->evicted_bos != evicted_bos) { + ret = -EAGAIN; goto unlock_notifier_out; + } if (confirm_valid_user_pages_locked(process_info)) { WARN(1, "User pages unexpectedly invalid"); + ret = -EINVAL; goto unlock_notifier_out; } @@ -2910,8 +2916,10 @@ unlock_notifier_out: unlock_out: mutex_unlock(&process_info->lock); - /* If validation failed, reschedule another attempt */ - if (evicted_bos) { + /* If validation failed, reschedule another attempt, unless the + * device is gone for good + */ + if (evicted_bos && ret != -ENODEV) { queue_delayed_work(system_freezable_wq, &process_info->restore_userptr_work, msecs_to_jiffies(AMDGPU_USERPTR_RESTORE_DELAY_MS)); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 3ad3ac658c3d..7edca4f7f583 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -217,6 +217,12 @@ static int amdgpu_cs_pass1(struct amdgpu_cs_parser *p, size = p->chunks[i].length_dw; + if (size > INT_MAX / sizeof(uint32_t)) { + ret = -EINVAL; + i--; + goto free_partial_kdata; + } + p->chunks[i].kdata = vmemdup_array_user(u64_to_user_ptr(user_chunk.chunk_data), size, sizeof(uint32_t)); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 77c42d91fa44..92cc0fa7ba33 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -3847,7 +3847,6 @@ int amdgpu_device_init(struct amdgpu_device *adev, /* mutex initialization are all done here so we * can recall function without having locking issues */ - mutex_init(&adev->firmware.mutex); mutex_init(&adev->pm.mutex); mutex_init(&adev->gfx.gpu_clock_mutex); mutex_init(&adev->srbm_mutex); @@ -4364,8 +4363,11 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev) * before ip_fini_early to prevent kfd locking refcount issues by calling * amdgpu_amdkfd_suspend() */ - if (pci_dev_is_disconnected(adev->pdev)) + if (pci_dev_is_disconnected(adev->pdev)) { + /* Drain KFD processes while kfd.dev is still valid */ + amdgpu_amdkfd_teardown_processes(adev); amdgpu_amdkfd_device_fini_sw(adev); + } amdgpu_coredump_fini(adev); amdgpu_device_ip_fini_early(adev); @@ -5269,8 +5271,6 @@ int amdgpu_device_reinit_after_reset(struct amdgpu_reset_context *reset_context) if (r) goto out; - drm_client_dev_resume(adev_to_drm(tmp_adev)); - /* * The GPU enters bad state once faulty pages * by ECC has reached the threshold, and ras @@ -5603,8 +5603,6 @@ static void amdgpu_device_halt_activities(struct amdgpu_device *adev, */ amdgpu_unregister_gpu_instance(tmp_adev); - drm_client_dev_suspend(adev_to_drm(tmp_adev)); - /* disable ras on ALL IPs */ if (!need_emergency_restart && !amdgpu_reset_in_dpc(adev)) amdgpu_ras_suspend(tmp_adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c index 1482fc031d44..9c879ac68352 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c @@ -634,8 +634,9 @@ unlock: * @vm: the VM with the reserved ID * @vmhub: the VMHUB which should be used * - * Waits for all work that used the reserved VMID to finish before unbinding - * its page table, so submissions still in flight don't suddenly fault. + * The caller must wait for all work that used the reserved VMID to finish + * before, so submissions still in flight don't suddenly fault when its page + * table gets unbound. */ void amdgpu_vmid_free_spm(struct amdgpu_device *adev, struct amdgpu_vm *vm, unsigned vmhub) @@ -649,9 +650,6 @@ void amdgpu_vmid_free_spm(struct amdgpu_device *adev, struct amdgpu_vm *vm, vm->reserved_vmid[vmhub] = NULL; id_mgr->reserved_vmid = false; - /* Only for kernel queues and kfd/userqueues by pass that */ - amdgpu_sync_wait(&id->active, false); - if (adev->vm_manager.spm_vmid && adev->gfxhub.funcs) amdgpu_gmc_bind_vmid(adev, AMDGPU_GFXHUB(0), adev->vm_manager.spm_vmid, 0); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 9cc210198fa4..8689a3c933b2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -313,22 +313,7 @@ void amdgpu_job_free_resources(struct amdgpu_job *job) static void amdgpu_job_free_cb(struct drm_sched_job *s_job) { - struct amdgpu_job *job = to_amdgpu_job(s_job); - - drm_sched_job_cleanup(s_job); - - amdgpu_sync_free(&job->explicit_sync); - - if (dma_fence_was_initialized(&job->hw_fence->base)) - dma_fence_put(&job->hw_fence->base); - else - kfree(job->hw_fence); - if (dma_fence_was_initialized(&job->hw_vm_fence->base)) - dma_fence_put(&job->hw_vm_fence->base); - else - kfree(job->hw_vm_fence); - - kfree(job); + amdgpu_job_free(to_amdgpu_job(s_job)); } void amdgpu_job_set_gang_leader(struct amdgpu_job *job, @@ -349,13 +334,14 @@ void amdgpu_job_set_gang_leader(struct amdgpu_job *job, void amdgpu_job_free(struct amdgpu_job *job) { - if (job->base.entity) + if (job->gang_submit != &job->base.s_fence->scheduled) + dma_fence_put(job->gang_submit); + + if (job->base.s_fence) drm_sched_job_cleanup(&job->base); amdgpu_job_free_resources(job); amdgpu_sync_free(&job->explicit_sync); - if (job->gang_submit != &job->base.s_fence->scheduled) - dma_fence_put(job->gang_submit); if (dma_fence_was_initialized(&job->hw_fence->base)) dma_fence_put(&job->hw_fence->base); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index 36bc4b431dd5..01dca6858833 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -4157,8 +4157,6 @@ static int psp_hw_init(struct amdgpu_ip_block *ip_block) int ret; struct amdgpu_device *adev = ip_block->adev; - mutex_lock(&adev->firmware.mutex); - ret = amdgpu_ucode_init_bo(adev); if (ret) goto failed; @@ -4169,12 +4167,10 @@ static int psp_hw_init(struct amdgpu_ip_block *ip_block) goto failed; } - mutex_unlock(&adev->firmware.mutex); return 0; failed: adev->firmware.load_type = AMDGPU_FW_LOAD_DIRECT; - mutex_unlock(&adev->firmware.mutex); return -EINVAL; } @@ -4282,8 +4278,6 @@ static int psp_resume(struct amdgpu_ip_block *ip_block) } } - mutex_lock(&adev->firmware.mutex); - ret = amdgpu_ucode_init_bo(adev); if (ret) goto failed; @@ -4345,13 +4339,10 @@ static int psp_resume(struct amdgpu_ip_block *ip_block) "SECUREDISPLAY: Failed to initialize SECUREDISPLAY\n"); } - mutex_unlock(&adev->firmware.mutex); - return 0; failed: dev_err(adev->dev, "PSP resume failed\n"); - mutex_unlock(&adev->firmware.mutex); return ret; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c index 227734541316..7b67e8cecca2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c @@ -213,11 +213,9 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring, unsigned int irq_type, unsigned int hw_prio, atomic_t *sched_score) { - int r; int sched_hw_submission = amdgpu_sched_hw_submission; - u32 *num_sched; - u32 hw_ip; unsigned int max_ibs_dw; + int r; /* Set the hw submission limit higher for KIQ because * it's used for a number of gfx/compute tasks by both @@ -359,10 +357,10 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring, ring->vmid_wait = dma_fence_get_stub(); if (!ring->no_scheduler && ring->funcs->type < AMDGPU_HW_IP_NUM) { - hw_ip = ring->funcs->type; - num_sched = &adev->gpu_sched[hw_ip][hw_prio].num_scheds; - adev->gpu_sched[hw_ip][hw_prio].sched[(*num_sched)++] = - &ring->sched; + struct amdgpu_sched *gpu_sched = + &adev->gpu_sched[ring->funcs->type][hw_prio]; + + gpu_sched->sched[gpu_sched->num_scheds++] = &ring->sched; } return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h index adb6cfae5052..9856a2fc2d08 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h @@ -30,6 +30,7 @@ #include "amdgpu_vram_mgr.h" #include "amdgpu_hmm.h" #include "amdgpu_gmc.h" +#include "amdgpu_sdma_types.h" #define AMDGPU_PL_GDS (TTM_PL_PRIV + 0) #define AMDGPU_PL_GWS (TTM_PL_PRIV + 1) @@ -89,7 +90,7 @@ struct amdgpu_mman { /* buffer handling */ const struct amdgpu_buffer_funcs *buffer_funcs; - struct drm_gpu_scheduler *buffer_funcs_scheds[AMDGPU_MAX_RINGS]; + struct drm_gpu_scheduler *buffer_funcs_scheds[AMDGPU_MAX_SDMA_INSTANCES]; u32 num_buffer_funcs_scheds; bool buffer_funcs_enabled; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h index 35277b240f25..7c809692807f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h @@ -612,7 +612,6 @@ struct amdgpu_firmware { /* firmwares are loaded by psp instead of smu from vega10 */ const struct amdgpu_psp_funcs *funcs; struct amdgpu_bo *rbuf; - struct mutex mutex; /* gpu info firmware data pointer */ const struct firmware *gpu_info_fw; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index ecd7caa95d4b..cd35ff7ca864 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -377,7 +377,8 @@ int amdgpu_uvd_sw_fini(struct amdgpu_device *adev) void *addr = amdgpu_bo_kptr(adev->uvd.ib_bo); int i, j; - drm_sched_entity_destroy(&adev->uvd.entity); + if (adev->uvd.entity.rq) + drm_sched_entity_destroy(&adev->uvd.entity); for (j = 0; j < adev->uvd.num_uvd_inst; ++j) { if (adev->uvd.harvest_config & (1 << j)) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index 1f7a98cdce5a..3952af9ae115 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -253,7 +253,8 @@ int amdgpu_vce_sw_fini(struct amdgpu_device *adev) if (adev->vce.vcpu_bo == NULL) return 0; - drm_sched_entity_destroy(&adev->vce.entity); + if (adev->vce.entity.rq) + drm_sched_entity_destroy(&adev->vce.entity); for (i = 0; i < adev->vce.num_rings; i++) amdgpu_ring_fini(&adev->vce.ring[i]); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 613c0b43ea3d..65974c0e7a16 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -630,7 +630,6 @@ int amdgpu_vm_validate(struct amdgpu_device *adev, struct amdgpu_vm *vm, dma_resv_assert_held(vm->root.bo->tbo.base.resv); if (vm->generation != new_vm_generation) { - vm->generation = new_vm_generation; amdgpu_vm_bo_reset_state_machine(vm); amdgpu_vm_fini_entities(vm); r = amdgpu_vm_init_entities(adev, vm); @@ -645,9 +644,18 @@ int amdgpu_vm_validate(struct amdgpu_device *adev, struct amdgpu_vm *vm, vm->update_funcs->map_table(to_amdgpu_bo_vm(bo_base->bo)); bo_base->moved = true; + + if (vm->generation != new_vm_generation) { + r = amdgpu_vm_pt_clear(adev, vm, to_amdgpu_bo_vm(bo_base->bo), false); + if (r) + return r; + } + amdgpu_vm_bo_needs_update(bo_base); } + vm->generation = new_vm_generation; + /* * As soon as all page tables are in place we can start updating them * again. @@ -2852,6 +2860,10 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm) root = amdgpu_bo_ref(vm->root.bo); amdgpu_bo_reserve(root, true); + /* Wait for the jobs which might still use the reserved VMID */ + if (vm->reserved_vmid[AMDGPU_GFXHUB(0)]) + dma_resv_wait_timeout(root->tbo.base.resv, DMA_RESV_USAGE_READ, + false, MAX_SCHEDULE_TIMEOUT); dma_fence_wait(vm->last_unlocked, false); dma_fence_put(vm->last_unlocked); dma_fence_wait(vm->last_tlb_flush, false); @@ -3002,9 +3014,19 @@ int amdgpu_vm_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) } return r; } - case AMDGPU_VM_OP_UNRESERVE_VMID: + case AMDGPU_VM_OP_UNRESERVE_VMID: { + struct amdgpu_bo *root = vm->root.bo; + + amdgpu_bo_reserve(root, true); + /* Wait for the jobs which might still use the reserved VMID */ + if (vm->reserved_vmid[AMDGPU_GFXHUB(0)]) + dma_resv_wait_timeout(root->tbo.base.resv, + DMA_RESV_USAGE_READ, false, + MAX_SCHEDULE_TIMEOUT); amdgpu_vmid_free_spm(adev, vm, AMDGPU_GFXHUB(0)); + amdgpu_bo_unreserve(root); break; + } default: return -EINVAL; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h index 2a2a2ccbaa2c..06e0ddd60c7b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h @@ -395,7 +395,7 @@ struct amdgpu_vm_manager { u64 vram_base_offset; /* vm pte handling */ const struct amdgpu_vm_pte_funcs *vm_pte_funcs; - struct drm_gpu_scheduler *vm_pte_scheds[AMDGPU_MAX_RINGS]; + struct drm_gpu_scheduler *vm_pte_scheds[AMDGPU_MAX_SDMA_INSTANCES]; unsigned vm_pte_num_scheds; struct amdgpu_ring *page_fault; diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c index b2e4da70d208..fa5810209f37 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c @@ -1034,6 +1034,12 @@ static int mes_v11_0_misc_op(struct amdgpu_mes *mes, memcpy(misc_pkt.set_shader_debugger.tcp_watch_cntl, input->set_shader_debugger.tcp_watch_cntl, sizeof(misc_pkt.set_shader_debugger.tcp_watch_cntl)); + for (int i = 0; i < 4; i++) { + misc_pkt.set_shader_debugger.tcp_watch_addr_lo[i] = + lower_32_bits(input->set_shader_debugger.watch_addresses[i]); + misc_pkt.set_shader_debugger.tcp_watch_addr_hi[i] = + upper_32_bits(input->set_shader_debugger.watch_addresses[i]) & 0xffff; + } misc_pkt.set_shader_debugger.trap_en = input->set_shader_debugger.trap_en; break; case MES_MISC_OP_CHANGE_CONFIG: diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c index ce577f49b630..496ac632c3e5 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c @@ -983,6 +983,12 @@ static int mes_v12_0_misc_op(struct amdgpu_mes *mes, memcpy(misc_pkt.set_shader_debugger.tcp_watch_cntl, input->set_shader_debugger.tcp_watch_cntl, sizeof(misc_pkt.set_shader_debugger.tcp_watch_cntl)); + for (int i = 0; i < 4; i++) { + misc_pkt.set_shader_debugger.tcp_watch_addr_lo[i] = + lower_32_bits(input->set_shader_debugger.watch_addresses[i]); + misc_pkt.set_shader_debugger.tcp_watch_addr_hi[i] = + upper_32_bits(input->set_shader_debugger.watch_addresses[i]) & 0xffff; + } misc_pkt.set_shader_debugger.trap_en = input->set_shader_debugger.trap_en; break; case MES_MISC_OP_CHANGE_CONFIG: diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c b/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c index 99e8a7eeaa4b..5573fe981a22 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c @@ -624,6 +624,12 @@ static int mes_v12_1_misc_op(struct amdgpu_mes *mes, memcpy(misc_pkt.set_shader_debugger.tcp_watch_cntl, input->set_shader_debugger.tcp_watch_cntl, sizeof(misc_pkt.set_shader_debugger.tcp_watch_cntl)); + for (int i = 0; i < 4; i++) { + misc_pkt.set_shader_debugger.tcp_watch_addr_lo[i] = + lower_32_bits(input->set_shader_debugger.watch_addresses[i]); + misc_pkt.set_shader_debugger.tcp_watch_addr_hi[i] = + upper_32_bits(input->set_shader_debugger.watch_addresses[i]) & 0xffff; + } misc_pkt.set_shader_debugger.trap_en = input->set_shader_debugger.trap_en; break; case MES_MISC_OP_CHANGE_CONFIG: diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 5f8fb934720b..1115f7ebd665 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -2876,6 +2876,7 @@ static int criu_process_info(struct file *filep, struct kfd_process *p, struct kfd_ioctl_criu_args *args) { + bool paused_here = false; int ret = 0; mutex_lock(&p->mutex); @@ -2886,11 +2887,15 @@ static int criu_process_info(struct file *filep, goto err_unlock; } - ret = kfd_process_evict_queues(p, KFD_QUEUE_EVICTION_CRIU_CHECKPOINT); - if (ret) - goto err_unlock; + /* UNPAUSE restores the queues once, so evict them only once */ + if (!p->queues_paused) { + ret = kfd_process_evict_queues(p, KFD_QUEUE_EVICTION_CRIU_CHECKPOINT); + if (ret) + goto err_unlock; - p->queues_paused = true; + p->queues_paused = true; + paused_here = true; + } args->pid = task_pid_nr_ns(p->lead_thread, task_active_pid_ns(p->lead_thread)); @@ -2905,7 +2910,7 @@ static int criu_process_info(struct file *filep, args->priv_data_size); err_unlock: - if (ret) { + if (ret && paused_here) { kfd_process_restore_queues(p); p->queues_paused = false; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c index 6e0df685503d..32d7573dffc9 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c @@ -2056,27 +2056,33 @@ static void kfd_find_numa_node_in_srat(struct kfd_node *kdev) return; } + if (table_header->length < sizeof(struct acpi_table_srat)) + goto invalid_srat; + table_end = (unsigned long)table_header + table_header->length; /* Parse all entries looking for a match. */ sub_header = (struct acpi_subtable_header *) ((unsigned long)table_header + sizeof(struct acpi_table_srat)); - subtable_len = sub_header->length; - while (((unsigned long)sub_header) + subtable_len < table_end) { - /* - * If length is 0, break from this loop to avoid - * infinite loop. - */ - if (subtable_len == 0) { - pr_err("SRAT invalid zero length\n"); - break; - } + while ((unsigned long)sub_header < table_end) { + unsigned long start = (unsigned long)sub_header; + + if (table_end - start < sizeof(*sub_header)) + goto invalid_srat; + + subtable_len = sub_header->length; + if (subtable_len < sizeof(*sub_header) || + subtable_len > table_end - start) + goto invalid_srat; switch (sub_header->type) { case ACPI_SRAT_TYPE_CPU_AFFINITY: cpu = (struct acpi_srat_cpu_affinity *)sub_header; + if (subtable_len < sizeof(*cpu)) + goto invalid_srat; + pxm = *((u32 *)cpu->proximity_domain_hi) << 8 | cpu->proximity_domain_lo; if (pxm > max_pxm) @@ -2084,6 +2090,9 @@ static void kfd_find_numa_node_in_srat(struct kfd_node *kdev) break; case ACPI_SRAT_TYPE_GENERIC_AFFINITY: gpu = (struct acpi_srat_generic_affinity *)sub_header; + if (subtable_len < sizeof(*gpu)) + goto invalid_srat; + bdf = *((u16 *)(&gpu->device_handle[0])) << 16 | *((u16 *)(&gpu->device_handle[2])); if (bdf == pci_id) { @@ -2100,9 +2109,13 @@ static void kfd_find_numa_node_in_srat(struct kfd_node *kdev) sub_header = (struct acpi_subtable_header *) ((unsigned long)sub_header + subtable_len); - subtable_len = sub_header->length; } + goto out; + +invalid_srat: + pr_err("SRAT contains an invalid subtable\n"); +out: acpi_put_table(table_header); /* Workaround bad cpu-gpu binding case */ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index bb4c6695f3cf..0f96c9e3fa4d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -1814,7 +1814,14 @@ void kgd2kfd_teardown_processes(struct amdgpu_device *adev) mutex_unlock(&kfd_processes_mutex); - /* wait all kfd processes use adev terminate */ + /* kfd.dev may already be freed on surprise removal */ + if (!adev->kfd.dev) + return; + + /* + * Wait for all KFD processes using adev to terminate. Must be + * unbounded: device state is freed once they are gone. + */ while (!!atomic_read(&adev->kfd.dev->kfd_processes_count)) cond_resched(); } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h index 38b46b696243..d63f7e9fae30 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h @@ -138,6 +138,15 @@ struct mqd_manager { uint32_t ctl_stack_size; }; +/* Keep offset <= size <= wave state offset, as init_mqd() and CP do */ +static inline void kfd_mqd_restore_ctl_stack(u32 *size, u32 *offset, u32 *wg_offset, + u32 ctl_stack_size) +{ + *size = ctl_stack_size; + *offset = min(*offset, ctl_stack_size); + *wg_offset = max(*wg_offset, ctl_stack_size); +} + struct mqd_user_context_save_area_header { /* Byte offset from start of user context * save area to the last saved top (lowest diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c index 4f8a8a1a6186..922615b713a9 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c @@ -305,6 +305,8 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd, addr = mqd_mem_obj->gpu_addr; memcpy(m, mqd_src, sizeof(*m)); + kfd_mqd_restore_ctl_stack(&m->cp_hqd_cntl_stack_size, &m->cp_hqd_cntl_stack_offset, + &m->cp_hqd_wg_state_offset, qp->ctl_stack_size); *mqd = m; if (gart_addr) @@ -396,6 +398,13 @@ static void update_mqd_sdma(struct mqd_manager *mm, void *mqd, m->sdma_queue_id = q->sdma_queue_id; m->sdmax_rlcx_dummy_reg = SDMA_RLC_DUMMY_DEFAULT; + /* Enable IB execution; allow context switch inside an IB so one + * queue cannot starve the engine. + */ + m->sdmax_rlcx_ib_cntl |= + SDMA0_RLC0_IB_CNTL__IB_ENABLE_MASK | + SDMA0_RLC0_IB_CNTL__SWITCH_INSIDE_IB_MASK; + q->is_active = QUEUE_IS_ACTIVE(*q); } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c index bf015dc5b868..62c3023152a5 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c @@ -340,6 +340,8 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd, addr = mqd_mem_obj->gpu_addr; memcpy(m, mqd_src, sizeof(*m)); + kfd_mqd_restore_ctl_stack(&m->cp_hqd_cntl_stack_size, &m->cp_hqd_cntl_stack_offset, + &m->cp_hqd_wg_state_offset, qp->ctl_stack_size); *mqd = m; if (gart_addr) @@ -478,6 +480,13 @@ static void update_mqd_sdma(struct mqd_manager *mm, void *mqd, m->sdma_queue_id = q->sdma_queue_id; m->sdmax_rlcx_dummy_reg = SDMA_RLC_DUMMY_DEFAULT; + /* Enable IB execution; allow context switch inside an IB so one + * queue cannot starve the engine. + */ + m->sdmax_rlcx_ib_cntl |= + SDMA0_QUEUE0_IB_CNTL__IB_ENABLE_MASK | + SDMA0_QUEUE0_IB_CNTL__SWITCH_INSIDE_IB_MASK; + q->is_active = QUEUE_IS_ACTIVE(*q); } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c index 6ea09b031caf..1d9b4890909f 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c @@ -353,11 +353,12 @@ static void update_mqd_sdma(struct mqd_manager *mm, void *mqd, m->sdmax_rlcx_dummy_reg = SDMA_RLC_DUMMY_DEFAULT; - /* Allow context switch so we don't cross-process starve with a massive - * command buffer of long-running SDMA commands - * sdmax_rlcx_ib_cntl represent SDMA_QUEUE0_IB_CNTL register - */ - m->sdmax_rlcx_ib_cntl |= SDMA0_QUEUE0_IB_CNTL__SWITCH_INSIDE_IB_MASK; + /* Enable IB execution; allow context switch inside an IB so one + * queue cannot starve the engine. + */ + m->sdmax_rlcx_ib_cntl |= + SDMA0_QUEUE0_IB_CNTL__IB_ENABLE_MASK | + SDMA0_QUEUE0_IB_CNTL__SWITCH_INSIDE_IB_MASK; q->is_active = QUEUE_IS_ACTIVE(*q); } @@ -393,6 +394,8 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd, memset(m, 0, AMDGPU_MQD_SIZE_ALIGN(mm->mqd_size)); memcpy(m, mqd_src, sizeof(*m)); + kfd_mqd_restore_ctl_stack(&m->cp_hqd_cntl_stack_size, &m->cp_hqd_cntl_stack_offset, + &m->cp_hqd_wg_state_offset, qp->ctl_stack_size); /* Update MQD base address to the newly allocated location */ m->cp_mqd_base_addr_lo = lower_32_bits(addr); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c index 2bbf5e63f615..e34103067fa0 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c @@ -457,11 +457,12 @@ static void update_mqd_sdma(struct mqd_manager *mm, void *mqd, m->sdmax_queuen_dummy_reg1 = 1; - /* Allow context switch so we don't cross-process starve with a massive - * command buffer of long-running SDMA commands - * sdmax_queuen_ib_cntl represent SDMA_QUEUE0_IB_CNTL register - */ - m->sdmax_queuen_ib_cntl |= SDMA0_SDMA_QUEUE0_IB_CNTL__SWITCH_INSIDE_IB_MASK; + /* Enable IB execution; allow context switch inside an IB so one + * queue cannot starve the engine. + */ + m->sdmax_queuen_ib_cntl |= + SDMA0_SDMA_QUEUE0_IB_CNTL__IB_ENABLE_MASK | + SDMA0_SDMA_QUEUE0_IB_CNTL__SWITCH_INSIDE_IB_MASK; q->is_active = QUEUE_IS_ACTIVE(*q); } @@ -692,6 +693,8 @@ static void restore_mqd_v12_1(struct mqd_manager *mm, void **mqd, memset(m, 0, AMDGPU_MQD_SIZE_ALIGN(mm->mqd_size) * NUM_XCC(mm->dev->xcc_mask)); memcpy(m, mqd_src, sizeof(*m)); + kfd_mqd_restore_ctl_stack(&m->cp_hqd_cntl_stack_size, &m->cp_hqd_cntl_stack_offset, + &m->cp_hqd_wg_state_offset, qp->ctl_stack_size); /* Update MQD base address to the newly allocated location */ m->cp_mqd_base_addr_lo = lower_32_bits(addr); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c index 6e6bc1ec0b64..e18c86c87d1c 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c @@ -462,6 +462,8 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd, addr = mqd_mem_obj->gpu_addr; memcpy(m, mqd_src, sizeof(*m)); + kfd_mqd_restore_ctl_stack(&m->cp_hqd_cntl_stack_size, &m->cp_hqd_cntl_stack_offset, + &m->cp_hqd_wg_state_offset, qp->ctl_stack_size); *mqd = m; if (gart_addr) @@ -569,10 +571,12 @@ static void update_mqd_sdma(struct mqd_manager *mm, void *mqd, m->sdma_engine_id = q->sdma_engine_id; m->sdma_queue_id = q->sdma_queue_id; m->sdmax_rlcx_dummy_reg = SDMA_RLC_DUMMY_DEFAULT; - /* Allow context switch so we don't cross-process starve with a massive - * command buffer of long-running SDMA commands + /* Enable IB execution; allow context switch inside an IB so one + * queue cannot starve the engine. */ - m->sdmax_rlcx_ib_cntl |= SDMA0_GFX_IB_CNTL__SWITCH_INSIDE_IB_MASK; + m->sdmax_rlcx_ib_cntl |= + SDMA0_GFX_IB_CNTL__IB_ENABLE_MASK | + SDMA0_GFX_IB_CNTL__SWITCH_INSIDE_IB_MASK; q->is_active = QUEUE_IS_ACTIVE(*q); } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c index 029572548c14..5ead0d5613b6 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c @@ -317,6 +317,8 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd, addr = mqd_mem_obj->gpu_addr; memcpy(m, mqd_src, sizeof(*m)); + kfd_mqd_restore_ctl_stack(&m->cp_hqd_cntl_stack_size, &m->cp_hqd_cntl_stack_offset, + &m->cp_hqd_wg_state_offset, qp->ctl_stack_size); *mqd = m; if (gart_addr) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c index a15a826519ad..78ab759ad854 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c @@ -26,6 +26,7 @@ #include <linux/list.h> #include "kfd_device_queue_manager.h" #include "kfd_priv.h" +#include "kfd_topology.h" #include "kfd_kernel_queue.h" #include "amdgpu_amdkfd.h" #include "amdgpu_reset.h" @@ -983,7 +984,7 @@ int kfd_criu_checkpoint_queues(struct kfd_process *p, } static void set_queue_properties_from_criu(struct queue_properties *qp, - struct kfd_criu_queue_priv_data *q_data, uint32_t num_xcc) + struct kfd_criu_queue_priv_data *q_data) { qp->is_interop = false; qp->queue_percent = q_data->q_percent; @@ -996,11 +997,6 @@ static void set_queue_properties_from_criu(struct queue_properties *qp, qp->eop_ring_buffer_size = q_data->eop_ring_buffer_size; qp->ctx_save_restore_area_address = q_data->ctx_save_restore_area_address; qp->ctx_save_restore_area_size = q_data->ctx_save_restore_area_size; - if (q_data->type == KFD_QUEUE_TYPE_COMPUTE) - qp->ctl_stack_size = q_data->ctl_stack_size / num_xcc; - else - qp->ctl_stack_size = q_data->ctl_stack_size; - qp->type = q_data->type; qp->format = q_data->format; } @@ -1012,6 +1008,7 @@ int kfd_criu_restore_queue(struct kfd_process *p, { uint8_t *mqd, *ctl_stack, *q_extra_data = NULL; struct kfd_criu_queue_priv_data *q_data; + struct kfd_topology_device *topo_dev; struct kfd_process_device *pdd; uint64_t q_extra_data_size; struct queue_properties qp; @@ -1048,6 +1045,24 @@ int kfd_criu_restore_queue(struct kfd_process *p, goto exit; } + memset(&qp, 0, sizeof(qp)); + set_queue_properties_from_criu(&qp, q_data); + + /* Per-XCC control stack size from topology, as create-queue requires */ + if (qp.type == KFD_QUEUE_TYPE_COMPUTE && pdd->dev->kfd->cwsr_enabled) { + topo_dev = kfd_topology_device_by_id(pdd->dev->id); + if (!topo_dev) { + ret = -EINVAL; + goto exit; + } + qp.ctl_stack_size = topo_dev->node_props.ctl_stack_size; + } + + if (q_data->ctl_stack_size > (u64)qp.ctl_stack_size * NUM_XCC(pdd->dev->xcc_mask)) { + ret = -EINVAL; + goto exit; + } + *priv_data_offset += sizeof(*q_data); q_extra_data_size = (uint64_t)q_data->ctl_stack_size + q_data->mqd_size; @@ -1077,9 +1092,6 @@ int kfd_criu_restore_queue(struct kfd_process *p, mqd = q_extra_data; ctl_stack = mqd + q_data->mqd_size; - memset(&qp, 0, sizeof(qp)); - set_queue_properties_from_criu(&qp, q_data, NUM_XCC(pdd->dev->xcc_mask)); - print_queue_properties(&qp); ret = pqm_create_queue(&p->pqm, pdd->dev, &qp, &queue_id, q_data, mqd, ctl_stack, NULL); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c index 6a7b4d959541..c87370a9f5f0 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c @@ -40,7 +40,7 @@ struct kfd_smi_client { struct kfd_node *dev; spinlock_t lock; struct rcu_head rcu; - pid_t pid; + pid_t tgid; bool suser; }; @@ -160,18 +160,18 @@ static int kfd_smi_ev_release(struct inode *inode, struct file *filep) return 0; } -static bool kfd_smi_ev_enabled(pid_t pid, struct kfd_smi_client *client, +static bool kfd_smi_ev_enabled(pid_t tgid, struct kfd_smi_client *client, unsigned int event) { uint64_t events = READ_ONCE(client->events); - if (pid && client->pid != pid && !client->suser) + if (tgid && client->tgid != tgid && !client->suser) return false; return events & KFD_SMI_EVENT_MASK_FROM_INDEX(event); } -static void add_event_to_kfifo(pid_t pid, struct kfd_node *dev, +static void add_event_to_kfifo(pid_t tgid, struct kfd_node *dev, unsigned int smi_event, char *event_msg, int len) { struct kfd_smi_client *client; @@ -179,7 +179,7 @@ static void add_event_to_kfifo(pid_t pid, struct kfd_node *dev, rcu_read_lock(); list_for_each_entry_rcu(client, &dev->smi_clients, list) { - if (!kfd_smi_ev_enabled(pid, client, smi_event)) + if (!kfd_smi_ev_enabled(tgid, client, smi_event)) continue; spin_lock(&client->lock); if (kfifo_avail(&client->fifo) >= len) { @@ -210,27 +210,33 @@ static inline pid_t kfd_smi_task_to_pid(struct task_struct *task) return task ? task_tgid_nr_ns(task, task_active_pid_ns(task)) : 0; } +/* + * Clients are matched by global TGID, which is unique across PID namespaces + * and stays valid after the task exited. Events show kfd_smi_task_to_pid(). + */ +static inline pid_t kfd_smi_task_tgid(struct task_struct *task) +{ + return task ? task_tgid_nr(task) : 0; +} + __printf(4, 5) -static void kfd_smi_event_add(struct task_struct *task, struct kfd_node *dev, +static void kfd_smi_event_add(pid_t tgid, struct kfd_node *dev, unsigned int event, char *fmt, ...) { char fifo_in[KFD_SMI_EVENT_MSG_SIZE]; int len; va_list args; - pid_t pid; if (list_empty(&dev->smi_clients)) return; - pid = kfd_smi_task_to_pid(task); - len = scnprintf(fifo_in, sizeof(fifo_in), "%x ", event); va_start(args, fmt); len += vscnprintf(fifo_in + len, sizeof(fifo_in) - len, fmt, args); va_end(args); - add_event_to_kfifo(pid, dev, event, fifo_in, len); + add_event_to_kfifo(tgid, dev, event, fifo_in, len); } void kfd_smi_event_update_gpu_reset(struct kfd_node *dev, bool post_reset, @@ -252,14 +258,14 @@ void kfd_smi_event_update_gpu_reset(struct kfd_node *dev, bool post_reset, amdgpu_reset_get_desc(reset_context, reset_cause, sizeof(reset_cause)); - kfd_smi_event_add(NULL, dev, event, KFD_EVENT_FMT_UPDATE_GPU_RESET( + kfd_smi_event_add(0, dev, event, KFD_EVENT_FMT_UPDATE_GPU_RESET( dev->reset_seq_num, reset_cause)); } void kfd_smi_event_update_thermal_throttling(struct kfd_node *dev, uint64_t throttle_bitmask) { - kfd_smi_event_add(NULL, dev, KFD_SMI_EVENT_THERMAL_THROTTLE, + kfd_smi_event_add(0, dev, KFD_SMI_EVENT_THERMAL_THROTTLE, KFD_EVENT_FMT_THERMAL_THROTTLING( throttle_bitmask, amdgpu_dpm_get_thermal_throttling_counter(dev->adev))); @@ -271,10 +277,14 @@ void kfd_smi_event_update_vmfault(struct kfd_node *dev, uint16_t pasid) task_info = amdgpu_vm_get_task_info_pasid(dev->adev, pasid); if (task_info) { - /* Report VM faults from user applications, not retry from kernel */ + /* + * Report VM faults from user applications, not retry from + * kernel, and only to clients allowed to see that process. + */ if (task_info->task.pid) - kfd_smi_event_add(NULL, dev, KFD_SMI_EVENT_VMFAULT, KFD_EVENT_FMT_VMFAULT( - task_info->task.pid, task_info->task.comm)); + kfd_smi_event_add(task_info->tgid, dev, KFD_SMI_EVENT_VMFAULT, + KFD_EVENT_FMT_VMFAULT(task_info->task.pid, + task_info->task.comm)); amdgpu_vm_put_task_info(task_info); } } @@ -283,7 +293,7 @@ void kfd_smi_event_page_fault_start(struct kfd_node *node, struct task_struct *t unsigned long address, bool write_fault, ktime_t ts) { - kfd_smi_event_add(task, node, KFD_SMI_EVENT_PAGE_FAULT_START, + kfd_smi_event_add(kfd_smi_task_tgid(task), node, KFD_SMI_EVENT_PAGE_FAULT_START, KFD_EVENT_FMT_PAGEFAULT_START(ktime_to_ns(ts), kfd_smi_task_to_pid(task), address, node->id, write_fault ? 'W' : 'R')); @@ -292,7 +302,7 @@ void kfd_smi_event_page_fault_start(struct kfd_node *node, struct task_struct *t void kfd_smi_event_page_fault_end(struct kfd_node *node, struct task_struct *task, unsigned long address, bool migration) { - kfd_smi_event_add(task, node, KFD_SMI_EVENT_PAGE_FAULT_END, + kfd_smi_event_add(kfd_smi_task_tgid(task), node, KFD_SMI_EVENT_PAGE_FAULT_END, KFD_EVENT_FMT_PAGEFAULT_END(ktime_get_boottime_ns(), kfd_smi_task_to_pid(task), address, node->id, migration ? 'M' : 'U')); @@ -304,7 +314,7 @@ void kfd_smi_event_migration_start(struct kfd_node *node, struct task_struct *ta uint32_t prefetch_loc, uint32_t preferred_loc, uint32_t trigger) { - kfd_smi_event_add(task, node, KFD_SMI_EVENT_MIGRATE_START, + kfd_smi_event_add(kfd_smi_task_tgid(task), node, KFD_SMI_EVENT_MIGRATE_START, KFD_EVENT_FMT_MIGRATE_START(ktime_get_boottime_ns(), kfd_smi_task_to_pid(task), start, end - start, from, to, prefetch_loc, preferred_loc, trigger)); @@ -315,7 +325,7 @@ void kfd_smi_event_migration_end(struct kfd_node *node, struct task_struct *task uint32_t from, uint32_t to, uint32_t trigger, int error_code) { - kfd_smi_event_add(task, node, KFD_SMI_EVENT_MIGRATE_END, + kfd_smi_event_add(kfd_smi_task_tgid(task), node, KFD_SMI_EVENT_MIGRATE_END, KFD_EVENT_FMT_MIGRATE_END(ktime_get_boottime_ns(), kfd_smi_task_to_pid(task), start, end - start, from, to, trigger, error_code)); @@ -324,14 +334,14 @@ void kfd_smi_event_migration_end(struct kfd_node *node, struct task_struct *task void kfd_smi_event_queue_eviction(struct kfd_node *node, struct task_struct *task, uint32_t trigger) { - kfd_smi_event_add(task, node, KFD_SMI_EVENT_QUEUE_EVICTION, + kfd_smi_event_add(kfd_smi_task_tgid(task), node, KFD_SMI_EVENT_QUEUE_EVICTION, KFD_EVENT_FMT_QUEUE_EVICTION(ktime_get_boottime_ns(), kfd_smi_task_to_pid(task), node->id, trigger)); } void kfd_smi_event_queue_restore(struct kfd_node *node, struct task_struct *task) { - kfd_smi_event_add(task, node, KFD_SMI_EVENT_QUEUE_RESTORE, + kfd_smi_event_add(kfd_smi_task_tgid(task), node, KFD_SMI_EVENT_QUEUE_RESTORE, KFD_EVENT_FMT_QUEUE_RESTORE(ktime_get_boottime_ns(), kfd_smi_task_to_pid(task), node->id, '0')); } @@ -348,7 +358,7 @@ void kfd_smi_event_queue_restore_rescheduled(struct mm_struct *mm) for (i = 0; i < p->n_pdds; i++) { struct kfd_process_device *pdd = p->pdds[i]; - kfd_smi_event_add(p->lead_thread, pdd->dev, + kfd_smi_event_add(kfd_smi_task_tgid(p->lead_thread), pdd->dev, KFD_SMI_EVENT_QUEUE_RESTORE, KFD_EVENT_FMT_QUEUE_RESTORE(ktime_get_boottime_ns(), kfd_smi_task_to_pid(p->lead_thread), @@ -361,7 +371,7 @@ void kfd_smi_event_unmap_from_gpu(struct kfd_node *node, struct task_struct *tas unsigned long address, unsigned long last, uint32_t trigger) { - kfd_smi_event_add(task, node, KFD_SMI_EVENT_UNMAP_FROM_GPU, + kfd_smi_event_add(kfd_smi_task_tgid(task), node, KFD_SMI_EVENT_UNMAP_FROM_GPU, KFD_EVENT_FMT_UNMAP_FROM_GPU(ktime_get_boottime_ns(), kfd_smi_task_to_pid(task), address, last - address + 1, node->id, trigger)); @@ -379,7 +389,7 @@ void kfd_smi_event_process(struct kfd_process_device *pdd, bool start) task_info = amdgpu_vm_get_task_info_vm(avm); if (task_info) { - kfd_smi_event_add(NULL, pdd->dev, + kfd_smi_event_add(kfd_smi_task_tgid(pdd->process->lead_thread), pdd->dev, start ? KFD_SMI_EVENT_PROCESS_START : KFD_SMI_EVENT_PROCESS_END, KFD_EVENT_FMT_PROCESS(task_info->task.pid, @@ -408,7 +418,7 @@ int kfd_smi_event_open(struct kfd_node *dev, uint32_t *fd) spin_lock_init(&client->lock); client->events = 0; client->dev = dev; - client->pid = kfd_smi_task_to_pid(current); + client->tgid = kfd_smi_task_tgid(current); client->suser = capable(CAP_SYS_ADMIN); spin_lock(&dev->smi_lock); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 1f5d73f0ebce..ed5e3318877b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -1020,9 +1020,12 @@ svm_range_split_pages(struct svm_range *new, struct svm_range *old, uint64_t start, uint64_t last) { uint64_t npages = last - start + 1; + bool has_dma_addr = false; int i, r; for (i = 0; i < MAX_GPU_INSTANCE; i++) { + if (old->dma_addr[i]) + has_dma_addr = true; r = svm_range_split_array(&new->dma_addr[i], &old->dma_addr[i], sizeof(*old->dma_addr[i]), old->start, npages, new->start, new->npages, @@ -1030,8 +1033,16 @@ svm_range_split_pages(struct svm_range *new, struct svm_range *old, if (r) return r; } - if (old->actual_loc) + if (old->actual_loc) { + /* + * Pages migrated by prefetch have no dma_addr until they are + * mapped on a GPU. A fully resident range still splits exactly, + * old->npages isn't adjusted yet here. + */ + if (!has_dma_addr && old->vram_pages == old->npages) + new->vram_pages = new->npages; old->vram_pages -= new->vram_pages; + } return 0; } @@ -1963,7 +1974,7 @@ static void svm_range_restore_work(struct work_struct *work) struct mm_struct *mm; int evicted_ranges; int invalid; - int r; + int r = 0; svms = container_of(dwork, struct svm_range_list, restore_work); evicted_ranges = atomic_read(&svms->evicted_ranges); @@ -2037,8 +2048,10 @@ out_reschedule: mmap_write_unlock(mm); mutex_unlock(&process_info->lock); - /* If validation failed, reschedule another attempt */ - if (evicted_ranges) { + /* If validation failed, reschedule another attempt, unless the + * device is gone for good + */ + if (evicted_ranges && r != -ENODEV) { pr_debug("reschedule to restore svm range\n"); queue_delayed_work(system_freezable_wq, &svms->restore_work, msecs_to_jiffies(AMDGPU_SVM_RANGE_RESTORE_DELAY_MS)); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index 35b3abe57b80..1ef4d26a0ac6 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -2091,7 +2091,7 @@ int kfd_topology_add_device(struct kfd_node *gpu) * needed for the topology */ for (i = 0; i < KFD_TOPOLOGY_PUBLIC_NAME_SIZE-1; i++) { - dev->node_props.name[i] = __tolower(asic_name[i]); + dev->node_props.name[i] = tolower(asic_name[i]); if (asic_name[i] == '\0') break; } 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 d740108b1274..56fca4e22df8 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -716,9 +716,6 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) dc_hardware_init(adev->dm.dc); - /* Enable cursor offload if the ASIC supports it. */ - dc_dmub_srv_cursor_offload_init(adev->dm.dc); - /* GOP/vBIOS may leave an OPTC enabled for a display present at power-on * but no longer driven (e.g. an external DP unplugged at boot). Such a * dangling pipe keeps DCN out of idle and blocks s0i3. Power it down @@ -1775,7 +1772,7 @@ STATIC_IFN_KUNIT void dm_gpureset_commit_state(struct dc_state *dc_state, struct dc_scaling_info scaling_infos[MAX_SURFACES]; struct dc_flip_addrs flip_addrs[MAX_SURFACES]; struct dc_stream_update stream_update; - } *bundle __free(kfree); + } *bundle __free(kfree) = NULL; int k, m; bundle = kzalloc_obj(*bundle); @@ -2021,10 +2018,6 @@ static int dm_resume(struct amdgpu_ip_block *ip_block) /* On resume we need to rewrite the MSTM control bits to enable MST*/ s3_handle_mst(ddev, false); - /* Exit IPS before the detection loop's first AUX/DDC access. */ - scoped_guard(mutex, &dm->dc_lock) - dc_exit_ips_for_hw_access(dm->dc); - /* Do detection*/ drm_connector_list_iter_begin(ddev, &iter); drm_for_each_connector_iter(connector, &iter) { @@ -4730,8 +4723,6 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_commit *state, if (dm_old_crtc_state->stream) remove_stream(adev, acrtc, dm_old_crtc_state->stream); - pm_runtime_get_noresume(dev->dev); - acrtc->enabled = true; acrtc->hw_mode = new_crtc_state->mode; crtc->hwmode = new_crtc_state->mode; @@ -5281,10 +5272,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_commit *state) * To fix this, DC should permit updating only stream properties. */ dummy_updates = kzalloc(sizeof(struct dc_surface_update) * MAX_SURFACES, GFP_KERNEL); - if (!dummy_updates) { - drm_err(adev_to_drm(adev), "Failed to allocate memory for dummy_updates.\n"); + if (!dummy_updates) continue; - } for (j = 0; j < status->plane_count; j++) dummy_updates[j].surface = status->plane_states[j]; @@ -5315,8 +5304,13 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_commit *state) #ifdef CONFIG_DEBUG_FS enum amdgpu_dm_pipe_crc_source cur_crc_src; #endif - /* Count number of newly disabled CRTCs for dropping PM refs later. */ - if (old_crtc_state->active && !new_crtc_state->active) + /* + * One runtime PM reference per active CRTC: take it when the + * CRTC turns on, count it when it turns off for dropping later. + */ + if (!old_crtc_state->active && new_crtc_state->active) + pm_runtime_get_noresume(dev->dev); + else if (old_crtc_state->active && !new_crtc_state->active) crtc_disable_count++; dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); @@ -5342,39 +5336,39 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_commit *state) amdgpu_dm_handle_vrr_transition(dm, dm_old_crtc_state, dm_new_crtc_state); #ifdef CONFIG_DEBUG_FS - if (new_crtc_state->active && - (!old_crtc_state->active || - drm_atomic_crtc_needs_modeset(new_crtc_state))) { - /** - * Frontend may have changed so reapply the CRC capture - * settings for the stream. - */ - if (amdgpu_dm_is_valid_crc_source(cur_crc_src)) { + if (!new_crtc_state->active || + (old_crtc_state->active && !drm_atomic_crtc_needs_modeset(new_crtc_state))) + continue; + + /** + * Frontend may have changed so reapply the CRC capture + * settings for the stream. + */ + if (!amdgpu_dm_is_valid_crc_source(cur_crc_src)) + continue; + #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) - if (amdgpu_dm_crc_window_is_activated(crtc)) { - uint8_t cnt; - - spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); - for (cnt = 0; cnt < MAX_CRC_WINDOW_NUM; cnt++) { - if (acrtc->dm_irq_params.window_param[cnt].enable) { - acrtc->dm_irq_params.window_param[cnt].update_win = true; - - /** - * It takes 2 frames for HW to stably generate CRC when - * resuming from suspend, so we set skip_frame_cnt 2. - */ - acrtc->dm_irq_params.window_param[cnt].skip_frame_cnt = 2; - } - } - spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); + if (amdgpu_dm_crc_window_is_activated(crtc)) { + uint8_t cnt; + + spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); + for (cnt = 0; cnt < MAX_CRC_WINDOW_NUM; cnt++) { + if (acrtc->dm_irq_params.window_param[cnt].enable) { + acrtc->dm_irq_params.window_param[cnt].update_win = true; + + /** + * It takes 2 frames for HW to stably generate CRC when + * resuming from suspend, so we set skip_frame_cnt 2. + */ + acrtc->dm_irq_params.window_param[cnt].skip_frame_cnt = 2; } -#endif - if (amdgpu_dm_crtc_configure_crc_source( - crtc, dm_new_crtc_state, cur_crc_src)) - drm_dbg_atomic(dev, "Failed to configure crc source"); } + spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); } #endif + if (amdgpu_dm_crtc_configure_crc_source(crtc, dm_new_crtc_state, cur_crc_src)) + drm_dbg_atomic(dev, "Failed to configure crc source"); +#endif } amdgpu_dm_mod_power_setup_streams(state, dm); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index 1b91fe4c3171..e4fed8c855ab 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -65,9 +65,9 @@ enum amd_vsdb_panel_type { */ #define AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS 5000 /* -#include "include/amdgpu_dal_power_if.h" -#include "amdgpu_dm_irq.h" -*/ + * #include "include/amdgpu_dal_power_if.h" + * #include "amdgpu_dm_irq.h" + */ #include "irq_types.h" #include "signal_types.h" @@ -349,7 +349,7 @@ struct hpd_rx_irq_offload_work { * @disable_hpd_irq: disables all HPD and HPD RX interrupt handling in the * driver when true * @dmub_aux_transfer_done: struct completion used to indicate when DMUB - * transfers are done + * transfers are done * @delayed_hpd_wq: work queue used to delay DMUB HPD work */ struct amdgpu_display_manager { @@ -833,8 +833,10 @@ struct amdgpu_dm_connector { struct cec_notifier *notifier; - /* we need to mind the EDID between detect - and get modes due to analog/digital/tvencoder */ + /* + * we need to mind the EDID between detect + * and get modes due to analog/digital/tvencoder + */ const struct drm_edid *drm_edid; /* shared with amdgpu */ @@ -843,8 +845,10 @@ struct amdgpu_dm_connector { /* number of modes generated from EDID at 'dc_sink' */ int num_modes; - /* The 'old' sink - before an HPD. - * The 'current' sink is in dc_link->sink. */ + /* + * The 'old' sink - before an HPD. + * The 'current' sink is in dc_link->sink. + */ struct dc_sink *dc_sink; struct dc_link *dc_link; @@ -880,7 +884,7 @@ struct amdgpu_dm_connector { * @max_vfreq: Maximum frequency supported by the display in Hz. This * value is set to zero when there is no FreeSync support. */ - int max_vfreq ; + int max_vfreq; /* Audio instance - protected by audio_lock. */ int audio_inst; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index ebb05a20aa0c..f9dc9f46a446 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -1525,7 +1525,7 @@ __set_dm_plane_degamma(struct drm_plane_state *plane_state, degamma_lut, degamma_size); if (ret) return ret; - } else { + } else { /* Check if format requires post-scale color processing (subsampled formats) */ is_subsampled_format = (dc_plane_state->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN && dc_plane_state->format < SURFACE_PIXEL_FORMAT_SUBSAMPLE_END); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c index 47d90b67120e..c6bb9fec9217 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c @@ -278,6 +278,10 @@ amdgpu_dm_build_default_pipeline(struct drm_device *dev, struct drm_plane *plane drm_colorop_set_next_property(ops[i-1], ops[i]); list->name = kasprintf(GFP_KERNEL, "Color Pipeline %d", ops[0]->base.id); + if (!list->name) { + ret = -ENOMEM; + goto cleanup; + } return 0; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c index c78e26a145e3..8db7956c01d3 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c @@ -1289,10 +1289,10 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector, link_bandwidth_kbps = dc_link_bandwidth_kbps(aconnector->dc_link, dc_link_get_link_cap(aconnector->dc_link)); - if (aconnector->dc_link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && - aconnector->dc_link->dpia_bw_alloc_config.bw_alloc_enabled) { + if (aconnector->dc_link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) { dsc_options.max_target_bpp_limit_override_x16 = 8 * 16; - dsc_options.force_dsc_when_not_needed = true; + if (aconnector->dc_link->dpia_bw_alloc_config.bw_alloc_enabled) + dsc_options.force_dsc_when_not_needed = true; } /* Set DSC policy according to dsc_clock_en */ @@ -2357,7 +2357,7 @@ amdgpu_dm_create_validate_stream_for_sink(struct drm_connector *connector, * Since we check for it a few times below, cache the result. */ is_hdmi_ep = (signal == SIGNAL_TYPE_HDMI_TYPE_A || - signal == SIGNAL_TYPE_HDMI_FRL || + signal == SIGNAL_TYPE_HDMI_FRL || aconnector->dc_link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER); is_dp_or_hdmi = dc_is_hdmi_signal(signal) || dc_is_dp_signal(signal); @@ -3790,10 +3790,9 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, parse_edid_displayid_vrr(connector, edid); has_vsdb = get_amd_vsdb(amdgpu_dm_connector, &vsdb_info) != 0; + amdgpu_dm_connector->vsdb_info = vsdb_info; if (has_vsdb) { - amdgpu_dm_connector->vsdb_info = vsdb_info; - /* copy refresh rate info as long as VSDB advertises FreeSync */ if (vsdb_info.freesync_supported) { amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c index 5036ac1c4fd5..3e0128a29d77 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c @@ -777,13 +777,15 @@ int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm, if (!cursor_plane) goto fail; - cursor_plane->type = DRM_PLANE_TYPE_CURSOR; - res = amdgpu_dm_plane_init(dm, cursor_plane, 0, NULL); - acrtc = kzalloc_obj(struct amdgpu_crtc); if (!acrtc) goto fail; + cursor_plane->type = DRM_PLANE_TYPE_CURSOR; + res = amdgpu_dm_plane_init(dm, cursor_plane, 0, NULL); + if (res) + goto fail; + res = drm_crtc_init_with_planes( dm->ddev, &acrtc->base, @@ -792,7 +794,7 @@ int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm, &amdgpu_dm_crtc_funcs, NULL); if (res) - goto fail; + goto fail_crtc_init; amdgpu_dm_ism_init(&acrtc->ism, &default_ism_config); @@ -844,6 +846,8 @@ int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm, error_ism_fini: amdgpu_dm_ism_flush(&acrtc->ism); drm_crtc_cleanup(&acrtc->base); +fail_crtc_init: + drm_plane_cleanup(cursor_plane); fail: kfree(acrtc); kfree(cursor_plane); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index 6622a686e5e0..0cef66e20a86 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -2756,6 +2756,7 @@ static int ips_residency_show(struct seq_file *m, void *unused) seq_printf(m, "ISP query failed\n"); } else { unsigned int pct, frac; + pct = info.residency_millipercent / 1000; frac = info.residency_millipercent % 1000; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c index f4b0ced7d391..b0325d686b28 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c @@ -319,6 +319,11 @@ int dm_dmub_hw_init(struct amdgpu_device *adev) return -ENOMEM; } + /* Cursor offload has to be enabled; prime it on every DMUB init, + * including post-suspend and GPU-reset. + */ + dc_dmub_srv_cursor_offload_init(adev->dm.dc); + drm_info(adev_to_drm(adev), "DMUB hardware initialized: version=0x%08X\n", adev->dm.dmcub_fw_version); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index 9774ea33272d..f0fc6d080c20 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -531,7 +531,7 @@ void dm_helpers_dp_mst_update_mst_mgr_for_deallocation( amdgpu_dm_set_mst_status(&aconnector->mst_status, set_flag, true); amdgpu_dm_set_mst_status(&aconnector->mst_status, clr_flag, false); - } +} EXPORT_IF_KUNIT(dm_helpers_dp_mst_update_mst_mgr_for_deallocation); void dm_dtn_log_begin(struct dc_context *ctx, @@ -1244,6 +1244,26 @@ void populate_hdmi_info_from_connector(bool enable_frl, struct drm_hdmi_info *hd } EXPORT_IF_KUNIT(populate_hdmi_info_from_connector); +static void dm_helpers_wait_for_edid_ready(struct dc_link *link, + struct i2c_adapter *ddc) +{ + const unsigned int retry_count = 50; + const unsigned int retry_interval_ms = 20; + unsigned int retry; + + if (!ddc || link->dpcd_caps.dongle_type != + DISPLAY_DONGLE_DP_DVI_DONGLE) + return; + + for (retry = 0; retry < retry_count; retry++) { + if (drm_probe_ddc(ddc)) + return; + + if (retry + 1 < retry_count) + msleep(retry_interval_ms); + } +} + enum dc_edid_status dm_helpers_read_local_edid( struct dc_context *ctx, struct dc_link *link, @@ -1268,6 +1288,8 @@ enum dc_edid_status dm_helpers_read_local_edid( if (link->dc->hwss.prepare_ddc) link->dc->hwss.prepare_ddc(link); + dm_helpers_wait_for_edid_ready(link, ddc); + /* some dongles read edid incorrectly the first time, * do check sum and retry to make sure read correct edid. */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h index 6ba567df5f0a..b9d90b0c62df 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h @@ -71,8 +71,8 @@ void amdgpu_dm_irq_fini(struct amdgpu_device *adev); * @handler_args: arguments which will be passed to ih * * Returns: - * IRQ Handler Index on success. - * NULL on failure. + * IRQ Handler Index on success. + * NULL on failure. * * Cannot be called from an interrupt handler. */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index ee3f3df6bb8d..5697645ef7cc 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -1342,6 +1342,8 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_commit *state, DRM_DEBUG_DRIVER("%s: MST_DSC Try to set up params from %d streams\n", __func__, dc_state->stream_count); for (i = 0; i < dc_state->stream_count; i++) { struct dc_dsc_policy dsc_policy = {0}; + u32 min_target_bpp_x16; + u32 max_target_bpp_x16; stream = dc_state->streams[i]; @@ -1380,7 +1382,15 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_commit *state, dc_link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && dc_link->dpia_bw_alloc_config.bw_alloc_enabled) params[count].clock_force_enable = DSC_CLK_FORCE_ENABLE; + dc_dsc_get_policy_for_timing(params[count].timing, 0, &dsc_policy, dc_link_get_highest_encoding_format(stream->link)); + min_target_bpp_x16 = dsc_policy.min_target_bpp * 16; + max_target_bpp_x16 = dsc_policy.max_target_bpp * 16; + if (dc_link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) { + max_target_bpp_x16 = min_t(u32, max_target_bpp_x16, 8 * 16); + if (dc_link->dpia_bw_alloc_config.bw_alloc_enabled) + max_target_bpp_x16 = min_target_bpp_x16; + } is_frl_endpoint_present = get_conv_frl_bw(aconnector, &frl_conv_bw_in_kbps, &frl_conv_dsc_bw_in_kbps); if (stream->sink->dsc_caps.dsc_dec_caps.is_dsc_supported && is_frl_endpoint_present && @@ -1390,11 +1400,8 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_commit *state, if (!dc_dsc_compute_bandwidth_range( stream->sink->ctx->dc->res_pool->dscs[0], stream->sink->ctx->dc->debug.dsc_min_slice_height_override, - dsc_policy.min_target_bpp * 16, - (dc_link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && - dc_link->dpia_bw_alloc_config.bw_alloc_enabled) ? - dsc_policy.min_target_bpp * 16 : - dsc_policy.max_target_bpp * 16, + min_target_bpp_x16, + max_target_bpp_x16, &stream->sink->dsc_caps.dsc_dec_caps, &stream->timing, dc_link_get_highest_encoding_format(dc_link), diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c index 91398230d408..b224d9596fd2 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c @@ -2132,15 +2132,15 @@ dm_atomic_plane_get_property(struct drm_plane *plane, } else if (property == adev->mode_info.plane_ctm_property) { *val = (dm_plane_state->ctm) ? dm_plane_state->ctm->base.id : 0; - } else if (property == adev->mode_info.plane_shaper_lut_property) { + } else if (property == adev->mode_info.plane_shaper_lut_property) { *val = (dm_plane_state->shaper_lut) ? dm_plane_state->shaper_lut->base.id : 0; } else if (property == adev->mode_info.plane_shaper_tf_property) { *val = dm_plane_state->shaper_tf; - } else if (property == adev->mode_info.plane_lut3d_property) { + } else if (property == adev->mode_info.plane_lut3d_property) { *val = (dm_plane_state->lut3d) ? dm_plane_state->lut3d->base.id : 0; - } else if (property == adev->mode_info.plane_blend_lut_property) { + } else if (property == adev->mode_info.plane_blend_lut_property) { *val = (dm_plane_state->blend_lut) ? dm_plane_state->blend_lut->base.id : 0; } else if (property == adev->mode_info.plane_blend_tf_property) { diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h index 3469a49d5f56..a432aad41b8f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: MIT +/* SPDX-License-Identifier: MIT */ /* * Copyright 2022 Advanced Micro Devices, Inc. * diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c index 23f1db81a154..b376185875ef 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c @@ -1,4 +1,4 @@ -//SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MIT /* * Copyright 2015 Advanced Micro Devices, Inc. * diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h index 7f05f73e5b33..9027933cec3f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_trace.h @@ -1,4 +1,4 @@ -//SPDX-License-Identifier: MIT +/* SPDX-License-Identifier: MIT */ /* * Copyright 2018 Advanced Micro Devices, Inc. * diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c index 172999cc84e5..35331d339780 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c @@ -120,11 +120,10 @@ void dc_fpu_end(const char *function_name, const int line) int depth; depth = this_cpu_dec_return(fpu_recursion_depth); - if (depth == 0) { + if (depth == 0) kernel_fpu_end(); - } else { + else WARN_ON_ONCE(depth < 0); - } TRACE_DCN_FPU(false, function_name, line, depth); preempt_enable(); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_audio_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_audio_test.c index 040a7a9c0335..281dac959dca 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_audio_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_audio_test.c @@ -77,7 +77,7 @@ static void dm_test_audio_init_disabled(struct kunit *test) int saved_audio = amdgpu_dm_audio_get_param(); adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); amdgpu_dm_audio_set_param(0); @@ -107,11 +107,11 @@ static void dm_test_audio_init_enabled_success(struct kunit *test) res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL); audio0 = kunit_kzalloc(test, sizeof(*audio0), GFP_KERNEL); audio1 = kunit_kzalloc(test, sizeof(*audio1), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res_pool); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio0); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio1); + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, res_pool); + KUNIT_ASSERT_NOT_NULL(test, audio0); + KUNIT_ASSERT_NOT_NULL(test, audio1); dev = root_device_register("kunit-dm-audio-init"); KUNIT_ASSERT_FALSE(test, IS_ERR(dev)); @@ -151,7 +151,7 @@ static void dm_test_audio_fini_without_enabled_audio(struct kunit *test) int saved_audio = amdgpu_dm_audio_get_param(); adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); amdgpu_dm_audio_set_param(1); adev->mode_info.audio.enabled = false; @@ -181,9 +181,9 @@ static void dm_test_fill_audio_info_ids_name_flags(struct kunit *test) audio_info = kunit_kzalloc(test, sizeof(*audio_info), GFP_KERNEL); connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); dc_sink = kunit_kzalloc(test, sizeof(*dc_sink), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio_info); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_sink); + KUNIT_ASSERT_NOT_NULL(test, audio_info); + KUNIT_ASSERT_NOT_NULL(test, connector); + KUNIT_ASSERT_NOT_NULL(test, dc_sink); dc_sink->edid_caps.manufacturer_id = 0x1234; dc_sink->edid_caps.product_id = 0xABCD; @@ -214,9 +214,9 @@ static void dm_test_fill_audio_info_cea_lt_3_skips_modes(struct kunit *test) audio_info = kunit_kzalloc(test, sizeof(*audio_info), GFP_KERNEL); connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); dc_sink = kunit_kzalloc(test, sizeof(*dc_sink), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio_info); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_sink); + KUNIT_ASSERT_NOT_NULL(test, audio_info); + KUNIT_ASSERT_NOT_NULL(test, connector); + KUNIT_ASSERT_NOT_NULL(test, dc_sink); connector->display_info.cea_rev = 2; dc_sink->edid_caps.audio_mode_count = 2; @@ -243,9 +243,9 @@ static void dm_test_fill_audio_info_cea_ge_3_copies_modes(struct kunit *test) audio_info = kunit_kzalloc(test, sizeof(*audio_info), GFP_KERNEL); connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); dc_sink = kunit_kzalloc(test, sizeof(*dc_sink), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio_info); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_sink); + KUNIT_ASSERT_NOT_NULL(test, audio_info); + KUNIT_ASSERT_NOT_NULL(test, connector); + KUNIT_ASSERT_NOT_NULL(test, dc_sink); connector->display_info.cea_rev = 3; dc_sink->edid_caps.audio_mode_count = 2; @@ -288,9 +288,9 @@ static void dm_test_fill_audio_info_latency_present(struct kunit *test) audio_info = kunit_kzalloc(test, sizeof(*audio_info), GFP_KERNEL); connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); dc_sink = kunit_kzalloc(test, sizeof(*dc_sink), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio_info); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_sink); + KUNIT_ASSERT_NOT_NULL(test, audio_info); + KUNIT_ASSERT_NOT_NULL(test, connector); + KUNIT_ASSERT_NOT_NULL(test, dc_sink); connector->display_info.cea_rev = 3; connector->latency_present[0] = true; @@ -316,9 +316,9 @@ static void dm_test_fill_audio_info_latency_absent_keeps_zero(struct kunit *test audio_info = kunit_kzalloc(test, sizeof(*audio_info), GFP_KERNEL); connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); dc_sink = kunit_kzalloc(test, sizeof(*dc_sink), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio_info); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_sink); + KUNIT_ASSERT_NOT_NULL(test, audio_info); + KUNIT_ASSERT_NOT_NULL(test, connector); + KUNIT_ASSERT_NOT_NULL(test, dc_sink); connector->display_info.cea_rev = 3; connector->latency_present[0] = false; @@ -347,9 +347,9 @@ static void dm_test_fill_audio_info_cea_ge_3_zero_modes(struct kunit *test) audio_info = kunit_kzalloc(test, sizeof(*audio_info), GFP_KERNEL); connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); dc_sink = kunit_kzalloc(test, sizeof(*dc_sink), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio_info); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_sink); + KUNIT_ASSERT_NOT_NULL(test, audio_info); + KUNIT_ASSERT_NOT_NULL(test, connector); + KUNIT_ASSERT_NOT_NULL(test, dc_sink); connector->display_info.cea_rev = 3; dc_sink->edid_caps.audio_mode_count = 0; @@ -379,9 +379,9 @@ static void dm_test_audio_component_bind_sets_fields(struct kunit *test) adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); kdev = kunit_kzalloc(test, sizeof(*kdev), GFP_KERNEL); acomp = kunit_kzalloc(test, sizeof(*acomp), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, kdev); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acomp); + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, kdev); + KUNIT_ASSERT_NOT_NULL(test, acomp); dev_set_drvdata(kdev, &adev->ddev); @@ -409,9 +409,9 @@ static void dm_test_audio_component_unbind_clears_fields(struct kunit *test) adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); kdev = kunit_kzalloc(test, sizeof(*kdev), GFP_KERNEL); acomp = kunit_kzalloc(test, sizeof(*acomp), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, kdev); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acomp); + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, kdev); + KUNIT_ASSERT_NOT_NULL(test, acomp); dev_set_drvdata(kdev, &adev->ddev); @@ -472,9 +472,9 @@ static void dm_test_eld_notify_invokes_callback(struct kunit *test) adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); acomp = kunit_kzalloc(test, sizeof(*acomp), GFP_KERNEL); audio_ops = kunit_kzalloc(test, sizeof(*audio_ops), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acomp); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio_ops); + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, acomp); + KUNIT_ASSERT_NOT_NULL(test, audio_ops); audio_ops->audio_ptr = ▮ audio_ops->pin_eld_notify = dm_test_pin_eld_notify; @@ -504,7 +504,7 @@ static void dm_test_eld_notify_no_component(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); adev->dm.audio_component = NULL; @@ -528,8 +528,8 @@ static void dm_test_eld_notify_null_audio_ops(struct kunit *test) adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); acomp = kunit_kzalloc(test, sizeof(*acomp), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acomp); + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, acomp); acomp->audio_ops = NULL; adev->dm.audio_component = acomp; @@ -557,9 +557,9 @@ static void dm_test_eld_notify_null_callback(struct kunit *test) adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); acomp = kunit_kzalloc(test, sizeof(*acomp), GFP_KERNEL); audio_ops = kunit_kzalloc(test, sizeof(*audio_ops), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acomp); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio_ops); + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, acomp); + KUNIT_ASSERT_NOT_NULL(test, audio_ops); audio_ops->pin_eld_notify = NULL; acomp->audio_ops = audio_ops; @@ -589,7 +589,7 @@ static void dm_test_audio_init_pins_sets_defaults(struct kunit *test) int i; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); amdgpu_dm_audio_init_pins(adev, 2, inst_array); @@ -619,7 +619,7 @@ static void dm_test_audio_init_pins_zero_count(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); /* Pre-fill a sentinel so we can confirm the loop never ran. */ adev->mode_info.audio.pin[0].channels = 99; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_backlight_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_backlight_test.c index 5221050dec2f..c6d15fb8ad98 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_backlight_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_backlight_test.c @@ -44,9 +44,9 @@ static void setup_test_connector(struct kunit *test, fixture->adev = kunit_kzalloc(test, sizeof(*fixture->adev), GFP_KERNEL); fixture->aconnector = kunit_kzalloc(test, sizeof(*fixture->aconnector), GFP_KERNEL); fixture->link = kunit_kzalloc(test, sizeof(*fixture->link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fixture->adev); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fixture->aconnector); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fixture->link); + KUNIT_ASSERT_NOT_NULL(test, fixture->adev); + KUNIT_ASSERT_NOT_NULL(test, fixture->aconnector); + KUNIT_ASSERT_NOT_NULL(test, fixture->link); fixture->aconnector->bl_idx = bl_idx; fixture->aconnector->dc_link = fixture->link; @@ -111,7 +111,7 @@ static void dm_test_backlight_set_level_connector_off(struct kunit *test) setup_test_dm_ddev(test, dm); aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconnector); + KUNIT_ASSERT_NOT_NULL(test, aconnector); INIT_LIST_HEAD(&aconnector->base.head); aconnector->bl_idx = 1; aconnector->base.encoder = NULL; @@ -169,7 +169,7 @@ static void dm_test_backlight_set_level_aux_programs_power_module(struct kunit * /* Non-matching connector exercises the bl_idx skip (continue). */ other = kunit_kzalloc(test, sizeof(*other), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, other); + KUNIT_ASSERT_NOT_NULL(test, other); INIT_LIST_HEAD(&other->base.head); other->bl_idx = 0; list_add_tail(&other->base.head, &dm->ddev->mode_config.connector_list); @@ -245,16 +245,16 @@ static void dm_test_backlight_set_level_reallows_idle(struct kunit *test) /* dm_kunit_alloc_dm() leaves dc->ctx NULL; the idle path dereferences it. */ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + KUNIT_ASSERT_NOT_NULL(test, ctx); dm->dc->ctx = ctx; logger = kunit_kzalloc(test, sizeof(*logger), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, logger); + KUNIT_ASSERT_NOT_NULL(test, logger); logger->dev = &adev->ddev; dm->dc->ctx->logger = logger; dmub_srv = kunit_kzalloc(test, sizeof(*dmub_srv), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmub_srv); + KUNIT_ASSERT_NOT_NULL(test, dmub_srv); dmub_srv->idle_allowed = true; dm->dc->ctx->dmub_srv = dmub_srv; dm->dc->caps.ips_support = true; @@ -286,7 +286,7 @@ static void dm_test_backlight_update_status_no_stream(struct kunit *test) setup_test_dm_ddev(test, dm); bd = kunit_kzalloc(test, sizeof(*bd), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bd); + KUNIT_ASSERT_NOT_NULL(test, bd); dev_set_drvdata(&bd->dev, dm); bd->props.brightness = 3456; dm->num_of_edps = 2; @@ -305,9 +305,9 @@ static void setup_test_link_service(struct kunit *test, struct dc_link *link) dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv); + KUNIT_ASSERT_NOT_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, ctx); + KUNIT_ASSERT_NOT_NULL(test, link_srv); dc->ctx = ctx; dc->link_srv = link_srv; @@ -440,7 +440,7 @@ static void dm_test_backlight_get_brightness_uses_device_index(struct kunit *tes setup_test_link_service(test, link); link->dc->link_srv->edp_get_backlight_level = dm_test_get_backlight_level_error; bd = kunit_kzalloc(test, sizeof(*bd), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bd); + KUNIT_ASSERT_NOT_NULL(test, bd); dev_set_drvdata(&bd->dev, dm); dm->num_of_edps = 2; dm->backlight_dev[1] = bd; @@ -487,7 +487,7 @@ static void dm_test_register_backlight_device_success(struct kunit *test) setup_test_link_service(test, link); link->dc->link_srv->edp_get_backlight_level = dm_test_get_backlight_level_error; primary = kunit_kzalloc(test, sizeof(*primary), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, primary); + KUNIT_ASSERT_NOT_NULL(test, primary); adev->ddev.primary = primary; adev->dm.backlight_link[0] = link; @@ -531,9 +531,9 @@ static struct drm_connector *setup_panel_power_savings_connector(struct kunit *t connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); device = kunit_kzalloc(test, sizeof(*device), GFP_KERNEL); state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, device); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + KUNIT_ASSERT_NOT_NULL(test, connector); + KUNIT_ASSERT_NOT_NULL(test, device); + KUNIT_ASSERT_NOT_NULL(test, state); connector->dev = &adev->ddev; connector->state = &state->base; @@ -646,9 +646,9 @@ static void dm_test_panel_power_savings_store_rejects_invalid_text(struct kunit connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); drm = kunit_kzalloc(test, sizeof(*drm), GFP_KERNEL); device = kunit_kzalloc(test, sizeof(*device), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, drm); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, device); + KUNIT_ASSERT_NOT_NULL(test, connector); + KUNIT_ASSERT_NOT_NULL(test, drm); + KUNIT_ASSERT_NOT_NULL(test, device); connector->dev = drm; dev_set_drvdata(device, connector); @@ -669,9 +669,9 @@ static void dm_test_panel_power_savings_store_rejects_out_of_range(struct kunit connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); drm = kunit_kzalloc(test, sizeof(*drm), GFP_KERNEL); device = kunit_kzalloc(test, sizeof(*device), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, drm); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, device); + KUNIT_ASSERT_NOT_NULL(test, connector); + KUNIT_ASSERT_NOT_NULL(test, drm); + KUNIT_ASSERT_NOT_NULL(test, device); connector->dev = drm; dev_set_drvdata(device, connector); @@ -1518,7 +1518,7 @@ static void dm_test_update_connector_ext_caps_negative_bl_idx(struct kunit *test struct amdgpu_dm_connector *aconnector; aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconnector); + KUNIT_ASSERT_NOT_NULL(test, aconnector); aconnector->bl_idx = -1; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c index 8c2f7ab5f8d3..c07661ef56c1 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c @@ -71,7 +71,7 @@ static void dm_test_is_lut_linear_with_linear_lut(struct kunit *test) int i; lut = kunit_kcalloc(test, size, sizeof(*lut), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, lut); + KUNIT_ASSERT_NOT_NULL(test, lut); for (i = 0; i < size; i++) { uint16_t val = (uint16_t)(i * MAX_DRM_LUT_VALUE / (size - 1)); @@ -91,7 +91,7 @@ static void dm_test_is_lut_linear_with_nonlinear_lut(struct kunit *test) int i; lut = kunit_kcalloc(test, size, sizeof(*lut), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, lut); + KUNIT_ASSERT_NOT_NULL(test, lut); /* Fill with all-max values: clearly non-linear */ for (i = 0; i < size; i++) { @@ -110,7 +110,7 @@ static void dm_test_is_lut_linear_rgb_mismatch(struct kunit *test) int i; lut = kunit_kcalloc(test, size, sizeof(*lut), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, lut); + KUNIT_ASSERT_NOT_NULL(test, lut); for (i = 0; i < size; i++) { uint16_t val = (uint16_t)(i * MAX_DRM_LUT_VALUE / (size - 1)); @@ -1871,7 +1871,7 @@ dm_test_colorop_setup(struct kunit *test, enum drm_colorop_type type) KUNIT_ASSERT_NOT_NULL(test, f.colorop_state); f.colorop_state->colorop = f.colorop; - colorops = kunit_kcalloc(test, 1, sizeof(*colorops), GFP_KERNEL); + colorops = kunit_kzalloc(test, sizeof(*colorops), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, colorops); colorops[0].ptr = f.colorop; colorops[0].new_state = f.colorop_state; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_colorop_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_colorop_test.c index 90cc5592ef5d..27cd4b8500e8 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_colorop_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_colorop_test.c @@ -232,7 +232,7 @@ static void dm_test_initialize_default_pipeline_caps(struct kunit *test, drm = &adev->ddev; dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, dc); adev->dm.dc = dc; adev->dm.dc->caps.color.dpp.hw_3d_lut = dpp_hw_3d_lut; adev->dm.dc->caps.color.mpc.preblend = mpc_preblend; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c index 5fdf8ce023b9..b6aecb540654 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c @@ -46,7 +46,7 @@ static void dm_test_subconnector_type_none(struct kunit *test) { struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE; KUNIT_EXPECT_EQ(test, (int)get_subconnector_type(link), (int)DRM_MODE_SUBCONNECTOR_Native); @@ -60,7 +60,7 @@ static void dm_test_subconnector_type_vga(struct kunit *test) { struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_VGA_CONVERTER; KUNIT_EXPECT_EQ(test, (int)get_subconnector_type(link), (int)DRM_MODE_SUBCONNECTOR_VGA); @@ -74,7 +74,7 @@ static void dm_test_subconnector_type_dvi_converter(struct kunit *test) { struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_DVI_CONVERTER; KUNIT_EXPECT_EQ(test, (int)get_subconnector_type(link), (int)DRM_MODE_SUBCONNECTOR_DVID); @@ -88,7 +88,7 @@ static void dm_test_subconnector_type_dvi_dongle(struct kunit *test) { struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_DVI_DONGLE; KUNIT_EXPECT_EQ(test, (int)get_subconnector_type(link), (int)DRM_MODE_SUBCONNECTOR_DVID); @@ -102,7 +102,7 @@ static void dm_test_subconnector_type_hdmi_converter(struct kunit *test) { struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_HDMI_CONVERTER; KUNIT_EXPECT_EQ(test, (int)get_subconnector_type(link), (int)DRM_MODE_SUBCONNECTOR_HDMIA); @@ -116,7 +116,7 @@ static void dm_test_subconnector_type_hdmi_dongle(struct kunit *test) { struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_HDMI_DONGLE; KUNIT_EXPECT_EQ(test, (int)get_subconnector_type(link), (int)DRM_MODE_SUBCONNECTOR_HDMIA); @@ -130,7 +130,7 @@ static void dm_test_subconnector_type_mismatched(struct kunit *test) { struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE; KUNIT_EXPECT_EQ(test, (int)get_subconnector_type(link), (int)DRM_MODE_SUBCONNECTOR_Unknown); @@ -144,7 +144,7 @@ static void dm_test_subconnector_type_default_unknown(struct kunit *test) { struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); link->dpcd_caps.dongle_type = (typeof(link->dpcd_caps.dongle_type))0x7f; KUNIT_EXPECT_EQ(test, (int)get_subconnector_type(link), (int)DRM_MODE_SUBCONNECTOR_Unknown); @@ -842,7 +842,7 @@ static void dm_test_color_depth_from_info_bpc8(struct kunit *test) struct drm_connector *connector; connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + KUNIT_ASSERT_NOT_NULL(test, connector); connector->display_info.bpc = 8; KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, false, 0), @@ -858,7 +858,7 @@ static void dm_test_color_depth_from_info_bpc10(struct kunit *test) struct drm_connector *connector; connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + KUNIT_ASSERT_NOT_NULL(test, connector); connector->display_info.bpc = 10; KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, false, 0), @@ -875,7 +875,7 @@ static void dm_test_color_depth_from_info_zero_bpc_defaults_888(struct kunit *te struct drm_connector *connector; connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + KUNIT_ASSERT_NOT_NULL(test, connector); connector->display_info.bpc = 0; KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, false, 0), @@ -891,7 +891,7 @@ static void dm_test_color_depth_from_info_requested_bpc_caps(struct kunit *test) struct drm_connector *connector; connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + KUNIT_ASSERT_NOT_NULL(test, connector); /* Display supports 12bpc but user requests max 10 */ connector->display_info.bpc = 12; @@ -908,7 +908,7 @@ static void dm_test_color_depth_from_info_y420_default(struct kunit *test) struct drm_connector *connector; connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + KUNIT_ASSERT_NOT_NULL(test, connector); /* No Y420 DC modes set → 8bpc */ KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, true, 0), @@ -924,7 +924,7 @@ static void dm_test_color_depth_from_info_y420_10bpc(struct kunit *test) struct drm_connector *connector; connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + KUNIT_ASSERT_NOT_NULL(test, connector); connector->display_info.hdmi.y420_dc_modes = DRM_EDID_YCBCR420_DC_30; KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, true, 0), @@ -940,7 +940,7 @@ static void dm_test_color_depth_from_info_y420_12bpc(struct kunit *test) struct drm_connector *connector; connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + KUNIT_ASSERT_NOT_NULL(test, connector); connector->display_info.hdmi.y420_dc_modes = DRM_EDID_YCBCR420_DC_36; KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, true, 0), @@ -956,7 +956,7 @@ static void dm_test_color_depth_from_info_y420_16bpc(struct kunit *test) struct drm_connector *connector; connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + KUNIT_ASSERT_NOT_NULL(test, connector); connector->display_info.hdmi.y420_dc_modes = DRM_EDID_YCBCR420_DC_48; KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, true, 0), @@ -972,7 +972,7 @@ static void dm_test_color_depth_from_info_requested_odd_bpc(struct kunit *test) struct drm_connector *connector; connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + KUNIT_ASSERT_NOT_NULL(test, connector); connector->display_info.bpc = 12; KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, false, 11), @@ -988,7 +988,7 @@ static void dm_test_color_depth_from_info_unsupported_bpc(struct kunit *test) struct drm_connector *connector; connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + KUNIT_ASSERT_NOT_NULL(test, connector); connector->display_info.bpc = 9; KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, false, 0), @@ -1133,7 +1133,7 @@ static void dm_test_is_duplicate_mode_empty_list(struct kunit *test) struct drm_display_mode mode = {}; aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconnector); + KUNIT_ASSERT_NOT_NULL(test, aconnector); INIT_LIST_HEAD(&aconnector->base.probed_modes); mode.hdisplay = 1920; @@ -1153,7 +1153,7 @@ static void dm_test_is_duplicate_mode_match(struct kunit *test) struct drm_display_mode candidate = {}; aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconnector); + KUNIT_ASSERT_NOT_NULL(test, aconnector); INIT_LIST_HEAD(&aconnector->base.probed_modes); existing.hdisplay = 1920; @@ -1179,7 +1179,7 @@ static void dm_test_is_duplicate_mode_no_match(struct kunit *test) struct drm_display_mode candidate = {}; aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconnector); + KUNIT_ASSERT_NOT_NULL(test, aconnector); INIT_LIST_HEAD(&aconnector->base.probed_modes); existing.hdisplay = 1920; @@ -1206,7 +1206,7 @@ static void dm_test_is_duplicate_mode_same_size_different_clock(struct kunit *te struct drm_display_mode candidate = {}; aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconnector); + KUNIT_ASSERT_NOT_NULL(test, aconnector); INIT_LIST_HEAD(&aconnector->base.probed_modes); existing.hdisplay = 1920; @@ -1232,7 +1232,7 @@ static void dm_test_encoder_crtc_mask_1(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); adev->mode_info.num_crtc = 1; KUNIT_EXPECT_EQ(test, amdgpu_dm_get_encoder_crtc_mask(adev), 0x1); @@ -1247,7 +1247,7 @@ static void dm_test_encoder_crtc_mask_2(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); adev->mode_info.num_crtc = 2; KUNIT_EXPECT_EQ(test, amdgpu_dm_get_encoder_crtc_mask(adev), 0x3); @@ -1262,7 +1262,7 @@ static void dm_test_encoder_crtc_mask_3(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); adev->mode_info.num_crtc = 3; KUNIT_EXPECT_EQ(test, amdgpu_dm_get_encoder_crtc_mask(adev), 0x7); @@ -1277,7 +1277,7 @@ static void dm_test_encoder_crtc_mask_4(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); adev->mode_info.num_crtc = 4; KUNIT_EXPECT_EQ(test, amdgpu_dm_get_encoder_crtc_mask(adev), 0xf); @@ -1292,7 +1292,7 @@ static void dm_test_encoder_crtc_mask_5(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); adev->mode_info.num_crtc = 5; KUNIT_EXPECT_EQ(test, amdgpu_dm_get_encoder_crtc_mask(adev), 0x1f); @@ -1307,7 +1307,7 @@ static void dm_test_encoder_crtc_mask_6(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); adev->mode_info.num_crtc = 6; KUNIT_EXPECT_EQ(test, amdgpu_dm_get_encoder_crtc_mask(adev), 0x3f); @@ -1322,7 +1322,7 @@ static void dm_test_encoder_crtc_mask_default(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); /* Values > 6 use the default case */ adev->mode_info.num_crtc = 8; @@ -1799,7 +1799,7 @@ static void dm_test_atomic_dup_state_copies_fields(struct kunit *test) KUNIT_EXPECT_EQ(test, new_dm_state->vcpi_slots, 4); KUNIT_EXPECT_EQ(test, (int)new_dm_state->pbn, 1234); - kfree(new_dm_state); + connector->funcs->atomic_destroy_state(connector, new_state); } /* Tests for amdgpu_dm_fill_hdr_info_packet() */ @@ -2527,9 +2527,9 @@ static void setup_cacp_fixture(struct kunit *test, fixture->aconnector = kunit_kzalloc(test, sizeof(*fixture->aconnector), GFP_KERNEL); fixture->link = kunit_kzalloc(test, sizeof(*fixture->link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fixture->adev); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fixture->aconnector); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fixture->link); + KUNIT_ASSERT_NOT_NULL(test, fixture->adev); + KUNIT_ASSERT_NOT_NULL(test, fixture->aconnector); + KUNIT_ASSERT_NOT_NULL(test, fixture->link); fixture->aconnector->dc_link = fixture->link; fixture->aconnector->base.dev = &fixture->adev->ddev; @@ -2675,11 +2675,11 @@ static void setup_panel_type_fixture(struct kunit *test, fixture->aconnector = drmm_kzalloc(fixture->drm, sizeof(*fixture->aconnector), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fixture->aconnector); + KUNIT_ASSERT_NOT_NULL(test, fixture->aconnector); fixture->link = kunit_kzalloc(test, sizeof(*fixture->link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fixture->link); + KUNIT_ASSERT_NOT_NULL(test, fixture->link); fixture->sink = kunit_kzalloc(test, sizeof(*fixture->sink), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fixture->sink); + KUNIT_ASSERT_NOT_NULL(test, fixture->sink); fixture->aconnector->dc_link = fixture->link; drmm_connector_init(fixture->drm, &fixture->aconnector->base, @@ -7398,8 +7398,7 @@ static void dm_test_conn_ac_bind_crtc(struct kunit *test, ctx->crtc_state = kunit_kzalloc(test, sizeof(*ctx->crtc_state), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, ctx->crtc_state); - ctx->state->crtcs = kunit_kcalloc(test, 1, sizeof(*ctx->state->crtcs), - GFP_KERNEL); + ctx->state->crtcs = kunit_kzalloc(test, sizeof(*ctx->state->crtcs), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, ctx->state->crtcs); ctx->state->crtcs[0].ptr = ctx->crtc; ctx->state->crtcs[0].new_state = ctx->crtc_state; @@ -7710,6 +7709,8 @@ static void dm_test_update_after_detect_connect_edid(struct kunit *test) KUNIT_EXPECT_PTR_EQ(test, ctx->aconnector->dc_sink, sink); KUNIT_EXPECT_NOT_NULL(test, ctx->aconnector->timing_requested); + drm_edid_free(ctx->aconnector->drm_edid); + ctx->aconnector->drm_edid = NULL; kfree(ctx->aconnector->timing_requested); ctx->aconnector->timing_requested = NULL; } @@ -7744,6 +7745,9 @@ static void dm_test_update_after_detect_replace_no_edid(struct kunit *test) KUNIT_EXPECT_PTR_EQ(test, ctx->aconnector->dc_sink, new_sink); KUNIT_EXPECT_EQ(test, (int)new_sink->sink_signal, (int)SIGNAL_TYPE_HDMI_FRL); + + kfree(ctx->aconnector->timing_requested); + ctx->aconnector->timing_requested = NULL; } /** diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c index 489dd56474b9..c130d809098c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c @@ -114,7 +114,7 @@ static void dm_test_crtc_vrr_active_irq_variable(struct kunit *test) struct amdgpu_crtc *acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + KUNIT_ASSERT_NOT_NULL(test, acrtc); acrtc->dm_irq_params.freesync_config.state = VRR_STATE_ACTIVE_VARIABLE; @@ -130,7 +130,7 @@ static void dm_test_crtc_vrr_active_irq_fixed(struct kunit *test) struct amdgpu_crtc *acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + KUNIT_ASSERT_NOT_NULL(test, acrtc); acrtc->dm_irq_params.freesync_config.state = VRR_STATE_ACTIVE_FIXED; @@ -146,7 +146,7 @@ static void dm_test_crtc_vrr_active_irq_inactive(struct kunit *test) struct amdgpu_crtc *acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + KUNIT_ASSERT_NOT_NULL(test, acrtc); acrtc->dm_irq_params.freesync_config.state = VRR_STATE_INACTIVE; @@ -162,7 +162,7 @@ static void dm_test_crtc_vrr_active_irq_disabled(struct kunit *test) struct amdgpu_crtc *acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + KUNIT_ASSERT_NOT_NULL(test, acrtc); acrtc->dm_irq_params.freesync_config.state = VRR_STATE_DISABLED; @@ -178,7 +178,7 @@ static void dm_test_crtc_vrr_active_irq_unsupported(struct kunit *test) struct amdgpu_crtc *acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + KUNIT_ASSERT_NOT_NULL(test, acrtc); acrtc->dm_irq_params.freesync_config.state = VRR_STATE_UNSUPPORTED; @@ -197,7 +197,7 @@ static void dm_test_crtc_vrr_active_variable(struct kunit *test) sizeof(*dm_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_state); + KUNIT_ASSERT_NOT_NULL(test, dm_state); dm_state->freesync_config.state = VRR_STATE_ACTIVE_VARIABLE; @@ -214,7 +214,7 @@ static void dm_test_crtc_vrr_active_fixed(struct kunit *test) sizeof(*dm_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_state); + KUNIT_ASSERT_NOT_NULL(test, dm_state); dm_state->freesync_config.state = VRR_STATE_ACTIVE_FIXED; @@ -231,7 +231,7 @@ static void dm_test_crtc_vrr_active_inactive(struct kunit *test) sizeof(*dm_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_state); + KUNIT_ASSERT_NOT_NULL(test, dm_state); dm_state->freesync_config.state = VRR_STATE_INACTIVE; @@ -248,7 +248,7 @@ static void dm_test_crtc_vrr_active_disabled(struct kunit *test) sizeof(*dm_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_state); + KUNIT_ASSERT_NOT_NULL(test, dm_state); dm_state->freesync_config.state = VRR_STATE_DISABLED; @@ -265,7 +265,7 @@ static void dm_test_crtc_vrr_active_unsupported(struct kunit *test) sizeof(*dm_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_state); + KUNIT_ASSERT_NOT_NULL(test, dm_state); dm_state->freesync_config.state = VRR_STATE_UNSUPPORTED; @@ -304,7 +304,7 @@ static void dm_test_crtc_is_headless_no_connectors(struct kunit *test) struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); struct drm_device *dev = dm_kunit_alloc_drm_with_connector_list(test); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); adev->dm.ddev = dev; KUNIT_EXPECT_TRUE(test, amdgpu_dm_is_headless(adev)); @@ -320,8 +320,8 @@ static void dm_test_crtc_is_headless_writeback_only(struct kunit *test) struct drm_device *dev = dm_kunit_alloc_drm_with_connector_list(test); struct drm_connector *wb = kunit_kzalloc(test, sizeof(*wb), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, wb); + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, wb); adev->dm.ddev = dev; dm_test_add_connector(dev, wb, DRM_MODE_CONNECTOR_WRITEBACK, @@ -340,8 +340,8 @@ static void dm_test_crtc_is_headless_disconnected_display(struct kunit *test) struct drm_device *dev = dm_kunit_alloc_drm_with_connector_list(test); struct drm_connector *display = kunit_kzalloc(test, sizeof(*display), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, display); + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, display); adev->dm.ddev = dev; dm_test_add_connector(dev, display, DRM_MODE_CONNECTOR_HDMIA, @@ -360,8 +360,8 @@ static void dm_test_crtc_is_headless_connected_display(struct kunit *test) struct drm_device *dev = dm_kunit_alloc_drm_with_connector_list(test); struct drm_connector *display = kunit_kzalloc(test, sizeof(*display), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, display); + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, display); adev->dm.ddev = dev; dm_test_add_connector(dev, display, DRM_MODE_CONNECTOR_HDMIA, @@ -381,9 +381,9 @@ static void dm_test_crtc_is_headless_mixed_connectors(struct kunit *test) struct drm_connector *wb = kunit_kzalloc(test, sizeof(*wb), GFP_KERNEL); struct drm_connector *display = kunit_kzalloc(test, sizeof(*display), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, wb); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, display); + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, wb); + KUNIT_ASSERT_NOT_NULL(test, display); adev->dm.ddev = dev; dm_test_add_connector(dev, wb, DRM_MODE_CONNECTOR_WRITEBACK, @@ -426,7 +426,7 @@ static void dm_test_crtc_set_vupdate_irq_no_otg(struct kunit *test) adev = dm_kunit_alloc_adev(test); acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + KUNIT_ASSERT_NOT_NULL(test, acrtc); acrtc->base.dev = &adev->ddev; acrtc->otg_inst = -1; @@ -451,7 +451,7 @@ static void dm_test_crtc_set_vupdate_irq_dc_busy(struct kunit *test) KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + KUNIT_ASSERT_NOT_NULL(test, acrtc); acrtc->base.dev = &adev->ddev; acrtc->otg_inst = 0; @@ -514,20 +514,19 @@ static void dm_test_crtc_set_vupdate_irq_enable(struct kunit *test) KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + KUNIT_ASSERT_NOT_NULL(test, acrtc); dc = dm_kunit_alloc_dc_with_ctx(test); res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res_pool); + KUNIT_ASSERT_NOT_NULL(test, res_pool); irqs = kunit_kzalloc(test, sizeof(*irqs), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, irqs); + KUNIT_ASSERT_NOT_NULL(test, irqs); /* * Populate the per-source info table so amdgpu_dm_irq_set() succeeds. */ - info = kunit_kzalloc(test, sizeof(*info) * DAL_IRQ_SOURCES_NUMBER, - GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info); + info = kunit_kcalloc(test, DAL_IRQ_SOURCES_NUMBER, sizeof(*info), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, info); for (i = 0; i < DAL_IRQ_SOURCES_NUMBER; i++) info[i].funcs = &dm_test_vupdate_irq_src_funcs; @@ -560,7 +559,7 @@ static void dm_test_idle_create_workqueue(struct kunit *test) struct idle_workqueue *idle_work; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); idle_work = idle_create_workqueue(adev); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, idle_work); @@ -588,7 +587,7 @@ static void dm_test_idle_worker_disabled_clears_running(struct kunit *test) KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); idle_work = kunit_kzalloc(test, sizeof(*idle_work), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, idle_work); + KUNIT_ASSERT_NOT_NULL(test, idle_work); idle_work->dm = &adev->dm; idle_work->enable = false; @@ -623,7 +622,7 @@ static void dm_test_idle_worker_enabled_breaks_when_idle_disallowed(struct kunit adev->dm.dc->idle_optimizations_allowed = false; idle_work = kunit_kzalloc(test, sizeof(*idle_work), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, idle_work); + KUNIT_ASSERT_NOT_NULL(test, idle_work); idle_work->dm = &adev->dm; idle_work->enable = true; @@ -668,12 +667,12 @@ static void dm_test_idle_worker_enabled_breaks_when_not_headless(struct kunit *t /* A connected display makes amdgpu_dm_is_headless() false. */ display = kunit_kzalloc(test, sizeof(*display), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, display); + KUNIT_ASSERT_NOT_NULL(test, display); dm_test_add_connector(adev->dm.ddev, display, DRM_MODE_CONNECTOR_HDMIA, connector_status_connected); idle_work = kunit_kzalloc(test, sizeof(*idle_work), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, idle_work); + KUNIT_ASSERT_NOT_NULL(test, idle_work); idle_work->dm = &adev->dm; idle_work->enable = true; adev->dm.idle_workqueue = idle_work; @@ -727,7 +726,7 @@ static void dm_test_idle_worker_enabled_runs_body(struct kunit *test) adev->dm.dc->caps.is_apu = true; /* dc_allow() logs via DC_LOG_DEBUG() when it flips the flag. */ logger = kunit_kzalloc(test, sizeof(*logger), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, logger); + KUNIT_ASSERT_NOT_NULL(test, logger); logger->dev = &adev->ddev; adev->dm.dc->ctx->logger = logger; /* dc_allow() only flips the flag when clk_mgr and apply() are present. */ @@ -736,7 +735,7 @@ static void dm_test_idle_worker_enabled_runs_body(struct kunit *test) adev->dm.dc->hwss.apply_idle_power_optimizations = dm_test_idle_apply_flip; idle_work = kunit_kzalloc(test, sizeof(*idle_work), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, idle_work); + KUNIT_ASSERT_NOT_NULL(test, idle_work); idle_work->dm = &adev->dm; idle_work->enable = true; adev->dm.idle_workqueue = idle_work; @@ -764,7 +763,7 @@ static void dm_test_crtc_set_static_screen_optimze_no_sr_entry(struct kunit *tes struct dc_stream_state *stream; dm = kunit_kzalloc(test, sizeof(*dm), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm); + KUNIT_ASSERT_NOT_NULL(test, dm); link = dm_kunit_alloc_link(test); stream = dm_kunit_alloc_stream(test, link); @@ -790,7 +789,7 @@ static void dm_test_crtc_set_static_screen_optimze_sr_entry_psr(struct kunit *te struct dc_stream_state *stream; dm = kunit_kzalloc(test, sizeof(*dm), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm); + KUNIT_ASSERT_NOT_NULL(test, dm); link = dm_kunit_alloc_link(test); stream = dm_kunit_alloc_stream(test, link); @@ -816,7 +815,7 @@ static void dm_test_crtc_set_static_screen_optimze_psr_su_skips(struct kunit *te struct dc_stream_state *stream; dm = kunit_kzalloc(test, sizeof(*dm), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm); + KUNIT_ASSERT_NOT_NULL(test, dm); link = dm_kunit_alloc_link(test); stream = dm_kunit_alloc_stream(test, link); @@ -842,7 +841,7 @@ static void dm_test_crtc_enable_vblank_rejects_unconfigured(struct kunit *test) struct amdgpu_crtc *acrtc; acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + KUNIT_ASSERT_NOT_NULL(test, acrtc); acrtc->base.dev = &adev->ddev; acrtc->base.enabled = false; @@ -926,7 +925,7 @@ static void dm_test_crtc_arm_irq_src(struct kunit *test, atomic_t *enabled; enabled = kunit_kzalloc(test, sizeof(*enabled), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, enabled); + KUNIT_ASSERT_NOT_NULL(test, enabled); atomic_set(enabled, count); src->num_types = 1; @@ -970,11 +969,11 @@ dm_test_crtc_setup_enable(struct kunit *test, struct amdgpu_device **adev_out, adev->mode_info.num_crtc = 1; reset_domain = kunit_kzalloc(test, sizeof(*reset_domain), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, reset_domain); + KUNIT_ASSERT_NOT_NULL(test, reset_domain); adev->reset_domain = reset_domain; acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + KUNIT_ASSERT_NOT_NULL(test, acrtc); acrtc->base.dev = &adev->ddev; acrtc->base.funcs = &dm_test_crtc_funcs; acrtc->base.enabled = true; @@ -988,7 +987,7 @@ dm_test_crtc_setup_enable(struct kunit *test, struct amdgpu_device **adev_out, stream = dm_kunit_alloc_stream(test, link); dm_state = kunit_kzalloc(test, sizeof(*dm_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_state); + KUNIT_ASSERT_NOT_NULL(test, dm_state); dm_state->stream = stream; acrtc->base.state = &dm_state->base; @@ -1053,16 +1052,15 @@ static void dm_test_crtc_enable_vblank_vupdate_busy(struct kunit *test) acrtc_state->freesync_config.state = VRR_STATE_ACTIVE_VARIABLE; res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res_pool); + KUNIT_ASSERT_NOT_NULL(test, res_pool); irqs = kunit_kzalloc(test, sizeof(*irqs), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, irqs); + KUNIT_ASSERT_NOT_NULL(test, irqs); /* * Per-source .set fails so amdgpu_dm_irq_set() reports the source busy. */ - info = kunit_kzalloc(test, sizeof(*info) * DAL_IRQ_SOURCES_NUMBER, - GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info); + info = kunit_kcalloc(test, DAL_IRQ_SOURCES_NUMBER, sizeof(*info), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, info); for (i = 0; i < DAL_IRQ_SOURCES_NUMBER; i++) info[i].funcs = &dm_test_vupdate_irq_src_busy_funcs; @@ -1286,7 +1284,7 @@ static struct drm_crtc *dm_test_crtc_setup_vline0(struct kunit *test, KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc); + KUNIT_ASSERT_NOT_NULL(test, crtc); crtc->dev = &adev->ddev; adev->ip_versions[DCE_HWIP][0] = ip_version; @@ -1375,7 +1373,7 @@ static void dm_test_crtc_update_active_planes_no_stream(struct kunit *test) struct dm_crtc_state *dm_state; dm_state = kunit_kzalloc(test, sizeof(*dm_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_state); + KUNIT_ASSERT_NOT_NULL(test, dm_state); dm_state->stream = NULL; dm_state->active_planes = 5; @@ -1413,11 +1411,11 @@ static void dm_test_count_crtc_active_planes_none(struct kunit *test) INIT_LIST_HEAD(&dev->mode_config.plane_list); state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + KUNIT_ASSERT_NOT_NULL(test, state); state->dev = dev; crtc_state = kunit_kzalloc(test, sizeof(*crtc_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); + KUNIT_ASSERT_NOT_NULL(test, crtc_state); crtc_state->state = state; crtc_state->plane_mask = 0; @@ -1452,15 +1450,15 @@ static void dm_test_count_crtc_active_planes_mixed(struct kunit *test) INIT_LIST_HEAD(&dev->mode_config.plane_list); plane_no_state = kunit_kzalloc(test, sizeof(*plane_no_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_no_state); + KUNIT_ASSERT_NOT_NULL(test, plane_no_state); plane_cursor = kunit_kzalloc(test, sizeof(*plane_cursor), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_cursor); + KUNIT_ASSERT_NOT_NULL(test, plane_cursor); plane_with_fb = kunit_kzalloc(test, sizeof(*plane_with_fb), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_with_fb); + KUNIT_ASSERT_NOT_NULL(test, plane_with_fb); plane_no_fb = kunit_kzalloc(test, sizeof(*plane_no_fb), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_no_fb); + KUNIT_ASSERT_NOT_NULL(test, plane_no_fb); plane_excluded = kunit_kzalloc(test, sizeof(*plane_excluded), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_excluded); + KUNIT_ASSERT_NOT_NULL(test, plane_excluded); dm_test_add_plane(dev, plane_no_state, 0, DRM_PLANE_TYPE_PRIMARY); dm_test_add_plane(dev, plane_cursor, 1, DRM_PLANE_TYPE_CURSOR); @@ -1469,19 +1467,19 @@ static void dm_test_count_crtc_active_planes_mixed(struct kunit *test) dm_test_add_plane(dev, plane_excluded, 4, DRM_PLANE_TYPE_PRIMARY); fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fb); + KUNIT_ASSERT_NOT_NULL(test, fb); ps_fb = kunit_kzalloc(test, sizeof(*ps_fb), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ps_fb); + KUNIT_ASSERT_NOT_NULL(test, ps_fb); ps_fb->fb = fb; ps_no_fb = kunit_kzalloc(test, sizeof(*ps_no_fb), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ps_no_fb); + KUNIT_ASSERT_NOT_NULL(test, ps_no_fb); ps_no_fb->fb = NULL; state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + KUNIT_ASSERT_NOT_NULL(test, state); state->dev = dev; - state->planes = kunit_kzalloc(test, sizeof(*state->planes) * 5, GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state->planes); + state->planes = kunit_kcalloc(test, 5, sizeof(*state->planes), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, state->planes); state->planes[0].new_state = NULL; state->planes[1].new_state = ps_fb; state->planes[2].new_state = ps_fb; @@ -1489,7 +1487,7 @@ static void dm_test_count_crtc_active_planes_mixed(struct kunit *test) state->planes[4].new_state = ps_fb; crtc_state = kunit_kzalloc(test, sizeof(*crtc_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); + KUNIT_ASSERT_NOT_NULL(test, crtc_state); crtc_state->state = state; /* Exclude plane index 4 from the CRTC. */ crtc_state->plane_mask = BIT(0) | BIT(1) | BIT(2) | BIT(3); @@ -1514,9 +1512,9 @@ static void dm_test_crtc_duplicate_state_copies_fields(struct kunit *test) struct dm_crtc_state *dm_dup; crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc); + KUNIT_ASSERT_NOT_NULL(test, crtc); cur = kunit_kzalloc(test, sizeof(*cur), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cur); + KUNIT_ASSERT_NOT_NULL(test, cur); cur->abm_level = 3; cur->active_planes = 2; @@ -1560,9 +1558,9 @@ static void dm_test_crtc_duplicate_state_retains_stream(struct kunit *test) struct dc_link *link; crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc); + KUNIT_ASSERT_NOT_NULL(test, crtc); cur = kunit_kzalloc(test, sizeof(*cur), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cur); + KUNIT_ASSERT_NOT_NULL(test, cur); link = dm_kunit_alloc_link(test); stream = dm_kunit_alloc_stream(test, link); @@ -1595,7 +1593,7 @@ static void dm_test_crtc_duplicate_state_null_state_returns_null(struct kunit *t struct drm_crtc *crtc; crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc); + KUNIT_ASSERT_NOT_NULL(test, crtc); crtc->state = NULL; KUNIT_EXPECT_NULL(test, amdgpu_dm_crtc_duplicate_state(crtc)); @@ -1629,7 +1627,7 @@ static void dm_test_crtc_destroy_cleans_up_and_frees(struct kunit *test) /* amdgpu_dm_crtc_destroy() kfree()s the CRTC, so use a plain alloc. */ acrtc = kzalloc_obj(*acrtc, GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + KUNIT_ASSERT_NOT_NULL(test, acrtc); ret = drm_crtc_init_with_planes(&adev->ddev, &acrtc->base, plane, NULL, &dm_test_crtc_funcs, NULL); @@ -1657,7 +1655,7 @@ static void dm_test_crtc_create_state_allocates_state(struct kunit *test) struct drm_crtc *crtc; crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc); + KUNIT_ASSERT_NOT_NULL(test, crtc); crtc->dev = &adev->ddev; crtc->state = NULL; @@ -1686,7 +1684,7 @@ static void dm_test_crtc_reset_state_replaces_existing(struct kunit *test) struct dc_link *link; crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc); + KUNIT_ASSERT_NOT_NULL(test, crtc); crtc->dev = &adev->ddev; link = dm_kunit_alloc_link(test); @@ -1696,7 +1694,7 @@ static void dm_test_crtc_reset_state_replaces_existing(struct kunit *test) /* reset_state kfree()s the old state, so use a plain (unmanaged) alloc. */ old = kzalloc_obj(*old, GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old); + KUNIT_ASSERT_NOT_NULL(test, old); old->stream = stream; crtc->state = &old->base; @@ -1725,7 +1723,7 @@ static void dm_test_crtc_destroy_state_no_stream(struct kunit *test) /* destroy_state kfree()s the state, so use a plain (unmanaged) alloc. */ dm_state = kzalloc_obj(*dm_state); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_state); + KUNIT_ASSERT_NOT_NULL(test, dm_state); amdgpu_dm_crtc_destroy_state(NULL, &dm_state->base); } @@ -1755,7 +1753,7 @@ static void dm_test_crtc_destroy_state_releases_stream(struct kunit *test) /* destroy_state kfree()s the state, so use a plain (unmanaged) alloc. */ dm_state = kzalloc_obj(*dm_state); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_state); + KUNIT_ASSERT_NOT_NULL(test, dm_state); dm_state->stream = stream; amdgpu_dm_crtc_destroy_state(NULL, &dm_state->base); @@ -1783,7 +1781,7 @@ static void dm_test_crtc_handle_vblank_no_event(struct kunit *test) KUNIT_ASSERT_EQ(test, drm_vblank_init(&adev->ddev, 1), 0); acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + KUNIT_ASSERT_NOT_NULL(test, acrtc); acrtc->base.dev = &adev->ddev; acrtc->event = NULL; @@ -1811,9 +1809,9 @@ static void dm_test_crtc_handle_vblank_skips_when_flip_submitted(struct kunit *t KUNIT_ASSERT_EQ(test, drm_vblank_init(&adev->ddev, 1), 0); acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + KUNIT_ASSERT_NOT_NULL(test, acrtc); event = kunit_kzalloc(test, sizeof(*event), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, event); + KUNIT_ASSERT_NOT_NULL(test, event); acrtc->base.dev = &adev->ddev; acrtc->base.funcs = &dm_test_crtc_funcs; @@ -1850,11 +1848,11 @@ static void dm_test_crtc_handle_vblank_completes_cursor_only(struct kunit *test) KUNIT_ASSERT_EQ(test, drm_vblank_init(&adev->ddev, 1), 0); acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + KUNIT_ASSERT_NOT_NULL(test, acrtc); /* drm_crtc_send_vblank_event() consumes (kfree()s) the event. */ event = kzalloc_obj(*event); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, event); + KUNIT_ASSERT_NOT_NULL(test, event); acrtc->base.dev = &adev->ddev; acrtc->base.funcs = &dm_test_crtc_funcs; @@ -1907,7 +1905,7 @@ dm_test_vblank_control_worker_setup(struct kunit *test, bool enable, adev->dm.active_vblank_irq_count = count; acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + KUNIT_ASSERT_NOT_NULL(test, acrtc); acrtc->base.dev = &adev->ddev; acrtc->base.state = NULL; @@ -1918,7 +1916,7 @@ dm_test_vblank_control_worker_setup(struct kunit *test, bool enable, /* Worker kfree()s the work item, so it must be a plain allocation. */ work = kzalloc_obj(*work); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, work); + KUNIT_ASSERT_NOT_NULL(test, work); work->dm = &adev->dm; work->acrtc = acrtc; work->stream = stream; @@ -2012,7 +2010,7 @@ static void dm_test_crtc_disable_vblank_no_irq_installed(struct kunit *test) adev->irq.installed = false; acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + KUNIT_ASSERT_NOT_NULL(test, acrtc); acrtc->base.dev = &adev->ddev; acrtc->crtc_id = 0; @@ -2047,7 +2045,7 @@ static void dm_test_crtc_disable_vblank_vrr(struct kunit *test) adev->irq.installed = true; reset_domain = kunit_kzalloc(test, sizeof(*reset_domain), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, reset_domain); + KUNIT_ASSERT_NOT_NULL(test, reset_domain); adev->reset_domain = reset_domain; /* Seed with 2 so amdgpu_irq_put() drops to a non-zero refcount. */ @@ -2055,7 +2053,7 @@ static void dm_test_crtc_disable_vblank_vrr(struct kunit *test) dm_test_crtc_arm_irq_src(test, &adev->pageflip_irq, 2); acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + KUNIT_ASSERT_NOT_NULL(test, acrtc); acrtc->base.dev = &adev->ddev; acrtc->crtc_id = 0; /* OTG unassigned -> amdgpu_dm_crtc_set_vupdate_irq() returns 0 early. */ @@ -2098,7 +2096,7 @@ static void dm_test_crtc_disable_vblank_queues_work(struct kunit *test) adev->irq.installed = true; reset_domain = kunit_kzalloc(test, sizeof(*reset_domain), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, reset_domain); + KUNIT_ASSERT_NOT_NULL(test, reset_domain); adev->reset_domain = reset_domain; /* Seed with 2 so amdgpu_irq_put() drops to a non-zero refcount. */ @@ -2106,7 +2104,7 @@ static void dm_test_crtc_disable_vblank_queues_work(struct kunit *test) dm_test_crtc_arm_irq_src(test, &adev->pageflip_irq, 2); acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + KUNIT_ASSERT_NOT_NULL(test, acrtc); acrtc->base.dev = &adev->ddev; acrtc->crtc_id = 0; acrtc->otg_inst = -1; @@ -2118,7 +2116,7 @@ static void dm_test_crtc_disable_vblank_queues_work(struct kunit *test) /* CRTC state with no stream -> the stream-retain branch is skipped. */ dm_state = kunit_kzalloc(test, sizeof(*dm_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_state); + KUNIT_ASSERT_NOT_NULL(test, dm_state); acrtc->base.state = &dm_state->base; /* Real workqueue so the queue_work() branch runs the control worker. */ @@ -2152,7 +2150,7 @@ static void dm_test_crtc_late_register_inits_debugfs(struct kunit *test) int ret; crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc); + KUNIT_ASSERT_NOT_NULL(test, crtc); crtc->debugfs_entry = debugfs_create_dir("dm_test_crtc", NULL); @@ -2304,18 +2302,18 @@ static void dm_test_crtc_atomic_check_no_stream_passes(struct kunit *test) KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc); + KUNIT_ASSERT_NOT_NULL(test, crtc); crtc->dev = &adev->ddev; dm_crtc_state = kunit_kzalloc(test, sizeof(*dm_crtc_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_crtc_state); + KUNIT_ASSERT_NOT_NULL(test, dm_crtc_state); dm_crtc_state->base.crtc = crtc; state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + KUNIT_ASSERT_NOT_NULL(test, state); state->dev = &adev->ddev; state->crtcs = kunit_kzalloc(test, sizeof(*state->crtcs), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state->crtcs); + KUNIT_ASSERT_NOT_NULL(test, state->crtcs); state->crtcs[0].new_state = &dm_crtc_state->base; dm_crtc_state->base.state = state; @@ -2364,24 +2362,24 @@ static void dm_test_crtc_atomic_check_enable_without_primary_fails(struct kunit KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); primary = kunit_kzalloc(test, sizeof(*primary), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, primary); + KUNIT_ASSERT_NOT_NULL(test, primary); crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc); + KUNIT_ASSERT_NOT_NULL(test, crtc); crtc->dev = &adev->ddev; crtc->primary = primary; dm_crtc_state = kunit_kzalloc(test, sizeof(*dm_crtc_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_crtc_state); + KUNIT_ASSERT_NOT_NULL(test, dm_crtc_state); dm_crtc_state->base.crtc = crtc; dm_crtc_state->base.enable = true; dm_crtc_state->base.plane_mask = 0; state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + KUNIT_ASSERT_NOT_NULL(test, state); state->dev = &adev->ddev; state->crtcs = kunit_kzalloc(test, sizeof(*state->crtcs), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state->crtcs); + KUNIT_ASSERT_NOT_NULL(test, state->crtcs); state->crtcs[0].new_state = &dm_crtc_state->base; dm_crtc_state->base.state = state; @@ -2409,20 +2407,20 @@ static void dm_test_crtc_atomic_check_async_flip_non_fast_fails(struct kunit *te KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc); + KUNIT_ASSERT_NOT_NULL(test, crtc); crtc->dev = &adev->ddev; dm_crtc_state = kunit_kzalloc(test, sizeof(*dm_crtc_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_crtc_state); + KUNIT_ASSERT_NOT_NULL(test, dm_crtc_state); dm_crtc_state->base.crtc = crtc; dm_crtc_state->base.async_flip = true; dm_crtc_state->update_type = UPDATE_TYPE_FULL; state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + KUNIT_ASSERT_NOT_NULL(test, state); state->dev = &adev->ddev; state->crtcs = kunit_kzalloc(test, sizeof(*state->crtcs), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state->crtcs); + KUNIT_ASSERT_NOT_NULL(test, state->crtcs); state->crtcs[0].new_state = &dm_crtc_state->base; dm_crtc_state->base.state = state; @@ -2453,33 +2451,33 @@ static void dm_test_crtc_atomic_check_vrr_pulls_primary(struct kunit *test) KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); primary = kunit_kzalloc(test, sizeof(*primary), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, primary); + KUNIT_ASSERT_NOT_NULL(test, primary); crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc); + KUNIT_ASSERT_NOT_NULL(test, crtc); crtc->dev = &adev->ddev; crtc->primary = primary; dm_crtc_state = kunit_kzalloc(test, sizeof(*dm_crtc_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_crtc_state); + KUNIT_ASSERT_NOT_NULL(test, dm_crtc_state); dm_crtc_state->base.crtc = crtc; dm_crtc_state->freesync_config.state = VRR_STATE_ACTIVE_VARIABLE; state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + KUNIT_ASSERT_NOT_NULL(test, state); state->dev = &adev->ddev; state->crtcs = kunit_kzalloc(test, sizeof(*state->crtcs), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state->crtcs); + KUNIT_ASSERT_NOT_NULL(test, state->crtcs); state->crtcs[0].new_state = &dm_crtc_state->base; dm_crtc_state->base.state = state; /* acquire ctx must be set; existing plane state avoids taking a lock. */ state->acquire_ctx = kunit_kzalloc(test, sizeof(*state->acquire_ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state->acquire_ctx); + KUNIT_ASSERT_NOT_NULL(test, state->acquire_ctx); state->planes = kunit_kzalloc(test, sizeof(*state->planes), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state->planes); + KUNIT_ASSERT_NOT_NULL(test, state->planes); primary_plane_state = kunit_kzalloc(test, sizeof(*primary_plane_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, primary_plane_state); + KUNIT_ASSERT_NOT_NULL(test, primary_plane_state); state->planes[0].new_state = primary_plane_state; ret = amdgpu_dm_crtc_helper_atomic_check(crtc, state); @@ -2514,18 +2512,18 @@ static void dm_test_crtc_atomic_check_valid_stream_passes(struct kunit *test) dc = dm_kunit_alloc_dc_with_ctx(test); res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res_pool); + KUNIT_ASSERT_NOT_NULL(test, res_pool); tg = kunit_kzalloc(test, sizeof(*tg), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, tg); + KUNIT_ASSERT_NOT_NULL(test, tg); tg_funcs = kunit_kzalloc(test, sizeof(*tg_funcs), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, tg_funcs); + KUNIT_ASSERT_NOT_NULL(test, tg_funcs); tg_funcs->validate_timing = dm_test_atomic_check_validate_timing_ok; tg->funcs = tg_funcs; res_pool->timing_generators[0] = tg; dc->res_pool = res_pool; link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv); + KUNIT_ASSERT_NOT_NULL(test, link_srv); link_srv->validate_mode_timing = dm_test_atomic_check_validate_mode_timing_ok; dc->link_srv = link_srv; adev->dm.dc = dc; @@ -2535,19 +2533,19 @@ static void dm_test_crtc_atomic_check_valid_stream_passes(struct kunit *test) stream = dm_kunit_alloc_stream(test, link); crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc); + KUNIT_ASSERT_NOT_NULL(test, crtc); crtc->dev = &adev->ddev; dm_crtc_state = kunit_kzalloc(test, sizeof(*dm_crtc_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_crtc_state); + KUNIT_ASSERT_NOT_NULL(test, dm_crtc_state); dm_crtc_state->base.crtc = crtc; dm_crtc_state->stream = stream; state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + KUNIT_ASSERT_NOT_NULL(test, state); state->dev = &adev->ddev; state->crtcs = kunit_kzalloc(test, sizeof(*state->crtcs), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state->crtcs); + KUNIT_ASSERT_NOT_NULL(test, state->crtcs); state->crtcs[0].new_state = &dm_crtc_state->base; dm_crtc_state->base.state = state; @@ -2582,11 +2580,11 @@ static void dm_test_crtc_atomic_check_invalid_stream_fails(struct kunit *test) dc = dm_kunit_alloc_dc_with_ctx(test); res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res_pool); + KUNIT_ASSERT_NOT_NULL(test, res_pool); tg = kunit_kzalloc(test, sizeof(*tg), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, tg); + KUNIT_ASSERT_NOT_NULL(test, tg); tg_funcs = kunit_kzalloc(test, sizeof(*tg_funcs), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, tg_funcs); + KUNIT_ASSERT_NOT_NULL(test, tg_funcs); tg_funcs->validate_timing = dm_test_atomic_check_validate_timing_fail; tg->funcs = tg_funcs; res_pool->timing_generators[0] = tg; @@ -2597,19 +2595,19 @@ static void dm_test_crtc_atomic_check_invalid_stream_fails(struct kunit *test) stream = dm_kunit_alloc_stream(test, link); crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc); + KUNIT_ASSERT_NOT_NULL(test, crtc); crtc->dev = &adev->ddev; dm_crtc_state = kunit_kzalloc(test, sizeof(*dm_crtc_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_crtc_state); + KUNIT_ASSERT_NOT_NULL(test, dm_crtc_state); dm_crtc_state->base.crtc = crtc; dm_crtc_state->stream = stream; state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + KUNIT_ASSERT_NOT_NULL(test, state); state->dev = &adev->ddev; state->crtcs = kunit_kzalloc(test, sizeof(*state->crtcs), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state->crtcs); + KUNIT_ASSERT_NOT_NULL(test, state->crtcs); state->crtcs[0].new_state = &dm_crtc_state->base; dm_crtc_state->base.state = state; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c index 1e499acbcb90..2e273dea17ef 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c @@ -90,7 +90,7 @@ static struct dmub_srv *dm_test_alloc_dmub_srv(struct kunit *test) struct dmub_srv *dmub_srv; dmub_srv = kunit_kzalloc(test, sizeof(*dmub_srv), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmub_srv); + KUNIT_ASSERT_NOT_NULL(test, dmub_srv); dmub_srv->sw_init = true; dmub_srv->hw_init = true; @@ -110,10 +110,10 @@ static const struct firmware *dm_test_alloc_dmub_fw(struct kunit *test) u8 *data; fw = kunit_kzalloc(test, sizeof(*fw), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fw); + KUNIT_ASSERT_NOT_NULL(test, fw); data = kunit_kzalloc(test, DM_TEST_FW_SIZE, GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, data); + KUNIT_ASSERT_NOT_NULL(test, data); hdr = (struct dmcub_firmware_header_v1_0 *)data; hdr->header.ucode_array_offset_bytes = cpu_to_le32(0); @@ -136,7 +136,7 @@ static void dm_test_register_dmub_notify_callback_null_callback(struct kunit *te struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); KUNIT_EXPECT_FALSE(test, dm_register_dmub_notify_callback(adev, DMUB_NOTIFICATION_AUX_REPLY, NULL, false)); @@ -151,7 +151,7 @@ static void dm_test_register_dmub_notify_callback_type_out_of_range(struct kunit struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); KUNIT_EXPECT_FALSE(test, dm_register_dmub_notify_callback(adev, AMDGPU_DMUB_NOTIFICATION_MAX, dummy_callback, false)); @@ -166,7 +166,7 @@ static void dm_test_register_dmub_notify_callback_valid(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); KUNIT_EXPECT_TRUE(test, dm_register_dmub_notify_callback(adev, DMUB_NOTIFICATION_AUX_REPLY, dummy_callback, true)); @@ -186,7 +186,7 @@ static void dm_test_register_dmub_notify_callback_offload_false(struct kunit *te struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); KUNIT_EXPECT_TRUE(test, dm_register_dmub_notify_callback(adev, DMUB_NOTIFICATION_HPD, dummy_callback, false)); @@ -210,10 +210,10 @@ static void dm_test_dmub_aux_setconfig_callback_copies_and_completes(struct kuni struct dmub_notification notify = {}; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); dm_notify = kunit_kzalloc(test, sizeof(*dm_notify), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_notify); + KUNIT_ASSERT_NOT_NULL(test, dm_notify); init_completion(&adev->dm.dmub_aux_transfer_done); adev->dm.dmub_notify = dm_notify; @@ -249,10 +249,10 @@ static void dm_test_dmub_aux_setconfig_callback_non_aux_no_complete(struct kunit struct dmub_notification notify = {}; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); dm_notify = kunit_kzalloc(test, sizeof(*dm_notify), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_notify); + KUNIT_ASSERT_NOT_NULL(test, dm_notify); init_completion(&adev->dm.dmub_aux_transfer_done); adev->dm.dmub_notify = dm_notify; @@ -276,7 +276,7 @@ static void dm_test_dmub_aux_setconfig_callback_aux_with_null_dm_notify(struct k struct dmub_notification notify = {}; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); init_completion(&adev->dm.dmub_aux_transfer_done); adev->dm.dmub_notify = NULL; @@ -299,10 +299,10 @@ static void dm_test_dmub_aux_setconfig_callback_set_config_reply(struct kunit *t struct dmub_notification notify = {}; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); dm_notify = kunit_kzalloc(test, sizeof(*dm_notify), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_notify); + KUNIT_ASSERT_NOT_NULL(test, dm_notify); init_completion(&adev->dm.dmub_aux_transfer_done); adev->dm.dmub_notify = dm_notify; @@ -337,7 +337,7 @@ static void dm_test_dmub_aux_fused_io_callback_copies_reply_and_completes(struct uint8_t ddc_line = 2; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); init_completion(&adev->dm.fused_io[ddc_line].replied); @@ -380,7 +380,7 @@ static void dm_test_dmub_aux_fused_io_callback_max_ddc_line(struct kunit *test) uint8_t ddc_line; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); ddc_line = ARRAY_SIZE(adev->dm.fused_io) - 1; init_completion(&adev->dm.fused_io[ddc_line].replied); @@ -430,7 +430,7 @@ static void dm_test_get_default_ips_mode_dcn35(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 5, 0); @@ -447,7 +447,7 @@ static void dm_test_get_default_ips_mode_dcn351(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 5, 1); @@ -464,7 +464,7 @@ static void dm_test_get_default_ips_mode_dcn36(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 6, 0); @@ -481,7 +481,7 @@ static void dm_test_get_default_ips_mode_older_than_dcn35(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 2, 0); @@ -498,7 +498,7 @@ static void dm_test_get_default_ips_mode_newer_default(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); /* DCN 4.0.1 is >= 3.5 but has no explicit case, returns ENABLE */ adev->ip_versions[DCE_HWIP][0] = IP_VERSION(4, 0, 1); @@ -522,16 +522,16 @@ static struct amdgpu_device *dm_test_alloc_adev_with_dc(struct kunit *test) struct resource_pool *res_pool; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, dc); res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res_pool); + KUNIT_ASSERT_NOT_NULL(test, res_pool); ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + KUNIT_ASSERT_NOT_NULL(test, ctx); dc->res_pool = res_pool; dc->ctx = ctx; @@ -551,20 +551,20 @@ static struct amdgpu_device *dm_test_alloc_adev_with_dmub(struct kunit *test) adev = dm_test_alloc_adev_with_dc(test); fb_info = kunit_kzalloc(test, sizeof(*fb_info), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fb_info); + KUNIT_ASSERT_NOT_NULL(test, fb_info); fb_info->num_fb = DMUB_WINDOW_TOTAL; for (i = 0; i < DMUB_WINDOW_TOTAL; i++) { fb_info->fb[i].size = PAGE_SIZE; fb_info->fb[i].cpu_addr = kunit_kzalloc(test, PAGE_SIZE, GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fb_info->fb[i].cpu_addr); + KUNIT_ASSERT_NOT_NULL(test, fb_info->fb[i].cpu_addr); } adev->dm.dmub_srv = dm_test_alloc_dmub_srv(test); adev->dm.dmub_fb_info = fb_info; adev->dm.dmub_fw = dm_test_alloc_dmub_fw(test); adev->bios = kunit_kzalloc(test, 4, GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev->bios); + KUNIT_ASSERT_NOT_NULL(test, adev->bios); adev->bios_size = 4; adev->dm.fw_inst_size = 0; @@ -600,7 +600,7 @@ static void dm_test_dmub_hw_init_no_fb_info(struct kunit *test) struct dmub_srv *dmub_srv; dmub_srv = kunit_kzalloc(test, sizeof(*dmub_srv), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmub_srv); + KUNIT_ASSERT_NOT_NULL(test, dmub_srv); adev->dm.dmub_srv = dmub_srv; adev->dm.dmub_fb_info = NULL; @@ -622,10 +622,10 @@ static void dm_test_dmub_hw_init_no_firmware(struct kunit *test) struct dmub_srv_fb_info *fb_info; dmub_srv = kunit_kzalloc(test, sizeof(*dmub_srv), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmub_srv); + KUNIT_ASSERT_NOT_NULL(test, dmub_srv); fb_info = kunit_kzalloc(test, sizeof(*fb_info), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fb_info); + KUNIT_ASSERT_NOT_NULL(test, fb_info); adev->dm.dmub_srv = dmub_srv; adev->dm.dmub_fb_info = fb_info; @@ -791,10 +791,10 @@ static void dm_test_dmub_hw_init_dmcu_abm(struct kunit *test) struct abm *abm; dmcu = kunit_kzalloc(test, sizeof(*dmcu), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmcu); + KUNIT_ASSERT_NOT_NULL(test, dmcu); abm = kunit_kzalloc(test, sizeof(*abm), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, abm); + KUNIT_ASSERT_NOT_NULL(test, abm); dmcu->funcs = &dm_test_dmcu_funcs; dmcu->psp_version = 0x12345678; @@ -911,7 +911,7 @@ static void dm_test_dmub_sw_init_unsupported_asic(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); adev->ip_versions[DCE_HWIP][0] = IP_VERSION(1, 0, 0); @@ -932,7 +932,7 @@ static void dm_test_init_microcode_unsupported_asic(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); adev->ip_versions[DCE_HWIP][0] = IP_VERSION(1, 0, 0); @@ -954,7 +954,7 @@ static void dm_test_dmub_get_vbios_bounding_box_default_null(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 5, 0); @@ -977,13 +977,13 @@ static void dm_test_execute_dmub_cmd_null_dmub_srv(struct kunit *test) union dmub_rb_cmd *cmd; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + KUNIT_ASSERT_NOT_NULL(test, ctx); cmd = kunit_kzalloc(test, sizeof(*cmd), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cmd); + KUNIT_ASSERT_NOT_NULL(test, cmd); spin_lock_init(&adev->dm.dmub_lock); ctx->driver_context = adev; @@ -1014,19 +1014,19 @@ static void dm_test_process_dmub_aux_transfer_sync_engine_acquire(struct kunit * int ret; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + KUNIT_ASSERT_NOT_NULL(test, ctx); dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, dc); payload = kunit_kzalloc(test, sizeof(*payload), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload); + KUNIT_ASSERT_NOT_NULL(test, payload); notify = kunit_kzalloc(test, sizeof(*notify), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, notify); + KUNIT_ASSERT_NOT_NULL(test, notify); dc->link_count = 0; ctx->dc = dc; @@ -1063,28 +1063,28 @@ static void dm_test_process_dmub_aux_transfer_sync_protocol_error(struct kunit * int ret; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + KUNIT_ASSERT_NOT_NULL(test, ctx); dc_ctx = kunit_kzalloc(test, sizeof(*dc_ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_ctx); + KUNIT_ASSERT_NOT_NULL(test, dc_ctx); dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, dc); link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); ddc = kunit_kzalloc(test, sizeof(*ddc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ddc); + KUNIT_ASSERT_NOT_NULL(test, ddc); payload = kunit_kzalloc(test, sizeof(*payload), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload); + KUNIT_ASSERT_NOT_NULL(test, payload); notify = kunit_kzalloc(test, sizeof(*notify), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, notify); + KUNIT_ASSERT_NOT_NULL(test, notify); link->ddc = ddc; dc->ctx = dc_ctx; @@ -1131,28 +1131,28 @@ static void dm_test_process_dmub_aux_transfer_sync_copies_data(struct kunit *tes int ret; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + KUNIT_ASSERT_NOT_NULL(test, ctx); dc_ctx = kunit_kzalloc(test, sizeof(*dc_ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_ctx); + KUNIT_ASSERT_NOT_NULL(test, dc_ctx); dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, dc); link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); ddc = kunit_kzalloc(test, sizeof(*ddc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ddc); + KUNIT_ASSERT_NOT_NULL(test, ddc); payload = kunit_kzalloc(test, sizeof(*payload), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload); + KUNIT_ASSERT_NOT_NULL(test, payload); notify = kunit_kzalloc(test, sizeof(*notify), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, notify); + KUNIT_ASSERT_NOT_NULL(test, notify); link->ddc = ddc; dc->ctx = dc_ctx; @@ -1212,28 +1212,28 @@ static void dm_test_process_dmub_aux_transfer_sync_zero_length(struct kunit *tes int ret; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + KUNIT_ASSERT_NOT_NULL(test, ctx); dc_ctx = kunit_kzalloc(test, sizeof(*dc_ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_ctx); + KUNIT_ASSERT_NOT_NULL(test, dc_ctx); dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, dc); link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); ddc = kunit_kzalloc(test, sizeof(*ddc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ddc); + KUNIT_ASSERT_NOT_NULL(test, ddc); payload = kunit_kzalloc(test, sizeof(*payload), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload); + KUNIT_ASSERT_NOT_NULL(test, payload); notify = kunit_kzalloc(test, sizeof(*notify), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, notify); + KUNIT_ASSERT_NOT_NULL(test, notify); link->ddc = ddc; dc->ctx = dc_ctx; @@ -1286,25 +1286,25 @@ static void dm_test_process_dmub_set_config_sync_unknown_error(struct kunit *tes int ret; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + KUNIT_ASSERT_NOT_NULL(test, ctx); dc_ctx = kunit_kzalloc(test, sizeof(*dc_ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_ctx); + KUNIT_ASSERT_NOT_NULL(test, dc_ctx); dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, dc); link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); payload = kunit_kzalloc(test, sizeof(*payload), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload); + KUNIT_ASSERT_NOT_NULL(test, payload); notify = kunit_kzalloc(test, sizeof(*notify), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, notify); + KUNIT_ASSERT_NOT_NULL(test, notify); dc->ctx = dc_ctx; dc_ctx->dmub_srv = NULL; @@ -1338,13 +1338,13 @@ static void dm_test_abort_fused_io_no_dmub_srv(struct kunit *test) struct dmub_cmd_fused_request *req; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + KUNIT_ASSERT_NOT_NULL(test, ctx); req = kunit_kzalloc(test, sizeof(*req), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, req); + KUNIT_ASSERT_NOT_NULL(test, req); spin_lock_init(&adev->dm.dmub_lock); ctx->driver_context = adev; @@ -1484,7 +1484,7 @@ static int dm_test_dmub_hw_access_init(struct kunit *test) void *cpu_ptr; cpu_ptr = kunit_kzalloc(test, PAGE_SIZE, GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cpu_ptr); + KUNIT_ASSERT_NOT_NULL(test, cpu_ptr); dm_test_bo = (struct dm_test_bo_ctx) { .cpu_ptr = cpu_ptr }; dm_test_cgs = (struct dm_test_cgs_ctx) { .dev.ops = &dm_test_cgs_ops }; @@ -1509,7 +1509,7 @@ static struct amdgpu_device *dm_test_alloc_adev_with_cgs(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); adev->dm.cgs_device = &dm_test_cgs.dev; INIT_LIST_HEAD(&adev->dm.da_list); @@ -1532,7 +1532,7 @@ static void dm_test_dmub_reg_write_then_read(struct kunit *test) struct dc_perf_trace *perf_trace; perf_trace = kunit_kzalloc(test, sizeof(*perf_trace), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, perf_trace); + KUNIT_ASSERT_NOT_NULL(test, perf_trace); adev->dm.dc->ctx->cgs_device = &dm_test_cgs.dev; adev->dm.dc->ctx->perf_trace = perf_trace; @@ -1690,7 +1690,7 @@ static void dm_test_init_microcode_fw_names(struct kunit *test) unsigned int i; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); for (i = 0; i < ARRAY_SIZE(dm_test_ucode_cases); i++) { const struct dm_test_ucode_case *c = &dm_test_ucode_cases[i]; @@ -1719,7 +1719,7 @@ static void dm_test_init_microcode_request_fails(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 5, 0); dm_test_ucode_ret = -ENOENT; @@ -1735,7 +1735,7 @@ static struct amdgpu_device *dm_test_alloc_adev_for_sw_init(struct kunit *test) adev->dm.dmub_fw = dm_test_alloc_dmub_fw(test); adev->bios = kunit_kzalloc(test, 4, GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev->bios); + KUNIT_ASSERT_NOT_NULL(test, adev->bios); adev->bios_size = 4; return adev; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_freesync_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_freesync_test.c index 616a2b385140..710cdc7f40bf 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_freesync_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_freesync_test.c @@ -166,11 +166,11 @@ static void dm_test_dc_timing_adjust_pending(struct kunit *test) struct dc_stream_state *stream; old_state = kunit_kzalloc(test, sizeof(*old_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_state); + KUNIT_ASSERT_NOT_NULL(test, old_state); new_state = kunit_kzalloc(test, sizeof(*new_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_state); + KUNIT_ASSERT_NOT_NULL(test, new_state); stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); + KUNIT_ASSERT_NOT_NULL(test, stream); new_state->stream = stream; stream->timing_adjust_pending = 1; @@ -188,11 +188,11 @@ static void dm_test_dc_timing_adjust_active_fixed(struct kunit *test) struct dc_stream_state *stream; old_state = kunit_kzalloc(test, sizeof(*old_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_state); + KUNIT_ASSERT_NOT_NULL(test, old_state); new_state = kunit_kzalloc(test, sizeof(*new_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_state); + KUNIT_ASSERT_NOT_NULL(test, new_state); stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); + KUNIT_ASSERT_NOT_NULL(test, stream); new_state->stream = stream; new_state->freesync_config.state = VRR_STATE_ACTIVE_FIXED; @@ -210,11 +210,11 @@ static void dm_test_dc_timing_adjust_vrr_toggle(struct kunit *test) struct dc_stream_state *stream; old_state = kunit_kzalloc(test, sizeof(*old_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_state); + KUNIT_ASSERT_NOT_NULL(test, old_state); new_state = kunit_kzalloc(test, sizeof(*new_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_state); + KUNIT_ASSERT_NOT_NULL(test, new_state); stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); + KUNIT_ASSERT_NOT_NULL(test, stream); new_state->stream = stream; old_state->freesync_config.state = VRR_STATE_ACTIVE_VARIABLE; @@ -233,11 +233,11 @@ static void dm_test_dc_timing_adjust_not_needed(struct kunit *test) struct dc_stream_state *stream; old_state = kunit_kzalloc(test, sizeof(*old_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_state); + KUNIT_ASSERT_NOT_NULL(test, old_state); new_state = kunit_kzalloc(test, sizeof(*new_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_state); + KUNIT_ASSERT_NOT_NULL(test, new_state); stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); + KUNIT_ASSERT_NOT_NULL(test, stream); new_state->stream = stream; old_state->freesync_config.state = VRR_STATE_INACTIVE; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c index cfdcc44581b1..5af6ae47bb21 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c @@ -1352,9 +1352,9 @@ static void dm_test_hdcp_destroy_frees_and_removes_sysfs(struct kunit *test) INIT_DELAYED_WORK(&work->watchdog_timer_dwork, dummy_work_fn); INIT_DELAYED_WORK(&work->property_validate_dwork, dummy_work_fn); - work->srm = kzalloc(16, GFP_KERNEL); + work->srm = kzalloc_objs(*work->srm, 16); KUNIT_ASSERT_NOT_NULL(test, work->srm); - work->srm_temp = kzalloc(16, GFP_KERNEL); + work->srm_temp = kzalloc_objs(*work->srm_temp, 16); KUNIT_ASSERT_NOT_NULL(test, work->srm_temp); kobj = setup_destroy_sysfs(test, work); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c index a2ae30eb55bf..873e7c73e84b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c @@ -428,17 +428,16 @@ static struct dc *dm_test_alloc_dc_with_irq_service(struct kunit *test, dc = dm_kunit_alloc_dc_with_ctx(test); res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res_pool); + KUNIT_ASSERT_NOT_NULL(test, res_pool); irqs = kunit_kzalloc(test, sizeof(*irqs), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, irqs); + KUNIT_ASSERT_NOT_NULL(test, irqs); /* * Populate the per-source info table so amdgpu_dm_irq_set()/_ack() * succeed without touching hardware registers. */ - info = kunit_kzalloc(test, sizeof(*info) * DAL_IRQ_SOURCES_NUMBER, - GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info); + info = kunit_kcalloc(test, DAL_IRQ_SOURCES_NUMBER, sizeof(*info), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, info); for (i = 0; i < DAL_IRQ_SOURCES_NUMBER; i++) info[i].funcs = &dm_test_irq_src_funcs; @@ -504,7 +503,7 @@ static struct amdgpu_crtc *dm_test_add_crtc(struct kunit *test, struct amdgpu_crtc *acrtc; acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + KUNIT_ASSERT_NOT_NULL(test, acrtc); INIT_LIST_HEAD(&acrtc->base.head); acrtc->base.dev = &adev->ddev; @@ -577,7 +576,7 @@ static struct hdcp_workqueue *dm_test_alloc_hdcp_workqueue(struct kunit *test) struct hdcp_workqueue *hdcp_work; hdcp_work = kunit_kzalloc(test, sizeof(*hdcp_work), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hdcp_work); + KUNIT_ASSERT_NOT_NULL(test, hdcp_work); mutex_init(&hdcp_work->mutex); INIT_WORK(&hdcp_work->cpirq_work, dm_test_hdcp_dummy_work); @@ -679,7 +678,7 @@ static void dm_test_are_sinks_equal_first_null(struct kunit *test) struct dc_sink *sink2; sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2); + KUNIT_ASSERT_NOT_NULL(test, sink2); KUNIT_EXPECT_FALSE(test, are_sinks_equal(NULL, sink2)); } @@ -693,7 +692,7 @@ static void dm_test_are_sinks_equal_second_null(struct kunit *test) struct dc_sink *sink1; sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1); + KUNIT_ASSERT_NOT_NULL(test, sink1); KUNIT_EXPECT_FALSE(test, are_sinks_equal(sink1, NULL)); } @@ -707,9 +706,9 @@ static void dm_test_are_sinks_equal_different_signal(struct kunit *test) struct dc_sink *sink1, *sink2; sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1); + KUNIT_ASSERT_NOT_NULL(test, sink1); sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2); + KUNIT_ASSERT_NOT_NULL(test, sink2); sink1->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A; sink2->sink_signal = SIGNAL_TYPE_DISPLAY_PORT; @@ -726,9 +725,9 @@ static void dm_test_are_sinks_equal_different_edid_length(struct kunit *test) struct dc_sink *sink1, *sink2; sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1); + KUNIT_ASSERT_NOT_NULL(test, sink1); sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2); + KUNIT_ASSERT_NOT_NULL(test, sink2); sink1->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A; sink2->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A; @@ -747,9 +746,9 @@ static void dm_test_are_sinks_equal_different_edid_data(struct kunit *test) struct dc_sink *sink1, *sink2; sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1); + KUNIT_ASSERT_NOT_NULL(test, sink1); sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2); + KUNIT_ASSERT_NOT_NULL(test, sink2); sink1->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A; sink2->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A; @@ -770,9 +769,9 @@ static void dm_test_are_sinks_equal_zero_length(struct kunit *test) struct dc_sink *sink1, *sink2; sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1); + KUNIT_ASSERT_NOT_NULL(test, sink1); sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2); + KUNIT_ASSERT_NOT_NULL(test, sink2); sink1->sink_signal = SIGNAL_TYPE_DISPLAY_PORT; sink2->sink_signal = SIGNAL_TYPE_DISPLAY_PORT; @@ -791,9 +790,9 @@ static void dm_test_are_sinks_equal_full_edid_identical(struct kunit *test) struct dc_sink *sink1, *sink2; sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1); + KUNIT_ASSERT_NOT_NULL(test, sink1); sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2); + KUNIT_ASSERT_NOT_NULL(test, sink2); sink1->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A; sink2->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A; @@ -814,9 +813,9 @@ static void dm_test_are_sinks_equal_full_edid_last_byte_differs(struct kunit *te struct dc_sink *sink1, *sink2; sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1); + KUNIT_ASSERT_NOT_NULL(test, sink1); sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2); + KUNIT_ASSERT_NOT_NULL(test, sink2); sink1->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A; sink2->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A; @@ -928,7 +927,7 @@ static void dm_test_irq_init_initializes_lists(struct kunit *test) int src; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); KUNIT_EXPECT_EQ(test, amdgpu_dm_irq_init(adev), 0); @@ -952,7 +951,7 @@ static void dm_test_irq_register_rejects_null_params(struct kunit *test) struct dc_interrupt_params int_params = { 0 }; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT; int_params.irq_source = DC_IRQ_SOURCE_HPD1; @@ -974,7 +973,7 @@ static void dm_test_irq_register_rejects_invalid_context(struct kunit *test) struct dc_interrupt_params int_params = { 0 }; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); int_params.int_context = INTERRUPT_CONTEXT_NUMBER; int_params.irq_source = DC_IRQ_SOURCE_HPD1; @@ -994,7 +993,7 @@ static void dm_test_irq_register_rejects_invalid_source(struct kunit *test) struct dc_interrupt_params int_params = { 0 }; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT; int_params.irq_source = DC_IRQ_SOURCE_INVALID; @@ -1015,7 +1014,7 @@ static void dm_test_irq_register_separate_contexts(struct kunit *test) void *handler; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); int_params.irq_source = DC_IRQ_SOURCE_HPD5; @@ -1066,7 +1065,7 @@ static void dm_test_irq_unregister_rejects_invalid_source(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_INVALID, @@ -1087,7 +1086,7 @@ static void dm_test_irq_unregister_rejects_null_handler(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD1, @@ -1110,7 +1109,7 @@ static void dm_test_irq_unregister_handler_not_found(struct kunit *test) void *handler; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT; @@ -1146,7 +1145,7 @@ static void dm_test_irq_fini_removes_registered_handlers(struct kunit *test) void *handler; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT; @@ -1179,7 +1178,7 @@ static void dm_test_irq_fini_on_empty_tables(struct kunit *test) int src; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); amdgpu_dm_irq_fini(adev); @@ -1208,9 +1207,9 @@ static void dm_test_get_crtc_by_otg_inst_returns_match(struct kunit *test) drm = &adev->ddev; acrtc_a = kunit_kzalloc(test, sizeof(*acrtc_a), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc_a); + KUNIT_ASSERT_NOT_NULL(test, acrtc_a); acrtc_b = kunit_kzalloc(test, sizeof(*acrtc_b), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc_b); + KUNIT_ASSERT_NOT_NULL(test, acrtc_b); INIT_LIST_HEAD(&acrtc_a->base.head); INIT_LIST_HEAD(&acrtc_b->base.head); @@ -1239,7 +1238,7 @@ static void dm_test_get_crtc_by_otg_inst_returns_null(struct kunit *test) drm = &adev->ddev; acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + KUNIT_ASSERT_NOT_NULL(test, acrtc); INIT_LIST_HEAD(&acrtc->base.head); acrtc->otg_inst = 2; @@ -1279,7 +1278,7 @@ static void dm_test_get_crtc_by_otg_inst_unassigned_otg(struct kunit *test) adev = dm_kunit_alloc_adev(test); acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + KUNIT_ASSERT_NOT_NULL(test, acrtc); adev->mode_info.crtcs[0] = acrtc; KUNIT_EXPECT_PTR_EQ(test, amdgpu_dm_get_crtc_by_otg_inst(adev, -1), acrtc); @@ -1296,7 +1295,7 @@ static void dm_test_set_irq_funcs(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); adev->mode_info.num_crtc = 6; adev->mode_info.num_hpd = 4; @@ -1534,12 +1533,12 @@ static void dm_test_hpd_rx_irq_create_workqueue(struct kunit *test) adev = dm_kunit_alloc_adev(test); dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, dc); dc->caps.max_links = 4; adev->dm.dc = dc; ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + KUNIT_ASSERT_NOT_NULL(test, ctx); ctx->wq = amdgpu_dm_hpd_rx_irq_create_workqueue(adev); KUNIT_ASSERT_NOT_NULL(test, ctx->wq); @@ -1561,7 +1560,7 @@ static void dm_test_hpd_rx_irq_work_suspend_null(struct kunit *test) struct amdgpu_display_manager *dm; dm = kunit_kzalloc(test, sizeof(*dm), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm); + KUNIT_ASSERT_NOT_NULL(test, dm); /* A NULL hpd_rx_offload_wq must be a safe no-op (DC untouched). */ amdgpu_dm_hpd_rx_irq_work_suspend(dm); @@ -1580,12 +1579,12 @@ static void dm_test_hpd_rx_irq_work_suspend_flushes(struct kunit *test) adev = dm_kunit_alloc_adev(test); dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, dc); dc->caps.max_links = 2; adev->dm.dc = dc; ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + KUNIT_ASSERT_NOT_NULL(test, ctx); ctx->wq = amdgpu_dm_hpd_rx_irq_create_workqueue(adev); KUNIT_ASSERT_NOT_NULL(test, ctx->wq); @@ -1608,7 +1607,7 @@ static void dm_test_set_crtc_irq_state_no_crtc(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); /* mode_info.crtcs[0] is NULL -> returns 0 without dereferencing DC. */ KUNIT_EXPECT_EQ(test, @@ -1624,7 +1623,7 @@ static void dm_test_set_pflip_irq_state_no_crtc(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); KUNIT_EXPECT_EQ(test, amdgpu_dm_set_pflip_irq_state(adev, NULL, 0, AMDGPU_IRQ_STATE_DISABLE), 0); @@ -1639,7 +1638,7 @@ static void dm_test_set_vline0_irq_state_no_crtc(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); KUNIT_EXPECT_EQ(test, amdgpu_dm_set_vline0_irq_state(adev, NULL, 0, AMDGPU_IRQ_STATE_ENABLE), 0); @@ -1654,7 +1653,7 @@ static void dm_test_set_vupdate_irq_state_no_crtc(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); KUNIT_EXPECT_EQ(test, amdgpu_dm_set_vupdate_irq_state(adev, NULL, 0, AMDGPU_IRQ_STATE_ENABLE), 0); @@ -1672,9 +1671,9 @@ static void dm_test_set_crtc_irq_state_otg_disabled(struct kunit *test) struct amdgpu_crtc *acrtc; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + KUNIT_ASSERT_NOT_NULL(test, acrtc); /* otg_inst == -1 short-circuits before computing the irq source. */ acrtc->otg_inst = -1; @@ -1694,9 +1693,9 @@ static void dm_test_set_crtc_irq_state_enable(struct kunit *test) struct amdgpu_crtc *acrtc; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + KUNIT_ASSERT_NOT_NULL(test, acrtc); /* * otg_inst >= 0 computes the irq source and reaches the NULL-safe @@ -1719,9 +1718,9 @@ static void dm_test_set_pflip_irq_state_disable(struct kunit *test) struct amdgpu_crtc *acrtc; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + KUNIT_ASSERT_NOT_NULL(test, acrtc); /* The disable state exercises the st == false path. */ acrtc->otg_inst = 1; @@ -1749,13 +1748,13 @@ static void dm_test_set_crtc_irq_state_allows_idle(struct kunit *test) adev = dm_kunit_alloc_adev(test); acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + KUNIT_ASSERT_NOT_NULL(test, acrtc); dc = dm_test_alloc_dc_with_irq_service(test, &dm_test_irq_service_funcs_dcn10); /* DC_LOG_* dereferences ctx->logger->dev, so wire a real drm device. */ logger = kunit_kzalloc(test, sizeof(*logger), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, logger); + KUNIT_ASSERT_NOT_NULL(test, logger); logger->dev = &adev->ddev; dc->ctx->logger = logger; @@ -1783,7 +1782,7 @@ static void dm_test_irq_immediate_work_empty(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); /* No registered high-context handlers: must be a safe no-op. */ @@ -1802,7 +1801,7 @@ static void dm_test_irq_immediate_work_invokes_all(struct kunit *test) void *handler; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT; @@ -1833,7 +1832,7 @@ static void dm_test_irq_schedule_work_empty(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); /* Empty handler list: schedule_work returns immediately. */ @@ -1852,7 +1851,7 @@ static void dm_test_irq_schedule_work_queues_handler(struct kunit *test) void *handler; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT; @@ -1893,7 +1892,7 @@ static void dm_test_irq_schedule_work_requeue_fallback(struct kunit *test) void *handler; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT; @@ -1931,7 +1930,7 @@ static void dm_test_irq_schedule_work_no_workqueue(struct kunit *test) void *handler; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT; @@ -1960,7 +1959,7 @@ static void dm_test_set_hpd_irq_state_null_dc(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); /* amdgpu_dm_irq_set() is a no-op when dc is NULL, so both states * return 0 without dereferencing the (absent) DC. @@ -1982,7 +1981,7 @@ static void dm_test_set_dmub_outbox_irq_state_null_dc(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); KUNIT_EXPECT_EQ(test, amdgpu_dm_set_dmub_outbox_irq_state(adev, NULL, 0, AMDGPU_IRQ_STATE_ENABLE), 0); @@ -2001,7 +2000,7 @@ static void dm_test_set_dmub_trace_irq_state_null_dc(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); KUNIT_EXPECT_EQ(test, amdgpu_dm_set_dmub_trace_irq_state(adev, NULL, 0, AMDGPU_IRQ_STATE_ENABLE), 0); @@ -2020,7 +2019,7 @@ static void dm_test_outbox_init_null_dc(struct kunit *test) struct amdgpu_device *adev; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); /* Single amdgpu_dm_irq_set() call must be skipped when dc is NULL. */ amdgpu_dm_outbox_init(adev); @@ -2050,7 +2049,7 @@ static void dm_test_hpd_init_empty_connectors(struct kunit *test) adev->dm.dc = dc; link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); link->irq_source_hpd = DC_IRQ_SOURCE_HPD1; link->irq_source_hpd_rx = DC_IRQ_SOURCE_HPD1RX; dc->links[0] = link; @@ -2099,7 +2098,7 @@ static void dm_test_hpd_init_fini_with_connectors(struct kunit *test) /* A writeback connector must be skipped by the per-connector loop. */ wbconn = kunit_kzalloc(test, sizeof(*wbconn), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, wbconn); + KUNIT_ASSERT_NOT_NULL(test, wbconn); KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, wbconn, &dm_test_connector_funcs, DRM_MODE_CONNECTOR_WRITEBACK), 0); KUNIT_ASSERT_EQ(test, @@ -2107,7 +2106,7 @@ static void dm_test_hpd_init_fini_with_connectors(struct kunit *test) /* A DisplayPort connector with a dc_link exercises the loop body. */ aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn); + KUNIT_ASSERT_NOT_NULL(test, aconn); KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base, &dm_test_connector_funcs, DRM_MODE_CONNECTOR_DisplayPort), 0); @@ -2115,7 +2114,7 @@ static void dm_test_hpd_init_fini_with_connectors(struct kunit *test) kunit_add_action_or_reset(test, dm_test_connector_cleanup, &aconn->base), 0); link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); link->irq_source_hpd = DC_IRQ_SOURCE_HPD1; link->irq_source_hpd_rx = DC_IRQ_SOURCE_HPD1RX; aconn->dc_link = link; @@ -2146,7 +2145,7 @@ static void dm_test_hpd_init_fini_analog_connector(struct kunit *test) adev->dm.dc = dc; aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn); + KUNIT_ASSERT_NOT_NULL(test, aconn); KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base, &dm_test_connector_funcs, DRM_MODE_CONNECTOR_VGA), 0); @@ -2154,7 +2153,7 @@ static void dm_test_hpd_init_fini_analog_connector(struct kunit *test) kunit_add_action_or_reset(test, dm_test_connector_cleanup, &aconn->base), 0); link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); link->irq_source_hpd = DC_IRQ_SOURCE_HPD1; link->irq_source_hpd_rx = DC_IRQ_SOURCE_HPD1RX; /* An analog connector id makes the loop request polling. */ @@ -2199,7 +2198,7 @@ static void dm_test_hpd_init_fini_irq_ref(struct kunit *test) adev->mode_info.num_hpd = 1; aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn); + KUNIT_ASSERT_NOT_NULL(test, aconn); KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base, &dm_test_connector_funcs, DRM_MODE_CONNECTOR_DisplayPort), 0); @@ -2207,7 +2206,7 @@ static void dm_test_hpd_init_fini_irq_ref(struct kunit *test) kunit_add_action_or_reset(test, dm_test_connector_cleanup, &aconn->base), 0); link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); link->irq_source_hpd = DC_IRQ_SOURCE_HPD1; link->irq_source_hpd_rx = DC_IRQ_SOURCE_INVALID; aconn->dc_link = link; @@ -2237,7 +2236,7 @@ static void dm_test_hpd_init_skips_connector_without_link(struct kunit *test) adev->dm.dc = dm_test_alloc_dc_with_irq_service(test, &dm_test_irq_service_funcs_dcn10); aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn); + KUNIT_ASSERT_NOT_NULL(test, aconn); KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base, &dm_test_connector_funcs, DRM_MODE_CONNECTOR_DisplayPort), 0); @@ -2265,10 +2264,10 @@ static void dm_test_hpd_rx_offload_work_no_connector(struct kunit *test) adev = dm_kunit_alloc_adev(test); offload_wq = kunit_kzalloc(test, sizeof(*offload_wq), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_wq); + KUNIT_ASSERT_NOT_NULL(test, offload_wq); offload_work = kzalloc_obj(*offload_work); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_work); + KUNIT_ASSERT_NOT_NULL(test, offload_work); offload_work->offload_wq = offload_wq; offload_work->adev = adev; INIT_WORK(&offload_work->work, dm_handle_hpd_rx_offload_work); @@ -2301,10 +2300,10 @@ dm_test_setup_hpd_rx_offload_work(struct kunit *test, mutex_init(&adev->dm.dc_lock); adev->reset_domain = kunit_kzalloc(test, sizeof(*adev->reset_domain), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev->reset_domain); + KUNIT_ASSERT_NOT_NULL(test, adev->reset_domain); offload_wq = kunit_kzalloc(test, sizeof(*offload_wq), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_wq); + KUNIT_ASSERT_NOT_NULL(test, offload_wq); spin_lock_init(&offload_wq->offload_lock); aconn = dm_kunit_alloc_connector(test, adev, NULL); @@ -2312,13 +2311,13 @@ dm_test_setup_hpd_rx_offload_work(struct kunit *test, offload_wq->aconnector = aconn; dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, dc); ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + KUNIT_ASSERT_NOT_NULL(test, ctx); link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv); + KUNIT_ASSERT_NOT_NULL(test, link_srv); link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); link_srv->detect_connection_type = dm_test_detect_connection_single; dc->link_srv = link_srv; @@ -2330,7 +2329,7 @@ dm_test_setup_hpd_rx_offload_work(struct kunit *test, aconn->dc_link = link; offload_work = kzalloc_obj(*offload_work, GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_work); + KUNIT_ASSERT_NOT_NULL(test, offload_work); offload_work->offload_wq = offload_wq; offload_work->adev = adev; INIT_WORK(&offload_work->work, dm_handle_hpd_rx_offload_work); @@ -2537,13 +2536,13 @@ static struct amdgpu_dm_connector *dm_test_setup_hdmi_debounce(struct kunit *tes amdgpu_dm_hdmi_hpd_debounce_work); dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, dc); ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + KUNIT_ASSERT_NOT_NULL(test, ctx); link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv); + KUNIT_ASSERT_NOT_NULL(test, link_srv); link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); link_srv->detect_link = dm_test_detect_link_false; dc->ctx = ctx; @@ -2595,9 +2594,9 @@ static void dm_test_hdmi_hpd_debounce_reallow_idle(struct kunit *test) dc = aconn->dc_link->ctx->dc; logger = kunit_kzalloc(test, sizeof(*logger), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, logger); + KUNIT_ASSERT_NOT_NULL(test, logger); dmub_srv = kunit_kzalloc(test, sizeof(*dmub_srv), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmub_srv); + KUNIT_ASSERT_NOT_NULL(test, dmub_srv); /* DC_LOG_* dereferences ctx->logger->dev, so wire a real drm device. */ logger->dev = aconn->base.dev; @@ -2698,15 +2697,15 @@ static void dm_test_handle_hpd_irq_disabled(struct kunit *test) aconn = dm_kunit_alloc_connector(test, adev, NULL); state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + KUNIT_ASSERT_NOT_NULL(test, state); aconn->base.state = &state->base; dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, dc); ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + KUNIT_ASSERT_NOT_NULL(test, ctx); link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); dc->ctx = ctx; ctx->dc = dc; @@ -2747,17 +2746,17 @@ static struct amdgpu_dm_connector *dm_test_setup_hpd_irq_helper(struct kunit *te amdgpu_dm_hdmi_hpd_debounce_work); state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + KUNIT_ASSERT_NOT_NULL(test, state); aconn->base.state = &state->base; dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, dc); ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + KUNIT_ASSERT_NOT_NULL(test, ctx); link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv); + KUNIT_ASSERT_NOT_NULL(test, link_srv); link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); link_srv->detect_connection_type = dm_test_detect_connection_none; dc->ctx = ctx; @@ -3006,19 +3005,19 @@ static void dm_test_handle_hpd_rx_irq_disabled(struct kunit *test) adev->dm.disable_hpd_irq = true; offload_wq = kunit_kzalloc(test, sizeof(*offload_wq), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_wq); + KUNIT_ASSERT_NOT_NULL(test, offload_wq); adev->dm.hpd_rx_offload_wq = offload_wq; aconn = dm_kunit_alloc_connector(test, adev, NULL); dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, dc); ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + KUNIT_ASSERT_NOT_NULL(test, ctx); link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv); + KUNIT_ASSERT_NOT_NULL(test, link_srv); link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); link_srv->dp_handle_hpd_rx_irq = dm_test_handle_hpd_rx_no_work; dc->ctx = ctx; @@ -3045,7 +3044,7 @@ static void dm_test_schedule_hpd_rx_offload_work(struct kunit *test) adev = dm_kunit_alloc_adev(test); offload_wq = kunit_kzalloc(test, sizeof(*offload_wq), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_wq); + KUNIT_ASSERT_NOT_NULL(test, offload_wq); offload_wq->wq = create_singlethread_workqueue("dm_irq_test_hpd_rx"); KUNIT_ASSERT_NOT_NULL(test, offload_wq->wq); @@ -3083,7 +3082,7 @@ static struct amdgpu_dm_connector *dm_test_setup_hpd_rx_irq(struct kunit *test, mutex_init(&adev->dm.dc_lock); offload_wq = kunit_kzalloc(test, sizeof(*offload_wq), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_wq); + KUNIT_ASSERT_NOT_NULL(test, offload_wq); spin_lock_init(&offload_wq->offload_lock); offload_wq->wq = create_singlethread_workqueue("dm_irq_test_hpd_rx"); KUNIT_ASSERT_NOT_NULL(test, offload_wq->wq); @@ -3096,13 +3095,13 @@ static struct amdgpu_dm_connector *dm_test_setup_hpd_rx_irq(struct kunit *test, aconn->mst_mgr.mst_state = true; dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, dc); ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + KUNIT_ASSERT_NOT_NULL(test, ctx); link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv); + KUNIT_ASSERT_NOT_NULL(test, link_srv); link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); dc->ctx = ctx; dc->link_srv = link_srv; @@ -3327,7 +3326,7 @@ static void dm_test_dmub_hpd_callback_invalid_index(struct kunit *test) adev = dm_kunit_alloc_adev(test); dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, dc); adev->dm.dc = dc; notify.link_index = 1; @@ -3346,7 +3345,7 @@ static void dm_test_dmub_hpd_callback_empty_connectors(struct kunit *test) adev = dm_kunit_alloc_adev(test); dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, dc); adev->dm.dc = dc; adev->dm.ddev = &adev->ddev; dc->link_count = 1; @@ -3371,7 +3370,7 @@ static void dm_test_dmub_hpd_callback_suspend_skip(struct kunit *test) adev = dm_kunit_alloc_adev(test); dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, dc); adev->dm.dc = dc; adev->in_suspend = true; dc->link_count = 1; @@ -3403,25 +3402,25 @@ static void dm_test_dmub_hpd_callback_unknown_type_match(struct kunit *test) adev = dm_kunit_alloc_adev(test); dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, dc); adev->dm.dc = dc; adev->dm.ddev = &adev->ddev; dc->link_count = 1; link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); dc->links[0] = link; /* A writeback connector must be skipped by the loop. */ wbconn = kunit_kzalloc(test, sizeof(*wbconn), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, wbconn); + KUNIT_ASSERT_NOT_NULL(test, wbconn); KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, wbconn, &dm_test_connector_funcs, DRM_MODE_CONNECTOR_WRITEBACK), 0); KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test, dm_test_connector_cleanup, wbconn), 0); /* A DisplayPort connector whose dc_link matches drives the match branch. */ aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn); + KUNIT_ASSERT_NOT_NULL(test, aconn); KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base, &dm_test_connector_funcs, DRM_MODE_CONNECTOR_DisplayPort), 0); @@ -3458,13 +3457,13 @@ static void dm_test_dmub_hpd_callback_hpd_type(struct kunit *test) mutex_init(&adev->dm.dc_lock); dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, dc); ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + KUNIT_ASSERT_NOT_NULL(test, ctx); link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv); + KUNIT_ASSERT_NOT_NULL(test, link_srv); link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); link_srv->detect_connection_type = dm_test_detect_connection_none; link_srv->detect_link = dm_test_detect_link_false; @@ -3480,7 +3479,7 @@ static void dm_test_dmub_hpd_callback_hpd_type(struct kunit *test) dc->links[0] = link; aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn); + KUNIT_ASSERT_NOT_NULL(test, aconn); KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base, &dm_test_connector_funcs, DRM_MODE_CONNECTOR_DisplayPort), 0); @@ -3522,18 +3521,18 @@ static void dm_test_dmub_hpd_callback_hpd_irq_type(struct kunit *test) mutex_init(&adev->dm.dc_lock); offload_wq = kunit_kzalloc(test, sizeof(*offload_wq), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, offload_wq); + KUNIT_ASSERT_NOT_NULL(test, offload_wq); spin_lock_init(&offload_wq->offload_lock); adev->dm.hpd_rx_offload_wq = offload_wq; dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, dc); ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + KUNIT_ASSERT_NOT_NULL(test, ctx); link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link_srv); + KUNIT_ASSERT_NOT_NULL(test, link_srv); link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); link_srv->dp_handle_hpd_rx_irq = dm_test_handle_hpd_rx_no_work; dc->ctx = ctx; @@ -3550,7 +3549,7 @@ static void dm_test_dmub_hpd_callback_hpd_irq_type(struct kunit *test) dc->links[0] = link; aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn); + KUNIT_ASSERT_NOT_NULL(test, aconn); KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base, &dm_test_connector_funcs, DRM_MODE_CONNECTOR_DisplayPort), 0); @@ -3579,7 +3578,7 @@ static void dm_test_register_hpd_handlers_empty(struct kunit *test) adev = dm_kunit_alloc_adev(test); dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, dc); adev->dm.dc = dc; KUNIT_EXPECT_EQ(test, amdgpu_dm_register_hpd_handlers(adev), 0); @@ -3604,18 +3603,18 @@ static void dm_test_register_hpd_handlers_valid(struct kunit *test) adev = dm_kunit_alloc_adev(test); KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, dc); adev->dm.dc = dc; wbconn = kunit_kzalloc(test, sizeof(*wbconn), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, wbconn); + KUNIT_ASSERT_NOT_NULL(test, wbconn); KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, wbconn, &dm_test_connector_funcs, DRM_MODE_CONNECTOR_WRITEBACK), 0); KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test, dm_test_connector_cleanup, wbconn), 0); aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn); + KUNIT_ASSERT_NOT_NULL(test, aconn); KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base, &dm_test_connector_funcs, DRM_MODE_CONNECTOR_DisplayPort), 0); @@ -3623,7 +3622,7 @@ static void dm_test_register_hpd_handlers_valid(struct kunit *test) kunit_add_action_or_reset(test, dm_test_connector_cleanup, &aconn->base), 0); link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); link->irq_source_hpd = DC_IRQ_SOURCE_HPD1; link->irq_source_hpd_rx = DC_IRQ_SOURCE_HPD1RX; aconn->dc_link = link; @@ -3651,11 +3650,11 @@ static void dm_test_register_hpd_handlers_invalid_hpd(struct kunit *test) adev = dm_kunit_alloc_adev(test); KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, dc); adev->dm.dc = dc; aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn); + KUNIT_ASSERT_NOT_NULL(test, aconn); KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base, &dm_test_connector_funcs, DRM_MODE_CONNECTOR_DisplayPort), 0); @@ -3663,7 +3662,7 @@ static void dm_test_register_hpd_handlers_invalid_hpd(struct kunit *test) kunit_add_action_or_reset(test, dm_test_connector_cleanup, &aconn->base), 0); link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); link->irq_source_hpd = DC_IRQ_SOURCE_HPD1RX; link->irq_source_hpd_rx = DC_IRQ_SOURCE_INVALID; aconn->dc_link = link; @@ -3686,11 +3685,11 @@ static void dm_test_register_hpd_handlers_invalid_hpd_rx(struct kunit *test) adev = dm_kunit_alloc_adev(test); KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, dc); adev->dm.dc = dc; aconn = kunit_kzalloc(test, sizeof(*aconn), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconn); + KUNIT_ASSERT_NOT_NULL(test, aconn); KUNIT_ASSERT_EQ(test, drm_connector_init(&adev->ddev, &aconn->base, &dm_test_connector_funcs, DRM_MODE_CONNECTOR_DisplayPort), 0); @@ -3698,7 +3697,7 @@ static void dm_test_register_hpd_handlers_invalid_hpd_rx(struct kunit *test) kunit_add_action_or_reset(test, dm_test_connector_cleanup, &aconn->base), 0); link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); link->irq_source_hpd = DC_IRQ_SOURCE_INVALID; link->irq_source_hpd_rx = DC_IRQ_SOURCE_HPD1; aconn->dc_link = link; @@ -3803,7 +3802,7 @@ static void dm_test_pflip_high_irq_completes_flip(struct kunit *test) /* drm_crtc_send_vblank_event() consumes (kfree()s) the event. */ event = kzalloc_obj(*event, GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, event); + KUNIT_ASSERT_NOT_NULL(test, event); acrtc->event = event; /* Balance the handler's drm_crtc_vblank_put(). */ @@ -3839,7 +3838,7 @@ static struct amdgpu_crtc *dm_test_setup_vrr_pflip_crtc(struct kunit *test, dc = dm_kunit_alloc_dc_with_ctx(test); dc->current_state = kunit_kzalloc(test, sizeof(*dc->current_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc->current_state); + KUNIT_ASSERT_NOT_NULL(test, dc->current_state); adev->dm.dc = dc; link = dm_kunit_alloc_link(test); @@ -3879,7 +3878,7 @@ static void dm_test_pflip_high_irq_vrr_no_scanoutpos(struct kunit *test) /* drm_crtc_send_vblank_event() consumes (kfree()s) the event. */ event = kzalloc_obj(*event, GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, event); + KUNIT_ASSERT_NOT_NULL(test, event); acrtc->event = event; /* Balance the handler's drm_crtc_vblank_put(). */ @@ -3912,14 +3911,14 @@ static void dm_test_pflip_high_irq_vrr_front_porch(struct kunit *test) struct amdgpu_crtc *acrtc; tg = kunit_kzalloc(test, sizeof(*tg), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, tg); + KUNIT_ASSERT_NOT_NULL(test, tg); tg->funcs = &dm_test_tg_funcs; acrtc = dm_test_setup_vrr_pflip_crtc(test, tg); adev = drm_to_adev(acrtc->base.dev); event = kzalloc_obj(*event, GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, event); + KUNIT_ASSERT_NOT_NULL(test, event); acrtc->event = event; params.adev = adev; @@ -3980,7 +3979,7 @@ static void dm_test_vupdate_high_irq_dcn_completes_flip(struct kunit *test) acrtc->pflip_status = AMDGPU_FLIP_SUBMITTED; event = kzalloc_obj(*event, GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, event); + KUNIT_ASSERT_NOT_NULL(test, event); acrtc->event = event; adev->ddev.vblank[0].time = ktime_get(); @@ -4052,7 +4051,7 @@ static struct amdgpu_crtc *dm_test_setup_vmin_vmax_crtc(struct kunit *test, dc = dm_kunit_alloc_dc_with_ctx(test); dc->current_state = kunit_kzalloc(test, sizeof(*dc->current_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc->current_state); + KUNIT_ASSERT_NOT_NULL(test, dc->current_state); adev->dm.dc = dc; link = dm_kunit_alloc_link(test); @@ -4209,7 +4208,7 @@ static void dm_test_crtc_high_irq_writeback_disables(struct kunit *test) acrtc = dm_test_add_crtc(test, adev); wb_conn = kunit_kzalloc(test, sizeof(*wb_conn), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, wb_conn); + KUNIT_ASSERT_NOT_NULL(test, wb_conn); acrtc->wb_conn = wb_conn; acrtc->wb_pending = true; @@ -4245,7 +4244,7 @@ static void dm_test_crtc_high_irq_writeback_completes(struct kunit *test) acrtc = dm_test_add_crtc(test, adev); wb_conn = kunit_kzalloc(test, sizeof(*wb_conn), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, wb_conn); + KUNIT_ASSERT_NOT_NULL(test, wb_conn); spin_lock_init(&wb_conn->job_lock); INIT_LIST_HEAD(&wb_conn->job_queue); @@ -4254,7 +4253,7 @@ static void dm_test_crtc_high_irq_writeback_completes(struct kunit *test) * work only kfree()s it; it needs nothing from this test. */ job = kzalloc_obj(*job, GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, job); + KUNIT_ASSERT_NOT_NULL(test, job); list_add_tail(&job->list_entry, &wb_conn->job_queue); acrtc->wb_conn = wb_conn; @@ -4322,9 +4321,9 @@ static void dm_test_handle_hpd_work_out_of_range(struct kunit *test) adev = dm_kunit_alloc_adev(test); hpd_work = kzalloc_obj(*hpd_work); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hpd_work); + KUNIT_ASSERT_NOT_NULL(test, hpd_work); hpd_work->dmub_notify = kzalloc_obj(*hpd_work->dmub_notify); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hpd_work->dmub_notify); + KUNIT_ASSERT_NOT_NULL(test, hpd_work->dmub_notify); hpd_work->dmub_notify->type = (enum dmub_notification_type)ARRAY_SIZE(adev->dm.dmub_callback); hpd_work->adev = adev; @@ -4346,7 +4345,7 @@ static void dm_test_handle_hpd_work_null_notify(struct kunit *test) adev = dm_kunit_alloc_adev(test); hpd_work = kzalloc_obj(*hpd_work, GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hpd_work); + KUNIT_ASSERT_NOT_NULL(test, hpd_work); hpd_work->adev = adev; INIT_WORK(&hpd_work->handle_hpd_work, dm_handle_hpd_work); @@ -4372,9 +4371,9 @@ static void dm_test_dmub_outbox1_low_irq_empty(struct kunit *test) adev = dm_kunit_alloc_adev(test); dc = dm_kunit_alloc_dc_with_ctx(test); dc_dmub_srv = kunit_kzalloc(test, sizeof(*dc_dmub_srv), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_dmub_srv); + KUNIT_ASSERT_NOT_NULL(test, dc_dmub_srv); dmub = kunit_kzalloc(test, sizeof(*dmub), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmub); + KUNIT_ASSERT_NOT_NULL(test, dmub); dmub->hw_funcs.get_outbox0_wptr = dm_test_dmub_get_outbox0_wptr; dc_dmub_srv->dmub = dmub; @@ -4406,11 +4405,11 @@ static void dm_test_dmub_outbox1_low_irq_drains_trace(struct kunit *test) adev = dm_kunit_alloc_adev(test); dc = dm_kunit_alloc_dc_with_ctx(test); dc_dmub_srv = kunit_kzalloc(test, sizeof(*dc_dmub_srv), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_dmub_srv); + KUNIT_ASSERT_NOT_NULL(test, dc_dmub_srv); dmub = kunit_kzalloc(test, sizeof(*dmub), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmub); + KUNIT_ASSERT_NOT_NULL(test, dmub); rb = kunit_kzalloc(test, DM_TEST_OUTBOX0_RB_SIZE, GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, rb); + KUNIT_ASSERT_NOT_NULL(test, rb); dmub->outbox0_rb.base_address = rb; dmub->outbox0_rb.capacity = DM_TEST_OUTBOX0_RB_SIZE; @@ -4446,9 +4445,9 @@ static struct amdgpu_device *dm_test_alloc_adev_outbox_notify(struct kunit *test adev = dm_kunit_alloc_adev(test); dc = dm_kunit_alloc_dc_with_ctx(test); dc_dmub_srv = kunit_kzalloc(test, sizeof(*dc_dmub_srv), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_dmub_srv); + KUNIT_ASSERT_NOT_NULL(test, dc_dmub_srv); dmub = kunit_kzalloc(test, sizeof(*dmub), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmub); + KUNIT_ASSERT_NOT_NULL(test, dmub); dmub->hw_init = true; dmub->hw_funcs.get_outbox0_wptr = dm_test_dmub_get_outbox0_wptr; @@ -4926,7 +4925,7 @@ static void dm_test_register_outbox_irq_handlers_with_dmub(struct kunit *test) adev), 0); dc = dm_test_alloc_dc_with_irq_service(test, &dm_test_irq_service_funcs_dcn10); dc_dmub_srv = kunit_kzalloc(test, sizeof(*dc_dmub_srv), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_dmub_srv); + KUNIT_ASSERT_NOT_NULL(test, dc_dmub_srv); dc->ctx->dmub_srv = dc_dmub_srv; adev->dm.dc = dc; amdgpu_dm_set_irq_funcs(adev); @@ -4969,7 +4968,7 @@ static void dm_test_irq_handler_dispatches_work(struct kunit *test) struct dc *dc; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); dc = dm_test_alloc_dc_with_irq_service(test, @@ -5029,7 +5028,7 @@ static void dm_test_irq_handler_invalid_source(struct kunit *test) int low_count = 0; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); /* This stub maps every src_id to DC_IRQ_SOURCE_INVALID. */ @@ -5076,17 +5075,17 @@ static void dm_test_handle_vmin_vmax_update(struct kunit *test) struct dc *dc; adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, adev); mutex_init(&adev->dm.dc_lock); dc = dm_kunit_alloc_dc_with_ctx(test); dc->current_state = kunit_kzalloc(test, sizeof(*dc->current_state), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc->current_state); + KUNIT_ASSERT_NOT_NULL(test, dc->current_state); adev->dm.dc = dc; stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); + KUNIT_ASSERT_NOT_NULL(test, stream); /* * Start at two references: the worker's dc_stream_release() drops one, * leaving the kunit-managed allocation intact (no kfree). @@ -5096,9 +5095,9 @@ static void dm_test_handle_vmin_vmax_update(struct kunit *test) /* The worker kfree()s both, so they must come from the slab. */ work = kzalloc_obj(*work); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, work); + KUNIT_ASSERT_NOT_NULL(test, work); adjust = kzalloc_obj(*adjust); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adjust); + KUNIT_ASSERT_NOT_NULL(test, adjust); work->adev = adev; work->stream = stream; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_kunit_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_kunit_helpers.c index aad122c7229f..f844b644bb77 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_kunit_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_kunit_helpers.c @@ -182,7 +182,7 @@ struct drm_device *dm_kunit_alloc_drm_with_connector_list(struct kunit *test) struct drm_device *dev; dev = kunit_kzalloc(test, sizeof(*dev), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + KUNIT_ASSERT_NOT_NULL(test, dev); INIT_LIST_HEAD(&dev->mode_config.connector_list); spin_lock_init(&dev->mode_config.connector_list_lock); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c index eafa3e6733a6..237431c83a81 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c @@ -203,7 +203,7 @@ static void dm_mst_test_needs_dsc_aux_workaround_match(struct kunit *test) { struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); link->dpcd_caps.branch_dev_id = DP_BRANCH_DEVICE_ID_90CC24; link->dpcd_caps.dpcd_rev.raw = DPCD_REV_14; @@ -223,7 +223,7 @@ static void dm_mst_test_needs_dsc_aux_workaround_rev12(struct kunit *test) { struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); link->dpcd_caps.branch_dev_id = DP_BRANCH_DEVICE_ID_90CC24; link->dpcd_caps.dpcd_rev.raw = DPCD_REV_12; @@ -243,7 +243,7 @@ static void dm_mst_test_needs_dsc_aux_workaround_wrong_dev_id(struct kunit *test { struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); link->dpcd_caps.branch_dev_id = 0x123456; link->dpcd_caps.dpcd_rev.raw = DPCD_REV_14; @@ -263,7 +263,7 @@ static void dm_mst_test_needs_dsc_aux_workaround_wrong_rev(struct kunit *test) { struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); link->dpcd_caps.branch_dev_id = DP_BRANCH_DEVICE_ID_90CC24; link->dpcd_caps.dpcd_rev.raw = 0x11; /* DPCD 1.1 */ @@ -283,7 +283,7 @@ static void dm_mst_test_needs_dsc_aux_workaround_low_sink_count(struct kunit *te { struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); link->dpcd_caps.branch_dev_id = DP_BRANCH_DEVICE_ID_90CC24; link->dpcd_caps.dpcd_rev.raw = DPCD_REV_14; @@ -303,7 +303,7 @@ static void dm_mst_test_needs_dsc_aux_workaround_zero_sink_count(struct kunit *t { struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, link); link->dpcd_caps.branch_dev_id = DP_BRANCH_DEVICE_ID_90CC24; link->dpcd_caps.dpcd_rev.raw = DPCD_REV_14; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_quirks_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_quirks_test.c index 150c53a68bed..8547ac047e7f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_quirks_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_quirks_test.c @@ -27,7 +27,7 @@ static void dm_test_quirks_aux_hpd_discon_reset(struct kunit *test) struct amdgpu_display_manager *dm; dm = kunit_kzalloc(test, sizeof(*dm), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm); + KUNIT_ASSERT_NOT_NULL(test, dm); dm->aux_hpd_discon_quirk = true; @@ -54,7 +54,7 @@ static void dm_test_quirks_edp0_on_dp1_reset(struct kunit *test) struct amdgpu_display_manager *dm; dm = kunit_kzalloc(test, sizeof(*dm), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm); + KUNIT_ASSERT_NOT_NULL(test, dm); dm->edp0_on_dp1_quirk = true; @@ -76,7 +76,7 @@ static void dm_test_quirks_no_dmi_match_both_false(struct kunit *test) struct amdgpu_display_manager *dm; dm = kunit_kzalloc(test, sizeof(*dm), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm); + KUNIT_ASSERT_NOT_NULL(test, dm); retrieve_dmi_info(dm); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c index e77e6fa18a72..c375ee68778b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c @@ -258,9 +258,9 @@ static void dm_test_plane_layer_index_cmp_equal(struct kunit *test) struct dc_surface_update sa, sb; plane_a = kunit_kzalloc(test, sizeof(*plane_a), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_a); + KUNIT_ASSERT_NOT_NULL(test, plane_a); plane_b = kunit_kzalloc(test, sizeof(*plane_b), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_b); + KUNIT_ASSERT_NOT_NULL(test, plane_b); plane_a->layer_index = 5; plane_b->layer_index = 5; @@ -281,9 +281,9 @@ static void dm_test_plane_layer_index_cmp_descending(struct kunit *test) struct dc_surface_update sa, sb; plane_a = kunit_kzalloc(test, sizeof(*plane_a), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_a); + KUNIT_ASSERT_NOT_NULL(test, plane_a); plane_b = kunit_kzalloc(test, sizeof(*plane_b), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_b); + KUNIT_ASSERT_NOT_NULL(test, plane_b); plane_a->layer_index = 3; plane_b->layer_index = 7; @@ -305,9 +305,9 @@ static void dm_test_plane_layer_index_cmp_ascending(struct kunit *test) struct dc_surface_update sa, sb; plane_a = kunit_kzalloc(test, sizeof(*plane_a), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_a); + KUNIT_ASSERT_NOT_NULL(test, plane_a); plane_b = kunit_kzalloc(test, sizeof(*plane_b), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_b); + KUNIT_ASSERT_NOT_NULL(test, plane_b); plane_a->layer_index = 9; plane_b->layer_index = 2; @@ -763,7 +763,7 @@ static void dm_test_multisync_trigger_disabled(struct kunit *test) struct dc_stream_state *stream; stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); + KUNIT_ASSERT_NOT_NULL(test, stream); stream->triggered_crtc_reset.enabled = false; stream->triggered_crtc_reset.event = CRTC_EVENT_VSYNC_FALLING; @@ -788,9 +788,9 @@ static void dm_test_multisync_trigger_rising(struct kunit *test) struct dc_stream_state *master; stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); + KUNIT_ASSERT_NOT_NULL(test, stream); master = kunit_kzalloc(test, sizeof(*master), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, master); + KUNIT_ASSERT_NOT_NULL(test, master); master->timing.flags.VSYNC_POSITIVE_POLARITY = 1; stream->triggered_crtc_reset.enabled = true; @@ -814,9 +814,9 @@ static void dm_test_multisync_trigger_falling(struct kunit *test) struct dc_stream_state *master; stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); + KUNIT_ASSERT_NOT_NULL(test, stream); master = kunit_kzalloc(test, sizeof(*master), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, master); + KUNIT_ASSERT_NOT_NULL(test, master); master->timing.flags.VSYNC_POSITIVE_POLARITY = 0; stream->triggered_crtc_reset.enabled = true; @@ -842,9 +842,9 @@ static void dm_test_master_stream_highest_refresh(struct kunit *test) struct dc_stream_state *stream_set[2]; stream0 = kunit_kzalloc(test, sizeof(*stream0), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream0); + KUNIT_ASSERT_NOT_NULL(test, stream0); stream1 = kunit_kzalloc(test, sizeof(*stream1), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream1); + KUNIT_ASSERT_NOT_NULL(test, stream1); stream_set[0] = stream0; stream_set[1] = stream1; @@ -880,9 +880,9 @@ static void dm_test_master_stream_defaults_to_first(struct kunit *test) struct dc_stream_state *stream_set[2]; stream0 = kunit_kzalloc(test, sizeof(*stream0), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream0); + KUNIT_ASSERT_NOT_NULL(test, stream0); stream1 = kunit_kzalloc(test, sizeof(*stream1), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream1); + KUNIT_ASSERT_NOT_NULL(test, stream1); stream_set[0] = stream0; stream_set[1] = stream1; diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile index 39cffa0a8116..84c68b87210f 100644 --- a/drivers/gpu/drm/amd/display/dc/Makefile +++ b/drivers/gpu/drm/amd/display/dc/Makefile @@ -83,6 +83,13 @@ FILES += core/dc_surface.o FILES += core/dc_vm_helper.o FILES += core2/dc_core2.o FILES += core2/dc_core2_init.o +FILES += core2/dc_core2_legacy_init.o +FILES += bls_builder/bls_builder.o +FILES += bls_builder/dcn401_init_builder.o +FILES += bls_builder/dcn401_init_builder_legacy.o +FILES += bls_executor/bls_executor.o +FILES += workaround_manager/workaround_manager.o +FILES += dmub_messenger/dmub_messenger.o AMD_DISPLAY_FILES += $(addprefix $(AMDDALPATH)/dc/, $(FILES)) diff --git a/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder.c b/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder.c new file mode 100644 index 000000000000..8ac202487189 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#include "dm_services.h" +#include "bls_builder/bls_builder_internal.h" + +const struct bls_builder *bls_builder_create(struct dc *dc, + enum bls_builder_name name) +{ + if (!dc || !dc->ctx) + return NULL; + + switch (dc->ctx->dce_version) { + case DCN_VERSION_4_01: + return dcn401_bls_builder_create(name); + default: + return NULL; + } +} diff --git a/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder.h b/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder.h new file mode 100644 index 000000000000..422ee25cf348 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder.h @@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#pragma once + +#include "dc.h" +#include "dmub_cmd.h" +#include "dmub/dmub_srv.h" +#include "hwss/hw_sequencer.h" +#include "bls_builder/dmub_abi.h" +#include "bls_builder/bls_builder_legacy_init.h" + +#define DC2_BLS_MAX_STEPS 64 + +enum bls_builder_result { + BLS_BUILD_SUCCESS, + BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE, + BLS_BUILD_ERROR_RESOURCE_MAPPING, + BLS_BUILD_ERROR_DMUB_ABI_UNRESOLVED, +}; + +enum bls_builder_name { + DCN_DECL_INITIALIZATION, + DCN_DECL_INITIALIZATION_LEGACY, + BLS_BUILDER_NAME_COUNT, +}; + +enum bls_builder_kind { + BLS_BUILDER_DECLARATIVE, + BLS_BUILDER_IMPERATIVE, +}; + +struct bls_builder_output_init { + unsigned int xtalin_clock_inKhz; + unsigned int dccg_ref_clock_inKhz; + unsigned int dchub_ref_clock_inKhz; + unsigned int dchub_ref_clock_inKhz_before; + unsigned int backlight; + bool dcmode_power_limits_present; + unsigned int dmub_stop_fw_response; + struct dmub_abi dmub_abi; + union dmub_rb_cmd dmub_query_feature_caps_cmd; + union dmub_rb_cmd dmub_initialize_dcn_cmd; +}; + +struct bls_builder_output_targets { + union { + struct bls_builder_output_init *DCN_DECL_INITIALIZATION; + struct bls_builder_legacy_hw_init_info *DCN_DECL_INITIALIZATION_LEGACY; + }; +}; + +struct bls_builder_check_capability_params { + struct dc *dc; + const struct dc_state *current_state; + const struct dc_state *new_state; +}; + +struct bls_builder_declarative_params { + struct dc *dc; + const struct dc_state *current_state; + const struct dc_state *new_state; + const struct dmub_abi *dmub_abi; + const struct dmub_srv_hw_params *dmub_hw_params; + /* + * Filled when the caller does not pass dmub_hw_params and dmub_srv + * already retained framebuffer windows. fb_info on dmub_srv is + * const, so the window table is copied here before the PSP entry + * points at owned_dmub_hw_params. + */ + struct dmub_srv_hw_params owned_dmub_hw_params; + struct dmub_srv_fb_info owned_dmub_fb_info; + struct bls_builder_output_targets *out_targets; + struct block_sequence head_sequence[DC2_BLS_MAX_STEPS]; + unsigned int head_num_steps; + struct block_sequence tail_sequence[DC2_BLS_MAX_STEPS]; + unsigned int tail_num_steps; +}; + +typedef bool (*bls_builder_check_capability)( + const struct bls_builder_check_capability_params *params); + +typedef enum bls_builder_result (*bls_builder_build_declarative)( + struct bls_builder_declarative_params *params); + +struct bls_builder { + enum bls_builder_name name; + enum bls_builder_kind kind; + bls_builder_check_capability check_capability; + union { + bls_builder_build_declarative declarative; + } build; +}; + +const struct bls_builder *bls_builder_create(struct dc *dc, + enum bls_builder_name name); diff --git a/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder_internal.h b/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder_internal.h new file mode 100644 index 000000000000..216879c93f9e --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder_internal.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#pragma once + +#include "bls_builder/bls_builder.h" + +const struct bls_builder *dcn401_bls_builder_create( + enum bls_builder_name name); diff --git a/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder_legacy_init.h b/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder_legacy_init.h new file mode 100644 index 000000000000..e9259699a9c0 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/bls_builder/bls_builder_legacy_init.h @@ -0,0 +1,128 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#pragma once + +#include "dmub_cmd.h" +#include "grph_object_ctrl_defs.h" +#include "bios_parser_types.h" +#include "inc/hw/hw_shared.h" + +/* + * DC2_DC1_Wrapped hardware init: dcn401_init_hw as twelve BLS stages. + * A stage ends on a read that a later stage depends on. Stage N writes + * bls_builder_output_legacy_init_stageN; a later stage reads it from + * dc_state.hw_init_info. + */ +enum bls_builder_legacy_init_stage { + LEGACY_INIT_STAGE_CLOCKS = 1, + LEGACY_INIT_STAGE_DCHUB_REF, + LEGACY_INIT_STAGE_LINK_ENC, + LEGACY_INIT_STAGE_FEC, + LEGACY_INIT_STAGE_BLANK, + LEGACY_INIT_STAGE_POWER_DOWN, + LEGACY_INIT_STAGE_MIN_CLOCKS, + LEGACY_INIT_STAGE_POWER_DOWN_EDP0, + LEGACY_INIT_STAGE_POWER_DOWN_EDP1, + LEGACY_INIT_STAGE_GATING, + LEGACY_INIT_STAGE_HUBBUB, + LEGACY_INIT_STAGE_POWER_STATE, + LEGACY_INIT_STAGE_COUNT = LEGACY_INIT_STAGE_POWER_STATE, +}; + +/* CLOCKS: DC-mode limits and the DCCG reference clocks. */ +struct bls_builder_output_legacy_init_stage1 { + bool dcmode_power_limits_present; + unsigned int xtalin_clock_inKhz; + unsigned int dccg_ref_clock_inKhz; +}; + +/* DCHUB_REF: the DCHUB reference clock, before and after the read. */ +struct bls_builder_output_legacy_init_stage2 { + unsigned int dchub_ref_clock_mhz_before; + unsigned int dchub_ref_clock_inKhz; +}; + +/* LINK_ENC: per dc->links entry, the DIG state and the I2C info. */ +struct bls_builder_output_legacy_init_stage3 { + bool link_dig_enabled[MAX_LINKS]; + struct graphics_object_i2c_info link_i2c_info[MAX_LINKS]; + enum bp_result link_i2c_result[MAX_LINKS]; +}; + +/* FEC: per dc->links entry, whether FEC is active. */ +struct bls_builder_output_legacy_init_stage4 { + bool link_fec_active[MAX_LINKS]; +}; + +/* BLANK: the VBIOS accelerated-mode bit after blanking. */ +struct bls_builder_output_legacy_init_stage5 { + bool accelerated_mode; +}; + +/* POWER_DOWN: the DENTIST dispclk. */ +struct bls_builder_output_legacy_init_stage6 { + int dispclk_from_dentist_khz; +}; + +/* MIN_CLOCKS: power-down-on-boot DIG reads for eDP slot 0, or every link. */ +struct bls_builder_output_legacy_init_stage7 { + bool edp_dig_enabled; + bool boot_dig_enabled[MAX_LINKS]; +}; + +/* POWER_DOWN_EDP0: the power-down-on-boot DIG read for eDP slot 1. */ +struct bls_builder_output_legacy_init_stage8 { + bool edp_dig_enabled; +}; + +/* POWER_DOWN_EDP1: the backlight panel_cntl reports, and the IHC commands. */ +struct bls_builder_output_legacy_init_stage9 { + uint32_t backlight; + uint32_t user_level; + union dmub_rb_cmd dmub_ihc_cmd[MAX_LINKS]; +}; + +/* GATING: the VBIOS accelerated-mode bit after gating. */ +struct bls_builder_output_legacy_init_stage10 { + bool accelerated_mode; +}; + +/* + * HUBBUB: whether the DMUB feature caps apply, whether the query was + * sent, and the command that holds the reply. + */ +struct bls_builder_output_legacy_init_stage11 { + bool dmub_caps_read; + bool dmub_caps_query_sent; + union dmub_rb_cmd dmub_query_feature_caps_cmd; +}; + +/* POWER_STATE: the D0 power-state command. */ +struct bls_builder_output_legacy_init_stage12 { + union dmub_rb_cmd dmub_power_state_cmd; +}; + +/* + * next_stage is the stage the builder builds next, and s1 up to the + * stage before it are valid. Core stops at init_done. + */ +struct bls_builder_legacy_hw_init_info { + bool init_done; + bool init_success; + unsigned int next_stage; + struct bls_builder_output_legacy_init_stage1 s1; + struct bls_builder_output_legacy_init_stage2 s2; + struct bls_builder_output_legacy_init_stage3 s3; + struct bls_builder_output_legacy_init_stage4 s4; + struct bls_builder_output_legacy_init_stage5 s5; + struct bls_builder_output_legacy_init_stage6 s6; + struct bls_builder_output_legacy_init_stage7 s7; + struct bls_builder_output_legacy_init_stage8 s8; + struct bls_builder_output_legacy_init_stage9 s9; + struct bls_builder_output_legacy_init_stage10 s10; + struct bls_builder_output_legacy_init_stage11 s11; + struct bls_builder_output_legacy_init_stage12 s12; +}; diff --git a/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder.c b/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder.c new file mode 100644 index 000000000000..589a950e078b --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder.c @@ -0,0 +1,413 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#include "dm_services.h" +#include "core_types.h" +#include "clk_mgr.h" +#include "dccg.h" +#include "resource.h" +#include "dc_dmub_srv.h" +#include "dmub_cmd.h" +#include "bls_builder/bls_builder_internal.h" +#include "bls_builder/dcn401_init_builder.h" +#include "bls_builder/dcn401_init_builder_legacy.h" + +static const enum block_sequence_func dcn401_dc2_init_sequence[] = { + LEGACY_CLK_MGR_INIT_CLOCKS, + LEGACY_CLK_MGR_IS_DC_MODE_PRESENT, + DCCG_INITIALIZE_CLOCKS, + DMUB_HALT_FW, + PSP_RELOAD_DMUB_FW, + DMUB_GPINT_SEND_AND_WAIT, + DMUB_SEND_DMCUB_CMD, + DMUB_INITIALIZE_DCN, +}; + +static enum bls_builder_result dcn401_check_initialization_support( + const struct bls_builder_check_capability_params *params) +{ + struct dc *dc; + + if (!params || !params->dc) + return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE; + + dc = params->dc; + if (!dc->ctx || !dc->res_pool || !dc->res_pool->dccg) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + if (dc->config.seamless_boot_edp_requested) + return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE; + + return BLS_BUILD_SUCCESS; +} + +static bool dcn401_initialization_check_capability( + const struct bls_builder_check_capability_params *params) +{ + return dcn401_check_initialization_support(params) == + BLS_BUILD_SUCCESS; +} + +static enum bls_builder_result dcn401_validate_initialization_step( + const struct bls_builder_declarative_params *params, + enum block_sequence_func func) +{ + struct bls_builder_output_init *out_init = NULL; + struct clk_mgr *clk_mgr = params->dc->clk_mgr; + struct dccg *dccg = params->dc->res_pool->dccg; + + if (params->out_targets) + out_init = params->out_targets->DCN_DECL_INITIALIZATION; + + switch (func) { + case LEGACY_CLK_MGR_INIT_CLOCKS: + if (!clk_mgr || !clk_mgr->funcs || + !clk_mgr->funcs->init_clocks) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + return BLS_BUILD_SUCCESS; + case LEGACY_CLK_MGR_IS_DC_MODE_PRESENT: + if (!clk_mgr || !clk_mgr->funcs || + !clk_mgr->funcs->is_dc_mode_present || + !out_init) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + return BLS_BUILD_SUCCESS; + case DCCG_INITIALIZE_CLOCKS: + if (!dccg->funcs || !dccg->funcs->dccg_init) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + return BLS_BUILD_SUCCESS; + case DMUB_GPINT_SEND_AND_WAIT: + case DMUB_HALT_FW: { + struct dc_context *ctx = params->dc->ctx; + struct dmub_srv *dmub; + + if (!ctx || !ctx->dmub_srv || !ctx->dmub_srv->dmub || !out_init) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + dmub = ctx->dmub_srv->dmub; + if (!dmub->sw_init || !dmub->hw_funcs.set_gpint || + !dmub->hw_funcs.is_gpint_acked || + !dmub->hw_funcs.get_gpint_response) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + return BLS_BUILD_SUCCESS; + } + case PSP_RELOAD_DMUB_FW: { + struct dmub_srv *dmub; + + if (!params->dc->ctx || !params->dc->ctx->dmub_srv || + !params->dc->ctx->dmub_srv->dmub) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + /* + * An explicit caller pointer wins, including a test double + * whose fb_info is still empty. Otherwise use the windows + * dmub_srv retained from the DM's earlier hw init. + */ + if (params->dmub_hw_params) + return BLS_BUILD_SUCCESS; + dmub = params->dc->ctx->dmub_srv->dmub; + if (!dmub->fb_info || + dmub->fb_info->num_fb < DMUB_WINDOW_TOTAL) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + return BLS_BUILD_SUCCESS; + } + case DMUB_SEND_DMCUB_CMD: + case DMUB_INITIALIZE_DCN: + if (!params->dc->ctx || !params->dc->ctx->dmub_srv || + !params->dc->ctx->dmub_srv->dmub || !out_init) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + return BLS_BUILD_SUCCESS; + default: + return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE; + } +} + +enum bls_builder_result dcn401_build_clk_mgr_init( + struct clk_mgr *clk_mgr, struct block_sequence_state *sequence) +{ + union block_sequence_params bls_params = {0}; + + bls_params.legacy_clk_mgr_init_clocks_params.clk_mgr = clk_mgr; + if (!bls_append(sequence, LEGACY_CLK_MGR_INIT_CLOCKS, &bls_params)) + return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE; + + return BLS_BUILD_SUCCESS; +} + +enum bls_builder_result dcn401_build_dc_mode_read( + struct clk_mgr *clk_mgr, bool *out_dcmode_power_limits_present, + struct block_sequence_state *sequence) +{ + union block_sequence_params bls_params = {0}; + + bls_params.legacy_clk_mgr_is_dc_mode_present_params.clk_mgr = clk_mgr; + bls_params.legacy_clk_mgr_is_dc_mode_present_params + .out_dcmode_power_limits_present = + out_dcmode_power_limits_present; + if (!bls_append(sequence, LEGACY_CLK_MGR_IS_DC_MODE_PRESENT, + &bls_params)) + return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE; + + return BLS_BUILD_SUCCESS; +} + +enum bls_builder_result dcn401_build_dccg_init( + struct dccg *dccg, struct block_sequence_state *sequence) +{ + union block_sequence_params bls_params = {0}; + + bls_params.dccg_initialize_clocks_params.dccg = dccg; + if (!bls_append(sequence, DCCG_INITIALIZE_CLOCKS, &bls_params)) + return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE; + + return BLS_BUILD_SUCCESS; +} + +static inline enum bls_builder_result dcn401_build_dmub_halt_fw( + struct bls_builder_declarative_params *params, + struct block_sequence_state *sequence) +{ + union block_sequence_params bls_params = {0}; + struct bls_builder_output_init *out_init = + params->out_targets->DCN_DECL_INITIALIZATION; + + bls_params.dmub_gpint_params.command_code = DMUB_GPINT__STOP_FW; + bls_params.dmub_gpint_params.param = 0; + bls_params.dmub_gpint_params.response = + &out_init->dmub_stop_fw_response; + if (!bls_append(sequence, DMUB_HALT_FW, &bls_params)) + return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE; + + return BLS_BUILD_SUCCESS; +} + +static const struct dmub_srv_hw_params *dcn401_psp_hw_params( + struct bls_builder_declarative_params *params) +{ + struct dmub_srv *dmub; + + if (params->dmub_hw_params) + return params->dmub_hw_params; + + dmub = params->dc->ctx->dmub_srv->dmub; + params->owned_dmub_fb_info = *dmub->fb_info; + memset(¶ms->owned_dmub_hw_params, 0, + sizeof(params->owned_dmub_hw_params)); + params->owned_dmub_hw_params.fb_info = ¶ms->owned_dmub_fb_info; + params->owned_dmub_hw_params.soc_fb_info = dmub->soc_fb_info; + params->owned_dmub_hw_params.psp_version = dmub->psp_version; + return ¶ms->owned_dmub_hw_params; +} + +static inline enum bls_builder_result dcn401_build_psp_reload( + struct bls_builder_declarative_params *params, + struct block_sequence_state *sequence) +{ + union block_sequence_params bls_params = {0}; + + bls_params.psp_reload_dmub_fw_params.dmub = + params->dc->ctx->dmub_srv->dmub; + bls_params.psp_reload_dmub_fw_params.hw_params = + dcn401_psp_hw_params(params); + if (!bls_append(sequence, PSP_RELOAD_DMUB_FW, &bls_params)) + return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE; + + return BLS_BUILD_SUCCESS; +} + +static inline enum bls_builder_result dcn401_build_dmub_fw_version( + struct bls_builder_declarative_params *params, + struct block_sequence_state *sequence) +{ + union block_sequence_params bls_params = {0}; + struct bls_builder_output_init *out_init = + params->out_targets->DCN_DECL_INITIALIZATION; + + bls_params.dmub_gpint_params.command_code = + DMUB_GPINT__GET_FW_VERSION; + bls_params.dmub_gpint_params.param = 0; + bls_params.dmub_gpint_params.response = + &out_init->dmub_abi.fw_version; + if (!bls_append(sequence, DMUB_GPINT_SEND_AND_WAIT, &bls_params)) + return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE; + + return BLS_BUILD_SUCCESS; +} + +bool dcn401_add_dmub_cmd(struct block_sequence_state *sequence, + struct dc_context *ctx, union dmub_rb_cmd *cmd, + enum dm_dmub_wait_type wait_type, bool continue_on_error) +{ + union block_sequence_params bls_params = {0}; + + bls_params.send_dmcub_cmd_params.ctx = ctx; + bls_params.send_dmcub_cmd_params.cmd = cmd; + bls_params.send_dmcub_cmd_params.wait_type = wait_type; + bls_params.send_dmcub_cmd_params.continue_on_error = continue_on_error; + return bls_append(sequence, DMUB_SEND_DMCUB_CMD, &bls_params); +} + +void dcn401_fill_query_feature_caps_cmd(union dmub_rb_cmd *cmd) +{ + memset(cmd, 0, sizeof(*cmd)); + cmd->query_feature_caps.header.type = DMUB_CMD__QUERY_FEATURE_CAPS; + cmd->query_feature_caps.header.sub_type = 0; + cmd->query_feature_caps.header.ret_status = 1; + cmd->query_feature_caps.header.payload_bytes = + sizeof(struct dmub_cmd_query_feature_caps_data); +} + +static inline enum bls_builder_result dcn401_build_dmub_feature_caps( + struct bls_builder_declarative_params *params, + struct block_sequence_state *sequence) +{ + struct bls_builder_output_init *out_init = + params->out_targets->DCN_DECL_INITIALIZATION; + union dmub_rb_cmd *cmd = &out_init->dmub_query_feature_caps_cmd; + + dcn401_fill_query_feature_caps_cmd(cmd); + if (!dcn401_add_dmub_cmd(sequence, params->dc->ctx, cmd, + DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY, false)) + return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE; + + return BLS_BUILD_SUCCESS; +} + +static inline enum bls_builder_result dcn401_build_dmub_initialize_dcn( + struct bls_builder_declarative_params *params, + struct block_sequence_state *sequence) +{ + union block_sequence_params bls_params = {0}; + struct bls_builder_output_init *out_init = + params->out_targets->DCN_DECL_INITIALIZATION; + union dmub_rb_cmd *cmd = &out_init->dmub_initialize_dcn_cmd; + + /* + * No Initialize DCN opcode exists in dmub_cmd.h. A caller-supplied + * non-zero type is preserved for tests; zero stays an undefined + * command and cannot complete a successful build. + */ + if (!cmd->cmd_common.header.type) + memset(cmd, 0, sizeof(*cmd)); + bls_params.send_dmcub_cmd_params.ctx = params->dc->ctx; + bls_params.send_dmcub_cmd_params.cmd = cmd; + bls_params.send_dmcub_cmd_params.wait_type = + DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY; + if (!bls_append(sequence, DMUB_INITIALIZE_DCN, &bls_params)) + return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE; + + return BLS_BUILD_SUCCESS; +} + +static enum bls_builder_result dcn401_build_initialization_step( + struct bls_builder_declarative_params *params, + struct block_sequence_state *sequence, + enum block_sequence_func func) +{ + switch (func) { + case LEGACY_CLK_MGR_INIT_CLOCKS: + return dcn401_build_clk_mgr_init(params->dc->clk_mgr, sequence); + case LEGACY_CLK_MGR_IS_DC_MODE_PRESENT: + return dcn401_build_dc_mode_read(params->dc->clk_mgr, + ¶ms->out_targets->DCN_DECL_INITIALIZATION + ->dcmode_power_limits_present, sequence); + case DCCG_INITIALIZE_CLOCKS: + return dcn401_build_dccg_init(params->dc->res_pool->dccg, + sequence); + case DMUB_HALT_FW: + return dcn401_build_dmub_halt_fw(params, sequence); + case PSP_RELOAD_DMUB_FW: + return dcn401_build_psp_reload(params, sequence); + case DMUB_GPINT_SEND_AND_WAIT: + return dcn401_build_dmub_fw_version(params, sequence); + case DMUB_SEND_DMCUB_CMD: + return dcn401_build_dmub_feature_caps(params, sequence); + case DMUB_INITIALIZE_DCN: + return dcn401_build_dmub_initialize_dcn(params, sequence); + default: + return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE; + } +} + +static enum bls_builder_result dcn401_build_initialization( + struct bls_builder_declarative_params *params) +{ + struct bls_builder_check_capability_params check_params = {0}; + enum bls_builder_result result; + struct block_sequence_state sequence; + struct bls_builder_output_init *out_init = NULL; + unsigned int i; + + if (!params) + return dcn401_check_initialization_support(NULL); + + check_params.dc = params->dc; + check_params.current_state = params->current_state; + check_params.new_state = params->new_state; + result = + dcn401_check_initialization_support(&check_params); + if (result != BLS_BUILD_SUCCESS) + return result; + + params->head_num_steps = 0; + params->tail_num_steps = 0; + for (i = 0; i < ARRAY_SIZE(dcn401_dc2_init_sequence); i++) { + result = dcn401_validate_initialization_step(params, + dcn401_dc2_init_sequence[i]); + if (result != BLS_BUILD_SUCCESS) + return result; + } + + sequence.steps = params->head_sequence; + sequence.num_steps = ¶ms->head_num_steps; + if (params->out_targets) + out_init = params->out_targets->DCN_DECL_INITIALIZATION; + if (out_init) { + out_init->dcmode_power_limits_present = false; + out_init->dmub_stop_fw_response = 0; + out_init->dmub_abi.fw_version = 0; + memset(&out_init->dmub_abi.feature_caps, 0, + sizeof(out_init->dmub_abi.feature_caps)); + } + + /* + * LEGACY/pmfw-msg: preserve the clock-manager entry points until + * PMFW Messenger can express the same calls, order, and output. + */ + for (i = 0; i < ARRAY_SIZE(dcn401_dc2_init_sequence); i++) { + result = dcn401_build_initialization_step(params, &sequence, + dcn401_dc2_init_sequence[i]); + if (result != BLS_BUILD_SUCCESS) + return result; + } + + if (out_init && + out_init->dmub_initialize_dcn_cmd.cmd_common.header.type) + return BLS_BUILD_SUCCESS; + + return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE; +} + +const struct bls_builder *dcn401_bls_builder_create( + enum bls_builder_name name) +{ + static const struct bls_builder initialization_builder = { + .name = DCN_DECL_INITIALIZATION, + .kind = BLS_BUILDER_DECLARATIVE, + .check_capability = dcn401_initialization_check_capability, + .build.declarative = dcn401_build_initialization, + }; + static const struct bls_builder legacy_initialization_builder = { + .name = DCN_DECL_INITIALIZATION_LEGACY, + .kind = BLS_BUILDER_DECLARATIVE, + .check_capability = dcn401_dc1_initialization_check_capability, + .build.declarative = dcn401_build_dc1_initialization, + }; + + switch (name) { + case DCN_DECL_INITIALIZATION: + return &initialization_builder; + case DCN_DECL_INITIALIZATION_LEGACY: + return &legacy_initialization_builder; + default: + return NULL; + } +} diff --git a/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder.h b/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder.h new file mode 100644 index 000000000000..fe70971cb8a5 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#pragma once + +#include "bls_builder/bls_builder.h" + +struct clk_mgr; +struct dccg; +struct dc_context; + +static inline bool bls_append(struct block_sequence_state *sequence, + enum block_sequence_func func, + const union block_sequence_params *params) +{ + struct block_sequence *entry; + + if (!sequence || !sequence->steps || !sequence->num_steps || + !params || *sequence->num_steps >= + DC2_BLS_MAX_STEPS) + return false; + + entry = &sequence->steps[*sequence->num_steps]; + entry->params = *params; + entry->func = func; + (*sequence->num_steps)++; + return true; +} + +enum bls_builder_result dcn401_build_clk_mgr_init( + struct clk_mgr *clk_mgr, struct block_sequence_state *sequence); +enum bls_builder_result dcn401_build_dc_mode_read( + struct clk_mgr *clk_mgr, bool *out_dcmode_power_limits_present, + struct block_sequence_state *sequence); +enum bls_builder_result dcn401_build_dccg_init( + struct dccg *dccg, struct block_sequence_state *sequence); +bool dcn401_add_dmub_cmd(struct block_sequence_state *sequence, + struct dc_context *ctx, union dmub_rb_cmd *cmd, + enum dm_dmub_wait_type wait_type, bool continue_on_error); +void dcn401_fill_query_feature_caps_cmd(union dmub_rb_cmd *cmd); diff --git a/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder_legacy.c b/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder_legacy.c new file mode 100644 index 000000000000..e13c16920a0c --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder_legacy.c @@ -0,0 +1,1071 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#include "dm_services.h" +#include "core_types.h" +#include "clk_mgr.h" +#include "dccg.h" +#include "resource.h" +#include "dc_dmub_srv.h" +#include "dmub_cmd.h" +#include "abm.h" +#include "audio.h" +#include "dchubbub.h" +#include "dio.h" +#include "link_encoder.h" +#include "panel_cntl.h" +#include "link_service.h" +#include "dc_bios_types.h" +#include "dce/dce_hwseq.h" +#include "hwss/hw_sequencer_private.h" +#include "dcn32/dcn32_resource.h" +#include "bls_builder/dcn401_init_builder.h" +#include "bls_builder/dcn401_init_builder_legacy.h" + +/* + * DC2_DC1_Wrapped: dcn401_init_hw as BLS entries, built one stage per + * call. A stage ends on a read whose value a later stage needs: Core + * executes the stage and retains its output in dc_state.hw_init_info, + * where the next build reads it. Same calls in the same order, and an + * entry is left out only where dcn401_init_hw skips the call. The build + * reads dc and hw_init_info, and writes only the sequence and the + * output target. + */ +static_assert(LEGACY_INIT_STAGE_POWER_DOWN_EDP1 - + LEGACY_INIT_STAGE_POWER_DOWN_EDP0 + 1 == MAX_NUM_EDP, + "one power-down-on-boot stage per eDP slot"); + +static bool dcn401_dc1_is_phy_link(const struct dc_link *link) +{ + return link->ep_type == DISPLAY_ENDPOINT_PHY; +} + +static bool dcn401_dc1_powers_down_pipes(struct dc *dc, + const struct bls_builder_legacy_hw_init_info *in) +{ + return in->s5.accelerated_mode || + !dc->config.seamless_boot_edp_requested; +} + +static bool dcn401_dc1_uses_accelerated_mode(struct dc *dc) +{ + return dc->hwss.enable_accelerated_mode && + dc->debug.disable_boot_optimizations; +} + +static bool dcn401_dc1_has_dmub(struct dc *dc) +{ + return dc->ctx->dmub_srv && dc->ctx->dmub_srv->dmub; +} + +static enum bls_builder_result dcn401_validate_dc1_links(struct dc *dc) +{ + struct dc_bios *dcb = dc->ctx->dc_bios; + unsigned int i; + + if (dc->link_count > MAX_LINKS) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + for (i = 0; i < dc->link_count; i++) { + const struct dc_link *link = dc->links[i]; + + if (!link) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + if (dcn401_dc1_is_phy_link(link) && (!link->link_enc || + !link->link_enc->funcs || + !link->link_enc->funcs->hw_init)) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + if (link->panel_cntl && (!link->panel_cntl->funcs || + !link->panel_cntl->funcs->hw_init)) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + if (link->force_to_use_aux && (!link->ctx || + !dcb->funcs->get_i2c_info)) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + } + + return BLS_BUILD_SUCCESS; +} + +static enum bls_builder_result dcn401_validate_dc1_power_down(struct dc *dc) +{ + if (!dcn401_dc1_uses_accelerated_mode(dc) && + !dc->hwseq->funcs.init_pipes) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + if (!dc->current_state || !dc->clk_mgr || !dc->clk_mgr->funcs || + !dc->clk_mgr->funcs->update_clocks || + !dc->clk_mgr->bw_params) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + + return BLS_BUILD_SUCCESS; +} + +static enum bls_builder_result dcn401_validate_dc1_hwseq(struct dc *dc) +{ + const struct hwseq_private_funcs *funcs = &dc->hwseq->funcs; + + if (dc->debug.enable_mem_low_power.bits.optc && + !funcs->init_odm_mem_power) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + if (dc->debug.enable_mem_low_power.bits.vga && + !funcs->power_down_vga_mem) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + if (!dc->debug.disable_clock_gate && !funcs->dcfclk_gating_control) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + if (!funcs->init_hpo_hw_control) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + + return BLS_BUILD_SUCCESS; +} + +static enum bls_builder_result dcn401_validate_dc1_initialization( + const struct bls_builder_declarative_params *params) +{ + const struct bls_builder_legacy_hw_init_info *in; + struct dc *dc = params->dc; + struct resource_pool *pool; + struct dc_bios *dcb; + unsigned int i; + + if (!dc || !dc->ctx || !dc->res_pool || !params->current_state || + !params->out_targets || + !params->out_targets->DCN_DECL_INITIALIZATION_LEGACY) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + in = ¶ms->current_state->hw_init_info; + if (in->next_stage < LEGACY_INIT_STAGE_CLOCKS || + in->next_stage > LEGACY_INIT_STAGE_COUNT) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + if (dc->ctx->dce_environment == DCE_ENV_VIRTUAL_HW) + return BLS_BUILD_SUCCESS; + + pool = dc->res_pool; + dcb = dc->ctx->dc_bios; + if (!dcb || !dcb->funcs || !dcb->funcs->is_accelerated_mode || + !pool->dccg || !pool->dccg->funcs || !pool->hubbub || + !pool->hubbub->funcs || !dc->hwseq || !dc->link_srv || + !dc->link_srv->blank_all_dp_displays) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + /* Later stages re-check only what a stage read-back decides. */ + if ((in->next_stage == LEGACY_INIT_STAGE_POWER_DOWN || + in->next_stage == LEGACY_INIT_STAGE_MIN_CLOCKS) && + dcn401_dc1_powers_down_pipes(dc, in)) + return dcn401_validate_dc1_power_down(dc); + if (in->next_stage != LEGACY_INIT_STAGE_CLOCKS) + return BLS_BUILD_SUCCESS; + + if (dcb->fw_info_valid && (!pool->dccg->funcs->get_dccg_ref_freq || + !pool->hubbub->funcs->get_dchub_ref_freq)) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + if (dcn401_validate_dc1_links(dc) != BLS_BUILD_SUCCESS) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + if (dcn401_validate_dc1_hwseq(dc) != BLS_BUILD_SUCCESS) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + for (i = 0; i < pool->audio_count; i++) + if (!pool->audios[i] || !pool->audios[i]->funcs || + !pool->audios[i]->funcs->hw_init) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + for (i = 0; i < pool->pipe_count; i++) + if (pool->multiple_abms[i] && pool->multiple_abms[i]->funcs && + !pool->multiple_abms[i]->funcs->abm_init) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + if (pool->dio && !pool->dio->funcs) + return BLS_BUILD_ERROR_RESOURCE_MAPPING; + /* Without seamless boot the pipes power down whatever the BIOS reads. */ + if (!dc->config.seamless_boot_edp_requested) + return dcn401_validate_dc1_power_down(dc); + + return BLS_BUILD_SUCCESS; +} + +static bool dcn401_add_hwseq_reg(struct block_sequence_state *sequence, + enum block_sequence_func func, struct dce_hwseq *hws, + bool enable) +{ + union block_sequence_params bls_params = {0}; + + bls_params.hwseq_reg_control_params.hws = hws; + bls_params.hwseq_reg_control_params.enable = enable; + return bls_append(sequence, func, &bls_params); +} + +static bool dcn401_add_dc_call(struct block_sequence_state *sequence, + enum block_sequence_func func, struct dc *dc, bool enable) +{ + union block_sequence_params bls_params = {0}; + + bls_params.dc_init_call_params.dc = dc; + bls_params.dc_init_call_params.enable = enable; + return bls_append(sequence, func, &bls_params); +} + +static bool dcn401_add_dccg_ref_freq(struct block_sequence_state *sequence, + struct dc *dc, struct bls_builder_output_legacy_init_stage1 *out) +{ + union block_sequence_params bls_params = {0}; + + bls_params.dccg_get_ref_freq_params.dccg = dc->res_pool->dccg; + bls_params.dccg_get_ref_freq_params.xtalin_khz = + dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; + bls_params.dccg_get_ref_freq_params.out_xtalin_khz = + &out->xtalin_clock_inKhz; + bls_params.dccg_get_ref_freq_params.out_dccg_ref_khz = + &out->dccg_ref_clock_inKhz; + return bls_append(sequence, DCCG_GET_REF_FREQ, &bls_params); +} + +/* Core published the DCCG reference clock after the previous stage. */ +static bool dcn401_add_dchub_ref_freq(struct block_sequence_state *sequence, + struct dc *dc, struct bls_builder_output_legacy_init_stage2 *out) +{ + union block_sequence_params bls_params = {0}; + struct resource_pool *pool = dc->res_pool; + + out->dchub_ref_clock_mhz_before = + pool->ref_clocks.dchub_ref_clock_inKhz / 1000; + bls_params.hubbub_get_dchub_ref_freq_params.hubbub = pool->hubbub; + bls_params.hubbub_get_dchub_ref_freq_params.dccg_ref_khz = + pool->ref_clocks.dccg_ref_clock_inKhz; + bls_params.hubbub_get_dchub_ref_freq_params.out_dchub_ref_khz = + &out->dchub_ref_clock_inKhz; + return bls_append(sequence, HUBBUB_GET_DCHUB_REF_FREQ, &bls_params); +} + +static bool dcn401_add_accelerated_mode_read( + struct block_sequence_state *sequence, struct dc *dc, + bool *out_accelerated_mode) +{ + union block_sequence_params bls_params = {0}; + + bls_params.bios_is_accelerated_mode_params.dcb = dc->ctx->dc_bios; + bls_params.bios_is_accelerated_mode_params.out_accelerated_mode = + out_accelerated_mode; + return bls_append(sequence, BIOS_IS_ACCELERATED_MODE, &bls_params); +} + +static bool dcn401_add_link_enc_hw_init( + struct block_sequence_state *sequence, + struct link_encoder *link_enc) +{ + union block_sequence_params bls_params = {0}; + + bls_params.link_enc_hw_init_params.link_enc = link_enc; + return bls_append(sequence, DIO_LINK_ENC_HW_INIT, &bls_params); +} + +/* Without is_dig_enabled, dcn401_init_hw takes the DIG as disabled. */ +static bool dcn401_add_dig_read(struct block_sequence_state *sequence, + struct link_encoder *link_enc, bool *out_dig_enabled) +{ + union block_sequence_params bls_params = {0}; + + if (!link_enc || !link_enc->funcs || !link_enc->funcs->is_dig_enabled) + return true; + bls_params.link_enc_is_dig_enabled_params.link_enc = link_enc; + bls_params.link_enc_is_dig_enabled_params.out_dig_enabled = + out_dig_enabled; + return bls_append(sequence, DIO_LINK_ENC_IS_DIG_ENABLED, &bls_params); +} + +static bool dcn401_add_fec_read(struct block_sequence_state *sequence, + struct link_encoder *link_enc, bool *out_fec_active) +{ + union block_sequence_params bls_params = {0}; + + bls_params.link_enc_fec_is_active_params.link_enc = link_enc; + bls_params.link_enc_fec_is_active_params.out_fec_active = + out_fec_active; + return bls_append(sequence, DIO_LINK_ENC_FEC_IS_ACTIVE, &bls_params); +} + +static bool dcn401_add_i2c_info_read(struct block_sequence_state *sequence, + struct dc *dc, const struct dc_link *link, + struct graphics_object_i2c_info *out_info, + enum bp_result *out_result) +{ + union block_sequence_params bls_params = {0}; + + bls_params.bios_get_i2c_info_params.dcb = dc->ctx->dc_bios; + bls_params.bios_get_i2c_info_params.link_id = link->link_id; + bls_params.bios_get_i2c_info_params.out_info = out_info; + bls_params.bios_get_i2c_info_params.out_result = out_result; + return bls_append(sequence, BIOS_GET_I2C_INFO, &bls_params); +} + +static bool dcn401_add_dentist_read(struct block_sequence_state *sequence, + struct clk_mgr *clk_mgr, int *out_dispclk_khz) +{ + union block_sequence_params bls_params = {0}; + + bls_params.clk_mgr_get_dispclk_from_dentist_params.clk_mgr = clk_mgr; + bls_params.clk_mgr_get_dispclk_from_dentist_params.out_dispclk_khz = + out_dispclk_khz; + return bls_append(sequence, CLK_MGR_GET_DISPCLK_FROM_DENTIST, + &bls_params); +} + +static bool dcn401_add_edp_control(struct block_sequence_state *sequence, + enum block_sequence_func func, struct dc_link *link, + bool enable) +{ + union block_sequence_params bls_params = {0}; + + bls_params.edp_control_params.link = link; + bls_params.edp_control_params.enable = enable; + return bls_append(sequence, func, &bls_params); +} + +static bool dcn401_add_self_refresh_control( + struct block_sequence_state *sequence, struct dc *dc) +{ + union block_sequence_params bls_params = {0}; + + bls_params.hubbub_allow_self_refresh_control_params.hubbub = + dc->res_pool->hubbub; + bls_params.hubbub_allow_self_refresh_control_params.allow = + !dc->debug.disable_stutter; + return bls_append(sequence, HUBBUB_ALLOW_SELF_REFRESH_CONTROL, + &bls_params); +} + +/* The clocks dcn401_initialize_min_clocks requests, from software state. */ +static bool dcn401_add_min_clocks(struct block_sequence_state *sequence, + struct dc *dc, const struct bls_builder_legacy_hw_init_info *in) +{ + union block_sequence_params bls_params = {0}; + struct clk_mgr_initialize_min_clocks_params *p = + &bls_params.clk_mgr_initialize_min_clocks_params; + struct clk_mgr *clk_mgr = dc->clk_mgr; + const struct clk_limit_table_entry *entry = + &clk_mgr->bw_params->clk_table.entries[0]; + + p->clk_mgr = clk_mgr; + p->context = dc->current_state; + p->dcfclk_deep_sleep_khz = DCN3_2_DCFCLK_DS_INIT_KHZ; + p->dcfclk_khz = entry->dcfclk_mhz * 1000; + p->socclk_khz = entry->socclk_mhz * 1000; + p->dramclk_khz = entry->memclk_mhz * 1000; + p->dppclk_khz = entry->dppclk_mhz * 1000; + if (dc->debug.disable_boot_optimizations) + p->dispclk_khz = entry->dispclk_mhz * 1000; + else if (clk_mgr->funcs->get_dispclk_from_dentist) + /* Keep the current DISPCLK so a lit display keeps its timing. */ + p->dispclk_khz = in->s6.dispclk_from_dentist_khz; + else + p->dispclk_khz = clk_mgr->boot_snapshot.dispclk; + p->ref_dtbclk_khz = entry->dtbclk_mhz * 1000; + p->fclk_p_state_change_support = true; + p->p_state_change_support = true; + return bls_append(sequence, LEGACY_CLK_MGR_INITIALIZE_MIN_CLOCKS, + &bls_params); +} + +static bool dcn401_add_audio_hw_init(struct block_sequence_state *sequence, + struct audio *audio) +{ + union block_sequence_params bls_params = {0}; + + bls_params.audio_hw_init_params.audio = audio; + return bls_append(sequence, AUDIO_HW_INIT, &bls_params); +} + +static bool dcn401_add_panel_cntl_hw_init( + struct block_sequence_state *sequence, + struct panel_cntl *panel_cntl, uint32_t *out_backlight, + uint32_t *out_user_level) +{ + union block_sequence_params bls_params = {0}; + + bls_params.panel_cntl_hw_init_params.panel_cntl = panel_cntl; + bls_params.panel_cntl_hw_init_params.out_backlight = out_backlight; + bls_params.panel_cntl_hw_init_params.out_user_level = out_user_level; + return bls_append(sequence, PANEL_CNTL_HW_INIT, &bls_params); +} + +static bool dcn401_add_ddc_open(struct block_sequence_state *sequence, + const struct dc_link *link, + const struct graphics_object_i2c_info *i2c_info) +{ + union block_sequence_params bls_params = {0}; + struct gpio_ddc_open_params *p = &bls_params.gpio_ddc_open_params; + + p->gpio_service = link->ctx->gpio_service; + p->clk_a_register_index = i2c_info->gpio_info.clk_a_register_index; + p->clk_a_mask = 1 << i2c_info->gpio_info.clk_a_shift; + p->hw_info.ddc_channel = i2c_info->i2c_line; + p->hw_info.hw_supported = i2c_info->i2c_hw_assist; + return bls_append(sequence, GPIO_DDC_OPEN, &bls_params); +} + +/* dc_dmub_srv_ihc_set_dig_hdcp_interrupt_dest(dmub_srv, eng_id, true) */ +static bool dcn401_add_hdcp_interrupt_dest( + struct block_sequence_state *sequence, struct dc *dc, + const struct dc_link *link, union dmub_rb_cmd *cmd) +{ + memset(cmd, 0, sizeof(*cmd)); + cmd->ihc.header.type = DMUB_CMD__IHC; + cmd->ihc.header.sub_type = DMUB_CMD__IHC_SET_DIG_HDCP_INTERRUPT_DEST; + cmd->ihc.header.payload_bytes = sizeof(cmd->ihc.data); + cmd->ihc.data.dig_id = (uint8_t)link->eng_id; + cmd->ihc.data.to_dmu = 1; + return dcn401_add_dmub_cmd(sequence, dc->ctx, cmd, + DM_DMUB_WAIT_TYPE_WAIT, true); +} + +static bool dcn401_add_abm_init(struct block_sequence_state *sequence, + struct abm *abm, const struct bls_builder_legacy_hw_init_info *in) +{ + union block_sequence_params bls_params = {0}; + + bls_params.abm_init_params.abm = abm; + bls_params.abm_init_params.backlight = in->s9.backlight; + bls_params.abm_init_params.user_level = in->s9.user_level; + return bls_append(sequence, ABM_INIT, &bls_params); +} + +static bool dcn401_add_dio_mem_power(struct block_sequence_state *sequence, + struct dio *dio) +{ + union block_sequence_params bls_params = {0}; + + bls_params.dio_set_mem_power_params.dio = dio; + bls_params.dio_set_mem_power_params.enable = false; + return bls_append(sequence, DIO_AFMT_SET_MEM_POWER, &bls_params); +} + +static bool dcn401_add_root_clock_gating( + struct block_sequence_state *sequence, struct dccg *dccg) +{ + union block_sequence_params bls_params = {0}; + + bls_params.dccg_set_root_clock_gating_params.dccg = dccg; + bls_params.dccg_set_root_clock_gating_params.allow = true; + return bls_append(sequence, DCCG_SET_ROOT_CLOCK_GATING, &bls_params); +} + +static bool dcn401_add_init_watermarks(struct block_sequence_state *sequence, + struct hubbub *hubbub) +{ + union block_sequence_params bls_params = {0}; + + bls_params.hubbub_init_watermarks_params.hubbub = hubbub; + return bls_append(sequence, HUBBUB_INIT_WATERMARKS, &bls_params); +} + +static bool dcn401_add_notify_wm_ranges( + struct block_sequence_state *sequence, struct clk_mgr *clk_mgr) +{ + union block_sequence_params bls_params = {0}; + + bls_params.clk_mgr_notify_wm_ranges_params.clk_mgr = clk_mgr; + return bls_append(sequence, LEGACY_CLK_MGR_NOTIFY_WM_RANGES, + &bls_params); +} + +static bool dcn401_add_force_pstate(struct block_sequence_state *sequence, + struct hubbub *hubbub) +{ + union block_sequence_params bls_params = {0}; + + bls_params.hubbub_force_pstate_change_control_params.hubbub = hubbub; + bls_params.hubbub_force_pstate_change_control_params.enable = false; + bls_params.hubbub_force_pstate_change_control_params.allow = false; + return bls_append(sequence, HUBBUB_FORCE_PSTATE_CHANGE_CONTROL, + &bls_params); +} + +static bool dcn401_add_init_crb(struct block_sequence_state *sequence, + struct hubbub *hubbub) +{ + union block_sequence_params bls_params = {0}; + + bls_params.hubbub_init_crb_params.hubbub = hubbub; + return bls_append(sequence, HUBBUB_INIT_CRB, &bls_params); +} + +static bool dcn401_add_request_limit(struct block_sequence_state *sequence, + struct dc *dc) +{ + union block_sequence_params bls_params = {0}; + + bls_params.hubbub_set_request_limit_params.hubbub = + dc->res_pool->hubbub; + bls_params.hubbub_set_request_limit_params.num_chans = + dc->ctx->dc_bios->vram_info.num_chans; + bls_params.hubbub_set_request_limit_params.words_per_umc = + dc->config.sdpif_request_limit_words_per_umc; + return bls_append(sequence, HUBBUB_SET_REQUEST_LIMIT, &bls_params); +} + +/* + * dc_dmub_srv_query_caps_cmd. The reply stays in the command; Core + * interprets it. The caps apply whether or not the query is sent. + */ +static bool dcn401_add_query_caps(struct block_sequence_state *sequence, + struct dc *dc, struct bls_builder_output_legacy_init_stage11 *out) +{ + struct dc_dmub_srv *dc_dmub_srv = dc->ctx->dmub_srv; + + if (!dc_dmub_srv) + return true; + if (!dc_dmub_srv->dmub) + return false; + out->dmub_caps_read = true; + dcn401_fill_query_feature_caps_cmd(&out->dmub_query_feature_caps_cmd); + out->dmub_caps_query_sent = true; + return dcn401_add_dmub_cmd(sequence, dc->ctx, + &out->dmub_query_feature_caps_cmd, + DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY, true); +} + +/* dc_dmub_srv_notify_fw_dc_power_state(dmub_srv, D0) */ +static bool dcn401_add_notify_power_state( + struct block_sequence_state *sequence, struct dc *dc, + union dmub_rb_cmd *cmd) +{ + if (!dcn401_dc1_has_dmub(dc)) + return true; + memset(cmd, 0, sizeof(*cmd)); + cmd->idle_opt_set_dc_power_state.header.type = DMUB_CMD__IDLE_OPT; + cmd->idle_opt_set_dc_power_state.header.sub_type = + DMUB_CMD__IDLE_OPT_SET_DC_POWER_STATE; + cmd->idle_opt_set_dc_power_state.header.payload_bytes = + sizeof(cmd->idle_opt_set_dc_power_state) - + sizeof(cmd->idle_opt_set_dc_power_state.header); + cmd->idle_opt_set_dc_power_state.data.power_state = + DMUB_IDLE_OPT_DC_POWER_STATE_D0; + return dcn401_add_dmub_cmd(sequence, dc->ctx, cmd, + DM_DMUB_WAIT_TYPE_WAIT, true); +} + +/* + * Power down on boot, eDP slot by slot. A slot reads its eDP's DIG only + * after the previous slot acted, since power_down can change it. With + * no eDP, slot 0 reads every PHY link and powers down once. + */ +static bool dcn401_add_boot_dig_read(struct dc *dc, + bool *out_edp_dig_enabled, bool *out_boot_dig_enabled, + struct block_sequence_state *sequence, unsigned int slot) +{ + struct dc_link *edp_links[MAX_NUM_EDP]; + unsigned int edp_num; + unsigned int i; + + if (dc->config.seamless_boot_edp_requested) + return true; + dc_get_edp_links(dc, edp_links, &edp_num); + if (edp_num) + return slot >= edp_num || dcn401_add_dig_read(sequence, + edp_links[slot]->link_enc, out_edp_dig_enabled); + if (slot) + return true; + for (i = 0; i < dc->link_count; i++) + if (dcn401_dc1_is_phy_link(dc->links[i]) && + !dcn401_add_dig_read(sequence, + dc->links[i]->link_enc, + &out_boot_dig_enabled[i])) + return false; + return true; +} + +static bool dcn401_add_boot_power_down(struct dc *dc, + bool edp_dig_enabled, const bool *boot_dig_enabled, + struct block_sequence_state *sequence, unsigned int slot) +{ + struct dc_link *edp_links[MAX_NUM_EDP]; + struct dc_link *link; + unsigned int edp_num; + unsigned int i; + + if (dc->config.seamless_boot_edp_requested || + !dc->hwseq->funcs.power_down) + return true; + dc_get_edp_links(dc, edp_links, &edp_num); + if (edp_num) { + if (slot >= edp_num || !edp_dig_enabled || + !dc->hwss.edp_backlight_control || + !dc->hwss.edp_power_control) + return true; + link = edp_links[slot]; + return dcn401_add_edp_control(sequence, EDP_BACKLIGHT_CONTROL, + link, false) && + dcn401_add_dc_call(sequence, HWSEQ_POWER_DOWN, dc, + false) && + dcn401_add_edp_control(sequence, EDP_POWER_CONTROL, + link, false); + } + if (slot) + return true; + for (i = 0; i < dc->link_count; i++) + if (boot_dig_enabled[i]) + return dcn401_add_dc_call(sequence, HWSEQ_POWER_DOWN, dc, + false); + return true; +} + +/* + * dcn401_init_hw call order, cut at each read a later stage depends on. + * funcs append through dcn401_dc1_add_step: per pipe for the looped + * calls, and nothing where dcn401_init_hw skips the call. link_funcs + * follow step-major: each link_func expands for every link before the + * next link_func. The BLC trace logs only enc401_hw_init per link, and + * the panel, DDC and HDCP calls program separate blocks. In funcs, + * DIO_LINK_ENC_IS_DIG_ENABLED and HWSEQ_POWER_DOWN are the power down + * on boot read and act of the stage's eDP slot, and DMUB_SEND_DMCUB_CMD + * is the stage's DMUB command. + */ +struct dcn401_dc1_stage_list { + const enum block_sequence_func *funcs; + unsigned int num_funcs; + const enum block_sequence_func *link_funcs; + unsigned int num_link_funcs; +}; + +static const enum block_sequence_func dcn401_dc1_clocks_stage[] = { + LEGACY_CLK_MGR_INIT_CLOCKS, + LEGACY_CLK_MGR_IS_DC_MODE_PRESENT, + DCCG_INITIALIZE_CLOCKS, + OPTC_SET_ODM_MEM_POWER, + MMHUBBUB_SET_MEM_POWER, + DCCG_GET_REF_FREQ, +}; + +static const enum block_sequence_func dcn401_dc1_dchub_ref_stage[] = { + HUBBUB_GET_DCHUB_REF_FREQ, +}; + +static const enum block_sequence_func dcn401_dc1_link_enc_loop[] = { + DIO_LINK_ENC_HW_INIT, + DIO_LINK_ENC_IS_DIG_ENABLED, + BIOS_GET_I2C_INFO, +}; + +static const enum block_sequence_func dcn401_dc1_fec_loop[] = { + DIO_LINK_ENC_FEC_IS_ACTIVE, +}; + +static const enum block_sequence_func dcn401_dc1_blank_stage[] = { + PG_SET_PLANE_POWER_GATING, + LINK_BLANK_ALL_DP_DISPLAYS, + BIOS_IS_ACCELERATED_MODE, +}; + +static const enum block_sequence_func dcn401_dc1_power_down_stage[] = { + HWSS_ENABLE_ACCELERATED_MODE, + HWSEQ_INIT_PIPES, + HUBBUB_ALLOW_SELF_REFRESH_CONTROL, + CLK_MGR_GET_DISPCLK_FROM_DENTIST, +}; + +static const enum block_sequence_func dcn401_dc1_min_clocks_stage[] = { + LEGACY_CLK_MGR_INITIALIZE_MIN_CLOCKS, + DMUB_SET_IDLE_OPTIMIZATION, + DIO_LINK_ENC_IS_DIG_ENABLED, +}; + +static const enum block_sequence_func dcn401_dc1_power_down_edp0_stage[] = { + HWSEQ_POWER_DOWN, + DIO_LINK_ENC_IS_DIG_ENABLED, +}; + +static const enum block_sequence_func dcn401_dc1_power_down_edp1_stage[] = { + HWSEQ_POWER_DOWN, + AUDIO_HW_INIT, +}; + +static const enum block_sequence_func dcn401_dc1_panel_loop[] = { + PANEL_CNTL_HW_INIT, + GPIO_DDC_OPEN, + DMUB_SEND_DMCUB_CMD, +}; + +static const enum block_sequence_func dcn401_dc1_gating_stage[] = { + ABM_INIT, + DIO_AFMT_SET_MEM_POWER, + DCCG_SET_ROOT_CLOCK_GATING, + DCCG_SET_DCFCLK_GATING, + HPO_SET_HW_CONTROL, + BIOS_IS_ACCELERATED_MODE, +}; + +static const enum block_sequence_func dcn401_dc1_hubbub_stage[] = { + HUBBUB_INIT_WATERMARKS, + LEGACY_CLK_MGR_NOTIFY_WM_RANGES, + HUBBUB_FORCE_PSTATE_CHANGE_CONTROL, + HUBBUB_INIT_CRB, + HUBBUB_SET_REQUEST_LIMIT, + DMUB_SEND_DMCUB_CMD, +}; + +static const enum block_sequence_func dcn401_dc1_power_state_stage[] = { + DMUB_SEND_DMCUB_CMD, +}; + +#define DCN401_DC1_STAGE(list) { list, ARRAY_SIZE(list), NULL, 0 } +#define DCN401_DC1_LINK_STAGE(loop) { NULL, 0, loop, ARRAY_SIZE(loop) } +#define DCN401_DC1_LOOP_STAGE(list, loop) \ + { list, ARRAY_SIZE(list), loop, ARRAY_SIZE(loop) } + +static const struct dcn401_dc1_stage_list + dcn401_dc1_stages[LEGACY_INIT_STAGE_COUNT + 1] = { + [LEGACY_INIT_STAGE_CLOCKS] = DCN401_DC1_STAGE(dcn401_dc1_clocks_stage), + [LEGACY_INIT_STAGE_DCHUB_REF] = + DCN401_DC1_STAGE(dcn401_dc1_dchub_ref_stage), + [LEGACY_INIT_STAGE_LINK_ENC] = + DCN401_DC1_LINK_STAGE(dcn401_dc1_link_enc_loop), + [LEGACY_INIT_STAGE_FEC] = DCN401_DC1_LINK_STAGE(dcn401_dc1_fec_loop), + [LEGACY_INIT_STAGE_BLANK] = DCN401_DC1_STAGE(dcn401_dc1_blank_stage), + [LEGACY_INIT_STAGE_POWER_DOWN] = + DCN401_DC1_STAGE(dcn401_dc1_power_down_stage), + [LEGACY_INIT_STAGE_MIN_CLOCKS] = + DCN401_DC1_STAGE(dcn401_dc1_min_clocks_stage), + [LEGACY_INIT_STAGE_POWER_DOWN_EDP0] = + DCN401_DC1_STAGE(dcn401_dc1_power_down_edp0_stage), + [LEGACY_INIT_STAGE_POWER_DOWN_EDP1] = + DCN401_DC1_LOOP_STAGE(dcn401_dc1_power_down_edp1_stage, + dcn401_dc1_panel_loop), + [LEGACY_INIT_STAGE_GATING] = DCN401_DC1_STAGE(dcn401_dc1_gating_stage), + [LEGACY_INIT_STAGE_HUBBUB] = DCN401_DC1_STAGE(dcn401_dc1_hubbub_stage), + [LEGACY_INIT_STAGE_POWER_STATE] = + DCN401_DC1_STAGE(dcn401_dc1_power_state_stage), +}; + +static bool dcn401_dc1_add_link_step(struct dc *dc, + const struct bls_builder_legacy_hw_init_info *in, + struct bls_builder_legacy_hw_init_info *out, + struct block_sequence_state *sequence, + enum block_sequence_func func, unsigned int i) +{ + const struct dc_link *link = dc->links[i]; + + switch (func) { + case DIO_LINK_ENC_HW_INIT: + return !dcn401_dc1_is_phy_link(link) || + dcn401_add_link_enc_hw_init(sequence, + link->link_enc); + case DIO_LINK_ENC_IS_DIG_ENABLED: + return !dcn401_dc1_is_phy_link(link) || + dcn401_add_dig_read(sequence, link->link_enc, + &out->s3.link_dig_enabled[i]); + case BIOS_GET_I2C_INFO: + return !link->force_to_use_aux || + dcn401_add_i2c_info_read(sequence, dc, link, + &out->s3.link_i2c_info[i], + &out->s3.link_i2c_result[i]); + case DIO_LINK_ENC_FEC_IS_ACTIVE: + return !dcn401_dc1_is_phy_link(link) || + !in->s3.link_dig_enabled[i] || + !link->link_enc->funcs->fec_is_active || + dcn401_add_fec_read(sequence, link->link_enc, + &out->s4.link_fec_active[i]); + case PANEL_CNTL_HW_INIT: + return !link->panel_cntl || + dcn401_add_panel_cntl_hw_init(sequence, + link->panel_cntl, &out->s9.backlight, + &out->s9.user_level); + case GPIO_DDC_OPEN: + return !link->force_to_use_aux || + in->s3.link_i2c_result[i] != BP_RESULT_OK || + dcn401_add_ddc_open(sequence, link, + &in->s3.link_i2c_info[i]); + case DMUB_SEND_DMCUB_CMD: + /* Sent whatever the I2C info read returned. */ + return !link->force_to_use_aux || !dcn401_dc1_has_dmub(dc) || + dcn401_add_hdcp_interrupt_dest(sequence, dc, link, + &out->s9.dmub_ihc_cmd[i]); + default: + return false; + } +} + +static bool dcn401_dc1_add_step(struct dc *dc, + const struct bls_builder_legacy_hw_init_info *in, + struct bls_builder_legacy_hw_init_info *out, + struct block_sequence_state *sequence, + enum block_sequence_func func) +{ + struct resource_pool *pool = dc->res_pool; + struct clk_mgr *clk_mgr = dc->clk_mgr; + struct hubbub *hubbub = pool->hubbub; + bool has_init_clocks = clk_mgr && clk_mgr->funcs && + clk_mgr->funcs->init_clocks; + unsigned int i; + + switch (func) { + case LEGACY_CLK_MGR_INIT_CLOCKS: + return !has_init_clocks || + dcn401_build_clk_mgr_init(clk_mgr, sequence) == + BLS_BUILD_SUCCESS; + case LEGACY_CLK_MGR_IS_DC_MODE_PRESENT: + /* Without the callback the limits stay not present. */ + return !has_init_clocks || + !clk_mgr->funcs->is_dc_mode_present || + dcn401_build_dc_mode_read(clk_mgr, + &out->s1.dcmode_power_limits_present, + sequence) == BLS_BUILD_SUCCESS; + case DCCG_INITIALIZE_CLOCKS: + return !pool->dccg->funcs->dccg_init || + dcn401_build_dccg_init(pool->dccg, sequence) == + BLS_BUILD_SUCCESS; + case OPTC_SET_ODM_MEM_POWER: + return !dc->debug.enable_mem_low_power.bits.optc || + dcn401_add_hwseq_reg(sequence, func, dc->hwseq, + true); + case MMHUBBUB_SET_MEM_POWER: + return !dc->debug.enable_mem_low_power.bits.vga || + dcn401_add_hwseq_reg(sequence, func, dc->hwseq, + true); + case DCCG_GET_REF_FREQ: + if (!dc->ctx->dc_bios->fw_info_valid) { + ASSERT_CRITICAL(false); + return true; + } + return dcn401_add_dccg_ref_freq(sequence, dc, &out->s1); + case HUBBUB_GET_DCHUB_REF_FREQ: + return !dc->ctx->dc_bios->fw_info_valid || + dcn401_add_dchub_ref_freq(sequence, dc, &out->s2); + case PG_SET_PLANE_POWER_GATING: + return !dc->hwseq->funcs.enable_power_gating_plane || + dcn401_add_hwseq_reg(sequence, func, dc->hwseq, + true); + case LINK_BLANK_ALL_DP_DISPLAYS: + return dcn401_add_dc_call(sequence, func, dc, false); + case BIOS_IS_ACCELERATED_MODE: + return dcn401_add_accelerated_mode_read(sequence, dc, + in->next_stage == LEGACY_INIT_STAGE_BLANK ? + &out->s5.accelerated_mode : + &out->s10.accelerated_mode); + case HWSS_ENABLE_ACCELERATED_MODE: + return !dcn401_dc1_powers_down_pipes(dc, in) || + !dcn401_dc1_uses_accelerated_mode(dc) || + dcn401_add_dc_call(sequence, func, dc, false); + case HWSEQ_INIT_PIPES: + return !dcn401_dc1_powers_down_pipes(dc, in) || + dcn401_dc1_uses_accelerated_mode(dc) || + dcn401_add_dc_call(sequence, func, dc, false); + case HUBBUB_ALLOW_SELF_REFRESH_CONTROL: + return !dcn401_dc1_powers_down_pipes(dc, in) || + !hubbub->funcs->allow_self_refresh_control || + dcn401_add_self_refresh_control(sequence, dc); + case CLK_MGR_GET_DISPCLK_FROM_DENTIST: + return !dcn401_dc1_powers_down_pipes(dc, in) || + dc->debug.disable_boot_optimizations || + !clk_mgr || !clk_mgr->funcs || + !clk_mgr->funcs->get_dispclk_from_dentist || + dcn401_add_dentist_read(sequence, clk_mgr, + &out->s6.dispclk_from_dentist_khz); + case LEGACY_CLK_MGR_INITIALIZE_MIN_CLOCKS: + return !dcn401_dc1_powers_down_pipes(dc, in) || + dcn401_add_min_clocks(sequence, dc, in); + case DMUB_SET_IDLE_OPTIMIZATION: + /* + * Off, then on: in BOCO / BOMACO the hardware can be reset + * while software still has idle optimizations allowed. + */ + return !dcn401_dc1_powers_down_pipes(dc, in) || + (dcn401_add_dc_call(sequence, func, dc, false) && + dcn401_add_dc_call(sequence, func, dc, true)); + case DIO_LINK_ENC_IS_DIG_ENABLED: + if (in->next_stage == LEGACY_INIT_STAGE_MIN_CLOCKS) + return dcn401_add_boot_dig_read(dc, + &out->s7.edp_dig_enabled, + out->s7.boot_dig_enabled, sequence, 0); + return dcn401_add_boot_dig_read(dc, &out->s8.edp_dig_enabled, + NULL, sequence, 1); + case HWSEQ_POWER_DOWN: + if (in->next_stage == LEGACY_INIT_STAGE_POWER_DOWN_EDP0) + return dcn401_add_boot_power_down(dc, + in->s7.edp_dig_enabled, + in->s7.boot_dig_enabled, sequence, 0); + return dcn401_add_boot_power_down(dc, in->s8.edp_dig_enabled, + NULL, sequence, 1); + case AUDIO_HW_INIT: + for (i = 0; i < pool->audio_count; i++) + if (!dcn401_add_audio_hw_init(sequence, pool->audios[i])) + return false; + return true; + case ABM_INIT: + for (i = 0; i < pool->pipe_count; i++) { + struct abm *abm = pool->multiple_abms[i]; + + if (abm && abm->funcs && + !dcn401_add_abm_init(sequence, abm, in)) + return false; + } + return true; + case DIO_AFMT_SET_MEM_POWER: + return !pool->dio || !pool->dio->funcs->mem_pwr_ctrl || + dcn401_add_dio_mem_power(sequence, pool->dio); + case DCCG_SET_ROOT_CLOCK_GATING: + return dc->debug.disable_clock_gate || + !pool->dccg->funcs->allow_clock_gating || + dcn401_add_root_clock_gating(sequence, pool->dccg); + case DCCG_SET_DCFCLK_GATING: + return dc->debug.disable_clock_gate || + dcn401_add_hwseq_reg(sequence, func, dc->hwseq, + true); + case HPO_SET_HW_CONTROL: + return dcn401_add_hwseq_reg(sequence, func, dc->hwseq, true); + case HUBBUB_INIT_WATERMARKS: + return in->s10.accelerated_mode || + !hubbub->funcs->init_watermarks || + dcn401_add_init_watermarks(sequence, hubbub); + case LEGACY_CLK_MGR_NOTIFY_WM_RANGES: + return !clk_mgr || !clk_mgr->funcs || + !clk_mgr->funcs->notify_wm_ranges || + dcn401_add_notify_wm_ranges(sequence, clk_mgr); + case HUBBUB_FORCE_PSTATE_CHANGE_CONTROL: + return !hubbub->funcs->force_pstate_change_control || + dcn401_add_force_pstate(sequence, hubbub); + case HUBBUB_INIT_CRB: + return !hubbub->funcs->init_crb || + dcn401_add_init_crb(sequence, hubbub); + case HUBBUB_SET_REQUEST_LIMIT: + return !hubbub->funcs->set_request_limit || + dc->config.sdpif_request_limit_words_per_umc == 0 || + dcn401_add_request_limit(sequence, dc); + case DMUB_SEND_DMCUB_CMD: + if (in->next_stage == LEGACY_INIT_STAGE_POWER_STATE) + return dcn401_add_notify_power_state(sequence, dc, + &out->s12.dmub_power_state_cmd); + return dcn401_add_query_caps(sequence, dc, &out->s11); + default: + return false; + } +} + +static bool dcn401_dc1_add_stage(struct dc *dc, + const struct bls_builder_legacy_hw_init_info *in, + struct bls_builder_legacy_hw_init_info *out, + struct block_sequence_state *sequence) +{ + const struct dcn401_dc1_stage_list *stage = + &dcn401_dc1_stages[in->next_stage]; + unsigned int i, j; + + for (i = 0; i < stage->num_funcs; i++) + if (!dcn401_dc1_add_step(dc, in, out, sequence, + stage->funcs[i])) + return false; + if (!stage->num_link_funcs) + return true; + for (j = 0; j < stage->num_link_funcs; j++) + for (i = 0; i < dc->link_count; i++) + if (!dcn401_dc1_add_link_step(dc, in, out, sequence, + stage->link_funcs[j], i)) + return false; + + return true; +} + +/* + * Seed the stage output with the values its reads leave in place when + * they are skipped: the current reference clocks, the default + * backlight and no I2C info. + */ +static void dcn401_dc1_seed_stage_output(struct dc *dc, + struct bls_builder_legacy_hw_init_info *out, unsigned int stage) +{ + const struct resource_pool *pool = dc->res_pool; + unsigned int i; + + switch (stage) { + case LEGACY_INIT_STAGE_CLOCKS: + memset(&out->s1, 0, sizeof(out->s1)); + out->s1.xtalin_clock_inKhz = pool->ref_clocks.xtalin_clock_inKhz; + out->s1.dccg_ref_clock_inKhz = + pool->ref_clocks.dccg_ref_clock_inKhz; + break; + case LEGACY_INIT_STAGE_DCHUB_REF: + memset(&out->s2, 0, sizeof(out->s2)); + out->s2.dchub_ref_clock_inKhz = + pool->ref_clocks.dchub_ref_clock_inKhz; + break; + case LEGACY_INIT_STAGE_LINK_ENC: + memset(&out->s3, 0, sizeof(out->s3)); + for (i = 0; i < MAX_LINKS; i++) + out->s3.link_i2c_result[i] = BP_RESULT_NORECORD; + break; + case LEGACY_INIT_STAGE_FEC: + memset(&out->s4, 0, sizeof(out->s4)); + break; + case LEGACY_INIT_STAGE_BLANK: + memset(&out->s5, 0, sizeof(out->s5)); + break; + case LEGACY_INIT_STAGE_POWER_DOWN: + memset(&out->s6, 0, sizeof(out->s6)); + break; + case LEGACY_INIT_STAGE_MIN_CLOCKS: + memset(&out->s7, 0, sizeof(out->s7)); + break; + case LEGACY_INIT_STAGE_POWER_DOWN_EDP0: + memset(&out->s8, 0, sizeof(out->s8)); + break; + case LEGACY_INIT_STAGE_POWER_DOWN_EDP1: + memset(&out->s9, 0, sizeof(out->s9)); + out->s9.backlight = MAX_BACKLIGHT_LEVEL; + out->s9.user_level = MAX_BACKLIGHT_LEVEL; + break; + case LEGACY_INIT_STAGE_GATING: + memset(&out->s10, 0, sizeof(out->s10)); + break; + case LEGACY_INIT_STAGE_HUBBUB: + memset(&out->s11, 0, sizeof(out->s11)); + break; + case LEGACY_INIT_STAGE_POWER_STATE: + memset(&out->s12, 0, sizeof(out->s12)); + break; + } +} + +enum bls_builder_result dcn401_build_dc1_initialization( + struct bls_builder_declarative_params *params) +{ + const struct bls_builder_legacy_hw_init_info *in; + struct bls_builder_legacy_hw_init_info *out; + struct block_sequence_state sequence; + enum bls_builder_result result; + struct dc *dc; + + if (!params) + return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE; + params->head_num_steps = 0; + params->tail_num_steps = 0; + result = dcn401_validate_dc1_initialization(params); + if (result != BLS_BUILD_SUCCESS) + return result; + + dc = params->dc; + in = ¶ms->current_state->hw_init_info; + out = params->out_targets->DCN_DECL_INITIALIZATION_LEGACY; + sequence.steps = params->head_sequence; + sequence.num_steps = ¶ms->head_num_steps; + + /* Virtual hardware only notifies DMUB of the power state. */ + if (dc->ctx->dce_environment == DCE_ENV_VIRTUAL_HW) { + dcn401_dc1_seed_stage_output(dc, out, + LEGACY_INIT_STAGE_POWER_STATE); + if (!dcn401_add_notify_power_state(&sequence, dc, + &out->s12.dmub_power_state_cmd)) + return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE; + out->next_stage = LEGACY_INIT_STAGE_COUNT + 1; + out->init_done = true; + return BLS_BUILD_SUCCESS; + } + + dcn401_dc1_seed_stage_output(dc, out, in->next_stage); + if (!dcn401_dc1_add_stage(dc, in, out, &sequence)) { + params->head_num_steps = 0; + return BLS_BUILD_ERROR_UNSUPPORTED_STATE_UPDATE; + } + out->next_stage = in->next_stage + 1; + out->init_done = in->next_stage == LEGACY_INIT_STAGE_COUNT; + + return BLS_BUILD_SUCCESS; +} + +bool dcn401_dc1_initialization_check_capability( + const struct bls_builder_check_capability_params *params) +{ + return params && params->dc && params->dc->ctx && + params->dc->res_pool; +} diff --git a/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder_legacy.h b/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder_legacy.h new file mode 100644 index 000000000000..71a1cdb46527 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/bls_builder/dcn401_init_builder_legacy.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#pragma once + +#include "bls_builder/bls_builder.h" + +/* + * DC2_DC1_Wrapped: build stage params->current_state->hw_init_info + * .next_stage of dcn401_init_hw into the head sequence. The stage + * outputs land in out_targets->DCN_DECL_INITIALIZATION_LEGACY. + */ +enum bls_builder_result dcn401_build_dc1_initialization( + struct bls_builder_declarative_params *params); +bool dcn401_dc1_initialization_check_capability( + const struct bls_builder_check_capability_params *params); diff --git a/drivers/gpu/drm/amd/display/dc/bls_builder/dmub_abi.h b/drivers/gpu/drm/amd/display/dc/bls_builder/dmub_abi.h new file mode 100644 index 000000000000..1a51af6da94b --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/bls_builder/dmub_abi.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#pragma once + +#include "dmub_cmd.h" + +struct dmub_abi { + unsigned int fw_version; + struct dmub_feature_caps feature_caps; +}; diff --git a/drivers/gpu/drm/amd/display/dc/bls_executor/bls_executor.c b/drivers/gpu/drm/amd/display/dc/bls_executor/bls_executor.c new file mode 100644 index 000000000000..7600954c3478 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/bls_executor/bls_executor.c @@ -0,0 +1,703 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright 2026 Advanced Micro Devices, Inc. + * + */ + +#include "dm_services.h" +#include "clk_mgr.h" +#include "dccg.h" +#include "core_types.h" +#include "dc_dmub_srv.h" +#include "dmub_cmd.h" +#include "abm.h" +#include "audio.h" +#include "dchubbub.h" +#include "dio.h" +#include "link_encoder.h" +#include "panel_cntl.h" +#include "link_service.h" +#include "dc_bios_types.h" +#include "gpio_service_interface.h" +#include "hwss/hw_sequencer_private.h" +#include "bls_executor/bls_executor.h" +#include "dmub_messenger/dmub_messenger.h" + +static noinline_for_stack bool dc2_bls_step_supported(const struct dc2 *dc2, + const struct block_sequence *step) +{ + const struct dc *dc = dc2 ? &dc2->dc : NULL; + struct dmub_srv *dmub; + struct clk_mgr *clk_mgr; + struct dccg *dccg; + struct dc_context *ctx; + + switch (step->func) { + case LEGACY_CLK_MGR_INIT_CLOCKS: + clk_mgr = + step->params.legacy_clk_mgr_init_clocks_params.clk_mgr; + return clk_mgr && clk_mgr->funcs && + clk_mgr->funcs->init_clocks; + case LEGACY_CLK_MGR_IS_DC_MODE_PRESENT: + clk_mgr = step->params + .legacy_clk_mgr_is_dc_mode_present_params.clk_mgr; + return clk_mgr && clk_mgr->funcs && + clk_mgr->funcs->is_dc_mode_present && + step->params + .legacy_clk_mgr_is_dc_mode_present_params + .out_dcmode_power_limits_present; + case DCCG_INITIALIZE_CLOCKS: + dccg = step->params.dccg_initialize_clocks_params.dccg; + return dccg && dccg->funcs && dccg->funcs->dccg_init; + case DMUB_SEND_DMCUB_CMD: + ctx = step->params.send_dmcub_cmd_params.ctx; + if (!ctx || !ctx->dmub_srv || !ctx->dmub_srv->dmub || + !step->params.send_dmcub_cmd_params.cmd || + (ctx->dmub_srv->idle_allowed && !ctx->dc)) + return false; + return true; + case DMUB_GPINT_SEND_AND_WAIT: + case DMUB_HALT_FW: + if (!dc || !dc->ctx || !dc->ctx->dmub_srv || + !dc->ctx->dmub_srv->dmub || + (dc->ctx->dmub_srv->idle_allowed && + !dc->ctx->dc)) + return false; + dmub = dc->ctx->dmub_srv->dmub; + return dmub->sw_init && dmub->hw_funcs.set_gpint && + dmub->hw_funcs.is_gpint_acked && + dmub->hw_funcs.get_gpint_response && + step->params.dmub_gpint_params.response; + case PSP_RELOAD_DMUB_FW: { + const struct dmub_srv_hw_params *hw_params = + step->params.psp_reload_dmub_fw_params.hw_params; + + return step->params.psp_reload_dmub_fw_params.dmub && + hw_params && hw_params->fb_info && + hw_params->fb_info->num_fb >= DMUB_WINDOW_TOTAL; + } + case DMUB_INITIALIZE_DCN: + ctx = step->params.send_dmcub_cmd_params.ctx; + if (!ctx || !ctx->dmub_srv || !ctx->dmub_srv->dmub || + !step->params.send_dmcub_cmd_params.cmd || + !step->params.send_dmcub_cmd_params.cmd->cmd_common + .header.type || + (ctx->dmub_srv->idle_allowed && !ctx->dc)) + return false; + return true; + case OPTC_SET_ODM_MEM_POWER: { + struct dce_hwseq *hws = step->params.hwseq_reg_control_params.hws; + + return hws && hws->funcs.init_odm_mem_power; + } + case MMHUBBUB_SET_MEM_POWER: { + struct dce_hwseq *hws = step->params.hwseq_reg_control_params.hws; + + return hws && hws->funcs.power_down_vga_mem; + } + case DCCG_SET_DCFCLK_GATING: { + struct dce_hwseq *hws = step->params.hwseq_reg_control_params.hws; + + return hws && hws->funcs.dcfclk_gating_control; + } + case HPO_SET_HW_CONTROL: { + struct dce_hwseq *hws = step->params.hwseq_reg_control_params.hws; + + return hws && hws->funcs.init_hpo_hw_control; + } + case PG_SET_PLANE_POWER_GATING: { + struct dce_hwseq *hws = step->params.hwseq_reg_control_params.hws; + + return hws && hws->funcs.enable_power_gating_plane; + } + case DCCG_GET_REF_FREQ: { + const struct dccg_get_ref_freq_params *p = + &step->params.dccg_get_ref_freq_params; + + return p->dccg && p->dccg->funcs && + p->dccg->funcs->get_dccg_ref_freq && + p->out_xtalin_khz && p->out_dccg_ref_khz; + } + case HUBBUB_GET_DCHUB_REF_FREQ: { + const struct hubbub_get_dchub_ref_freq_params *p = + &step->params.hubbub_get_dchub_ref_freq_params; + + return p->hubbub && p->hubbub->funcs && + p->hubbub->funcs->get_dchub_ref_freq && + p->out_dchub_ref_khz; + } + case DIO_LINK_ENC_HW_INIT: { + struct link_encoder *enc = + step->params.link_enc_hw_init_params.link_enc; + + return enc && enc->funcs && enc->funcs->hw_init; + } + case DIO_LINK_ENC_IS_DIG_ENABLED: { + const struct link_enc_is_dig_enabled_params *p = + &step->params.link_enc_is_dig_enabled_params; + + return p->link_enc && p->link_enc->funcs && + p->link_enc->funcs->is_dig_enabled && + p->out_dig_enabled; + } + case DIO_LINK_ENC_FEC_IS_ACTIVE: { + const struct link_enc_fec_is_active_params *p = + &step->params.link_enc_fec_is_active_params; + + return p->link_enc && p->link_enc->funcs && + p->link_enc->funcs->fec_is_active && + p->out_fec_active; + } + case BIOS_GET_I2C_INFO: { + const struct bios_get_i2c_info_params *p = + &step->params.bios_get_i2c_info_params; + + return p->dcb && p->dcb->funcs && p->dcb->funcs->get_i2c_info && + p->out_info && p->out_result; + } + case CLK_MGR_GET_DISPCLK_FROM_DENTIST: { + const struct clk_mgr_get_dispclk_from_dentist_params *p = + &step->params.clk_mgr_get_dispclk_from_dentist_params; + + return p->clk_mgr && p->clk_mgr->funcs && + p->clk_mgr->funcs->get_dispclk_from_dentist && + p->out_dispclk_khz; + } + case EDP_BACKLIGHT_CONTROL: { + struct dc_link *link = step->params.edp_control_params.link; + + return link && link->dc && link->dc->hwss.edp_backlight_control; + } + case EDP_POWER_CONTROL: { + struct dc_link *link = step->params.edp_control_params.link; + + return link && link->dc && link->dc->hwss.edp_power_control; + } + case LINK_BLANK_ALL_DP_DISPLAYS: { + struct dc *init_dc = step->params.dc_init_call_params.dc; + + return init_dc && init_dc->link_srv && + init_dc->link_srv->blank_all_dp_displays; + } + case HWSS_ENABLE_ACCELERATED_MODE: { + struct dc *init_dc = step->params.dc_init_call_params.dc; + + return init_dc && init_dc->hwss.enable_accelerated_mode; + } + case HWSEQ_INIT_PIPES: { + struct dc *init_dc = step->params.dc_init_call_params.dc; + + return init_dc && init_dc->hwseq && + init_dc->hwseq->funcs.init_pipes; + } + case DMUB_SET_IDLE_OPTIMIZATION: + return step->params.dc_init_call_params.dc != NULL; + case HWSEQ_POWER_DOWN: { + struct dc *init_dc = step->params.dc_init_call_params.dc; + + return init_dc && init_dc->hwseq && + init_dc->hwseq->funcs.power_down; + } + case HUBBUB_ALLOW_SELF_REFRESH_CONTROL: { + struct hubbub *hubbub = step->params + .hubbub_allow_self_refresh_control_params.hubbub; + + return hubbub && hubbub->funcs && + hubbub->funcs->allow_self_refresh_control; + } + case LEGACY_CLK_MGR_INITIALIZE_MIN_CLOCKS: { + const struct clk_mgr_initialize_min_clocks_params *p = + &step->params.clk_mgr_initialize_min_clocks_params; + + return p->clk_mgr && p->clk_mgr->funcs && + p->clk_mgr->funcs->update_clocks && p->context; + } + case AUDIO_HW_INIT: { + struct audio *audio = step->params.audio_hw_init_params.audio; + + return audio && audio->funcs && audio->funcs->hw_init; + } + case PANEL_CNTL_HW_INIT: { + const struct panel_cntl_hw_init_params *p = + &step->params.panel_cntl_hw_init_params; + + return p->panel_cntl && p->panel_cntl->funcs && + p->panel_cntl->funcs->hw_init && + p->out_backlight && p->out_user_level; + } + case GPIO_DDC_OPEN: + return step->params.gpio_ddc_open_params.gpio_service != NULL; + case ABM_INIT: { + const struct abm_init_params *p = &step->params.abm_init_params; + + return p->abm && p->abm->funcs && p->abm->funcs->abm_init; + } + case DIO_AFMT_SET_MEM_POWER: { + struct dio *dio = step->params.dio_set_mem_power_params.dio; + + return dio && dio->funcs && dio->funcs->mem_pwr_ctrl; + } + case DCCG_SET_ROOT_CLOCK_GATING: { + struct dccg *gating_dccg = + step->params.dccg_set_root_clock_gating_params.dccg; + + return gating_dccg && gating_dccg->funcs && + gating_dccg->funcs->allow_clock_gating; + } + case HUBBUB_INIT_WATERMARKS: { + const struct hubbub_init_watermarks_params *p = + &step->params.hubbub_init_watermarks_params; + + return p->hubbub && p->hubbub->funcs && + p->hubbub->funcs->init_watermarks; + } + case BIOS_IS_ACCELERATED_MODE: { + const struct bios_is_accelerated_mode_params *p = + &step->params.bios_is_accelerated_mode_params; + + return p->dcb && p->dcb->funcs && + p->dcb->funcs->is_accelerated_mode && + p->out_accelerated_mode; + } + case LEGACY_CLK_MGR_NOTIFY_WM_RANGES: + clk_mgr = step->params.clk_mgr_notify_wm_ranges_params.clk_mgr; + return clk_mgr && clk_mgr->funcs && + clk_mgr->funcs->notify_wm_ranges; + case HUBBUB_INIT_CRB: { + struct hubbub *hubbub = + step->params.hubbub_init_crb_params.hubbub; + + return hubbub && hubbub->funcs && hubbub->funcs->init_crb; + } + case HUBBUB_SET_REQUEST_LIMIT: { + struct hubbub *hubbub = + step->params.hubbub_set_request_limit_params.hubbub; + + return hubbub && hubbub->funcs && + hubbub->funcs->set_request_limit; + } + case HUBBUB_FORCE_PSTATE_CHANGE_CONTROL: { + struct hubbub *hubbub = step->params + .hubbub_force_pstate_change_control_params.hubbub; + + return hubbub && hubbub->funcs && + hubbub->funcs->force_pstate_change_control; + } + default: + return false; + } +} + +static noinline_for_stack void dc2_bls_exec_initialize_min_clocks( + const struct clk_mgr_initialize_min_clocks_params *p) +{ + struct dc_clocks *clocks = &p->context->bw_ctx.bw.dcn.clk; + + clocks->dcfclk_deep_sleep_khz = p->dcfclk_deep_sleep_khz; + clocks->dcfclk_khz = p->dcfclk_khz; + clocks->socclk_khz = p->socclk_khz; + clocks->dramclk_khz = p->dramclk_khz; + clocks->dppclk_khz = p->dppclk_khz; + clocks->dispclk_khz = p->dispclk_khz; + clocks->ref_dtbclk_khz = p->ref_dtbclk_khz; + clocks->fclk_p_state_change_support = p->fclk_p_state_change_support; + clocks->p_state_change_support = p->p_state_change_support; + + p->clk_mgr->funcs->update_clocks(p->clk_mgr, p->context, true); +} + +static noinline_for_stack enum dc2_bls_exec_result dc2_bls_exec_dmub_send( + const struct block_sequence *entry) +{ + struct dmub_messenger messenger; + struct dmub_messenger_init_data init_data; + struct dmub_send_cmd_params params; + struct dc_context *ctx; + + ctx = entry->params.send_dmcub_cmd_params.ctx; + init_data.ctx = ctx; + init_data.dc_dmub_srv = ctx->dmub_srv; + params.cmd = entry->params.send_dmcub_cmd_params.cmd; + params.wait_type = entry->params.send_dmcub_cmd_params.wait_type; + + dmub_messenger_construct(&messenger, &init_data); + if (messenger.funcs->inbox_cmd_send_and_wait(&messenger, ¶ms) != + DMUB_MSG_OK) + return entry->params.send_dmcub_cmd_params.continue_on_error ? + DC2_BLS_EXEC_CONTINUED_ON_ERROR : + DC2_BLS_EXEC_ERROR; + + return DC2_BLS_EXEC_OK; +} + +static noinline_for_stack enum dc2_bls_exec_result dc2_bls_exec_dmub_gpint( + struct dc2 *dc2, const struct block_sequence *entry) +{ + struct dmub_messenger messenger; + struct dmub_messenger_init_data init_data; + + init_data.ctx = dc2->dc.ctx; + init_data.dc_dmub_srv = dc2->dc.ctx->dmub_srv; + dmub_messenger_construct(&messenger, &init_data); + if (messenger.funcs->gpint_send_and_wait(&messenger, + &entry->params.dmub_gpint_params) != DMUB_MSG_OK) + return DC2_BLS_EXEC_ERROR; + + return DC2_BLS_EXEC_OK; +} + +enum dc2_bls_exec_result dc2_bls_execute( + struct dc2 *dc2, + const struct block_sequence *steps, + unsigned int num_steps) +{ + enum dc2_bls_exec_result result = DC2_BLS_EXEC_OK; + const struct block_sequence *entry; + enum dc2_bls_exec_result sent; + unsigned int i; + + if (!steps || num_steps > MAX_HWSS_BLOCK_SEQUENCE_SIZE) + return DC2_BLS_EXEC_ERROR; + + for (i = 0; i < num_steps; i++) + if (!dc2_bls_step_supported(dc2, &steps[i])) + return DC2_BLS_EXEC_ERROR; + + for (i = 0; i < num_steps; i++) { + entry = &steps[i]; + switch (entry->func) { + /* + * LEGACY/pmfw-msg: remove both cases when PMFW Messenger can + * reproduce the same calls, order, and output. + */ + case LEGACY_CLK_MGR_INIT_CLOCKS: + entry->params.legacy_clk_mgr_init_clocks_params + .clk_mgr->funcs->init_clocks( + entry->params + .legacy_clk_mgr_init_clocks_params.clk_mgr); + break; + case LEGACY_CLK_MGR_IS_DC_MODE_PRESENT: { + const struct legacy_clk_mgr_is_dc_mode_present_params *p = + &entry->params + .legacy_clk_mgr_is_dc_mode_present_params; + + *p->out_dcmode_power_limits_present = + p->clk_mgr->funcs->is_dc_mode_present( + p->clk_mgr); + break; + } + case DCCG_INITIALIZE_CLOCKS: + entry->params.dccg_initialize_clocks_params.dccg->funcs->dccg_init( + entry->params.dccg_initialize_clocks_params.dccg); + break; + case DMUB_SEND_DMCUB_CMD: + sent = dc2_bls_exec_dmub_send(entry); + if (sent == DC2_BLS_EXEC_ERROR) + return DC2_BLS_EXEC_ERROR; + if (sent == DC2_BLS_EXEC_CONTINUED_ON_ERROR) + result = DC2_BLS_EXEC_CONTINUED_ON_ERROR; + break; + case DMUB_GPINT_SEND_AND_WAIT: + case DMUB_HALT_FW: + if (dc2_bls_exec_dmub_gpint(dc2, entry) != DC2_BLS_EXEC_OK) + return DC2_BLS_EXEC_ERROR; + break; + case PSP_RELOAD_DMUB_FW: + if (dmub_srv_hw_init( + entry->params.psp_reload_dmub_fw_params.dmub, + entry->params.psp_reload_dmub_fw_params.hw_params) != + DMUB_STATUS_OK) + return DC2_BLS_EXEC_ERROR; + break; + case DMUB_INITIALIZE_DCN: + if (dc2_bls_exec_dmub_send(entry) != DC2_BLS_EXEC_OK) + return DC2_BLS_EXEC_ERROR; + break; + /* + * S-INT/bld-seq: dce_hwseq init functions. Remove when the + * OPTC, MMHUBBUB, DCCG and HPO BLCs expose them. + */ + case OPTC_SET_ODM_MEM_POWER: { + struct dce_hwseq *hws = + entry->params.hwseq_reg_control_params.hws; + + hws->funcs.init_odm_mem_power(hws); + break; + } + case MMHUBBUB_SET_MEM_POWER: { + struct dce_hwseq *hws = + entry->params.hwseq_reg_control_params.hws; + + hws->funcs.power_down_vga_mem(hws); + break; + } + case DCCG_SET_DCFCLK_GATING: { + struct dce_hwseq *hws = + entry->params.hwseq_reg_control_params.hws; + + hws->funcs.dcfclk_gating_control(hws, + entry->params.hwseq_reg_control_params + .enable); + break; + } + case HPO_SET_HW_CONTROL: { + struct dce_hwseq *hws = + entry->params.hwseq_reg_control_params.hws; + + hws->funcs.init_hpo_hw_control(hws, + entry->params.hwseq_reg_control_params + .enable); + break; + } + case PG_SET_PLANE_POWER_GATING: { + struct dce_hwseq *hws = + entry->params.hwseq_reg_control_params.hws; + + hws->funcs.enable_power_gating_plane(hws, + entry->params.hwseq_reg_control_params + .enable); + break; + } + case DCCG_GET_REF_FREQ: { + const struct dccg_get_ref_freq_params *p = + &entry->params.dccg_get_ref_freq_params; + + *p->out_xtalin_khz = p->xtalin_khz; + p->dccg->funcs->get_dccg_ref_freq(p->dccg, p->xtalin_khz, + p->out_dccg_ref_khz); + break; + } + case HUBBUB_GET_DCHUB_REF_FREQ: { + const struct hubbub_get_dchub_ref_freq_params *p = + &entry->params.hubbub_get_dchub_ref_freq_params; + + p->hubbub->funcs->get_dchub_ref_freq(p->hubbub, + p->dccg_ref_khz, p->out_dchub_ref_khz); + break; + } + case DIO_LINK_ENC_HW_INIT: { + struct link_encoder *enc = + entry->params.link_enc_hw_init_params.link_enc; + + enc->funcs->hw_init(enc); + break; + } + case DIO_LINK_ENC_IS_DIG_ENABLED: { + const struct link_enc_is_dig_enabled_params *p = + &entry->params.link_enc_is_dig_enabled_params; + + *p->out_dig_enabled = + p->link_enc->funcs->is_dig_enabled(p->link_enc); + break; + } + case DIO_LINK_ENC_FEC_IS_ACTIVE: { + const struct link_enc_fec_is_active_params *p = + &entry->params.link_enc_fec_is_active_params; + + *p->out_fec_active = + p->link_enc->funcs->fec_is_active(p->link_enc); + break; + } + /* + * S-INT/bld-seq: VBIOS table read through dc_bios. Remove + * when a BLC exposes the DDC GPIO info. + */ + case BIOS_GET_I2C_INFO: { + const struct bios_get_i2c_info_params *p = + &entry->params.bios_get_i2c_info_params; + + *p->out_result = p->dcb->funcs->get_i2c_info(p->dcb, + p->link_id, p->out_info); + break; + } + /* + * S-INT/link-seq: composite link call. Remove when Link + * builds the blanking through the shared Builder/Executor. + */ + case LINK_BLANK_ALL_DP_DISPLAYS: { + struct dc *init_dc = entry->params.dc_init_call_params.dc; + + init_dc->link_srv->blank_all_dp_displays(init_dc); + break; + } + /* + * S-INT/bld-seq: composite hwseq calls. Remove each when the + * DCN401 BLCs it drives are contract-conformant. + */ + case HWSS_ENABLE_ACCELERATED_MODE: { + struct dc *init_dc = entry->params.dc_init_call_params.dc; + + init_dc->hwss.enable_accelerated_mode(init_dc, + init_dc->current_state); + break; + } + case HWSEQ_INIT_PIPES: { + struct dc *init_dc = entry->params.dc_init_call_params.dc; + + init_dc->hwseq->funcs.init_pipes(init_dc, + init_dc->current_state); + break; + } + case HWSEQ_POWER_DOWN: { + struct dc *init_dc = entry->params.dc_init_call_params.dc; + + init_dc->hwseq->funcs.power_down(init_dc); + break; + } + case EDP_BACKLIGHT_CONTROL: { + struct dc_link *link = entry->params.edp_control_params.link; + + link->dc->hwss.edp_backlight_control(link, + entry->params.edp_control_params.enable); + break; + } + case EDP_POWER_CONTROL: { + struct dc_link *link = entry->params.edp_control_params.link; + + link->dc->hwss.edp_power_control(link, + entry->params.edp_control_params.enable); + break; + } + case HUBBUB_ALLOW_SELF_REFRESH_CONTROL: { + const struct hubbub_allow_self_refresh_control_params *p = + &entry->params + .hubbub_allow_self_refresh_control_params; + + p->hubbub->funcs->allow_self_refresh_control(p->hubbub, + p->allow); + break; + } + /* + * S-INT/pmfw-msg: remove these cases when PMFW Messenger can + * reproduce the same calls, order, and output. + */ + case CLK_MGR_GET_DISPCLK_FROM_DENTIST: { + const struct clk_mgr_get_dispclk_from_dentist_params *p = + &entry->params + .clk_mgr_get_dispclk_from_dentist_params; + + *p->out_dispclk_khz = + p->clk_mgr->funcs->get_dispclk_from_dentist( + p->clk_mgr); + break; + } + case LEGACY_CLK_MGR_INITIALIZE_MIN_CLOCKS: + dc2_bls_exec_initialize_min_clocks( + &entry->params + .clk_mgr_initialize_min_clocks_params); + break; + case LEGACY_CLK_MGR_NOTIFY_WM_RANGES: { + struct clk_mgr *wm_clk_mgr = entry->params + .clk_mgr_notify_wm_ranges_params.clk_mgr; + + wm_clk_mgr->funcs->notify_wm_ranges(wm_clk_mgr); + break; + } + /* + * S-INT/dmub-msg: composite idle call. Remove when DMUB + * Messenger carries the idle commands. + */ + case DMUB_SET_IDLE_OPTIMIZATION: + dc_allow_idle_optimizations( + entry->params.dc_init_call_params.dc, + entry->params.dc_init_call_params.enable); + break; + case AUDIO_HW_INIT: { + struct audio *audio = + entry->params.audio_hw_init_params.audio; + + audio->funcs->hw_init(audio); + break; + } + case PANEL_CNTL_HW_INIT: { + const struct panel_cntl_hw_init_params *p = + &entry->params.panel_cntl_hw_init_params; + + *p->out_backlight = + p->panel_cntl->funcs->hw_init(p->panel_cntl); + *p->out_user_level = p->panel_cntl + ->stored_backlight_registers.USER_LEVEL; + break; + } + case GPIO_DDC_OPEN: { + const struct gpio_ddc_open_params *p = + &entry->params.gpio_ddc_open_params; + + dal_gpio_ddc_open_aux_once(p->gpio_service, + p->clk_a_register_index, p->clk_a_mask, + &p->hw_info); + break; + } + case ABM_INIT: { + const struct abm_init_params *p = + &entry->params.abm_init_params; + + p->abm->funcs->abm_init(p->abm, p->backlight, + p->user_level); + break; + } + case DIO_AFMT_SET_MEM_POWER: { + const struct dio_set_mem_power_params *p = + &entry->params.dio_set_mem_power_params; + + p->dio->funcs->mem_pwr_ctrl(p->dio, p->enable); + break; + } + case DCCG_SET_ROOT_CLOCK_GATING: { + const struct dccg_set_root_clock_gating_params *p = + &entry->params.dccg_set_root_clock_gating_params; + + p->dccg->funcs->allow_clock_gating(p->dccg, p->allow); + break; + } + case HUBBUB_INIT_WATERMARKS: { + struct hubbub *hubbub = entry->params + .hubbub_init_watermarks_params.hubbub; + + hubbub->funcs->init_watermarks(hubbub); + break; + } + /* + * S-INT/bld-seq: VBIOS scratch read through dc_bios. Remove + * when a BLC exposes the accelerated-mode bit. + */ + case BIOS_IS_ACCELERATED_MODE: { + const struct bios_is_accelerated_mode_params *p = + &entry->params.bios_is_accelerated_mode_params; + + *p->out_accelerated_mode = + p->dcb->funcs->is_accelerated_mode(p->dcb); + break; + } + case HUBBUB_FORCE_PSTATE_CHANGE_CONTROL: { + const struct hubbub_force_pstate_change_control_params *p = + &entry->params + .hubbub_force_pstate_change_control_params; + + p->hubbub->funcs->force_pstate_change_control(p->hubbub, + p->enable, p->allow); + break; + } + case HUBBUB_INIT_CRB: { + struct hubbub *hubbub = + entry->params.hubbub_init_crb_params.hubbub; + + hubbub->funcs->init_crb(hubbub); + break; + } + case HUBBUB_SET_REQUEST_LIMIT: { + const struct hubbub_set_request_limit_params *p = + &entry->params.hubbub_set_request_limit_params; + + p->hubbub->funcs->set_request_limit(p->hubbub, + p->num_chans, p->words_per_umc); + break; + } + default: + ASSERT(false); + return DC2_BLS_EXEC_ERROR; + } + } + + return result; +} diff --git a/drivers/gpu/drm/amd/display/dc/bls_executor/bls_executor.h b/drivers/gpu/drm/amd/display/dc/bls_executor/bls_executor.h new file mode 100644 index 000000000000..d686f03c34c2 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/bls_executor/bls_executor.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#pragma once + +#include "bls_builder/bls_builder.h" +#include "dc_api_dispatch/api_shim.h" + +enum dc2_bls_exec_result { + DC2_BLS_EXEC_OK, + DC2_BLS_EXEC_ERROR, + /* Every step ran; at least one continue-on-error step failed. */ + DC2_BLS_EXEC_CONTINUED_ON_ERROR, +}; + +enum dc2_bls_exec_result dc2_bls_execute( + struct dc2 *dc2, + const struct block_sequence *steps, + unsigned int num_steps); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 3dbcece49188..ae5f03a73132 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -944,31 +944,23 @@ void dc_stream_set_static_screen_params(struct dc *dc, static void dc_destruct_update_scratch_pool(struct dc *dc) { - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(dc->update_scratch_pool); i++) { - kfree(dc->update_scratch_pool[i]); - dc->update_scratch_pool[i] = NULL; - dc->update_scratch_in_use[i] = false; - } + dc_memory_pool_destroy(dc->update_scratch_pool); } static bool dc_construct_update_scratch_pool(struct dc *dc) { - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(dc->update_scratch_pool); i++) { - dc->update_scratch_pool[i] = kzalloc_obj(struct dc_update_scratch_space); - if (!dc->update_scratch_pool[i]) - return false; - dc->update_scratch_in_use[i] = false; - } + // +1 to allow updates not tied to any specific stream + const size_t size = sizeof(struct dc_update_scratch_space); + const size_t capacity = MAX_STREAMS + 1; - return true; + dc->update_scratch_pool = dc_memory_pool_create(size, capacity); + return dc->update_scratch_pool != NULL; } static void dc_destruct(struct dc *dc) { + unsigned int i; + // reset link encoder assignment table on destruct if (dc->res_pool && dc->res_pool->funcs->link_encs_assign && !dc->config.unify_link_enc_assignment) @@ -981,6 +973,13 @@ static void dc_destruct(struct dc *dc) dc->current_state = NULL; } + for (i = 0; i < ARRAY_SIZE(dc->scratch_dc_context); i++) { + if (dc->scratch_dc_context[i]) { + dc_state_release(dc->scratch_dc_context[i]); + dc->scratch_dc_context[i] = NULL; + } + } + destroy_links(dc); destroy_link_encoders(dc); @@ -1219,6 +1218,22 @@ static bool dc_construct(struct dc *dc, goto fail; } + /* Pre-allocate the states used by the no-allocation update path, only + * for DMs that ask for it. + */ + if (dc->config.preallocate_scratch_state) { + unsigned int scratch_idx; + + for (scratch_idx = 0; scratch_idx < ARRAY_SIZE(dc->scratch_dc_context); scratch_idx++) { + dc->scratch_dc_context[scratch_idx] = dc_state_create(dc, NULL); + + if (!dc->scratch_dc_context[scratch_idx]) { + dm_error("%s: failed to create scratch ctx\n", __func__); + goto fail; + } + } + } + if (!dc_construct_update_scratch_pool(dc)) { dm_error("%s: failed to create update scratch pool\n", __func__); goto fail; @@ -3828,6 +3843,29 @@ static void restore_minimal_pipe_split_policy(struct dc *dc, } /** + * dc_state_acquire_scratch: Pick a pre-allocated state safe to build into. + * @dc: DC context + * + * Skips the buffer installed as @dc->current_state, since building into it + * would mean copying a state onto itself. + * + * Return: a usable scratch state, or NULL if none were pre-allocated. + */ +static struct dc_state *dc_state_acquire_scratch(struct dc *dc) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(dc->scratch_dc_context); i++) { + struct dc_state *scratch = dc->scratch_dc_context[i]; + + if (scratch && scratch != dc->current_state) + return scratch; + } + + return NULL; +} + +/** * update_planes_and_stream_state() - The function takes planes and stream * updates as inputs and determines the appropriate update type. If update type * is FULL, the function allocates a new context, populates and validates it. @@ -3933,7 +3971,24 @@ static bool update_planes_and_stream_state(struct dc *dc, new_planes[i] = srf_updates[i].surface; /* initialize scratch memory for building context */ - context = dc_state_create_copy(dc->current_state); + if (!dc->config.use_preallocated_state) { + context = dc_state_create_copy(dc->current_state); + } else { + context = dc_state_acquire_scratch(dc); + + if (context) { + // Drop the references this buffer still holds from its + // previous use; dc_state_copy() overwrites the pointers + // without releasing them. + dc_state_destruct(context); + dc_state_copy(context, dc->current_state); + + // Balance the reference that the commit path consumes + // when it installs this as current_state, so the buffer + // stays owned by dc->scratch_dc_context[] as well. + dc_state_retain(context); + } + } if (context == NULL) { DC_ERROR("Failed to allocate new validate context!\n"); return false; @@ -4014,6 +4069,8 @@ static bool update_planes_and_stream_state(struct dc *dc, return true; fail: + // For a scratch buffer this drops the reference taken above, leaving it + // owned by dc->scratch_dc_context[] rather than freeing it. dc_state_release(context); return false; @@ -6026,32 +6083,17 @@ static void clear_update_bits(struct dc_surface_update *srf_updates, static struct dc_update_scratch_space *dc_update_scratch_acquire(struct dc *dc) { - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(dc->update_scratch_pool); i++) { - if (dc->update_scratch_in_use[i]) - continue; - - dc->update_scratch_in_use[i] = true; - return dc->update_scratch_pool[i]; - } + void *p = dc_memory_pool_acquire(dc->update_scratch_pool); /* TODO: add recoverable scratch acquisition failure handling. */ - ASSERT(false); - return NULL; + ASSERT(p); + return p; } static void dc_update_scratch_release(struct dc *dc, struct dc_update_scratch_space *scratch) { - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(dc->update_scratch_pool); i++) { - if (dc->update_scratch_pool[i] == scratch) { - dc->update_scratch_in_use[i] = false; - return; - } - } + dc_memory_pool_release(dc->update_scratch_pool, scratch); } /** @@ -8117,6 +8159,16 @@ static bool update_planes_and_stream_prepare_v3( ASSERT(scratch->update_type >= UPDATE_TYPE_FULL); + /* The minimal-transition fallbacks below allocate, so the scratch path + * commits the new context directly - possibly a non-seamless pipe-topology + * transition. Placed after the suspend above to keep the cleanup resume + * balanced. + */ + if (scratch->dc->config.use_preallocated_state) { + scratch->flow = UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS; + return true; + } + const bool seamless = scratch->dc->hwss.is_pipe_topology_transition_seamless( scratch->dc, scratch->dc->current_state, diff --git a/drivers/gpu/drm/amd/display/dc/core2/dc_core2_init.c b/drivers/gpu/drm/amd/display/dc/core2/dc_core2_init.c index d4777cdbd569..69a376351df1 100644 --- a/drivers/gpu/drm/amd/display/dc/core2/dc_core2_init.c +++ b/drivers/gpu/drm/amd/display/dc/core2/dc_core2_init.c @@ -5,9 +5,85 @@ #include "dm_services.h" #include "dc.h" +#include "bls_builder/bls_builder.h" +#include "bls_executor/bls_executor.h" +#include "workaround_manager/workaround_manager.h" #include "core2/dc_core2_init.h" +#include "core2/dc_core2_legacy_init.h" +#include "dc_api_dispatch/api_shim.h" +/* + * S-INT/link-seq: the eDP sink check legacy_hardware_init runs before + * init_hw. Remove when Link owns boot-time eDP detection. + */ +static void core2_detect_edp_presence(struct dc *dc) +{ + struct dc_link *edp_links[MAX_NUM_EDP]; + enum dc_connection_type type; + unsigned int i, edp_num; + + dc_get_edp_links(dc, edp_links, &edp_num); + for (i = 0; i < edp_num; i++) { + if (dc->config.edp_not_connected) { + edp_links[i]->edp_sink_present = false; + } else { + edp_links[i]->edp_sink_present = + dc_link_detect_connection_type(edp_links[i], + &type) && type != dc_connection_none; + } + } +} + +static void core2_run_native_hardware_init(struct dc *dc) +{ + struct bls_builder_declarative_params *params; + struct bls_builder_output_init *out_init; + struct bls_builder_output_targets out_targets = {0}; + const struct bls_builder *builder; + enum bls_builder_result result; + + builder = bls_builder_create(dc, DCN_DECL_INITIALIZATION); + if (!builder || builder->kind != BLS_BUILDER_DECLARATIVE || + !builder->build.declarative) + return; + + /* + * The declarative params hold 128 block-sequence entries, and the + * init output holds DMUB command buffers. Keep both off the stack + * so the kernel frame stays under the 2048-byte limit. + */ + params = kvzalloc(sizeof(*params), GFP_KERNEL); + out_init = kvzalloc(sizeof(*out_init), GFP_KERNEL); + if (!params || !out_init) + goto out; + + params->dc = dc; + out_targets.DCN_DECL_INITIALIZATION = out_init; + params->out_targets = &out_targets; + /* + * The builder copies DMUB windows retained on dmub_srv. Missing + * windows fail the build closed. Execute only a successful build, + * and do not fall back to legacy hwseq. + */ + result = builder->build.declarative(params); + if (result == BLS_BUILD_SUCCESS) + dc2_bls_execute(TO_DC2(dc), params->head_sequence, + params->head_num_steps); + +out: + kvfree(params); + kvfree(out_init); +} + +/* CORE2 runs the DC2_DC1_Wrapped init until dcn401 init is native. */ void core2_hardware_init(struct dc *dc) { - dc2_legacy_funcs()->hardware_init(dc); + if (!dc) + return; + + core2_detect_edp_presence(dc); + if (TO_DC2(dc)->selection == DC2_SELECTION_CORE2) + core2_run_legacy_hardware_init(dc, dc2_workaround_manager_get()); + else + core2_run_native_hardware_init(dc); } diff --git a/drivers/gpu/drm/amd/display/dc/core2/dc_core2_legacy_init.c b/drivers/gpu/drm/amd/display/dc/core2/dc_core2_legacy_init.c new file mode 100644 index 000000000000..285dfc9e6e69 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/core2/dc_core2_legacy_init.c @@ -0,0 +1,236 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#include "dm_services.h" +#include "dc.h" +#include "core_types.h" +#include "clk_mgr.h" +#include "dc_dmub_srv.h" +#include "bls_builder/bls_builder.h" +#include "bls_executor/bls_executor.h" +#include "workaround_manager/workaround_manager.h" +#include "core2/dc_core2_legacy_init.h" +#include "dc_api_dispatch/api_shim.h" + +/* + * dcn401_init_hw marks a link active when its DIG is already enabled, + * and FEC enabled when it is also active. Applied after each stage that + * reads the DIG or FEC state, before any later stage runs. + */ +static void core2_apply_dc1_link_states(struct dc *dc, + const struct bls_builder_legacy_hw_init_info *info) +{ + unsigned int i; + + for (i = 0; i < dc->link_count; i++) { + struct dc_link *link = dc->links[i]; + + if (!info->s3.link_dig_enabled[i]) + continue; + link->link_status.link_active = true; + link->phy_state.symclk_state = SYMCLK_ON_TX_ON; + if (info->s4.link_fec_active[i]) + link->fec_state = dc_link_fec_enabled; + } +} + +/* + * The HUBBUB stage resolved the DMUB feature caps. Take the query reply + * as dc_dmub_srv_query_caps_cmd does, retain dmub_abi for later builds, + * then apply the caps and the bounding-box update, all before the next + * stage runs. + */ +static void core2_apply_dmub_caps(struct dc *dc, + const struct bls_builder_legacy_hw_init_info *info) +{ + const union dmub_rb_cmd *reply = &info->s11.dmub_query_feature_caps_cmd; + struct dmub_srv *dmub = dc->ctx->dmub_srv->dmub; + struct resource_pool *pool = dc->res_pool; + struct dc2 *dc2 = TO_DC2(dc); + const struct dmub_feature_caps *caps = &dc2->dmub_abi.feature_caps; + bool dchub_ref_freq_changed; + + /* + * S-INT/dmub-msg: the rest of DC reads feature_caps from dmub_srv. + * Remove when those readers take dmub_abi. + */ + if (info->s11.dmub_caps_query_sent && + reply->query_feature_caps.header.ret_status == 0) + memcpy(&dmub->feature_caps, + &reply->query_feature_caps.query_feature_caps_data, + sizeof(dmub->feature_caps)); + memset(&dc2->dmub_abi, 0, sizeof(dc2->dmub_abi)); + dc2->dmub_abi.feature_caps = dmub->feature_caps; + dc2->dmub_abi_resolved = true; + + dc->caps.dmub_caps.psr = caps->psr; + dc->caps.dmub_caps.mclk_sw = caps->fw_assisted_mclk_switch_ver > 0; + dc->caps.dmub_caps.fams_ver = caps->fw_assisted_mclk_switch_ver; + + /* sw and fw FAMS versions must match for support */ + dc->debug.fams2_config.bits.enable &= + dc->caps.dmub_caps.fams_ver == dc->debug.fams_version.ver; + dchub_ref_freq_changed = pool->ref_clocks.dchub_ref_clock_inKhz / 1000 != + info->s2.dchub_ref_clock_mhz_before; + if ((!dc->debug.fams2_config.bits.enable || dchub_ref_freq_changed) && + pool->funcs->update_bw_bounding_box && + dc->clk_mgr && dc->clk_mgr->bw_params) + pool->funcs->update_bw_bounding_box(dc, dc->clk_mgr->bw_params); +} + +/* + * Move the output of the stage just executed into dc_state.hw_init_info, + * where the next build reads it, then apply what dcn401_init_hw left on + * dc by this point: the reference clocks, DC-mode limits, link state and + * DMUB caps. + */ +static void core2_retain_init_stage(struct dc *dc, + const struct bls_builder_legacy_hw_init_info *out) +{ + struct bls_builder_legacy_hw_init_info *info = + &dc->current_state->hw_init_info; + struct resource_pool *pool = dc->res_pool; + + switch (out->next_stage - 1) { + case LEGACY_INIT_STAGE_CLOCKS: + info->s1 = out->s1; + pool->ref_clocks.xtalin_clock_inKhz = info->s1.xtalin_clock_inKhz; + pool->ref_clocks.dccg_ref_clock_inKhz = + info->s1.dccg_ref_clock_inKhz; + if (dc->clk_mgr && dc->clk_mgr->funcs && + dc->clk_mgr->funcs->init_clocks) + dc->caps.dcmode_power_limits_present = + info->s1.dcmode_power_limits_present; + break; + case LEGACY_INIT_STAGE_DCHUB_REF: + info->s2 = out->s2; + pool->ref_clocks.dchub_ref_clock_inKhz = + info->s2.dchub_ref_clock_inKhz; + break; + case LEGACY_INIT_STAGE_LINK_ENC: + info->s3 = out->s3; + core2_apply_dc1_link_states(dc, info); + break; + case LEGACY_INIT_STAGE_FEC: + info->s4 = out->s4; + core2_apply_dc1_link_states(dc, info); + break; + case LEGACY_INIT_STAGE_BLANK: + info->s5 = out->s5; + break; + case LEGACY_INIT_STAGE_POWER_DOWN: + info->s6 = out->s6; + break; + case LEGACY_INIT_STAGE_MIN_CLOCKS: + info->s7 = out->s7; + break; + case LEGACY_INIT_STAGE_POWER_DOWN_EDP0: + info->s8 = out->s8; + break; + case LEGACY_INIT_STAGE_POWER_DOWN_EDP1: + info->s9 = out->s9; + break; + case LEGACY_INIT_STAGE_GATING: + info->s10 = out->s10; + break; + case LEGACY_INIT_STAGE_HUBBUB: + info->s11 = out->s11; + if (info->s11.dmub_caps_read) + core2_apply_dmub_caps(dc, info); + break; + case LEGACY_INIT_STAGE_POWER_STATE: + info->s12 = out->s12; + break; + } + info->next_stage = out->next_stage; + info->init_done = out->init_done; +} + +/* + * Build, workaround, execute. Execute only a successful build and a + * workaround pass that kept the stage within the sequence storage, and + * do not fall back to legacy hwseq. + */ +static bool core2_run_init_stage(struct dc *dc, + const struct bls_builder *builder, + const struct workaround_manager *wam, + struct bls_builder_declarative_params *params) +{ + struct workaround_context wa_ctx = {0}; + struct block_sequence_state sequence; + enum dc2_bls_exec_result result; + + if (builder->build.declarative(params) != BLS_BUILD_SUCCESS) + return false; + + sequence.steps = params->head_sequence; + sequence.num_steps = ¶ms->head_num_steps; + wa_ctx.current_state = dc->current_state; + wa_ctx.builder_name = builder->name; + wa_ctx.dcn_version = dc->ctx->dce_version; + wa_ctx.bug_wa = &dc->work_arounds; + wa_ctx.debug = &dc->debug; + if (workaround_manager_apply(wam, &sequence, &wa_ctx) != WAM_OK || + params->head_num_steps > DC2_BLS_MAX_STEPS) + return false; + + /* dcn401_init_hw ignores the DMUB sends that continue on error. */ + result = dc2_bls_execute(TO_DC2(dc), params->head_sequence, + params->head_num_steps); + return result == DC2_BLS_EXEC_OK || + result == DC2_BLS_EXEC_CONTINUED_ON_ERROR; +} + +bool core2_run_legacy_hardware_init(struct dc *dc, + const struct workaround_manager *wam) +{ + struct bls_builder_declarative_params *params; + struct bls_builder_legacy_hw_init_info *out; + struct bls_builder_legacy_hw_init_info *info; + struct bls_builder_output_targets out_targets = {0}; + const struct bls_builder *builder; + unsigned int stage; + + if (!dc || !dc->current_state || !wam) + return false; + + info = &dc->current_state->hw_init_info; + memset(info, 0, sizeof(*info)); + info->next_stage = LEGACY_INIT_STAGE_CLOCKS; + builder = bls_builder_create(dc, DCN_DECL_INITIALIZATION_LEGACY); + if (!builder || builder->kind != BLS_BUILDER_DECLARATIVE || + !builder->build.declarative) + return false; + TO_DC2(dc)->dmub_abi_resolved = false; + + /* + * The declarative params hold 128 block-sequence entries, and the + * stage outputs hold DMUB command buffers. Keep both off the stack + * so the kernel frame stays under the 2048-byte limit. + */ + params = kvzalloc(sizeof(*params), GFP_KERNEL); + out = kvzalloc(sizeof(*out), GFP_KERNEL); + if (!params || !out) + goto out; + + params->dc = dc; + params->current_state = dc->current_state; + out_targets.DCN_DECL_INITIALIZATION_LEGACY = out; + params->out_targets = &out_targets; + /* The builder reports init_done no later than its last stage. */ + for (stage = 0; stage < LEGACY_INIT_STAGE_COUNT && !info->init_done; + stage++) { + if (!core2_run_init_stage(dc, builder, wam, params)) + break; + core2_retain_init_stage(dc, out); + } + info->init_success = info->init_done; + +out: + info->init_done = true; + kvfree(params); + kvfree(out); + return info->init_success; +} diff --git a/drivers/gpu/drm/amd/display/dc/core2/dc_core2_legacy_init.h b/drivers/gpu/drm/amd/display/dc/core2/dc_core2_legacy_init.h new file mode 100644 index 000000000000..d0cd7a5cb2c6 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/core2/dc_core2_legacy_init.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#pragma once + +struct dc; +struct workaround_manager; + +/* + * DC2_DC1_Wrapped hardware init: dcn401_init_hw as twelve staged BLS + * builds, each passed through wam. A migration shim; it and + * dcn401_init_builder_legacy.c are removed together. + */ +bool core2_run_legacy_hardware_init(struct dc *dc, + const struct workaround_manager *wam); diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index f4fefa7c9ab8..d983bab7eea3 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -30,6 +30,7 @@ #include "dc_state.h" #include "dc_plane.h" #include "dc_probe.h" +#include "dc_memory_pool.h" #include "grph_object_defs.h" #include "logger_types.h" #include "hdcp_msg_types.h" @@ -68,7 +69,7 @@ struct dcn_dsc_reg_state; struct dcn_optc_reg_state; struct dcn_dccg_reg_state; -#define DC_VER "3.2.403" +#define DC_VER "3.2.404" /** * MAX_SURFACES - representative of the upper bound of surfaces that can be piped to a single CRTC @@ -635,6 +636,15 @@ struct dc_config { struct spl_sharpness_range dcn_sharpness_range; struct spl_sharpness_range dcn_override_sharpness_range; bool no_native422_support; + + // Pre-allocate dc_state buffers at dc_construct time so that a commit can + // run on a code path where allocation is not permitted. + bool preallocate_scratch_state; + + // Build commits into the pre-allocated buffers instead of allocating. + // Set by the DM around a commit that runs where allocation is not + // permitted; requires preallocate_scratch_state. + bool use_preallocated_state; }; enum visual_confirm { @@ -811,9 +821,6 @@ struct dc_clocks { int idle_fclk_khz; int subvp_prefetch_dramclk_khz; int subvp_prefetch_fclk_khz; - /* deprecated: use _KBps variants — will be removed after DML update */ - unsigned int utm_urgent_bandwidth_lb_Kbps; - unsigned int utm_nominal_bandwidth_lb_Kbps; unsigned int utm_urgent_bandwidth_lb_KBps; unsigned int utm_nominal_bandwidth_lb_KBps; unsigned int utm_latency_ub_index; @@ -1104,6 +1111,12 @@ struct dc_debug_options { */ enum pipe_split_policy pipe_split_policy; bool force_single_disp_pipe_split; + /* + * @force_mpc_combine: Override the DML2.1 per-plane MPC combine + * decision. 0 = auto (default), 1 = force single DPP (no MPC combine), + * 2 = force 2:1 MPC combine. + */ + uint8_t force_mpc_combine; bool voltage_align_fclk; bool disable_min_fclk; @@ -1321,13 +1334,13 @@ struct dc_debug_options { unsigned int urgent_watermark_override; bool enable_block_sequence_programming; uint32_t custom_psp_footer_size; + uint32_t dmcub_fw_load_type; bool disable_deferred_minimal_transitions; unsigned int num_fast_flips_to_steady_state_override; bool enable_dmu_recovery; unsigned int force_vmin_threshold; bool enable_otg_frame_sync_pwa; unsigned int min_deep_sleep_dcfclk_khz; - unsigned int force_odm2to1_for_edp_pixclk_mhz; bool enable_replay_esd_recovery; uint8_t iommu_mismatch_temp_wka; bool disable_dynamic_expansion_for_test_pattern; @@ -2023,13 +2036,19 @@ struct dc { struct link_service *link_srv; struct dc_state *current_state; + /** + * @scratch_dc_context: Pre-allocated states for the no-allocation update + * path, created only when dc_config.preallocate_scratch_state is set. + * Two are kept because the commit path installs the new context as + * @current_state, so a single buffer would alias it and self-copy. + */ + struct dc_state *scratch_dc_context[2]; struct resource_pool *res_pool; /** * @update_scratch_pool: Per-commit scratch buffers for dc_update_state. */ - struct dc_update_scratch_space *update_scratch_pool[MAX_STREAMS + 1]; - bool update_scratch_in_use[MAX_STREAMS + 1]; + struct dc_memory_pool *update_scratch_pool; // MAX_STREAMS + 1 struct clk_mgr *clk_mgr; diff --git a/drivers/gpu/drm/amd/display/dc/dc_api_dispatch/api_shim.h b/drivers/gpu/drm/amd/display/dc/dc_api_dispatch/api_shim.h index fee03a5dd596..b972ae06663d 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_api_dispatch/api_shim.h +++ b/drivers/gpu/drm/amd/display/dc/dc_api_dispatch/api_shim.h @@ -7,11 +7,15 @@ #include "dc.h" #include "inc/dc_core_interface.h" +#include "bls_builder/dmub_abi.h" struct dc2 { /* First member: TO_DC2 is a typed upcast, not container_of. */ struct dc dc; enum dc2_selection selection; + /* Resolved by hardware init; later builds take it as dmub_abi. */ + struct dmub_abi dmub_abi; + bool dmub_abi_resolved; }; #define TO_DC2(ptr) ((struct dc2 *)(ptr)) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c index feb6ca92802c..37a010e0bd6e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c @@ -44,6 +44,7 @@ #include "dcn10/dcn10_hubbub.h" #include "dcn10_cm_common.h" #include "clk_mgr.h" +#include "dsc.h" __printf(3, 4) unsigned int snprintf_count(char *pbuf, unsigned int bufsize, const char *fmt, ...) @@ -488,6 +489,149 @@ static unsigned int dcn10_get_clock_states(struct dc *dc, char *pBuf, unsigned i return bufSize - remaining_buffer; } +static unsigned int dcn10_get_bios_state(struct dc *dc, char *pBuf, unsigned int bufSize) +{ + struct dc_bios *bios = dc->ctx->dc_bios; + int acc_mode = -1; + + if (bios && bios->funcs->is_accelerated_mode) + acc_mode = bios->funcs->is_accelerated_mode(bios); + + return snprintf_count(pBuf, bufSize, "acc_mode\n%d\n", acc_mode); +} + +/* Preset in a read_state struct for fields that only some generations read. */ +#define HW_STATE_NOT_READ 0xFFFFFFFF + +static int dcn10_dig_source_otg(struct dc *dc, unsigned int fe) +{ + struct resource_pool *pool = dc->res_pool; + unsigned int i; + + for (i = 0; i < pool->stream_enc_count; i++) { + struct stream_encoder *se = pool->stream_enc[i]; + + if (se && se->id == fe && se->funcs->dig_source_otg) + return se->funcs->dig_source_otg(se); + } + return -1; +} + +static unsigned int dcn10_get_link_states(struct dc *dc, char *pBuf, unsigned int bufSize) +{ + unsigned int chars_printed = 0; + unsigned int remaining_buffer = bufSize; + unsigned int i; + + chars_printed = snprintf_count(pBuf, remaining_buffer, + "link,enc,hpd,dig_en,dig_mode,dig_fe,src_otg,preferred_otg,phy_on,phy_active\n"); + remaining_buffer -= chars_printed; + pBuf += chars_printed; + + for (i = 0; i < dc->link_count && remaining_buffer > 0; i++) { + struct dc_link *link = dc->links[i]; + struct link_encoder *enc = link ? link->link_enc : NULL; + int hpd = -1, dig_en = -1, dig_mode = -1, dig_fe = -1, src_otg = -1; + int phy_on = -1, phy_active = -1; + struct link_enc_state s = {0}; + + if (!enc || link->connector_signal == SIGNAL_TYPE_VIRTUAL) + continue; + + if (enc->funcs->get_hpd_state) + hpd = enc->funcs->get_hpd_state(enc); + if (enc->funcs->is_dig_enabled) + dig_en = enc->funcs->is_dig_enabled(enc); + if (dig_en == 1 && enc->funcs->get_dig_mode) + dig_mode = enc->funcs->get_dig_mode(enc); + if (dig_en == 1 && enc->funcs->get_dig_frontend) { + dig_fe = enc->funcs->get_dig_frontend(enc); + src_otg = dcn10_dig_source_otg(dc, dig_fe); + } + s.rdpcs_phy_reset = HW_STATE_NOT_READ; + s.rdpcs_tx_data_en = HW_STATE_NOT_READ; + if (enc->funcs->read_state) + enc->funcs->read_state(enc, &s); + if (s.rdpcs_phy_reset != HW_STATE_NOT_READ) + phy_on = s.rdpcs_phy_reset == 0; + if (s.rdpcs_tx_data_en != HW_STATE_NOT_READ) + phy_active = s.rdpcs_tx_data_en != 0; + + chars_printed = snprintf_count(pBuf, remaining_buffer, + "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", + i, enc->transmitter, hpd, dig_en, dig_mode, dig_fe, + src_otg, enc->preferred_engine, phy_on, phy_active); + remaining_buffer -= chars_printed; + pBuf += chars_printed; + } + + return bufSize - remaining_buffer; +} + +static unsigned int dcn10_get_dsc_states(struct dc *dc, char *pBuf, unsigned int bufSize) +{ + struct resource_pool *pool = dc->res_pool; + unsigned int chars_printed = 0; + unsigned int remaining_buffer = bufSize; + unsigned int i; + + if (pool->res_cap->num_dsc == 0) + return 0; + + chars_printed = snprintf_count(pBuf, remaining_buffer, + "dsc,clock_en,slice_width,bits_pp\n"); + remaining_buffer -= chars_printed; + pBuf += chars_printed; + + for (i = 0; i < (unsigned int)pool->res_cap->num_dsc && remaining_buffer > 0; i++) { + struct display_stream_compressor *dsc = pool->dscs[i]; + struct dcn_dsc_state s = {0}; + + if (!dsc || !dsc->funcs->dsc_read_state) + continue; + + dsc->funcs->dsc_read_state(dsc, &s); + chars_printed = snprintf_count(pBuf, remaining_buffer, + "%d,%d,%d,%d\n", i, s.dsc_clock_en, + s.dsc_slice_width, s.dsc_bits_per_pixel); + remaining_buffer -= chars_printed; + pBuf += chars_printed; + } + + return bufSize - remaining_buffer; +} + +static unsigned int dcn10_get_cursor_lock_states(struct dc *dc, char *pBuf, unsigned int bufSize) +{ + struct resource_pool *pool = dc->res_pool; + unsigned int chars_printed = 0; + unsigned int remaining_buffer = bufSize; + unsigned int i; + + chars_printed = snprintf_count(pBuf, remaining_buffer, "mpcc,opp,cur_lock\n"); + remaining_buffer -= chars_printed; + pBuf += chars_printed; + + for (i = 0; i < pool->mpcc_count && remaining_buffer > 0; i++) { + struct mpcc_state s = {0}; + int lock = -1; + + s.cur_vupdate_lock = HW_STATE_NOT_READ; + pool->mpc->funcs->read_mpcc_state(pool->mpc, i, &s); + if (s.opp_id == 0xf) + continue; + if (s.cur_vupdate_lock != HW_STATE_NOT_READ) + lock = s.cur_vupdate_lock; + + chars_printed = snprintf_count(pBuf, remaining_buffer, "%d,%d,%d\n", + i, s.opp_id, lock); + remaining_buffer -= chars_printed; + pBuf += chars_printed; + } + + return bufSize - remaining_buffer; +} + static void dcn10_clear_otpc_underflow(struct dc *dc) { struct resource_pool *pool = dc->res_pool; @@ -548,6 +692,7 @@ void dcn10_get_hw_state(struct dc *dc, char *pBuf, unsigned int bufSize, unsigne * Mask Format * Bit 0 - 15: Hardware block mask * Bit 15: 1 = Invariant Only, 0 = All + * Bit 16 and up: opt-in blocks, never selected by mask 0 */ const unsigned int DC_HW_STATE_MASK_HUBBUB = 0x1; const unsigned int DC_HW_STATE_MASK_HUBP = 0x2; @@ -559,6 +704,10 @@ void dcn10_get_hw_state(struct dc *dc, char *pBuf, unsigned int bufSize, unsigne const unsigned int DC_HW_STATE_MASK_OTG = 0x80; const unsigned int DC_HW_STATE_MASK_CLOCKS = 0x100; const unsigned int DC_HW_STATE_INVAR_ONLY = 0x8000; + const unsigned int DC_HW_STATE_MASK_BIOS = 0x10000; + const unsigned int DC_HW_STATE_MASK_LINK = 0x20000; + const unsigned int DC_HW_STATE_MASK_DSC = 0x40000; + const unsigned int DC_HW_STATE_MASK_CURSOR_LOCK = 0x80000; unsigned int chars_printed = 0; unsigned int remaining_buf_size = bufSize; @@ -619,4 +768,28 @@ void dcn10_get_hw_state(struct dc *dc, char *pBuf, unsigned int bufSize, unsigne pBuf += chars_printed; remaining_buf_size -= chars_printed; } + + if ((mask & DC_HW_STATE_MASK_BIOS) && remaining_buf_size > 0) { + chars_printed = dcn10_get_bios_state(dc, pBuf, remaining_buf_size); + pBuf += chars_printed; + remaining_buf_size -= chars_printed; + } + + if ((mask & DC_HW_STATE_MASK_LINK) && remaining_buf_size > 0) { + chars_printed = dcn10_get_link_states(dc, pBuf, remaining_buf_size); + pBuf += chars_printed; + remaining_buf_size -= chars_printed; + } + + if ((mask & DC_HW_STATE_MASK_DSC) && remaining_buf_size > 0) { + chars_printed = dcn10_get_dsc_states(dc, pBuf, remaining_buf_size); + pBuf += chars_printed; + remaining_buf_size -= chars_printed; + } + + if ((mask & DC_HW_STATE_MASK_CURSOR_LOCK) && remaining_buf_size > 0) { + chars_printed = dcn10_get_cursor_lock_states(dc, pBuf, remaining_buf_size); + pBuf += chars_printed; + remaining_buf_size -= chars_printed; + } } diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.c index 6594fbb3fa43..4d62a5982632 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.c @@ -364,6 +364,26 @@ bool dcn401_is_dig_enabled(struct link_encoder *enc) return (clk_enabled == 1 && dig_enabled == 1); } +void dcn401_link_encoder_read_state(struct link_encoder *enc, struct link_enc_state *s) +{ + struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc); + uint32_t tx0 = 0, tx1 = 0, tx2 = 0, tx3 = 0; + + link_enc2_read_state(enc, s); + + if (enc10->link_regs->RDPCSTX_PHY_CNTL0) + REG_GET(RDPCSTX_PHY_CNTL0, RDPCS_PHY_RESET, &s->rdpcs_phy_reset); + + if (enc10->link_regs->RDPCSTX_PHY_CNTL3) { + REG_GET_4(RDPCSTX_PHY_CNTL3, + RDPCS_PHY_DP_TX0_DATA_EN, &tx0, + RDPCS_PHY_DP_TX1_DATA_EN, &tx1, + RDPCS_PHY_DP_TX2_DATA_EN, &tx2, + RDPCS_PHY_DP_TX3_DATA_EN, &tx3); + s->rdpcs_tx_data_en = tx0 | tx1 << 1 | tx2 << 2 | tx3 << 3; + } +} + enum signal_type dcn401_get_dig_mode( struct link_encoder *enc) { @@ -399,7 +419,7 @@ void dcn401_setup_ri_pj_check_in_sw_or_hw_mode( } static const struct link_encoder_funcs dcn401_link_enc_funcs = { - .read_state = link_enc2_read_state, + .read_state = dcn401_link_encoder_read_state, .validate_output_with_stream = dcn30_link_encoder_validate_output_with_stream, .hw_init = enc401_hw_init, diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.h index 62f8f9098b53..689fc817dbc5 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_link_encoder.h @@ -28,6 +28,13 @@ #include "dcn30/dcn30_dio_link_encoder.h" +#define LINK_ENCODER_PHY_STATE_MASK_SH_LIST_DCN401(mask_sh) \ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL0, RDPCS_PHY_RESET, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX0_DATA_EN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX1_DATA_EN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX2_DATA_EN, mask_sh),\ + LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL3, RDPCS_PHY_DP_TX3_DATA_EN, mask_sh) + #define LINK_ENCODER_MASK_SH_LIST_DCN401(mask_sh) \ LE_SF(DIG0_DIG_BE_EN_CNTL, DIG_BE_ENABLE, mask_sh),\ LE_SF(DIG0_DIG_BE_CNTL, DIG_RB_SWITCH_EN, mask_sh),\ @@ -150,6 +157,7 @@ enum signal_type dcn401_get_dig_mode( struct link_encoder *enc); bool dcn401_is_dig_enabled(struct link_encoder *enc); +void dcn401_link_encoder_read_state(struct link_encoder *enc, struct link_enc_state *s); enum signal_type dcn401_get_dig_mode(struct link_encoder *enc); diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c index a4a77e375d9f..c84cbad7fde1 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c @@ -11052,6 +11052,8 @@ static bool dml_core_mode_programming(struct dml2_core_calcs_mode_programming_ex calculate_tdlut_setting_params->cursor_buffer_size = mode_lib->ip.cursor_buffer_size; calculate_tdlut_setting_params->gpuvm_enable = display_cfg->gpuvm_enable; calculate_tdlut_setting_params->gpuvm_page_size_kbytes = display_cfg->plane_descriptors[k].overrides.gpuvm_min_page_size_kbytes; + calculate_tdlut_setting_params->tdlut_mpc_width_flag = display_cfg->plane_descriptors[k].tdlut.tdlut_mpc_width_flag; + calculate_tdlut_setting_params->is_gfx11 = dml_get_gfx_version(display_cfg->plane_descriptors[k].surface.tiling); // output calculate_tdlut_setting_params->tdlut_pte_bytes_per_frame = &s->tdlut_pte_bytes_per_frame[k]; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_calcs_dchub.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_calcs_dchub.c index 485ad96f64b1..b3a2858281ec 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_calcs_dchub.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_calcs_dchub.c @@ -260,9 +260,10 @@ static unsigned int calculate_max_mem_size_per_plane_per_dpp(const struct dml2_c odm_slice_pixels = (double)h_active / odm_combine_factor * h_ratio + (odm_combine_factor == 3 ? 2 : 0); /* Unaligned copy region dimensions (in pixels / lines) prior to tile alignment. - * Also divide vp_widht/height by NoOfDPP for MPC combine scenarios (i.e., MPC split within an ODM slice). */ - copy_width = vertical_access ? copy_src_lines : (unsigned int)math_ceil(math_min2(odm_slice_pixels, vp_width / p->NoOfDPP[plane_idx])); - copy_height = vertical_access ? (unsigned int)math_ceil(math_min2(odm_slice_pixels, vp_height / p->NoOfDPP[plane_idx])) : copy_src_lines; + * No need to divide vp width/height by NoOfDPP. The entire viewport could be within a single ODM slice if less than the odm slice pixels + * (e.g., multi-plane scenario with ODM combine). */ + copy_width = vertical_access ? copy_src_lines : (unsigned int)math_ceil(math_min2(odm_slice_pixels, vp_width)); + copy_height = vertical_access ? (unsigned int)math_ceil(math_min2(odm_slice_pixels, vp_height)) : copy_src_lines; return calculate_tile_aligned_size(copy_width, copy_height, tile_width, tile_height, byte_per_pixel); } diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn6.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn6.c index 0bdf0d902aa0..23bd073f1889 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn6.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn6.c @@ -145,7 +145,7 @@ static const struct dml2_pmo_pstate_strategy base_pstate_strategy_list_4_display static const int base_pstate_strategy_list_4_display_size = sizeof(base_pstate_strategy_list_4_display) / sizeof(struct dml2_pmo_pstate_strategy); -static void dml2_pmo_dcn6_assign_pstate_strategies(struct dml2_pmo_instance *pmo) +void dml2_pmo_dcn6_assign_pstate_strategies(struct dml2_pmo_instance *pmo) { int i = 0; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn6.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn6.h index dd7d9f855988..b3b297aca47a 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn6.h +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn6.h @@ -6,6 +6,7 @@ #define __DML2_PMO_DCN6_H__ #include "dml2_internal_shared_types.h" +void dml2_pmo_dcn6_assign_pstate_strategies(struct dml2_pmo_instance *pmo); bool dml2_pmo_dcn6a_initialize(struct dml2_pmo_initialize_in_out *in_out); int dml2_pmo_dcn6a_get_ordered_mandatory_stage_optimizers(struct dml2_pmo_instance *pmo, struct dml2_pmo_stage_optimizer **optimers); diff --git a/drivers/gpu/drm/amd/display/dc/dml2_wrapper/dml21_wrapper/dml21_translation_helper.c b/drivers/gpu/drm/amd/display/dc/dml2_wrapper/dml21_wrapper/dml21_translation_helper.c index 366767f4413e..6a9f822b2b33 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_wrapper/dml21_wrapper/dml21_translation_helper.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_wrapper/dml21_wrapper/dml21_translation_helper.c @@ -828,6 +828,9 @@ static void populate_dml21_plane_config_from_plane_state(struct dml2_context *dm plane->composition.rect_out_height_spans_vactive = plane_state->dst_rect.height >= stream->src.height && stream->dst.height >= (int)stream->timing.v_addressable; + + if (plane_state->ctx->dc->debug.force_mpc_combine) + plane->overrides.mpcc_combine_factor = plane_state->ctx->dc->debug.force_mpc_combine; } //TODO : Could be possibly moved to a common helper layer. @@ -1027,8 +1030,8 @@ void dml21_copy_clocks_to_dc_state(struct dml2_context *in_ctx, struct dc_state context->bw_ctx.bw.dcn.clk.subvp_prefetch_dramclk_khz = in_ctx->v21.mode_programming.programming->min_clocks.dcn4x.svp_prefetch_no_throttle.uclk_khz; context->bw_ctx.bw.dcn.clk.subvp_prefetch_fclk_khz = in_ctx->v21.mode_programming.programming->min_clocks.dcn4x.svp_prefetch_no_throttle.fclk_khz; context->bw_ctx.bw.dcn.clk.utm_latency_ub_index = 0; /* TODO - derive from qos model */ - context->bw_ctx.bw.dcn.clk.utm_nominal_bandwidth_lb_Kbps = (unsigned int) in_ctx->v21.mode_programming.programming->qos_bound.bandwidth_lb.dcn5.non_urgent_bandwidth_kbps; - context->bw_ctx.bw.dcn.clk.utm_urgent_bandwidth_lb_Kbps = (unsigned int) in_ctx->v21.mode_programming.programming->qos_bound.bandwidth_lb.dcn5.urgent_bandwidth_kbps; + context->bw_ctx.bw.dcn.clk.utm_nominal_bandwidth_lb_KBps = (unsigned int) in_ctx->v21.mode_programming.programming->qos_bound.bandwidth_lb.dcn5.non_urgent_bandwidth_kbps; + context->bw_ctx.bw.dcn.clk.utm_urgent_bandwidth_lb_KBps = (unsigned int) in_ctx->v21.mode_programming.programming->qos_bound.bandwidth_lb.dcn5.urgent_bandwidth_kbps; context->bw_ctx.bw.dcn.clk.stutter_efficiency.base_efficiency = (uint8_t)in_ctx->v21.mode_programming.programming->stutter.base_percent_efficiency; context->bw_ctx.bw.dcn.clk.stutter_efficiency.low_power_efficiency = (uint8_t)in_ctx->v21.mode_programming.programming->stutter.low_power_percent_efficiency; context->bw_ctx.bw.dcn.clk.stutter_efficiency.z8_stutter_efficiency = (uint8_t)in_ctx->v21.mode_programming.programming->informative.power_management.z8.stutter_efficiency; @@ -1168,8 +1171,8 @@ void dml21_init_min_clocks_for_dc_state(struct dml2_context *in_ctx, struct dc_s min_clocks->subvp_prefetch_fclk_khz = 0; min_clocks->phyclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.phyclk.clk_values_khz[lowest_dpm_state_index]; min_clocks->utm_latency_ub_index = 0; /* TODO - derive from qos model */ - min_clocks->utm_nominal_bandwidth_lb_Kbps = 0; - min_clocks->utm_urgent_bandwidth_lb_Kbps = 0; + min_clocks->utm_nominal_bandwidth_lb_KBps = 0; + min_clocks->utm_urgent_bandwidth_lb_KBps = 0; min_clocks->stutter_efficiency.base_efficiency = 1; min_clocks->stutter_efficiency.low_power_efficiency = 1; min_clocks->stutter_efficiency.z8_stutter_efficiency = 1; diff --git a/drivers/gpu/drm/amd/display/dc/dmub_messenger/dmub_messenger.c b/drivers/gpu/drm/amd/display/dc/dmub_messenger/dmub_messenger.c new file mode 100644 index 000000000000..d99c1bd6e914 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dmub_messenger/dmub_messenger.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#include "dm_services.h" +#include "dc_dmub_srv.h" +#include "hwss/hw_sequencer.h" +#include "dmub_messenger/dmub_messenger.h" + +static enum dmub_msg_result dmub_inbox_cmd_send_and_wait( + struct dmub_messenger *messenger, + const struct dmub_send_cmd_params *params) +{ + if (!messenger || !messenger->ctx || !messenger->dc_dmub_srv || + !messenger->dc_dmub_srv->dmub || !params || + !params->cmd) + return DMUB_MSG_ERROR; + + if (messenger->dc_dmub_srv->idle_allowed && !messenger->ctx->dc) + return DMUB_MSG_ERROR; + + /* + * Transport only: copy the builder-built command through the + * injected DMUB service. Do not read the command header or payload. + */ + if (!dc_wake_and_execute_dmub_cmd(messenger->ctx, params->cmd, + params->wait_type)) + return DMUB_MSG_ERROR; + + return DMUB_MSG_OK; +} + +static enum dmub_msg_result dmub_gpint_send_and_wait( + struct dmub_messenger *messenger, + const struct dmub_gpint_params *params) +{ + struct dmub_srv *dmub; + + if (!messenger || !messenger->ctx || !messenger->dc_dmub_srv || + !messenger->dc_dmub_srv->dmub || !params || + !params->response) + return DMUB_MSG_ERROR; + + if (messenger->dc_dmub_srv->idle_allowed && !messenger->ctx->dc) + return DMUB_MSG_ERROR; + + dmub = messenger->dc_dmub_srv->dmub; + if (!dmub->sw_init || !dmub->hw_funcs.set_gpint || + !dmub->hw_funcs.is_gpint_acked || + !dmub->hw_funcs.get_gpint_response) + return DMUB_MSG_ERROR; + + /* + * Transport only: issue the builder-selected GPINT and write the + * raw response. Do not interpret the command or the result. + */ + if (!dc_wake_and_execute_gpint(messenger->ctx, + (enum dmub_gpint_command)params->command_code, + (uint16_t)params->param, params->response, + DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) + return DMUB_MSG_ERROR; + + return DMUB_MSG_OK; +} + +static const struct dmub_messenger_funcs dmub_messenger_funcs = { + .inbox_cmd_send_and_wait = dmub_inbox_cmd_send_and_wait, + .gpint_send_and_wait = dmub_gpint_send_and_wait, +}; + +void dmub_messenger_construct(struct dmub_messenger *messenger, + const struct dmub_messenger_init_data *init_data) +{ + if (!messenger) + return; + + messenger->funcs = &dmub_messenger_funcs; + messenger->ctx = init_data ? init_data->ctx : NULL; + messenger->dc_dmub_srv = init_data ? init_data->dc_dmub_srv : NULL; +} diff --git a/drivers/gpu/drm/amd/display/dc/dmub_messenger/dmub_messenger.h b/drivers/gpu/drm/amd/display/dc/dmub_messenger/dmub_messenger.h new file mode 100644 index 000000000000..6d3bf5791e28 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dmub_messenger/dmub_messenger.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#pragma once + +#include "dm_services_types.h" + +struct dc_context; +struct dc_dmub_srv; +struct dmub_gpint_params; +union dmub_rb_cmd; + +/* + * Live DMUB_SEND_DMCUB_CMD still carries wait_type. Distinct inbox + * primitives are unresolved in the DMUB Messenger spec, so this shim + * forwards the builder-selected wait without interpreting the command. + */ +struct dmub_send_cmd_params { + union dmub_rb_cmd *cmd; + enum dm_dmub_wait_type wait_type; +}; + +struct dmub_messenger_init_data { + struct dc_context *ctx; + struct dc_dmub_srv *dc_dmub_srv; +}; + +enum dmub_msg_result { + DMUB_MSG_OK, + DMUB_MSG_NO_MSG, + DMUB_MSG_TIMEOUT, + DMUB_MSG_ERROR, +}; + +struct dmub_messenger; + +struct dmub_messenger_funcs { + enum dmub_msg_result (*inbox_cmd_send_and_wait)( + struct dmub_messenger *messenger, + const struct dmub_send_cmd_params *params); + enum dmub_msg_result (*gpint_send_and_wait)( + struct dmub_messenger *messenger, + const struct dmub_gpint_params *params); +}; + +struct dmub_messenger { + const struct dmub_messenger_funcs *funcs; + struct dc_context *ctx; + struct dc_dmub_srv *dc_dmub_srv; +}; + +void dmub_messenger_construct(struct dmub_messenger *messenger, + const struct dmub_messenger_init_data *init_data); diff --git a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c index 95f8b7c7d657..66010841dcf8 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c @@ -552,6 +552,25 @@ void dal_gpio_destroy_ddc( *ddc = NULL; } +/* Switch the DDC pad to AUX mode, one time only. */ +void dal_gpio_ddc_open_aux_once( + struct gpio_service *service, + uint32_t offset, + uint32_t mask, + const struct gpio_ddc_hw_info *info) +{ + struct gpio_ddc_hw_info hw_info = *info; + struct ddc *ddc_pin; + + ddc_pin = dal_gpio_create_ddc(service, offset, mask, &hw_info); + if (!ddc_pin) + return; + + dal_ddc_open(ddc_pin, GPIO_MODE_HARDWARE, + GPIO_DDC_CONFIG_TYPE_MODE_AUX); + dal_gpio_destroy_ddc(&ddc_pin); +} + enum gpio_result dal_ddc_open( struct ddc *ddc, enum gpio_mode mode, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c index f2391d45d4c5..09692fc817f9 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c @@ -169,15 +169,11 @@ void dcn401_init_hw(struct dc *dc) //} // Set default OPTC memory power states - if (dc->debug.enable_mem_low_power.bits.optc) { - // Shutdown when unassigned and light sleep in VBLANK - REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1); - } + if (dc->debug.enable_mem_low_power.bits.optc) + dcn401_init_odm_mem_power(hws); - if (dc->debug.enable_mem_low_power.bits.vga) { - // Power down VGA memory - REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1); - } + if (dc->debug.enable_mem_low_power.bits.vga) + dcn401_power_down_vga_mem(hws); if (dc->ctx->dc_bios->fw_info_valid) { res_pool->ref_clocks.xtalin_clock_inKhz = @@ -367,7 +363,7 @@ void dcn401_init_hw(struct dc *dc) if (dc->res_pool->dccg && dc->res_pool->dccg->funcs && dc->res_pool->dccg->funcs->allow_clock_gating) dc->res_pool->dccg->funcs->allow_clock_gating(dc->res_pool->dccg, true); - REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); + dcn401_dcfclk_gating_control(hws, true); } dcn401_setup_hpo_hw_control(hws, true); @@ -818,15 +814,6 @@ enum dc_status dcn401_enable_stream_timing( hws->funcs.blank_pixel_data(dc, pipe_ctx, true); - /* Legacy code path will enable DSC during DPMS on sequence. Since DSC - * HW block programming is independent from link and stream encoder operations, it - * has moved to hwss and should be called when enabling/disabling OTG. - */ - if (stream->timing.flags.DSC && pipe_ctx->stream_res.dsc) { - if (dc->hwss.configure_dsc) - dc->hwss.configure_dsc(pipe_ctx, true); - } - /* VTG is within DCHUB command block. DCFCLK is always on */ if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(pipe_ctx->stream_res.tg)) { BREAK_TO_DEBUGGER(); @@ -981,6 +968,22 @@ void dcn401_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable) REG_UPDATE(HPO_TOP_HW_CONTROL, HPO_IO_EN, enable); } +void dcn401_init_odm_mem_power(struct dce_hwseq *hws) +{ + // Shutdown when unassigned and light sleep in VBLANK + REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1); +} + +void dcn401_power_down_vga_mem(struct dce_hwseq *hws) +{ + REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1); +} + +void dcn401_dcfclk_gating_control(struct dce_hwseq *hws, bool enable) +{ + REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, !enable); +} + void adjust_hotspot_between_slices_for_2x_magnify(uint32_t cursor_width, struct dc_cursor_position *pos_cpy) { if (cursor_width <= 128) { @@ -2125,15 +2128,6 @@ void dcn401_reset_back_end_for_pipe( pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg); - /* Legacy code path will enable DSC during DPMS on sequence. Since DSC - * HW block programming is independent from backend operations, it - * has moved to hwss and should be called when enabling/disabling OTG. - */ - if (pipe_ctx->stream_res.dsc) { - if (dc->hwss.configure_dsc) - dc->hwss.configure_dsc(pipe_ctx, false); - } - pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false); } if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass) diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h index 9df72e980e7a..d5853cd01a93 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h @@ -50,6 +50,9 @@ enum dc_status dcn401_enable_stream_timing( struct dc *dc); void dcn401_enable_stream(struct pipe_ctx *pipe_ctx); void dcn401_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable); +void dcn401_init_odm_mem_power(struct dce_hwseq *hws); +void dcn401_power_down_vga_mem(struct dce_hwseq *hws); +void dcn401_dcfclk_gating_control(struct dce_hwseq *hws, bool enable); void dcn401_disable_link_output(struct dc_link *link, const struct link_resource *link_res, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c index 1a387e52218d..dbeda44ebc8e 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c @@ -150,6 +150,10 @@ static const struct hwseq_private_funcs dcn401_private_funcs = { .plane_atomic_power_down = dcn401_plane_atomic_power_down, .plane_atomic_power_down_sequence = dcn401_plane_atomic_power_down_sequence, .enable_power_gating_plane = dcn32_enable_power_gating_plane, + .init_hpo_hw_control = dcn401_setup_hpo_hw_control, + .init_odm_mem_power = dcn401_init_odm_mem_power, + .power_down_vga_mem = dcn401_power_down_vga_mem, + .dcfclk_gating_control = dcn401_dcfclk_gating_control, .hubp_pg_control = dcn32_hubp_pg_control, .program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree, .program_all_writeback_pipes_in_tree_sequence = dcn401_program_all_writeback_pipes_in_tree_sequence, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c index c5fab430b7f7..f8254dfe1ce7 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c @@ -53,103 +53,6 @@ #define FN(reg_name, field_name) \ hws->shifts->field_name, hws->masks->field_name -bool dcn60_configure_dsc(struct pipe_ctx *pipe_ctx, bool enable) -{ - struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc; - struct dc *dc = pipe_ctx->stream->ctx->dc; - struct dc_stream_state *stream = pipe_ctx->stream; - struct pipe_ctx *odm_pipe; - struct dccg *dccg = dc->res_pool->dccg; - struct dsc_config dsc_cfg = {0}; - struct dsc_optc_config dsc_optc_cfg = {0}; - uint32_t odm_count = 1; - - /* It has been found that when DSCCLK is lower than 16Mhz, we will get DCN - * register access hung. When DSCCLk is based on refclk, DSCCLk is always a - * fixed value higher than 16Mhz so the issue doesn't occur. When DSCCLK is - * generated by DTO, DSCCLK would be based on 1/3 dispclk. For small timings - * with DSC such as 480p60Hz, the dispclk could be low enough to trigger - * this problem. We are implementing a workaround here to keep using dscclk - * based on fixed value refclk when timing is smaller than 3x16Mhz (i.e - * 48Mhz) pixel clock to avoid hitting this problem. - */ - bool use_dto = dccg->funcs->set_dto_dscclk && stream->timing.pix_clk_100hz > 480000; - - if (!dsc) - return false; - - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) - odm_count++; - - if (enable) { - dsc_cfg.pic_width = (stream->timing.h_addressable + - pipe_ctx->dsc_padding_params.dsc_hactive_padding + - stream->timing.h_border_left + stream->timing.h_border_right) / odm_count; - dsc_cfg.pic_height = stream->timing.v_addressable + - stream->timing.v_border_top + stream->timing.v_border_bottom; - dsc_cfg.pixel_encoding = stream->timing.pixel_encoding; - dsc_cfg.color_depth = stream->timing.display_color_depth; - dsc_cfg.is_odm = pipe_ctx->next_odm_pipe != NULL; - dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg; - ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % odm_count == 0); - dsc_cfg.dc_dsc_cfg.num_slices_h /= odm_count; - - if (use_dto) - dccg->funcs->set_dto_dscclk(dccg, dsc->inst, - (uint32_t)dsc_cfg.dc_dsc_cfg.num_slices_h); - if (!dsc->funcs->dsc_prepare_config(dsc, &dsc_cfg, &dsc_optc_cfg)) { - ASSERT(false); - return false; - } - dsc->funcs->dsc_set_config(dsc); - dsc->funcs->dsc_enable(dsc, (int)pipe_ctx->stream_res.opp->inst); - - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { - struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc; - - ASSERT(odm_dsc); - if (!odm_dsc) - return false; - if (use_dto) - dccg->funcs->set_dto_dscclk(dccg, odm_dsc->inst, - (uint32_t)dsc_cfg.dc_dsc_cfg.num_slices_h); - if (!odm_dsc->funcs->dsc_prepare_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg)) { - ASSERT(false); - return false; - } - odm_dsc->funcs->dsc_set_config(odm_dsc); - odm_dsc->funcs->dsc_enable(odm_dsc, (int)odm_pipe->stream_res.opp->inst); - } - - { - enum optc_dsc_mode mode = dsc_optc_cfg.is_pixel_format_444 ? - OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED; - - DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst); - pipe_ctx->stream_res.tg->funcs->set_dsc_config( - pipe_ctx->stream_res.tg, mode, - dsc_optc_cfg.bytes_per_pixel, dsc_optc_cfg.slice_width); - } - return true; - } - - DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst); - pipe_ctx->stream_res.tg->funcs->set_dsc_config( - pipe_ctx->stream_res.tg, OPTC_DSC_DISABLED, 0, 0); - - for (odm_pipe = pipe_ctx; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { - struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc; - - if (!odm_dsc) - continue; - odm_dsc->funcs->dsc_disconnect(odm_dsc); - odm_dsc->funcs->dsc_disable(odm_dsc); - if (dccg->funcs->set_ref_dscclk) - dccg->funcs->set_ref_dscclk(dccg, (uint32_t)odm_dsc->inst); - } - return true; -} - bool dcn60_set_rmcm_luts(struct set_input_transfer_func_params *params) { struct dpp *dpp_base = params->dpp; diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.h index 44eb30608feb..b880988ff1fc 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.h @@ -31,6 +31,5 @@ void dcn60_program_perfmon(struct dc *dc, struct dc_state *context); bool dcn60_apply_idle_power_optimizations(struct dc *dc, bool enable); bool dcn60_set_rmcm_luts(struct set_input_transfer_func_params *params); -bool dcn60_configure_dsc(struct pipe_ctx *pipe_ctx, bool enable); #endif /* __DC_HWSS_DCN60_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_init.c index 7b488753fe50..80125c3596ce 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_init.c @@ -25,7 +25,6 @@ static const struct hw_sequencer_funcs dcn60_funcs = { .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, .post_unlock_program_front_end = dcn50_post_unlock_program_front_end, .update_plane_addr = dcn20_update_plane_addr, - .configure_dsc = dcn60_configure_dsc, .prepare_plane_addr_update = dcn20_prepare_plane_addr_update, .update_dchub = dcn10_update_dchub, .update_pending_status = dcn10_update_pending_status, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h index 8f4ed80385fc..3ee6129a388d 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h @@ -63,6 +63,7 @@ struct hpo_frl_stream_encoder; struct link_training_settings; struct dc_link; struct dc_crtc_timing; +struct dmub_srv_hw_params; struct tg_lock_params { struct dc *dc; @@ -140,6 +141,147 @@ struct send_dmcub_cmd_params { struct dc_context *ctx; union dmub_rb_cmd *cmd; enum dm_dmub_wait_type wait_type; + bool continue_on_error; +}; + +struct dmub_gpint_params { + unsigned int command_code; + unsigned int param; + unsigned int *response; +}; + +struct psp_reload_dmub_fw_params { + struct dmub_srv *dmub; + const struct dmub_srv_hw_params *hw_params; +}; + +struct hwseq_reg_control_params { + struct dce_hwseq *hws; + bool enable; +}; + +struct dc_init_call_params { + struct dc *dc; + bool enable; +}; + +struct dccg_get_ref_freq_params { + struct dccg *dccg; + unsigned int xtalin_khz; + unsigned int *out_xtalin_khz; + unsigned int *out_dccg_ref_khz; +}; + +struct hubbub_get_dchub_ref_freq_params { + struct hubbub *hubbub; + unsigned int dccg_ref_khz; + unsigned int *out_dchub_ref_khz; +}; + +struct link_enc_hw_init_params { + struct link_encoder *link_enc; +}; + +struct link_enc_is_dig_enabled_params { + struct link_encoder *link_enc; + bool *out_dig_enabled; +}; + +struct link_enc_fec_is_active_params { + struct link_encoder *link_enc; + bool *out_fec_active; +}; + +struct clk_mgr_get_dispclk_from_dentist_params { + struct clk_mgr *clk_mgr; + int *out_dispclk_khz; +}; + +struct edp_control_params { + struct dc_link *link; + bool enable; +}; + +struct bios_get_i2c_info_params { + struct dc_bios *dcb; + struct graphics_object_id link_id; + struct graphics_object_i2c_info *out_info; + enum bp_result *out_result; +}; + +struct hubbub_allow_self_refresh_control_params { + struct hubbub *hubbub; + bool allow; +}; + +struct audio_hw_init_params { + struct audio *audio; +}; + +struct panel_cntl_hw_init_params { + struct panel_cntl *panel_cntl; + uint32_t *out_backlight; + uint32_t *out_user_level; +}; + +struct gpio_ddc_open_params { + struct gpio_service *gpio_service; + uint32_t clk_a_register_index; + uint32_t clk_a_mask; + struct gpio_ddc_hw_info hw_info; +}; + +struct abm_init_params { + struct abm *abm; + uint32_t backlight; + uint32_t user_level; +}; + +struct dio_set_mem_power_params { + struct dio *dio; + bool enable; +}; + +struct dccg_set_root_clock_gating_params { + struct dccg *dccg; + bool allow; +}; + +struct hubbub_init_watermarks_params { + struct hubbub *hubbub; +}; + +struct hubbub_init_crb_params { + struct hubbub *hubbub; +}; + +struct hubbub_set_request_limit_params { + struct hubbub *hubbub; + unsigned int num_chans; + unsigned int words_per_umc; +}; + +struct clk_mgr_initialize_min_clocks_params { + struct clk_mgr *clk_mgr; + struct dc_state *context; + int dcfclk_deep_sleep_khz; + int dcfclk_khz; + int socclk_khz; + int dramclk_khz; + int dppclk_khz; + int dispclk_khz; + int ref_dtbclk_khz; + bool fclk_p_state_change_support; + bool p_state_change_support; +}; + +struct clk_mgr_notify_wm_ranges_params { + struct clk_mgr *clk_mgr; +}; + +struct bios_is_accelerated_mode_params { + struct dc_bios *dcb; + bool *out_accelerated_mode; }; struct lsdma_send_pio_copy_params { @@ -1003,6 +1145,19 @@ struct clk_mgr_update_clocks_params { struct clk_mgr *clk_mgr; }; +struct legacy_clk_mgr_init_clocks_params { + struct clk_mgr *clk_mgr; +}; + +struct legacy_clk_mgr_is_dc_mode_present_params { + struct clk_mgr *clk_mgr; + bool *out_dcmode_power_limits_present; +}; + +struct dccg_initialize_clocks_params { + struct dccg *dccg; +}; + struct hubbub_program_watermarks_params { struct dc *dc; struct hubbub *hubbub; @@ -1198,6 +1353,40 @@ union block_sequence_params { struct link_set_dpms_on_params link_set_dpms_on_params; struct clk_mgr_set_max_memclk_params clk_mgr_set_max_memclk_params; struct clk_mgr_update_clocks_params clk_mgr_update_clocks_params; + struct legacy_clk_mgr_init_clocks_params + legacy_clk_mgr_init_clocks_params; + struct legacy_clk_mgr_is_dc_mode_present_params + legacy_clk_mgr_is_dc_mode_present_params; + struct dccg_initialize_clocks_params dccg_initialize_clocks_params; + struct dmub_gpint_params dmub_gpint_params; + struct psp_reload_dmub_fw_params psp_reload_dmub_fw_params; + struct hwseq_reg_control_params hwseq_reg_control_params; + struct dc_init_call_params dc_init_call_params; + struct dccg_get_ref_freq_params dccg_get_ref_freq_params; + struct hubbub_get_dchub_ref_freq_params hubbub_get_dchub_ref_freq_params; + struct link_enc_hw_init_params link_enc_hw_init_params; + struct link_enc_is_dig_enabled_params link_enc_is_dig_enabled_params; + struct link_enc_fec_is_active_params link_enc_fec_is_active_params; + struct clk_mgr_get_dispclk_from_dentist_params + clk_mgr_get_dispclk_from_dentist_params; + struct edp_control_params edp_control_params; + struct bios_get_i2c_info_params bios_get_i2c_info_params; + struct hubbub_allow_self_refresh_control_params + hubbub_allow_self_refresh_control_params; + struct audio_hw_init_params audio_hw_init_params; + struct panel_cntl_hw_init_params panel_cntl_hw_init_params; + struct gpio_ddc_open_params gpio_ddc_open_params; + struct abm_init_params abm_init_params; + struct dio_set_mem_power_params dio_set_mem_power_params; + struct dccg_set_root_clock_gating_params + dccg_set_root_clock_gating_params; + struct hubbub_init_watermarks_params hubbub_init_watermarks_params; + struct hubbub_init_crb_params hubbub_init_crb_params; + struct hubbub_set_request_limit_params hubbub_set_request_limit_params; + struct clk_mgr_initialize_min_clocks_params + clk_mgr_initialize_min_clocks_params; + struct clk_mgr_notify_wm_ranges_params clk_mgr_notify_wm_ranges_params; + struct bios_is_accelerated_mode_params bios_is_accelerated_mode_params; struct hubbub_program_watermarks_params hubbub_program_watermarks_params; struct hubbub_program_arbiter_params hubbub_program_arbiter_params; struct hubbub_program_compbuf_segments_params hubbub_program_compbuf_segments_params; @@ -1368,6 +1557,45 @@ enum block_sequence_func { HUBBUB_PERFMON_GET_URGENT_ASSERTION_COUNT, HUBBUB_PERFMON_GET_PREFETCH_DATA_SIZE, HUBBUB_PERFMON_GET_URGENT_RAMP_LATENCY, + LEGACY_CLK_MGR_INIT_CLOCKS, + LEGACY_CLK_MGR_IS_DC_MODE_PRESENT, + DCCG_INITIALIZE_CLOCKS, + DMUB_GPINT_SEND_AND_WAIT, + DMUB_HALT_FW, + PSP_RELOAD_DMUB_FW, + DMUB_INITIALIZE_DCN, + OPTC_SET_ODM_MEM_POWER, + MMHUBBUB_SET_MEM_POWER, + DCCG_GET_REF_FREQ, + HUBBUB_GET_DCHUB_REF_FREQ, + DIO_LINK_ENC_HW_INIT, + DIO_LINK_ENC_IS_DIG_ENABLED, + DIO_LINK_ENC_FEC_IS_ACTIVE, + BIOS_GET_I2C_INFO, + PG_SET_PLANE_POWER_GATING, + LINK_BLANK_ALL_DP_DISPLAYS, + HWSS_ENABLE_ACCELERATED_MODE, + HWSEQ_INIT_PIPES, + HUBBUB_ALLOW_SELF_REFRESH_CONTROL, + CLK_MGR_GET_DISPCLK_FROM_DENTIST, + LEGACY_CLK_MGR_INITIALIZE_MIN_CLOCKS, + DMUB_SET_IDLE_OPTIMIZATION, + EDP_BACKLIGHT_CONTROL, + HWSEQ_POWER_DOWN, + EDP_POWER_CONTROL, + AUDIO_HW_INIT, + PANEL_CNTL_HW_INIT, + GPIO_DDC_OPEN, + ABM_INIT, + DIO_AFMT_SET_MEM_POWER, + DCCG_SET_ROOT_CLOCK_GATING, + DCCG_SET_DCFCLK_GATING, + HPO_SET_HW_CONTROL, + HUBBUB_INIT_WATERMARKS, + LEGACY_CLK_MGR_NOTIFY_WM_RANGES, + HUBBUB_INIT_CRB, + HUBBUB_SET_REQUEST_LIMIT, + BIOS_IS_ACCELERATED_MODE, /* This must be the last value in this enum, add new ones above */ HWSS_BLOCK_SEQUENCE_FUNC_COUNT }; @@ -1413,7 +1641,6 @@ struct hw_sequencer_funcs { struct dc_state *context); void (*update_plane_addr)(const struct dc *dc, struct pipe_ctx *pipe_ctx); - bool (*configure_dsc)(struct pipe_ctx *pipe_ctx, bool enable); void (*prepare_plane_addr_update)(const struct dc *dc, struct pipe_ctx *pipe_ctx, struct dc_plane_address *addr_to_program, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h index 9c5e9abf5a95..91a84fb50b59 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h @@ -203,6 +203,14 @@ struct hwseq_private_funcs { void (*PLAT_58856_wa)(struct dc_state *context, struct pipe_ctx *pipe_ctx); void (*setup_hpo_hw_control)(const struct dce_hwseq *hws, bool enable); + /* + * Init-time only. setup_hpo_hw_control also drives the HPO toggle + * on every commit, so a DCN that leaves it unset keeps it unset. + */ + void (*init_hpo_hw_control)(const struct dce_hwseq *hws, bool enable); + void (*init_odm_mem_power)(struct dce_hwseq *hws); + void (*power_down_vga_mem)(struct dce_hwseq *hws); + void (*dcfclk_gating_control)(struct dce_hwseq *hws, bool enable); void (*enable_plane)(struct dc *dc, struct pipe_ctx *pipe_ctx, struct dc_state *context); void (*program_mall_pipe_config)(struct dc *dc, struct dc_state *context); diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index 6563eaaa0c0c..695eaa5cbf65 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -40,6 +40,7 @@ #include "mcif_wb.h" #include "panel_cntl.h" #include "dmub/inc/dmub_cmd.h" +#include "bls_builder/bls_builder_legacy_init.h" #include "pg_cntl.h" #include "sspl/dc_spl.h" @@ -722,6 +723,12 @@ struct dc_state { } perf_params; enum dc_power_source_type power_source; + + /** + * @hw_init_info: DC2_DC1_Wrapped hardware init progress and the + * outputs of each stage run so far + */ + struct bls_builder_legacy_hw_init_info hw_init_info; }; struct replay_context { diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h index f3ef5bbfad81..1c95d643af14 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h @@ -117,6 +117,8 @@ struct link_enc_state { uint32_t dphy_fec_ready_shadow; uint32_t dphy_fec_active_status; uint32_t dp_link_training_complete; + uint32_t rdpcs_phy_reset; + uint32_t rdpcs_tx_data_en; }; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h b/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h index 75ebfab87efc..a0a8ab195533 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h @@ -298,6 +298,7 @@ struct mpcc_state { uint32_t overlap_only; uint32_t idle; uint32_t busy; + uint32_t cur_vupdate_lock; uint32_t shaper_lut_mode; uint32_t lut3d_mode; uint32_t lut3d_bit_depth; diff --git a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c index d3172dbdcdf0..83f676a49fd1 100644 --- a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c +++ b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c @@ -80,6 +80,7 @@ static void dp_retrain_link_dp_test(struct dc_link *link, struct dc_stream_state *streams_on_link[MAX_PIPES]; int num_streams_on_link = 0; struct dc *dc = (struct dc *)link->dc; + struct dc_surface_update *srf_updates; needs_divider_update = (link->dc->link_srv->dp_get_encoding_format(link_setting) != link->dc->link_srv->dp_get_encoding_format((const struct dc_link_settings *) &link->cur_link_settings)) @@ -151,13 +152,29 @@ static void dp_retrain_link_dp_test(struct dc_link *link, streams_on_link[num_streams_on_link++] = state->streams[i]; } + srf_updates = kcalloc(MAX_SURFACES, sizeof(*srf_updates), GFP_KERNEL); + for (i = 0; i < num_streams_on_link; i++) { if (streams_on_link[i] && streams_on_link[i]->link && streams_on_link[i]->link == link) { + struct dc_stream_status *stream_status = dc_stream_get_status(streams_on_link[i]); + int surface_count = 0; + int j; + + if (srf_updates && stream_status) { + memset(srf_updates, 0, MAX_SURFACES * sizeof(*srf_updates)); + for (j = 0; j < stream_status->plane_count; j++) + srf_updates[j].surface = stream_status->plane_states[j]; + surface_count = stream_status->plane_count; + } + stream_update.stream = streams_on_link[i]; stream_update.dpms_off = &dpms_off; - dc_update_planes_and_stream(dc, NULL, 0, streams_on_link[i], &stream_update); + dc_update_planes_and_stream(dc, srf_updates, surface_count, + streams_on_link[i], &stream_update); } } + + kfree(srf_updates); } static void dp_test_send_link_training(struct dc_link *link) diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c index 9b5b0599d977..75e232ebffe8 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c @@ -717,94 +717,21 @@ static bool dp_set_hblank_reduction_on_rx(struct pipe_ctx *pipe_ctx) return result; } -/* TODO - There is overlapping functionality between link_set_dsc_pps_packet, - * and set_encoder_dsc_config, the two functions should be refactored to avoid code duplication. - */ -static void set_encoder_dsc_config(struct pipe_ctx *pipe_ctx, - struct dsc_config *dsc_cfg, - struct dsc_optc_config *dsc_optc_cfg, - bool enable) -{ - struct dc *dc = pipe_ctx->stream->ctx->dc; - struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc; - struct dc_stream_state *stream = pipe_ctx->stream; - enum optc_dsc_mode optc_dsc_mode; - int odm_count = 1; - struct pipe_ctx *odm_pipe; - DC_LOGGER_INIT(dsc->ctx->logger); - - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) - odm_count++; - - if (enable) { - optc_dsc_mode = dsc_optc_cfg->is_pixel_format_444 ? - OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED; - - if (dc_is_dp_signal(stream->signal) && !dp_is_128b_132b_signal(pipe_ctx)) { - DC_LOG_DSC("Setting stream encoder DSC config for engine %d:", (int)pipe_ctx->stream_res.stream_enc->id); - dsc_optc_config_log(dsc, dsc_optc_cfg); - if (pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config) - pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(pipe_ctx->stream_res.stream_enc, - optc_dsc_mode, - dsc_optc_cfg->bytes_per_pixel, - dsc_optc_cfg->slice_width); - - /* PPS SDP is set elsewhere because it has to be done after DIG FE is connected to DIG BE */ - } else if (dc_is_hdmi_frl_signal(stream->signal)) { - uint8_t dsc_packed_pps[128]; - struct dc_crtc_timing patched_crtc_timing = stream->timing; - - DC_LOG_DSC("Setting stream encoder DSC config for engine %d:", (int)pipe_ctx->stream_res.hpo_frl_stream_enc->id); - dsc_optc_config_log(dsc, dsc_optc_cfg); - dsc_cfg->dc_dsc_cfg.num_slices_h *= odm_count; - dsc_cfg->pic_width *= odm_count; - dsc_cfg->dsc_padding = pipe_ctx->dsc_padding_params.dsc_hactive_padding; - if (dc->debug.enable_hblank_borrow) - dsc_cfg->pic_width = stream->timing.h_addressable; - dsc->funcs->dsc_get_packed_pps(dsc, dsc_cfg, &dsc_packed_pps[0]); - pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->hdmi_frl_set_dsc_config( - pipe_ctx->stream_res.hpo_frl_stream_enc, &patched_crtc_timing, &dsc_packed_pps[0]); - } - - return; - } - if (dc_is_dp_signal(stream->signal)) { - if (dp_is_128b_132b_signal(pipe_ctx)) - pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet( - pipe_ctx->stream_res.hpo_dp_stream_enc, - false, - NULL, - true); - else { - if (pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config) - pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config( - pipe_ctx->stream_res.stream_enc, - OPTC_DSC_DISABLED, 0, 0); - pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet( - pipe_ctx->stream_res.stream_enc, false, NULL, true); - } - } else if (dc_is_hdmi_frl_signal(stream->signal)) { - pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->hdmi_frl_set_dsc_config( - pipe_ctx->stream_res.hpo_frl_stream_enc, &stream->timing, NULL); - } -} - -/* Legacy implementation of DSC configuration sequence. DSC HW block programming - * is independent of stream encoder and link configuration operations, and should - * be configured separately during front-end programming, not within link DPMS sequences. +/* The stream with these settings can be sent (unblanked) only after DSC was enabled on RX first, + * i.e. after dp_enable_dsc_on_rx() had been called */ -static bool configure_dsc_hw_block(struct pipe_ctx *pipe_ctx, bool enable, - struct dsc_config *dsc_cfg, struct dsc_optc_config *dsc_optc_cfg) +void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) { + /* TODO: Move this to HWSS as this is hardware programming sequence not a + * link layer sequence + */ struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc; struct dc *dc = pipe_ctx->stream->ctx->dc; struct dc_stream_state *stream = pipe_ctx->stream; struct pipe_ctx *odm_pipe; - struct dccg *dccg = dc->res_pool->dccg; int opp_cnt = 1; - DC_LOGGER_INIT(dsc->ctx->logger); - + struct dccg *dccg = dc->res_pool->dccg; /* It has been found that when DSCCLK is lower than 16Mhz, we will get DCN * register access hung. When DSCCLk is based on refclk, DSCCLk is always a * fixed value higher than 16Mhz so the issue doesn't occur. When DSCCLK is @@ -814,34 +741,35 @@ static bool configure_dsc_hw_block(struct pipe_ctx *pipe_ctx, bool enable, * based on fixed value refclk when timing is smaller than 3x16Mhz (i.e * 48Mhz) pixel clock to avoid hitting this problem. */ - bool should_use_dto_dscclk = dccg->funcs->set_dto_dscclk && + bool should_use_dto_dscclk = (dccg->funcs->set_dto_dscclk != NULL) && stream->timing.pix_clk_100hz > 480000; + DC_LOGGER_INIT(dsc->ctx->logger); for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) opp_cnt++; if (enable) { + struct dsc_config dsc_cfg; + struct dsc_optc_config dsc_optc_cfg = {0}; enum optc_dsc_mode optc_dsc_mode; - memset(dsc_cfg, 0, sizeof(*dsc_cfg)); - memset(dsc_optc_cfg, 0, sizeof(*dsc_optc_cfg)); /* Enable DSC hw block */ - dsc_cfg->pic_width = (stream->timing.h_addressable + pipe_ctx->dsc_padding_params.dsc_hactive_padding + + dsc_cfg.pic_width = (stream->timing.h_addressable + pipe_ctx->dsc_padding_params.dsc_hactive_padding + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt; - dsc_cfg->pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom; - dsc_cfg->pixel_encoding = stream->timing.pixel_encoding; - dsc_cfg->color_depth = stream->timing.display_color_depth; - dsc_cfg->is_odm = pipe_ctx->next_odm_pipe != NULL; - dsc_cfg->dc_dsc_cfg = stream->timing.dsc_cfg; - ASSERT(dsc_cfg->dc_dsc_cfg.num_slices_h % opp_cnt == 0); - dsc_cfg->dc_dsc_cfg.num_slices_h /= opp_cnt; - dsc_cfg->dsc_padding = 0; + dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom; + dsc_cfg.pixel_encoding = stream->timing.pixel_encoding; + dsc_cfg.color_depth = stream->timing.display_color_depth; + dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false; + dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg; + ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0); + dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt; + dsc_cfg.dsc_padding = 0; if (should_use_dto_dscclk) - dccg->funcs->set_dto_dscclk(dccg, dsc->inst, dsc_cfg->dc_dsc_cfg.num_slices_h); - if (!dsc->funcs->dsc_prepare_config(dsc, dsc_cfg, dsc_optc_cfg)) { + dccg->funcs->set_dto_dscclk(dccg, dsc->inst, dsc_cfg.dc_dsc_cfg.num_slices_h); + if (!dsc->funcs->dsc_prepare_config(dsc, &dsc_cfg, &dsc_optc_cfg)) { ASSERT(false); - return false; + return; } dsc->funcs->dsc_set_config(dsc); dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst); @@ -850,92 +778,110 @@ static bool configure_dsc_hw_block(struct pipe_ctx *pipe_ctx, bool enable, ASSERT(odm_dsc); if (!odm_dsc) - return false; + return; if (should_use_dto_dscclk) - dccg->funcs->set_dto_dscclk(dccg, odm_dsc->inst, - dsc_cfg->dc_dsc_cfg.num_slices_h); - if (!odm_dsc->funcs->dsc_prepare_config(odm_dsc, dsc_cfg, dsc_optc_cfg)) { + dccg->funcs->set_dto_dscclk(dccg, odm_dsc->inst, dsc_cfg.dc_dsc_cfg.num_slices_h); + if (!odm_dsc->funcs->dsc_prepare_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg)) { ASSERT(false); - return false; + return; } odm_dsc->funcs->dsc_set_config(odm_dsc); odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst); } - optc_dsc_mode = dsc_optc_cfg->is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED; + dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt; + dsc_cfg.pic_width *= opp_cnt; + dsc_cfg.dsc_padding = pipe_ctx->dsc_padding_params.dsc_hactive_padding; - /* Enable DSC in OPTC */ - DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst); - dsc_optc_config_log(dsc, dsc_optc_cfg); - pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg, - optc_dsc_mode, - dsc_optc_cfg->bytes_per_pixel, - dsc_optc_cfg->slice_width); - return true; - } + optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED; - /* disable DSC in OPTC */ - pipe_ctx->stream_res.tg->funcs->set_dsc_config( - pipe_ctx->stream_res.tg, - OPTC_DSC_DISABLED, 0, 0); + /* Enable DSC in encoder */ + if (dc_is_dp_signal(stream->signal) && !dp_is_128b_132b_signal(pipe_ctx)) { + DC_LOG_DSC("Setting stream encoder DSC config for engine %d:", (int)pipe_ctx->stream_res.stream_enc->id); + dsc_optc_config_log(dsc, &dsc_optc_cfg); + if (pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config) + pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(pipe_ctx->stream_res.stream_enc, + optc_dsc_mode, + dsc_optc_cfg.bytes_per_pixel, + dsc_optc_cfg.slice_width); - for (odm_pipe = pipe_ctx; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { - odm_pipe->stream_res.dsc->funcs->dsc_disconnect(odm_pipe->stream_res.dsc); + /* PPS SDP is set elsewhere because it has to be done after DIG FE is connected to DIG BE */ + } else if (dc_is_hdmi_frl_signal(stream->signal)) { + uint8_t dsc_packed_pps[128]; + struct dc_crtc_timing patched_crtc_timing = stream->timing; - /* - * dsc_disconnect is a double buffered register. - * by the time we call dsc_disable, dsc may still remain - * connected to OPP. In this case OPTC will no longer - * get correct pixel data because DSCC is off. However - * we also can't wait for the disconnect pending - * complete, because this function can be called - * with/without OTG master lock acquired. When the lock - * is acquired we will never get pending complete until - * we release the lock later. So there is no easy way to - * solve this problem especially when the lock is - * acquired. DSC is a front end hw block it should be - * programmed as part of front end sequence, where the - * commit sequence without lock and update sequence - * with lock are completely separated. However because - * we are programming dsc as part of back end link - * programming sequence, we don't know if front end OPTC - * master lock is acquired. The back end should be - * agnostic to front end lock. DSC programming shouldn't - * belong to this sequence. - */ - odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc); - if (dccg->funcs->set_ref_dscclk) - dccg->funcs->set_ref_dscclk(dccg, odm_pipe->stream_res.dsc->inst); - } - return true; -} + DC_LOG_DSC("Setting stream encoder DSC config for engine %d:", (int)pipe_ctx->stream_res.hpo_frl_stream_enc->id); + dsc_optc_config_log(dsc, &dsc_optc_cfg); -/* The stream with these settings can be sent (unblanked) only after DSC was enabled on RX first, - * i.e. after dp_enable_dsc_on_rx() had been called - */ -void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) -{ - struct dc *dc = pipe_ctx->stream->ctx->dc; - struct dsc_config dsc_cfg = {0}; - struct dsc_optc_config dsc_optc_cfg = {0}; + /* if we are borrowing from hblank, h_addressable and pic_width need to be adjusted */ + if (dc->debug.enable_hblank_borrow) { + dsc_cfg.pic_width = stream->timing.h_addressable; + } - if (!pipe_ctx->stream_res.dsc) { - ASSERT(false); - return; - } + dsc->funcs->dsc_get_packed_pps(dsc, &dsc_cfg, &dsc_packed_pps[0]); + pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->hdmi_frl_set_dsc_config( + pipe_ctx->stream_res.hpo_frl_stream_enc, &patched_crtc_timing, &dsc_packed_pps[0]); + } - if (dc->hwss.configure_dsc) { - /* If the hwss configure_dsc function is supported, then DSC will be programmed - * in the same sequence of OTG enable/disable. Thus, we don't need to configure - * the DSC hw block here. - */ - set_encoder_dsc_config(pipe_ctx, &dsc_cfg, &dsc_optc_cfg, false); + /* Enable DSC in OPTC */ + DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst); + dsc_optc_config_log(dsc, &dsc_optc_cfg); + pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg, + optc_dsc_mode, + dsc_optc_cfg.bytes_per_pixel, + dsc_optc_cfg.slice_width); } else { - if (enable) { - if (configure_dsc_hw_block(pipe_ctx, true, &dsc_cfg, &dsc_optc_cfg)) - set_encoder_dsc_config(pipe_ctx, &dsc_cfg, &dsc_optc_cfg, true); - } else { - set_encoder_dsc_config(pipe_ctx, &dsc_cfg, &dsc_optc_cfg, false); - configure_dsc_hw_block(pipe_ctx, false, &dsc_cfg, &dsc_optc_cfg); + /* disable DSC in OPTC */ + pipe_ctx->stream_res.tg->funcs->set_dsc_config( + pipe_ctx->stream_res.tg, + OPTC_DSC_DISABLED, 0, 0); + + /* disable DSC in stream encoder */ + if (dc_is_dp_signal(stream->signal)) { + if (dp_is_128b_132b_signal(pipe_ctx)) + pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet( + pipe_ctx->stream_res.hpo_dp_stream_enc, + false, + NULL, + true); + else { + if (pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config) + pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config( + pipe_ctx->stream_res.stream_enc, + OPTC_DSC_DISABLED, 0, 0); + pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet( + pipe_ctx->stream_res.stream_enc, false, NULL, true); + } + } else if (dc_is_hdmi_frl_signal(stream->signal)) + pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->hdmi_frl_set_dsc_config( + pipe_ctx->stream_res.hpo_frl_stream_enc, &stream->timing, NULL); + + /* disable DSC block */ + for (odm_pipe = pipe_ctx; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + odm_pipe->stream_res.dsc->funcs->dsc_disconnect(odm_pipe->stream_res.dsc); + /* + * TODO - dsc_disconnect is a double buffered register. + * by the time we call dsc_disable, dsc may still remain + * connected to OPP. In this case OPTC will no longer + * get correct pixel data because DSCC is off. However + * we also can't wait for the disconnect pending + * complete, because this function can be called + * with/without OTG master lock acquired. When the lock + * is acquired we will never get pending complete until + * we release the lock later. So there is no easy way to + * solve this problem especially when the lock is + * acquired. DSC is a front end hw block it should be + * programmed as part of front end sequence, where the + * commit sequence without lock and update sequence + * with lock are completely separated. However because + * we are programming dsc as part of back end link + * programming sequence, we don't know if front end OPTC + * master lock is acquired. The back end should be + * agnostic to front end lock. DSC programming shouldn't + * belong to this sequence. + */ + odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc); + if (dccg->funcs->set_ref_dscclk) + dccg->funcs->set_ref_dscclk(dccg, odm_pipe->stream_res.dsc->inst); } } } diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn10/dcn10_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn10/dcn10_mpc.c index f9bd1d6e1642..a737887b7c71 100644 --- a/drivers/gpu/drm/amd/display/dc/mpc/dcn10/dcn10_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn10/dcn10_mpc.c @@ -453,6 +453,8 @@ void mpc1_read_mpcc_state( MPCC_BLND_ACTIVE_OVERLAP_ONLY, &s->overlap_only); REG_GET_2(MPCC_STATUS[mpcc_inst], MPCC_IDLE, &s->idle, MPCC_BUSY, &s->busy); + if (s->opp_id < MAX_OPP && mpc10->mpc_regs->CUR[s->opp_id]) + REG_GET(CUR[s->opp_id], CUR_VUPDATE_LOCK_SET, &s->cur_vupdate_lock); } void mpc1_cursor_lock(struct mpc *mpc, int opp_id, bool lock) diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.c index 5f5c27eb1d64..a485db71c166 100644 --- a/drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.c @@ -627,7 +627,7 @@ void mpc401_get_lut_mode(struct mpc *mpc, } } -static void mpc401_read_mpcc_state( +void mpc401_read_mpcc_state( struct mpc *mpc, int mpcc_inst, struct mpcc_state *s) diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.h b/drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.h index 75fa05ed2b22..2731045f277c 100644 --- a/drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.h +++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.h @@ -275,4 +275,9 @@ void mpc401_update_3dlut_fast_load_select( int mpcc_id, int hubp_idx); +void mpc401_read_mpcc_state( + struct mpc *mpc, + int mpcc_inst, + struct mpcc_state *s); + #endif diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.c index 37d024cfb3fb..f15690b026cc 100644 --- a/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.c @@ -65,16 +65,8 @@ void mpc42_update_blending( -void mpc42_read_mpcc_state( - struct mpc *mpc, - int mpcc_inst, - struct mpcc_state *s) -{ - mpc1_read_mpcc_state(mpc, mpcc_inst, s); -} - static const struct mpc_funcs dcn42_mpc_funcs = { - .read_mpcc_state = mpc42_read_mpcc_state, + .read_mpcc_state = mpc401_read_mpcc_state, .insert_plane = mpc1_insert_plane, .remove_mpcc = mpc1_remove_mpcc, .mpc_init = mpc32_mpc_init, diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.c index e38582f0a319..89c4d431a82c 100644 --- a/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.c @@ -229,7 +229,7 @@ static bool mpc60_program_3dlut( } static const struct mpc_funcs dcn60_mpc_funcs = { - .read_mpcc_state = mpc1_read_mpcc_state, + .read_mpcc_state = mpc401_read_mpcc_state, .insert_plane = mpc60_insert_plane, .remove_mpcc = mpc1_remove_mpcc, .mpc_init = mpc32_mpc_init, diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c index b78b0541d113..19e175f54f68 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c @@ -307,19 +307,23 @@ static struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[5]; #define link_regs_init(id, phyid) \ LE_DCN401_REG_LIST_RI(id), \ - LE_DCN60_REG_LIST_RI(id) + LE_DCN60_REG_LIST_RI(id), \ + SRI_ARR(RDPCSTX_PHY_CNTL0, RDPCSTX, id), \ + SRI_ARR(RDPCSTX_PHY_CNTL3, RDPCSTX, id) static struct dcn10_link_enc_registers link_enc_regs[4]; static const struct dcn10_link_enc_shift le_shift = { LINK_ENCODER_MASK_SH_LIST_DCN401(__SHIFT), \ - LINK_ENCODER_MASK_SH_LIST_DCN60_ON_DCN401(__SHIFT) + LINK_ENCODER_MASK_SH_LIST_DCN60_ON_DCN401(__SHIFT), \ + LINK_ENCODER_PHY_STATE_MASK_SH_LIST_DCN401(__SHIFT) }; static const struct dcn10_link_enc_mask le_mask = { LINK_ENCODER_MASK_SH_LIST_DCN401(_MASK), \ - LINK_ENCODER_MASK_SH_LIST_DCN60_ON_DCN401(_MASK) + LINK_ENCODER_MASK_SH_LIST_DCN60_ON_DCN401(_MASK), \ + LINK_ENCODER_PHY_STATE_MASK_SH_LIST_DCN401(_MASK) }; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c index e172163942b4..2ad191ec5c38 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c @@ -816,7 +816,6 @@ static const struct dc_debug_options debug_defaults_drv = { .min_deep_sleep_dcfclk_khz = 8000, .replay_skip_crtc_disabled = true, .psr_skip_crtc_disable = true, - .force_odm2to1_for_edp_pixclk_mhz = 0, // disable the policy for now .iommu_mismatch_temp_wka = 0x7, }; @@ -1885,10 +1884,6 @@ enum dc_status dcn42_validate_bandwidth(struct dc *dc, bool out = false; DC_FP_START(); - if (validate_mode == DC_VALIDATE_MODE_AND_PROGRAMMING) { - /*only do this when programing HW*/ - dcn42_decide_odm_override(dc, context); - } out = dml2_validate(dc, context, context->bw_ctx.dml2, validate_mode); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource_fpu.c b/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource_fpu.c index ee330559c233..33b9775420d3 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource_fpu.c @@ -45,25 +45,3 @@ void dcn42_decide_zstate_support(struct dc *dc, struct dc_state *context) context->bw_ctx.bw.dcn.clk.zstate_support = support; } - -bool dcn42_decide_odm_override(struct dc *dc, struct dc_state *context) -{ - bool odm_override = false; - - DC_LOGGER_INIT(dc->ctx->logger); - if (dc->ctx->dce_environment == DCE_ENV_DIAG) - return false; - - if (context->stream_count == 1 && context->streams[0]->signal == SIGNAL_TYPE_EDP) { - - if (dc->debug.force_odm2to1_for_edp_pixclk_mhz != 0 && - context->streams[0]->timing.pix_clk_100hz > dc->debug.force_odm2to1_for_edp_pixclk_mhz * 10000) { - odm_override = true; - context->streams[0]->debug.force_odm_combine_segments = 2; - } - DC_LOG_SMU("odm_override: %d, eDP pixelclock: %d, force_odm2to1_for_edp_pixclk_mhz: %d\n", - odm_override, context->streams[0]->timing.pix_clk_100hz / 10000, dc->debug.force_odm2to1_for_edp_pixclk_mhz); - } - return odm_override; -} - diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource_fpu.h b/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource_fpu.h index aff7be777681..81693c88443e 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource_fpu.h +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource_fpu.h @@ -29,5 +29,4 @@ #include "core_types.h" void dcn42_decide_zstate_support(struct dc *dc, struct dc_state *context); -bool dcn42_decide_odm_override(struct dc *dc, struct dc_state *context); #endif /* _DCN42_RESOURCE_FPU_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/workaround_manager/workaround_manager.c b/drivers/gpu/drm/amd/display/dc/workaround_manager/workaround_manager.c new file mode 100644 index 000000000000..067a7069186b --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/workaround_manager/workaround_manager.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#include "dm_services.h" +#include "workaround_manager/workaround_manager.h" + +static const struct workaround_manager dc2_wam_empty = { + .registry = NULL, + .count = 0, +}; + +/* BSS, not the stack: 64 block_sequence entries exceed the kernel frame limit. */ +static struct block_sequence dc2_wam_saved_steps[DC2_BLS_MAX_STEPS]; + +const struct workaround_manager *dc2_workaround_manager_get(void) +{ + return &dc2_wam_empty; +} + +enum workaround_manager_result workaround_manager_apply( + const struct workaround_manager *wam, + struct block_sequence_state *bls, + const struct workaround_context *ctx) +{ + struct block_sequence *saved_steps = dc2_wam_saved_steps; + enum workaround_manager_result result; + unsigned int saved_num; + unsigned int i; + + if (!wam || !bls || !bls->steps || !bls->num_steps || !ctx || + *bls->num_steps > MAX_HWSS_BLOCK_SEQUENCE_SIZE || + (wam->count && !wam->registry)) + return WAM_INVALID_INPUT; + + /* Snapshot buffer is DC2_BLS_MAX_STEPS; larger built lists stay unmodified. */ + if (*bls->num_steps > DC2_BLS_MAX_STEPS) { + if (!wam->count) + return WAM_OK; + return WAM_INVALID_INPUT; + } + + saved_num = *bls->num_steps; + memmove(saved_steps, bls->steps, + saved_num * sizeof(saved_steps[0])); + + for (i = 0; i < wam->count; i++) { + const struct workaround *wa = &wam->registry[i]; + + if (!wa->enabled) + continue; + if (!wa->is_applicable || !wa->apply) { + memmove(bls->steps, saved_steps, + saved_num * sizeof(saved_steps[0])); + *bls->num_steps = saved_num; + return WAM_INTERNAL_ERROR; + } + if (!wa->is_applicable(bls, ctx)) + continue; + result = wa->apply(bls, ctx); + if (result != WAM_OK || + *bls->num_steps > MAX_HWSS_BLOCK_SEQUENCE_SIZE) { + memmove(bls->steps, saved_steps, + saved_num * sizeof(saved_steps[0])); + *bls->num_steps = saved_num; + if (result != WAM_OK) + return result; + return WAM_SIZE_EXCEEDED; + } + } + + return WAM_OK; +} diff --git a/drivers/gpu/drm/amd/display/dc/workaround_manager/workaround_manager.h b/drivers/gpu/drm/amd/display/dc/workaround_manager/workaround_manager.h new file mode 100644 index 000000000000..4cbadffd6a8b --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/workaround_manager/workaround_manager.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#pragma once + +#include "bls_builder/bls_builder.h" + +enum workaround_manager_result { + WAM_OK, + WAM_INVALID_INPUT, + WAM_SIZE_EXCEEDED, + WAM_INTERNAL_ERROR, +}; + +struct workaround_context { + const struct dc_state *current_state; + const struct dc_state *target; + enum bls_builder_name builder_name; + unsigned int dcn_version; + const struct dc_bug_wa *bug_wa; + const struct dc_debug_options *debug; +}; + +struct workaround { + const char *name; + bool enabled; + bool (*is_applicable)(const struct block_sequence_state *bls, + const struct workaround_context *ctx); + enum workaround_manager_result (*apply)( + struct block_sequence_state *bls, + const struct workaround_context *ctx); +}; + +struct workaround_manager { + const struct workaround *registry; + unsigned int count; +}; + +const struct workaround_manager *dc2_workaround_manager_get(void); + +enum workaround_manager_result workaround_manager_apply( + const struct workaround_manager *wam, + struct block_sequence_state *bls, + const struct workaround_context *ctx); diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index 31f147547605..a75d38d44916 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -2621,7 +2621,8 @@ struct dmub_fams2_alternate_stream_dynamic_state { uint16_t vstartup_line; uint16_t vready_line; uint8_t cursor_size[3]; // Cursor array per plane for now - if we assume a single cursor, then we don't need an array - uint8_t pad; // to maintain alignment for below fields - re-arrange structure once all fields are finalized + uint8_t disabled_pipe_mask; // bitmask of pipes with RECOUT_HEIGHT == 0 (disabled) + struct plane_pipe_rect pipe_viewports[4]; /* outputs: */ uint16_t subvp_start_line_a[3]; uint16_t subvp_height_a[3]; @@ -4800,6 +4801,14 @@ struct dmub_cmd_replay_copy_settings_data { * @pad: Align structure to 4 byte boundary. */ uint8_t pad[1]; + /** + * @frame_update_interval: Frame update interval; 0 disabled. + */ + uint16_t frame_update_interval; + /** + * @pad2: Align structure to 4 byte boundary. + */ + uint8_t pad2[2]; }; diff --git a/drivers/gpu/drm/amd/display/include/gpio_service_interface.h b/drivers/gpu/drm/amd/display/include/gpio_service_interface.h index 63813009a3a6..130c78600b6e 100644 --- a/drivers/gpu/drm/amd/display/include/gpio_service_interface.h +++ b/drivers/gpu/drm/amd/display/include/gpio_service_interface.h @@ -77,6 +77,12 @@ struct ddc *dal_gpio_create_ddc( void dal_gpio_destroy_ddc( struct ddc **ddc); +void dal_gpio_ddc_open_aux_once( + struct gpio_service *service, + uint32_t offset, + uint32_t mask, + const struct gpio_ddc_hw_info *info); + void dal_gpio_service_destroy( struct gpio_service **ptr); diff --git a/drivers/gpu/drm/amd/include/cgs_common.h b/drivers/gpu/drm/amd/include/cgs_common.h index f40b6a03fe63..79522e1bec4f 100644 --- a/drivers/gpu/drm/amd/include/cgs_common.h +++ b/drivers/gpu/drm/amd/include/cgs_common.h @@ -63,6 +63,14 @@ enum cgs_ucode_id { /** * struct cgs_firmware_info - Firmware information + * @version: firmware header version + * @fw_version: firmware version reported by the IP block + * @feature_version: firmware feature version + * @image_size: firmware image size in bytes + * @mc_addr: GPU address of the firmware image + * @ucode_start_address: ucode start address (SMU firmware only) + * @kptr: kernel virtual address of the firmware image + * @is_kicker: whether this is a "kicker" (k) firmware variant */ struct cgs_firmware_info { uint16_t version; @@ -78,45 +86,6 @@ struct cgs_firmware_info { bool is_kicker; }; -typedef unsigned long cgs_handle_t; - -/** - * cgs_read_register() - Read an MMIO register - * @cgs_device: opaque device handle - * @offset: register offset - * - * Return: register value - */ -typedef uint32_t (*cgs_read_register_t)(struct cgs_device *cgs_device, unsigned offset); - -/** - * cgs_write_register() - Write an MMIO register - * @cgs_device: opaque device handle - * @offset: register offset - * @value: register value - */ -typedef void (*cgs_write_register_t)(struct cgs_device *cgs_device, unsigned offset, - uint32_t value); - -/** - * cgs_read_ind_register() - Read an indirect register - * @cgs_device: opaque device handle - * @offset: register offset - * - * Return: register value - */ -typedef uint32_t (*cgs_read_ind_register_t)(struct cgs_device *cgs_device, enum cgs_ind_reg space, - unsigned index); - -/** - * cgs_write_ind_register() - Write an indirect register - * @cgs_device: opaque device handle - * @offset: register offset - * @value: register value - */ -typedef void (*cgs_write_ind_register_t)(struct cgs_device *cgs_device, enum cgs_ind_reg space, - unsigned index, uint32_t value); - #define CGS_REG_FIELD_SHIFT(reg, field) reg##__##field##__SHIFT #define CGS_REG_FIELD_MASK(reg, field) reg##__##field##_MASK @@ -133,18 +102,27 @@ typedef void (*cgs_write_ind_register_t)(struct cgs_device *cgs_device, enum cgs #define CGS_WREG32_FIELD_IND(device, space, reg, field, val) \ cgs_write_ind_register(device, space, ix##reg, (cgs_read_ind_register(device, space, ix##reg) & ~CGS_REG_FIELD_MASK(reg, field)) | (val) << CGS_REG_FIELD_SHIFT(reg, field)) -typedef int (*cgs_get_firmware_info)(struct cgs_device *cgs_device, - enum cgs_ucode_id type, - struct cgs_firmware_info *info); - +/** + * struct cgs_ops - Common Graphics Services operations + * @read_register: read register value + * @write_register: write register value + * @read_ind_register: read indirect register value + * @write_ind_register: write indirect register value + * @get_firmware_info: get firmware information + */ struct cgs_ops { /* MMIO access */ - cgs_read_register_t read_register; - cgs_write_register_t write_register; - cgs_read_ind_register_t read_ind_register; - cgs_write_ind_register_t write_ind_register; + uint32_t (*read_register)(struct cgs_device *cgs_device, unsigned int offset); + void (*write_register)(struct cgs_device *cgs_device, unsigned int offset, + uint32_t value); + uint32_t (*read_ind_register)(struct cgs_device *cgs_device, enum cgs_ind_reg space, + unsigned int index); + void (*write_ind_register)(struct cgs_device *cgs_device, enum cgs_ind_reg space, + unsigned int index, uint32_t value); /* Firmware Info */ - cgs_get_firmware_info get_firmware_info; + int (*get_firmware_info)(struct cgs_device *cgs_device, + enum cgs_ucode_id type, + struct cgs_firmware_info *info); }; struct cgs_os_ops; /* To be define in OS-specific CGS header */ diff --git a/drivers/gpu/drm/amd/include/mes_v11_api_def.h b/drivers/gpu/drm/amd/include/mes_v11_api_def.h index f8eaca8a22f6..6d67d015a74f 100644 --- a/drivers/gpu/drm/amd/include/mes_v11_api_def.h +++ b/drivers/gpu/drm/amd/include/mes_v11_api_def.h @@ -683,6 +683,9 @@ struct SET_SHADER_DEBUGGER { uint32_t spi_gdbg_per_vmid_cntl; uint32_t tcp_watch_cntl[4]; /* TCP_WATCHx_CNTL */ uint32_t trap_en; + uint32_t tcp_watch_addr_lo[4]; /* TCP_WATCHx_ADDR_L */ + uint32_t tcp_watch_addr_hi[4]; /* TCP_WATCHx_ADDR_H */ + uint32_t process_context_array_index; }; enum MESAPI_MISC__CHANGE_CONFIG_OPTION { diff --git a/drivers/gpu/drm/amd/include/mes_v12_api_def.h b/drivers/gpu/drm/amd/include/mes_v12_api_def.h index 3e214cb4f6e1..090c9142674e 100644 --- a/drivers/gpu/drm/amd/include/mes_v12_api_def.h +++ b/drivers/gpu/drm/amd/include/mes_v12_api_def.h @@ -805,6 +805,9 @@ struct SET_SHADER_DEBUGGER { uint32_t spi_gdbg_per_vmid_cntl; uint32_t tcp_watch_cntl[4]; // TCP_WATCHx_CNTL uint32_t trap_en; + uint32_t tcp_watch_addr_lo[4]; // TCP_WATCHx_ADDR_L + uint32_t tcp_watch_addr_hi[4]; // TCP_WATCHx_ADDR_H + uint32_t process_context_array_index; }; struct SET_GANG_SUBMIT { diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c index a9bf686783e9..14b2acd36897 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c @@ -63,6 +63,9 @@ static void smu_v13_0_0_get_od_setting_limits(struct smu_context *smu, int od_feature_bit, int32_t *min, int32_t *max); static int smu_v13_0_0_init_ppt_limits(struct smu_context *smu); +static int +smu_v13_0_0_upload_overdrive_table(struct smu_context *smu, + OverDriveTableExternal_t *od_table); static const struct smu_feature_bits smu_v13_0_0_dpm_features = { .bits = { @@ -1079,6 +1082,93 @@ out: return feature_enabled; } +static u32 +smu_v13_0_0_filter_od_feature_mask(struct smu_context *smu, u32 feature_mask) +{ + PPTable_t *pptable = smu->smu_table.driver_pptable; + u32 supported_mask = + pptable->SkuTable.OverDriveLimitsBasicMax.FeatureCtrlMask; + + return feature_mask & supported_mask; +} + +static bool smu_v13_0_0_fan_is_default(const OverDriveTable_t *od, + const OverDriveTable_t *boot) +{ + return !memcmp(od->FanLinearPwmPoints, boot->FanLinearPwmPoints, + sizeof(od->FanLinearPwmPoints)) && + !memcmp(od->FanLinearTempPoints, boot->FanLinearTempPoints, + sizeof(od->FanLinearTempPoints)) && + od->FanMinimumPwm == boot->FanMinimumPwm && + od->AcousticTargetRpmThreshold == boot->AcousticTargetRpmThreshold && + od->AcousticLimitRpmThreshold == boot->AcousticLimitRpmThreshold && + od->FanTargetTemperature == boot->FanTargetTemperature && + od->FanMode == boot->FanMode; +} + +static bool smu_v13_0_0_zero_fan_is_default(const OverDriveTable_t *od, + const OverDriveTable_t *boot) +{ + return od->FanZeroRpmEnable == boot->FanZeroRpmEnable && + od->FanZeroRpmStopTemp == boot->FanZeroRpmStopTemp; +} + +static u32 smu_v13_0_0_normalize_feature_mask(const OverDriveTable_t *od, + const OverDriveTable_t *boot, + u32 feature_mask) +{ + if (od->GfxclkFmin == boot->GfxclkFmin && + od->GfxclkFmax == boot->GfxclkFmax) + feature_mask &= ~BIT(PP_OD_FEATURE_GFXCLK_BIT); + if (od->UclkFmin == boot->UclkFmin && + od->UclkFmax == boot->UclkFmax) + feature_mask &= ~BIT(PP_OD_FEATURE_UCLK_BIT); + if (!memcmp(od->VoltageOffsetPerZoneBoundary, + boot->VoltageOffsetPerZoneBoundary, + sizeof(od->VoltageOffsetPerZoneBoundary))) + feature_mask &= ~BIT(PP_OD_FEATURE_GFX_VF_CURVE_BIT); + if (smu_v13_0_0_fan_is_default(od, boot)) + feature_mask &= ~BIT(PP_OD_FEATURE_FAN_CURVE_BIT); + if (smu_v13_0_0_zero_fan_is_default(od, boot)) + feature_mask &= ~BIT(PP_OD_FEATURE_ZERO_FAN_BIT); + if (!od->Ppt) + feature_mask &= ~BIT(PP_OD_FEATURE_PPT_BIT); + + return feature_mask; +} + +static int +smu_v13_0_0_upload_ppt_overdrive_table(struct smu_context *smu, s16 ppt) +{ + struct smu_table_context *table_context = &smu->smu_table; + OverDriveTableExternal_t *od_table = table_context->overdrive_table; + OverDriveTableExternal_t *user_od_table = table_context->user_overdrive_table; + OverDriveTableExternal_t upload_table; + u32 next_mask = table_context->user_od_feature_mask; + int ret; + + /* Do not commit OD settings staged after the last c operation. */ + memcpy(&upload_table, user_od_table, sizeof(upload_table)); + upload_table.OverDriveTable.Ppt = ppt; + if (ppt) + next_mask |= BIT(PP_OD_FEATURE_PPT_BIT); + else + next_mask &= ~BIT(PP_OD_FEATURE_PPT_BIT); + upload_table.OverDriveTable.FeatureCtrlMask = + smu_v13_0_0_filter_od_feature_mask(smu, next_mask); + + ret = smu_v13_0_0_upload_overdrive_table(smu, &upload_table); + if (ret) + return ret; + + table_context->user_od_feature_mask = + upload_table.OverDriveTable.FeatureCtrlMask; + od_table->OverDriveTable.Ppt = ppt; + user_od_table->OverDriveTable.Ppt = ppt; + + return 0; +} + static void smu_v13_0_0_get_od_setting_limits(struct smu_context *smu, int od_feature_bit, int32_t *min, @@ -1514,41 +1604,30 @@ static int smu_v13_0_0_od_restore_table_single(struct smu_context *smu, long inp boot_overdrive_table->OverDriveTable.FanLinearPwmPoints[i]; } od_table->OverDriveTable.FanMode = FAN_MODE_AUTO; - od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); break; case PP_OD_EDIT_ACOUSTIC_LIMIT: od_table->OverDriveTable.AcousticLimitRpmThreshold = boot_overdrive_table->OverDriveTable.AcousticLimitRpmThreshold; - od_table->OverDriveTable.FanMode = FAN_MODE_AUTO; - od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); break; case PP_OD_EDIT_ACOUSTIC_TARGET: od_table->OverDriveTable.AcousticTargetRpmThreshold = boot_overdrive_table->OverDriveTable.AcousticTargetRpmThreshold; - od_table->OverDriveTable.FanMode = FAN_MODE_AUTO; - od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); break; case PP_OD_EDIT_FAN_TARGET_TEMPERATURE: od_table->OverDriveTable.FanTargetTemperature = boot_overdrive_table->OverDriveTable.FanTargetTemperature; - od_table->OverDriveTable.FanMode = FAN_MODE_AUTO; - od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); break; case PP_OD_EDIT_FAN_MINIMUM_PWM: od_table->OverDriveTable.FanMinimumPwm = boot_overdrive_table->OverDriveTable.FanMinimumPwm; - od_table->OverDriveTable.FanMode = FAN_MODE_AUTO; - od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); break; case PP_OD_EDIT_FAN_ZERO_RPM_ENABLE: od_table->OverDriveTable.FanZeroRpmEnable = boot_overdrive_table->OverDriveTable.FanZeroRpmEnable; - od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT); break; case PP_OD_EDIT_FAN_ZERO_RPM_STOP_TEMP: od_table->OverDriveTable.FanZeroRpmStopTemp = boot_overdrive_table->OverDriveTable.FanZeroRpmStopTemp; - od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT); break; default: dev_info(adev->dev, "Invalid table index: %ld\n", input); @@ -1566,9 +1645,17 @@ static int smu_v13_0_0_od_edit_dpm_table(struct smu_context *smu, struct smu_table_context *table_context = &smu->smu_table; OverDriveTableExternal_t *od_table = (OverDriveTableExternal_t *)table_context->overdrive_table; + OverDriveTableExternal_t *user_od_table = + (OverDriveTableExternal_t *)table_context->user_overdrive_table; + OverDriveTableExternal_t *boot_od_table = + (OverDriveTableExternal_t *)table_context->boot_overdrive_table; + OverDriveTableExternal_t upload_table; + OverDriveTable_t *od = &od_table->OverDriveTable; + OverDriveTable_t *boot = &boot_od_table->OverDriveTable; struct amdgpu_device *adev = smu->adev; uint32_t offset_of_voltageoffset; int32_t minimum, maximum; + u32 next_mask; int i, ret = 0; switch (type) { @@ -1892,36 +1979,41 @@ static int smu_v13_0_0_od_edit_dpm_table(struct smu_context *smu, } else { memcpy(od_table, table_context->boot_overdrive_table, - sizeof(OverDriveTableExternal_t)); + sizeof(OverDriveTableExternal_t)); od_table->OverDriveTable.FeatureCtrlMask = 0; - table_context->user_od_feature_mask = 0; } fallthrough; case PP_OD_COMMIT_DPM_TABLE: - table_context->user_od_feature_mask = - od_table->OverDriveTable.FeatureCtrlMask; offset_of_voltageoffset = offsetof(OverDriveTable_t, VoltageOffsetPerZoneBoundary); - if (memcmp((u8 *)od_table + offset_of_voltageoffset, - table_context->user_overdrive_table + offset_of_voltageoffset, - sizeof(OverDriveTableExternal_t) - offset_of_voltageoffset)) { - smu_v13_0_0_dump_od_table(smu, od_table); + next_mask = smu_v13_0_0_filter_od_feature_mask(smu, + table_context->user_od_feature_mask | + od->FeatureCtrlMask); + next_mask = smu_v13_0_0_normalize_feature_mask(od, boot, + next_mask); - ret = smu_v13_0_0_upload_overdrive_table(smu, od_table); + if (memcmp((u8 *)od_table + offset_of_voltageoffset, + (u8 *)user_od_table + offset_of_voltageoffset, + sizeof(OverDriveTableExternal_t) - offset_of_voltageoffset) || + next_mask != table_context->user_od_feature_mask) { + memcpy(&upload_table, od_table, sizeof(upload_table)); + upload_table.OverDriveTable.FeatureCtrlMask = next_mask; + smu_v13_0_0_dump_od_table(smu, &upload_table); + + ret = smu_v13_0_0_upload_overdrive_table(smu, &upload_table); if (ret) { dev_err(adev->dev, "Failed to upload overdrive table!\n"); return ret; } - memcpy(table_context->user_overdrive_table + offset_of_voltageoffset, + table_context->user_od_feature_mask = next_mask; + od_table->OverDriveTable.FeatureCtrlMask = 0; + memcpy((u8 *)user_od_table + offset_of_voltageoffset, (u8 *)od_table + offset_of_voltageoffset, sizeof(OverDriveTableExternal_t) - offset_of_voltageoffset); + user_od_table->OverDriveTable.FeatureCtrlMask = 0; - if (!memcmp(table_context->user_overdrive_table, - table_context->boot_overdrive_table, - sizeof(OverDriveTableExternal_t))) - smu->user_dpm_profile.user_od = false; - else - smu->user_dpm_profile.user_od = true; + smu->user_dpm_profile.user_od = + !!(next_mask & ~BIT(PP_OD_FEATURE_PPT_BIT)); } break; @@ -2186,6 +2278,7 @@ static int smu_v13_0_0_set_default_od_settings(struct smu_context *smu) memcpy(od_table, boot_od_table, sizeof(OverDriveTableExternal_t)); + od_table->OverDriveTable.FeatureCtrlMask = 0; /* * For S3/S4/Runpm resume, we need to setup those overdrive tables again, @@ -2195,6 +2288,7 @@ static int smu_v13_0_0_set_default_od_settings(struct smu_context *smu) memcpy(user_od_table, boot_od_table, sizeof(OverDriveTableExternal_t)); + user_od_table->OverDriveTable.FeatureCtrlMask = 0; smu->user_dpm_profile.user_od = false; smu->smu_table.user_od_feature_mask = 0; } else if (smu->user_dpm_profile.user_od) { @@ -2233,6 +2327,14 @@ static int smu_v13_0_0_set_default_od_settings(struct smu_context *smu) user_od_table_bak.OverDriveTable.FanZeroRpmEnable; user_od_table->OverDriveTable.FanZeroRpmStopTemp = user_od_table_bak.OverDriveTable.FanZeroRpmStopTemp; + user_od_table->OverDriveTable.FanMode = + user_od_table_bak.OverDriveTable.FanMode; + user_od_table->OverDriveTable.FeatureCtrlMask = 0; + } + if (smu->adev->in_suspend) { + user_od_table->OverDriveTable.Ppt = 0; + smu->smu_table.user_od_feature_mask &= + ~BIT(PP_OD_FEATURE_PPT_BIT); } smu_v13_0_0_set_supported_od_feature_mask(smu); @@ -2245,13 +2347,22 @@ static int smu_v13_0_0_restore_user_od_settings(struct smu_context *smu) struct smu_table_context *table_context = &smu->smu_table; OverDriveTableExternal_t *od_table = table_context->overdrive_table; OverDriveTableExternal_t *user_od_table = table_context->user_overdrive_table; + OverDriveTableExternal_t upload_table; + u32 next_mask; int res; - user_od_table->OverDriveTable.FeatureCtrlMask = - table_context->user_od_feature_mask; - res = smu_v13_0_0_upload_overdrive_table(smu, user_od_table); - user_od_table->OverDriveTable.FeatureCtrlMask = 0; - if (res == 0) + + next_mask = smu_v13_0_0_filter_od_feature_mask(smu, + table_context->user_od_feature_mask); + memcpy(&upload_table, user_od_table, sizeof(upload_table)); + upload_table.OverDriveTable.FeatureCtrlMask = next_mask; + res = smu_v13_0_0_upload_overdrive_table(smu, &upload_table); + if (res == 0) { + table_context->user_od_feature_mask = next_mask; + smu->user_dpm_profile.user_od = + !!(next_mask & ~BIT(PP_OD_FEATURE_PPT_BIT)); memcpy(od_table, user_od_table, sizeof(OverDriveTableExternal_t)); + od_table->OverDriveTable.FeatureCtrlMask = 0; + } return res; } @@ -3045,10 +3156,8 @@ static int smu_v13_0_0_set_ppt_limit(struct smu_context *smu, SkuTable_t *skutable = &pptable->SkuTable; uint32_t msg_limit = skutable->MsgLimits.Power [PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; - struct smu_table_context *table_context = &smu->smu_table; - OverDriveTableExternal_t *od_table = - (OverDriveTableExternal_t *)table_context->overdrive_table; OverDriveTableExternal_t current_od_table; + s16 ppt; int ret = 0; if (limit_type != SMU_PPT_LIMIT_PPT0) @@ -3060,12 +3169,7 @@ static int smu_v13_0_0_set_ppt_limit(struct smu_context *smu, return ret; if (current_od_table.OverDriveTable.Ppt) { - od_table->OverDriveTable.Ppt = 0; - table_context->user_od_feature_mask &= - ~(1U << PP_OD_FEATURE_PPT_BIT); - od_table->OverDriveTable.FeatureCtrlMask = - table_context->user_od_feature_mask; - ret = smu_v13_0_0_upload_overdrive_table(smu, od_table); + ret = smu_v13_0_0_upload_ppt_overdrive_table(smu, 0); if (ret) { dev_err(smu->adev->dev, "Failed to upload overdrive table!\n"); return ret; @@ -3077,11 +3181,8 @@ static int smu_v13_0_0_set_ppt_limit(struct smu_context *smu, if (ret) return ret; - od_table->OverDriveTable.Ppt = (limit * 100) / msg_limit - 100; - table_context->user_od_feature_mask |= 1U << PP_OD_FEATURE_PPT_BIT; - od_table->OverDriveTable.FeatureCtrlMask = - table_context->user_od_feature_mask; - ret = smu_v13_0_0_upload_overdrive_table(smu, od_table); + ppt = (limit * 100) / msg_limit - 100; + ret = smu_v13_0_0_upload_ppt_overdrive_table(smu, ppt); if (ret) { dev_err(smu->adev->dev, "Failed to upload overdrive table!\n"); return ret; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c index d8715a94ec6a..1530bdf8401b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c @@ -63,6 +63,9 @@ static void smu_v13_0_7_get_od_setting_limits(struct smu_context *smu, int od_feature_bit, int32_t *min, int32_t *max); static int smu_v13_0_7_init_ppt_limits(struct smu_context *smu); +static int +smu_v13_0_7_upload_overdrive_table(struct smu_context *smu, + OverDriveTableExternal_t *od_table); static const struct smu_feature_bits smu_v13_0_7_dpm_features = { .bits = { @@ -94,6 +97,7 @@ static const struct smu_feature_bits smu_v13_0_7_dpm_features = { #define PP_OD_FEATURE_GFXCLK_FMAX 1 #define PP_OD_FEATURE_UCLK_FMIN 2 #define PP_OD_FEATURE_UCLK_FMAX 3 + #define PP_OD_FEATURE_GFX_VF_CURVE 4 #define PP_OD_FEATURE_FAN_CURVE_TEMP 5 #define PP_OD_FEATURE_FAN_CURVE_PWM 6 @@ -1089,6 +1093,93 @@ out: return feature_enabled; } +static u32 +smu_v13_0_7_filter_od_feature_mask(struct smu_context *smu, u32 feature_mask) +{ + PPTable_t *pptable = smu->smu_table.driver_pptable; + u32 supported_mask = + pptable->SkuTable.OverDriveLimitsBasicMax.FeatureCtrlMask; + + return feature_mask & supported_mask; +} + +static bool smu_v13_0_7_fan_is_default(const OverDriveTable_t *od, + const OverDriveTable_t *boot) +{ + return !memcmp(od->FanLinearPwmPoints, boot->FanLinearPwmPoints, + sizeof(od->FanLinearPwmPoints)) && + !memcmp(od->FanLinearTempPoints, boot->FanLinearTempPoints, + sizeof(od->FanLinearTempPoints)) && + od->FanMinimumPwm == boot->FanMinimumPwm && + od->AcousticTargetRpmThreshold == boot->AcousticTargetRpmThreshold && + od->AcousticLimitRpmThreshold == boot->AcousticLimitRpmThreshold && + od->FanTargetTemperature == boot->FanTargetTemperature && + od->FanMode == boot->FanMode; +} + +static bool smu_v13_0_7_zero_fan_is_default(const OverDriveTable_t *od, + const OverDriveTable_t *boot) +{ + return od->FanZeroRpmEnable == boot->FanZeroRpmEnable && + od->FanZeroRpmStopTemp == boot->FanZeroRpmStopTemp; +} + +static u32 smu_v13_0_7_normalize_feature_mask(const OverDriveTable_t *od, + const OverDriveTable_t *boot, + u32 feature_mask) +{ + if (od->GfxclkFmin == boot->GfxclkFmin && + od->GfxclkFmax == boot->GfxclkFmax) + feature_mask &= ~BIT(PP_OD_FEATURE_GFXCLK_BIT); + if (od->UclkFmin == boot->UclkFmin && + od->UclkFmax == boot->UclkFmax) + feature_mask &= ~BIT(PP_OD_FEATURE_UCLK_BIT); + if (!memcmp(od->VoltageOffsetPerZoneBoundary, + boot->VoltageOffsetPerZoneBoundary, + sizeof(od->VoltageOffsetPerZoneBoundary))) + feature_mask &= ~BIT(PP_OD_FEATURE_GFX_VF_CURVE_BIT); + if (smu_v13_0_7_fan_is_default(od, boot)) + feature_mask &= ~BIT(PP_OD_FEATURE_FAN_CURVE_BIT); + if (smu_v13_0_7_zero_fan_is_default(od, boot)) + feature_mask &= ~BIT(PP_OD_FEATURE_ZERO_FAN_BIT); + if (!od->Ppt) + feature_mask &= ~BIT(PP_OD_FEATURE_PPT_BIT); + + return feature_mask; +} + +static int +smu_v13_0_7_upload_ppt_overdrive_table(struct smu_context *smu, s16 ppt) +{ + struct smu_table_context *table_context = &smu->smu_table; + OverDriveTableExternal_t *od_table = table_context->overdrive_table; + OverDriveTableExternal_t *user_od_table = table_context->user_overdrive_table; + OverDriveTableExternal_t upload_table; + u32 next_mask = table_context->user_od_feature_mask; + int ret; + + /* Do not commit OD settings staged after the last c operation. */ + memcpy(&upload_table, user_od_table, sizeof(upload_table)); + upload_table.OverDriveTable.Ppt = ppt; + if (ppt) + next_mask |= BIT(PP_OD_FEATURE_PPT_BIT); + else + next_mask &= ~BIT(PP_OD_FEATURE_PPT_BIT); + upload_table.OverDriveTable.FeatureCtrlMask = + smu_v13_0_7_filter_od_feature_mask(smu, next_mask); + + ret = smu_v13_0_7_upload_overdrive_table(smu, &upload_table); + if (ret) + return ret; + + table_context->user_od_feature_mask = + upload_table.OverDriveTable.FeatureCtrlMask; + od_table->OverDriveTable.Ppt = ppt; + user_od_table->OverDriveTable.Ppt = ppt; + + return 0; +} + static void smu_v13_0_7_get_od_setting_limits(struct smu_context *smu, int od_feature_bit, int32_t *min, @@ -1523,41 +1614,30 @@ static int smu_v13_0_7_od_restore_table_single(struct smu_context *smu, long inp boot_overdrive_table->OverDriveTable.FanLinearPwmPoints[i]; } od_table->OverDriveTable.FanMode = FAN_MODE_AUTO; - od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); break; case PP_OD_EDIT_ACOUSTIC_LIMIT: od_table->OverDriveTable.AcousticLimitRpmThreshold = boot_overdrive_table->OverDriveTable.AcousticLimitRpmThreshold; - od_table->OverDriveTable.FanMode = FAN_MODE_AUTO; - od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); break; case PP_OD_EDIT_ACOUSTIC_TARGET: od_table->OverDriveTable.AcousticTargetRpmThreshold = boot_overdrive_table->OverDriveTable.AcousticTargetRpmThreshold; - od_table->OverDriveTable.FanMode = FAN_MODE_AUTO; - od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); break; case PP_OD_EDIT_FAN_TARGET_TEMPERATURE: od_table->OverDriveTable.FanTargetTemperature = boot_overdrive_table->OverDriveTable.FanTargetTemperature; - od_table->OverDriveTable.FanMode = FAN_MODE_AUTO; - od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); break; case PP_OD_EDIT_FAN_MINIMUM_PWM: od_table->OverDriveTable.FanMinimumPwm = boot_overdrive_table->OverDriveTable.FanMinimumPwm; - od_table->OverDriveTable.FanMode = FAN_MODE_AUTO; - od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); break; case PP_OD_EDIT_FAN_ZERO_RPM_ENABLE: od_table->OverDriveTable.FanZeroRpmEnable = boot_overdrive_table->OverDriveTable.FanZeroRpmEnable; - od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT); break; case PP_OD_EDIT_FAN_ZERO_RPM_STOP_TEMP: od_table->OverDriveTable.FanZeroRpmStopTemp = boot_overdrive_table->OverDriveTable.FanZeroRpmStopTemp; - od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT); break; default: dev_info(adev->dev, "Invalid table index: %ld\n", input); @@ -1575,9 +1655,17 @@ static int smu_v13_0_7_od_edit_dpm_table(struct smu_context *smu, struct smu_table_context *table_context = &smu->smu_table; OverDriveTableExternal_t *od_table = (OverDriveTableExternal_t *)table_context->overdrive_table; + OverDriveTableExternal_t *user_od_table = + (OverDriveTableExternal_t *)table_context->user_overdrive_table; + OverDriveTableExternal_t *boot_od_table = + (OverDriveTableExternal_t *)table_context->boot_overdrive_table; + OverDriveTableExternal_t upload_table; + OverDriveTable_t *od = &od_table->OverDriveTable; + OverDriveTable_t *boot = &boot_od_table->OverDriveTable; struct amdgpu_device *adev = smu->adev; uint32_t offset_of_voltageoffset; int32_t minimum, maximum; + u32 next_mask; int i, ret = 0; switch (type) { @@ -1903,35 +1991,40 @@ static int smu_v13_0_7_od_edit_dpm_table(struct smu_context *smu, table_context->boot_overdrive_table, sizeof(OverDriveTableExternal_t)); od_table->OverDriveTable.FeatureCtrlMask = 0; - table_context->user_od_feature_mask = 0; } fallthrough; case PP_OD_COMMIT_DPM_TABLE: - table_context->user_od_feature_mask = - od_table->OverDriveTable.FeatureCtrlMask; offset_of_voltageoffset = offsetof(OverDriveTable_t, VoltageOffsetPerZoneBoundary); - if (memcmp((u8 *)od_table + offset_of_voltageoffset, - table_context->user_overdrive_table + offset_of_voltageoffset, - sizeof(OverDriveTableExternal_t) - offset_of_voltageoffset)) { - smu_v13_0_7_dump_od_table(smu, od_table); + next_mask = smu_v13_0_7_filter_od_feature_mask(smu, + table_context->user_od_feature_mask | + od->FeatureCtrlMask); + next_mask = smu_v13_0_7_normalize_feature_mask(od, boot, + next_mask); - ret = smu_v13_0_7_upload_overdrive_table(smu, od_table); + if (memcmp((u8 *)od_table + offset_of_voltageoffset, + (u8 *)user_od_table + offset_of_voltageoffset, + sizeof(OverDriveTableExternal_t) - offset_of_voltageoffset) || + next_mask != table_context->user_od_feature_mask) { + memcpy(&upload_table, od_table, sizeof(upload_table)); + upload_table.OverDriveTable.FeatureCtrlMask = next_mask; + smu_v13_0_7_dump_od_table(smu, &upload_table); + + ret = smu_v13_0_7_upload_overdrive_table(smu, &upload_table); if (ret) { dev_err(adev->dev, "Failed to upload overdrive table!\n"); return ret; } - memcpy(table_context->user_overdrive_table + offset_of_voltageoffset, + table_context->user_od_feature_mask = next_mask; + od_table->OverDriveTable.FeatureCtrlMask = 0; + memcpy((u8 *)user_od_table + offset_of_voltageoffset, (u8 *)od_table + offset_of_voltageoffset, sizeof(OverDriveTableExternal_t) - offset_of_voltageoffset); + user_od_table->OverDriveTable.FeatureCtrlMask = 0; - if (!memcmp(table_context->user_overdrive_table, - table_context->boot_overdrive_table, - sizeof(OverDriveTableExternal_t))) - smu->user_dpm_profile.user_od = false; - else - smu->user_dpm_profile.user_od = true; + smu->user_dpm_profile.user_od = + !!(next_mask & ~BIT(PP_OD_FEATURE_PPT_BIT)); } break; @@ -2187,6 +2280,7 @@ static int smu_v13_0_7_set_default_od_settings(struct smu_context *smu) memcpy(od_table, boot_od_table, sizeof(OverDriveTableExternal_t)); + od_table->OverDriveTable.FeatureCtrlMask = 0; /* * For S3/S4/Runpm resume, we need to setup those overdrive tables again, @@ -2196,6 +2290,7 @@ static int smu_v13_0_7_set_default_od_settings(struct smu_context *smu) memcpy(user_od_table, boot_od_table, sizeof(OverDriveTableExternal_t)); + user_od_table->OverDriveTable.FeatureCtrlMask = 0; smu->user_dpm_profile.user_od = false; smu->smu_table.user_od_feature_mask = 0; } else if (smu->user_dpm_profile.user_od) { @@ -2234,6 +2329,14 @@ static int smu_v13_0_7_set_default_od_settings(struct smu_context *smu) user_od_table_bak.OverDriveTable.FanZeroRpmEnable; user_od_table->OverDriveTable.FanZeroRpmStopTemp = user_od_table_bak.OverDriveTable.FanZeroRpmStopTemp; + user_od_table->OverDriveTable.FanMode = + user_od_table_bak.OverDriveTable.FanMode; + user_od_table->OverDriveTable.FeatureCtrlMask = 0; + } + if (smu->adev->in_suspend) { + user_od_table->OverDriveTable.Ppt = 0; + smu->smu_table.user_od_feature_mask &= + ~BIT(PP_OD_FEATURE_PPT_BIT); } smu_v13_0_7_set_supported_od_feature_mask(smu); @@ -2246,14 +2349,22 @@ static int smu_v13_0_7_restore_user_od_settings(struct smu_context *smu) struct smu_table_context *table_context = &smu->smu_table; OverDriveTableExternal_t *od_table = table_context->overdrive_table; OverDriveTableExternal_t *user_od_table = table_context->user_overdrive_table; + OverDriveTableExternal_t upload_table; + u32 next_mask; int res; - user_od_table->OverDriveTable.FeatureCtrlMask = - table_context->user_od_feature_mask; - res = smu_v13_0_7_upload_overdrive_table(smu, user_od_table); - user_od_table->OverDriveTable.FeatureCtrlMask = 0; - if (res == 0) + next_mask = smu_v13_0_7_filter_od_feature_mask(smu, + table_context->user_od_feature_mask); + memcpy(&upload_table, user_od_table, sizeof(upload_table)); + upload_table.OverDriveTable.FeatureCtrlMask = next_mask; + res = smu_v13_0_7_upload_overdrive_table(smu, &upload_table); + if (res == 0) { + table_context->user_od_feature_mask = next_mask; + smu->user_dpm_profile.user_od = + !!(next_mask & ~BIT(PP_OD_FEATURE_PPT_BIT)); memcpy(od_table, user_od_table, sizeof(OverDriveTableExternal_t)); + od_table->OverDriveTable.FeatureCtrlMask = 0; + } return res; } @@ -2695,10 +2806,8 @@ static int smu_v13_0_7_set_ppt_limit(struct smu_context *smu, SkuTable_t *skutable = &pptable->SkuTable; uint32_t msg_limit = skutable->MsgLimits.Power [PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; - struct smu_table_context *table_context = &smu->smu_table; - OverDriveTableExternal_t *od_table = - (OverDriveTableExternal_t *)table_context->overdrive_table; OverDriveTableExternal_t current_od_table; + s16 ppt; int ret = 0; if (limit_type != SMU_PPT_LIMIT_PPT0) @@ -2710,13 +2819,7 @@ static int smu_v13_0_7_set_ppt_limit(struct smu_context *smu, return ret; if (current_od_table.OverDriveTable.Ppt) { - od_table->OverDriveTable.Ppt = 0; - table_context->user_od_feature_mask &= - ~(1U << PP_OD_FEATURE_PPT_BIT); - od_table->OverDriveTable.FeatureCtrlMask = - table_context->user_od_feature_mask; - - ret = smu_v13_0_7_upload_overdrive_table(smu, od_table); + ret = smu_v13_0_7_upload_ppt_overdrive_table(smu, 0); if (ret) { dev_err(smu->adev->dev, "Failed to upload overdrive table!\n"); return ret; @@ -2728,12 +2831,8 @@ static int smu_v13_0_7_set_ppt_limit(struct smu_context *smu, if (ret) return ret; - od_table->OverDriveTable.Ppt = (limit * 100) / msg_limit - 100; - table_context->user_od_feature_mask |= 1U << PP_OD_FEATURE_PPT_BIT; - od_table->OverDriveTable.FeatureCtrlMask = - table_context->user_od_feature_mask; - - ret = smu_v13_0_7_upload_overdrive_table(smu, od_table); + ppt = (limit * 100) / msg_limit - 100; + ret = smu_v13_0_7_upload_ppt_overdrive_table(smu, ppt); if (ret) { dev_err(smu->adev->dev, "Failed to upload overdrive table!\n"); return ret; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c index 3f2c120ef2dc..24a3d61d8ea6 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c @@ -91,6 +91,10 @@ static const struct smu_feature_bits smu_v14_0_2_dpm_features = { #define PP_OD_FEATURE_FAN_ZERO_RPM_ENABLE 11 #define PP_OD_FEATURE_FAN_ZERO_RPM_STOP_TEMP 12 +#define SMU_14_0_2_OD_FAN_FEATURE_MASK \ + (BIT(PP_OD_FEATURE_FAN_CURVE_BIT) | \ + BIT(PP_OD_FEATURE_FAN_LEGACY_BIT)) + static struct cmn2asic_msg_mapping smu_v14_0_2_message_map[SMU_MSG_MAX_COUNT] = { MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1), MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 1), @@ -963,6 +967,84 @@ out: return feature_enabled; } +static u32 +smu_v14_0_2_filter_od_feature_mask(struct smu_context *smu, u32 feature_mask) +{ + PPTable_t *pptable = smu->smu_table.driver_pptable; + u32 supported_mask = + pptable->SkuTable.OverDriveLimitsBasicMax.FeatureCtrlMask; + + return feature_mask & supported_mask; +} + +static u32 +smu_v14_0_2_get_od_feature_mask(struct smu_context *smu, u32 pending_mask) +{ + u32 supported_mask = smu_v14_0_2_filter_od_feature_mask(smu, ~0U); + u32 fan_mask = supported_mask & SMU_14_0_2_OD_FAN_FEATURE_MASK; + u32 mask = smu->smu_table.user_od_feature_mask; + + if (pending_mask & fan_mask) + mask &= ~fan_mask; + mask |= pending_mask; + + return smu_v14_0_2_filter_od_feature_mask(smu, mask); +} + +static bool smu_v14_0_2_fan_is_default(const OverDriveTable_t *od, + const OverDriveTable_t *boot) +{ + return !memcmp(od->FanLinearPwmPoints, boot->FanLinearPwmPoints, + sizeof(od->FanLinearPwmPoints)) && + !memcmp(od->FanLinearTempPoints, boot->FanLinearTempPoints, + sizeof(od->FanLinearTempPoints)) && + od->AcousticTargetRpmThreshold == boot->AcousticTargetRpmThreshold && + od->AcousticLimitRpmThreshold == boot->AcousticLimitRpmThreshold && + od->FanTargetTemperature == boot->FanTargetTemperature && + od->FanMode == boot->FanMode; +} + +static bool smu_v14_0_2_legacy_fan_is_default(const OverDriveTable_t *od, + const OverDriveTable_t *boot) +{ + return od->FanMinimumPwm == boot->FanMinimumPwm && + od->FanMode == boot->FanMode; +} + +static bool smu_v14_0_2_zero_fan_is_default(const OverDriveTable_t *od, + const OverDriveTable_t *boot) +{ + return od->FanZeroRpmEnable == boot->FanZeroRpmEnable && + od->FanZeroRpmStopTemp == boot->FanZeroRpmStopTemp; +} + +static u32 smu_v14_0_2_normalize_feature_mask(const OverDriveTable_t *od, + const OverDriveTable_t *boot, + u32 feature_mask) +{ + if (od->GfxclkFoffset == boot->GfxclkFoffset) + feature_mask &= ~BIT(PP_OD_FEATURE_GFXCLK_BIT); + if (od->UclkFmin == boot->UclkFmin && + od->UclkFmax == boot->UclkFmax) + feature_mask &= ~BIT(PP_OD_FEATURE_UCLK_BIT); + if (!memcmp(od->VoltageOffsetPerZoneBoundary, + boot->VoltageOffsetPerZoneBoundary, + sizeof(od->VoltageOffsetPerZoneBoundary))) + feature_mask &= ~BIT(PP_OD_FEATURE_GFX_VF_CURVE_BIT); + if ((feature_mask & BIT(PP_OD_FEATURE_FAN_CURVE_BIT)) && + smu_v14_0_2_fan_is_default(od, boot)) + feature_mask &= ~BIT(PP_OD_FEATURE_FAN_CURVE_BIT); + if ((feature_mask & BIT(PP_OD_FEATURE_FAN_LEGACY_BIT)) && + smu_v14_0_2_legacy_fan_is_default(od, boot)) + feature_mask &= ~BIT(PP_OD_FEATURE_FAN_LEGACY_BIT); + if (smu_v14_0_2_zero_fan_is_default(od, boot)) + feature_mask &= ~BIT(PP_OD_FEATURE_ZERO_FAN_BIT); + if (!od->Ppt) + feature_mask &= ~BIT(PP_OD_FEATURE_PPT_BIT); + + return feature_mask; +} + static void smu_v14_0_2_get_od_setting_limits(struct smu_context *smu, int od_feature_bit, int32_t *min, @@ -2320,6 +2402,38 @@ static int smu_v14_0_2_upload_overdrive_table(struct smu_context *smu, return ret; } +static int +smu_v14_0_2_upload_ppt_overdrive_table(struct smu_context *smu, s16 ppt) +{ + struct smu_table_context *table_context = &smu->smu_table; + OverDriveTableExternal_t *od_table = table_context->overdrive_table; + OverDriveTableExternal_t *user_od_table = table_context->user_overdrive_table; + OverDriveTableExternal_t upload_table; + u32 next_mask = table_context->user_od_feature_mask; + int ret; + + /* Do not commit OD settings staged after the last c operation. */ + memcpy(&upload_table, user_od_table, sizeof(upload_table)); + upload_table.OverDriveTable.Ppt = ppt; + if (ppt) + next_mask |= BIT(PP_OD_FEATURE_PPT_BIT); + else + next_mask &= ~BIT(PP_OD_FEATURE_PPT_BIT); + upload_table.OverDriveTable.FeatureCtrlMask = + smu_v14_0_2_filter_od_feature_mask(smu, next_mask); + + ret = smu_v14_0_2_upload_overdrive_table(smu, &upload_table); + if (ret) + return ret; + + table_context->user_od_feature_mask = + upload_table.OverDriveTable.FeatureCtrlMask; + od_table->OverDriveTable.Ppt = ppt; + user_od_table->OverDriveTable.Ppt = ppt; + + return 0; +} + static void smu_v14_0_2_set_supported_od_feature_mask(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; @@ -2378,6 +2492,7 @@ static int smu_v14_0_2_set_default_od_settings(struct smu_context *smu) memcpy(od_table, boot_od_table, sizeof(OverDriveTableExternal_t)); + od_table->OverDriveTable.FeatureCtrlMask = 0; /* * For S3/S4/Runpm resume, we need to setup those overdrive tables again, @@ -2387,6 +2502,7 @@ static int smu_v14_0_2_set_default_od_settings(struct smu_context *smu) memcpy(user_od_table, boot_od_table, sizeof(OverDriveTableExternal_t)); + user_od_table->OverDriveTable.FeatureCtrlMask = 0; smu->user_dpm_profile.user_od = false; smu->smu_table.user_od_feature_mask = 0; } else if (smu->user_dpm_profile.user_od) { @@ -2423,6 +2539,14 @@ static int smu_v14_0_2_set_default_od_settings(struct smu_context *smu) user_od_table_bak.OverDriveTable.FanZeroRpmEnable; user_od_table->OverDriveTable.FanZeroRpmStopTemp = user_od_table_bak.OverDriveTable.FanZeroRpmStopTemp; + user_od_table->OverDriveTable.FanMode = + user_od_table_bak.OverDriveTable.FanMode; + user_od_table->OverDriveTable.FeatureCtrlMask = 0; + } + if (smu->adev->in_suspend) { + user_od_table->OverDriveTable.Ppt = 0; + smu->smu_table.user_od_feature_mask &= + ~BIT(PP_OD_FEATURE_PPT_BIT); } smu_v14_0_2_set_supported_od_feature_mask(smu); @@ -2435,14 +2559,22 @@ static int smu_v14_0_2_restore_user_od_settings(struct smu_context *smu) struct smu_table_context *table_context = &smu->smu_table; OverDriveTableExternal_t *od_table = table_context->overdrive_table; OverDriveTableExternal_t *user_od_table = table_context->user_overdrive_table; + OverDriveTableExternal_t upload_table; + u32 next_mask; int res; - user_od_table->OverDriveTable.FeatureCtrlMask = - table_context->user_od_feature_mask; - res = smu_v14_0_2_upload_overdrive_table(smu, user_od_table); - user_od_table->OverDriveTable.FeatureCtrlMask = 0; - if (res == 0) + next_mask = smu_v14_0_2_filter_od_feature_mask(smu, + table_context->user_od_feature_mask); + memcpy(&upload_table, user_od_table, sizeof(upload_table)); + upload_table.OverDriveTable.FeatureCtrlMask = next_mask; + res = smu_v14_0_2_upload_overdrive_table(smu, &upload_table); + if (res == 0) { + table_context->user_od_feature_mask = next_mask; + smu->user_dpm_profile.user_od = + !!(next_mask & ~BIT(PP_OD_FEATURE_PPT_BIT)); memcpy(od_table, user_od_table, sizeof(OverDriveTableExternal_t)); + od_table->OverDriveTable.FeatureCtrlMask = 0; + } return res; } @@ -2466,13 +2598,10 @@ static int smu_v14_0_2_od_restore_table_single(struct smu_context *smu, long inp boot_overdrive_table->OverDriveTable.FanLinearPwmPoints[i]; } od_table->OverDriveTable.FanMode = FAN_MODE_AUTO; - od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); - od_table->OverDriveTable.FeatureCtrlMask &= ~BIT(PP_OD_FEATURE_FAN_LEGACY_BIT); break; case PP_OD_EDIT_FAN_ZERO_RPM_ENABLE: od_table->OverDriveTable.FanZeroRpmEnable = boot_overdrive_table->OverDriveTable.FanZeroRpmEnable; - od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT); break; case PP_OD_EDIT_FAN_ZERO_RPM_STOP_TEMP: od_table->OverDriveTable.FanZeroRpmStopTemp = @@ -2482,27 +2611,18 @@ static int smu_v14_0_2_od_restore_table_single(struct smu_context *smu, long inp case PP_OD_EDIT_ACOUSTIC_LIMIT: od_table->OverDriveTable.AcousticLimitRpmThreshold = boot_overdrive_table->OverDriveTable.AcousticLimitRpmThreshold; - od_table->OverDriveTable.FanMode = FAN_MODE_AUTO; - od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); break; case PP_OD_EDIT_ACOUSTIC_TARGET: od_table->OverDriveTable.AcousticTargetRpmThreshold = boot_overdrive_table->OverDriveTable.AcousticTargetRpmThreshold; - od_table->OverDriveTable.FanMode = FAN_MODE_AUTO; - od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); break; case PP_OD_EDIT_FAN_TARGET_TEMPERATURE: od_table->OverDriveTable.FanTargetTemperature = boot_overdrive_table->OverDriveTable.FanTargetTemperature; - od_table->OverDriveTable.FanMode = FAN_MODE_AUTO; - od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); break; case PP_OD_EDIT_FAN_MINIMUM_PWM: od_table->OverDriveTable.FanMinimumPwm = boot_overdrive_table->OverDriveTable.FanMinimumPwm; - od_table->OverDriveTable.FanMode = FAN_MODE_AUTO; - od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_LEGACY_BIT); - od_table->OverDriveTable.FeatureCtrlMask &= ~BIT(PP_OD_FEATURE_FAN_CURVE_BIT); break; default: dev_info(adev->dev, "Invalid table index: %ld\n", input); @@ -2520,9 +2640,17 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu, struct smu_table_context *table_context = &smu->smu_table; OverDriveTableExternal_t *od_table = (OverDriveTableExternal_t *)table_context->overdrive_table; + OverDriveTableExternal_t *user_od_table = + (OverDriveTableExternal_t *)table_context->user_overdrive_table; + OverDriveTableExternal_t *boot_od_table = + (OverDriveTableExternal_t *)table_context->boot_overdrive_table; + OverDriveTableExternal_t upload_table; + OverDriveTable_t *od = &od_table->OverDriveTable; + OverDriveTable_t *boot = &boot_od_table->OverDriveTable; struct amdgpu_device *adev = smu->adev; uint32_t offset_of_voltageoffset; int32_t minimum, maximum; + u32 next_mask; int i, ret = 0; switch (type) { @@ -2694,6 +2822,7 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu, od_table->OverDriveTable.AcousticLimitRpmThreshold = input[0]; od_table->OverDriveTable.FanMode = FAN_MODE_AUTO; od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); + od_table->OverDriveTable.FeatureCtrlMask &= ~BIT(PP_OD_FEATURE_FAN_LEGACY_BIT); break; case PP_OD_EDIT_ACOUSTIC_TARGET: @@ -2716,6 +2845,7 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu, od_table->OverDriveTable.AcousticTargetRpmThreshold = input[0]; od_table->OverDriveTable.FanMode = FAN_MODE_AUTO; od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); + od_table->OverDriveTable.FeatureCtrlMask &= ~BIT(PP_OD_FEATURE_FAN_LEGACY_BIT); break; case PP_OD_EDIT_FAN_TARGET_TEMPERATURE: @@ -2738,6 +2868,7 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu, od_table->OverDriveTable.FanTargetTemperature = input[0]; od_table->OverDriveTable.FanMode = FAN_MODE_AUTO; od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); + od_table->OverDriveTable.FeatureCtrlMask &= ~BIT(PP_OD_FEATURE_FAN_LEGACY_BIT); break; case PP_OD_EDIT_FAN_MINIMUM_PWM: @@ -2815,44 +2946,38 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu, table_context->boot_overdrive_table, sizeof(OverDriveTableExternal_t)); od_table->OverDriveTable.FeatureCtrlMask = 0; - table_context->user_od_feature_mask = 0; } fallthrough; case PP_OD_COMMIT_DPM_TABLE: - /* - * PMFW interprets FeatureCtrlMask as the complete set of OD - * features that are currently overridden, not as a delta - * describing this single operation. Any feature whose bit is - * clear gets reset to its default on import. od_table's mask - * has accumulated every feature the user touched since the - * last full restore, so record it and keep restating it on - * subsequent uploads. - */ - table_context->user_od_feature_mask = - od_table->OverDriveTable.FeatureCtrlMask; - offset_of_voltageoffset = offsetof(OverDriveTable_t, VoltageOffsetPerZoneBoundary); - if (memcmp((u8 *)od_table + offset_of_voltageoffset, - table_context->user_overdrive_table + offset_of_voltageoffset, - sizeof(OverDriveTableExternal_t) - offset_of_voltageoffset)) { - smu_v14_0_2_dump_od_table(smu, od_table); + next_mask = smu_v14_0_2_get_od_feature_mask(smu, + od->FeatureCtrlMask); + next_mask = smu_v14_0_2_normalize_feature_mask(od, boot, + next_mask); - ret = smu_v14_0_2_upload_overdrive_table(smu, od_table); + if (memcmp((u8 *)od_table + offset_of_voltageoffset, + (u8 *)user_od_table + offset_of_voltageoffset, + sizeof(OverDriveTableExternal_t) - offset_of_voltageoffset) || + next_mask != table_context->user_od_feature_mask) { + memcpy(&upload_table, od_table, sizeof(upload_table)); + upload_table.OverDriveTable.FeatureCtrlMask = next_mask; + smu_v14_0_2_dump_od_table(smu, &upload_table); + + ret = smu_v14_0_2_upload_overdrive_table(smu, &upload_table); if (ret) { dev_err(adev->dev, "Failed to upload overdrive table!\n"); return ret; } - memcpy(table_context->user_overdrive_table + offset_of_voltageoffset, + table_context->user_od_feature_mask = next_mask; + od_table->OverDriveTable.FeatureCtrlMask = 0; + memcpy((u8 *)user_od_table + offset_of_voltageoffset, (u8 *)od_table + offset_of_voltageoffset, sizeof(OverDriveTableExternal_t) - offset_of_voltageoffset); + user_od_table->OverDriveTable.FeatureCtrlMask = 0; - if (!memcmp(table_context->user_overdrive_table, - table_context->boot_overdrive_table, - sizeof(OverDriveTableExternal_t))) - smu->user_dpm_profile.user_od = false; - else - smu->user_dpm_profile.user_od = true; + smu->user_dpm_profile.user_od = + !!(next_mask & ~BIT(PP_OD_FEATURE_PPT_BIT)); } break; @@ -2870,10 +2995,8 @@ static int smu_v14_0_2_set_ppt_limit(struct smu_context *smu, PPTable_t *pptable = smu->smu_table.driver_pptable; uint32_t msg_limit = pptable->SkuTable.MsgLimits.Power [PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; - struct smu_table_context *table_context = &smu->smu_table; - OverDriveTableExternal_t *od_table = - (OverDriveTableExternal_t *)table_context->overdrive_table; OverDriveTableExternal_t current_od_table; + s16 ppt; int ret = 0; if (limit_type != SMU_PPT_LIMIT_PPT0) @@ -2885,13 +3008,7 @@ static int smu_v14_0_2_set_ppt_limit(struct smu_context *smu, return ret; if (current_od_table.OverDriveTable.Ppt) { - od_table->OverDriveTable.Ppt = 0; - table_context->user_od_feature_mask &= - ~(1U << PP_OD_FEATURE_PPT_BIT); - od_table->OverDriveTable.FeatureCtrlMask = - table_context->user_od_feature_mask; - - ret = smu_v14_0_2_upload_overdrive_table(smu, od_table); + ret = smu_v14_0_2_upload_ppt_overdrive_table(smu, 0); if (ret) { dev_err(smu->adev->dev, "Failed to upload overdrive table!\n"); return ret; @@ -2903,12 +3020,8 @@ static int smu_v14_0_2_set_ppt_limit(struct smu_context *smu, if (ret) return ret; - od_table->OverDriveTable.Ppt = (limit * 100) / msg_limit - 100; - table_context->user_od_feature_mask |= 1U << PP_OD_FEATURE_PPT_BIT; - od_table->OverDriveTable.FeatureCtrlMask = - table_context->user_od_feature_mask; - - ret = smu_v14_0_2_upload_overdrive_table(smu, od_table); + ppt = (limit * 100) / msg_limit - 100; + ret = smu_v14_0_2_upload_ppt_overdrive_table(smu, ppt); if (ret) { dev_err(smu->adev->dev, "Failed to upload overdrive table!\n"); return ret; diff --git a/drivers/gpu/drm/amd/ras/core/ras_eeprom_mgr.c b/drivers/gpu/drm/amd/ras/core/ras_eeprom_mgr.c index 223e0a791fae..cab2d763fc79 100644 --- a/drivers/gpu/drm/amd/ras/core/ras_eeprom_mgr.c +++ b/drivers/gpu/drm/amd/ras/core/ras_eeprom_mgr.c @@ -26,7 +26,6 @@ #include "ras.h" #include "eeprom.h" #include "eeprom_fw.h" -#include "ras_mp1.h" static bool __ras_eeprom_disabled(struct ras_core_context *ras_core) { @@ -37,36 +36,24 @@ static const struct ras_eeprom_ops *ras_eeprom_mgr_get_ip_func( struct ras_core_context *ras_core, uint32_t ip_version) { struct ras_eeprom_mgr *mgr = &ras_core->eeprom_mgr; - int ret = 0; - u32 status = 0; - - ret = ras_mp1_check_feature_status(ras_core, - (enum ras_mp1_feature_id)RAS_CORE_FW_FEATURE_BIT__RAS_EEPROM, &status); - if (ret) - RAS_DEV_ERR(ras_core->dev, "Check RAS EEPROM feature failed, ret=%d", ret); switch (ip_version) { case IP_VERSION(13, 0, 6): case IP_VERSION(13, 0, 12): case IP_VERSION(13, 0, 14): - case IP_VERSION(13, 0, 15): mgr->eeprom_early_init_service_supported = false; - break; + return &ras_drv_eeprom_ops; + case IP_VERSION(13, 0, 15): case IP_VERSION(15, 0, 8): mgr->eeprom_early_init_service_supported = true; - break; + mgr->fw_record_enabled = true; + return &ras_fw_eeprom_ops; default: RAS_DEV_ERR(ras_core->dev, "EEPROM(MP1) ip version(0x%x) is not supported!\n", ip_version); - return NULL; } - if (status) { - mgr->fw_record_enabled = true; - return &ras_fw_eeprom_ops; - } else { - return &ras_drv_eeprom_ops; - } + return NULL; } int ras_eeprom_mgr_sw_init(struct ras_core_context *ras_core) @@ -98,7 +85,7 @@ int ras_eeprom_mgr_sw_init(struct ras_core_context *ras_core) mgr->ras_err_threshold = param_cfg.eeprom_record_threshold_count; mgr->work_mode_over_thresh = param_cfg.work_mode_over_thresh; mgr->eeprom_ip_version = param_cfg.eeprom_ip_version; - mgr->eeprom_ops = ras_eeprom_mgr_get_ip_func(ras_core, mgr->eeprom_ip_version); + mgr->eeprom_ops = ras_eeprom_mgr_get_ip_func(ras_core, ras_core->config->psp_ip_version); if (!mgr->eeprom_ops) return -ENODEV; diff --git a/drivers/gpu/drm/drm_kms_helper_common.c b/drivers/gpu/drm/drm_kms_helper_common.c index 1e55ecac4698..b9e206b7f9e8 100644 --- a/drivers/gpu/drm/drm_kms_helper_common.c +++ b/drivers/gpu/drm/drm_kms_helper_common.c @@ -43,7 +43,7 @@ EXPORT_SYMBOL(drm_fbdev_overalloc); module_param(drm_fbdev_overalloc, int, 0444); MODULE_PARM_DESC(drm_fbdev_overalloc, "Overallocation of the fbdev buffer (%) [default=" - __MODULE_STRING(CONFIG_DRM_FBDEV_OVERALLOC) "]"); + __stringify(CONFIG_DRM_FBDEV_OVERALLOC) "]"); /* * In order to keep user-space compatibility, we want in certain use-cases diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index d5aadced7da0..1b7f5bf13e50 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -1522,8 +1522,9 @@ static int eb_relocate_vma(struct i915_execbuffer *eb, struct eb_vma *ev) /* * We must check that the entire relocation array is safe - * to read. However, if the array is not writable the user loses - * the updated relocation values. + * to read. Whether it is also writable only shows when we + * write back the presumed offsets below, and if that fails we + * fall back to the slow path. */ if (unlikely(!access_ok(urelocs, remain * sizeof(*urelocs)))) return -EFAULT; @@ -1553,6 +1554,7 @@ static int eb_relocate_vma(struct i915_execbuffer *eb, struct eb_vma *ev) remain -= count; do { u64 offset = eb_relocate_entry(eb, ev, r); + int err; if (likely(offset == 0)) continue; @@ -1562,28 +1564,41 @@ static int eb_relocate_vma(struct i915_execbuffer *eb, struct eb_vma *ev) goto out; } /* - * Note that reporting an error now - * leaves everything in an inconsistent - * state as we have *already* changed - * the relocation value inside the - * object. As we have not changed the - * reloc.presumed_offset or will not - * change the execobject.offset, on the - * call we may not rewrite the value - * inside the object, leaving it - * dangling and causing a GPU hang. Unless - * userspace dynamically rebuilds the - * relocations on each execbuf rather than - * presume a static tree. + * Write back the presumed offset. We hold the + * objects' dma_resv locks here, so this must not + * take a page fault: that would take mmap_lock + * under dma_resv, the opposite of the order our + * own fault handler uses. * - * We did previously check if the relocations - * were writable (access_ok), an error now - * would be a strange race with mprotect, - * having already demonstrated that we - * can read from this userspace address. + * If the write fails (the page is read-only, + * copy-on-write, or gone since we read it), we + * must not just carry on. We have already changed + * the relocation value inside the object, and a + * stale presumed_offset could later match again + * and make us skip a relocation that is needed, + * hanging the GPU. So fall back to the slow path, + * as for a failed read: it retries after + * prefaulting and, failing that, marks every + * presumed_offset invalid with faults allowed and + * no locks held. */ offset = gen8_canonical_addr(offset & ~UPDATE); - __put_user(offset, &urelocs[r - stack].presumed_offset); + pagefault_disable(); + err = put_user(offset, &urelocs[r - stack].presumed_offset); + pagefault_enable(); + + /* + * Error handling is disabled on purpose. No, it makes + * no sense, and the code will loop over the relocations + * without writing them back and just waste CPU time, + * but that's apparently what the mprotect test-cases + * want. See commit 97a37c919f62 ("drm/i915/gem: Ignore + * readonly failures when updating relocs") + */ + if (unlikely(err) && 0) { + remain = -EFAULT; + goto out; + } } while (r++, --count); urelocs += ARRAY_SIZE(stack); } while (remain); @@ -1635,11 +1650,11 @@ static int check_relocations(const struct drm_i915_gem_exec_object2 *entry) end = addr + size; for (; addr < end; addr += PAGE_SIZE) { - int err = __get_user(c, addr); + int err = get_user(c, addr); if (err) return err; } - return __get_user(c, end - 1); + return get_user(c, end - 1); } static int eb_copy_relocations(const struct i915_execbuffer *eb) @@ -2837,7 +2852,7 @@ add_timeline_fence_array(struct i915_execbuffer *eb, if (user_fence.flags & __I915_EXEC_FENCE_UNKNOWN_FLAGS) return -EINVAL; - if (__get_user(point, user_values++)) + if (get_user(point, user_values++)) return -EFAULT; syncobj = drm_syncobj_find(eb->file, user_fence.handle); diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c index 4d49fd6c15e3..303be698891f 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c @@ -1465,7 +1465,7 @@ static int __igt_mmap_access(struct drm_i915_private *i915, return addr; ptr = (unsigned long __user *)addr; - err = __put_user(A, ptr); + err = put_user(A, ptr); if (err) { pr_err("%s(%s): failed to write into user mmap\n", obj->mm.region->name, repr_mmap_type(type)); @@ -1490,7 +1490,7 @@ static int __igt_mmap_access(struct drm_i915_private *i915, intel_gt_flush_ggtt_writes(to_gt(i915)); - err = __get_user(y, ptr); + err = get_user(y, ptr); if (err) { pr_err("%s(%s): failed to read from user mmap\n", obj->mm.region->name, repr_mmap_type(type)); @@ -1738,12 +1738,12 @@ static int prefault_range(u64 start, u64 len) end = addr + len; for (; addr < end; addr += PAGE_SIZE) { - err = __get_user(c, addr); + err = get_user(c, addr); if (err) return err; } - return __get_user(c, end - 1); + return get_user(c, end - 1); } static int __igt_mmap_revoke(struct drm_i915_private *i915, diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 3cbc6eedbf66..eb94916c8f68 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -4847,6 +4847,20 @@ restart_ih: drm_dbg(ddev, "IH: UVD int: 0x%08x\n", src_data); radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX); break; + case 167: /* VCE */ + drm_dbg(ddev, "IH: VCE int: 0x%08x\n", src_data); + switch (src_data) { + case 0: + radeon_fence_process(rdev, TN_RING_TYPE_VCE1_INDEX); + break; + case 1: + radeon_fence_process(rdev, TN_RING_TYPE_VCE2_INDEX); + break; + default: + drm_err(ddev, "Unhandled interrupt: %d %d\n", src_id, src_data); + break; + } + break; case 146: case 147: addr = RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR); diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 4681ff28630a..af3c4026d183 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -6347,6 +6347,20 @@ restart_ih: DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data); radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX); break; + case 167: /* VCE */ + DRM_DEBUG("IH: VCE int: 0x%08x\n", src_data); + switch (src_data) { + case 0: + radeon_fence_process(rdev, TN_RING_TYPE_VCE1_INDEX); + break; + case 1: + radeon_fence_process(rdev, TN_RING_TYPE_VCE2_INDEX); + break; + default: + DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data); + break; + } + break; case 146: case 147: addr = RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR); diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h index f9267b026f8d..ba322de844b3 100644 --- a/drivers/gpu/drm/radeon/sid.h +++ b/drivers/gpu/drm/radeon/sid.h @@ -1878,6 +1878,8 @@ #define DMA_PACKET_NOP 0xf #define VCE_STATUS 0x20004 +#define VCE_SYS_INT_EN 0x20d00 +#define VCE_SYS_INT_TRAP_INTERRUPT_EN (1 << 3) #define VCE_VCPU_CNTL 0x20014 #define VCE_CLK_EN (1 << 0) #define VCE_VCPU_CACHE_OFFSET0 0x20024 diff --git a/drivers/gpu/drm/radeon/uvd_v1_0.c b/drivers/gpu/drm/radeon/uvd_v1_0.c index 5e6607e16244..3a9672eff3da 100644 --- a/drivers/gpu/drm/radeon/uvd_v1_0.c +++ b/drivers/gpu/drm/radeon/uvd_v1_0.c @@ -158,24 +158,48 @@ int uvd_v1_0_init(struct radeon_device *rdev) { struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; uint32_t tmp; - int r; + int r, retry, clk_err; + + /* after resume the first ring test can race with the hardware; retry */ + for (retry = 0; retry < 3; retry++) { + /* raise clocks while booting up the VCPU */ + if (rdev->family < CHIP_RV740) + clk_err = radeon_set_uvd_clocks(rdev, 10000, 10000); + else + clk_err = radeon_set_uvd_clocks(rdev, 53300, 40000); + r = clk_err; + if (r) + drm_warn(&rdev->ddev, "radeon: raising UVD clocks failed (%d), attempt %d\n", + r, retry + 1); + + if (!r) { + r = uvd_v1_0_start(rdev); + if (r) + drm_warn(&rdev->ddev, "radeon: starting UVD failed (%d), attempt %d\n", + r, retry + 1); + } - /* raise clocks while booting up the VCPU */ - if (rdev->family < CHIP_RV740) - radeon_set_uvd_clocks(rdev, 10000, 10000); - else - radeon_set_uvd_clocks(rdev, 53300, 40000); + if (!r) { + ring->ready = true; + r = radeon_ring_test(rdev, R600_RING_TYPE_UVD_INDEX, ring); + if (r) { + ring->ready = false; + drm_warn(&rdev->ddev, "radeon: UVD ring test failed (%d), attempt %d\n", + r, retry + 1); + } + } - r = uvd_v1_0_start(rdev); - if (r) - goto done; + if (!r) + break; - ring->ready = true; - r = radeon_ring_test(rdev, R600_RING_TYPE_UVD_INDEX, ring); - if (r) { - ring->ready = false; - goto done; + /* MMIO is only safe when the block is actually clocked */ + if (!clk_err) + uvd_v1_0_stop(rdev); + if (retry < 2) + mdelay(20); } + if (r) + goto done; r = radeon_ring_lock(rdev, ring, 10); if (r) { diff --git a/drivers/gpu/drm/radeon/vce_v1_0.c b/drivers/gpu/drm/radeon/vce_v1_0.c index bdfbcf14b864..09fc1572ab0a 100644 --- a/drivers/gpu/drm/radeon/vce_v1_0.c +++ b/drivers/gpu/drm/radeon/vce_v1_0.c @@ -350,6 +350,15 @@ int vce_v1_0_start(struct radeon_device *rdev) return r; } + /* + * Enable the trap interrupt so that VCE fences are processed. + * CIK also gets here but has VCE_SYS_INT_EN elsewhere and enables + * it in vce_v2_0_resume(). + */ + if (rdev->family < CHIP_BONAIRE) + WREG32_P(VCE_SYS_INT_EN, VCE_SYS_INT_TRAP_INTERRUPT_EN, + ~VCE_SYS_INT_TRAP_INTERRUPT_EN); + return 0; } diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c index ff611c618d6b..956be198f8a7 100644 --- a/drivers/gpu/drm/vc4/vc4_gem.c +++ b/drivers/gpu/drm/vc4/vc4_gem.c @@ -652,13 +652,14 @@ vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec, fence->seqno = exec->seqno; exec->fence = &fence->base; + /* The job can complete and drop exec->fence as soon as job_lock is + * released, so hold our own reference. + */ if (out_sync) - drm_syncobj_replace_fence(out_sync, exec->fence); + dma_fence_get(&fence->base); vc4_attach_fences(exec); - drm_exec_fini(exec_ctx); - list_add_tail(&exec->head, &vc4->bin_job_list); /* If no bin job was executing and if the render job (if any) has the @@ -675,6 +676,13 @@ vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec, spin_unlock_irqrestore(&vc4->job_lock, irqflags); + drm_exec_fini(exec_ctx); + + if (out_sync) { + drm_syncobj_replace_fence(out_sync, &fence->base); + dma_fence_put(&fence->base); + } + return 0; } diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 10930c924070..6fb916f1699b 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -154,6 +154,7 @@ xe-y += xe_bb.o \ xe_vsec.o \ xe_wa.o \ xe_wait_user_fence.o \ + xe_wedge.o \ xe_wopcm.o xe-$(CONFIG_I2C) += xe_i2c.o \ diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h index f5cd3a94e47f..1d396bc5833b 100644 --- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h +++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h @@ -487,10 +487,6 @@ #define XEHPC_L3CLOS_MASK(i) XE_REG_MCR(0xb194 + (i) * 8) -#define L2COMPUTESIDECTRL XE_REG_MCR(0xb1c0) -#define CECTRL REG_GENMASK(2, 1) -#define CECTRL_CENODATA_ALWAYS REG_FIELD_PREP(CECTRL, 0x0) - #define XE2_GLOBAL_INVAL XE_REG(0xb404) #define XE2LPM_L3SQCREG2 XE_REG_MCR(0xb604) diff --git a/drivers/gpu/drm/xe/regs/xe_lrc_layout.h b/drivers/gpu/drm/xe/regs/xe_lrc_layout.h index 6f7abc0181b5..a2795aa9fd71 100644 --- a/drivers/gpu/drm/xe/regs/xe_lrc_layout.h +++ b/drivers/gpu/drm/xe/regs/xe_lrc_layout.h @@ -45,4 +45,7 @@ #define INDIRECT_CTX_RING_START_UDW (0x08 + 1) #define INDIRECT_CTX_RING_CTL (0x0a + 1) +#define CTX_INDIRECT_CTX_OFFSET_MASK REG_GENMASK(15, 6) +#define CTX_INDIRECT_CTX_OFFSET_DEFAULT REG_FIELD_PREP(CTX_INDIRECT_CTX_OFFSET_MASK, 0xd) + #endif diff --git a/drivers/gpu/drm/xe/tests/xe_kunit_helpers.c b/drivers/gpu/drm/xe/tests/xe_kunit_helpers.c index 27740b40c8ae..57ea88cce92d 100644 --- a/drivers/gpu/drm/xe/tests/xe_kunit_helpers.c +++ b/drivers/gpu/drm/xe/tests/xe_kunit_helpers.c @@ -15,6 +15,7 @@ #include "xe_device.h" #include "xe_device_types.h" #include "xe_pm.h" +#include "xe_wedge.h" /** * xe_kunit_helper_alloc_xe_device - Allocate a &xe_device for a KUnit test. @@ -123,7 +124,7 @@ int xe_kunit_helper_xe_device_live_test_init(struct kunit *test) KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xe); kunit_info(test, "running on %s device\n", xe->info.platform_name); - KUNIT_ASSERT_FALSE(test, xe_device_wedged(xe)); + KUNIT_ASSERT_FALSE(test, xe_wedged(xe)); xe_pm_runtime_get(xe); KUNIT_ASSERT_EQ(test, 0, kunit_add_action_or_reset(test, put_xe_pm_runtime, xe)); diff --git a/drivers/gpu/drm/xe/tests/xe_migrate.c b/drivers/gpu/drm/xe/tests/xe_migrate.c index f10d9513747b..a9ef8f2dcebb 100644 --- a/drivers/gpu/drm/xe/tests/xe_migrate.c +++ b/drivers/gpu/drm/xe/tests/xe_migrate.c @@ -6,9 +6,12 @@ #include <kunit/test.h> #include <kunit/visibility.h> +#include <linux/prandom.h> + #include "tests/xe_kunit_helpers.h" #include "tests/xe_pci_test.h" +#include "xe_migrate.h" #include "xe_pat.h" #include "xe_pci.h" #include "xe_pm.h" @@ -770,9 +773,308 @@ static void xe_validate_ccs_kunit(struct kunit *test) validate_ccs_test_run_device(xe); } +#define ACCESS_MEM_BO_SIZE SZ_512K +#define ACCESS_MEM_NUM_CELLS (ACCESS_MEM_BO_SIZE / sizeof(u32)) +#define ACCESS_MEM_UNALIGNED_OFFSET 0x215ee + +/* + * Verify byte-by-byte that data read from the BO matches expected cell pattern. + * The BO is primed with u32 cells where cell[i] = i, so BO byte at offset B + * has value: (B / 4 >> (B%4 * 8)) & 0xFF. + * + * @buf: the target buffer + * @buf_start: index into buf where read data begins + * @bo_start: the BO byte offset corresponding to buf[buf_start] + * @size: number of bytes to verify + * @scenario: label for error messages + * + * Returns true if all bytes match, false on first mismatch. + */ +static bool verify_access_memory_read(struct kunit *test, u8 *buf, + u32 buf_start, u32 bo_start, + u32 size, const char *scenario) +{ + u32 j; + + for (j = 0; j < size; j++) { + u32 bo_byte_offset = bo_start + j; + u32 byte_in_cell = bo_byte_offset % sizeof(u32); + u32 cell_idx = bo_byte_offset / sizeof(u32); + u32 cell_value = cell_idx; + u8 expected_byte = (cell_value >> (byte_in_cell * 8)) & 0xFF; + u8 got_byte = buf[buf_start + j]; + + if (got_byte != expected_byte) { + u32 context_end = min(j + 8, size - 1); + u32 context_start = (j >= 8) ? j - 8 : 0; + u32 k; + + KUNIT_FAIL(test, + "%s MISMATCH\n" + " Buffer index: %u (0x%x)\n" + " BO offset: 0x%x\n" + " Cell index: %u (BO offset 0x%x..0x%x)\n" + " Byte in cell: %u\n" + " Expected value: 0x%02x (from cell_value 0x%08x)\n" + " Got value: 0x%02x\n", + scenario, + buf_start + j, buf_start + j, + bo_byte_offset, + cell_idx, cell_idx * 4, cell_idx * 4 + 3, + byte_in_cell, + expected_byte, cell_value, + got_byte); + + kunit_info(test, "Buffer context around mismatch (buf[%u..%u]):\n", + buf_start + context_start, + buf_start + context_end); + + for (k = context_start; k <= context_end; k++) { + u32 k_bo_offset = bo_start + k; + u32 k_cell = k_bo_offset / sizeof(u32); + u32 k_byte = k_bo_offset % sizeof(u32); + u32 k_cell_val = k_cell; + u8 k_expected = (k_cell_val >> (k_byte * 8)) & 0xFF; + + kunit_info(test, + " buf[%4u] @ BO 0x%05x: got 0x%02x, expected 0x%02x %s\n", + buf_start + k, k_bo_offset, + buf[buf_start + k], k_expected, + (k == j) ? "<-- MISMATCH" : ""); + } + return false; + } + } + return true; +} + +static void access_memory_test_unaligned_bo_offset(struct kunit *test, + struct xe_migrate *m, + struct xe_bo *bo, u8 *buf, + u32 unaligned_offset) +{ + u32 partial_size = ACCESS_MEM_BO_SIZE - unaligned_offset; + int ret; + + memset(buf, 0, ACCESS_MEM_BO_SIZE); + + kunit_info(test, "Partial read: bo_offset=0x%x bytes=0x%x\n", + unaligned_offset, partial_size); + + ret = xe_migrate_access_memory(m, bo, unaligned_offset, buf, + partial_size, false); + if (ret) { + KUNIT_FAIL(test, "Partial read failed: %d\n", ret); + return; + } + + if (verify_access_memory_read(test, buf, 0, unaligned_offset, + partial_size, + "Partial read from unaligned BO offset")) + kunit_info(test, "Partial read from unaligned BO offset 0x%x verified\n", + unaligned_offset); +} + +static void access_memory_test_unaligned_dst(struct kunit *test, + struct xe_migrate *m, + struct xe_bo *bo, u8 *buf, + u32 unaligned_offset) +{ + u32 partial_size = ACCESS_MEM_BO_SIZE - unaligned_offset; + int ret; + + memset(buf, 0, ACCESS_MEM_BO_SIZE); + + kunit_info(test, "Read to unaligned dst: bo_offset=0x0 dst_offset=0x%x bytes=0x%x\n", + unaligned_offset, partial_size); + + ret = xe_migrate_access_memory(m, bo, 0, buf + unaligned_offset, + partial_size, false); + if (ret) { + KUNIT_FAIL(test, "Read to unaligned dst failed: %d\n", ret); + return; + } + + if (verify_access_memory_read(test, buf, unaligned_offset, 0, + partial_size, + "Read to unaligned dst")) + kunit_info(test, "Read to unaligned dst offset 0x%x verified\n", + unaligned_offset); +} + +static void access_memory_test_unaligned_dst_aligned_size(struct kunit *test, + struct xe_migrate *m, + struct xe_bo *bo, + u8 *buf, + u32 unaligned_offset) +{ + u32 partial_size = round_down(ACCESS_MEM_BO_SIZE - unaligned_offset, 4); + int ret; + + memset(buf, 0, ACCESS_MEM_BO_SIZE); + + kunit_info(test, "Read to unaligned dst (aligned size): bo_offset=0x0 dst_offset=0x%x bytes=0x%x\n", + unaligned_offset, partial_size); + + ret = xe_migrate_access_memory(m, bo, 0, buf + unaligned_offset, + partial_size, false); + if (ret) { + KUNIT_FAIL(test, "Read to unaligned dst (aligned size) failed: %d\n", ret); + return; + } + + if (verify_access_memory_read(test, buf, unaligned_offset, 0, + partial_size, + "Read to unaligned dst (aligned size)")) + kunit_info(test, "Read to unaligned dst (aligned size) offset 0x%x verified\n", + unaligned_offset); +} + +static void access_memory_test_run_tile(struct xe_device *xe, + struct xe_tile *tile, + struct kunit *test, + bool use_random_offset) +{ + struct drm_exec *exec = XE_VALIDATION_OPT_OUT; + unsigned int bo_flags = XE_BO_FLAG_VRAM_IF_DGFX(tile); + struct xe_migrate *m = tile->migrate; + u32 j, unaligned_offset; + struct xe_bo *bo; + long timeout; + u8 *buf; + int ret; + + if (use_random_offset) { + unaligned_offset = get_random_u32() % (ACCESS_MEM_BO_SIZE / 2); + /* Ensure the offset is not 4-byte aligned */ + if (IS_ALIGNED(unaligned_offset, 4)) + unaligned_offset |= 2; + if (!unaligned_offset) + unaligned_offset = 3; + } else { + unaligned_offset = ACCESS_MEM_UNALIGNED_OFFSET; + } + + kunit_info(test, "Using unaligned offset: 0x%x (%s)\n", + unaligned_offset, use_random_offset ? "random" : "predefined"); + + buf = kvmalloc(ACCESS_MEM_BO_SIZE, GFP_KERNEL); + if (!buf) { + KUNIT_FAIL(test, "Failed to allocate buffer\n"); + return; + } + + bo = xe_bo_create_user(xe, NULL, ACCESS_MEM_BO_SIZE, + DRM_XE_GEM_CPU_CACHING_WC, + bo_flags | XE_BO_FLAG_NEEDS_CPU_ACCESS, NULL); + if (IS_ERR(bo)) { + KUNIT_FAIL(test, "Failed to create bo: %pe\n", bo); + goto free_buf; + } + + /* Prime the BO */ + for (j = 0; j < ACCESS_MEM_NUM_CELLS; j++) + ((u32 *)buf)[j] = j; + + kunit_info(test, "Writing %lu KiB to VRAM bo\n", + (unsigned long)ACCESS_MEM_BO_SIZE / SZ_1K); + + xe_bo_lock(bo, false); + + /* The BO is unpinned, so make sure it is in VRAM once locked */ + ret = xe_bo_validate(bo, NULL, false, exec); + if (ret) { + KUNIT_FAIL(test, "Failed to validate bo: %d\n", ret); + goto cleanup_bo; + } + + if (!xe_bo_is_vram(bo)) { + KUNIT_FAIL(test, "BO is not in VRAM after validation\n"); + goto cleanup_bo; + } + + timeout = dma_resv_wait_timeout(bo->ttm.base.resv, DMA_RESV_USAGE_KERNEL, + true, 5 * HZ); + if (timeout <= 0) { + KUNIT_FAIL(test, "Failed to wait for bo to become idle: %ld\n", + timeout); + goto cleanup_bo; + } + + ret = xe_migrate_access_memory(m, bo, 0, buf, ACCESS_MEM_BO_SIZE, true); + if (ret) { + KUNIT_FAIL(test, "Failed to write bo: %d\n", ret); + goto cleanup_bo; + } + + /* Full read */ + memset(buf, 0, ACCESS_MEM_BO_SIZE); + kunit_info(test, "Full read: bo_offset=0x0 bytes=0x%x\n", ACCESS_MEM_BO_SIZE); + + ret = xe_migrate_access_memory(m, bo, 0, buf, ACCESS_MEM_BO_SIZE, false); + if (ret) { + KUNIT_FAIL(test, "Full read failed: %d\n", ret); + goto cleanup_bo; + } + + for (j = 0; j < ACCESS_MEM_NUM_CELLS; j++) { + u32 expected = j; + u32 got = ((u32 *)buf)[j]; + + if (got != expected) { + KUNIT_FAIL(test, + "Full read mismatch at cell %u: expected 0x%08x, got 0x%08x\n", + j, expected, got); + goto cleanup_bo; + } + } + kunit_info(test, "Full read verified\n"); + + access_memory_test_unaligned_bo_offset(test, m, bo, buf, unaligned_offset); + access_memory_test_unaligned_dst(test, m, bo, buf, unaligned_offset); + access_memory_test_unaligned_dst_aligned_size(test, m, bo, buf, unaligned_offset); + +cleanup_bo: + xe_bo_unlock(bo); + xe_bo_put(bo); +free_buf: + kvfree(buf); +} + +static int access_memory_test_run_device(struct xe_device *xe) +{ + struct kunit *test = kunit_get_current_test(); + struct xe_tile *tile; + int id; + + if (!IS_DGFX(xe)) { + kunit_skip(test, "non-discrete device\n"); + return 0; + } + + guard(xe_pm_runtime)(xe); + for_each_tile(tile, xe, id) { + kunit_info(test, "Testing tile id %d (predefined offset)\n", id); + access_memory_test_run_tile(xe, tile, test, false); + + kunit_info(test, "Testing tile id %d (random offset)\n", id); + access_memory_test_run_tile(xe, tile, test, true); + } + + return 0; +} + +static void xe_migrate_access_memory_kunit(struct kunit *test) +{ + struct xe_device *xe = test->priv; + + access_memory_test_run_device(xe); +} + static struct kunit_case xe_migrate_tests[] = { KUNIT_CASE_PARAM(xe_migrate_sanity_kunit, xe_pci_live_device_gen_param), KUNIT_CASE_PARAM(xe_validate_ccs_kunit, xe_pci_live_device_gen_param), + KUNIT_CASE_PARAM(xe_migrate_access_memory_kunit, xe_pci_live_device_gen_param), {} }; diff --git a/drivers/gpu/drm/xe/xe_amc.c b/drivers/gpu/drm/xe/xe_amc.c index edd50bf8261e..37694e34271a 100644 --- a/drivers/gpu/drm/xe/xe_amc.c +++ b/drivers/gpu/drm/xe/xe_amc.c @@ -15,9 +15,12 @@ #include "regs/xe_i2c_regs.h" #include "xe_amc.h" +#include "xe_any.h" #include "xe_device.h" #include "xe_i2c.h" #include "xe_mmio.h" +#include "xe_pm.h" +#include "xe_wedge.h" /** * DOC: Add-In Management Controller (AMC) @@ -108,11 +111,14 @@ static void xe_amc_work(struct work_struct *work) { const struct amc_request *request = &amc_get_alert_reason; struct xe_amc *amc = from_work(amc, work, work); + struct xe_device *xe = xe_any_to_xe(amc->i2c->drm_dev); u8 alert_reason = AMC_ALERT_UNKNOWN; struct amc_response response; struct i2c_client *client; int ret; + xe_pm_runtime_get(xe); + client = amc->i2c->client[XE_I2C_CLIENT_AMC]; if (IS_ERR_OR_NULL(client)) goto out_reassert_interrupt; @@ -160,12 +166,15 @@ out_reassert_interrupt: case AMC_ALERT_OOB_RESET: case AMC_ALERT_CATERR: dev_warn(amc->i2c->drm_dev, "AMC Alert: %s\n", amc_alert[alert_reason]); - xe_device_declare_wedged(i2c_client_to_xe_device(client)); + xe_wedge_declare(i2c_client_to_xe_device(client), + DRM_WEDGE_RECOVERY_REBIND | DRM_WEDGE_RECOVERY_BUS_RESET); break; default: dev_warn(amc->i2c->drm_dev, "unknown AMC alert: %d\n", alert_reason); break; } + + xe_pm_runtime_put(xe); } void xe_amc_handle_alert(struct xe_i2c *i2c) diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index 1b74331b15ec..42a6aa1a2e4a 100644 --- a/drivers/gpu/drm/xe/xe_bo.c +++ b/drivers/gpu/drm/xe/xe_bo.c @@ -41,6 +41,7 @@ #include "xe_ttm_stolen_mgr.h" #include "xe_vm.h" #include "xe_vram_types.h" +#include "xe_wedge.h" const char *const xe_mem_type_to_name[TTM_NUM_MEM_TYPES] = { [XE_PL_SYSTEM] = "system", @@ -992,6 +993,38 @@ static void xe_bo_set_purgeable_shrinker(struct xe_bo *bo, } } +/* + * Change @bo's TTM LRU priority to @priority. @bo's dma-resv must be held. + * + * Private, user BOs of non-fault-mode VMs have bo->ttm.bulk_move set to their + * VM's LRU bulk-move range (see xe_bo_create_user()), which tracks a + * contiguous [first, last] run of resources per (mem_type, priority) bucket. + * Writing bo->ttm.priority while the BO is still attached to that range would + * leave the resource linked in the old priority's bucket while the bulk-move + * code looks it up under the new one, corrupting both buckets. Temporarily + * detaching the BO from its bulk-move range moves it with a plain, non-bulk + * LRU update instead, and reattaching afterwards re-inserts it into the new + * priority's bucket. + */ +static void xe_bo_update_ttm_priority(struct xe_bo *bo, int priority) +{ + struct ttm_lru_bulk_move *bulk = bo->ttm.bulk_move; + + xe_bo_assert_held(bo); + + if (bo->ttm.priority == priority) + return; + + if (bulk) + ttm_bo_set_bulk_move(&bo->ttm, NULL); + + bo->ttm.priority = priority; + ttm_bo_move_to_lru_tail_unlocked(&bo->ttm); + + if (bulk) + ttm_bo_set_bulk_move(&bo->ttm, bulk); +} + /** * xe_bo_set_purgeable_state() - Set BO purgeable state with validation * @bo: Buffer object @@ -1001,6 +1034,10 @@ static void xe_bo_set_purgeable_shrinker(struct xe_bo *bo, * transitions. Once a BO is PURGED, it cannot transition to any other state. * Invalid transitions are caught with xe_assert(). Shrinker page accounting * is updated automatically. + * + * A WILLNEED -> DONTNEED transition also lowers the BO's TTM LRU priority to + * XE_BO_PRIORITY_LOW. Conversely, a DONTNEED -> WILLNEED transition restores + * XE_BO_PRIORITY_NORMAL. */ void xe_bo_set_purgeable_state(struct xe_bo *bo, enum xe_madv_purgeable_state new_state) @@ -1018,6 +1055,13 @@ void xe_bo_set_purgeable_state(struct xe_bo *bo, xe_assert(xe, !(bo->purgeable.state == XE_MADV_PURGEABLE_PURGED && new_state != XE_MADV_PURGEABLE_PURGED)); + if (new_state == XE_MADV_PURGEABLE_DONTNEED && + bo->purgeable.state == XE_MADV_PURGEABLE_WILLNEED) + xe_bo_update_ttm_priority(bo, XE_BO_PRIORITY_LOW); + else if (new_state == XE_MADV_PURGEABLE_WILLNEED && + bo->purgeable.state == XE_MADV_PURGEABLE_DONTNEED) + xe_bo_update_ttm_priority(bo, XE_BO_PRIORITY_NORMAL); + bo->purgeable.state = new_state; xe_bo_set_purgeable_shrinker(bo, new_state); } @@ -2203,7 +2247,7 @@ static vm_fault_t xe_bo_cpu_fault(struct vm_fault *vmf) int err = 0; int idx; - if (xe_device_wedged(xe) || !drm_dev_enter(&xe->drm, &idx)) + if (xe_wedged(xe) || !drm_dev_enter(&xe->drm, &idx)) return ttm_bo_vm_dummy_page(vmf, vmf->vma->vm_page_prot); ret = xe_bo_cpu_fault_fastpath(vmf, xe, bo, needs_rpm); diff --git a/drivers/gpu/drm/xe/xe_bo_types.h b/drivers/gpu/drm/xe/xe_bo_types.h index 8ec4a01a0092..0265fb314c77 100644 --- a/drivers/gpu/drm/xe/xe_bo_types.h +++ b/drivers/gpu/drm/xe/xe_bo_types.h @@ -24,7 +24,13 @@ struct xe_exec_queue; #define XE_BO_MAX_PLACEMENTS 3 -/* TODO: To be selected with VM_MADVISE */ +/* + * TTM LRU priority bands. The LRU is walked in ascending priority order, so + * XE_BO_PRIORITY_LOW objects are the first candidates for eviction and + * shrinking. BOs advised DONTNEED through DRM_XE_MADVISE live at + * XE_BO_PRIORITY_LOW, everything else at XE_BO_PRIORITY_NORMAL. + */ +#define XE_BO_PRIORITY_LOW 0 #define XE_BO_PRIORITY_NORMAL 1 /** diff --git a/drivers/gpu/drm/xe/xe_configfs.h b/drivers/gpu/drm/xe/xe_configfs.h index 10a00d6bbf8f..327b648944ff 100644 --- a/drivers/gpu/drm/xe/xe_configfs.h +++ b/drivers/gpu/drm/xe/xe_configfs.h @@ -14,7 +14,7 @@ struct pci_dev; -#if IS_ENABLED(CONFIG_CONFIGFS_FS) +#if IS_REACHABLE(CONFIG_CONFIGFS_FS) int xe_configfs_init(void); void xe_configfs_exit(void); void xe_configfs_check_device(struct pci_dev *pdev); diff --git a/drivers/gpu/drm/xe/xe_debugfs.c b/drivers/gpu/drm/xe/xe_debugfs.c index 926020c7526e..e59d4964d811 100644 --- a/drivers/gpu/drm/xe/xe_debugfs.c +++ b/drivers/gpu/drm/xe/xe_debugfs.c @@ -18,13 +18,12 @@ #include "xe_force_wake.h" #include "xe_gt.h" #include "xe_gt_debugfs.h" -#include "xe_gt_printk.h" -#include "xe_guc_ads.h" #include "xe_hw_engine.h" #include "xe_mmio.h" #include "xe_pagefault.h" #include "xe_pcode.h" #include "xe_pm.h" +#include "xe_printk.h" #include "xe_psmi.h" #include "xe_pxp_debugfs.h" #include "xe_sriov.h" @@ -36,6 +35,7 @@ #include "xe_ttm_vram_mgr.h" #include "xe_vsec.h" #include "xe_wa.h" +#include "xe_wedge.h" #ifdef CONFIG_DRM_XE_DEBUG #include "xe_bo_evict.h" @@ -424,58 +424,6 @@ static ssize_t wedged_mode_show(struct file *f, char __user *ubuf, return simple_read_from_buffer(ubuf, size, pos, buf, len); } -static int __wedged_mode_set_reset_policy(struct xe_gt *gt, enum xe_wedged_mode mode) -{ - bool enable_engine_reset; - int ret; - - enable_engine_reset = (mode != XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET); - ret = xe_guc_ads_scheduler_policy_toggle_reset(>->uc.guc.ads, - enable_engine_reset); - if (ret) - xe_gt_err(gt, "Failed to update GuC ADS scheduler policy (%pe)\n", ERR_PTR(ret)); - - return ret; -} - -static int wedged_mode_set_reset_policy(struct xe_device *xe, enum xe_wedged_mode mode) -{ - struct xe_gt *gt; - int ret; - u8 id; - - guard(xe_pm_runtime)(xe); - for_each_gt(gt, xe, id) { - ret = __wedged_mode_set_reset_policy(gt, mode); - if (ret) { - if (id > 0) { - xe->wedged.inconsistent_reset = true; - drm_err(&xe->drm, "Inconsistent reset policy state between GTs\n"); - } - return ret; - } - } - - xe->wedged.inconsistent_reset = false; - - return 0; -} - -static bool wedged_mode_needs_policy_update(struct xe_device *xe, enum xe_wedged_mode mode) -{ - if (xe->wedged.inconsistent_reset) - return true; - - if (xe->wedged.mode == mode) - return false; - - if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET || - mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) - return true; - - return false; -} - static ssize_t wedged_mode_set(struct file *f, const char __user *ubuf, size_t size, loff_t *pos) { @@ -487,18 +435,10 @@ static ssize_t wedged_mode_set(struct file *f, const char __user *ubuf, if (ret) return ret; - ret = xe_device_validate_wedged_mode(xe, wedged_mode); + ret = xe_wedge_set_mode(xe, wedged_mode); if (ret) return ret; - if (wedged_mode_needs_policy_update(xe, wedged_mode)) { - ret = wedged_mode_set_reset_policy(xe, wedged_mode); - if (ret) - return ret; - } - - xe->wedged.mode = wedged_mode; - return size; } diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 4caf86be8c29..07a7ab6ac083 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -81,6 +81,7 @@ #include "xe_vsec.h" #include "xe_wait_user_fence.h" #include "xe_wa.h" +#include "xe_wedge.h" #include <generated/xe_device_wa_oob.h> #include <generated/xe_wa_oob.h> @@ -238,7 +239,7 @@ static long xe_drm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) struct xe_device *xe = to_xe_device(file_priv->minor->dev); long ret; - if (xe_device_wedged(xe)) + if (xe_wedged(xe)) return -ECANCELED; ACQUIRE(xe_pm_runtime_ioctl, pm)(xe); @@ -256,7 +257,7 @@ static long xe_drm_compat_ioctl(struct file *file, unsigned int cmd, unsigned lo struct xe_device *xe = to_xe_device(file_priv->minor->dev); long ret; - if (xe_device_wedged(xe)) + if (xe_wedged(xe)) return -ECANCELED; ACQUIRE(xe_pm_runtime_ioctl, pm)(xe); @@ -756,19 +757,37 @@ int xe_device_probe_early(struct xe_device *xe) */ assert_lmem_ready(xe); - xe->wedged.mode = xe_device_validate_wedged_mode(xe, xe_modparam.wedged_mode) ? - XE_DEFAULT_WEDGED_MODE : xe_modparam.wedged_mode; - drm_dbg(&xe->drm, "wedged_mode: setting mode (%u) %s\n", - xe->wedged.mode, xe_wedged_mode_to_string(xe->wedged.mode)); - err = xe_device_vram_alloc(xe); if (err) return err; + err = xe_wedge_init(xe); + if (err) + return err; + return 0; } ALLOW_ERROR_INJECTION(xe_device_probe_early, ERRNO); /* See xe_pci_probe() */ +static void override_has_cached_pt(struct xe_device *xe) +{ + struct xe_gt *gt; + u8 id; + + for_each_gt(gt, xe, id) { + /* + * Wa_16029380221: The affected GT will always use + * non-coherent access to page tables, so we must do + * uncached writes from the CPU. + */ + if (XE_GT_WA(gt, 16029380221)) + xe->info.has_cached_pt = false; + + if (XE_GT_WA(gt, 14026539277)) + xe->info.has_cached_pt = false; + } +} + static int probe_has_flat_ccs(struct xe_device *xe) { struct xe_gt *gt; @@ -851,14 +870,6 @@ static void detect_preproduction_hw(struct xe_device *xe) } } -static void xe_device_wedged_fini(struct drm_device *drm, void *arg) -{ - struct xe_device *xe = arg; - - if (atomic_read(&xe->wedged.flag)) - xe_pm_runtime_put(xe); -} - #ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE static int xe_debug_page_size_alloc_ctrl_init(struct xe_device *xe) { @@ -919,14 +930,7 @@ int xe_device_probe(struct xe_device *xe) return err; } - /* - * Wa_16029380221: The affected GT will always use non-coherent - * access to page tables, so we must do uncached writes from the - * CPU. - */ - for_each_gt(gt, xe, id) - if (XE_GT_WA(gt, 16029380221)) - xe->info.has_cached_pt = false; + override_has_cached_pt(xe); for_each_tile(tile, xe, id) { err = xe_ggtt_init_early(tile->mem.ggtt); @@ -1099,17 +1103,6 @@ int xe_device_probe(struct xe_device *xe) detect_preproduction_hw(xe); - err = drmm_add_action_or_reset(&xe->drm, xe_device_wedged_fini, xe); - if (err) - goto err_unregister_display; - - /* - * Process and log any errors detected by hardware. Possible results can - * include declaring the device as wedged, which must be done only after - * xe_device_wedged_fini() is registered. - */ - xe_ras_process_errors(xe); - err = devm_add_action_or_reset(xe->drm.dev, xe_device_sanitize, xe); if (err) goto err_unregister_display; @@ -1346,163 +1339,6 @@ u64 xe_device_uncanonicalize_addr(struct xe_device *xe, u64 address) } /** - * DOC: Xe Device Wedging - * - * Xe driver uses drm device wedged uevent as documented in Documentation/gpu/drm-uapi.rst. - * When device is in wedged state, every IOCTL will be blocked and GT cannot - * be used. The conditions under which the driver declares the device wedged - * depend on the wedged mode configuration (see &enum xe_wedged_mode). The - * default recovery method for a wedged state is rebind/bus-reset. - * - * Another recovery method is vendor-specific. Below are the cases that send - * ``WEDGED=vendor-specific`` recovery method in drm device wedged uevent. - * - * Case: Firmware Flash - * -------------------- - * - * Identification Hint - * +++++++++++++++++++ - * - * ``WEDGED=vendor-specific`` drm device wedged uevent with - * :ref:`Runtime Survivability mode <xe-survivability-mode>` is used to notify - * admin/userspace consumer about the need for a firmware flash. - * - * Recovery Procedure - * ++++++++++++++++++ - * - * Once ``WEDGED=vendor-specific`` drm device wedged uevent is received, follow - * the below steps - * - * - Check Runtime Survivability mode sysfs. - * If enabled, firmware flash is required to recover the device. - * - * /sys/bus/pci/devices/<device>/survivability_mode - * - * - Admin/userspace consumer can use firmware flashing tools like fwupd to flash - * firmware and restore device to normal operation. - */ - -/** - * xe_device_set_wedged_method - Set wedged recovery method - * @xe: xe device instance - * @method: recovery method to set - * - * Set wedged recovery method to be sent in drm wedged uevent. - */ -void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method) -{ - xe->wedged.method = method; -} - -#define WEDGED_URL "https://docs.kernel.org/gpu/drm-uapi.html#device-wedging" -#define XE_BUG_URL "https://gitlab.freedesktop.org/drm/xe/kernel/issues/new" - -/** - * xe_device_declare_wedged - Declare device wedged - * @xe: xe device instance - * - * This is a final state that can only be cleared with the recovery method - * specified in the drm wedged uevent. The method can be set using - * xe_device_set_wedged_method before declaring the device as wedged. If no method - * is set, reprobe (unbind/re-bind) will be sent by default. - * - * In this state every IOCTL will be blocked so the GT cannot be used. - * In general it will be called upon any critical error such as gt reset - * failure or guc loading failure. Userspace will be notified of this state - * through device wedged uevent. - * If xe.wedged module parameter is set to 2, this function will be called - * on every single execution timeout (a.k.a. GPU hang) right after devcoredump - * snapshot capture. In this mode, GT reset won't be attempted so the state of - * the issue is preserved for further debugging. - */ -void xe_device_declare_wedged(struct xe_device *xe) -{ - struct xe_gt *gt; - u8 id; - - if (xe->wedged.mode == XE_WEDGED_MODE_NEVER) { - drm_dbg(&xe->drm, "Wedged mode is forcibly disabled\n"); - return; - } - - if (!atomic_xchg(&xe->wedged.flag, 1)) { - xe->needs_flr_on_fini = true; - xe_pm_runtime_get_noresume(xe); - - xe_log_err_fatal(xe, WEDGED, -EIO, "Device declared wedged!\n"); - xe_err_once(xe, "IOCTLs and executions are now blocked!\n" - "For recovery procedure, refer to %s\n" - "Please file a _new_ bug report at %s\n", - WEDGED_URL, XE_BUG_URL); - } - - for_each_gt(gt, xe, id) - xe_gt_declare_wedged(gt); - - if (xe_device_wedged(xe)) { - /* - * XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET is intended for debugging - * hangs, so wedge the device with 'none' recovery method and have - * it available to the user for debugging. - */ - if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) - xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_NONE); - /* If no wedge recovery method is set, use default */ - else if (!xe->wedged.method) - xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_REBIND | - DRM_WEDGE_RECOVERY_BUS_RESET); - - /* Notify userspace of wedged device */ - drm_dev_wedged_event(&xe->drm, xe->wedged.method, NULL); - } -} - -/** - * xe_device_validate_wedged_mode - Check if given mode is supported - * @xe: the &xe_device - * @mode: requested mode to validate - * - * Check whether the provided wedged mode is supported. - * - * Return: 0 if mode is supported, error code otherwise. - */ -int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode) -{ - if (mode > XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) { - drm_dbg(&xe->drm, "wedged_mode: invalid value (%u)\n", mode); - return -EINVAL; - } else if (mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET && (IS_SRIOV_VF(xe) || - (IS_SRIOV_PF(xe) && !IS_ENABLED(CONFIG_DRM_XE_DEBUG)))) { - drm_dbg(&xe->drm, "wedged_mode: (%u) %s mode is not supported for %s\n", - mode, xe_wedged_mode_to_string(mode), - xe_sriov_mode_to_string(xe_device_sriov_mode(xe))); - return -EPERM; - } - - return 0; -} - -/** - * xe_wedged_mode_to_string - Convert enum value to string. - * @mode: the &xe_wedged_mode to convert - * - * Returns: wedged mode as a user friendly string. - */ -const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode) -{ - switch (mode) { - case XE_WEDGED_MODE_NEVER: - return "never"; - case XE_WEDGED_MODE_UPON_CRITICAL_ERROR: - return "upon-critical-error"; - case XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET: - return "upon-any-hang-no-reset"; - default: - return "<invalid>"; - } -} - -/** * xe_device_asid_to_vm() - Find VM from ASID * @xe: the &xe_device * @asid: Address space ID diff --git a/drivers/gpu/drm/xe/xe_device.h b/drivers/gpu/drm/xe/xe_device.h index 83d6dafab53c..6df60edcb8f8 100644 --- a/drivers/gpu/drm/xe/xe_device.h +++ b/drivers/gpu/drm/xe/xe_device.h @@ -139,6 +139,10 @@ static inline bool xe_device_uc_enabled(struct xe_device *xe) for_each_gt((gt__), (tile__)->xe, (id__)) \ for_each_if((gt__)->tile == (tile__)) +#define for_each_initialized_gt(gt__, xe__, id__) \ + for_each_gt((gt__), (xe__), (id__)) \ + for_each_if(READ_ONCE((gt__)->initialized)) + static inline struct xe_force_wake *gt_to_fw(struct xe_gt *gt) { return >->pm.fw; @@ -207,11 +211,6 @@ bool xe_device_is_l2_flush_optimized(struct xe_device *xe); void xe_device_td_flush(struct xe_device *xe); void xe_device_l2_flush(struct xe_device *xe, bool force); -static inline bool xe_device_wedged(struct xe_device *xe) -{ - return atomic_read(&xe->wedged.flag); -} - #ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE static inline bool xe_debug_page_size_supported(struct xe_device *xe) { @@ -260,11 +259,6 @@ static inline bool xe_debug_page_size_mode_is_mixed(struct xe_device *xe) } #endif -void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method); -void xe_device_declare_wedged(struct xe_device *xe); -int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode); -const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode); - struct xe_file *xe_file_get(struct xe_file *xef); void xe_file_put(struct xe_file *xef); diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index aa3a98ddb457..6a6f9a24365c 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -31,6 +31,7 @@ #include "xe_sysctrl_types.h" #include "xe_tile_types.h" #include "xe_validation.h" +#include "xe_wedge_types.h" #if IS_ENABLED(CONFIG_DRM_XE_DEBUG) #define TEST_VM_OPS_ERROR @@ -48,22 +49,6 @@ struct xe_pxp; struct xe_ttm_stolen_mgr; struct xe_vram_region; -/** - * enum xe_wedged_mode - possible wedged modes - * @XE_WEDGED_MODE_NEVER: Device will never be declared wedged. - * @XE_WEDGED_MODE_UPON_CRITICAL_ERROR: Device will be declared wedged only - * when critical error occurs like GT reset failure or firmware failure. - * This is the default mode. - * @XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET: Device will be declared wedged on - * any hang. In this mode, engine resets are disabled to avoid automatic - * recovery attempts. This mode is primarily intended for debugging hangs. - */ -enum xe_wedged_mode { - XE_WEDGED_MODE_NEVER = 0, - XE_WEDGED_MODE_UPON_CRITICAL_ERROR = 1, - XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET = 2, -}; - #ifdef CONFIG_DRM_XE_DEBUG_PAGE_SIZE /** * enum xe_page_size_alloc_ctrl_mode - User BO page-size allocation control modes @@ -556,16 +541,7 @@ struct xe_device { atomic_t in_reset; /** @wedged: Struct to control Wedged States and mode */ - struct { - /** @wedged.flag: Xe device faced a critical error and is now blocked. */ - atomic_t flag; - /** @wedged.mode: Mode controlled by kernel parameter and debugfs */ - enum xe_wedged_mode mode; - /** @wedged.method: Recovery method to be sent in the drm device wedged uevent */ - unsigned long method; - /** @wedged.inconsistent_reset: Inconsistent reset policy state between GTs */ - bool inconsistent_reset; - } wedged; + struct xe_wedge wedged; /** @devres_group: devres group */ void *devres_group; diff --git a/drivers/gpu/drm/xe/xe_device_wa_oob.rules b/drivers/gpu/drm/xe/xe_device_wa_oob.rules index d8dc41851425..356b4707dafe 100644 --- a/drivers/gpu/drm/xe/xe_device_wa_oob.rules +++ b/drivers/gpu/drm/xe/xe_device_wa_oob.rules @@ -3,7 +3,6 @@ PLATFORM(PANTHERLAKE) 22019338487_display PLATFORM(LUNARLAKE) 14022085890 SUBPLATFORM(BATTLEMAGE, G21) -14026539277 PLATFORM(NOVALAKE_P), PLATFORM_STEP(A0, B0) 14026633728 PLATFORM(CRESCENTISLAND) 14026746987 PLATFORM(CRESCENTISLAND) 14026779378 PLATFORM(CRESCENTISLAND) diff --git a/drivers/gpu/drm/xe/xe_gsc.c b/drivers/gpu/drm/xe/xe_gsc.c index 524ac56bdcc7..db669a953886 100644 --- a/drivers/gpu/drm/xe/xe_gsc.c +++ b/drivers/gpu/drm/xe/xe_gsc.c @@ -31,6 +31,7 @@ #include "xe_sched_job.h" #include "xe_uc_fw.h" #include "xe_wa.h" +#include "xe_wedge.h" #include "instructions/xe_gsc_commands.h" #include "regs/xe_gsc_regs.h" #include "regs/xe_gt_regs.h" @@ -340,7 +341,8 @@ static int gsc_er_complete(struct xe_gt *gt) * declare the device as wedged. */ xe_gt_err(gt, "GSC ER timed out!\n"); - xe_device_declare_wedged(gt_to_xe(gt)); + xe_wedge_declare(gt_to_xe(gt), + DRM_WEDGE_RECOVERY_REBIND | DRM_WEDGE_RECOVERY_BUS_RESET); return -EIO; } diff --git a/drivers/gpu/drm/xe/xe_gt.c b/drivers/gpu/drm/xe/xe_gt.c index bc9bf6f0b5a7..45fb074812a2 100644 --- a/drivers/gpu/drm/xe/xe_gt.c +++ b/drivers/gpu/drm/xe/xe_gt.c @@ -12,7 +12,6 @@ #include <drm/drm_managed.h> #include <uapi/drm/xe_drm.h> -#include <generated/xe_device_wa_oob.h> #include <generated/xe_wa_oob.h> #include "instructions/xe_alu_commands.h" @@ -68,6 +67,7 @@ #include "xe_uc_fw.h" #include "xe_vm.h" #include "xe_wa.h" +#include "xe_wedge.h" #include "xe_wopcm.h" #define GRDOM_RESET_TIMEOUT_MS 5 @@ -175,6 +175,7 @@ static void xe_gt_enable_comp_1wcoh(struct xe_gt *gt) } static void gt_reset_worker(struct work_struct *w); +static void gt_wedge_worker(struct work_struct *w); static int emit_job_sync(struct xe_exec_queue *q, struct xe_bb *bb, long timeout_jiffies, bool force_reset) @@ -458,35 +459,6 @@ put_exec_queue: return err; } -static void wa_14026539277(struct xe_gt *gt) -{ - struct xe_device *xe = gt_to_xe(gt); - u32 val; - - /* - * FIXME: We currently can't use FUNC(xe_rtp_match_not_sriov_vf) in the - * rules for Wa_14026539277 due to xe_wa_process_device_oob() being - * called before xe_sriov_probe_early(); and we can't move the call to - * the former to happen after the latter because MMIO read functions - * already depend on a device OOB workaround. This needs to be fixed by - * allowing workaround checks to happen at different stages of driver - * initialization. - */ - if (IS_SRIOV_VF(xe)) - return; - - if (!XE_DEVICE_WA(xe, 14026539277)) - return; - - if (!xe_gt_is_main_type(gt)) - return; - - val = xe_gt_mcr_unicast_read_any(gt, L2COMPUTESIDECTRL); - val &= ~CECTRL; - val |= CECTRL_CENODATA_ALWAYS; - xe_gt_mcr_multicast_write(gt, L2COMPUTESIDECTRL, val); -} - int xe_gt_init_early(struct xe_gt *gt) { int err; @@ -546,6 +518,8 @@ int xe_gt_init_early(struct xe_gt *gt) xe_gt_mcr_init_early(gt); xe_pat_init(gt); + INIT_WORK(>->reset.worker, gt_reset_worker); + INIT_WORK(>->wedge.worker, gt_wedge_worker); return 0; } @@ -618,28 +592,24 @@ static int gt_init_with_gt_forcewake(struct xe_gt *gt) else gt->info.has_wmtp_disabled = 0; - /* - * Wa_14026539277 can't be implemented as a regular GT workaround (i.e. - * as an entry in gt_was[]) for two reasons: it is actually a device - * workaround that happens to involve programming a GT register; and it - * needs to be applied early to avoid getting the hardware in a bad - * state before we have a chance to do the necessary programming. - */ - wa_14026539277(gt); - return 0; } -static void gt_reset_worker_disable(void *arg) +static void gt_worker_disable(void *arg) { struct xe_gt *gt = arg; + WRITE_ONCE(gt->initialized, false); + if (disable_work_sync(>->reset.worker)) /* * If gt_reset_worker was halted from executing, take care of * releasing the rpm reference here. */ xe_pm_runtime_put(gt_to_xe(gt)); + + if (disable_work_sync(>->wedge.worker)) + xe_pm_runtime_put(gt_to_xe(gt)); } static int gt_init_with_all_forcewake(struct xe_gt *gt) @@ -712,7 +682,7 @@ static int gt_init_with_all_forcewake(struct xe_gt *gt) xe_gt_sriov_pf_init_hw(gt); /* Last action registered here so devres drains resets before teardown */ - err = devm_add_action_or_reset(xe->drm.dev, gt_reset_worker_disable, gt); + err = devm_add_action_or_reset(xe->drm.dev, gt_worker_disable, gt); if (err) return err; @@ -724,7 +694,7 @@ static void xe_gt_fini(void *arg) struct xe_gt *gt = arg; int i; - gt_reset_worker_disable(gt); + gt_worker_disable(gt); for (i = 0; i < XE_ENGINE_CLASS_MAX; ++i) xe_hw_fence_irq_finish(>->fence_irq[i]); @@ -737,8 +707,6 @@ int xe_gt_init(struct xe_gt *gt) int err; int i; - INIT_WORK(>->reset.worker, gt_reset_worker); - for (i = 0; i < XE_ENGINE_CLASS_MAX; ++i) { gt->ring_ops[i] = xe_ring_ops_get(gt, i); xe_hw_fence_irq_init(>->fence_irq[i]); @@ -768,7 +736,7 @@ int xe_gt_init(struct xe_gt *gt) err = gt_init_with_all_forcewake(gt); if (err) { - gt_reset_worker_disable(gt); + gt_worker_disable(gt); return err; } @@ -784,6 +752,8 @@ int xe_gt_init(struct xe_gt *gt) return err; } + /* Must be last */ + WRITE_ONCE(gt->initialized, true); return 0; } @@ -942,7 +912,7 @@ static void gt_reset_worker(struct work_struct *w) unsigned int fw_ref; int err; - if (xe_device_wedged(gt_to_xe(gt))) + if (xe_wedged(gt_to_xe(gt))) goto err_pm_put; if (xe_device_is_in_reset(gt_to_xe(gt))) @@ -1001,7 +971,7 @@ err_out: err_fail: xe_log_err_fatal(gt, GT, err, "reset failed\n"); - xe_device_declare_wedged(gt_to_xe(gt)); + xe_wedge_declare(gt_to_xe(gt), DRM_WEDGE_RECOVERY_REBIND | DRM_WEDGE_RECOVERY_BUS_RESET); err_pm_put: xe_pm_runtime_put(gt_to_xe(gt)); } @@ -1204,17 +1174,30 @@ struct xe_hw_engine *xe_gt_any_hw_engine(struct xe_gt *gt) return NULL; } +static void gt_wedge_worker(struct work_struct *w) +{ + struct xe_gt *gt = container_of(w, typeof(*gt), wedge.worker); + + xe_uc_wedge_declare(>->uc); + xe_tlb_inval_reset(>->tlb_inval); + xe_pm_runtime_put(gt_to_xe(gt)); +} + /** - * xe_gt_declare_wedged() - Declare GT wedged + * xe_gt_wedge_declare() - Declare GT wedged * @gt: the GT object * * Wedge the GT which stops all submission, saves desired debug state, and * cleans up anything which could timeout. */ -void xe_gt_declare_wedged(struct xe_gt *gt) +void xe_gt_wedge_declare(struct xe_gt *gt) { - xe_gt_assert(gt, gt_to_xe(gt)->wedged.mode); + struct xe_device *xe = gt_to_xe(gt); - xe_uc_declare_wedged(>->uc); - xe_tlb_inval_reset(>->tlb_inval); + xe_gt_assert(gt, xe->wedged.mode); + xe_uc_reset_prepare(>->uc); + + xe_pm_runtime_get_noresume(xe); + if (!queue_work(gt->ordered_wq, >->wedge.worker)) + xe_pm_runtime_put(xe); } diff --git a/drivers/gpu/drm/xe/xe_gt.h b/drivers/gpu/drm/xe/xe_gt.h index 92d934d50244..7b6952fe804c 100644 --- a/drivers/gpu/drm/xe/xe_gt.h +++ b/drivers/gpu/drm/xe/xe_gt.h @@ -40,7 +40,7 @@ struct xe_gt *xe_gt_alloc(struct xe_tile *tile); int xe_gt_init_early(struct xe_gt *gt); int xe_gt_init(struct xe_gt *gt); void xe_gt_mmio_init(struct xe_gt *gt); -void xe_gt_declare_wedged(struct xe_gt *gt); +void xe_gt_wedge_declare(struct xe_gt *gt); int xe_gt_record_default_lrcs(struct xe_gt *gt); /** diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_vf.c b/drivers/gpu/drm/xe/xe_gt_sriov_vf.c index 37899fcf5b22..2a5f2064ad3e 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_vf.c +++ b/drivers/gpu/drm/xe/xe_gt_sriov_vf.c @@ -37,6 +37,7 @@ #include "xe_tile_sriov_vf.h" #include "xe_tlb_inval.h" #include "xe_uc_fw.h" +#include "xe_wedge.h" #include "xe_wopcm.h" #define make_u64_from_u32(hi, lo) ((u64)((u64)(u32)(hi) << 32 | (u32)(lo))) @@ -1462,7 +1463,7 @@ static void vf_post_migration_recovery(struct xe_gt *gt) fail: vf_post_migration_abort(gt); xe_gt_sriov_err(gt, "migration recovery failed (%pe)\n", ERR_PTR(err)); - xe_device_declare_wedged(xe); + xe_wedge_declare(xe, DRM_WEDGE_RECOVERY_REBIND | DRM_WEDGE_RECOVERY_BUS_RESET); return; queue: diff --git a/drivers/gpu/drm/xe/xe_gt_types.h b/drivers/gpu/drm/xe/xe_gt_types.h index 628911346455..c00a7c171f80 100644 --- a/drivers/gpu/drm/xe/xe_gt_types.h +++ b/drivers/gpu/drm/xe/xe_gt_types.h @@ -233,6 +233,12 @@ struct xe_gt { struct work_struct worker; } reset; + /** @wedge: state for GT wedge */ + struct { + /** @wedge.worker: worker for GT wedge to be done async */ + struct work_struct worker; + } wedge; + /** @tlb_inval: TLB invalidation state */ struct xe_tlb_inval tlb_inval; @@ -419,6 +425,9 @@ struct xe_gt { /** @eu_stall: EU stall counters subsystem per gt info */ struct xe_eu_stall_gt *eu_stall; + + /** @initialized: GT is initialized */ + bool initialized; }; #endif diff --git a/drivers/gpu/drm/xe/xe_guc.c b/drivers/gpu/drm/xe/xe_guc.c index c64cff067e97..ab891e818876 100644 --- a/drivers/gpu/drm/xe/xe_guc.c +++ b/drivers/gpu/drm/xe/xe_guc.c @@ -1832,17 +1832,16 @@ int xe_guc_print_info(struct xe_guc *guc, struct drm_printer *p) } /** - * xe_guc_declare_wedged() - Declare GuC wedged + * xe_guc_wedge_declare() - Declare GuC wedged * @guc: the GuC object * * Wedge the GuC which stops all submission, saves desired debug state, and * cleans up anything which could timeout. */ -void xe_guc_declare_wedged(struct xe_guc *guc) +void xe_guc_wedge_declare(struct xe_guc *guc) { xe_gt_assert(guc_to_gt(guc), guc_to_xe(guc)->wedged.mode); - xe_guc_reset_prepare(guc); xe_guc_ct_stop(&guc->ct); xe_guc_submit_wedge(guc); } diff --git a/drivers/gpu/drm/xe/xe_guc.h b/drivers/gpu/drm/xe/xe_guc.h index c4eca40d69cf..75c4b9acb065 100644 --- a/drivers/gpu/drm/xe/xe_guc.h +++ b/drivers/gpu/drm/xe/xe_guc.h @@ -62,7 +62,7 @@ void xe_guc_reset_wait(struct xe_guc *guc); void xe_guc_stop_prepare(struct xe_guc *guc); void xe_guc_stop(struct xe_guc *guc); int xe_guc_start(struct xe_guc *guc); -void xe_guc_declare_wedged(struct xe_guc *guc); +void xe_guc_wedge_declare(struct xe_guc *guc); bool xe_guc_using_main_gamctrl_queues(struct xe_guc *guc); bool xe_guc_has_paging_engine(struct xe_guc *guc); diff --git a/drivers/gpu/drm/xe/xe_guc_ct.c b/drivers/gpu/drm/xe/xe_guc_ct.c index 86246f925203..0a1b37fa0efb 100644 --- a/drivers/gpu/drm/xe/xe_guc_ct.c +++ b/drivers/gpu/drm/xe/xe_guc_ct.c @@ -37,6 +37,7 @@ #include "xe_sleep.h" #include "xe_sriov_vf.h" #include "xe_trace_guc.h" +#include "xe_wedge.h" /** * DOC: GuC CT Error Codes @@ -1161,7 +1162,7 @@ static int __guc_ct_send_locked(struct xe_guc_ct *ct, const u32 *action, xe_gt_assert(gt, g2h_len || !num_g2h); lockdep_assert_held(&ct->lock); - if (xe_device_wedged(ct_to_xe(ct))) { + if (xe_wedged(ct_to_xe(ct))) { ret = -ENOTRECOVERABLE; goto out; } @@ -1590,7 +1591,7 @@ wait_again: if (g2h_fence.fail) { if (g2h_fence.cancel) { xe_gt_dbg(gt, "H2G request %#x canceled!\n", action[0]); - ret = xe_device_wedged(ct_to_xe(ct)) ? -ENOTRECOVERABLE : -ECANCELED; + ret = xe_wedged(ct_to_xe(ct)) ? -ENOTRECOVERABLE : -ECANCELED; goto unlock; } xe_gt_err(gt, "H2G request %#x failed: error %#x hint %#x\n", @@ -1935,7 +1936,7 @@ static int g2h_read(struct xe_guc_ct *ct, u32 *msg, bool fast_path) lockdep_assert_held(&ct->fast_lock); /* Keep in sync with g2h_err_is_fatal() */ - if (xe_device_wedged(xe)) + if (xe_wedged(xe)) return -ENOTRECOVERABLE; if (ct->state == XE_GUC_CT_STATE_DISABLED) diff --git a/drivers/gpu/drm/xe/xe_guc_pc.c b/drivers/gpu/drm/xe/xe_guc_pc.c index e0105222a2c7..9558d7196a51 100644 --- a/drivers/gpu/drm/xe/xe_guc_pc.c +++ b/drivers/gpu/drm/xe/xe_guc_pc.c @@ -36,6 +36,7 @@ #include "xe_pm.h" #include "xe_sriov.h" #include "xe_wa.h" +#include "xe_wedge.h" #define MCHBAR_MIRROR_BASE_SNB 0x140000 @@ -188,7 +189,7 @@ static int pc_action_reset(struct xe_guc_pc *pc) int ret; ret = xe_guc_ct_send(ct, action, ARRAY_SIZE(action), 0, 0); - if (ret && !(xe_device_wedged(pc_to_xe(pc)) && ret == -ECANCELED)) + if (ret && !(xe_wedged(pc_to_xe(pc)) && ret == -ECANCELED)) xe_gt_err(pc_to_gt(pc), "GuC PC reset failed: %pe\n", ERR_PTR(ret)); @@ -212,7 +213,7 @@ static int pc_action_query_task_state(struct xe_guc_pc *pc) /* Blocking here to ensure the results are ready before reading them */ ret = xe_guc_ct_send_block(ct, action, ARRAY_SIZE(action)); - if (ret && !(xe_device_wedged(pc_to_xe(pc)) && ret == -ECANCELED)) + if (ret && !(xe_wedged(pc_to_xe(pc)) && ret == -ECANCELED)) xe_gt_err(pc_to_gt(pc), "GuC PC query task state failed: %pe\n", ERR_PTR(ret)); @@ -235,7 +236,7 @@ static int pc_action_set_param(struct xe_guc_pc *pc, u8 id, u32 value) return -EAGAIN; ret = xe_guc_ct_send(ct, action, ARRAY_SIZE(action), 0, 0); - if (ret && !(xe_device_wedged(pc_to_xe(pc)) && ret == -ECANCELED)) + if (ret && !(xe_wedged(pc_to_xe(pc)) && ret == -ECANCELED)) xe_gt_err(pc_to_gt(pc), "GuC PC set param[%u]=%u failed: %pe\n", id, value, ERR_PTR(ret)); @@ -257,7 +258,7 @@ static int pc_action_unset_param(struct xe_guc_pc *pc, u8 id) return -EAGAIN; ret = xe_guc_ct_send(ct, action, ARRAY_SIZE(action), 0, 0); - if (ret && !(xe_device_wedged(pc_to_xe(pc)) && ret == -ECANCELED)) + if (ret && !(xe_wedged(pc_to_xe(pc)) && ret == -ECANCELED)) xe_gt_err(pc_to_gt(pc), "GuC PC unset param failed: %pe", ERR_PTR(ret)); @@ -1357,7 +1358,7 @@ static void xe_guc_pc_fini_hw(void *arg) struct xe_guc_pc *pc = arg; struct xe_device *xe = pc_to_xe(pc); - if (xe_device_wedged(xe)) + if (xe_wedged(xe)) return; xe_guc_pc_stop(pc); diff --git a/drivers/gpu/drm/xe/xe_guc_rc.c b/drivers/gpu/drm/xe/xe_guc_rc.c index 99fa127b261f..fa3062ab134a 100644 --- a/drivers/gpu/drm/xe/xe_guc_rc.c +++ b/drivers/gpu/drm/xe/xe_guc_rc.c @@ -16,6 +16,7 @@ #include "xe_guc_pc.h" #include "xe_guc_rc.h" #include "xe_pm.h" +#include "xe_wedge.h" /** * DOC: GuC RC (Render C-states) @@ -40,7 +41,7 @@ static int guc_action_setup_gucrc(struct xe_guc *guc, u32 control) int ret; ret = xe_guc_ct_send(&guc->ct, action, ARRAY_SIZE(action), 0, 0); - if (ret && !(xe_device_wedged(guc_to_xe(guc)) && ret == -ECANCELED)) + if (ret && !(xe_wedged(guc_to_xe(guc)) && ret == -ECANCELED)) xe_gt_err(guc_to_gt(guc), "GuC RC setup %s(%u) failed (%pe)\n", control == GUCRC_HOST_CONTROL ? "HOST_CONTROL" : @@ -73,7 +74,7 @@ static void xe_guc_rc_fini_hw(void *arg) struct xe_device *xe = guc_to_xe(guc); struct xe_gt *gt = guc_to_gt(guc); - if (xe_device_wedged(xe)) + if (xe_wedged(xe)) return; CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index bc39cea08ecc..9e7c2778029c 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.c +++ b/drivers/gpu/drm/xe/xe_guc_submit.c @@ -50,6 +50,7 @@ #include "xe_trace.h" #include "xe_uc_fw.h" #include "xe_vm.h" +#include "xe_wedge.h" #define XE_GUC_EXEC_QUEUE_CGP_CONTEXT_ERROR_LEN 6 @@ -1455,10 +1456,10 @@ static bool guc_submit_hint_wedged(struct xe_guc *guc) if (xe->wedged.mode != XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) return false; - if (xe_device_wedged(xe)) + if (xe_wedged(xe)) return true; - xe_device_declare_wedged(xe); + xe_wedge_declare(xe, DRM_WEDGE_RECOVERY_REBIND | DRM_WEDGE_RECOVERY_BUS_RESET); return true; } @@ -1671,7 +1672,7 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) if (!exec_queue_killed(q)) wedged = guc_submit_hint_wedged(exec_queue_to_guc(q)); else - wedged = xe_device_wedged(xe); + wedged = xe_wedged(xe); /* * Only tag as GPU hang if this is the original timeout, not a @@ -1791,7 +1792,8 @@ trigger_reset: } if (wedge_device) - xe_device_declare_wedged(gt_to_xe(q->gt)); + xe_wedge_declare(gt_to_xe(q->gt), + DRM_WEDGE_RECOVERY_REBIND | DRM_WEDGE_RECOVERY_BUS_RESET); /* * We want the job added back to the pending list so it gets freed; this @@ -2556,7 +2558,7 @@ retry: WAIT_COND, HZ * 5); } - if (!blocking && vf_recovery(guc) && !xe_device_wedged(xe)) + if (!blocking && vf_recovery(guc) && !xe_wedged(xe)) return -EAGAIN; if (!ret) @@ -2816,7 +2818,7 @@ int xe_guc_submit_reset_prepare(struct xe_guc *guc) void xe_guc_submit_reset_wait(struct xe_guc *guc) { - wait_event(guc->ct.wq, xe_device_wedged(guc_to_xe(guc)) || + wait_event(guc->ct.wq, xe_wedged(guc_to_xe(guc)) || !xe_guc_read_stopped(guc)); } @@ -3368,8 +3370,17 @@ static void handle_sched_done(struct xe_guc *guc, struct xe_exec_queue *q, xe_gt_assert(guc_to_gt(guc), runnable_state == 0); xe_gt_assert(guc_to_gt(guc), exec_queue_pending_disable(q)); + /* + * A TDR stops the scheduler, which can trap a queued SUSPEND + * message, and then issues a disable of its own. suspend_pending + * is still set in that case, so only attribute this SCHED_DONE + * to a suspend if the SUSPEND message actually ran, i.e. it + * marked the queue suspended before disabling scheduling. The + * trapped message completes the suspend once submission + * restarts. + */ xe_sched_msg_lock(&q->guc->sched); - was_pending = q->guc->suspend_pending; + was_pending = q->guc->suspend_pending && exec_queue_suspended(q); if (was_pending) { clear_exec_queue_pending_disable(q); suspend_fence_signal(q); @@ -3377,26 +3388,27 @@ static void handle_sched_done(struct xe_guc *guc, struct xe_exec_queue *q, xe_sched_msg_unlock(&q->guc->sched); if (!was_pending) { - if (exec_queue_banned(q)) { - smp_wmb(); - wake_up_all(&guc->ct.wq); - } - if (exec_queue_destroyed(q)) { - /* - * Make sure to clear the pending_disable only - * after sampling the destroyed state. We want - * to ensure we don't trigger the unregister too - * early with something intending to only - * disable scheduling. The caller doing the - * destroy must wait for an ongoing - * pending_disable before marking as destroyed. - */ - clear_exec_queue_pending_disable(q); + /* + * Make sure to clear the pending_disable only after + * sampling the destroyed state. We want to ensure we + * don't trigger the unregister too early with something + * intending to only disable scheduling. The caller + * doing the destroy must wait for an ongoing + * pending_disable before marking as destroyed. + */ + bool destroyed = exec_queue_destroyed(q); + + clear_exec_queue_pending_disable(q); + if (destroyed) deregister_exec_queue(guc, q); - } else { - clear_exec_queue_pending_disable(q); - } } + + /* + * Wake after pending_disable is cleared, not before, so waiters + * such as the TDR see the updated state on the first re-check. + */ + smp_wmb(); + wake_up_all(&guc->ct.wq); } } diff --git a/drivers/gpu/drm/xe/xe_guc_tlb_inval.c b/drivers/gpu/drm/xe/xe_guc_tlb_inval.c index 111fef781b2a..dd38d95c6014 100644 --- a/drivers/gpu/drm/xe/xe_guc_tlb_inval.c +++ b/drivers/gpu/drm/xe/xe_guc_tlb_inval.c @@ -19,6 +19,7 @@ #include "xe_sa.h" #include "xe_tlb_inval.h" #include "xe_vm.h" +#include "xe_wedge.h" #include "regs/xe_guc_regs.h" @@ -77,7 +78,7 @@ static int send_tlb_inval_ggtt(struct xe_tlb_inval *tlb_inval, u32 seqno) }; return send_tlb_inval(guc, action, ARRAY_SIZE(action)); - } else if (xe_device_uc_enabled(xe) && !xe_device_wedged(xe)) { + } else if (xe_device_uc_enabled(xe) && !xe_wedged(xe)) { struct xe_mmio *mmio = >->mmio; if (IS_SRIOV_VF(xe)) diff --git a/drivers/gpu/drm/xe/xe_hw_error.c b/drivers/gpu/drm/xe/xe_hw_error.c index f53a6b3055de..ac720710c8e8 100644 --- a/drivers/gpu/drm/xe/xe_hw_error.c +++ b/drivers/gpu/drm/xe/xe_hw_error.c @@ -14,6 +14,7 @@ #include "xe_drm_ras.h" #include "xe_hw_error.h" #include "xe_mmio.h" +#include "xe_pm.h" #include "xe_survivability_mode.h" #define GT_HW_ERROR_MAX_ERR_BITS 16 @@ -170,6 +171,7 @@ static void csc_hw_error_work(struct work_struct *work) struct xe_tile *tile = container_of(work, typeof(*tile), csc_hw_error_work); struct xe_device *xe = tile_to_xe(tile); + guard(xe_pm_runtime)(xe); xe_survivability_mode_runtime_enable(xe); } diff --git a/drivers/gpu/drm/xe/xe_lrc.c b/drivers/gpu/drm/xe/xe_lrc.c index fe2909b7b84d..040a52f9320e 100644 --- a/drivers/gpu/drm/xe/xe_lrc.c +++ b/drivers/gpu/drm/xe/xe_lrc.c @@ -1469,15 +1469,15 @@ setup_indirect_ctx(struct xe_lrc *lrc, struct xe_hw_engine *hwe) finish_bo(&state); kfree(state.buffer); - /* - * Enable INDIRECT_CTX leaving INDIRECT_CTX_OFFSET at its default: it - * varies per engine class, but the default is good enough - */ xe_lrc_write_ctx_reg(lrc, CTX_CS_INDIRECT_CTX, (xe_bo_ggtt_addr(lrc->bo) + state.offset) | /* Size in CLs. */ (state.written * sizeof(u32) / 64)); + if (GRAPHICS_VER(lrc_to_xe(lrc)) < 20) + xe_lrc_write_ctx_reg(lrc, + CTX_CS_INDIRECT_CTX_OFFSET, + CTX_INDIRECT_CTX_OFFSET_DEFAULT); return 0; } diff --git a/drivers/gpu/drm/xe/xe_mert.c b/drivers/gpu/drm/xe/xe_mert.c index 32700c19a1df..a2eae6088c1a 100644 --- a/drivers/gpu/drm/xe/xe_mert.c +++ b/drivers/gpu/drm/xe/xe_mert.c @@ -11,6 +11,7 @@ #include "xe_mmio.h" #include "xe_sriov_printk.h" #include "xe_tile.h" +#include "xe_wedge.h" /** * xe_mert_init_early() - Initialize MERT data @@ -74,7 +75,7 @@ static void mert_handle_cat_error(struct xe_device *xe) break; case CATERR_UNMAPPED_GGTT: xe_sriov_err(xe, "MERT: CAT_ERR: Access to an unmapped GGTT!\n"); - xe_device_declare_wedged(xe); + xe_wedge_declare(xe, DRM_WEDGE_RECOVERY_REBIND | DRM_WEDGE_RECOVERY_BUS_RESET); break; case CATERR_LMTT_FAULT: xe_sriov_dbg_ratelimited(xe, "MERT: CAT_ERR: VF%u LMTT fault!\n", vfid); @@ -82,7 +83,7 @@ static void mert_handle_cat_error(struct xe_device *xe) break; default: xe_sriov_err(xe, "MERT: Unexpected CAT_ERR code=%#x!\n", code); - xe_device_declare_wedged(xe); + xe_wedge_declare(xe, DRM_WEDGE_RECOVERY_REBIND | DRM_WEDGE_RECOVERY_BUS_RESET); break; } } diff --git a/drivers/gpu/drm/xe/xe_migrate.c b/drivers/gpu/drm/xe/xe_migrate.c index fffb3eb6c76e..70408fa0a606 100644 --- a/drivers/gpu/drm/xe/xe_migrate.c +++ b/drivers/gpu/drm/xe/xe_migrate.c @@ -2187,17 +2187,18 @@ static bool xe_migrate_vram_use_pde(struct drm_pagemap_addr *sram_addr, #define XE_CACHELINE_BYTES 64ull #define XE_CACHELINE_MASK (XE_CACHELINE_BYTES - 1) -static u32 xe_migrate_copy_pitch(struct xe_device *xe, u32 len) +static u32 xe_migrate_copy_pitch(struct xe_device *xe, u32 len, u64 dst_addr) { + u64 align_check = len | dst_addr; u32 pitch; - if (IS_ALIGNED(len, PAGE_SIZE)) + if (IS_ALIGNED(align_check, PAGE_SIZE)) pitch = PAGE_SIZE; - else if (IS_ALIGNED(len, SZ_4K)) + else if (IS_ALIGNED(align_check, SZ_4K)) pitch = SZ_4K; - else if (IS_ALIGNED(len, SZ_256)) + else if (IS_ALIGNED(align_check, SZ_256)) pitch = SZ_256; - else if (IS_ALIGNED(len, 4)) + else if (IS_ALIGNED(align_check, 4)) pitch = 4; else pitch = 1; @@ -2206,6 +2207,86 @@ static u32 xe_migrate_copy_pitch(struct xe_device *xe, u32 len) return pitch; } +/** + * xe_migrate_dst_pitch() - Determine max pitch supported by dst alignment + * @dst_addr: Destination address (page offset) + * + * Returns the largest pitch (PAGE_SIZE, SZ_4K, SZ_256, or 4) that dst_addr + * supports based solely on its alignment. Returns 1 if not even 4-byte aligned. + */ +static u32 xe_migrate_dst_pitch(u64 dst_addr) +{ + if (IS_ALIGNED(dst_addr, PAGE_SIZE)) + return PAGE_SIZE; + if (IS_ALIGNED(dst_addr, SZ_4K)) + return SZ_4K; + if (IS_ALIGNED(dst_addr, SZ_256)) + return SZ_256; + if (IS_ALIGNED(dst_addr, 4)) + return 4; + return 1; +} + +/** + * xe_migrate_bytes_to_align() - Calculate bytes needed to reach target alignment + * @dst_addr: Current destination address + * @alignment: Target alignment (PAGE_SIZE, SZ_4K, SZ_256, or 4) + * + * Returns: Number of bytes to copy to reach the target alignment. + */ +static u32 xe_migrate_bytes_to_align(u64 dst_addr, u32 alignment) +{ + return round_up(dst_addr, alignment) - dst_addr; +} + +/** + * xe_migrate_best_alignment() - Find the best alignment reachable within max_bytes + * @dst_addr: Current destination address + * @max_bytes: Maximum bytes we can copy to reach alignment (typically U16_MAX) + * + * Returns the largest alignment (PAGE_SIZE, SZ_4K, SZ_256, or 4) that dst_addr + * can reach by copying at most max_bytes. Returns 0 if already at best alignment + * or if no useful alignment can be reached. + */ +static u32 xe_migrate_best_alignment(u64 dst_addr, u32 max_bytes) +{ + u32 bytes_to_page = xe_migrate_bytes_to_align(dst_addr, PAGE_SIZE); + u32 bytes_to_4k = xe_migrate_bytes_to_align(dst_addr, SZ_4K); + u32 bytes_to_256 = xe_migrate_bytes_to_align(dst_addr, SZ_256); + u32 bytes_to_4 = xe_migrate_bytes_to_align(dst_addr, 4); + + if (bytes_to_page == 0) + return 0; + + if (bytes_to_page <= max_bytes) + return PAGE_SIZE; + + if (bytes_to_4k > 0 && bytes_to_4k <= max_bytes) + return SZ_4K; + + if (bytes_to_256 > 0 && bytes_to_256 <= max_bytes) + return SZ_256; + + if (bytes_to_4 > 0 && bytes_to_4 <= max_bytes) + return 4; + + return 0; +} + +/** + * xe_migrate_aligned_copy_len() - Calculate the aligned copy length for matrix copy + * @len: Remaining bytes + * @pitch: The pitch to use for matrix copy + * + * Returns: Length rounded down to pitch, or 0 if less than pitch. + */ +static u32 xe_migrate_aligned_copy_len(u32 len, u32 pitch) +{ + if (len < pitch) + return 0; + return round_down(len, pitch); +} + static struct dma_fence *xe_migrate_vram(struct xe_migrate *m, unsigned long len, unsigned long sram_offset, @@ -2224,16 +2305,11 @@ static struct dma_fence *xe_migrate_vram(struct xe_migrate *m, struct xe_bb *bb; u32 update_idx, pt_slot = 0; unsigned long npages = DIV_ROUND_UP(len + sram_offset, PAGE_SIZE); - unsigned int pitch = xe_migrate_copy_pitch(xe, len); + unsigned int pitch; int err; unsigned long i, j; bool use_pde = xe_migrate_vram_use_pde(sram_addr, len + sram_offset); - if (!xe->info.has_mem_copy_instr && - drm_WARN_ON(&xe->drm, - (!IS_ALIGNED(len, pitch)) || (sram_offset | vram_addr) & XE_CACHELINE_MASK)) - return ERR_PTR(-EOPNOTSUPP); - xe_assert(xe, npages * PAGE_SIZE <= MAX_PREEMPTDISABLE_TRANSFER); batch_size += pte_update_cmd_size(npages << PAGE_SHIFT); @@ -2285,6 +2361,15 @@ static struct dma_fence *xe_migrate_vram(struct xe_migrate *m, dst_L0_ofs = xe_migrate_vm_addr(pt_slot, 0) + sram_offset; } + pitch = xe_migrate_copy_pitch(xe, len, dst_L0_ofs); + if (!xe->info.has_mem_copy_instr && + drm_WARN_ON(&xe->drm, + (!IS_ALIGNED(len, pitch)) || + (sram_offset | vram_addr) & XE_CACHELINE_MASK)) { + err = -EOPNOTSUPP; + goto err; + } + bb->cs[bb->len++] = MI_BATCH_BUFFER_END; update_idx = bb->len; @@ -2527,7 +2612,6 @@ int xe_migrate_access_memory(struct xe_migrate *m, struct xe_bo *bo, u64 vram_addr = vram_region_gpu_offset(bo->ttm.resource) + cursor.start; int current_bytes; - u32 pitch; if (cursor.size > MAX_PREEMPTDISABLE_TRANSFER) current_bytes = min_t(int, bytes_left, @@ -2535,13 +2619,62 @@ int xe_migrate_access_memory(struct xe_migrate *m, struct xe_bo *bo, else current_bytes = min_t(int, bytes_left, cursor.size); - pitch = xe_migrate_copy_pitch(xe, current_bytes); - if (xe->info.has_mem_copy_instr) - current_bytes = min_t(int, current_bytes, U16_MAX * pitch); - else - current_bytes = min_t(int, current_bytes, - round_down(S16_MAX * pitch, - XE_CACHELINE_BYTES)); + { + /* + * Optimized copy strategy to minimize number of jobs: + * 1. Linear copy to align dst to best reachable alignment + * 2. Matrix copy for bulk data copy + * 3. Single linear copy for remaining bytes + * + * The phase logic controls transfer chunking; emit_copy() selects + * MEM_COPY_CMD or XY_FAST_COPY_BLT based on hardware support. + */ + u64 dst_addr = write ? vram_addr : + (unsigned long)buf & ~PAGE_MASK; + u32 max_linear = xe->info.has_mem_copy_instr ? U16_MAX : + round_down(S16_MAX, XE_CACHELINE_BYTES); + u32 best_align = xe_migrate_best_alignment(dst_addr, max_linear); + u32 bytes_to_align = best_align ? + xe_migrate_bytes_to_align(dst_addr, best_align) : 0; + + if (bytes_to_align > 0 && bytes_to_align <= (u32)current_bytes) { + /* + * Phase 1: Linear copy to reach best alignment. + * Copy just enough bytes to align dst_addr. + */ + current_bytes = min_t(int, bytes_to_align, max_linear); + } else if (IS_ALIGNED(dst_addr, 4)) { + /* + * Phase 2: Matrix copy for aligned bulk data. + * Use the best pitch that dst alignment supports, + * then round down len to that pitch. + */ + u32 dst_pitch = xe_migrate_dst_pitch(dst_addr); + u32 aligned_len = xe_migrate_aligned_copy_len(current_bytes, + dst_pitch); + + if (aligned_len >= dst_pitch) { + u32 max_bytes = xe->info.has_mem_copy_instr ? + U16_MAX * dst_pitch : + round_down(S16_MAX * dst_pitch, + XE_CACHELINE_BYTES); + + current_bytes = min_t(int, aligned_len, max_bytes); + } else { + /* + * Phase 3: Linear copy for remainder. + * Not enough for matrix copy - do single linear copy. + */ + current_bytes = min_t(int, current_bytes, max_linear); + } + } else { + /* + * Phase 3: Linear copy for remainder. + * dst not 4-aligned and can't reach alignment - linear copy. + */ + current_bytes = min_t(int, current_bytes, max_linear); + } + } __fence = xe_migrate_vram(m, current_bytes, (unsigned long)buf & ~PAGE_MASK, @@ -2563,7 +2696,7 @@ int xe_migrate_access_memory(struct xe_migrate *m, struct xe_bo *bo, buf += current_bytes; offset += current_bytes; - current_page = (int)(buf - orig_buf) / PAGE_SIZE; + current_page = (int)(buf - orig_buf + page_offset) / PAGE_SIZE; bytes_left -= current_bytes; if (bytes_left) xe_res_next(&cursor, current_bytes); diff --git a/drivers/gpu/drm/xe/xe_oa.c b/drivers/gpu/drm/xe/xe_oa.c index c9320feeafba..838802482ada 100644 --- a/drivers/gpu/drm/xe/xe_oa.c +++ b/drivers/gpu/drm/xe/xe_oa.c @@ -1751,6 +1751,19 @@ static const struct file_operations xe_oa_fops = { .mmap = xe_oa_mmap, }; +static bool oag_has_tail_address_wrap(struct xe_oa_stream *stream) +{ + return GRAPHICS_VER(stream->oa->xe) >= 20 && + stream->oa_unit->type == DRM_XE_OA_UNIT_TYPE_OAG; +} + +static bool oam_has_tail_address_wrap(struct xe_oa_stream *stream) +{ + return MEDIA_VER(stream->oa->xe) >= 30 && + (stream->oa_unit->type == DRM_XE_OA_UNIT_TYPE_OAM || + stream->oa_unit->type == DRM_XE_OA_UNIT_TYPE_OAM_SAG); +} + static int xe_oa_stream_init(struct xe_oa_stream *stream, struct xe_oa_open_param *param) { @@ -1775,12 +1788,13 @@ static int xe_oa_stream_init(struct xe_oa_stream *stream, stream->syncs = param->syncs; /* - * For Xe2+, when overrun mode is enabled, there are no partial reports at the end - * of buffer, making the OA buffer effectively a non-power-of-2 size circular - * buffer whose size, circ_size, is a multiple of the report size + * For Xe2+ OAG and Xe3+ OAM, when overrun mode is enabled, there are no + * partial reports at the end of buffer, making the OA buffer effectively a + * non-power-of-2 size circular buffer whose size, circ_size, is + * a multiple of the report size. */ - if (GRAPHICS_VER(stream->oa->xe) >= 20 && - stream->oa_unit->type == DRM_XE_OA_UNIT_TYPE_OAG && stream->sample) + if (stream->sample && + (oag_has_tail_address_wrap(stream) || oam_has_tail_address_wrap(stream))) stream->oa_buffer.circ_size = param->oa_buffer_size - param->oa_buffer_size % stream->oa_buffer.format->size; diff --git a/drivers/gpu/drm/xe/xe_pat.c b/drivers/gpu/drm/xe/xe_pat.c index 3dfcd364ac67..5938fef22579 100644 --- a/drivers/gpu/drm/xe/xe_pat.c +++ b/drivers/gpu/drm/xe/xe_pat.c @@ -94,29 +94,29 @@ struct xe_pat_ops { }; static const struct xe_pat_table_entry xelp_pat_table[] = { - [0] = { XELP_PAT_WB, XE_COH_1WAY }, - [1] = { XELP_PAT_WC, XE_COH_NONE }, - [2] = { XELP_PAT_WT, XE_COH_NONE }, - [3] = { XELP_PAT_UC, XE_COH_NONE }, + [0] = { XELP_PAT_WB, XE_COH_1WAY, 1 }, + [1] = { XELP_PAT_WC, XE_COH_NONE, 1 }, + [2] = { XELP_PAT_WT, XE_COH_NONE, 1 }, + [3] = { XELP_PAT_UC, XE_COH_NONE, 1 }, }; static const struct xe_pat_table_entry xehpc_pat_table[] = { - [0] = { XELP_PAT_UC, XE_COH_NONE }, - [1] = { XELP_PAT_WC, XE_COH_NONE }, - [2] = { XELP_PAT_WT, XE_COH_NONE }, - [3] = { XELP_PAT_WB, XE_COH_1WAY }, - [4] = { XEHPC_PAT_CLOS(1) | XELP_PAT_WT, XE_COH_NONE }, - [5] = { XEHPC_PAT_CLOS(1) | XELP_PAT_WB, XE_COH_1WAY }, - [6] = { XEHPC_PAT_CLOS(2) | XELP_PAT_WT, XE_COH_NONE }, - [7] = { XEHPC_PAT_CLOS(2) | XELP_PAT_WB, XE_COH_1WAY }, + [0] = { XELP_PAT_UC, XE_COH_NONE, 1 }, + [1] = { XELP_PAT_WC, XE_COH_NONE, 1 }, + [2] = { XELP_PAT_WT, XE_COH_NONE, 1 }, + [3] = { XELP_PAT_WB, XE_COH_1WAY, 1 }, + [4] = { XEHPC_PAT_CLOS(1) | XELP_PAT_WT, XE_COH_NONE, 1 }, + [5] = { XEHPC_PAT_CLOS(1) | XELP_PAT_WB, XE_COH_1WAY, 1 }, + [6] = { XEHPC_PAT_CLOS(2) | XELP_PAT_WT, XE_COH_NONE, 1 }, + [7] = { XEHPC_PAT_CLOS(2) | XELP_PAT_WB, XE_COH_1WAY, 1 }, }; static const struct xe_pat_table_entry xelpg_pat_table[] = { - [0] = { XELPG_PAT_0_WB, XE_COH_NONE }, - [1] = { XELPG_PAT_1_WT, XE_COH_NONE }, - [2] = { XELPG_PAT_3_UC, XE_COH_NONE }, - [3] = { XELPG_PAT_0_WB | XELPG_2_COH_1W, XE_COH_1WAY }, - [4] = { XELPG_PAT_0_WB | XELPG_3_COH_2W, XE_COH_2WAY }, + [0] = { XELPG_PAT_0_WB, XE_COH_NONE, 1 }, + [1] = { XELPG_PAT_1_WT, XE_COH_NONE, 1 }, + [2] = { XELPG_PAT_3_UC, XE_COH_NONE, 1 }, + [3] = { XELPG_PAT_0_WB | XELPG_2_COH_1W, XE_COH_1WAY, 1 }, + [4] = { XELPG_PAT_0_WB | XELPG_3_COH_2W, XE_COH_2WAY, 1 }, }; /* @@ -295,25 +295,69 @@ static const struct xe_pat_table_entry xe3p_lpg_pat_table[] = { [31] = XE2_PAT( 0, 0, 3, 0, 3, 3 ), }; +bool xe_pat_index_is_valid(struct xe_device *xe, u16 pat_index) +{ + if (WARN_ON(pat_index >= xe->pat.n_entries)) + return false; + + return xe->pat.table[pat_index].valid; +} + u16 xe_pat_index_get_coh_mode(struct xe_device *xe, u16 pat_index) { - WARN_ON(pat_index >= xe->pat.n_entries); + WARN_ON(!xe_pat_index_is_valid(xe, pat_index)); + WARN_ON(!xe->pat.table[pat_index].coh_mode || + xe->pat.table[pat_index].coh_mode > XE_COH_2WAY); return xe->pat.table[pat_index].coh_mode; } bool xe_pat_index_get_comp_en(struct xe_device *xe, u16 pat_index) { - WARN_ON(pat_index >= xe->pat.n_entries); + WARN_ON(!xe_pat_index_is_valid(xe, pat_index)); return !!(xe->pat.table[pat_index].value & XE2_COMP_EN); } u16 xe_pat_index_get_l3_policy(struct xe_device *xe, u16 pat_index) { - WARN_ON(pat_index >= xe->pat.n_entries); + WARN_ON(!xe_pat_index_is_valid(xe, pat_index)); return REG_FIELD_GET(XE2_L3_POLICY, xe->pat.table[pat_index].value); } +bool xe_pat_wa_14026539277_reserved(struct xe_device *xe, u16 pat_index) +{ + struct xe_gt *gt; + u8 id; + bool has_wa = false; + + for_each_gt(gt, xe, id) { + if (XE_GT_WA(gt, 14026539277)) { + has_wa = true; + break; + } + } + + /* + * Disallow 2-way coherency for any L3 cache policy because + * XE_L3_POLICY_UC could still be promoted to a cached policy + * by MOCS indices. + */ + return has_wa && xe_pat_index_get_coh_mode(xe, pat_index) == XE_COH_2WAY; +} + +static u32 wa_14026539277_fixup_pat_value(struct xe_gt *gt, u32 value) +{ + if (XE_GT_WA(gt, 14026539277)) { + if (REG_FIELD_GET(XE2_COH_MODE, value) == XE_COH_2WAY) { + value &= ~(XE2_L3_POLICY | XE2_COH_MODE); + value |= REG_FIELD_PREP(XE2_L3_POLICY, XE_L3_POLICY_UC) | + REG_FIELD_PREP(XE2_COH_MODE, XE_COH_1WAY); + } + } + + return value; +} + static const struct xe_pat_table_entry *gt_pta_entry(struct xe_gt *gt) { struct xe_device *xe = gt_to_xe(gt); @@ -374,18 +418,22 @@ static void program_pat_mcr(struct xe_gt *gt, const struct xe_pat_table_entry ta for (int i = 0; i < n_entries; i++) { struct xe_reg_mcr reg_mcr = XE_REG_MCR(_PAT_INDEX(i)); + u32 pat = wa_14026539277_fixup_pat_value(gt, table[i].value); - xe_gt_mcr_multicast_write(gt, reg_mcr, table[i].value); + xe_gt_mcr_multicast_write(gt, reg_mcr, pat); } if (xe->pat.pat_ats) - xe_gt_mcr_multicast_write(gt, XE_REG_MCR(_PAT_ATS), xe->pat.pat_ats->value); + xe_gt_mcr_multicast_write(gt, XE_REG_MCR(_PAT_ATS), + wa_14026539277_fixup_pat_value(gt, xe->pat.pat_ats->value)); if (pta_entry) - xe_gt_mcr_multicast_write(gt, XE_REG_MCR(_PAT_PTA), pta_entry->value); + xe_gt_mcr_multicast_write(gt, XE_REG_MCR(_PAT_PTA), + wa_14026539277_fixup_pat_value(gt, pta_entry->value)); if (tr_pta_entry) - xe_gt_mcr_multicast_write(gt, XE_REG_MCR(_PAT_TR_PTA), tr_pta_entry->value); + xe_gt_mcr_multicast_write(gt, XE_REG_MCR(_PAT_TR_PTA), + wa_14026539277_fixup_pat_value(gt, tr_pta_entry->value)); } static int xelp_dump(struct xe_gt *gt, struct drm_printer *p) @@ -535,13 +583,16 @@ static int xe2_dump(struct xe_gt *gt, struct drm_printer *p) drm_printf(p, "PAT table: (* = reserved entry)\n"); for (i = 0; i < xe->pat.n_entries; i++) { + bool rsvd = !xe->pat.table[i].valid || + xe_pat_wa_14026539277_reserved(xe, i); + if (xe_gt_is_media_type(gt)) pat = xe_mmio_read32(>->mmio, XE_REG(_PAT_INDEX(i))); else pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_INDEX(i))); xe_pat_index_label(label, sizeof(label), i); - xe->pat.ops->entry_dump(p, label, pat, !xe->pat.table[i].valid); + xe->pat.ops->entry_dump(p, label, pat, rsvd); } /* @@ -758,9 +809,14 @@ int xe_pat_dump_sw_config(struct xe_gt *gt, struct drm_printer *p) for (u32 i = 0; i < xe->pat.n_entries; i++) { u32 pat = xe->pat.table[i].value; + pat = wa_14026539277_fixup_pat_value(gt, pat); + if (GRAPHICS_VER(xe) >= 20) { + bool rsvd = !xe->pat.table[i].valid || + xe_pat_wa_14026539277_reserved(xe, i); + xe_pat_index_label(label, sizeof(label), i); - xe->pat.ops->entry_dump(p, label, pat, !xe->pat.table[i].valid); + xe->pat.ops->entry_dump(p, label, pat, rsvd); } else if (xe->info.platform == XE_METEORLAKE) { xelpg_pat_entry_dump(p, i, pat); } else if (xe->info.platform == XE_PVC) { @@ -775,6 +831,8 @@ int xe_pat_dump_sw_config(struct xe_gt *gt, struct drm_printer *p) if (pta_entry) { u32 pat = pta_entry->value; + pat = wa_14026539277_fixup_pat_value(gt, pat); + drm_printf(p, "Page Table Access:\n"); xe->pat.ops->entry_dump(p, "PTA_MODE", pat, false); } @@ -782,6 +840,8 @@ int xe_pat_dump_sw_config(struct xe_gt *gt, struct drm_printer *p) if (tr_pta_entry) { u32 pat = tr_pta_entry->value; + pat = wa_14026539277_fixup_pat_value(gt, pat); + drm_printf(p, "TRTT Page Table Access:\n"); xe->pat.ops->entry_dump(p, "TR_PTA_MODE", pat, false); } @@ -789,6 +849,8 @@ int xe_pat_dump_sw_config(struct xe_gt *gt, struct drm_printer *p) if (xe->pat.pat_ats) { u32 pat = xe->pat.pat_ats->value; + pat = wa_14026539277_fixup_pat_value(gt, pat); + drm_printf(p, "PCIe ATS/PASID:\n"); xe->pat.ops->entry_dump(p, "PAT_ATS ", pat, false); } diff --git a/drivers/gpu/drm/xe/xe_pat.h b/drivers/gpu/drm/xe/xe_pat.h index 6398c3ab4805..2ac6ddc66587 100644 --- a/drivers/gpu/drm/xe/xe_pat.h +++ b/drivers/gpu/drm/xe/xe_pat.h @@ -57,8 +57,18 @@ int xe_pat_dump(struct xe_gt *gt, struct drm_printer *p); int xe_pat_dump_sw_config(struct xe_gt *gt, struct drm_printer *p); /** + * xe_pat_index_is_valid - Check whether the given pat_index is valid. Index + * must be within valid range. + * @xe: xe device + * @pat_index: The pat_index to query + * + * Return: true if the pat_index entry is valid, false if reserved. + */ +bool xe_pat_index_is_valid(struct xe_device *xe, u16 pat_index); + +/** * xe_pat_index_get_coh_mode - Extract the coherency mode for the given - * pat_index. + * pat_index. Index must be valid for the hw. * @xe: xe device * @pat_index: The pat_index to query */ @@ -66,7 +76,7 @@ u16 xe_pat_index_get_coh_mode(struct xe_device *xe, u16 pat_index); /** * xe_pat_index_get_comp_en - Extract the compression enable flag for - * the given pat_index. + * the given pat_index. Index must be valid for the hw. * @xe: xe device * @pat_index: The pat_index to query * @@ -79,11 +89,22 @@ bool xe_pat_index_get_comp_en(struct xe_device *xe, u16 pat_index); #define XE_L3_POLICY_UC 3 /* Uncached */ /** * xe_pat_index_get_l3_policy - Extract the L3 policy for the given pat_index. + * Index must be valid for the hw. * @xe: xe device * @pat_index: The pat_index to query */ u16 xe_pat_index_get_l3_policy(struct xe_device *xe, u16 pat_index); +/** + * xe_pat_wa_14026539277_reserved - Is this PAT index reserved from + * use due to Wa_14026539277? + * @xe: xe device + * @pat_index: The pat_index to query + * + * Return: a boolean indicating whether the PAT index is reserved or not. + */ +bool xe_pat_wa_14026539277_reserved(struct xe_device *xe, u16 pat_index); + #define xe_cache_pat_idx(xe, cache_mode) ({ \ const struct xe_device *__xedev = (xe); \ enum xe_cache_level __mode = (cache_mode); \ diff --git a/drivers/gpu/drm/xe/xe_pci_error.c b/drivers/gpu/drm/xe/xe_pci_error.c index 79ce0c671549..9bf0da3a3d15 100644 --- a/drivers/gpu/drm/xe/xe_pci_error.c +++ b/drivers/gpu/drm/xe/xe_pci_error.c @@ -13,6 +13,7 @@ #include "xe_printk.h" #include "xe_ras.h" #include "xe_survivability_mode.h" +#include "xe_wedge.h" static void prepare_device_for_reset(struct pci_dev *pdev) { @@ -22,7 +23,7 @@ static void prepare_device_for_reset(struct pci_dev *pdev) /* * Wedge the device to prevent userspace access but do not send the uevent. - * xe_device_wedged_fini() releases runtime pm if wedged flag is set, so acquire a runtime + * xe_wedge_fini() releases runtime pm if wedged flag is set, so acquire a runtime * pm reference to avoid underflow. */ if (!atomic_xchg(&xe->wedged.flag, 1)) @@ -30,8 +31,10 @@ static void prepare_device_for_reset(struct pci_dev *pdev) xe_device_set_in_reset(xe); - for_each_gt(gt, xe, id) - xe_gt_declare_wedged(gt); + for_each_gt(gt, xe, id) { + xe_gt_wedge_declare(gt); + flush_work(>->wedge.worker); + } pci_disable_device(pdev); } @@ -61,7 +64,7 @@ static pci_ers_result_t xe_pci_error_detected(struct pci_dev *pdev, pci_channel_ return PCI_ERS_RESULT_DISCONNECT; /* If the device is already wedged or in survivability mode, do not attempt recovery */ - if (xe_survivability_mode_is_boot_enabled(xe) || xe_device_wedged(xe)) + if (xe_survivability_mode_is_boot_enabled(xe) || xe_wedged(xe)) return PCI_ERS_RESULT_DISCONNECT; switch (state) { @@ -86,7 +89,7 @@ static pci_ers_result_t xe_pci_error_mmio_enabled(struct pci_dev *pdev) /* User wants to debug the error, prevent reset */ if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) { - xe_device_declare_wedged(xe); + xe_wedge_declare(xe, DRM_WEDGE_RECOVERY_NONE); return PCI_ERS_RESULT_DISCONNECT; } diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c index 8a95d58d9c6f..c8ce37efd042 100644 --- a/drivers/gpu/drm/xe/xe_pt.c +++ b/drivers/gpu/drm/xe/xe_pt.c @@ -1625,7 +1625,6 @@ static int op_check_svm_userptr(struct xe_vm *vm, struct xe_vma_op *op) err = vma_check_userptr(vm, gpuva_to_vma(op->base.prefetch.va)); } break; -#if IS_ENABLED(CONFIG_DRM_XE_GPUSVM) case DRM_GPUVA_OP_DRIVER: if (op->subop == XE_VMA_SUBOP_MAP_RANGE) { struct xe_svm_range *range = op->map_range.range; @@ -1640,7 +1639,6 @@ static int op_check_svm_userptr(struct xe_vm *vm, struct xe_vma_op *op) } } break; -#endif default: drm_warn(&vm->xe->drm, "NOT POSSIBLE"); } diff --git a/drivers/gpu/drm/xe/xe_ras.c b/drivers/gpu/drm/xe/xe_ras.c index 9c15ce8f0b6a..db3cbc186a51 100644 --- a/drivers/gpu/drm/xe/xe_ras.c +++ b/drivers/gpu/drm/xe/xe_ras.c @@ -19,6 +19,7 @@ #include "xe_sysctrl_mailbox.h" #include "xe_sysctrl_mailbox_types.h" #include "xe_ttm_vram_mgr.h" +#include "xe_wedge.h" /* Any non-null entry marks the page as offlined by firmware */ #define XE_RAS_PAGE_OFFLINED xa_mk_value(1) @@ -563,8 +564,7 @@ static u8 handle_core_compute_errors(struct xe_ras_error_array *arr) static void punit_error_handler(struct xe_device *xe) { - xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_COLD_RESET); - xe_device_declare_wedged(xe); + xe_wedge_declare(xe, DRM_WEDGE_RECOVERY_COLD_RESET); } static u8 handle_soc_internal_errors(struct xe_device *xe, struct xe_ras_error_array *arr) @@ -1212,6 +1212,13 @@ int xe_ras_init(struct xe_device *xe) get_offline_list(xe); get_offline_queue(xe); + /* + * During probe, process and log any errors detected by firmware while the driver was not + * loaded. Critical errors such as Punit and CSC are reported through Pcode init failure, + * causing the driver to enter survivability mode. + */ + xe_ras_process_errors(xe); + ret = devm_device_add_group(xe->drm.dev, &gpu_health_group); if (ret) xe_err(xe, "Failed to create GPU health sysfs, err=%d\n", ret); diff --git a/drivers/gpu/drm/xe/xe_shrinker.c b/drivers/gpu/drm/xe/xe_shrinker.c index 772dab9b3ed7..c86455ea08d1 100644 --- a/drivers/gpu/drm/xe/xe_shrinker.c +++ b/drivers/gpu/drm/xe/xe_shrinker.c @@ -133,6 +133,9 @@ static int __xe_shrinker_walk(struct xe_shrinker *shrinker, } ttm_bo_lru_for_each_reserved_guarded(&curs, man, &arg, ttm_bo) { + if (flags.purge && ttm_bo->priority > XE_BO_PRIORITY_LOW) + break; + if (!ttm_bo_shrink_suitable(ttm_bo, ctx)) continue; diff --git a/drivers/gpu/drm/xe/xe_sriov_pf.c b/drivers/gpu/drm/xe/xe_sriov_pf.c index 33bd754d138f..ce0db26203ec 100644 --- a/drivers/gpu/drm/xe/xe_sriov_pf.c +++ b/drivers/gpu/drm/xe/xe_sriov_pf.c @@ -19,6 +19,7 @@ #include "xe_sriov_pf_service.h" #include "xe_sriov_pf_sysfs.h" #include "xe_sriov_printk.h" +#include "xe_wedge.h" static unsigned int wanted_max_vfs(struct xe_device *xe) { @@ -157,7 +158,7 @@ int xe_sriov_pf_wait_ready(struct xe_device *xe) unsigned int id; int err; - if (xe_device_wedged(xe)) + if (xe_wedged(xe)) return -ECANCELED; for_each_gt(gt, xe, id) { diff --git a/drivers/gpu/drm/xe/xe_survivability_mode.c b/drivers/gpu/drm/xe/xe_survivability_mode.c index 45d44ebe288b..d73cdad0b3a9 100644 --- a/drivers/gpu/drm/xe/xe_survivability_mode.c +++ b/drivers/gpu/drm/xe/xe_survivability_mode.c @@ -20,6 +20,7 @@ #include "xe_pcode_api.h" #include "xe_printk.h" #include "xe_vsec.h" +#include "xe_wedge.h" /** * DOC: Survivability Mode @@ -446,8 +447,7 @@ void xe_survivability_mode_runtime_enable(struct xe_device *xe) survivability->type = XE_SURVIVABILITY_TYPE_RUNTIME; xe_log_err(xe, SURVIVABILITY, 0, "Runtime Mode enabled!\n"); - xe_device_set_wedged_method(xe, DRM_WEDGE_RECOVERY_VENDOR); - xe_device_declare_wedged(xe); + xe_wedge_declare(xe, DRM_WEDGE_RECOVERY_VENDOR); xe_log_err(xe, SURVIVABILITY, 0, "Firmware flash required!\n"); xe_info(xe, "Please refer to the userspace documentation for more details how to flash the firmware on %s!\n", diff --git a/drivers/gpu/drm/xe/xe_tuning.c b/drivers/gpu/drm/xe/xe_tuning.c index 024dd2e71b17..1c230993648f 100644 --- a/drivers/gpu/drm/xe/xe_tuning.c +++ b/drivers/gpu/drm/xe/xe_tuning.c @@ -51,7 +51,7 @@ VISIBLE_IF_KUNIT const struct xe_rtp_table_sr gt_tunings = XE_RTP_TABLE_SR( SET(CCCHKNREG1, L3CMPCTRL)) }, { XE_RTP_NAME("Tuning: Compression Overfetch - media"), - XE_RTP_RULES(MEDIA_VERSION_RANGE(2000, XE_RTP_END_VERSION_UNDEFINED)), + XE_RTP_RULES(MEDIA_VERSION_RANGE(2000, 3499)), XE_RTP_ACTIONS(CLR(XE2LPM_CCCHKNREG1, ENCOMPPERFFIX), SET(XE2LPM_CCCHKNREG1, L3CMPCTRL)) }, diff --git a/drivers/gpu/drm/xe/xe_uc.c b/drivers/gpu/drm/xe/xe_uc.c index 65f59f06177f..686c28856014 100644 --- a/drivers/gpu/drm/xe/xe_uc.c +++ b/drivers/gpu/drm/xe/xe_uc.c @@ -326,15 +326,15 @@ void xe_uc_runtime_resume(struct xe_uc *uc) } /** - * xe_uc_declare_wedged() - Declare UC wedged + * xe_uc_wedge_declare() - Declare UC wedged * @uc: the UC object * * Wedge the UC which stops all submission, saves desired debug state, and * cleans up anything which could timeout. */ -void xe_uc_declare_wedged(struct xe_uc *uc) +void xe_uc_wedge_declare(struct xe_uc *uc) { xe_gt_assert(uc_to_gt(uc), uc_to_xe(uc)->wedged.mode); - xe_guc_declare_wedged(&uc->guc); + xe_guc_wedge_declare(&uc->guc); } diff --git a/drivers/gpu/drm/xe/xe_uc.h b/drivers/gpu/drm/xe/xe_uc.h index 255a54a8f876..23bc0ce1c42f 100644 --- a/drivers/gpu/drm/xe/xe_uc.h +++ b/drivers/gpu/drm/xe/xe_uc.h @@ -21,6 +21,6 @@ int xe_uc_start(struct xe_uc *uc); void xe_uc_suspend_prepare(struct xe_uc *uc); int xe_uc_suspend(struct xe_uc *uc); int xe_uc_sanitize_reset(struct xe_uc *uc); -void xe_uc_declare_wedged(struct xe_uc *uc); +void xe_uc_wedge_declare(struct xe_uc *uc); #endif diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index 3780d89a9342..dfbabfb19cbb 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -273,8 +273,15 @@ int xe_vm_add_compute_exec_queue(struct xe_vm *vm, struct xe_exec_queue *q) * Check to see if a preemption on VM is in flight or userptr * invalidation, if so trigger this preempt fence to sync state with * other preempt fences on the VM. + * + * Also trigger it if eviction or rebinding is pending. BOs evicted + * before the first exec queue was added had no preempt fence to + * trigger. Suspend this queue until the rebind worker restores + * the mappings. */ - wait = __xe_vm_userptr_needs_repin(vm) || preempt_fences_waiting(vm); + wait = __xe_vm_userptr_needs_repin(vm) || preempt_fences_waiting(vm) || + !list_empty(&vm->gpuvm.evict.list) || + !list_empty(&vm->rebind_list); if (wait) dma_fence_enable_signaling(pfence); @@ -3812,14 +3819,15 @@ static int vm_bind_ioctl_check_args(struct xe_device *xe, struct xe_vm *vm, pat_index = array_index_nospec(pat_index, xe->pat.n_entries); (*bind_ops)[i].pat_index = pat_index; - coh_mode = xe_pat_index_get_coh_mode(xe, pat_index); - comp_en = xe_pat_index_get_comp_en(xe, pat_index); - if (XE_IOCTL_DBG(xe, !coh_mode)) { /* hw reserved */ + if (XE_IOCTL_DBG(xe, !xe_pat_index_is_valid(xe, pat_index))) { err = -EINVAL; goto free_bind_ops; } - if (XE_WARN_ON(coh_mode > XE_COH_2WAY)) { + coh_mode = xe_pat_index_get_coh_mode(xe, pat_index); + comp_en = xe_pat_index_get_comp_en(xe, pat_index); + + if (XE_IOCTL_DBG(xe, xe_pat_wa_14026539277_reserved(xe, pat_index))) { err = -EINVAL; goto free_bind_ops; } diff --git a/drivers/gpu/drm/xe/xe_vm_madvise.c b/drivers/gpu/drm/xe/xe_vm_madvise.c index 5c7aefc641ee..31245c6c96d4 100644 --- a/drivers/gpu/drm/xe/xe_vm_madvise.c +++ b/drivers/gpu/drm/xe/xe_vm_madvise.c @@ -393,17 +393,13 @@ static bool madvise_args_are_sane(struct xe_device *xe, const struct drm_xe_madv break; case DRM_XE_MEM_RANGE_ATTR_PAT: { - u16 pat_index, coh_mode; + u16 pat_index; if (XE_IOCTL_DBG(xe, args->pat_index.val >= xe->pat.n_entries)) return false; pat_index = array_index_nospec(args->pat_index.val, xe->pat.n_entries); - coh_mode = xe_pat_index_get_coh_mode(xe, pat_index); - if (XE_IOCTL_DBG(xe, !coh_mode)) - return false; - - if (XE_WARN_ON(coh_mode > XE_COH_2WAY)) + if (XE_IOCTL_DBG(xe, !xe_pat_index_is_valid(xe, pat_index))) return false; if (XE_IOCTL_DBG(xe, args->pat_index.pad)) @@ -411,6 +407,10 @@ static bool madvise_args_are_sane(struct xe_device *xe, const struct drm_xe_madv if (XE_IOCTL_DBG(xe, args->pat_index.reserved)) return false; + + if (XE_IOCTL_DBG(xe, xe_pat_wa_14026539277_reserved(xe, pat_index))) + return false; + break; } case DRM_XE_VMA_ATTR_PURGEABLE_STATE: @@ -659,11 +659,8 @@ int xe_vm_madvise_ioctl(struct drm_device *dev, void *data, struct drm_file *fil err = -EINVAL; goto free_vmas; } - } - if (args->type == DRM_XE_MEM_RANGE_ATTR_PAT) { - if (!check_pat_args_are_sane(xe, &madvise_range, - args->pat_index.val)) { + if (!check_pat_args_are_sane(xe, &madvise_range, pat_index)) { err = -EINVAL; goto free_vmas; } diff --git a/drivers/gpu/drm/xe/xe_wa_oob.rules b/drivers/gpu/drm/xe/xe_wa_oob.rules index f35181fc4e49..96132c6e3340 100644 --- a/drivers/gpu/drm/xe/xe_wa_oob.rules +++ b/drivers/gpu/drm/xe/xe_wa_oob.rules @@ -72,7 +72,8 @@ GRAPHICS_VERSION(3511) 16029897822 MEDIA_VERSION(3500) GRAPHICS_VERSION(3510) +14026539277 GRAPHICS_VERSION(3510), GRAPHICS_STEP(A0, B0) 14027054324 GRAPHICS_VERSION(3511) 14025941587 GRAPHICS_VERSION_RANGE(2001, 3511), FUNC(xe_rtp_match_not_sriov_vf) MEDIA_VERSION_RANGE(1301, 3503), FUNC(xe_rtp_match_not_sriov_vf) -16030224309 GRAPHICS_VERSION(3510) +16030224309 GRAPHICS_VERSION_RANGE(3510, 3511) diff --git a/drivers/gpu/drm/xe/xe_wedge.c b/drivers/gpu/drm/xe/xe_wedge.c new file mode 100644 index 000000000000..2f35937c5e66 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_wedge.c @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2026 Intel Corporation + */ + +#include <drm/drm_drv.h> +#include <drm/drm_managed.h> + +#include "xe_defaults.h" +#include "xe_device.h" +#include "xe_gt.h" +#include "xe_gt_printk.h" +#include "xe_guc_ads.h" +#include "xe_log.h" +#include "xe_module.h" +#include "xe_pm.h" +#include "xe_printk.h" +#include "xe_sriov.h" +#include "xe_wedge.h" + +/** + * DOC: Xe Device Wedging + * + * Xe driver uses drm device wedged uevent as documented in Documentation/gpu/drm-uapi.rst. + * When device is in wedged state, every IOCTL will be blocked and GT cannot + * be used. The conditions under which the driver declares the device wedged + * depend on the wedge mode configuration (see &enum xe_wedged_mode). The + * default recovery method for a wedged state is rebind/bus-reset. + * + * Another recovery method is vendor-specific. Below are the cases that send + * ``WEDGED=vendor-specific`` recovery method in drm device wedged uevent. + * + * Case: Firmware Flash + * -------------------- + * + * Identification Hint + * +++++++++++++++++++ + * + * ``WEDGED=vendor-specific`` drm device wedged uevent with + * :ref:`Runtime Survivability mode <xe-survivability-mode>` is used to notify + * admin/userspace consumer about the need for a firmware flash. + * + * Recovery Procedure + * ++++++++++++++++++ + * + * Once ``WEDGED=vendor-specific`` drm device wedged uevent is received, follow + * the below steps + * + * - Check Runtime Survivability mode sysfs. + * If enabled, firmware flash is required to recover the device. + * + * /sys/bus/pci/devices/<device>/survivability_mode + * + * - Admin/userspace consumer can use firmware flashing tools like fwupd to flash + * firmware and restore device to normal operation. + */ + +static void wedge_work(struct work_struct *work) +{ + struct xe_device *xe = container_of(work, struct xe_device, wedged.work); + + /* Notify userspace of wedged device */ + drm_dev_wedged_event(&xe->drm, xe->wedged.method, NULL); +} + +#define WEDGED_URL "https://docs.kernel.org/gpu/drm-uapi.html#device-wedging" +#define XE_BUG_URL "https://gitlab.freedesktop.org/drm/xe/kernel/issues/new" + +/** + * xe_wedge_declare() - Declare device wedged + * @xe: xe device instance + * @method: method(s) to be used for recovery + * + * This is the final state that can only be cleared with the recovery method + * specified in the drm wedged uevent. + * + * In this state every IOCTL will be blocked so the GT cannot be used. + * In general it will be called upon any critical error such as gt reset + * failure or guc loading failure. Userspace will be notified of this state + * through device wedged uevent. + * + * If xe.wedged module parameter is set to 2, this function will be called + * on every single execution timeout (a.k.a. GPU hang) right after devcoredump + * snapshot capture. In this mode, GT reset won't be attempted so the state of + * the issue is preserved for further debugging. + * + * Since the wedge handling is done as part of worker thread, this is safe for + * atomic callers. + */ +void xe_wedge_declare(struct xe_device *xe, unsigned long method) +{ + struct xe_gt *gt; + u8 id; + + if (xe->wedged.mode == XE_WEDGED_MODE_NEVER) { + xe_dbg(xe, "Wedged mode is forcibly disabled\n"); + return; + } + + if (atomic_xchg(&xe->wedged.flag, 1)) + return; + + xe->needs_flr_on_fini = true; + xe_pm_runtime_get_noresume(xe); + + xe_log_err_fatal(xe, WEDGED, -EIO, "Device declared wedged!\n"); + xe_err_once(xe, "IOCTLs and executions are now blocked!\n" + "For recovery procedure, refer to %s\n" + "Please file a _new_ bug report at %s\n", + WEDGED_URL, XE_BUG_URL); + + for_each_initialized_gt(gt, xe, id) + xe_gt_wedge_declare(gt); + + /* + * XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET is intended for debugging + * hangs, so wedge the device with 'none' recovery method and have + * it available to the user for debugging. + */ + if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) + xe->wedged.method = DRM_WEDGE_RECOVERY_NONE; + else + xe->wedged.method = method; + + schedule_work(&xe->wedged.work); +} + +static const char *wedge_mode_to_string(enum xe_wedged_mode mode) +{ + switch (mode) { + case XE_WEDGED_MODE_NEVER: + return "never"; + case XE_WEDGED_MODE_UPON_CRITICAL_ERROR: + return "upon-critical-error"; + case XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET: + return "upon-any-hang-no-reset"; + default: + return "<invalid>"; + } +} + +static int wedge_validate_mode(struct xe_device *xe, unsigned int mode) +{ + if (mode > XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) { + xe_dbg(xe, "wedged_mode: invalid value (%u)\n", mode); + return -EINVAL; + } else if (mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET && (IS_SRIOV_VF(xe) || + (IS_SRIOV_PF(xe) && !IS_ENABLED(CONFIG_DRM_XE_DEBUG)))) { + xe_dbg(xe, "wedged_mode: (%u) %s mode is not supported for %s\n", + mode, wedge_mode_to_string(mode), + xe_sriov_mode_to_string(xe_device_sriov_mode(xe))); + return -EPERM; + } + + return 0; +} + +static bool wedge_mode_needs_policy_update(struct xe_device *xe, enum xe_wedged_mode mode) +{ + if (xe->wedged.inconsistent_reset) + return true; + + if (xe->wedged.mode == mode) + return false; + + if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET || + mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) + return true; + + return false; +} + +static int __wedge_mode_set_reset_policy(struct xe_gt *gt, enum xe_wedged_mode mode) +{ + bool enable_engine_reset; + int ret; + + enable_engine_reset = (mode != XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET); + ret = xe_guc_ads_scheduler_policy_toggle_reset(>->uc.guc.ads, + enable_engine_reset); + if (ret) + xe_gt_err(gt, "Failed to update GuC ADS scheduler policy (%pe)\n", ERR_PTR(ret)); + + return ret; +} + +static int wedge_mode_set_reset_policy(struct xe_device *xe, enum xe_wedged_mode mode) +{ + struct xe_gt *gt; + int ret; + u8 id; + + guard(xe_pm_runtime)(xe); + for_each_gt(gt, xe, id) { + ret = __wedge_mode_set_reset_policy(gt, mode); + if (ret) { + if (id > 0) { + xe->wedged.inconsistent_reset = true; + xe_err(xe, "Inconsistent reset policy state between GTs\n"); + } + return ret; + } + } + + xe->wedged.inconsistent_reset = false; + + return 0; +} + +/** + * xe_wedge_set_mode() - Set wedge mode + * @xe: xe device instance + * @mode: wedge mode to be set + * + * Returns: 0 on success, negative error code otherwise. + */ +int xe_wedge_set_mode(struct xe_device *xe, enum xe_wedged_mode mode) +{ + int ret; + + ret = wedge_validate_mode(xe, mode); + if (ret) + return ret; + + if (wedge_mode_needs_policy_update(xe, mode)) { + ret = wedge_mode_set_reset_policy(xe, mode); + if (ret) + return ret; + } + + xe->wedged.mode = mode; + + return ret; +} + +static void xe_wedge_fini(struct drm_device *drm, void *arg) +{ + struct xe_device *xe = arg; + + disable_work_sync(&xe->wedged.work); + + if (atomic_read(&xe->wedged.flag)) + xe_pm_runtime_put(xe); +} + +/** + * xe_wedge_init() - Initialize wedge + * @xe: xe device instance + * + * Returns: 0 on success, negative error code otherwise. + */ +int xe_wedge_init(struct xe_device *xe) +{ + INIT_WORK(&xe->wedged.work, wedge_work); + + xe->wedged.mode = wedge_validate_mode(xe, xe_modparam.wedged_mode) ? + XE_DEFAULT_WEDGED_MODE : xe_modparam.wedged_mode; + xe_dbg(xe, "wedged_mode: setting mode (%u) %s\n", + xe->wedged.mode, wedge_mode_to_string(xe->wedged.mode)); + + return drmm_add_action_or_reset(&xe->drm, xe_wedge_fini, xe); +} diff --git a/drivers/gpu/drm/xe/xe_wedge.h b/drivers/gpu/drm/xe/xe_wedge.h new file mode 100644 index 000000000000..3b5499dfc30d --- /dev/null +++ b/drivers/gpu/drm/xe/xe_wedge.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2026 Intel Corporation + */ + +#ifndef _XE_WEDGE_H_ +#define _XE_WEDGE_H_ + +#include <linux/atomic.h> +#include <linux/types.h> + +#include "xe_device_types.h" +#include "xe_wedge_types.h" + +static inline bool xe_wedged(struct xe_device *xe) +{ + return atomic_read(&xe->wedged.flag); +} + +void xe_wedge_declare(struct xe_device *xe, unsigned long method); +int xe_wedge_init(struct xe_device *xe); +int xe_wedge_set_mode(struct xe_device *xe, enum xe_wedged_mode mode); + +#endif diff --git a/drivers/gpu/drm/xe/xe_wedge_types.h b/drivers/gpu/drm/xe/xe_wedge_types.h new file mode 100644 index 000000000000..e472c5fcbd26 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_wedge_types.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2026 Intel Corporation + */ + +#ifndef _XE_WEDGE_TYPES_H_ +#define _XE_WEDGE_TYPES_H_ + +#include <linux/types.h> +#include <linux/workqueue_types.h> + +/** + * enum xe_wedged_mode - Possible wedge modes + * @XE_WEDGED_MODE_NEVER: Device will never be declared wedged. + * @XE_WEDGED_MODE_UPON_CRITICAL_ERROR: Device will be declared wedged only + * when critical error occurs like GT reset failure or firmware failure. + * This is the default mode. + * @XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET: Device will be declared wedged on + * any hang. In this mode, engine resets are disabled to avoid automatic + * recovery attempts. This mode is primarily intended for debugging hangs. + */ +enum xe_wedged_mode { + XE_WEDGED_MODE_NEVER = 0, + XE_WEDGED_MODE_UPON_CRITICAL_ERROR = 1, + XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET = 2, +}; + +/** + * struct xe_wedge - Struct to control Wedged States and mode + */ +struct xe_wedge { + /** @flag: Xe device faced a critical error and is now blocked. */ + atomic_t flag; + /** @mode: Mode controlled by kernel parameter and debugfs */ + enum xe_wedged_mode mode; + /** @method: Recovery method to be sent in the drm device wedged uevent */ + unsigned long method; + /** @inconsistent_reset: Inconsistent reset policy state between GTs */ + bool inconsistent_reset; + /** @work: Worker to defer non-atomic calls */ + struct work_struct work; +}; + +#endif |
