diff options
| author | Dave Airlie <airlied@redhat.com> | 2026-10-29 14:41:47 +1000 |
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2026-10-29 16:01:40 +1000 |
| commit | f94ed3d7cba3c83eef50b1a96d630d63cf54f69c (patch) | |
| tree | 97e14658229f9e3f2306dc49d15e32e7acb0aaf1 /drivers/gpu | |
| parent | 460635aa3d5ddba65ee147e9f864a17d6b2665b1 (diff) | |
| parent | fbb201890156e04b062c4488d1b500de52367684 (diff) | |
Merge tag 'amd-drm-next-fixes-7.4-2026-10-28' of https://gitlab.freedesktop.org/drm/amdgpu/kernel into drm-next
amd-drm-next-fixes-7.4-2026-10-28:
amdgpu:
- VCE/UVD sched teardown fix
- Display runpm reference fix
- Display TD-LUT fix
- SMU 13.x fixes
- SMU 14.x fixes
- Gang submit fix
- Passive DVI sink fix
- USB4 tunnel fix
- Freesync fix
amdkfd:
- Bounds checking fixes
- Hotplug fixes
- SVM fixes
- CRIU fixes
- GFX12 fix
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Alex Deucher <alexander.deucher@amd.com>
Link: https://patch.msgid.link/20261028214423.1295475-1-alexander.deucher@amd.com
Diffstat (limited to 'drivers/gpu')
28 files changed, 734 insertions, 255 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 3391e8c77f13..53dde87f97f5 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_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index ff77e8ae9fe6..3a4b3424b5b2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -2854,6 +2854,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; @@ -2873,14 +2874,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 @@ -2889,11 +2892,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; } @@ -2911,8 +2917,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 65e13ad445bb..70bc53923d11 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -218,6 +218,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 f147c0c459da..c65bc575a57a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -4331,8 +4331,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); 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_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/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index cad60ccdb216..d65ae53c81a5 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..6c9bafa3962e 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) 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..5709949de2eb 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) 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..aea80266d254 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c @@ -393,6 +393,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 d508ac5a18f8..33f0ecbe6b0a 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 @@ -690,6 +690,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..fca43017ee7e 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) 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/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 5b634ae07c0d..0ea45ab12119 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -2021,10 +2021,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) { @@ -4709,8 +4705,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; @@ -5294,8 +5288,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); 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 2b81396bd06e..b498fc5fbb14 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 */ @@ -3780,10 +3780,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_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index 6febc15ebc2b..41e52c54156e 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 @@ -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_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/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 2d43a35c4c42..7a288b352079 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/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c index 468aaeb79ffb..e80087e35e19 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; @@ -2184,6 +2276,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, @@ -2193,6 +2286,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) { @@ -2231,6 +2325,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); @@ -2243,13 +2345,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; } @@ -3043,10 +3154,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) @@ -3058,12 +3167,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; @@ -3075,11 +3179,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 51e419e6380c..8285d4a91589 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; @@ -2186,6 +2279,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, @@ -2195,6 +2289,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) { @@ -2233,6 +2328,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); @@ -2245,14 +2348,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; } @@ -2664,10 +2775,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) @@ -2679,13 +2788,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; @@ -2697,12 +2800,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 549716349117..6a12d6f8c9dd 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 @@ -89,6 +89,11 @@ static const struct smu_feature_bits smu_v14_0_2_dpm_features = { #define PP_OD_FEATURE_FAN_TARGET_TEMPERATURE 9 #define PP_OD_FEATURE_FAN_MINIMUM_PWM 10 #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), @@ -962,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, @@ -1020,6 +1103,10 @@ static void smu_v14_0_2_get_od_setting_limits(struct smu_context *smu, od_min_setting = overdrive_lowerlimits->FanZeroRpmEnable; od_max_setting = overdrive_upperlimits->FanZeroRpmEnable; break; + case PP_OD_FEATURE_FAN_ZERO_RPM_STOP_TEMP: + od_min_setting = pptable->SkuTable.MsgLimits.FanStopTempMin; + od_max_setting = pptable->SkuTable.MsgLimits.FanStopTempMax; + break; default: od_min_setting = od_max_setting = INT_MAX; break; @@ -1244,6 +1331,24 @@ static int smu_v14_0_2_emit_clk_levels(struct smu_context *smu, min_value, max_value); break; + case SMU_OD_FAN_ZERO_RPM_STOP_TEMP: + if (!smu_v14_0_2_is_od_feature_supported(smu, + PP_OD_FEATURE_ZERO_FAN_BIT)) + break; + + size += sysfs_emit_at(buf, size, "FAN_ZERO_RPM_STOP_TEMPERATURE:\n"); + size += sysfs_emit_at(buf, size, "%d\n", + (int)od_table->OverDriveTable.FanZeroRpmStopTemp); + + size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE"); + smu_v14_0_2_get_od_setting_limits(smu, + PP_OD_FEATURE_FAN_ZERO_RPM_STOP_TEMP, + &min_value, + &max_value); + size += sysfs_emit_at(buf, size, "ZERO_RPM_STOP_TEMPERATURE: %u %u\n", + min_value, max_value); + break; + case SMU_OD_RANGE: if (!smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_GFXCLK_BIT) && !smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_UCLK_BIT) && @@ -2294,6 +2399,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; @@ -2311,7 +2448,9 @@ static void smu_v14_0_2_set_supported_od_feature_mask(struct smu_context *smu) OD_OPS_SUPPORT_FAN_MINIMUM_PWM_RETRIEVE | OD_OPS_SUPPORT_FAN_MINIMUM_PWM_SET | OD_OPS_SUPPORT_FAN_ZERO_RPM_ENABLE_RETRIEVE | - OD_OPS_SUPPORT_FAN_ZERO_RPM_ENABLE_SET; + OD_OPS_SUPPORT_FAN_ZERO_RPM_ENABLE_SET | + OD_OPS_SUPPORT_FAN_ZERO_RPM_STOP_TEMP_RETRIEVE | + OD_OPS_SUPPORT_FAN_ZERO_RPM_STOP_TEMP_SET; } static int smu_v14_0_2_get_overdrive_table(struct smu_context *smu, @@ -2350,6 +2489,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, @@ -2359,6 +2499,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) { @@ -2393,6 +2534,16 @@ static int smu_v14_0_2_set_default_od_settings(struct smu_context *smu) user_od_table_bak.OverDriveTable.FanMinimumPwm; user_od_table->OverDriveTable.FanZeroRpmEnable = 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); @@ -2405,14 +2556,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; } @@ -2436,38 +2595,30 @@ 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 = + boot_overdrive_table->OverDriveTable.FanZeroRpmStopTemp; 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_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); @@ -2485,9 +2636,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) { @@ -2659,6 +2818,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: @@ -2681,6 +2841,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: @@ -2703,6 +2864,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: @@ -2749,6 +2911,27 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu, od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT); break; + case PP_OD_EDIT_FAN_ZERO_RPM_STOP_TEMP: + if (!smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_ZERO_FAN_BIT)) { + dev_warn(adev->dev, "Zero RPM setting not supported!\n"); + return -ENOTSUPP; + } + + smu_v14_0_2_get_od_setting_limits(smu, + PP_OD_FEATURE_FAN_ZERO_RPM_STOP_TEMP, + &minimum, + &maximum); + if (input[0] < minimum || + input[0] > maximum) { + dev_info(adev->dev, "zero RPM stop temperature setting(%ld) must be within [%d, %d]!\n", + input[0], minimum, maximum); + return -EINVAL; + } + + od_table->OverDriveTable.FanZeroRpmStopTemp = input[0]; + od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT); + break; + case PP_OD_RESTORE_DEFAULT_TABLE: if (size == 1) { ret = smu_v14_0_2_od_restore_table_single(smu, input[0]); @@ -2759,44 +2942,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; @@ -2814,10 +2991,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) @@ -2829,13 +3004,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; @@ -2847,12 +3016,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; |
