diff options
| author | Dave Airlie <airlied@redhat.com> | 2026-01-18 23:53:41 +0300 |
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2026-01-18 23:54:46 +0300 |
| commit | c098b1aa2fa60fad42df8a1a6250099329e33311 (patch) | |
| tree | 59f8067c25de3a4e6bde2fb3bc067b6df2798ff1 | |
| parent | 971c2b68bddb87f4929e66cd4563fca78b722210 (diff) | |
| parent | 6a681cd9034587fe3550868bacfbd639d1c6891f (diff) | |
| download | linux-c098b1aa2fa60fad42df8a1a6250099329e33311.tar.xz | |
Merge tag 'amd-drm-next-6.20-2026-01-16' of https://gitlab.freedesktop.org/agd5f/linux into drm-next
amd-drm-next-6.20-2026-01-16:
amdgpu:
- SR-IOV fixes
- Rework SMU mailbox handling
- Drop MMIO_REMAP domain
- UserQ fixes
- MES cleanups
- Panel Replay updates
- HDMI fixes
- Backlight fixes
- SMU 14.x fixes
- SMU 15 updates
amdkfd:
- Fix a memory leak
- Fixes for systems with non-4K pages
- LDS/Scratch cleanup
- MES process eviction fix
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Alex Deucher <alexander.deucher@amd.com>
Link: https://patch.msgid.link/20260116202609.23107-1-alexander.deucher@amd.com
101 files changed, 1951 insertions, 1239 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 11a36c132905..9c11535c44c6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -269,6 +269,8 @@ extern int amdgpu_rebar; extern int amdgpu_wbrf; extern int amdgpu_user_queue; +extern uint amdgpu_hdmi_hpd_debounce_delay_ms; + #define AMDGPU_VM_MAX_NUM_CTX 4096 #define AMDGPU_SG_THRESHOLD (256*1024*1024) #define AMDGPU_WAIT_IDLE_TIMEOUT_IN_MS 3000 diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 67a01c4f3885..15770e9a7e63 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -248,6 +248,11 @@ void amdgpu_amdkfd_interrupt(struct amdgpu_device *adev, kgd2kfd_interrupt(adev->kfd.dev, ih_ring_entry); } +void amdgpu_amdkfd_teardown_processes(struct amdgpu_device *adev) +{ + kgd2kfd_teardown_processes(adev); +} + void amdgpu_amdkfd_suspend(struct amdgpu_device *adev, bool suspend_proc) { if (adev->kfd.dev) { @@ -316,8 +321,8 @@ void amdgpu_amdkfd_gpu_reset(struct amdgpu_device *adev) &adev->kfd.reset_work); } -int amdgpu_amdkfd_alloc_gtt_mem(struct amdgpu_device *adev, size_t size, - void **mem_obj, uint64_t *gpu_addr, +int amdgpu_amdkfd_alloc_kernel_mem(struct amdgpu_device *adev, size_t size, + u32 domain, void **mem_obj, uint64_t *gpu_addr, void **cpu_ptr, bool cp_mqd_gfx9) { struct amdgpu_bo *bo = NULL; @@ -328,7 +333,7 @@ int amdgpu_amdkfd_alloc_gtt_mem(struct amdgpu_device *adev, size_t size, memset(&bp, 0, sizeof(bp)); bp.size = size; bp.byte_align = PAGE_SIZE; - bp.domain = AMDGPU_GEM_DOMAIN_GTT; + bp.domain = domain; bp.flags = AMDGPU_GEM_CREATE_CPU_GTT_USWC; bp.type = ttm_bo_type_kernel; bp.resv = NULL; @@ -351,7 +356,7 @@ int amdgpu_amdkfd_alloc_gtt_mem(struct amdgpu_device *adev, size_t size, goto allocate_mem_reserve_bo_failed; } - r = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT); + r = amdgpu_bo_pin(bo, domain); if (r) { dev_err(adev->dev, "(%d) failed to pin bo for amdkfd\n", r); goto allocate_mem_pin_bo_failed; @@ -388,7 +393,7 @@ allocate_mem_reserve_bo_failed: return r; } -void amdgpu_amdkfd_free_gtt_mem(struct amdgpu_device *adev, void **mem_obj) +void amdgpu_amdkfd_free_kernel_mem(struct amdgpu_device *adev, void **mem_obj) { struct amdgpu_bo **bo = (struct amdgpu_bo **) mem_obj; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index da4575676335..cdbab7f8cee8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -158,6 +158,7 @@ struct amdkfd_process_info { int amdgpu_amdkfd_init(void); void amdgpu_amdkfd_fini(void); +void amdgpu_amdkfd_teardown_processes(struct amdgpu_device *adev); void amdgpu_amdkfd_suspend(struct amdgpu_device *adev, bool suspend_proc); int amdgpu_amdkfd_resume(struct amdgpu_device *adev, bool resume_proc); @@ -240,10 +241,10 @@ int amdgpu_amdkfd_bo_validate_and_fence(struct amdgpu_bo *bo, } #endif /* Shared API */ -int amdgpu_amdkfd_alloc_gtt_mem(struct amdgpu_device *adev, size_t size, - void **mem_obj, uint64_t *gpu_addr, +int amdgpu_amdkfd_alloc_kernel_mem(struct amdgpu_device *adev, size_t size, + u32 domain, void **mem_obj, uint64_t *gpu_addr, void **cpu_ptr, bool mqd_gfx9); -void amdgpu_amdkfd_free_gtt_mem(struct amdgpu_device *adev, void **mem_obj); +void amdgpu_amdkfd_free_kernel_mem(struct amdgpu_device *adev, void **mem_obj); int amdgpu_amdkfd_alloc_gws(struct amdgpu_device *adev, size_t size, void **mem_obj); void amdgpu_amdkfd_free_gws(struct amdgpu_device *adev, void *mem_obj); @@ -438,6 +439,8 @@ int kgd2kfd_stop_sched_all_nodes(struct kfd_dev *kfd); bool kgd2kfd_compute_active(struct kfd_dev *kfd, uint32_t node_id); bool kgd2kfd_vmfault_fast_path(struct amdgpu_device *adev, struct amdgpu_iv_entry *entry, bool retry_fault); +void kgd2kfd_lock_kfd(void); +void kgd2kfd_teardown_processes(struct amdgpu_device *adev); #else static inline int kgd2kfd_init(void) @@ -550,5 +553,13 @@ static inline bool kgd2kfd_vmfault_fast_path(struct amdgpu_device *adev, struct return false; } +static inline void kgd2kfd_lock_kfd(void) +{ +} + +static inline void kgd2kfd_teardown_processes(struct amdgpu_device *adev) +{ +} + #endif #endif /* AMDGPU_AMDKFD_H_INCLUDED */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index 88fc430b9425..768998c82b43 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -2215,7 +2215,7 @@ int amdgpu_amdkfd_gpuvm_sync_memory( * @bo_gart: Return bo reference * * Before return, bo reference count is incremented. To release the reference and unpin/ - * unmap the BO, call amdgpu_amdkfd_free_gtt_mem. + * unmap the BO, call amdgpu_amdkfd_free_kernel_mem. */ int amdgpu_amdkfd_map_gtt_bo_to_gart(struct amdgpu_bo *bo, struct amdgpu_bo **bo_gart) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 347996f6ffaa..502500f8d70e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -3509,6 +3509,7 @@ static int amdgpu_device_ip_fini_early(struct amdgpu_device *adev) amdgpu_device_set_cg_state(adev, AMD_CG_STATE_UNGATE); amdgpu_amdkfd_suspend(adev, true); + amdgpu_amdkfd_teardown_processes(adev); amdgpu_userq_suspend(adev); /* Workaround for ASICs need to disable SMC first */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index 8070a6da794f..ee2c08f81051 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -891,22 +891,19 @@ static ssize_t num_base_addresses_show(struct ip_hw_instance *ip_hw_instance, ch static ssize_t base_addr_show(struct ip_hw_instance *ip_hw_instance, char *buf) { - ssize_t res, at; + ssize_t at; int ii; - for (res = at = ii = 0; ii < ip_hw_instance->num_base_addresses; ii++) { + for (at = ii = 0; ii < ip_hw_instance->num_base_addresses; ii++) { /* Here we satisfy the condition that, at + size <= PAGE_SIZE. */ if (at + 12 > PAGE_SIZE) break; - res = sysfs_emit_at(buf, at, "0x%08X\n", + at += sysfs_emit_at(buf, at, "0x%08X\n", ip_hw_instance->base_addr[ii]); - if (res <= 0) - break; - at += res; } - return res < 0 ? res : at; + return at; } static struct ip_hw_instance_attr ip_hw_attr[] = { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index bb8d9256fae0..d6d0a6e34c6b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -247,6 +247,7 @@ int amdgpu_damage_clips = -1; /* auto */ int amdgpu_umsch_mm_fwlog; int amdgpu_rebar = -1; /* auto */ int amdgpu_user_queue = -1; +uint amdgpu_hdmi_hpd_debounce_delay_ms; DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0, "DRM_UT_CORE", @@ -1123,6 +1124,16 @@ module_param_named(rebar, amdgpu_rebar, int, 0444); MODULE_PARM_DESC(user_queue, "Enable user queues (-1 = auto (default), 0 = disable, 1 = enable, 2 = enable UQs and disable KQs)"); module_param_named(user_queue, amdgpu_user_queue, int, 0444); +/* + * DOC: hdmi_hpd_debounce_delay_ms (uint) + * HDMI HPD disconnect debounce delay in milliseconds. + * + * Used to filter short disconnect->reconnect HPD toggles some HDMI sinks + * generate while entering/leaving power save. Set to 0 to disable by default. + */ +MODULE_PARM_DESC(hdmi_hpd_debounce_delay_ms, "HDMI HPD disconnect debounce delay in milliseconds (0 to disable (by default), 1500 is common)"); +module_param_named(hdmi_hpd_debounce_delay_ms, amdgpu_hdmi_hpd_debounce_delay_ms, uint, 0644); + /* These devices are not supported by amdgpu. * They are supported by the mach64, r128, radeon drivers */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c index 16c3b78e50cb..ec911dce345f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c @@ -375,7 +375,7 @@ void amdgpu_gart_map(struct amdgpu_device *adev, uint64_t offset, * @start_page: first page to map in the GART aperture * @num_pages: number of pages to be mapped * @flags: page table entry flags - * @dst: CPU address of the GART table + * @dst: valid CPU address of GART table, cannot be null * * Binds a BO that is allocated in VRAM to the GART page table * (all ASICs). @@ -396,7 +396,7 @@ void amdgpu_gart_map_vram_range(struct amdgpu_device *adev, uint64_t pa, return; for (i = 0; i < num_pages; ++i) { - amdgpu_gmc_set_pte_pde(adev, adev->gart.ptr, + amdgpu_gmc_set_pte_pde(adev, dst, start_page + i, pa + AMDGPU_GPU_PAGE_SIZE * i, flags); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 032971d0a3cc..5f9fa2140f09 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -417,9 +417,6 @@ int amdgpu_gem_create_ioctl(struct drm_device *dev, void *data, /* always clear VRAM */ flags |= AMDGPU_GEM_CREATE_VRAM_CLEARED; - if (args->in.domains & AMDGPU_GEM_DOMAIN_MMIO_REMAP) - return -EINVAL; - /* create a gem object to contain this object in */ if (args->in.domains & (AMDGPU_GEM_DOMAIN_GDS | AMDGPU_GEM_DOMAIN_GWS | AMDGPU_GEM_DOMAIN_OA)) { @@ -732,15 +729,23 @@ amdgpu_gem_va_update_vm(struct amdgpu_device *adev, struct amdgpu_bo_va *bo_va, uint32_t operation) { - struct dma_fence *clear_fence = dma_fence_get_stub(); - struct dma_fence *last_update = NULL; - int r; + struct dma_fence *fence; + int r = 0; + + /* Always start from the VM's existing last update fence. */ + fence = dma_fence_get(vm->last_update); if (!amdgpu_vm_ready(vm)) - return clear_fence; + return fence; - /* First clear freed BOs and get a fence for that work, if any. */ - r = amdgpu_vm_clear_freed(adev, vm, &clear_fence); + /* + * First clean up any freed mappings in the VM. + * + * amdgpu_vm_clear_freed() may replace @fence with a new fence if it + * schedules GPU work. If nothing needs clearing, @fence can remain as + * the original vm->last_update. + */ + r = amdgpu_vm_clear_freed(adev, vm, &fence); if (r) goto error; @@ -758,35 +763,38 @@ amdgpu_gem_va_update_vm(struct amdgpu_device *adev, goto error; /* - * Decide which fence represents the "last update" for this VM/BO: + * Decide which fence best represents the last update: + * + * MAP/REPLACE: + * - For always-valid mappings, use vm->last_update. + * - Otherwise, export bo_va->last_pt_update. * - * - For MAP/REPLACE we want the PT update fence, which is tracked as - * either vm->last_update (for always-valid BOs) or bo_va->last_pt_update - * (for per-BO updates). + * UNMAP/CLEAR: + * Keep the fence returned by amdgpu_vm_clear_freed(). If no work was + * needed, it can remain as vm->last_pt_update. * - * - For UNMAP/CLEAR we rely on the fence returned by - * amdgpu_vm_clear_freed(), which already covers the page table work - * for the removed mappings. + * The VM and BO update fences are always initialized to a valid value. + * vm->last_update and bo_va->last_pt_update always start as valid fences. + * and are never expected to be NULL. */ switch (operation) { case AMDGPU_VA_OP_MAP: case AMDGPU_VA_OP_REPLACE: - if (bo_va && bo_va->base.bo) { - if (amdgpu_vm_is_bo_always_valid(vm, bo_va->base.bo)) { - if (vm->last_update) - last_update = dma_fence_get(vm->last_update); - } else { - if (bo_va->last_pt_update) - last_update = dma_fence_get(bo_va->last_pt_update); - } - } + /* + * For MAP/REPLACE, return the page table update fence for the + * mapping we just modified. bo_va is expected to be valid here. + */ + dma_fence_put(fence); + + if (amdgpu_vm_is_bo_always_valid(vm, bo_va->base.bo)) + fence = dma_fence_get(vm->last_update); + else + fence = dma_fence_get(bo_va->last_pt_update); break; case AMDGPU_VA_OP_UNMAP: case AMDGPU_VA_OP_CLEAR: - if (clear_fence) - last_update = dma_fence_get(clear_fence); - break; default: + /* keep @fence as returned by amdgpu_vm_clear_freed() */ break; } @@ -794,17 +802,7 @@ error: if (r && r != -ERESTARTSYS) DRM_ERROR("Couldn't update BO_VA (%d)\n", r); - /* - * If we managed to pick a more specific last-update fence, prefer it - * over the generic clear_fence and drop the extra reference to the - * latter. - */ - if (last_update) { - dma_fence_put(clear_fence); - return last_update; - } - - return clear_fence; + return fence; } int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c index 6d7b8bb953ae..0e67fa4338ff 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c @@ -780,6 +780,10 @@ int amdgpu_gmc_flush_gpu_tlb_pasid(struct amdgpu_device *adev, uint16_t pasid, return 0; if (!adev->gmc.flush_pasid_uses_kiq || !ring->sched.ready) { + + if (!adev->gmc.gmc_funcs->flush_gpu_tlb_pasid) + return 0; + if (adev->gmc.flush_tlb_needs_extra_type_2) adev->gmc.gmc_funcs->flush_gpu_tlb_pasid(adev, pasid, 2, all_hub, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index dffa0f7276b7..6e19836c5ff6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -31,7 +31,6 @@ #define AMDGPU_MES_MAX_NUM_OF_QUEUES_PER_PROCESS 1024 #define AMDGPU_ONE_DOORBELL_SIZE 8 -#define AMDGPU_MES_RESERVED_QUEUES 2 int amdgpu_mes_doorbell_process_slice(struct amdgpu_device *adev) { @@ -89,12 +88,30 @@ static void amdgpu_mes_doorbell_free(struct amdgpu_device *adev) bitmap_free(adev->mes.doorbell_bitmap); } +static inline u32 amdgpu_mes_get_hqd_mask(u32 num_pipe, + u32 num_hqd_per_pipe, + u32 num_reserved_hqd) +{ + if (num_pipe == 0) + return 0; + + u32 total_hqd_mask = (u32)((1ULL << num_hqd_per_pipe) - 1); + u32 reserved_hqd_mask = (u32)((1ULL << DIV_ROUND_UP(num_reserved_hqd, num_pipe)) - 1); + + return (total_hqd_mask & ~reserved_hqd_mask); +} + int amdgpu_mes_init(struct amdgpu_device *adev) { int i, r, num_pipes; u32 total_vmid_mask, reserved_vmid_mask; - u32 queue_mask, reserved_queue_mask; int num_xcc = adev->gfx.xcc_mask ? NUM_XCC(adev->gfx.xcc_mask) : 1; + u32 gfx_hqd_mask = amdgpu_mes_get_hqd_mask(adev->gfx.me.num_pipe_per_me, + adev->gfx.me.num_queue_per_pipe, + adev->gfx.disable_kq ? 0 : adev->gfx.num_gfx_rings); + u32 compute_hqd_mask = amdgpu_mes_get_hqd_mask(adev->gfx.mec.num_pipe_per_mec, + adev->gfx.mec.num_queue_per_pipe, + adev->gfx.disable_kq ? 0 : adev->gfx.num_compute_rings); adev->mes.adev = adev; @@ -115,9 +132,6 @@ int amdgpu_mes_init(struct amdgpu_device *adev) adev->mes.vmid_mask_mmhub = 0xFF00; adev->mes.vmid_mask_gfxhub = total_vmid_mask & ~reserved_vmid_mask; - queue_mask = (u32)(1UL << adev->gfx.mec.num_queue_per_pipe) - 1; - reserved_queue_mask = (u32)(1UL << AMDGPU_MES_RESERVED_QUEUES) - 1; - num_pipes = adev->gfx.me.num_pipe_per_me * adev->gfx.me.num_me; if (num_pipes > AMDGPU_MES_MAX_GFX_PIPES) dev_warn(adev->dev, "more gfx pipes than supported by MES! (%d vs %d)\n", @@ -126,22 +140,8 @@ int amdgpu_mes_init(struct amdgpu_device *adev) for (i = 0; i < AMDGPU_MES_MAX_GFX_PIPES; i++) { if (i >= num_pipes) break; - if (amdgpu_ip_version(adev, GC_HWIP, 0) >= - IP_VERSION(12, 0, 0)) - /* - * GFX V12 has only one GFX pipe, but 8 queues in it. - * GFX pipe 0 queue 0 is being used by Kernel queue. - * Set GFX pipe 0 queue 1-7 for MES scheduling - * mask = 1111 1110b - */ - adev->mes.gfx_hqd_mask[i] = adev->gfx.disable_kq ? 0xFF : 0xFE; - else - /* - * GFX pipe 0 queue 0 is being used by Kernel queue. - * Set GFX pipe 0 queue 1 for MES scheduling - * mask = 10b - */ - adev->mes.gfx_hqd_mask[i] = adev->gfx.disable_kq ? 0x3 : 0x2; + + adev->mes.gfx_hqd_mask[i] = gfx_hqd_mask; } num_pipes = adev->gfx.mec.num_pipe_per_mec * adev->gfx.mec.num_mec; @@ -150,10 +150,16 @@ int amdgpu_mes_init(struct amdgpu_device *adev) num_pipes, AMDGPU_MES_MAX_COMPUTE_PIPES); for (i = 0; i < AMDGPU_MES_MAX_COMPUTE_PIPES; i++) { - if (i >= num_pipes) + /* + * Currently, only MEC1 is used for both kernel and user compute queue. + * To enable other MEC, we need to redistribute queues per pipe and + * adjust queue resource shared with kfd that needs a separate patch. + * Skip other MEC for now to avoid potential issues. + */ + if (i >= adev->gfx.mec.num_pipe_per_mec) break; - adev->mes.compute_hqd_mask[i] = - adev->gfx.disable_kq ? 0xF : (queue_mask & ~reserved_queue_mask); + + adev->mes.compute_hqd_mask[i] = compute_hqd_mask; } num_pipes = adev->sdma.num_instances; @@ -167,6 +173,17 @@ int amdgpu_mes_init(struct amdgpu_device *adev) adev->mes.sdma_hqd_mask[i] = 0xfc; } + dev_info(adev->dev, + "MES: vmid_mask_mmhub 0x%08x, vmid_mask_gfxhub 0x%08x\n", + adev->mes.vmid_mask_mmhub, + adev->mes.vmid_mask_gfxhub); + + dev_info(adev->dev, + "MES: gfx_hqd_mask 0x%08x, compute_hqd_mask 0x%08x, sdma_hqd_mask 0x%08x\n", + adev->mes.gfx_hqd_mask[0], + adev->mes.compute_hqd_mask[0], + adev->mes.sdma_hqd_mask[0]); + for (i = 0; i < AMDGPU_MAX_MES_PIPES * num_xcc; i++) { r = amdgpu_device_wb_get(adev, &adev->mes.sch_ctx_offs[i]); if (r) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index b676310ce9ac..1fb956400696 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -153,14 +153,6 @@ void amdgpu_bo_placement_from_domain(struct amdgpu_bo *abo, u32 domain) c++; } - if (domain & AMDGPU_GEM_DOMAIN_MMIO_REMAP) { - places[c].fpfn = 0; - places[c].lpfn = 0; - places[c].mem_type = AMDGPU_PL_MMIO_REMAP; - places[c].flags = 0; - c++; - } - if (domain & AMDGPU_GEM_DOMAIN_GTT) { places[c].fpfn = 0; places[c].lpfn = 0; @@ -1546,8 +1538,17 @@ u64 amdgpu_bo_gpu_offset_no_check(struct amdgpu_bo *bo) */ uint32_t amdgpu_bo_mem_stats_placement(struct amdgpu_bo *bo) { - uint32_t domain = bo->preferred_domains & AMDGPU_GEM_DOMAIN_MASK; + u32 domain; + /* + * MMIO_REMAP is internal now, so it no longer maps from a userspace + * domain bit. Keep fdinfo/mem-stats visibility by checking the actual + * TTM placement. + */ + if (bo->tbo.resource && bo->tbo.resource->mem_type == AMDGPU_PL_MMIO_REMAP) + return AMDGPU_PL_MMIO_REMAP; + + domain = bo->preferred_domains & AMDGPU_GEM_DOMAIN_MASK; if (!domain) return TTM_PL_SYSTEM; @@ -1566,8 +1567,6 @@ uint32_t amdgpu_bo_mem_stats_placement(struct amdgpu_bo *bo) return AMDGPU_PL_OA; case AMDGPU_GEM_DOMAIN_DOORBELL: return AMDGPU_PL_DOORBELL; - case AMDGPU_GEM_DOMAIN_MMIO_REMAP: - return AMDGPU_PL_MMIO_REMAP; default: return TTM_PL_SYSTEM; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h index 52c2d1731aab..912c9afaf9e1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h @@ -168,8 +168,6 @@ static inline unsigned amdgpu_mem_type_to_domain(u32 mem_type) return AMDGPU_GEM_DOMAIN_OA; case AMDGPU_PL_DOORBELL: return AMDGPU_GEM_DOMAIN_DOORBELL; - case AMDGPU_PL_MMIO_REMAP: - return AMDGPU_GEM_DOMAIN_MMIO_REMAP; default: break; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index cfbcce9c27c5..15d561e3d87f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1909,42 +1909,45 @@ static void amdgpu_ttm_pools_fini(struct amdgpu_device *adev) } /** - * amdgpu_ttm_mmio_remap_bo_init - Allocate the singleton 4K MMIO_REMAP BO + * amdgpu_ttm_mmio_remap_bo_init - Allocate the singleton MMIO_REMAP BO * @adev: amdgpu device * - * Allocates a one-page (4K) GEM BO in AMDGPU_GEM_DOMAIN_MMIO_REMAP when the + * Allocates a global BO with backing AMDGPU_PL_MMIO_REMAP when the * hardware exposes a remap base (adev->rmmio_remap.bus_addr) and the host * PAGE_SIZE is <= AMDGPU_GPU_PAGE_SIZE (4K). The BO is created as a regular * GEM object (amdgpu_bo_create). * - * The BO is created as a normal GEM object via amdgpu_bo_create(), then - * reserved and pinned at the TTM level (ttm_bo_pin()) so it can never be - * migrated or evicted. No CPU mapping is established here. - * * Return: * * 0 on success or intentional skip (feature not present/unsupported) * * negative errno on allocation failure */ -static int amdgpu_ttm_mmio_remap_bo_init(struct amdgpu_device *adev) +static int amdgpu_ttm_alloc_mmio_remap_bo(struct amdgpu_device *adev) { + struct ttm_operation_ctx ctx = { false, false }; + struct ttm_placement placement; + struct ttm_buffer_object *tbo; + struct ttm_place placements; struct amdgpu_bo_param bp; + struct ttm_resource *tmp; int r; /* Skip if HW doesn't expose remap, or if PAGE_SIZE > AMDGPU_GPU_PAGE_SIZE (4K). */ if (!adev->rmmio_remap.bus_addr || PAGE_SIZE > AMDGPU_GPU_PAGE_SIZE) return 0; + /* + * Allocate a BO first and then move it to AMDGPU_PL_MMIO_REMAP. + * The initial TTM resource assigned by amdgpu_bo_create() is + * replaced below with a fixed MMIO_REMAP placement. + */ memset(&bp, 0, sizeof(bp)); - - /* Create exactly one GEM BO in the MMIO_REMAP domain. */ - bp.type = ttm_bo_type_device; /* userspace-mappable GEM */ - bp.size = AMDGPU_GPU_PAGE_SIZE; /* 4K */ + bp.type = ttm_bo_type_device; + bp.size = AMDGPU_GPU_PAGE_SIZE; bp.byte_align = AMDGPU_GPU_PAGE_SIZE; - bp.domain = AMDGPU_GEM_DOMAIN_MMIO_REMAP; + bp.domain = 0; bp.flags = 0; bp.resv = NULL; bp.bo_ptr_size = sizeof(struct amdgpu_bo); - r = amdgpu_bo_create(adev, &bp, &adev->rmmio_remap.bo); if (r) return r; @@ -1953,42 +1956,60 @@ static int amdgpu_ttm_mmio_remap_bo_init(struct amdgpu_device *adev) if (r) goto err_unref; + tbo = &adev->rmmio_remap.bo->tbo; + /* * MMIO_REMAP is a fixed I/O placement (AMDGPU_PL_MMIO_REMAP). - * Use TTM-level pin so the BO cannot be evicted/migrated, - * independent of GEM domains. This - * enforces the “fixed I/O window” */ - ttm_bo_pin(&adev->rmmio_remap.bo->tbo); + placement.num_placement = 1; + placement.placement = &placements; + placements.fpfn = 0; + placements.lpfn = 0; + placements.mem_type = AMDGPU_PL_MMIO_REMAP; + placements.flags = 0; + /* Force the BO into the fixed MMIO_REMAP placement */ + r = ttm_bo_mem_space(tbo, &placement, &tmp, &ctx); + if (unlikely(r)) + goto err_unlock; + + ttm_resource_free(tbo, &tbo->resource); + ttm_bo_assign_mem(tbo, tmp); + ttm_bo_pin(tbo); amdgpu_bo_unreserve(adev->rmmio_remap.bo); return 0; +err_unlock: + amdgpu_bo_unreserve(adev->rmmio_remap.bo); + err_unref: - if (adev->rmmio_remap.bo) - amdgpu_bo_unref(&adev->rmmio_remap.bo); + amdgpu_bo_unref(&adev->rmmio_remap.bo); adev->rmmio_remap.bo = NULL; return r; } /** - * amdgpu_ttm_mmio_remap_bo_fini - Free the singleton MMIO_REMAP BO + * amdgpu_ttm_free_mmio_remap_bo - Free the singleton MMIO_REMAP BO * @adev: amdgpu device * * Frees the kernel-owned MMIO_REMAP BO if it was allocated by * amdgpu_ttm_mmio_remap_bo_init(). */ -static void amdgpu_ttm_mmio_remap_bo_fini(struct amdgpu_device *adev) +static void amdgpu_ttm_free_mmio_remap_bo(struct amdgpu_device *adev) { - struct amdgpu_bo *bo = adev->rmmio_remap.bo; - - if (!bo) - return; /* <-- safest early exit */ + if (!adev->rmmio_remap.bo) + return; if (!amdgpu_bo_reserve(adev->rmmio_remap.bo, true)) { ttm_bo_unpin(&adev->rmmio_remap.bo->tbo); amdgpu_bo_unreserve(adev->rmmio_remap.bo); } + + /* + * At this point we rely on normal DRM teardown ordering: + * no new user ioctls can access the global MMIO_REMAP BO + * once TTM teardown begins. + */ amdgpu_bo_unref(&adev->rmmio_remap.bo); adev->rmmio_remap.bo = NULL; } @@ -2172,8 +2193,8 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) return r; } - /* Allocate the singleton MMIO_REMAP BO (4K) if supported */ - r = amdgpu_ttm_mmio_remap_bo_init(adev); + /* Allocate the singleton MMIO_REMAP BO if supported */ + r = amdgpu_ttm_alloc_mmio_remap_bo(adev); if (r) return r; @@ -2241,7 +2262,7 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev) amdgpu_bo_free_kernel(&adev->mman.sdma_access_bo, NULL, &adev->mman.sdma_access_ptr); - amdgpu_ttm_mmio_remap_bo_fini(adev); + amdgpu_ttm_free_mmio_remap_bo(adev); amdgpu_ttm_fw_reserve_vram_fini(adev); amdgpu_ttm_drv_reserve_vram_fini(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index c5dd5815056c..c11ec5ab9cc1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -889,12 +889,28 @@ static int amdgpu_userq_input_args_validate(struct drm_device *dev, return 0; } +bool amdgpu_userq_enabled(struct drm_device *dev) +{ + struct amdgpu_device *adev = drm_to_adev(dev); + int i; + + for (i = 0; i < AMDGPU_HW_IP_NUM; i++) { + if (adev->userq_funcs[i]) + return true; + } + + return false; +} + int amdgpu_userq_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { union drm_amdgpu_userq *args = data; int r; + if (!amdgpu_userq_enabled(dev)) + return -ENOTSUPP; + if (amdgpu_userq_input_args_validate(dev, args, filp) < 0) return -EINVAL; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h index 1eaa94f8a291..95ace14e458c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h @@ -135,6 +135,7 @@ uint64_t amdgpu_userq_get_doorbell_index(struct amdgpu_userq_mgr *uq_mgr, struct drm_file *filp); u32 amdgpu_userq_get_supported_ip_mask(struct amdgpu_device *adev); +bool amdgpu_userq_enabled(struct drm_device *dev); int amdgpu_userq_suspend(struct amdgpu_device *adev); int amdgpu_userq_resume(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c index 25f178536469..8d7420a9a113 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c @@ -141,6 +141,8 @@ static void amdgpu_userq_walk_and_drop_fence_drv(struct xarray *xa) void amdgpu_userq_fence_driver_free(struct amdgpu_usermode_queue *userq) { + dma_fence_put(userq->last_fence); + amdgpu_userq_walk_and_drop_fence_drv(&userq->fence_drv_xa); xa_destroy(&userq->fence_drv_xa); /* Drop the fence_drv reference held by user queue */ @@ -474,6 +476,9 @@ int amdgpu_userq_signal_ioctl(struct drm_device *dev, void *data, struct drm_exec exec; u64 wptr; + if (!amdgpu_userq_enabled(dev)) + return -ENOTSUPP; + num_syncobj_handles = args->num_syncobj_handles; syncobj_handles = memdup_user(u64_to_user_ptr(args->syncobj_handles), size_mul(sizeof(u32), num_syncobj_handles)); @@ -656,6 +661,9 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data, int r, i, rentry, wentry, cnt; struct drm_exec exec; + if (!amdgpu_userq_enabled(dev)) + return -ENOTSUPP; + num_read_bo_handles = wait_info->num_bo_read_handles; bo_handles_read = memdup_user(u64_to_user_ptr(wait_info->bo_read_handles), size_mul(sizeof(u32), num_read_bo_handles)); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index f8eac92a2b36..f01f38509108 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -1262,6 +1262,7 @@ bool amdgpu_virt_fw_load_skip_check(struct amdgpu_device *adev, uint32_t ucode_i || ucode_id == AMDGPU_UCODE_ID_SDMA5 || ucode_id == AMDGPU_UCODE_ID_SDMA6 || ucode_id == AMDGPU_UCODE_ID_SDMA7 + || ucode_id == AMDGPU_UCODE_ID_SDMA_RS64 || ucode_id == AMDGPU_UCODE_ID_RLC_G || ucode_id == AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL || ucode_id == AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 0eccb31793ca..6a2ea200d90c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -1069,9 +1069,7 @@ amdgpu_vm_tlb_flush(struct amdgpu_vm_update_params *params, } /* Prepare a TLB flush fence to be attached to PTs */ - if (!params->unlocked && - /* SI doesn't support pasid or KIQ/MES */ - params->adev->family > AMDGPU_FAMILY_SI) { + if (!params->unlocked) { amdgpu_vm_tlb_fence_create(params->adev, vm, fence); /* Makes sure no PD/PT is freed before the flush */ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_debug.c b/drivers/gpu/drm/amd/amdkfd/kfd_debug.c index cd5a0b58c7d1..27176b2dc714 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_debug.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_debug.c @@ -357,8 +357,9 @@ int kfd_dbg_set_mes_debug_mode(struct kfd_process_device *pdd, bool sq_trap_en) return 0; if (!pdd->proc_ctx_cpu_ptr) { - r = amdgpu_amdkfd_alloc_gtt_mem(adev, + r = amdgpu_amdkfd_alloc_kernel_mem(adev, AMDGPU_MES_PROC_CTX_SIZE, + AMDGPU_GEM_DOMAIN_GTT, &pdd->proc_ctx_bo, &pdd->proc_ctx_gpu_addr, &pdd->proc_ctx_cpu_ptr, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index db37c2949d19..9a66ee661e57 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -820,12 +820,13 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, /* add another 512KB for all other allocations on gart (HPD, fences) */ size += 512 * 1024; - if (amdgpu_amdkfd_alloc_gtt_mem( - kfd->adev, size, &kfd->gtt_mem, + if (amdgpu_amdkfd_alloc_kernel_mem( + kfd->adev, size, AMDGPU_GEM_DOMAIN_GTT, + &kfd->gtt_mem, &kfd->gtt_start_gpu_addr, &kfd->gtt_start_cpu_ptr, false)) { dev_err(kfd_device, "Could not allocate %d bytes\n", size); - goto alloc_gtt_mem_failure; + goto alloc_kernel_mem_failure; } dev_info(kfd_device, "Allocated %d bytes on gart\n", size); @@ -951,8 +952,8 @@ node_alloc_error: kfd_doorbell_error: kfd_gtt_sa_fini(kfd); kfd_gtt_sa_init_error: - amdgpu_amdkfd_free_gtt_mem(kfd->adev, &kfd->gtt_mem); -alloc_gtt_mem_failure: + amdgpu_amdkfd_free_kernel_mem(kfd->adev, &kfd->gtt_mem); +alloc_kernel_mem_failure: dev_err(kfd_device, "device %x:%x NOT added due to errors\n", kfd->adev->pdev->vendor, kfd->adev->pdev->device); @@ -969,10 +970,13 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd) kfd_doorbell_fini(kfd); ida_destroy(&kfd->doorbell_ida); kfd_gtt_sa_fini(kfd); - amdgpu_amdkfd_free_gtt_mem(kfd->adev, &kfd->gtt_mem); + amdgpu_amdkfd_free_kernel_mem(kfd->adev, &kfd->gtt_mem); } kfree(kfd); + + /* after remove a kfd device unlock kfd driver */ + kgd2kfd_unlock_kfd(NULL); } int kgd2kfd_pre_reset(struct kfd_dev *kfd, @@ -1557,10 +1561,14 @@ out: return r; } +/* unlock a kfd dev or kfd driver */ void kgd2kfd_unlock_kfd(struct kfd_dev *kfd) { mutex_lock(&kfd_processes_mutex); - --kfd->kfd_dev_lock; + if (kfd) + --kfd->kfd_dev_lock; + else + --kfd_locked; mutex_unlock(&kfd_processes_mutex); } @@ -1729,6 +1737,73 @@ bool kgd2kfd_vmfault_fast_path(struct amdgpu_device *adev, struct amdgpu_iv_entr return false; } +/* check if there is kfd process still uses adev */ +static bool kgd2kfd_check_device_idle(struct amdgpu_device *adev) +{ + struct kfd_process *p; + struct hlist_node *p_temp; + unsigned int temp; + struct kfd_node *dev; + + mutex_lock(&kfd_processes_mutex); + + if (hash_empty(kfd_processes_table)) { + mutex_unlock(&kfd_processes_mutex); + return true; + } + + /* check if there is device still use adev */ + hash_for_each_safe(kfd_processes_table, temp, p_temp, p, kfd_processes) { + for (int i = 0; i < p->n_pdds; i++) { + dev = p->pdds[i]->dev; + if (dev->adev == adev) { + mutex_unlock(&kfd_processes_mutex); + return false; + } + } + } + + mutex_unlock(&kfd_processes_mutex); + + return true; +} + +/** kgd2kfd_teardown_processes - gracefully tear down existing + * kfd processes that use adev + * + * @adev: amdgpu_device where kfd processes run on and will be + * teardown + * + */ +void kgd2kfd_teardown_processes(struct amdgpu_device *adev) +{ + struct hlist_node *p_temp; + struct kfd_process *p; + struct kfd_node *dev; + unsigned int temp; + + mutex_lock(&kfd_processes_mutex); + + if (hash_empty(kfd_processes_table)) { + mutex_unlock(&kfd_processes_mutex); + return; + } + + hash_for_each_safe(kfd_processes_table, temp, p_temp, p, kfd_processes) { + for (int i = 0; i < p->n_pdds; i++) { + dev = p->pdds[i]->dev; + if (dev->adev == adev) + kfd_signal_process_terminate_event(p); + } + } + + mutex_unlock(&kfd_processes_mutex); + + /* wait all kfd processes use adev terminate */ + while (!kgd2kfd_check_device_idle(adev)) + cond_resched(); +} + #if defined(CONFIG_DEBUG_FS) /* This function will send a package to HIQ to hang the HWS diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index 9bc80f8ba7dc..b542de9d50d1 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -1211,14 +1211,8 @@ static int evict_process_queues_cpsch(struct device_queue_manager *dqm, pr_debug_ratelimited("Evicting process pid %d queues\n", pdd->process->lead_thread->pid); - if (dqm->dev->kfd->shared_resources.enable_mes) { + if (dqm->dev->kfd->shared_resources.enable_mes) pdd->last_evict_timestamp = get_jiffies_64(); - retval = suspend_all_queues_mes(dqm); - if (retval) { - dev_err(dev, "Suspending all queues failed"); - goto out; - } - } /* Mark all queues as evicted. Deactivate all active queues on * the qpd. @@ -1248,10 +1242,6 @@ static int evict_process_queues_cpsch(struct device_queue_manager *dqm, KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES : KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0, USE_DEFAULT_GRACE_PERIOD); - } else { - retval = resume_all_queues_mes(dqm); - if (retval) - dev_err(dev, "Resuming all queues failed"); } out: @@ -2909,13 +2899,22 @@ static int allocate_hiq_sdma_mqd(struct device_queue_manager *dqm) (dqm->mqd_mgrs[KFD_MQD_TYPE_HIQ]->mqd_size * NUM_XCC(dqm->dev->xcc_mask)); - retval = amdgpu_amdkfd_alloc_gtt_mem(dev->adev, size, - &(mem_obj->gtt_mem), &(mem_obj->gpu_addr), + retval = amdgpu_amdkfd_alloc_kernel_mem(dev->adev, size, + AMDGPU_GEM_DOMAIN_GTT, + &(mem_obj->mem), &(mem_obj->gpu_addr), (void *)&(mem_obj->cpu_ptr), false); return retval; } +static void deallocate_hiq_sdma_mqd(struct kfd_node *dev, + struct kfd_mem_obj *mqd) +{ + WARN(!mqd, "No hiq sdma mqd trunk to free"); + + amdgpu_amdkfd_free_kernel_mem(dev->adev, &mqd->mem); +} + struct device_queue_manager *device_queue_manager_init(struct kfd_node *dev) { struct device_queue_manager *dqm; @@ -3041,19 +3040,14 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_node *dev) return dqm; } + if (!dev->kfd->shared_resources.enable_mes) + deallocate_hiq_sdma_mqd(dev, &dqm->hiq_sdma_mqd); + out_free: kfree(dqm); return NULL; } -static void deallocate_hiq_sdma_mqd(struct kfd_node *dev, - struct kfd_mem_obj *mqd) -{ - WARN(!mqd, "No hiq sdma mqd trunk to free"); - - amdgpu_amdkfd_free_gtt_mem(dev->adev, &mqd->gtt_mem); -} - void device_queue_manager_uninit(struct device_queue_manager *dqm) { dqm->ops.stop(dqm); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c index 5a190dd6be4e..1ad312af8ff0 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c @@ -1380,3 +1380,32 @@ void kfd_signal_poison_consumed_event(struct kfd_node *dev, u32 pasid) kfd_unref_process(p); } + +/* signal KFD_EVENT_TYPE_SIGNAL events from process p + * send signal SIGBUS to correspondent user space process + */ +void kfd_signal_process_terminate_event(struct kfd_process *p) +{ + struct kfd_event *ev; + u32 id; + + rcu_read_lock(); + + /* iterate from id 1 for KFD_EVENT_TYPE_SIGNAL events */ + id = 1; + idr_for_each_entry_continue(&p->event_idr, ev, id) + if (ev->type == KFD_EVENT_TYPE_SIGNAL) { + spin_lock(&ev->lock); + set_event(ev); + spin_unlock(&ev->lock); + } + + /* Send SIGBUS to p->lead_thread */ + dev_notice(kfd_device, + "Sending SIGBUS to process %d", + p->lead_thread->pid); + + send_sig(SIGBUS, p->lead_thread, 0); + + rcu_read_unlock(); +} diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c index 557a5ade329a..e8da0b4527dc 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c @@ -342,7 +342,7 @@ static void kfd_init_apertures_vi(struct kfd_process_device *pdd, uint8_t id) static void kfd_init_apertures_v9(struct kfd_process_device *pdd, uint8_t id) { - if (pdd->dev->adev->vm_manager.root_level == AMDGPU_VM_PDB3) + if (KFD_GC_VERSION(pdd->dev) >= IP_VERSION(12, 1, 0)) pdd->lds_base = pdd->dev->adev->gmc.shared_aperture_start; else pdd->lds_base = MAKE_LDS_APP_BASE_V9(); @@ -352,7 +352,7 @@ static void kfd_init_apertures_v9(struct kfd_process_device *pdd, uint8_t id) pdd->gpuvm_limit = pdd->dev->kfd->shared_resources.gpuvm_size - 1; - if (pdd->dev->adev->vm_manager.root_level == AMDGPU_VM_PDB3) + if (KFD_GC_VERSION(pdd->dev) >= IP_VERSION(12, 1, 0)) pdd->scratch_base = pdd->dev->adev->gmc.private_aperture_start; else pdd->scratch_base = MAKE_SCRATCH_APP_BASE_V9(); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index a3b1722108b7..7a8990b30fa0 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -63,7 +63,7 @@ svm_migrate_gart_map(struct amdgpu_ring *ring, *gart_addr = adev->gmc.gart_start; num_dw = ALIGN(adev->mman.buffer_funcs->copy_num_dw, 8); - num_bytes = npages * 8; + num_bytes = npages * 8 * AMDGPU_GPU_PAGES_IN_CPU_PAGE; r = amdgpu_job_alloc_with_ib(adev, &entity->base, AMDGPU_FENCE_OWNER_UNDEFINED, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c index d9ae854b6908..f78b249e1a41 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c @@ -54,7 +54,7 @@ struct kfd_mem_obj *allocate_hiq_mqd(struct kfd_node *dev, struct queue_properti if (!mqd_mem_obj) return NULL; - mqd_mem_obj->gtt_mem = dev->dqm->hiq_sdma_mqd.gtt_mem; + mqd_mem_obj->mem = dev->dqm->hiq_sdma_mqd.mem; mqd_mem_obj->gpu_addr = dev->dqm->hiq_sdma_mqd.gpu_addr; mqd_mem_obj->cpu_ptr = dev->dqm->hiq_sdma_mqd.cpu_ptr; @@ -79,7 +79,7 @@ struct kfd_mem_obj *allocate_sdma_mqd(struct kfd_node *dev, offset += dev->dqm->mqd_mgrs[KFD_MQD_TYPE_HIQ]->mqd_size * NUM_XCC(dev->xcc_mask); - mqd_mem_obj->gtt_mem = (void *)((uint64_t)dev->dqm->hiq_sdma_mqd.gtt_mem + mqd_mem_obj->mem = (void *)((uint64_t)dev->dqm->hiq_sdma_mqd.mem + offset); mqd_mem_obj->gpu_addr = dev->dqm->hiq_sdma_mqd.gpu_addr + offset; mqd_mem_obj->cpu_ptr = (uint32_t *)((uint64_t) @@ -91,7 +91,7 @@ struct kfd_mem_obj *allocate_sdma_mqd(struct kfd_node *dev, void free_mqd_hiq_sdma(struct mqd_manager *mm, void *mqd, struct kfd_mem_obj *mqd_mem_obj) { - WARN_ON(!mqd_mem_obj->gtt_mem); + WARN_ON(!mqd_mem_obj->mem); kfree(mqd_mem_obj); } @@ -224,8 +224,8 @@ int kfd_destroy_mqd_cp(struct mqd_manager *mm, void *mqd, void kfd_free_mqd_cp(struct mqd_manager *mm, void *mqd, struct kfd_mem_obj *mqd_mem_obj) { - if (mqd_mem_obj->gtt_mem) { - amdgpu_amdkfd_free_gtt_mem(mm->dev->adev, &mqd_mem_obj->gtt_mem); + if (mqd_mem_obj->mem) { + amdgpu_amdkfd_free_kernel_mem(mm->dev->adev, &mqd_mem_obj->mem); kfree(mqd_mem_obj); } else { kfd_gtt_sa_free(mm->dev, mqd_mem_obj); @@ -280,8 +280,8 @@ void kfd_get_hiq_xcc_mqd(struct kfd_node *dev, struct kfd_mem_obj *mqd_mem_obj, offset = kfd_hiq_mqd_stride(dev) * virtual_xcc_id; - mqd_mem_obj->gtt_mem = (virtual_xcc_id == 0) ? - dev->dqm->hiq_sdma_mqd.gtt_mem : NULL; + mqd_mem_obj->mem = (virtual_xcc_id == 0) ? + dev->dqm->hiq_sdma_mqd.mem : NULL; mqd_mem_obj->gpu_addr = dev->dqm->hiq_sdma_mqd.gpu_addr + offset; mqd_mem_obj->cpu_ptr = (uint32_t *)((uintptr_t) dev->dqm->hiq_sdma_mqd.cpu_ptr + offset); 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 a06b4e89af8a..558216395a4d 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 @@ -454,8 +454,8 @@ static void get_xcc_mqd(struct kfd_mem_obj *mqd_mem_obj, struct kfd_mem_obj *xcc_mqd_mem_obj, uint64_t offset) { - xcc_mqd_mem_obj->gtt_mem = (offset == 0) ? - mqd_mem_obj->gtt_mem : NULL; + xcc_mqd_mem_obj->mem = (offset == 0) ? + mqd_mem_obj->mem : NULL; xcc_mqd_mem_obj->gpu_addr = mqd_mem_obj->gpu_addr + offset; xcc_mqd_mem_obj->cpu_ptr = (uint32_t *)((uintptr_t)mqd_mem_obj->cpu_ptr + offset); 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 2e9b6bcf2704..d234db138182 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c @@ -135,11 +135,12 @@ static struct kfd_mem_obj *allocate_mqd(struct kfd_node *node, mqd_mem_obj = kzalloc(sizeof(struct kfd_mem_obj), GFP_KERNEL); if (!mqd_mem_obj) return NULL; - retval = amdgpu_amdkfd_alloc_gtt_mem(node->adev, + retval = amdgpu_amdkfd_alloc_kernel_mem(node->adev, (ALIGN(q->ctl_stack_size, PAGE_SIZE) + ALIGN(sizeof(struct v9_mqd), PAGE_SIZE)) * NUM_XCC(node->xcc_mask), - &(mqd_mem_obj->gtt_mem), + AMDGPU_GEM_DOMAIN_GTT, + &(mqd_mem_obj->mem), &(mqd_mem_obj->gpu_addr), (void *)&(mqd_mem_obj->cpu_ptr), true); @@ -665,8 +666,8 @@ static void get_xcc_mqd(struct kfd_mem_obj *mqd_mem_obj, struct kfd_mem_obj *xcc_mqd_mem_obj, uint64_t offset) { - xcc_mqd_mem_obj->gtt_mem = (offset == 0) ? - mqd_mem_obj->gtt_mem : NULL; + xcc_mqd_mem_obj->mem = (offset == 0) ? + mqd_mem_obj->mem : NULL; xcc_mqd_mem_obj->gpu_addr = mqd_mem_obj->gpu_addr + offset; xcc_mqd_mem_obj->cpu_ptr = (uint32_t *)((uintptr_t)mqd_mem_obj->cpu_ptr + offset); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index d798baa7e52e..9849b54f54ba 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -252,7 +252,7 @@ struct kfd_mem_obj { uint32_t range_end; uint64_t gpu_addr; uint32_t *cpu_ptr; - void *gtt_mem; + void *mem; }; struct kfd_vmid_info { @@ -1192,6 +1192,7 @@ static inline struct kfd_node *kfd_node_by_irq_ids(struct amdgpu_device *adev, } int kfd_topology_enum_kfd_devices(uint8_t idx, struct kfd_node **kdev); int kfd_numa_node_to_apic_id(int numa_node_id); +uint32_t kfd_gpu_node_num(void); /* Interrupts */ #define KFD_IRQ_FENCE_CLIENTID 0xff @@ -1547,6 +1548,7 @@ void kfd_signal_vm_fault_event(struct kfd_process_device *pdd, void kfd_signal_reset_event(struct kfd_node *dev); void kfd_signal_poison_consumed_event(struct kfd_node *dev, u32 pasid); +void kfd_signal_process_terminate_event(struct kfd_process *p); static inline void kfd_flush_tlb(struct kfd_process_device *pdd, enum TLB_FLUSH_TYPE type) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index 1a77fa2deeb7..ba25d83c23e7 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -949,6 +949,12 @@ struct kfd_process *kfd_create_process(struct task_struct *thread) */ mutex_lock(&kfd_processes_mutex); + if (kfd_gpu_node_num() <= 0) { + pr_warn("no gpu node! Cannot create KFD process"); + process = ERR_PTR(-EINVAL); + goto out; + } + if (kfd_is_locked(NULL)) { pr_debug("KFD is locked! Cannot create process"); process = ERR_PTR(-EINVAL); @@ -1131,7 +1137,7 @@ static void kfd_process_destroy_pdds(struct kfd_process *p) if (pdd->dev->kfd->shared_resources.enable_mes && pdd->proc_ctx_cpu_ptr) - amdgpu_amdkfd_free_gtt_mem(pdd->dev->adev, + amdgpu_amdkfd_free_kernel_mem(pdd->dev->adev, &pdd->proc_ctx_bo); /* * before destroying pdd, make sure to report availability @@ -1235,7 +1241,6 @@ static void kfd_process_wq_release(struct work_struct *work) else ida_destroy(&p->id_table); - kfd_process_remove_sysfs(p); kfd_debugfs_remove_process(p); kfd_process_kunmap_signal_bo(p); @@ -1251,6 +1256,11 @@ static void kfd_process_wq_release(struct work_struct *work) put_task_struct(p->lead_thread); + /* the last step is removing process entries under /sys + * to indicate the process has been terminated. + */ + kfd_process_remove_sysfs(p); + kfree(p); } 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 a399770aa411..449be58e884c 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c @@ -210,8 +210,8 @@ static void pqm_clean_queue_resource(struct process_queue_manager *pqm, } if (dev->kfd->shared_resources.enable_mes) { - amdgpu_amdkfd_free_gtt_mem(dev->adev, &pqn->q->gang_ctx_bo); - amdgpu_amdkfd_free_gtt_mem(dev->adev, (void **)&pqn->q->wptr_bo_gart); + amdgpu_amdkfd_free_kernel_mem(dev->adev, &pqn->q->gang_ctx_bo); + amdgpu_amdkfd_free_kernel_mem(dev->adev, (void **)&pqn->q->wptr_bo_gart); } } @@ -265,8 +265,9 @@ static int init_user_queue(struct process_queue_manager *pqm, (*q)->process = pqm->process; if (dev->kfd->shared_resources.enable_mes) { - retval = amdgpu_amdkfd_alloc_gtt_mem(dev->adev, + retval = amdgpu_amdkfd_alloc_kernel_mem(dev->adev, AMDGPU_MES_GANG_CTX_SIZE, + AMDGPU_GEM_DOMAIN_GTT, &(*q)->gang_ctx_bo, &(*q)->gang_ctx_gpu_addr, &(*q)->gang_ctx_cpu_ptr, @@ -298,7 +299,7 @@ static int init_user_queue(struct process_queue_manager *pqm, return 0; free_gang_ctx_bo: - amdgpu_amdkfd_free_gtt_mem(dev->adev, &(*q)->gang_ctx_bo); + amdgpu_amdkfd_free_kernel_mem(dev->adev, &(*q)->gang_ctx_bo); cleanup: uninit_queue(*q); *q = NULL; @@ -368,8 +369,9 @@ int pqm_create_queue(struct process_queue_manager *pqm, /* Allocate proc_ctx_bo only if MES is enabled and this is the first queue */ if (!pdd->proc_ctx_cpu_ptr && dev->kfd->shared_resources.enable_mes) { - retval = amdgpu_amdkfd_alloc_gtt_mem(dev->adev, + retval = amdgpu_amdkfd_alloc_kernel_mem(dev->adev, AMDGPU_MES_PROC_CTX_SIZE, + AMDGPU_GEM_DOMAIN_GTT, &pdd->proc_ctx_bo, &pdd->proc_ctx_gpu_addr, &pdd->proc_ctx_cpu_ptr, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c index 1b465fdb2c64..d1978e3f68be 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c @@ -278,8 +278,8 @@ int kfd_queue_acquire_buffers(struct kfd_process_device *pdd, struct queue_prope /* EOP buffer is not required for all ASICs */ if (properties->eop_ring_buffer_address) { - if (properties->eop_ring_buffer_size != topo_dev->node_props.eop_buffer_size) { - pr_debug("queue eop bo size 0x%x not equal to node eop buf size 0x%x\n", + if (properties->eop_ring_buffer_size < topo_dev->node_props.eop_buffer_size) { + pr_debug("queue eop bo size 0x%x is less than node eop buf size 0x%x\n", properties->eop_ring_buffer_size, topo_dev->node_props.eop_buffer_size); err = -EINVAL; @@ -287,7 +287,7 @@ int kfd_queue_acquire_buffers(struct kfd_process_device *pdd, struct queue_prope } err = kfd_queue_buffer_get(vm, (void *)properties->eop_ring_buffer_address, &properties->eop_buf_bo, - properties->eop_ring_buffer_size); + ALIGN(properties->eop_ring_buffer_size, PAGE_SIZE)); if (err) goto out_err_unreserve; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 1ed08388d364..35036d47657b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -1355,11 +1355,16 @@ svm_range_unmap_from_gpu(struct amdgpu_device *adev, struct amdgpu_vm *vm, struct dma_fence **fence) { uint64_t init_pte_value = adev->gmc.init_pte_flags; + uint64_t gpu_start, gpu_end; - pr_debug("[0x%llx 0x%llx]\n", start, last); + /* Convert CPU page range to GPU page range */ + gpu_start = start * AMDGPU_GPU_PAGES_IN_CPU_PAGE; + gpu_end = (last + 1) * AMDGPU_GPU_PAGES_IN_CPU_PAGE - 1; - return amdgpu_vm_update_range(adev, vm, false, true, true, false, NULL, start, - last, init_pte_value, 0, 0, NULL, NULL, + pr_debug("CPU[0x%llx 0x%llx] -> GPU[0x%llx 0x%llx]\n", start, last, + gpu_start, gpu_end); + return amdgpu_vm_update_range(adev, vm, false, true, true, false, NULL, gpu_start, + gpu_end, init_pte_value, 0, 0, NULL, NULL, fence); } @@ -1439,6 +1444,9 @@ svm_range_map_to_gpu(struct kfd_process_device *pdd, struct svm_range *prange, last_start, last_start + npages - 1, readonly); for (i = offset; i < offset + npages; i++) { + uint64_t gpu_start; + uint64_t gpu_end; + last_domain = dma_addr[i] & SVM_RANGE_VRAM_DOMAIN; dma_addr[i] &= ~SVM_RANGE_VRAM_DOMAIN; @@ -1456,17 +1464,22 @@ svm_range_map_to_gpu(struct kfd_process_device *pdd, struct svm_range *prange, if (readonly) pte_flags &= ~AMDGPU_PTE_WRITEABLE; - pr_debug("svms 0x%p map [0x%lx 0x%llx] vram %d PTE 0x%llx\n", - prange->svms, last_start, prange->start + i, - (last_domain == SVM_RANGE_VRAM_DOMAIN) ? 1 : 0, - pte_flags); /* For dGPU mode, we use same vm_manager to allocate VRAM for * different memory partition based on fpfn/lpfn, we should use * same vm_manager.vram_base_offset regardless memory partition. */ + gpu_start = last_start * AMDGPU_GPU_PAGES_IN_CPU_PAGE; + gpu_end = (prange->start + i + 1) * AMDGPU_GPU_PAGES_IN_CPU_PAGE - 1; + + pr_debug("svms 0x%p map CPU[0x%lx 0x%llx] GPU[0x%llx 0x%llx] vram %d PTE 0x%llx\n", + prange->svms, last_start, prange->start + i, + gpu_start, gpu_end, + (last_domain == SVM_RANGE_VRAM_DOMAIN) ? 1 : 0, + pte_flags); + r = amdgpu_vm_update_range(adev, vm, false, false, flush_tlb, true, - NULL, last_start, prange->start + i, + NULL, gpu_start, gpu_end, pte_flags, (last_start - prange->start) << PAGE_SHIFT, bo_adev ? bo_adev->vm_manager.vram_base_offset : 0, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index 005a19602513..1ccd4514d3ee 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -2357,6 +2357,28 @@ int kfd_numa_node_to_apic_id(int numa_node_id) return kfd_cpumask_to_apic_id(cpumask_of_node(numa_node_id)); } +/* kfd_gpu_node_num - Return kfd gpu node number at system */ +uint32_t kfd_gpu_node_num(void) +{ + struct kfd_node *dev; + u8 gpu_num = 0; + u8 id = 0; + + while (kfd_topology_enum_kfd_devices(id, &dev) == 0) { + if (!dev || kfd_devcgroup_check_permission(dev)) { + /* Skip non GPU devices and devices to which the + * current process have no access to + */ + id++; + continue; + } + id++; + gpu_num++; + } + + return gpu_num; +} + #if defined(CONFIG_DEBUG_FS) int kfd_debugfs_hqds_by_device(struct seq_file *m, void *data) 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 06b97029001b..cb13a2b0de62 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1137,7 +1137,7 @@ static int amdgpu_dm_audio_component_get_eld(struct device *kdev, int port, mutex_unlock(&adev->dm.audio_lock); - DRM_DEBUG_KMS("Get ELD : idx=%d ret=%d en=%d\n", port, ret, *enabled); + drm_dbg_kms(adev_to_drm(adev), "Get ELD : idx=%d ret=%d en=%d\n", port, ret, *enabled); return ret; } @@ -1231,7 +1231,7 @@ static void amdgpu_dm_audio_eld_notify(struct amdgpu_device *adev, int pin) struct drm_audio_component *acomp = adev->dm.audio_component; if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) { - DRM_DEBUG_KMS("Notify ELD: %d\n", pin); + drm_dbg_kms(adev_to_drm(adev), "Notify ELD: %d\n", pin); acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, pin, -1); @@ -2377,7 +2377,7 @@ static int load_dmcu_fw(struct amdgpu_device *adev) } if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) { - DRM_DEBUG_KMS("dm: DMCU firmware not supported on direct or SMU loading\n"); + drm_dbg_kms(adev_to_drm(adev), "dm: DMCU firmware not supported on direct or SMU loading\n"); return 0; } @@ -2385,7 +2385,7 @@ static int load_dmcu_fw(struct amdgpu_device *adev) "%s", fw_name_dmcu); if (r == -ENODEV) { /* DMCU firmware is not necessary, so don't raise a fuss if it's missing */ - DRM_DEBUG_KMS("dm: DMCU firmware not found\n"); + drm_dbg_kms(adev_to_drm(adev), "dm: DMCU firmware not found\n"); adev->dm.fw_dmcu = NULL; return 0; } @@ -2409,7 +2409,7 @@ static int load_dmcu_fw(struct amdgpu_device *adev) adev->dm.dmcu_fw_version = le32_to_cpu(hdr->header.ucode_version); - DRM_DEBUG_KMS("PSP loading DMCU firmware\n"); + drm_dbg_kms(adev_to_drm(adev), "PSP loading DMCU firmware\n"); return 0; } @@ -4157,7 +4157,7 @@ static void schedule_hpd_rx_offload_work(struct amdgpu_device *adev, struct hpd_ offload_work->adev = adev; queue_work(offload_wq->wq, &offload_work->work); - DRM_DEBUG_KMS("queue work to handle hpd_rx offload work"); + drm_dbg_kms(adev_to_drm(adev), "queue work to handle hpd_rx offload work"); } static void handle_hpd_rx_irq(void *param) @@ -4986,7 +4986,7 @@ static void amdgpu_dm_update_backlight_caps(struct amdgpu_display_manager *dm, caps->min_input_signal < 0 || spread > AMDGPU_DM_DEFAULT_MAX_BACKLIGHT || spread < AMDGPU_DM_MIN_SPREAD) { - DRM_DEBUG_KMS("DM: Invalid backlight caps: min=%d, max=%d\n", + drm_dbg_kms(adev_to_drm(dm->adev), "DM: Invalid backlight caps: min=%d, max=%d\n", caps->min_input_signal, caps->max_input_signal); caps->caps_valid = false; } @@ -5279,6 +5279,8 @@ amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector) struct amdgpu_dm_backlight_caps *caps; char bl_name[16]; int min, max; + int real_brightness; + int init_brightness; if (aconnector->bl_idx == -1) return; @@ -5303,6 +5305,8 @@ amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector) } else props.brightness = props.max_brightness = MAX_BACKLIGHT_LEVEL; + init_brightness = props.brightness; + if (caps->data_points && !(amdgpu_dc_debug_mask & DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE)) { drm_info(drm, "Using custom brightness curve\n"); props.scale = BACKLIGHT_SCALE_NON_LINEAR; @@ -5321,8 +5325,20 @@ amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector) if (IS_ERR(dm->backlight_dev[aconnector->bl_idx])) { drm_err(drm, "DM: Backlight registration failed!\n"); dm->backlight_dev[aconnector->bl_idx] = NULL; - } else + } else { + /* + * dm->brightness[x] can be inconsistent just after startup until + * ops.get_brightness is called. + */ + real_brightness = + amdgpu_dm_backlight_ops.get_brightness(dm->backlight_dev[aconnector->bl_idx]); + + if (real_brightness != init_brightness) { + dm->actual_brightness[aconnector->bl_idx] = real_brightness; + dm->brightness[aconnector->bl_idx] = real_brightness; + } drm_dbg_driver(drm, "DM: Registered Backlight device: %s\n", bl_name); + } } static int initialize_plane(struct amdgpu_display_manager *dm, @@ -5515,7 +5531,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) } break; default: - DRM_DEBUG_KMS("Unsupported DCN IP version for outbox: 0x%X\n", + drm_dbg_kms(adev_to_drm(adev), "Unsupported DCN IP version for outbox: 0x%X\n", amdgpu_ip_version(adev, DCE_HWIP, 0)); } @@ -5639,7 +5655,8 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) if (psr_feature_enabled) { amdgpu_dm_set_psr_caps(link); - drm_info(adev_to_drm(adev), "PSR support %d, DC PSR ver %d, sink PSR ver %d DPCD caps 0x%x su_y_granularity %d\n", + drm_info(adev_to_drm(adev), "%s: PSR support %d, DC PSR ver %d, sink PSR ver %d DPCD caps 0x%x su_y_granularity %d\n", + aconnector->base.name, link->psr_settings.psr_feature_enabled, link->psr_settings.psr_version, link->dpcd_caps.psr_info.psr_version, @@ -6417,7 +6434,8 @@ ffu: &flip_addrs->dirty_rect_count, true); } -static void update_stream_scaling_settings(const struct drm_display_mode *mode, +static void update_stream_scaling_settings(struct drm_device *dev, + const struct drm_display_mode *mode, const struct dm_connector_state *dm_state, struct dc_stream_state *stream) { @@ -6467,8 +6485,8 @@ static void update_stream_scaling_settings(const struct drm_display_mode *mode, stream->src = src; stream->dst = dst; - DRM_DEBUG_KMS("Destination Rectangle x:%d y:%d width:%d height:%d\n", - dst.x, dst.y, dst.width, dst.height); + drm_dbg_kms(dev, "Destination Rectangle x:%d y:%d width:%d height:%d\n", + dst.x, dst.y, dst.width, dst.height); } @@ -7356,7 +7374,7 @@ create_stream_for_sink(struct drm_connector *connector, apply_dsc_policy_for_stream(aconnector, sink, stream, &dsc_caps); #endif - update_stream_scaling_settings(&mode, dm_state, stream); + update_stream_scaling_settings(dev, &mode, dm_state, stream); fill_audio_info( &stream->audio_info, @@ -8091,7 +8109,7 @@ create_validate_stream_for_sink(struct drm_connector *connector, dc_result = dm_validate_stream_and_context(adev->dm.dc, stream); if (dc_result != DC_OK) { - DRM_DEBUG_KMS("Pruned mode %d x %d (clk %d) %s %s -- %s\n", + drm_dbg_kms(connector->dev, "Pruned mode %d x %d (clk %d) %s %s -- %s\n", drm_mode->hdisplay, drm_mode->vdisplay, drm_mode->clock, @@ -8443,7 +8461,7 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder, drm_dp_atomic_find_time_slots(state, mst_mgr, mst_port, dm_new_connector_state->pbn); if (dm_new_connector_state->vcpi_slots < 0) { - DRM_DEBUG_ATOMIC("failed finding vcpi slots: %d\n", (int)dm_new_connector_state->vcpi_slots); + drm_dbg_atomic(connector->dev, "failed finding vcpi slots: %d\n", (int)dm_new_connector_state->vcpi_slots); return dm_new_connector_state->vcpi_slots; } return 0; @@ -8943,9 +8961,18 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm, mutex_init(&aconnector->hpd_lock); mutex_init(&aconnector->handle_mst_msg_ready); - aconnector->hdmi_hpd_debounce_delay_ms = AMDGPU_DM_HDMI_HPD_DEBOUNCE_MS; - INIT_DELAYED_WORK(&aconnector->hdmi_hpd_debounce_work, hdmi_hpd_debounce_work); - aconnector->hdmi_prev_sink = NULL; + /* + * If HDMI HPD debounce delay is set, use the minimum between selected + * value and AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS + */ + if (amdgpu_hdmi_hpd_debounce_delay_ms) { + aconnector->hdmi_hpd_debounce_delay_ms = min(amdgpu_hdmi_hpd_debounce_delay_ms, + AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS); + INIT_DELAYED_WORK(&aconnector->hdmi_hpd_debounce_work, hdmi_hpd_debounce_work); + aconnector->hdmi_prev_sink = NULL; + } else { + aconnector->hdmi_hpd_debounce_delay_ms = 0; + } /* * configure support HPD hot plug connector_>polled default value is 0 @@ -9627,7 +9654,7 @@ static void update_freesync_state_on_stream( new_stream->allow_freesync = mod_freesync_get_freesync_enabled(&vrr_params); if (new_crtc_state->freesync_vrr_info_changed) - DRM_DEBUG_KMS("VRR packet update: crtc=%u enabled=%d state=%d", + drm_dbg_kms(adev_to_drm(adev), "VRR packet update: crtc=%u enabled=%d state=%d", new_crtc_state->base.crtc->base.id, (int)new_crtc_state->base.vrr_enabled, (int)vrr_params.state); @@ -10893,7 +10920,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) stream_update.stream = dm_new_crtc_state->stream; if (scaling_changed) { - update_stream_scaling_settings(&dm_new_con_state->base.crtc->mode, + update_stream_scaling_settings(dev, &dm_new_con_state->base.crtc->mode, dm_new_con_state, dm_new_crtc_state->stream); stream_update.src = dm_new_crtc_state->stream->src; @@ -11573,7 +11600,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, dc_stream_retain(new_stream); - DRM_DEBUG_ATOMIC("Enabling DRM crtc: %d\n", + drm_dbg_atomic(adev_to_drm(adev), "Enabling DRM crtc: %d\n", crtc->base.id); if (dc_state_add_stream( @@ -11612,7 +11639,7 @@ skip_modeset: /* Scaling or underscan settings */ if (is_scaling_state_different(dm_old_conn_state, dm_new_conn_state) || drm_atomic_crtc_needs_modeset(new_crtc_state)) - update_stream_scaling_settings( + update_stream_scaling_settings(adev_to_drm(adev), &new_crtc_state->mode, dm_new_conn_state, dm_new_crtc_state->stream); /* ABM settings */ @@ -11803,14 +11830,14 @@ static int dm_check_cursor_fb(struct amdgpu_crtc *new_acrtc, if (fb->width > new_acrtc->max_cursor_width || fb->height > new_acrtc->max_cursor_height) { - DRM_DEBUG_ATOMIC("Bad cursor FB size %dx%d\n", + drm_dbg_atomic(adev_to_drm(adev), "Bad cursor FB size %dx%d\n", new_plane_state->fb->width, new_plane_state->fb->height); return -EINVAL; } if (new_plane_state->src_w != fb->width << 16 || new_plane_state->src_h != fb->height << 16) { - DRM_DEBUG_ATOMIC("Cropping not supported for cursor plane\n"); + drm_dbg_atomic(adev_to_drm(adev), "Cropping not supported for cursor plane\n"); return -EINVAL; } @@ -11818,7 +11845,7 @@ static int dm_check_cursor_fb(struct amdgpu_crtc *new_acrtc, pitch = fb->pitches[0] / fb->format->cpp[0]; if (fb->width != pitch) { - DRM_DEBUG_ATOMIC("Cursor FB width %d doesn't match pitch %d", + drm_dbg_atomic(adev_to_drm(adev), "Cursor FB width %d doesn't match pitch %d", fb->width, pitch); return -EINVAL; } @@ -11830,7 +11857,7 @@ static int dm_check_cursor_fb(struct amdgpu_crtc *new_acrtc, /* FB pitch is supported by cursor plane */ break; default: - DRM_DEBUG_ATOMIC("Bad cursor FB pitch %d px\n", pitch); + drm_dbg_atomic(adev_to_drm(adev), "Bad cursor FB pitch %d px\n", pitch); return -EINVAL; } @@ -11848,7 +11875,7 @@ static int dm_check_cursor_fb(struct amdgpu_crtc *new_acrtc, AMDGPU_TILING_GET(afb->tiling_flags, MICRO_TILE_MODE) == 0; } if (!linear) { - DRM_DEBUG_ATOMIC("Cursor FB not linear"); + drm_dbg_atomic(adev_to_drm(adev), "Cursor FB not linear"); return -EINVAL; } } @@ -11875,7 +11902,7 @@ static int dm_check_native_cursor_state(struct drm_crtc *new_plane_crtc, new_acrtc = to_amdgpu_crtc(new_plane_crtc); if (new_plane_state->src_x != 0 || new_plane_state->src_y != 0) { - DRM_DEBUG_ATOMIC("Cropping not supported for cursor plane\n"); + drm_dbg_atomic(new_plane_crtc->dev, "Cropping not supported for cursor plane\n"); return -EINVAL; } @@ -11974,7 +12001,7 @@ static int dm_update_plane_state(struct dc *dc, if (!dm_old_crtc_state->stream) return 0; - DRM_DEBUG_ATOMIC("Disabling DRM plane: %d on DRM crtc %d\n", + drm_dbg_atomic(old_plane_crtc->dev, "Disabling DRM plane: %d on DRM crtc %d\n", plane->base.id, old_plane_crtc->base.id); ret = dm_atomic_get_state(state, &dm_state); @@ -12027,7 +12054,7 @@ static int dm_update_plane_state(struct dc *dc, goto out; } - DRM_DEBUG_ATOMIC("Enabling DRM plane: %d on DRM crtc %d\n", + drm_dbg_atomic(new_plane_crtc->dev, "Enabling DRM plane: %d on DRM crtc %d\n", plane->base.id, new_plane_crtc->base.id); ret = fill_dc_plane_attributes( @@ -13119,7 +13146,7 @@ static int parse_amd_vsdb(struct amdgpu_dm_connector *aconnector, amd_vsdb->version == HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_VERSION_3) { vsdb_info->replay_mode = (amd_vsdb->feature_caps & AMD_VSDB_VERSION_3_FEATURECAP_REPLAYMODE) ? true : false; vsdb_info->amd_vsdb_version = HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_VERSION_3; - DRM_DEBUG_KMS("Panel supports Replay Mode: %d\n", vsdb_info->replay_mode); + drm_dbg_kms(aconnector->base.dev, "Panel supports Replay Mode: %d\n", vsdb_info->replay_mode); return true; } 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 ab363f2f6d47..115efd8ec68b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -59,7 +59,10 @@ #define AMDGPU_HDR_MULT_DEFAULT (0x100000000LL) -#define AMDGPU_DM_HDMI_HPD_DEBOUNCE_MS 1500 +/* + * Maximum HDMI HPD debounce delay in milliseconds + */ +#define AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS 5000 /* #include "include/amdgpu_dal_power_if.h" #include "amdgpu_dm_irq.h" @@ -815,6 +818,7 @@ struct amdgpu_dm_connector { int sr_skip_count; bool disallow_edp_enter_psr; + bool disallow_edp_enter_replay; /* Record progress status of mst*/ uint8_t mst_status; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c index 327b20055729..5851f2d55dde 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c @@ -32,6 +32,7 @@ #include "dc.h" #include "amdgpu_securedisplay.h" #include "amdgpu_dm_psr.h" +#include "amdgpu_dm_replay.h" static const char *const pipe_crc_sources[] = { "none", @@ -502,6 +503,7 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc, { struct amdgpu_device *adev = drm_to_adev(crtc->dev); struct dc_stream_state *stream_state = dm_crtc_state->stream; + struct amdgpu_dm_connector *aconnector = NULL; bool enable = amdgpu_dm_is_valid_crc_source(source); int ret = 0; @@ -509,11 +511,22 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc, if (!stream_state) return -EINVAL; + /* Get connector from stream */ + aconnector = (struct amdgpu_dm_connector *)stream_state->dm_stream_context; + mutex_lock(&adev->dm.dc_lock); - /* For PSR1, check that the panel has exited PSR */ - if (stream_state->link->psr_settings.psr_version < DC_PSR_VERSION_SU_1) - amdgpu_dm_psr_wait_disable(stream_state); + + if (enable) { + /* For PSR1, check that the panel has exited PSR */ + if (stream_state->link->psr_settings.psr_version < DC_PSR_VERSION_SU_1) + amdgpu_dm_psr_wait_disable(stream_state); + + /* Set flag to disallow enter replay when CRC source is enabled */ + if (aconnector) + aconnector->disallow_edp_enter_replay = true; + amdgpu_dm_replay_disable(stream_state); + } /* Enable or disable CRTC CRC generation */ if (dm_is_crc_source_crtc(source) || source == AMDGPU_DM_PIPE_CRC_SOURCE_NONE) { @@ -536,6 +549,12 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc, DYN_EXPANSION_AUTO); } + if (!enable) { + /* Clear flag to allow enter replay when CRC source is disabled */ + if (aconnector) + aconnector->disallow_edp_enter_replay = false; + } + unlock: mutex_unlock(&adev->dm.dc_lock); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c index da94e3544b65..8c150b001105 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c @@ -154,14 +154,21 @@ bool amdgpu_dm_replay_enable(struct dc_stream_state *stream, bool wait) { bool replay_active = true; struct dc_link *link = NULL; + struct amdgpu_dm_connector *aconnector = NULL; if (stream == NULL) return false; + /* Check if replay is disabled by connector flag */ + aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context; + if (!aconnector || aconnector->disallow_edp_enter_replay) { + return false; + } + link = stream->link; if (link) { - link->dc->link_srv->edp_setup_replay(link, stream); + link->dc->link_srv->dp_setup_replay(link, stream); link->dc->link_srv->edp_set_coasting_vtotal(link, stream->timing.v_total, 0); DRM_DEBUG_DRIVER("Enabling replay...\n"); link->dc->link_srv->edp_set_replay_allow_active(link, &replay_active, wait, false, NULL); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 57f6a4c8afff..aba5ad2a7a33 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -7246,6 +7246,14 @@ static bool update_planes_and_stream_prepare_v3_intermediate_seamless( ); } +static void transition_countdown_init(struct dc *dc) +{ + dc->check_config.transition_countdown_to_steady_state = + dc->debug.num_fast_flips_to_steady_state_override ? + dc->debug.num_fast_flips_to_steady_state_override : + NUM_FAST_FLIPS_TO_STEADY_STATE; +} + static bool update_planes_and_stream_prepare_v3( struct dc_update_scratch_space *scratch ) @@ -7305,9 +7313,17 @@ static bool update_planes_and_stream_prepare_v3( ); if (seamless) { scratch->flow = UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS; + if (scratch->dc->check_config.deferred_transition_state) + /* reset countdown as steady state not reached */ + transition_countdown_init(scratch->dc); return true; } + if (!scratch->dc->debug.disable_deferred_minimal_transitions) { + scratch->dc->check_config.deferred_transition_state = true; + transition_countdown_init(scratch->dc); + } + scratch->intermediate_context = create_minimal_transition_state( scratch->dc, scratch->new_context, @@ -7351,7 +7367,8 @@ static bool update_planes_and_stream_prepare_v3( static void update_planes_and_stream_execute_v3_commit( const struct dc_update_scratch_space *scratch, bool intermediate_update, - bool intermediate_context + bool intermediate_context, + bool use_stream_update ) { commit_planes_for_stream( @@ -7359,7 +7376,7 @@ static void update_planes_and_stream_execute_v3_commit( intermediate_update ? scratch->intermediate_updates : scratch->surface_updates, intermediate_update ? scratch->intermediate_count : scratch->surface_count, scratch->stream, - intermediate_context ? NULL : scratch->stream_update, + use_stream_update ? scratch->stream_update : NULL, intermediate_context ? UPDATE_TYPE_FULL : scratch->update_type, // `dc->current_state` only used in `NO_NEW_CONTEXT`, where it is equal to `new_context` intermediate_context ? scratch->intermediate_context : scratch->new_context @@ -7385,15 +7402,16 @@ static void update_planes_and_stream_execute_v3( case UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FULL: case UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS: - update_planes_and_stream_execute_v3_commit(scratch, false, false); + update_planes_and_stream_execute_v3_commit(scratch, false, false, true); break; case UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_NEW: - update_planes_and_stream_execute_v3_commit(scratch, false, true); + update_planes_and_stream_execute_v3_commit(scratch, false, true, + scratch->dc->check_config.deferred_transition_state); break; case UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_CURRENT: - update_planes_and_stream_execute_v3_commit(scratch, true, true); + update_planes_and_stream_execute_v3_commit(scratch, true, true, false); break; case UPDATE_V3_FLOW_INVALID: @@ -7402,13 +7420,6 @@ static void update_planes_and_stream_execute_v3( } } -static void update_planes_and_stream_cleanup_v3_new_context( - struct dc_update_scratch_space *scratch -) -{ - swap_and_release_current_context(scratch->dc, scratch->new_context, scratch->stream); -} - static void update_planes_and_stream_cleanup_v3_release_minimal( struct dc_update_scratch_space *scratch, bool backup @@ -7439,17 +7450,23 @@ static bool update_planes_and_stream_cleanup_v3( switch (scratch->flow) { case UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FAST: case UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FULL: - // No cleanup required + if (scratch->dc->check_config.transition_countdown_to_steady_state) + scratch->dc->check_config.transition_countdown_to_steady_state--; break; case UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS: - update_planes_and_stream_cleanup_v3_new_context(scratch); + swap_and_release_current_context(scratch->dc, scratch->new_context, scratch->stream); break; case UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_NEW: update_planes_and_stream_cleanup_v3_intermediate(scratch, false); - scratch->flow = UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS; - return true; + if (scratch->dc->check_config.deferred_transition_state) { + dc_state_release(scratch->new_context); + } else { + scratch->flow = UPDATE_V3_FLOW_NEW_CONTEXT_SEAMLESS; + return true; + } + break; case UPDATE_V3_FLOW_NEW_CONTEXT_MINIMAL_CURRENT: update_planes_and_stream_cleanup_v3_intermediate(scratch, true); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c index a8d7228907c2..7bb4504889be 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c @@ -493,24 +493,24 @@ bool dc_link_get_replay_state(const struct dc_link *link, uint64_t *state) bool dc_link_set_pr_enable(struct dc_link *link, bool enable) { - return link->dc->link_srv->edp_pr_enable(link, enable); + return link->dc->link_srv->dp_pr_enable(link, enable); } bool dc_link_update_pr_state(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data) { - return link->dc->link_srv->edp_pr_update_state(link, update_state_data); + return link->dc->link_srv->dp_pr_update_state(link, update_state_data); } bool dc_link_set_pr_general_cmd(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data) { - return link->dc->link_srv->edp_pr_set_general_cmd(link, general_cmd_data); + return link->dc->link_srv->dp_pr_set_general_cmd(link, general_cmd_data); } bool dc_link_get_pr_state(const struct dc_link *link, uint64_t *state) { - return link->dc->link_srv->edp_pr_get_state(link, state); + return link->dc->link_srv->dp_pr_get_state(link, state); } bool dc_link_wait_for_t12(struct dc_link *link) @@ -549,4 +549,3 @@ void dc_link_get_alpm_support(struct dc_link *link, { link->dc->link_srv->edp_get_alpm_support(link, auxless_support, auxwake_support); } - diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 69fa7fc02fa8..fc3dd1054710 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -63,7 +63,7 @@ struct dcn_dsc_reg_state; struct dcn_optc_reg_state; struct dcn_dccg_reg_state; -#define DC_VER "3.2.364" +#define DC_VER "3.2.365" /** * MAX_SURFACES - representative of the upper bound of surfaces that can be piped to a single CRTC diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c index 602655dd1323..2dc6ae6b5bea 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c @@ -999,6 +999,7 @@ void dc_dmub_srv_log_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv) DC_LOG_DEBUG(" is_traceport_en : %d", dc_dmub_srv->dmub->debug.is_traceport_en); DC_LOG_DEBUG(" is_cw0_en : %d", dc_dmub_srv->dmub->debug.is_cw0_enabled); DC_LOG_DEBUG(" is_cw6_en : %d", dc_dmub_srv->dmub->debug.is_cw6_enabled); + DC_LOG_DEBUG(" is_pwait : %d", dc_dmub_srv->dmub->debug.is_pwait); } static bool dc_dmub_should_update_cursor_data(struct pipe_ctx *pipe_ctx) diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h index 273610d85438..5e3646b7550c 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h @@ -1167,6 +1167,25 @@ union dpcd_panel_replay_capability_supported { unsigned char raw; }; +union dpcd_panel_replay_capability { + struct { + unsigned char RESERVED :2; + unsigned char DSC_DECODE_NOT_SUPPORTED :1; + unsigned char ASYNC_VIDEO_TIMING_NOT_SUPPORTED :1; + unsigned char DSC_CRC_OF_MULTI_SU_SUPPORTED :1; + unsigned char PR_SU_GRANULARITY_NEEDED :1; + unsigned char SU_Y_GRANULARITY_EXT_CAP_SUPPORTED :1; + unsigned char LINK_OFF_SUPPORTED_IN_PR_ACTIVE :1; + } bits; + unsigned char raw; +}; + +struct dpcd_panel_replay_selective_update_info { + uint16_t pr_su_x_granularity; + uint8_t pr_su_y_granularity; + uint16_t pr_su_y_granularity_extended_caps; +}; + enum dpcd_downstream_port_max_bpc { DOWN_STREAM_MAX_8BPC = 0, DOWN_STREAM_MAX_10BPC, @@ -1290,7 +1309,9 @@ struct dpcd_caps { struct edp_psr_info psr_info; struct replay_info pr_info; - union dpcd_panel_replay_capability_supported pr_caps_supported; + union dpcd_panel_replay_capability_supported vesa_replay_caps_supported; + union dpcd_panel_replay_capability vesa_replay_caps; + struct dpcd_panel_replay_selective_update_info vesa_replay_su_info; uint16_t edp_oled_emission_rate; union dp_receive_port0_cap receive_port0_cap; /* Indicates the number of SST links supported by MSO (Multi-Stream Output) */ @@ -1402,6 +1423,17 @@ union dpcd_sink_active_vtotal_control_mode { unsigned char raw; }; +union pr_error_status { + struct { + unsigned char LINK_CRC_ERROR :1; + unsigned char RFB_STORAGE_ERROR :1; + unsigned char VSC_SDP_ERROR :1; + unsigned char ASSDP_MISSING_ERROR :1; + unsigned char RESERVED :4; + } bits; + unsigned char raw; +}; + union psr_error_status { struct { unsigned char LINK_CRC_ERROR :1; diff --git a/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h b/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h index b015e80672ec..fcd3ab4b0045 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h @@ -41,7 +41,7 @@ /* kHZ*/ #define DP_ADAPTOR_DVI_MAX_TMDS_CLK 165000 /* kHZ*/ -#define DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK 165000 +#define DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK 340000 struct dp_hdmi_dongle_signature_data { int8_t id[15];/* "DP-HDMI ADAPTOR"*/ diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h index 667852517246..cfa569a7bff1 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -491,6 +491,12 @@ struct dc_cursor_position { * for each plane. */ bool translate_by_source; + + /** + * @use_viewport_for_clip: Use viewport position for clip_x calculation + * instead of clip_rect. Required to protect against clip being overwritten + */ + bool use_viewport_for_clip; }; struct dc_cursor_mi_param { diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index b3b785f1897d..bb1387233bd8 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -1101,7 +1101,6 @@ enum replay_FW_Message_type { Replay_Set_Residency_Frameupdate_Timer, Replay_Set_Pseudo_VTotal, Replay_Disabled_Adaptive_Sync_SDP, - Replay_Set_Version, Replay_Set_General_Cmd, }; @@ -1224,6 +1223,8 @@ struct replay_settings { uint32_t replay_desync_error_fail_count; /* The frame skip number dal send to DMUB */ uint16_t frame_skip_number; + /* Current Panel Replay event */ + uint32_t replay_events; }; /* To split out "global" and "per-panel" config settings. diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c index 5bfa2b0d2afd..7116fdd4c7ec 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c @@ -69,7 +69,7 @@ bool dmub_hw_lock_mgr_does_link_require_lock(const struct dc *dc, const struct d if (link->psr_settings.psr_version == DC_PSR_VERSION_SU_1) return true; - if (link->replay_settings.replay_feature_enabled) + if (link->replay_settings.replay_feature_enabled && dc_is_embedded_signal(link->connector_signal)) return true; if (link->psr_settings.psr_version == DC_PSR_VERSION_1) { diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c index cf1372aaff6c..fd8244c94687 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c @@ -387,19 +387,6 @@ static void dmub_replay_send_cmd(struct dmub_replay *dmub, cmd.replay_disabled_adaptive_sync_sdp.data.force_disabled = cmd_element->disabled_adaptive_sync_sdp_data.force_disabled; break; - case Replay_Set_Version: - //Header - cmd.replay_set_version.header.sub_type = - DMUB_CMD__REPLAY_SET_VERSION; - cmd.replay_set_version.header.payload_bytes = - sizeof(struct dmub_rb_cmd_replay_set_version) - - sizeof(struct dmub_cmd_header); - //Cmd Body - cmd.replay_set_version.replay_set_version_data.panel_inst = - cmd_element->version_data.panel_inst; - cmd.replay_set_version.replay_set_version_data.version = - cmd_element->version_data.version; - break; case Replay_Set_General_Cmd: //Header cmd.replay_set_general_cmd.header.sub_type = diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c index fa62e40a9858..8a23763ca98e 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c @@ -3666,7 +3666,11 @@ void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) int y_plane = pipe_ctx->plane_state->dst_rect.y; int x_pos = pos_cpy.x; int y_pos = pos_cpy.y; - int clip_x = pipe_ctx->plane_state->clip_rect.x; + bool is_primary_plane = (pipe_ctx->plane_state->layer_index == 0); + + int clip_x = (pos_cpy.use_viewport_for_clip && is_primary_plane && + !odm_combine_on && !pipe_split_on && param.viewport.x != 0) + ? param.viewport.x : pipe_ctx->plane_state->clip_rect.x; int clip_width = pipe_ctx->plane_state->clip_rect.width; if ((pipe_ctx->top_pipe != NULL) || (pipe_ctx->bottom_pipe != NULL)) { diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c index 1271bf55dac3..2675d7dca586 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c @@ -1727,3 +1727,55 @@ void dcn35_program_cursor_offload_now(struct dc *dc, const struct pipe_ctx *pipe { dc_dmub_srv_program_cursor_now(dc, pipe); } + +static void disable_link_output_symclk_on_tx_off(struct dc_link *link, enum dp_link_encoding link_encoding) +{ + struct dc *dc = link->ctx->dc; + struct pipe_ctx *pipe_ctx = NULL; + uint8_t i; + + for (i = 0; i < MAX_PIPES; i++) { + pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx->stream && pipe_ctx->stream->link == link && pipe_ctx->top_pipe == NULL) { + pipe_ctx->clock_source->funcs->program_pix_clk( + pipe_ctx->clock_source, + &pipe_ctx->stream_res.pix_clk_params, + link_encoding, + &pipe_ctx->pll_settings); + break; + } + } +} + +void dcn35_disable_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal) +{ + struct dc *dc = link->ctx->dc; + const struct link_hwss *link_hwss = get_link_hwss(link, link_res); + struct dmcu *dmcu = dc->res_pool->dmcu; + + if (signal == SIGNAL_TYPE_EDP && + link->dc->hwss.edp_backlight_control && + !link->skip_implict_edp_power_control) + link->dc->hwss.edp_backlight_control(link, false); + else if (dmcu != NULL && dmcu->funcs->lock_phy) + dmcu->funcs->lock_phy(dmcu); + + if (dc_is_tmds_signal(signal) && link->phy_state.symclk_ref_cnts.otg > 0) { + disable_link_output_symclk_on_tx_off(link, DP_UNKNOWN_ENCODING); + link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; + } else { + link_hwss->disable_link_output(link, link_res, signal); + link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF; + } + /* + * Add the logic to extract BOTH power up and power down sequences + * from enable/disable link output and only call edp panel control + * in enable_link_dp and disable_link_dp once. + */ + if (dmcu != NULL && dmcu->funcs->unlock_phy) + dmcu->funcs->unlock_phy(dmcu); + + dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY); +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h index 1ff41dba556c..e3459546a908 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h @@ -108,5 +108,8 @@ void dcn35_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pipe void dcn35_notify_cursor_offload_drr_update(struct dc *dc, struct dc_state *context, const struct dc_stream_state *stream); void dcn35_program_cursor_offload_now(struct dc *dc, const struct pipe_ctx *pipe); +void dcn35_disable_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal); #endif /* __DC_HWSS_DCN35_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c index 5a66c9db2670..81bd36f3381d 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c @@ -113,7 +113,7 @@ static const struct hw_sequencer_funcs dcn35_funcs = { .enable_lvds_link_output = dce110_enable_lvds_link_output, .enable_tmds_link_output = dce110_enable_tmds_link_output, .enable_dp_link_output = dce110_enable_dp_link_output, - .disable_link_output = dcn32_disable_link_output, + .disable_link_output = dcn35_disable_link_output, .z10_restore = dcn35_z10_restore, .z10_save_init = dcn31_z10_save_init, .set_disp_pattern_generator = dcn30_set_disp_pattern_generator, 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 b7593b886dc6..22c1d5e68420 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 @@ -287,6 +287,8 @@ void dcn401_init_hw(struct dc *dc) for (i = 0; i < dc->link_count; i++) { struct dc_link *link = dc->links[i]; + if (link->ep_type != DISPLAY_ENDPOINT_PHY) + continue; if (link->link_enc->funcs->is_dig_enabled && link->link_enc->funcs->is_dig_enabled(link->link_enc) && hws->funcs.power_down) { diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h index 500a601e99b5..1e6ffd86a4c0 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h @@ -333,6 +333,7 @@ struct dccg_funcs { void (*set_ref_dscclk)(struct dccg *dccg, uint32_t dsc_inst); void (*dccg_root_gate_disable_control)(struct dccg *dccg, uint32_t pipe_idx, uint32_t disable_clock_gating); void (*dccg_read_reg_state)(struct dccg *dccg, struct dcn_dccg_reg_state *dccg_reg_state); + void (*dccg_enable_global_fgcg)(struct dccg *dccg, bool enable); }; #endif //__DAL_DCCG_H__ diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_service.h b/drivers/gpu/drm/amd/display/dc/inc/link_service.h index 4b092a9ee4c6..57bb82e94942 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/link_service.h +++ b/drivers/gpu/drm/amd/display/dc/inc/link_service.h @@ -283,8 +283,6 @@ struct link_service { bool (*edp_set_replay_allow_active)(struct dc_link *dc_link, const bool *enable, bool wait, bool force_static, const unsigned int *power_opts); - bool (*edp_setup_replay)(struct dc_link *link, - const struct dc_stream_state *stream); bool (*edp_send_replay_cmd)(struct dc_link *link, enum replay_FW_Message_type msg, union dmub_replay_cmd_set *cmd_data); @@ -304,10 +302,12 @@ struct link_service { bool (*edp_receiver_ready_T9)(struct dc_link *link); bool (*edp_receiver_ready_T7)(struct dc_link *link); bool (*edp_power_alpm_dpcd_enable)(struct dc_link *link, bool enable); - bool (*edp_pr_enable)(struct dc_link *link, bool enable); - bool (*edp_pr_update_state)(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data); - bool (*edp_pr_set_general_cmd)(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data); - bool (*edp_pr_get_state)(const struct dc_link *link, uint64_t *state); + bool (*dp_setup_replay)(struct dc_link *link, const struct dc_stream_state *stream); + bool (*dp_pr_get_panel_inst)(const struct dc *dc, const struct dc_link *link, unsigned int *inst_out); + bool (*dp_pr_enable)(struct dc_link *link, bool enable); + bool (*dp_pr_update_state)(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data); + bool (*dp_pr_set_general_cmd)(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data); + bool (*dp_pr_get_state)(const struct dc_link *link, uint64_t *state); void (*edp_set_panel_power)(struct dc_link *link, bool powerOn); diff --git a/drivers/gpu/drm/amd/display/dc/link/Makefile b/drivers/gpu/drm/amd/display/dc/link/Makefile index 84c7af5fa589..84dace27daf7 100644 --- a/drivers/gpu/drm/amd/display/dc/link/Makefile +++ b/drivers/gpu/drm/amd/display/dc/link/Makefile @@ -56,7 +56,7 @@ LINK_PROTOCOLS = link_hpd.o link_ddc.o link_dpcd.o link_dp_dpia.o \ link_dp_training.o link_dp_training_8b_10b.o link_dp_training_128b_132b.o \ link_dp_training_dpia.o link_dp_training_auxless.o \ link_dp_training_fixed_vs_pe_retimer.o link_dp_phy.o link_dp_capability.o \ -link_edp_panel_control.o link_dp_irq_handler.o link_dp_dpia_bw.o +link_edp_panel_control.o link_dp_panel_replay.o link_dp_irq_handler.o link_dp_dpia_bw.o AMD_DAL_LINK_PROTOCOLS = $(addprefix $(AMDDALPATH)/dc/link/protocols/, \ $(LINK_PROTOCOLS)) 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 5a547d41d4a1..693d852b1c40 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 @@ -70,6 +70,7 @@ static void dp_retrain_link_dp_test(struct dc_link *link, struct dc_state *state = link->dc->current_state; struct dc_stream_update stream_update = { 0 }; bool dpms_off = false; + bool needs_divider_update = false; bool was_hpo_acquired = resource_is_hpo_acquired(link->dc->current_state); bool is_hpo_acquired; uint8_t count; @@ -79,6 +80,10 @@ static void dp_retrain_link_dp_test(struct dc_link *link, int num_streams_on_link = 0; struct dc *dc = (struct dc *)link->dc; + 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)) + || link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA; + udelay(100); link_get_master_pipes_with_dpms_on(link, state, &count, pipes); @@ -95,7 +100,7 @@ static void dp_retrain_link_dp_test(struct dc_link *link, pipes[i]->stream_res.tg->funcs->disable_crtc(pipes[i]->stream_res.tg); } - if (link->dc->res_pool->funcs->update_dc_state_for_encoder_switch) { + if (needs_divider_update && link->dc->res_pool->funcs->update_dc_state_for_encoder_switch) { link->dc->res_pool->funcs->update_dc_state_for_encoder_switch(link, link_setting, count, *pipes, &audio_output[0]); diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.c b/drivers/gpu/drm/amd/display/dc/link/link_detection.c index f24365395cd9..578509e8d0e2 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c @@ -335,7 +335,7 @@ static void query_dp_dual_mode_adaptor( /* Assume we have no valid DP passive dongle connected */ *dongle = DISPLAY_DONGLE_NONE; - sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK; + sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_DVI_MAX_TMDS_CLK; /* Read DP-HDMI dongle I2c (no response interpreted as DP-DVI dongle)*/ if (!i2c_read( @@ -391,6 +391,8 @@ static void query_dp_dual_mode_adaptor( } } + if (is_valid_hdmi_signature) + sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK; if (is_type2_dongle) { uint32_t max_tmds_clk = @@ -993,7 +995,7 @@ static bool detect_link_and_local_sink(struct dc_link *link, (link->dpcd_sink_ext_caps.bits.oled == 1)) { dpcd_set_source_specific_data(link); msleep(post_oui_delay); - set_default_brightness(link); + set_default_brightness_aux(link); } return true; 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 323cc0b3c09a..91742bde4dc2 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c @@ -46,6 +46,7 @@ #include "protocols/link_dp_capability.h" #include "protocols/link_dp_training.h" #include "protocols/link_edp_panel_control.h" +#include "protocols/link_dp_panel_replay.h" #include "protocols/link_dp_dpia_bw.h" #include "dm_helpers.h" @@ -2061,7 +2062,7 @@ static enum dc_status enable_link_dp(struct dc_state *state, skip_video_pattern = false; if (stream->sink_patches.oled_optimize_display_on) - set_default_brightness(link); + set_default_brightness_aux(link); if (perform_link_training_with_retries(link_settings, skip_video_pattern, @@ -2087,7 +2088,7 @@ static enum dc_status enable_link_dp(struct dc_state *state, link->dpcd_sink_ext_caps.bits.sdr_aux_backlight_control == 1 || link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 1) { if (!stream->sink_patches.oled_optimize_display_on) { - set_default_brightness(link); + set_default_brightness_aux(link); if (link->dpcd_sink_ext_caps.bits.oled == 1) msleep(bl_oled_enable_delay); edp_backlight_enable_aux(link, true); @@ -2529,6 +2530,9 @@ void link_set_dpms_on( link_set_dsc_enable(pipe_ctx, true); } + if (link->replay_settings.config.replay_supported && !dc_is_embedded_signal(link->connector_signal)) + dp_setup_replay(link, stream); + status = enable_link(state, pipe_ctx); if (status != DC_OK) { diff --git a/drivers/gpu/drm/amd/display/dc/link/link_factory.c b/drivers/gpu/drm/amd/display/dc/link/link_factory.c index 923517715651..5fbcf04c6251 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_factory.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c @@ -41,6 +41,7 @@ #include "protocols/link_dp_phy.h" #include "protocols/link_dp_training.h" #include "protocols/link_edp_panel_control.h" +#include "protocols/link_dp_panel_replay.h" #include "protocols/link_hpd.h" #include "gpio_service_interface.h" #include "atomfirmware.h" @@ -214,7 +215,6 @@ static void construct_link_service_edp_panel_control(struct link_service *link_s link_srv->edp_get_replay_state = edp_get_replay_state; link_srv->edp_set_replay_allow_active = edp_set_replay_allow_active; - link_srv->edp_setup_replay = edp_setup_replay; link_srv->edp_send_replay_cmd = edp_send_replay_cmd; link_srv->edp_set_coasting_vtotal = edp_set_coasting_vtotal; link_srv->edp_replay_residency = edp_replay_residency; @@ -228,13 +228,21 @@ static void construct_link_service_edp_panel_control(struct link_service *link_s link_srv->edp_receiver_ready_T9 = edp_receiver_ready_T9; link_srv->edp_receiver_ready_T7 = edp_receiver_ready_T7; link_srv->edp_power_alpm_dpcd_enable = edp_power_alpm_dpcd_enable; - link_srv->edp_pr_enable = edp_pr_enable; - link_srv->edp_pr_update_state = edp_pr_update_state; - link_srv->edp_pr_set_general_cmd = edp_pr_set_general_cmd; - link_srv->edp_pr_get_state = edp_pr_get_state; link_srv->edp_set_panel_power = edp_set_panel_power; } +/* link dp panel replay implements DP panel replay functionality. + */ +static void construct_link_service_dp_panel_replay(struct link_service *link_srv) +{ + link_srv->dp_setup_replay = dp_setup_replay; + link_srv->dp_pr_get_panel_inst = dp_pr_get_panel_inst; + link_srv->dp_pr_enable = dp_pr_enable; + link_srv->dp_pr_update_state = dp_pr_update_state; + link_srv->dp_pr_set_general_cmd = dp_pr_set_general_cmd; + link_srv->dp_pr_get_state = dp_pr_get_state; +} + /* link dp cts implements dp compliance test automation protocols and manual * testing interfaces for debugging and certification purpose. */ @@ -287,6 +295,7 @@ static void construct_link_service(struct link_service *link_srv) construct_link_service_dp_phy_or_dpia(link_srv); construct_link_service_dp_irq_handler(link_srv); construct_link_service_edp_panel_control(link_srv); + construct_link_service_dp_panel_replay(link_srv); construct_link_service_dp_cts(link_srv); construct_link_service_dp_trace(link_srv); } diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c index 54c417928b61..cdc7587cf0b6 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c @@ -1593,6 +1593,41 @@ static bool dpcd_read_sink_ext_caps(struct dc_link *link) return true; } +static void retrieve_vesa_replay_su_info(struct dc_link *link) +{ + uint8_t dpcd_data = 0; + + core_link_read_dpcd(link, + DP_PR_SU_X_GRANULARITY_LOW, + &dpcd_data, + sizeof(dpcd_data)); + link->dpcd_caps.vesa_replay_su_info.pr_su_x_granularity = dpcd_data; + + core_link_read_dpcd(link, + DP_PR_SU_X_GRANULARITY_HIGH, + &dpcd_data, + sizeof(dpcd_data)); + link->dpcd_caps.vesa_replay_su_info.pr_su_x_granularity |= (dpcd_data << 8); + + core_link_read_dpcd(link, + DP_PR_SU_Y_GRANULARITY, + &dpcd_data, + sizeof(dpcd_data)); + link->dpcd_caps.vesa_replay_su_info.pr_su_y_granularity = dpcd_data; + + core_link_read_dpcd(link, + DP_PR_SU_Y_GRANULARITY_EXTENDED_CAP_LOW, + &dpcd_data, + sizeof(dpcd_data)); + link->dpcd_caps.vesa_replay_su_info.pr_su_y_granularity_extended_caps = dpcd_data; + + core_link_read_dpcd(link, + DP_PR_SU_Y_GRANULARITY_EXTENDED_CAP_HIGH, + &dpcd_data, + sizeof(dpcd_data)); + link->dpcd_caps.vesa_replay_su_info.pr_su_y_granularity_extended_caps |= (dpcd_data << 8); +} + enum dc_status dp_retrieve_lttpr_cap(struct dc_link *link) { uint8_t lttpr_dpcd_data[10] = {0}; @@ -2094,8 +2129,16 @@ static bool retrieve_link_cap(struct dc_link *link) core_link_read_dpcd(link, DP_PANEL_REPLAY_CAPABILITY_SUPPORT, - &link->dpcd_caps.pr_caps_supported.raw, - sizeof(link->dpcd_caps.pr_caps_supported.raw)); + &link->dpcd_caps.vesa_replay_caps_supported.raw, + sizeof(link->dpcd_caps.vesa_replay_caps_supported.raw)); + + core_link_read_dpcd(link, + DP_PANEL_REPLAY_CAPABILITY, + &link->dpcd_caps.vesa_replay_caps.raw, + sizeof(link->dpcd_caps.vesa_replay_caps.raw)); + + /* Read VESA Panel Replay Selective Update caps */ + retrieve_vesa_replay_su_info(link); /* Read DP tunneling information. */ status = dpcd_get_tunneling_device_data(link); @@ -2167,7 +2210,7 @@ void detect_edp_sink_caps(struct dc_link *link) link->dpcd_caps.set_power_state_capable_edp = (general_edp_cap & DP_EDP_SET_POWER_CAP) ? true : false; - set_default_brightness(link); + set_default_brightness_aux(link); core_link_read_dpcd(link, DP_EDP_DPCD_REV, &link->dpcd_caps.edp_rev, diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c index 4b01ab0a5a7f..cc18a3bebef2 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c @@ -34,10 +34,12 @@ #include "link_dp_training.h" #include "link_dp_capability.h" #include "link_edp_panel_control.h" +#include "link_dp_panel_replay.h" #include "link/accessories/link_dp_trace.h" #include "link/link_dpms.h" #include "dm_helpers.h" #include "link_dp_dpia_bw.h" +#include "link_dp_panel_replay.h" #define DC_LOGGER \ link->ctx->logger @@ -185,6 +187,42 @@ static bool handle_hpd_irq_psr_sink(struct dc_link *link) return false; } +static void handle_hpd_irq_vesa_replay_sink(struct dc_link *link) +{ + union pr_error_status pr_error_status = {0}; + + if (!link->replay_settings.replay_feature_enabled || + link->replay_settings.config.replay_version != DC_VESA_PANEL_REPLAY) + return; + + dm_helpers_dp_read_dpcd( + link->ctx, + link, + DP_PR_ERROR_STATUS, + &pr_error_status.raw, + sizeof(pr_error_status.raw)); + + if (pr_error_status.bits.LINK_CRC_ERROR || + pr_error_status.bits.RFB_STORAGE_ERROR || + pr_error_status.bits.VSC_SDP_ERROR || + pr_error_status.bits.ASSDP_MISSING_ERROR) { + + /* Acknowledge and clear error bits */ + dm_helpers_dp_write_dpcd( + link->ctx, + link, + DP_PR_ERROR_STATUS, /*DpcdAddress_PR_Error_Status*/ + &pr_error_status.raw, + sizeof(pr_error_status.raw)); + + /* Replay error, disable and re-enable Replay */ + if (link->replay_settings.replay_allow_active) { + dp_pr_enable(link, false); + dp_pr_enable(link, true); + } + } +} + static void handle_hpd_irq_replay_sink(struct dc_link *link) { union dpcd_replay_configuration replay_configuration = {0}; @@ -196,6 +234,11 @@ static void handle_hpd_irq_replay_sink(struct dc_link *link) if (!link->replay_settings.replay_feature_enabled) return; + if (link->replay_settings.config.replay_version != DC_FREESYNC_REPLAY) { + handle_hpd_irq_vesa_replay_sink(link); + return; + } + while (retries < 10) { ret = dm_helpers_dp_read_dpcd( link->ctx, diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c new file mode 100644 index 000000000000..be441851d876 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c @@ -0,0 +1,343 @@ +/* + * Copyright 2025 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "link_dp_panel_replay.h" +#include "link_edp_panel_control.h" +#include "link_dpcd.h" +#include "dm_helpers.h" +#include "dc/dc_dmub_srv.h" +#include "dce/dmub_replay.h" + +#define DC_LOGGER \ + link->ctx->logger + +#define DP_SINK_PR_ENABLE_AND_CONFIGURATION 0x37B + +static bool dp_setup_panel_replay(struct dc_link *link, const struct dc_stream_state *stream) +{ + /* To-do: Setup Replay */ + struct dc *dc; + struct dmub_replay *replay; + int i; + unsigned int panel_inst; + struct replay_context replay_context = { 0 }; + unsigned int lineTimeInNs = 0; + + union panel_replay_enable_and_configuration_1 pr_config_1 = { 0 }; + union panel_replay_enable_and_configuration_2 pr_config_2 = { 0 }; + + union dpcd_alpm_configuration alpm_config; + + replay_context.controllerId = CONTROLLER_ID_UNDEFINED; + + if (!link) + return false; + + //Clear Panel Replay enable & config + dm_helpers_dp_write_dpcd(link->ctx, link, + DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_1, + (uint8_t *)&(pr_config_1.raw), sizeof(uint8_t)); + + dm_helpers_dp_write_dpcd(link->ctx, link, + DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2, + (uint8_t *)&(pr_config_2.raw), sizeof(uint8_t)); + + if (!(link->replay_settings.config.replay_supported)) + return false; + + dc = link->ctx->dc; + + //not sure should keep or not + replay = dc->res_pool->replay; + + if (!replay) + return false; + + if (!dp_pr_get_panel_inst(dc, link, &panel_inst)) + return false; + + replay_context.aux_inst = link->ddc->ddc_pin->hw_info.ddc_channel; + replay_context.digbe_inst = link->link_enc->transmitter; + replay_context.digfe_inst = link->link_enc->preferred_engine; + + for (i = 0; i < MAX_PIPES; i++) { + if (dc->current_state->res_ctx.pipe_ctx[i].stream + == stream) { + /* dmcu -1 for all controller id values, + * therefore +1 here + */ + replay_context.controllerId = + dc->current_state->res_ctx.pipe_ctx[i].stream_res.tg->inst + 1; + break; + } + } + + lineTimeInNs = + ((stream->timing.h_total * 1000000) / + (stream->timing.pix_clk_100hz / 10)) + 1; + + replay_context.line_time_in_ns = lineTimeInNs; + + link->replay_settings.replay_feature_enabled = dp_pr_copy_settings(link, &replay_context); + + if (link->replay_settings.replay_feature_enabled) { + if (dc_is_embedded_signal(link->connector_signal)) { + pr_config_1.bits.PANEL_REPLAY_ENABLE = 1; + pr_config_1.bits.PANEL_REPLAY_CRC_ENABLE = 1; + pr_config_1.bits.IRQ_HPD_ASSDP_MISSING = 1; + pr_config_1.bits.IRQ_HPD_VSCSDP_UNCORRECTABLE_ERROR = 1; + pr_config_1.bits.IRQ_HPD_RFB_ERROR = 1; + pr_config_1.bits.IRQ_HPD_ACTIVE_FRAME_CRC_ERROR = 1; + pr_config_1.bits.PANEL_REPLAY_SELECTIVE_UPDATE_ENABLE = 1; + pr_config_1.bits.PANEL_REPLAY_EARLY_TRANSPORT_ENABLE = 1; + } else { + pr_config_1.bits.PANEL_REPLAY_ENABLE = 1; + } + + pr_config_2.bits.SINK_REFRESH_RATE_UNLOCK_GRANTED = 0; + + if (link->dpcd_caps.vesa_replay_caps.bits.SU_Y_GRANULARITY_EXT_CAP_SUPPORTED) + pr_config_2.bits.SU_Y_GRANULARITY_EXT_VALUE_ENABLED = 1; + + pr_config_2.bits.SU_REGION_SCAN_LINE_CAPTURE_INDICATION = 0; + + dm_helpers_dp_write_dpcd(link->ctx, link, + DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_1, + (uint8_t *)&(pr_config_1.raw), sizeof(uint8_t)); + + dm_helpers_dp_write_dpcd(link->ctx, link, + DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2, + (uint8_t *)&(pr_config_2.raw), sizeof(uint8_t)); + + //ALPM Setup + memset(&alpm_config, 0, sizeof(alpm_config)); + alpm_config.bits.ENABLE = link->replay_settings.config.alpm_mode != DC_ALPM_UNSUPPORTED ? 1 : 0; + + if (link->replay_settings.config.alpm_mode == DC_ALPM_AUXLESS) { + alpm_config.bits.ALPM_MODE_SEL = 1; + alpm_config.bits.ACDS_PERIOD_DURATION = 1; + } + + dm_helpers_dp_write_dpcd( + link->ctx, + link, + DP_RECEIVER_ALPM_CONFIG, + &alpm_config.raw, + sizeof(alpm_config.raw)); + } + + return true; +} + + +bool dp_pr_get_panel_inst(const struct dc *dc, + const struct dc_link *link, + unsigned int *inst_out) +{ + if (dc_is_embedded_signal(link->connector_signal)) { + /* TODO: just get edp link panel inst for now, fix it */ + return dc_get_edp_link_panel_inst(dc, link, inst_out); + } else if (dc_is_dp_sst_signal(link->connector_signal)) { + /* TODO: just set to 1 for now, fix it */ + *inst_out = 1; + return true; + } + + return false; +} + +bool dp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream) +{ + if (!link) + return false; + if (link->replay_settings.config.replay_version == DC_VESA_PANEL_REPLAY) + return dp_setup_panel_replay(link, stream); + else if (link->replay_settings.config.replay_version == DC_FREESYNC_REPLAY) + return edp_setup_freesync_replay(link, stream); + else + return false; +} + +bool dp_pr_enable(struct dc_link *link, bool enable) +{ + struct dc *dc = link->ctx->dc; + unsigned int panel_inst = 0; + union dmub_rb_cmd cmd; + + if (!dp_pr_get_panel_inst(dc, link, &panel_inst)) + return false; + + if (link->replay_settings.replay_allow_active != enable) { + //for sending PR enable commands to DMUB + memset(&cmd, 0, sizeof(cmd)); + + cmd.pr_enable.header.type = DMUB_CMD__PR; + cmd.pr_enable.header.sub_type = DMUB_CMD__PR_ENABLE; + cmd.pr_enable.header.payload_bytes = sizeof(struct dmub_cmd_pr_enable_data); + cmd.pr_enable.data.panel_inst = panel_inst; + cmd.pr_enable.data.enable = enable ? 1 : 0; + + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + + link->replay_settings.replay_allow_active = enable; + } + return true; +} + +bool dp_pr_copy_settings(struct dc_link *link, struct replay_context *replay_context) +{ + struct dc *dc = link->ctx->dc; + unsigned int panel_inst = 0; + union dmub_rb_cmd cmd; + struct pipe_ctx *pipe_ctx = NULL; + + if (!dp_pr_get_panel_inst(dc, link, &panel_inst)) + return false; + + for (unsigned int i = 0; i < MAX_PIPES; i++) { + if (dc->current_state->res_ctx.pipe_ctx[i].stream && + dc->current_state->res_ctx.pipe_ctx[i].stream->link && + dc->current_state->res_ctx.pipe_ctx[i].stream->link == link && + dc_is_dp_sst_signal(dc->current_state->res_ctx.pipe_ctx[i].stream->link->connector_signal)) { + pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; + /* todo: need update for MST */ + break; + } + } + + if (!pipe_ctx) + return false; + + memset(&cmd, 0, sizeof(cmd)); + cmd.pr_copy_settings.header.type = DMUB_CMD__PR; + cmd.pr_copy_settings.header.sub_type = DMUB_CMD__PR_COPY_SETTINGS; + cmd.pr_copy_settings.header.payload_bytes = sizeof(struct dmub_cmd_pr_copy_settings_data); + cmd.pr_copy_settings.data.panel_inst = panel_inst; + // HW inst + cmd.pr_copy_settings.data.aux_inst = replay_context->aux_inst; + cmd.pr_copy_settings.data.digbe_inst = replay_context->digbe_inst; + cmd.pr_copy_settings.data.digfe_inst = replay_context->digfe_inst; + if (pipe_ctx->plane_res.dpp) + cmd.pr_copy_settings.data.dpp_inst = pipe_ctx->plane_res.dpp->inst; + else + cmd.pr_copy_settings.data.dpp_inst = 0; + if (pipe_ctx->stream_res.tg) + cmd.pr_copy_settings.data.otg_inst = pipe_ctx->stream_res.tg->inst; + else + cmd.pr_copy_settings.data.otg_inst = 0; + + cmd.pr_copy_settings.data.dpphy_inst = link->link_enc->transmitter; + + cmd.pr_copy_settings.data.line_time_in_ns = replay_context->line_time_in_ns; + cmd.pr_copy_settings.data.flags.bitfields.fec_enable_status = (link->fec_state == dc_link_fec_enabled); + cmd.pr_copy_settings.data.flags.bitfields.dsc_enable_status = (pipe_ctx->stream->timing.flags.DSC == 1); + cmd.pr_copy_settings.data.debug.u32All = link->replay_settings.config.debug_flags; + + cmd.pr_copy_settings.data.su_granularity_needed = link->dpcd_caps.vesa_replay_caps.bits.PR_SU_GRANULARITY_NEEDED; + cmd.pr_copy_settings.data.su_x_granularity = link->dpcd_caps.vesa_replay_su_info.pr_su_x_granularity; + cmd.pr_copy_settings.data.su_y_granularity = link->dpcd_caps.vesa_replay_su_info.pr_su_y_granularity; + cmd.pr_copy_settings.data.su_y_granularity_extended_caps = + link->dpcd_caps.vesa_replay_su_info.pr_su_y_granularity_extended_caps; + + if (pipe_ctx->stream->timing.dsc_cfg.num_slices_v > 0) + cmd.pr_copy_settings.data.dsc_slice_height = (pipe_ctx->stream->timing.v_addressable + + pipe_ctx->stream->timing.v_border_top + pipe_ctx->stream->timing.v_border_bottom) / + pipe_ctx->stream->timing.dsc_cfg.num_slices_v; + + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + return true; +} + +bool dp_pr_update_state(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data) +{ + struct dc *dc = link->ctx->dc; + unsigned int panel_inst = 0; + union dmub_rb_cmd cmd; + + if (!dp_pr_get_panel_inst(dc, link, &panel_inst)) + return false; + + memset(&cmd, 0, sizeof(cmd)); + cmd.pr_update_state.header.type = DMUB_CMD__PR; + cmd.pr_update_state.header.sub_type = DMUB_CMD__PR_UPDATE_STATE; + cmd.pr_update_state.header.payload_bytes = sizeof(struct dmub_cmd_pr_update_state_data); + cmd.pr_update_state.data.panel_inst = panel_inst; + + memcpy(&cmd.pr_update_state.data, update_state_data, sizeof(struct dmub_cmd_pr_update_state_data)); + + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + return true; +} + +bool dp_pr_set_general_cmd(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data) +{ + struct dc *dc = link->ctx->dc; + unsigned int panel_inst = 0; + union dmub_rb_cmd cmd; + + if (!dp_pr_get_panel_inst(dc, link, &panel_inst)) + return false; + + memset(&cmd, 0, sizeof(cmd)); + cmd.pr_general_cmd.header.type = DMUB_CMD__PR; + cmd.pr_general_cmd.header.sub_type = DMUB_CMD__PR_GENERAL_CMD; + cmd.pr_general_cmd.header.payload_bytes = sizeof(struct dmub_cmd_pr_general_cmd_data); + cmd.pr_general_cmd.data.panel_inst = panel_inst; + + memcpy(&cmd.pr_general_cmd.data, general_cmd_data, sizeof(struct dmub_cmd_pr_general_cmd_data)); + + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + return true; +} + +bool dp_pr_get_state(const struct dc_link *link, uint64_t *state) +{ + const struct dc *dc = link->ctx->dc; + unsigned int panel_inst = 0; + uint32_t retry_count = 0; + uint32_t replay_state = 0; + + if (!dp_pr_get_panel_inst(dc, link, &panel_inst)) + return false; + + do { + // Send gpint command and wait for ack + if (!dc_wake_and_execute_gpint(dc->ctx, DMUB_GPINT__GET_REPLAY_STATE, panel_inst, + &replay_state, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) { + // Return invalid state when GPINT times out + replay_state = PR_STATE_INVALID; + } + /* Copy 32-bit result into 64-bit output */ + *state = replay_state; + } while (++retry_count <= 1000 && *state == PR_STATE_INVALID); + + // Assert if max retry hit + if (retry_count >= 1000 && *state == PR_STATE_INVALID) { + ASSERT(0); + /* To-do: Add retry fail log */ + } + + return true; +} diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.h new file mode 100644 index 000000000000..5522d5911fd1 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.h @@ -0,0 +1,38 @@ +/* + * Copyright 2025 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ +#ifndef __DC_LINK_DP_PANEL_REPLAY_H__ +#define __DC_LINK_DP_PANEL_REPLAY_H__ + +#include "link_service.h" + +bool dp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream); +bool dp_pr_get_panel_inst(const struct dc *dc, const struct dc_link *link, unsigned int *inst_out); +bool dp_pr_enable(struct dc_link *link, bool enable); +bool dp_pr_copy_settings(struct dc_link *link, struct replay_context *replay_context); +bool dp_pr_update_state(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data); +bool dp_pr_set_general_cmd(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data); +bool dp_pr_get_state(const struct dc_link *link, uint64_t *state); + +#endif /* __DC_LINK_DP_PANEL_REPLAY_H__ */
\ No newline at end of file diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c index d6e91da72ef8..cb4129c0937a 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c @@ -50,11 +50,6 @@ static const uint8_t DP_VGA_LVDS_CONVERTER_ID_2[] = "sivarT"; /* Nutmeg */ static const uint8_t DP_VGA_LVDS_CONVERTER_ID_3[] = "dnomlA"; -static const unsigned int pwr_default_min_brightness_millinits = 1000; -static const unsigned int pwr_default_sdr_brightness_millinits = 270000; -static const unsigned int pwr_default_min_backlight_pwm = 0xC0C; -static const unsigned int pwr_default_max_backlight_pwm = 0xFFFF; - void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode) { union dpcd_edp_config edp_config_set; @@ -313,7 +308,7 @@ static bool read_default_bl_aux(struct dc_link *link, uint32_t *backlight_millin return true; } -bool set_default_brightness(struct dc_link *link) +bool set_default_brightness_aux(struct dc_link *link) { uint32_t default_backlight; @@ -324,23 +319,8 @@ bool set_default_brightness(struct dc_link *link) if (default_backlight < 1000 || default_backlight > 5000000) default_backlight = 150000; - if (link->backlight_control_type == BACKLIGHT_CONTROL_VESA_AUX && - link->dc->caps.dmub_caps.aux_backlight_support) { - struct set_backlight_level_params backlight_level_params = { 0 }; - - backlight_level_params.aux_inst = link->ddc->ddc_pin->hw_info.ddc_channel; - backlight_level_params.control_type = BACKLIGHT_CONTROL_VESA_AUX; - backlight_level_params.backlight_pwm_u16_16 = default_backlight; - backlight_level_params.transition_time_in_ms = 0; - // filled in the driver BL default values - backlight_level_params.min_luminance = pwr_default_min_brightness_millinits; - backlight_level_params.max_luminance = pwr_default_sdr_brightness_millinits; - backlight_level_params.min_backlight_pwm = pwr_default_min_backlight_pwm; - backlight_level_params.max_backlight_pwm = pwr_default_max_backlight_pwm; - return edp_set_backlight_level(link, &backlight_level_params); - } else - return edp_set_backlight_level_nits(link, true, - default_backlight, 0); + return edp_set_backlight_level_nits(link, true, + default_backlight, 0); } return false; } @@ -1003,116 +983,8 @@ bool edp_get_replay_state(const struct dc_link *link, uint64_t *state) return true; } -static bool edp_setup_panel_replay(struct dc_link *link, const struct dc_stream_state *stream) -{ - /* To-do: Setup Replay */ - struct dc *dc; - struct dmub_replay *replay; - int i; - unsigned int panel_inst; - struct replay_context replay_context = { 0 }; - unsigned int lineTimeInNs = 0; - - union panel_replay_enable_and_configuration_1 pr_config_1 = { 0 }; - union panel_replay_enable_and_configuration_2 pr_config_2 = { 0 }; - - union dpcd_alpm_configuration alpm_config; - - replay_context.controllerId = CONTROLLER_ID_UNDEFINED; - - if (!link) - return false; - - //Clear Panel Replay enable & config - dm_helpers_dp_write_dpcd(link->ctx, link, - DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_1, - (uint8_t *)&(pr_config_1.raw), sizeof(uint8_t)); - - dm_helpers_dp_write_dpcd(link->ctx, link, - DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2, - (uint8_t *)&(pr_config_2.raw), sizeof(uint8_t)); - - if (!(link->replay_settings.config.replay_supported)) - return false; - - dc = link->ctx->dc; - - //not sure should keep or not - replay = dc->res_pool->replay; - - if (!replay) - return false; - - if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) - return false; - - replay_context.aux_inst = link->ddc->ddc_pin->hw_info.ddc_channel; - replay_context.digbe_inst = link->link_enc->transmitter; - replay_context.digfe_inst = link->link_enc->preferred_engine; - - for (i = 0; i < MAX_PIPES; i++) { - if (dc->current_state->res_ctx.pipe_ctx[i].stream - == stream) { - /* dmcu -1 for all controller id values, - * therefore +1 here - */ - replay_context.controllerId = - dc->current_state->res_ctx.pipe_ctx[i].stream_res.tg->inst + 1; - break; - } - } - - lineTimeInNs = - ((stream->timing.h_total * 1000000) / - (stream->timing.pix_clk_100hz / 10)) + 1; - - replay_context.line_time_in_ns = lineTimeInNs; - - link->replay_settings.replay_feature_enabled = edp_pr_copy_settings(link, &replay_context); - - if (link->replay_settings.replay_feature_enabled) { - pr_config_1.bits.PANEL_REPLAY_ENABLE = 1; - pr_config_1.bits.PANEL_REPLAY_CRC_ENABLE = 1; - pr_config_1.bits.IRQ_HPD_ASSDP_MISSING = 1; - pr_config_1.bits.IRQ_HPD_VSCSDP_UNCORRECTABLE_ERROR = 1; - pr_config_1.bits.IRQ_HPD_RFB_ERROR = 1; - pr_config_1.bits.IRQ_HPD_ACTIVE_FRAME_CRC_ERROR = 1; - pr_config_1.bits.PANEL_REPLAY_SELECTIVE_UPDATE_ENABLE = 1; - pr_config_1.bits.PANEL_REPLAY_EARLY_TRANSPORT_ENABLE = 1; - - pr_config_2.bits.SINK_REFRESH_RATE_UNLOCK_GRANTED = 0; - pr_config_2.bits.SU_Y_GRANULARITY_EXT_VALUE_ENABLED = 0; - pr_config_2.bits.SU_REGION_SCAN_LINE_CAPTURE_INDICATION = 0; - - dm_helpers_dp_write_dpcd(link->ctx, link, - DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_1, - (uint8_t *)&(pr_config_1.raw), sizeof(uint8_t)); - - dm_helpers_dp_write_dpcd(link->ctx, link, - DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2, - (uint8_t *)&(pr_config_2.raw), sizeof(uint8_t)); - - //ALPM Setup - memset(&alpm_config, 0, sizeof(alpm_config)); - alpm_config.bits.ENABLE = link->replay_settings.config.alpm_mode != DC_ALPM_UNSUPPORTED ? 1 : 0; - - if (link->replay_settings.config.alpm_mode == DC_ALPM_AUXLESS) { - alpm_config.bits.ALPM_MODE_SEL = 1; - alpm_config.bits.ACDS_PERIOD_DURATION = 1; - } - - dm_helpers_dp_write_dpcd( - link->ctx, - link, - DP_RECEIVER_ALPM_CONFIG, - &alpm_config.raw, - sizeof(alpm_config.raw)); - } - - return true; -} -static bool edp_setup_freesync_replay(struct dc_link *link, const struct dc_stream_state *stream) +bool edp_setup_freesync_replay(struct dc_link *link, const struct dc_stream_state *stream) { /* To-do: Setup Replay */ struct dc *dc; @@ -1208,17 +1080,6 @@ static bool edp_setup_freesync_replay(struct dc_link *link, const struct dc_stre return true; } -bool edp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream) -{ - if (!link) - return false; - if (link->replay_settings.config.replay_version == DC_VESA_PANEL_REPLAY) - return edp_setup_panel_replay(link, stream); - else if (link->replay_settings.config.replay_version == DC_FREESYNC_REPLAY) - return edp_setup_freesync_replay(link, stream); - else - return false; -} /* * This is general Interface for Replay to set an 32 bit variable to dmub @@ -1323,156 +1184,6 @@ bool edp_set_replay_power_opt_and_coasting_vtotal(struct dc_link *link, return true; } -bool edp_pr_enable(struct dc_link *link, bool enable) -{ - struct dc *dc = link->ctx->dc; - unsigned int panel_inst = 0; - union dmub_rb_cmd cmd; - - if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) - return false; - - if (link->replay_settings.replay_allow_active != enable) { - //for sending PR enable commands to DMUB - memset(&cmd, 0, sizeof(cmd)); - - cmd.pr_enable.header.type = DMUB_CMD__PR; - cmd.pr_enable.header.sub_type = DMUB_CMD__PR_ENABLE; - cmd.pr_enable.header.payload_bytes = sizeof(struct dmub_cmd_pr_enable_data); - cmd.pr_enable.data.panel_inst = panel_inst; - cmd.pr_enable.data.enable = enable ? 1 : 0; - - dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); - - link->replay_settings.replay_allow_active = enable; - } - return true; -} - -bool edp_pr_copy_settings(struct dc_link *link, struct replay_context *replay_context) -{ - struct dc *dc = link->ctx->dc; - unsigned int panel_inst = 0; - union dmub_rb_cmd cmd; - struct pipe_ctx *pipe_ctx = NULL; - - if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) - return false; - - for (unsigned int i = 0; i < MAX_PIPES; i++) { - if (dc->current_state->res_ctx.pipe_ctx[i].stream && - dc->current_state->res_ctx.pipe_ctx[i].stream->link && - dc->current_state->res_ctx.pipe_ctx[i].stream->link == link && - dc->current_state->res_ctx.pipe_ctx[i].stream->link->connector_signal == SIGNAL_TYPE_EDP) { - pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; - //TODO: refactor for multi edp support - break; - } - } - - if (!pipe_ctx) - return false; - - memset(&cmd, 0, sizeof(cmd)); - cmd.pr_copy_settings.header.type = DMUB_CMD__PR; - cmd.pr_copy_settings.header.sub_type = DMUB_CMD__PR_COPY_SETTINGS; - cmd.pr_copy_settings.header.payload_bytes = sizeof(struct dmub_cmd_pr_copy_settings_data); - cmd.pr_copy_settings.data.panel_inst = panel_inst; - // HW inst - cmd.pr_copy_settings.data.aux_inst = replay_context->aux_inst; - cmd.pr_copy_settings.data.digbe_inst = replay_context->digbe_inst; - cmd.pr_copy_settings.data.digfe_inst = replay_context->digfe_inst; - if (pipe_ctx->plane_res.dpp) - cmd.pr_copy_settings.data.dpp_inst = pipe_ctx->plane_res.dpp->inst; - else - cmd.pr_copy_settings.data.dpp_inst = 0; - if (pipe_ctx->stream_res.tg) - cmd.pr_copy_settings.data.otg_inst = pipe_ctx->stream_res.tg->inst; - else - cmd.pr_copy_settings.data.otg_inst = 0; - - cmd.pr_copy_settings.data.dpphy_inst = link->link_enc->transmitter; - - cmd.pr_copy_settings.data.line_time_in_ns = replay_context->line_time_in_ns; - cmd.pr_copy_settings.data.flags.bitfields.fec_enable_status = (link->fec_state == dc_link_fec_enabled); - cmd.pr_copy_settings.data.flags.bitfields.dsc_enable_status = (pipe_ctx->stream->timing.flags.DSC == 1); - cmd.pr_copy_settings.data.debug.u32All = link->replay_settings.config.debug_flags; - - dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); - return true; -} - -bool edp_pr_update_state(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data) -{ - struct dc *dc = link->ctx->dc; - unsigned int panel_inst = 0; - union dmub_rb_cmd cmd; - - if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) - return false; - - memset(&cmd, 0, sizeof(cmd)); - cmd.pr_update_state.header.type = DMUB_CMD__PR; - cmd.pr_update_state.header.sub_type = DMUB_CMD__PR_UPDATE_STATE; - cmd.pr_update_state.header.payload_bytes = sizeof(struct dmub_cmd_pr_update_state_data); - cmd.pr_update_state.data.panel_inst = panel_inst; - - memcpy(&cmd.pr_update_state.data, update_state_data, sizeof(struct dmub_cmd_pr_update_state_data)); - - dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); - return true; -} - -bool edp_pr_set_general_cmd(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data) -{ - struct dc *dc = link->ctx->dc; - unsigned int panel_inst = 0; - union dmub_rb_cmd cmd; - - if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) - return false; - - memset(&cmd, 0, sizeof(cmd)); - cmd.pr_general_cmd.header.type = DMUB_CMD__PR; - cmd.pr_general_cmd.header.sub_type = DMUB_CMD__PR_GENERAL_CMD; - cmd.pr_general_cmd.header.payload_bytes = sizeof(struct dmub_cmd_pr_general_cmd_data); - cmd.pr_general_cmd.data.panel_inst = panel_inst; - - memcpy(&cmd.pr_general_cmd.data, general_cmd_data, sizeof(struct dmub_cmd_pr_general_cmd_data)); - - dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); - return true; -} - -bool edp_pr_get_state(const struct dc_link *link, uint64_t *state) -{ - const struct dc *dc = link->ctx->dc; - unsigned int panel_inst = 0; - uint32_t retry_count = 0; - uint32_t replay_state = 0; - - if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) - return false; - - do { - // Send gpint command and wait for ack - if (!dc_wake_and_execute_gpint(dc->ctx, DMUB_GPINT__GET_REPLAY_STATE, panel_inst, - &replay_state, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) { - // Return invalid state when GPINT times out - replay_state = PR_STATE_INVALID; - } - /* Copy 32-bit result into 64-bit output */ - *state = replay_state; - } while (++retry_count <= 1000 && *state == PR_STATE_INVALID); - - // Assert if max retry hit - if (retry_count >= 1000 && *state == PR_STATE_INVALID) { - ASSERT(0); - /* To-do: Add retry fail log */ - } - - return true; -} static struct abm *get_abm_from_stream_res(const struct dc_link *link) { diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h index fd63b5d0f948..8fdb76d9953e 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h @@ -29,7 +29,7 @@ enum dp_panel_mode dp_get_panel_mode(struct dc_link *link); void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode); -bool set_default_brightness(struct dc_link *link); +bool set_default_brightness_aux(struct dc_link *link); bool is_smartmux_suported(struct dc_link *link); void edp_panel_backlight_power_on(struct dc_link *link, bool wait_for_hpd); int edp_get_backlight_level(const struct dc_link *link); @@ -54,8 +54,6 @@ bool edp_set_sink_vtotal_in_psr_active(const struct dc_link *link, void edp_get_psr_residency(const struct dc_link *link, uint32_t *residency, enum psr_residency_mode mode); bool edp_set_replay_allow_active(struct dc_link *dc_link, const bool *enable, bool wait, bool force_static, const unsigned int *power_opts); -bool edp_setup_replay(struct dc_link *link, - const struct dc_stream_state *stream); bool edp_send_replay_cmd(struct dc_link *link, enum replay_FW_Message_type msg, union dmub_replay_cmd_set *cmd_data); @@ -75,11 +73,7 @@ void edp_add_delay_for_T9(struct dc_link *link); bool edp_receiver_ready_T9(struct dc_link *link); bool edp_receiver_ready_T7(struct dc_link *link); bool edp_power_alpm_dpcd_enable(struct dc_link *link, bool enable); -bool edp_pr_enable(struct dc_link *link, bool enable); -bool edp_pr_copy_settings(struct dc_link *link, struct replay_context *replay_context); -bool edp_pr_update_state(struct dc_link *link, struct dmub_cmd_pr_update_state_data *update_state_data); -bool edp_pr_set_general_cmd(struct dc_link *link, struct dmub_cmd_pr_general_cmd_data *general_cmd_data); -bool edp_pr_get_state(const struct dc_link *link, uint64_t *state); +bool edp_setup_freesync_replay(struct dc_link *link, const struct dc_stream_state *stream); void edp_set_panel_power(struct dc_link *link, bool powerOn); void edp_set_panel_assr(struct dc_link *link, struct pipe_ctx *pipe_ctx, enum dp_panel_mode *panel_mode, bool enable); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c index 0d667b54ccf8..e853ea110310 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c @@ -2250,12 +2250,15 @@ enum dc_status dcn31_update_dc_state_for_encoder_switch(struct dc_link *link, int i; #if defined(CONFIG_DRM_AMD_DC_FP) - for (i = 0; i < state->stream_count; i++) - if (state->streams[i] && state->streams[i]->link && state->streams[i]->link == link) - link->dc->hwss.calculate_pix_rate_divider((struct dc *)link->dc, state, state->streams[i]); + if (link->dc->hwss.calculate_pix_rate_divider) { + for (i = 0; i < state->stream_count; i++) + if (state->streams[i] && state->streams[i]->link && state->streams[i]->link == link) + link->dc->hwss.calculate_pix_rate_divider((struct dc *)link->dc, state, state->streams[i]); + } for (i = 0; i < pipe_count; i++) { - link->dc->res_pool->funcs->build_pipe_pix_clk_params(&pipes[i]); + if (link->dc->res_pool->funcs->build_pipe_pix_clk_params) + link->dc->res_pool->funcs->build_pipe_pix_clk_params(&pipes[i]); // Setup audio if (pipes[i].stream_res.audio != NULL) 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 6c599559c5da..9d0852760e78 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -1091,7 +1091,10 @@ union dmub_fw_boot_options { uint32_t lower_hbr3_phy_ssc: 1; /**< 1 to lower hbr3 phy ssc to 0.125 percent */ uint32_t override_hbr3_pll_vco: 1; /**< 1 to override the hbr3 pll vco to 0 */ uint32_t disable_dpia_bw_allocation: 1; /**< 1 to disable the USB4 DPIA BW allocation */ - uint32_t reserved : 4; /**< reserved */ + uint32_t bootcrc_en_at_preos: 1; /**< 1 to run the boot time crc during warm/cold boot*/ + uint32_t bootcrc_en_at_S0i3: 1; /**< 1 to run the boot time crc during S0i3 boot*/ + uint32_t bootcrc_boot_mode: 1; /**< 1 for S0i3 resume and 0 for Warm/cold boot*/ + uint32_t reserved : 1; /**< reserved */ } bits; /**< boot bits */ uint32_t all; /**< 32-bit access to bits */ }; @@ -2638,7 +2641,7 @@ union dmub_fams2_global_feature_config { uint32_t enable_visual_confirm: 1; uint32_t allow_delay_check_mode: 2; uint32_t legacy_method_no_fams2 : 1; - uint32_t reserved: 23; + uint32_t reserved : 23; } bits; uint32_t all; }; @@ -4335,10 +4338,6 @@ enum dmub_cmd_replay_type { */ DMUB_CMD__REPLAY_DISABLED_ADAPTIVE_SYNC_SDP = 8, /** - * Set version - */ - DMUB_CMD__REPLAY_SET_VERSION = 9, - /** * Set Replay General command. */ DMUB_CMD__REPLAY_SET_GENERAL_CMD = 16, @@ -4379,6 +4378,7 @@ enum dmub_cmd_replay_general_subtype { REPLAY_GENERAL_CMD_UPDATE_ERROR_STATUS, REPLAY_GENERAL_CMD_SET_LOW_RR_ACTIVATE, REPLAY_GENERAL_CMD_VIDEO_CONFERENCING, + REPLAY_GENERAL_CMD_SET_CONTINUOUSLY_RESYNC, }; struct dmub_alpm_auxless_data { @@ -4506,40 +4506,6 @@ enum replay_version { }; /** - * Data passed from driver to FW in a DMUB_CMD___SET_REPLAY_VERSION command. - */ -struct dmub_cmd_replay_set_version_data { - /** - * Panel Instance. - * Panel instance to identify which psr_state to use - * Currently the support is only for 0 or 1 - */ - uint8_t panel_inst; - /** - * Replay version that FW should implement. - */ - enum replay_version version; - /** - * Explicit padding to 4 byte boundary. - */ - uint8_t pad[3]; -}; - -/** - * Definition of a DMUB_CMD__REPLAY_SET_VERSION command. - */ -struct dmub_rb_cmd_replay_set_version { - /** - * Command header. - */ - struct dmub_cmd_header header; - /** - * Data passed from driver to FW in a DMUB_CMD__REPLAY_SET_VERSION command. - */ - struct dmub_cmd_replay_set_version_data replay_set_version_data; -}; - -/** * Definition of a DMUB_CMD__REPLAY_COPY_SETTINGS command. */ struct dmub_rb_cmd_replay_copy_settings { @@ -4930,10 +4896,6 @@ union dmub_replay_cmd_set { */ struct dmub_cmd_replay_disabled_adaptive_sync_sdp_data disabled_adaptive_sync_sdp_data; /** - * Definition of DMUB_CMD__REPLAY_SET_VERSION command data. - */ - struct dmub_cmd_replay_set_version_data version_data; - /** * Definition of DMUB_CMD__REPLAY_SET_GENERAL_CMD command data. */ struct dmub_cmd_replay_set_general_cmd_data set_general_cmd_data; @@ -7020,10 +6982,6 @@ union dmub_rb_cmd { * Definition of a DMUB_CMD__IDLE_OPT_SET_DC_POWER_STATE command. */ struct dmub_rb_cmd_idle_opt_set_dc_power_state idle_opt_set_dc_power_state; - /** - * Definition of a DMUB_CMD__REPLAY_SET_VERSION command. - */ - struct dmub_rb_cmd_replay_set_version replay_set_version; /* * Definition of a DMUB_CMD__REPLAY_COPY_SETTINGS command. */ diff --git a/drivers/gpu/drm/amd/display/include/dpcd_defs.h b/drivers/gpu/drm/amd/display/include/dpcd_defs.h index 8445c540f042..7d8359a7d99d 100644 --- a/drivers/gpu/drm/amd/display/include/dpcd_defs.h +++ b/drivers/gpu/drm/amd/display/include/dpcd_defs.h @@ -37,6 +37,21 @@ #ifndef DP_PANEL_REPLAY_CAPABILITY // can remove this once the define gets into linux drm_dp_helper.h #define DP_PANEL_REPLAY_CAPABILITY 0x0b1 #endif /* DP_PANEL_REPLAY_CAPABILITY */ +#ifndef DP_PR_SU_X_GRANULARITY_LOW // can remove this once the define gets into linux drm_dp_helper.h +#define DP_PR_SU_X_GRANULARITY_LOW 0x0b2 +#endif /* DP_PR_SU_X_GRANULARITY_LOW */ +#ifndef DP_PR_SU_X_GRANULARITY_HIGH // can remove this once the define gets into linux drm_dp_helper.h +#define DP_PR_SU_X_GRANULARITY_HIGH 0x0b3 +#endif /* DP_PR_SU_X_GRANULARITY_HIGH */ +#ifndef DP_PR_SU_Y_GRANULARITY // can remove this once the define gets into linux drm_dp_helper.h +#define DP_PR_SU_Y_GRANULARITY 0x0b4 +#endif /* DP_PR_SU_Y_GRANULARITY */ +#ifndef DP_PR_SU_Y_GRANULARITY_EXTENDED_CAP_LOW // can remove this once the define gets into linux drm_dp_helper.h +#define DP_PR_SU_Y_GRANULARITY_EXTENDED_CAP_LOW 0x0b5 +#endif /* DP_PR_SU_Y_GRANULARITY_EXTENDED_CAP_LOW */ +#ifndef DP_PR_SU_Y_GRANULARITY_EXTENDED_CAP_HIGH // can remove this once the define gets into linux drm_dp_helper.h +#define DP_PR_SU_Y_GRANULARITY_EXTENDED_CAP_HIGH 0x0b6 +#endif /* DP_PR_SU_Y_GRANULARITY_EXTENDED_CAP_HIGH */ #ifndef DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_1 // can remove this once the define gets into linux drm_dp_helper.h #define DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_1 0x1b0 #endif /* DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_1 */ @@ -46,6 +61,21 @@ #ifndef DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2 // can remove this once the define gets into linux drm_dp_helper.h #define DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2 0x1b1 #endif /* DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2 */ +#ifndef DP_PR_ERROR_STATUS // can remove this once the define gets into linux drm_dp_helper.h +#define DP_PR_ERROR_STATUS 0x2020 /* DP 2.0 */ +#endif /* DP_PR_ERROR_STATUS */ +#ifndef DP_PR_LINK_CRC_ERROR // can remove this once the define gets into linux drm_dp_helper.h +#define DP_PR_LINK_CRC_ERROR (1 << 0) +#endif /* DP_PR_LINK_CRC_ERROR */ +#ifndef DP_PR_RFB_STORAGE_ERROR // can remove this once the define gets into linux drm_dp_helper.h +#define DP_PR_RFB_STORAGE_ERROR (1 << 1) +#endif /* DP_PR_RFB_STORAGE_ERROR */ +#ifndef DP_PR_VSC_SDP_UNCORRECTABLE_ERROR // can remove this once the define gets into linux drm_dp_helper.h +#define DP_PR_VSC_SDP_UNCORRECTABLE_ERROR (1 << 2) /* eDP 1.4 */ +#endif /* DP_PR_VSC_SDP_UNCORRECTABLE_ERROR */ +#ifndef DP_PR_ASSDP_MISSING_ERROR // can remove this once the define gets into linux drm_dp_helper.h +#define DP_PR_ASSDP_MISSING_ERROR (1 << 3) /* eDP 1.5 */ +#endif /* DP_PR_ASSDP_MISSING_ERROR */ enum dpcd_revision { DPCD_REV_10 = 0x10, diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 8284f74b6c54..6b6b05e8f736 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -826,8 +826,6 @@ static int smu_early_init(struct amdgpu_ip_block *ip_block) smu->user_dpm_profile.fan_mode = -1; smu->power_profile_mode = PP_SMC_POWER_PROFILE_UNKNOWN; - mutex_init(&smu->message_lock); - adev->powerplay.pp_handle = smu; adev->powerplay.pp_funcs = &swsmu_pm_funcs; diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h index 99dd0f4d399a..1def04826f10 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -551,6 +551,86 @@ struct cmn2asic_mapping { int map_to; }; +#define SMU_MSG_MAX_ARGS 4 + +/* Message flags for smu_msg_args */ +#define SMU_MSG_FLAG_ASYNC BIT(0) /* Async send - skip post-poll */ +#define SMU_MSG_FLAG_LOCK_HELD BIT(1) /* Caller holds ctl->lock */ + +/* smu_msg_ctl flags */ +#define SMU_MSG_CTL_DEBUG_MAILBOX BIT(0) /* Debug mailbox supported */ + +struct smu_msg_ctl; +/** + * struct smu_msg_config - IP-level register configuration + * @msg_reg: Message register offset + * @resp_reg: Response register offset + * @arg_regs: Argument register offsets (up to SMU_MSG_MAX_ARGS) + * @num_arg_regs: Number of argument registers available + * @debug_msg_reg: Debug message register offset + * @debug_resp_reg: Debug response register offset + * @debug_param_reg: Debug parameter register offset + */ +struct smu_msg_config { + u32 msg_reg; + u32 resp_reg; + u32 arg_regs[SMU_MSG_MAX_ARGS]; + int num_arg_regs; + u32 debug_msg_reg; + u32 debug_resp_reg; + u32 debug_param_reg; +}; + +/** + * struct smu_msg_args - Per-call message arguments + * @msg: Common message type (enum smu_message_type) + * @args: Input arguments + * @num_args: Number of input arguments + * @out_args: Output arguments (filled after successful send) + * @num_out_args: Number of output arguments to read + * @flags: Message flags (SMU_MSG_FLAG_*) + * @timeout: Per-message timeout in us (0 = use default) + */ +struct smu_msg_args { + enum smu_message_type msg; + u32 args[SMU_MSG_MAX_ARGS]; + int num_args; + u32 out_args[SMU_MSG_MAX_ARGS]; + int num_out_args; + u32 flags; + u32 timeout; +}; + +/** + * struct smu_msg_ops - IP-level protocol operations + * @send_msg: send message protocol + * @wait_response: wait for response (for split send/wait cases) + * @decode_response: Convert response register value to errno + * @send_debug_msg: send debug message + */ +struct smu_msg_ops { + int (*send_msg)(struct smu_msg_ctl *ctl, struct smu_msg_args *args); + int (*wait_response)(struct smu_msg_ctl *ctl, u32 timeout_us); + int (*decode_response)(u32 resp); + int (*send_debug_msg)(struct smu_msg_ctl *ctl, u32 msg, u32 param); +}; + +/** + * struct smu_msg_ctl - Per-device message control block + * This is a standalone control block that encapsulates everything + * needed for SMU messaging. The ops->send_msg implements the complete + * protocol including all filtering and error handling. + */ +struct smu_msg_ctl { + struct smu_context *smu; + struct mutex lock; + struct smu_msg_config config; + const struct smu_msg_ops *ops; + const struct cmn2asic_msg_mapping *message_map; + u32 default_timeout; + u32 flags; +}; + struct stb_context { uint32_t stb_buf_size; bool enabled; @@ -587,13 +667,11 @@ struct smu_context { struct amdgpu_irq_src irq_source; const struct pptable_funcs *ppt_funcs; - const struct cmn2asic_msg_mapping *message_map; const struct cmn2asic_mapping *clock_map; const struct cmn2asic_mapping *feature_map; const struct cmn2asic_mapping *table_map; const struct cmn2asic_mapping *pwr_src_map; const struct cmn2asic_mapping *workload_map; - struct mutex message_lock; uint64_t pool_size; struct smu_table_context smu_table; @@ -677,20 +755,15 @@ struct smu_context { struct firmware pptable_firmware; - u32 param_reg; - u32 msg_reg; - u32 resp_reg; - - u32 debug_param_reg; - u32 debug_msg_reg; - u32 debug_resp_reg; - struct delayed_work swctf_delayed_work; /* data structures for wbrf feature support */ bool wbrf_supported; struct notifier_block wbrf_notifier; struct delayed_work wbrf_delayed_work; + + /* SMU message control block */ + struct smu_msg_ctl msg_ctl; }; struct i2c_adapter; @@ -757,15 +830,6 @@ struct pptable_funcs { int (*populate_umd_state_clk)(struct smu_context *smu); /** - * @print_clk_levels: Print DPM clock levels for a clock domain - * to buffer. Star current level. - * - * Used for sysfs interfaces. - * Return: Number of characters written to the buffer - */ - int (*print_clk_levels)(struct smu_context *smu, enum smu_clk_type clk_type, char *buf); - - /** * @emit_clk_levels: Print DPM clock levels for a clock domain * to buffer using sysfs_emit_at. Star current level. * @@ -1123,24 +1187,6 @@ struct pptable_funcs { int (*system_features_control)(struct smu_context *smu, bool en); /** - * @send_smc_msg_with_param: Send a message with a parameter to the SMU. - * &msg: Type of message. - * ¶m: Message parameter. - * &read_arg: SMU response (optional). - */ - int (*send_smc_msg_with_param)(struct smu_context *smu, - enum smu_message_type msg, uint32_t param, uint32_t *read_arg); - - /** - * @send_smc_msg: Send a message to the SMU. - * &msg: Type of message. - * &read_arg: SMU response (optional). - */ - int (*send_smc_msg)(struct smu_context *smu, - enum smu_message_type msg, - uint32_t *read_arg); - - /** * @init_display_count: Notify the SMU of the number of display * components in current display configuration. */ diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h index d18934c6fbd5..7c1701ed3e11 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h @@ -282,7 +282,8 @@ int smu_v11_0_handle_passthrough_sbr(struct smu_context *smu, bool enable); int smu_v11_0_restore_user_od_settings(struct smu_context *smu); -void smu_v11_0_set_smu_mailbox_registers(struct smu_context *smu); +void smu_v11_0_init_msg_ctl(struct smu_context *smu, + const struct cmn2asic_msg_mapping *message_map); #endif #endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v12_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v12_0.h index 0886d8cffbd0..fd3937b08662 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v12_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v12_0.h @@ -62,5 +62,8 @@ int smu_v12_0_set_driver_table_location(struct smu_context *smu); int smu_v12_0_get_vbios_bootup_values(struct smu_context *smu); +void smu_v12_0_init_msg_ctl(struct smu_context *smu, + const struct cmn2asic_msg_mapping *message_map); + #endif #endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h index c35cbb2aee93..efeaa3d57712 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h @@ -251,7 +251,8 @@ int smu_v13_0_od_edit_dpm_table(struct smu_context *smu, int smu_v13_0_set_default_dpm_tables(struct smu_context *smu); -void smu_v13_0_set_smu_mailbox_registers(struct smu_context *smu); +void smu_v13_0_init_msg_ctl(struct smu_context *smu, + const struct cmn2asic_msg_mapping *message_map); int smu_v13_0_mode1_reset(struct smu_context *smu); diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h index 4ecec85b8404..613d4d36f32f 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h @@ -215,10 +215,8 @@ int smu_v14_0_get_pptable_from_firmware(struct smu_context *smu, uint32_t pptable_id); int smu_v14_0_od_edit_dpm_table(struct smu_context *smu, - enum PP_OD_DPM_TABLE_COMMAND type, - long input[], uint32_t size); - -void smu_v14_0_set_smu_mailbox_registers(struct smu_context *smu); + enum PP_OD_DPM_TABLE_COMMAND type, + long input[], uint32_t size); int smu_v14_0_enable_thermal_alert(struct smu_context *smu); diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h index 9020317ffd69..14e8d8c7a80a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h @@ -237,8 +237,6 @@ int smu_v15_0_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABLE_COMMAND type, long input[], uint32_t size); -void smu_v15_0_set_smu_mailbox_registers(struct smu_context *smu); - int smu_v15_0_enable_thermal_alert(struct smu_context *smu); int smu_v15_0_disable_thermal_alert(struct smu_context *smu); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c index 81241976b53c..7c5ce6a6e2ca 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -1915,8 +1915,6 @@ static const struct pptable_funcs arcturus_ppt_funcs = { .set_tool_table_location = smu_v11_0_set_tool_table_location, .notify_memory_pool_location = smu_v11_0_notify_memory_pool_location, .system_features_control = smu_v11_0_system_features_control, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .init_display_count = NULL, .set_allowed_mask = smu_v11_0_set_allowed_mask, .get_enabled_mask = smu_cmn_get_enabled_mask, @@ -1959,11 +1957,10 @@ static const struct pptable_funcs arcturus_ppt_funcs = { void arcturus_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &arcturus_ppt_funcs; - smu->message_map = arcturus_message_map; smu->clock_map = arcturus_clk_map; smu->feature_map = arcturus_feature_mask_map; smu->table_map = arcturus_table_map; smu->pwr_src_map = arcturus_pwr_src_map; smu->workload_map = arcturus_workload_map; - smu_v11_0_set_smu_mailbox_registers(smu); + smu_v11_0_init_msg_ctl(smu, arcturus_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c index 51f0e299b840..4a5dcc893665 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c @@ -592,8 +592,6 @@ static const struct pptable_funcs cyan_skillfish_ppt_funcs = { .get_dpm_ultimate_freq = cyan_skillfish_get_dpm_ultimate_freq, .register_irq_handler = smu_v11_0_register_irq_handler, .notify_memory_pool_location = smu_v11_0_notify_memory_pool_location, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .set_driver_table_location = smu_v11_0_set_driver_table_location, .interrupt_work = smu_v11_0_interrupt_work, }; @@ -601,8 +599,7 @@ static const struct pptable_funcs cyan_skillfish_ppt_funcs = { void cyan_skillfish_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &cyan_skillfish_ppt_funcs; - smu->message_map = cyan_skillfish_message_map; smu->table_map = cyan_skillfish_table_map; smu->is_apu = true; - smu_v11_0_set_smu_mailbox_registers(smu); + smu_v11_0_init_msg_ctl(smu, cyan_skillfish_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c index 74f24618485a..1f84654bbc85 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -3319,8 +3319,6 @@ static const struct pptable_funcs navi10_ppt_funcs = { .set_tool_table_location = smu_v11_0_set_tool_table_location, .notify_memory_pool_location = smu_v11_0_notify_memory_pool_location, .system_features_control = smu_v11_0_system_features_control, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .init_display_count = smu_v11_0_init_display_count, .set_allowed_mask = smu_v11_0_set_allowed_mask, .get_enabled_mask = smu_cmn_get_enabled_mask, @@ -3369,11 +3367,10 @@ static const struct pptable_funcs navi10_ppt_funcs = { void navi10_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &navi10_ppt_funcs; - smu->message_map = navi10_message_map; smu->clock_map = navi10_clk_map; smu->feature_map = navi10_feature_mask_map; smu->table_map = navi10_table_map; smu->pwr_src_map = navi10_pwr_src_map; smu->workload_map = navi10_workload_map; - smu_v11_0_set_smu_mailbox_registers(smu); + smu_v11_0_init_msg_ctl(smu, navi10_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c index 3f3947dc52a9..f930ba2733e9 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c @@ -3043,21 +3043,21 @@ static int sienna_cichlid_stb_get_data_direct(struct smu_context *smu, static int sienna_cichlid_mode2_reset(struct smu_context *smu) { - int ret = 0, index; + struct smu_msg_ctl *ctl = &smu->msg_ctl; struct amdgpu_device *adev = smu->adev; + int ret = 0; int timeout = 100; - index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, - SMU_MSG_DriverMode2Reset); - - mutex_lock(&smu->message_lock); + mutex_lock(&ctl->lock); - ret = smu_cmn_send_msg_without_waiting(smu, (uint16_t)index, - SMU_RESET_MODE_2); + ret = smu_msg_send_async_locked(ctl, SMU_MSG_DriverMode2Reset, + SMU_RESET_MODE_2); + if (ret) + goto out; - ret = smu_cmn_wait_for_response(smu); + ret = smu_msg_wait_response(ctl, 0); while (ret != 0 && timeout) { - ret = smu_cmn_wait_for_response(smu); + ret = smu_msg_wait_response(ctl, 0); /* Wait a bit more time for getting ACK */ if (ret != 0) { --timeout; @@ -3075,11 +3075,11 @@ static int sienna_cichlid_mode2_reset(struct smu_context *smu) goto out; } - dev_info(smu->adev->dev, "restore config space...\n"); + dev_info(adev->dev, "restore config space...\n"); /* Restore the config space saved during init */ amdgpu_device_load_pci_state(adev->pdev); out: - mutex_unlock(&smu->message_lock); + mutex_unlock(&ctl->lock); return ret; } @@ -3126,8 +3126,6 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = { .set_tool_table_location = smu_v11_0_set_tool_table_location, .notify_memory_pool_location = smu_v11_0_notify_memory_pool_location, .system_features_control = sienna_cichlid_system_features_control, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .init_display_count = NULL, .set_allowed_mask = smu_v11_0_set_allowed_mask, .get_enabled_mask = smu_cmn_get_enabled_mask, @@ -3182,11 +3180,10 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = { void sienna_cichlid_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &sienna_cichlid_ppt_funcs; - smu->message_map = sienna_cichlid_message_map; smu->clock_map = sienna_cichlid_clk_map; smu->feature_map = sienna_cichlid_feature_mask_map; smu->table_map = sienna_cichlid_table_map; smu->pwr_src_map = sienna_cichlid_pwr_src_map; smu->workload_map = sienna_cichlid_workload_map; - smu_v11_0_set_smu_mailbox_registers(smu); + smu_v11_0_init_msg_ctl(smu, sienna_cichlid_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c index 3d03010abcc1..eb1b9faf8e5c 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c @@ -2168,11 +2168,19 @@ int smu_v11_0_restore_user_od_settings(struct smu_context *smu) return ret; } -void smu_v11_0_set_smu_mailbox_registers(struct smu_context *smu) +void smu_v11_0_init_msg_ctl(struct smu_context *smu, + const struct cmn2asic_msg_mapping *message_map) { struct amdgpu_device *adev = smu->adev; - - smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); - smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); - smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + struct smu_msg_ctl *ctl = &smu->msg_ctl; + + ctl->smu = smu; + mutex_init(&ctl->lock); + ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); + ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); + ctl->config.num_arg_regs = 1; + ctl->ops = &smu_msg_v1_ops; + ctl->default_timeout = adev->usec_timeout * 20; + ctl->message_map = message_map; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c index 65a0302ce875..4de1778ea6b3 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c @@ -2272,18 +2272,12 @@ static int vangogh_post_smu_init(struct smu_context *smu) static int vangogh_mode_reset(struct smu_context *smu, int type) { - int ret = 0, index = 0; - - index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, - SMU_MSG_GfxDeviceDriverReset); - if (index < 0) - return index == -EACCES ? 0 : index; - - mutex_lock(&smu->message_lock); - - ret = smu_cmn_send_msg_without_waiting(smu, (uint16_t)index, type); + struct smu_msg_ctl *ctl = &smu->msg_ctl; + int ret; - mutex_unlock(&smu->message_lock); + mutex_lock(&ctl->lock); + ret = smu_msg_send_async_locked(ctl, SMU_MSG_GfxDeviceDriverReset, type); + mutex_unlock(&ctl->lock); mdelay(10); @@ -2522,8 +2516,6 @@ static const struct pptable_funcs vangogh_ppt_funcs = { .fini_power = smu_v11_0_fini_power, .register_irq_handler = smu_v11_0_register_irq_handler, .notify_memory_pool_location = smu_v11_0_notify_memory_pool_location, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .dpm_set_vcn_enable = vangogh_dpm_set_vcn_enable, .dpm_set_jpeg_enable = vangogh_dpm_set_jpeg_enable, .is_dpm_running = vangogh_is_dpm_running, @@ -2563,10 +2555,9 @@ static const struct pptable_funcs vangogh_ppt_funcs = { void vangogh_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &vangogh_ppt_funcs; - smu->message_map = vangogh_message_map; smu->feature_map = vangogh_feature_mask_map; smu->table_map = vangogh_table_map; smu->workload_map = vangogh_workload_map; smu->is_apu = true; - smu_v11_0_set_smu_mailbox_registers(smu); + smu_v11_0_init_msg_ctl(smu, vangogh_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c index c72ddef3fce5..5346b60b09b9 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c @@ -41,15 +41,6 @@ #undef pr_info #undef pr_debug -#define mmMP1_SMN_C2PMSG_66 0x0282 -#define mmMP1_SMN_C2PMSG_66_BASE_IDX 0 - -#define mmMP1_SMN_C2PMSG_82 0x0292 -#define mmMP1_SMN_C2PMSG_82_BASE_IDX 0 - -#define mmMP1_SMN_C2PMSG_90 0x029a -#define mmMP1_SMN_C2PMSG_90_BASE_IDX 0 - static struct cmn2asic_msg_mapping renoir_message_map[SMU_MSG_MAX_COUNT] = { MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1), MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 1), @@ -1468,8 +1459,6 @@ static const struct pptable_funcs renoir_ppt_funcs = { .check_fw_status = smu_v12_0_check_fw_status, .check_fw_version = smu_v12_0_check_fw_version, .powergate_sdma = smu_v12_0_powergate_sdma, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .set_gfx_cgpg = smu_v12_0_set_gfx_cgpg, .gfx_off_control = smu_v12_0_gfx_off_control, .get_gfx_off_status = smu_v12_0_get_gfxoff_status, @@ -1495,16 +1484,11 @@ static const struct pptable_funcs renoir_ppt_funcs = { void renoir_set_ppt_funcs(struct smu_context *smu) { - struct amdgpu_device *adev = smu->adev; - smu->ppt_funcs = &renoir_ppt_funcs; - smu->message_map = renoir_message_map; smu->clock_map = renoir_clk_map; smu->table_map = renoir_table_map; smu->workload_map = renoir_workload_map; smu->smc_driver_if_version = SMU12_DRIVER_IF_VERSION; smu->is_apu = true; - smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); - smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); - smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + smu_v12_0_init_msg_ctl(smu, renoir_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c index 942bc3b0f700..2c20624caca4 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c @@ -405,3 +405,20 @@ int smu_v12_0_get_vbios_bootup_values(struct smu_context *smu) return 0; } + +void smu_v12_0_init_msg_ctl(struct smu_context *smu, + const struct cmn2asic_msg_mapping *message_map) +{ + struct amdgpu_device *adev = smu->adev; + struct smu_msg_ctl *ctl = &smu->msg_ctl; + + ctl->smu = smu; + mutex_init(&ctl->lock); + ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); + ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); + ctl->config.num_arg_regs = 1; + ctl->ops = &smu_msg_v1_ops; + ctl->default_timeout = adev->usec_timeout * 20; + ctl->message_map = message_map; +} diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index e999ee7d053e..9de0b676bb7b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -1828,26 +1828,28 @@ static int aldebaran_mode1_reset(struct smu_context *smu) static int aldebaran_mode2_reset(struct smu_context *smu) { - int ret = 0, index; + struct smu_msg_ctl *ctl = &smu->msg_ctl; struct amdgpu_device *adev = smu->adev; + int ret = 0; int timeout = 10; - index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, - SMU_MSG_GfxDeviceDriverReset); - if (index < 0 ) - return -EINVAL; - mutex_lock(&smu->message_lock); + mutex_lock(&ctl->lock); + if (smu->smc_fw_version >= 0x00441400) { - ret = smu_cmn_send_msg_without_waiting(smu, (uint16_t)index, SMU_RESET_MODE_2); + ret = smu_msg_send_async_locked(ctl, SMU_MSG_GfxDeviceDriverReset, + SMU_RESET_MODE_2); + if (ret) + goto out; + /* This is similar to FLR, wait till max FLR timeout */ msleep(100); - dev_dbg(smu->adev->dev, "restore config space...\n"); + dev_dbg(adev->dev, "restore config space...\n"); /* Restore the config space saved during init */ amdgpu_device_load_pci_state(adev->pdev); - dev_dbg(smu->adev->dev, "wait for reset ack\n"); + dev_dbg(adev->dev, "wait for reset ack\n"); while (ret == -ETIME && timeout) { - ret = smu_cmn_wait_for_response(smu); + ret = smu_msg_wait_response(ctl, 0); /* Wait a bit more time for getting ACK */ if (ret == -ETIME) { --timeout; @@ -1870,7 +1872,7 @@ static int aldebaran_mode2_reset(struct smu_context *smu) if (ret == 1) ret = 0; out: - mutex_unlock(&smu->message_lock); + mutex_unlock(&ctl->lock); return ret; } @@ -1994,8 +1996,6 @@ static const struct pptable_funcs aldebaran_ppt_funcs = { .set_tool_table_location = smu_v13_0_set_tool_table_location, .notify_memory_pool_location = smu_v13_0_notify_memory_pool_location, .system_features_control = aldebaran_system_features_control, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .get_enabled_mask = smu_cmn_get_enabled_mask, .feature_is_enabled = smu_cmn_feature_is_enabled, .disable_all_features_with_exception = smu_cmn_disable_all_features_with_exception, @@ -2032,10 +2032,9 @@ static const struct pptable_funcs aldebaran_ppt_funcs = { void aldebaran_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &aldebaran_ppt_funcs; - smu->message_map = aldebaran_message_map; smu->clock_map = aldebaran_clk_map; smu->feature_map = aldebaran_feature_mask_map; smu->table_map = aldebaran_table_map; smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_ALDE; - smu_v13_0_set_smu_mailbox_registers(smu); + smu_v13_0_init_msg_ctl(smu, aldebaran_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index bf00ed3f2848..51f96fdcec24 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -2244,18 +2244,21 @@ int smu_v13_0_baco_exit(struct smu_context *smu) int smu_v13_0_set_gfx_power_up_by_imu(struct smu_context *smu) { - uint16_t index; + struct smu_msg_ctl *ctl = &smu->msg_ctl; struct amdgpu_device *adev = smu->adev; + int ret; if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_EnableGfxImu, ENABLE_IMU_ARG_GFXOFF_ENABLE, NULL); } - index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, - SMU_MSG_EnableGfxImu); - return smu_cmn_send_msg_without_waiting(smu, index, - ENABLE_IMU_ARG_GFXOFF_ENABLE); + mutex_lock(&ctl->lock); + ret = smu_msg_send_async_locked(ctl, SMU_MSG_EnableGfxImu, + ENABLE_IMU_ARG_GFXOFF_ENABLE); + mutex_unlock(&ctl->lock); + + return ret; } int smu_v13_0_od_edit_dpm_table(struct smu_context *smu, @@ -2348,13 +2351,22 @@ int smu_v13_0_set_default_dpm_tables(struct smu_context *smu) smu_table->clocks_table, false); } -void smu_v13_0_set_smu_mailbox_registers(struct smu_context *smu) +void smu_v13_0_init_msg_ctl(struct smu_context *smu, + const struct cmn2asic_msg_mapping *message_map) { struct amdgpu_device *adev = smu->adev; - - smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); - smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); - smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + struct smu_msg_ctl *ctl = &smu->msg_ctl; + + ctl->smu = smu; + mutex_init(&ctl->lock); + ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); + ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); + ctl->config.num_arg_regs = 1; + ctl->ops = &smu_msg_v1_ops; + ctl->default_timeout = adev->usec_timeout * 20; + ctl->message_map = message_map; + ctl->flags = 0; } int smu_v13_0_mode1_reset(struct smu_context *smu) 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 91442e39aa79..ce52b616b935 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 @@ -70,15 +70,6 @@ #define MP0_MP1_DATA_REGION_SIZE_COMBOPPTABLE 0x4000 -#define mmMP1_SMN_C2PMSG_66 0x0282 -#define mmMP1_SMN_C2PMSG_66_BASE_IDX 0 - -#define mmMP1_SMN_C2PMSG_82 0x0292 -#define mmMP1_SMN_C2PMSG_82_BASE_IDX 0 - -#define mmMP1_SMN_C2PMSG_90 0x029a -#define mmMP1_SMN_C2PMSG_90_BASE_IDX 0 - #define mmMP1_SMN_C2PMSG_75 0x028b #define mmMP1_SMN_C2PMSG_75_BASE_IDX 0 @@ -2891,17 +2882,18 @@ static int smu_v13_0_0_enable_gfx_features(struct smu_context *smu) return -EOPNOTSUPP; } -static void smu_v13_0_0_set_smu_mailbox_registers(struct smu_context *smu) +static void smu_v13_0_0_init_msg_ctl(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; + struct smu_msg_ctl *ctl = &smu->msg_ctl; - smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); - smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); - smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + smu_v13_0_init_msg_ctl(smu, smu_v13_0_0_message_map); - smu->debug_param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_53); - smu->debug_msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_75); - smu->debug_resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_54); + /* Set up debug mailbox registers */ + ctl->config.debug_param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_53); + ctl->config.debug_msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_75); + ctl->config.debug_resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_54); + ctl->flags |= SMU_MSG_CTL_DEBUG_MAILBOX; } static int smu_v13_0_0_smu_send_bad_mem_page_num(struct smu_context *smu, @@ -3223,14 +3215,13 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = { void smu_v13_0_0_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &smu_v13_0_0_ppt_funcs; - smu->message_map = smu_v13_0_0_message_map; smu->clock_map = smu_v13_0_0_clk_map; smu->feature_map = smu_v13_0_0_feature_mask_map; smu->table_map = smu_v13_0_0_table_map; smu->pwr_src_map = smu_v13_0_0_pwr_src_map; smu->workload_map = smu_v13_0_0_workload_map; smu->smc_driver_if_version = SMU13_0_0_DRIVER_IF_VERSION; - smu_v13_0_0_set_smu_mailbox_registers(smu); + smu_v13_0_0_init_msg_ctl(smu); if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 10) && diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c index 4a99f585f071..41c61362f7fc 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c @@ -1101,8 +1101,6 @@ static const struct pptable_funcs smu_v13_0_4_ppt_funcs = { .fini_smc_tables = smu_v13_0_4_fini_smc_tables, .get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values, .system_features_control = smu_v13_0_4_system_features_control, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .dpm_set_vcn_enable = smu_v13_0_set_vcn_enable, .dpm_set_jpeg_enable = smu_v13_0_set_jpeg_enable, .set_default_dpm_table = smu_v13_0_set_default_dpm_tables, @@ -1124,13 +1122,20 @@ static const struct pptable_funcs smu_v13_0_4_ppt_funcs = { .set_gfx_power_up_by_imu = smu_v13_0_set_gfx_power_up_by_imu, }; -static void smu_v13_0_4_set_smu_mailbox_registers(struct smu_context *smu) +static void smu_v13_0_4_init_msg_ctl(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - - smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); - smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); - smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + struct smu_msg_ctl *ctl = &smu->msg_ctl; + + ctl->smu = smu; + mutex_init(&ctl->lock); + ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); + ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); + ctl->config.num_arg_regs = 1; + ctl->ops = &smu_msg_v1_ops; + ctl->default_timeout = adev->usec_timeout * 20; + ctl->message_map = smu_v13_0_4_message_map; } void smu_v13_0_4_set_ppt_funcs(struct smu_context *smu) @@ -1138,14 +1143,13 @@ void smu_v13_0_4_set_ppt_funcs(struct smu_context *smu) struct amdgpu_device *adev = smu->adev; smu->ppt_funcs = &smu_v13_0_4_ppt_funcs; - smu->message_map = smu_v13_0_4_message_map; smu->feature_map = smu_v13_0_4_feature_mask_map; smu->table_map = smu_v13_0_4_table_map; smu->smc_driver_if_version = SMU13_0_4_DRIVER_IF_VERSION; smu->is_apu = true; if (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 4)) - smu_v13_0_4_set_smu_mailbox_registers(smu); + smu_v13_0_4_init_msg_ctl(smu); else - smu_v13_0_set_smu_mailbox_registers(smu); + smu_v13_0_init_msg_ctl(smu, smu_v13_0_4_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c index f2e3c80ee203..e4be727789c0 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c @@ -1104,8 +1104,6 @@ static const struct pptable_funcs smu_v13_0_5_ppt_funcs = { .fini_smc_tables = smu_v13_0_5_fini_smc_tables, .get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values, .system_features_control = smu_v13_0_5_system_features_control, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .dpm_set_vcn_enable = smu_v13_0_5_dpm_set_vcn_enable, .dpm_set_jpeg_enable = smu_v13_0_5_dpm_set_jpeg_enable, .set_default_dpm_table = smu_v13_0_5_set_default_dpm_tables, @@ -1126,17 +1124,28 @@ static const struct pptable_funcs smu_v13_0_5_ppt_funcs = { .set_fine_grain_gfx_freq_parameters = smu_v13_0_5_set_fine_grain_gfx_freq_parameters, }; -void smu_v13_0_5_set_ppt_funcs(struct smu_context *smu) +static void smu_v13_0_5_init_msg_ctl(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; + struct smu_msg_ctl *ctl = &smu->msg_ctl; + + ctl->smu = smu; + mutex_init(&ctl->lock); + ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_2); + ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_33); + ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_34); + ctl->config.num_arg_regs = 1; + ctl->ops = &smu_msg_v1_ops; + ctl->default_timeout = adev->usec_timeout * 20; + ctl->message_map = smu_v13_0_5_message_map; +} +void smu_v13_0_5_set_ppt_funcs(struct smu_context *smu) +{ smu->ppt_funcs = &smu_v13_0_5_ppt_funcs; - smu->message_map = smu_v13_0_5_message_map; smu->feature_map = smu_v13_0_5_feature_mask_map; smu->table_map = smu_v13_0_5_table_map; smu->is_apu = true; smu->smc_driver_if_version = SMU13_0_5_DRIVER_IF_VERSION; - smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_34); - smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_2); - smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_C2PMSG_33); + smu_v13_0_5_init_msg_ctl(smu); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index 2c16da1065c8..1e82c43c851a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -2897,24 +2897,22 @@ static void smu_v13_0_6_restore_pci_config(struct smu_context *smu) static int smu_v13_0_6_mode2_reset(struct smu_context *smu) { - int ret = 0, index; + struct smu_msg_ctl *ctl = &smu->msg_ctl; struct amdgpu_device *adev = smu->adev; + int ret = 0; int timeout = 10; - index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, - SMU_MSG_GfxDeviceDriverReset); - if (index < 0) - return index; - - mutex_lock(&smu->message_lock); + mutex_lock(&ctl->lock); - ret = smu_cmn_send_msg_without_waiting(smu, (uint16_t)index, - SMU_RESET_MODE_2); + ret = smu_msg_send_async_locked(ctl, SMU_MSG_GfxDeviceDriverReset, + SMU_RESET_MODE_2); + if (ret) + goto out; /* Reset takes a bit longer, wait for 200ms. */ msleep(200); - dev_dbg(smu->adev->dev, "restore config space...\n"); + dev_dbg(adev->dev, "restore config space...\n"); /* Restore the config space saved during init */ amdgpu_device_load_pci_state(adev->pdev); @@ -2932,9 +2930,9 @@ static int smu_v13_0_6_mode2_reset(struct smu_context *smu) if (!(adev->flags & AMD_IS_APU)) smu_v13_0_6_restore_pci_config(smu); - dev_dbg(smu->adev->dev, "wait for reset ack\n"); + dev_dbg(adev->dev, "wait for reset ack\n"); do { - ret = smu_cmn_wait_for_response(smu); + ret = smu_msg_wait_response(ctl, 0); /* Wait a bit more time for getting ACK */ if (ret == -ETIME) { --timeout; @@ -2948,7 +2946,7 @@ static int smu_v13_0_6_mode2_reset(struct smu_context *smu) } while (ret == -ETIME && timeout); out: - mutex_unlock(&smu->message_lock); + mutex_unlock(&ctl->lock); if (ret) dev_err(adev->dev, "failed to send mode2 reset, error code %d", @@ -3862,8 +3860,6 @@ static const struct pptable_funcs smu_v13_0_6_ppt_funcs = { .set_tool_table_location = smu_v13_0_set_tool_table_location, .notify_memory_pool_location = smu_v13_0_notify_memory_pool_location, .system_features_control = smu_v13_0_6_system_features_control, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .get_enabled_mask = smu_v13_0_6_get_enabled_mask, .feature_is_enabled = smu_cmn_feature_is_enabled, .set_power_limit = smu_v13_0_6_set_power_limit, @@ -3901,8 +3897,10 @@ static const struct pptable_funcs smu_v13_0_6_ppt_funcs = { void smu_v13_0_6_set_ppt_funcs(struct smu_context *smu) { + const struct cmn2asic_msg_mapping *message_map; + smu->ppt_funcs = &smu_v13_0_6_ppt_funcs; - smu->message_map = (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12)) ? + message_map = (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12)) ? smu_v13_0_12_message_map : smu_v13_0_6_message_map; smu->clock_map = smu_v13_0_6_clk_map; smu->feature_map = (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12)) ? @@ -3910,7 +3908,7 @@ void smu_v13_0_6_set_ppt_funcs(struct smu_context *smu) smu->table_map = smu_v13_0_6_table_map; smu->smc_driver_if_version = SMU_IGNORE_IF_VERSION; smu->smc_fw_caps |= SMU_FW_CAP_RAS_PRI; - smu_v13_0_set_smu_mailbox_registers(smu); + smu_v13_0_init_msg_ctl(smu, message_map); smu_v13_0_6_set_temp_funcs(smu); amdgpu_mca_smu_init_funcs(smu->adev, &smu_v13_0_6_mca_smu_funcs); amdgpu_aca_set_smu_funcs(smu->adev, &smu_v13_0_6_aca_smu_funcs); 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 26f4e0383ace..0375e8484b2a 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 @@ -2809,12 +2809,11 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = { void smu_v13_0_7_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &smu_v13_0_7_ppt_funcs; - smu->message_map = smu_v13_0_7_message_map; smu->clock_map = smu_v13_0_7_clk_map; smu->feature_map = smu_v13_0_7_feature_mask_map; smu->table_map = smu_v13_0_7_table_map; smu->pwr_src_map = smu_v13_0_7_pwr_src_map; smu->workload_map = smu_v13_0_7_workload_map; smu->smc_driver_if_version = SMU13_0_7_DRIVER_IF_VERSION; - smu_v13_0_set_smu_mailbox_registers(smu); + smu_v13_0_init_msg_ctl(smu, smu_v13_0_7_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c index 358fe97ceea3..7f70f79c3b2f 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c @@ -1333,8 +1333,6 @@ static const struct pptable_funcs yellow_carp_ppt_funcs = { .fini_smc_tables = yellow_carp_fini_smc_tables, .get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values, .system_features_control = yellow_carp_system_features_control, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .dpm_set_vcn_enable = yellow_carp_dpm_set_vcn_enable, .dpm_set_jpeg_enable = yellow_carp_dpm_set_jpeg_enable, .set_default_dpm_table = yellow_carp_set_default_dpm_tables, @@ -1360,10 +1358,9 @@ static const struct pptable_funcs yellow_carp_ppt_funcs = { void yellow_carp_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &yellow_carp_ppt_funcs; - smu->message_map = yellow_carp_message_map; smu->feature_map = yellow_carp_feature_mask_map; smu->table_map = yellow_carp_table_map; smu->is_apu = true; smu->smc_driver_if_version = SMU13_YELLOW_CARP_DRIVER_IF_VERSION; - smu_v13_0_set_smu_mailbox_registers(smu); + smu_v13_0_init_msg_ctl(smu, yellow_carp_message_map); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c index 8f7f293de3d8..f85ba23f9d99 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c @@ -1834,17 +1834,21 @@ int smu_v14_0_baco_exit(struct smu_context *smu) int smu_v14_0_set_gfx_power_up_by_imu(struct smu_context *smu) { - uint16_t index; + struct smu_msg_ctl *ctl = &smu->msg_ctl; struct amdgpu_device *adev = smu->adev; + int ret; if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_EnableGfxImu, ENABLE_IMU_ARG_GFXOFF_ENABLE, NULL); } - index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, - SMU_MSG_EnableGfxImu); - return smu_cmn_send_msg_without_waiting(smu, index, ENABLE_IMU_ARG_GFXOFF_ENABLE); + mutex_lock(&ctl->lock); + ret = smu_msg_send_async_locked(ctl, SMU_MSG_EnableGfxImu, + ENABLE_IMU_ARG_GFXOFF_ENABLE); + mutex_unlock(&ctl->lock); + + return ret; } int smu_v14_0_set_default_dpm_tables(struct smu_context *smu) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c index ba895ca4f3e6..a4e376e8328c 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c @@ -1701,8 +1701,6 @@ static const struct pptable_funcs smu_v14_0_0_ppt_funcs = { .fini_smc_tables = smu_v14_0_0_fini_smc_tables, .get_vbios_bootup_values = smu_v14_0_get_vbios_bootup_values, .system_features_control = smu_v14_0_0_system_features_control, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .dpm_set_vcn_enable = smu_v14_0_set_vcn_enable, .dpm_set_jpeg_enable = smu_v14_0_set_jpeg_enable, .set_default_dpm_table = smu_v14_0_set_default_dpm_tables, @@ -1731,23 +1729,28 @@ static const struct pptable_funcs smu_v14_0_0_ppt_funcs = { .set_mall_enable = smu_v14_0_common_set_mall_enable, }; -static void smu_v14_0_0_set_smu_mailbox_registers(struct smu_context *smu) +static void smu_v14_0_0_init_msg_ctl(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - - smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); - smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); - smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + struct smu_msg_ctl *ctl = &smu->msg_ctl; + + ctl->smu = smu; + mutex_init(&ctl->lock); + ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_66); + ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_82); + ctl->config.num_arg_regs = 1; + ctl->ops = &smu_msg_v1_ops; + ctl->default_timeout = adev->usec_timeout * 20; + ctl->message_map = smu_v14_0_0_message_map; } void smu_v14_0_0_set_ppt_funcs(struct smu_context *smu) { - smu->ppt_funcs = &smu_v14_0_0_ppt_funcs; - smu->message_map = smu_v14_0_0_message_map; smu->feature_map = smu_v14_0_0_feature_mask_map; smu->table_map = smu_v14_0_0_table_map; smu->is_apu = true; - smu_v14_0_0_set_smu_mailbox_registers(smu); + smu_v14_0_0_init_msg_ctl(smu); } 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 b1fee26d989a..faae1da81bd4 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 @@ -1632,8 +1632,9 @@ static int smu_v14_0_2_get_power_limit(struct smu_context *smu, table_context->power_play_table; PPTable_t *pptable = table_context->driver_pptable; CustomSkuTable_t *skutable = &pptable->CustomSkuTable; - uint32_t power_limit, od_percent_upper = 0, od_percent_lower = 0; + int16_t od_percent_upper = 0, od_percent_lower = 0; uint32_t msg_limit = pptable->SkuTable.MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; + uint32_t power_limit; if (smu_v14_0_get_current_power_limit(smu, &power_limit)) power_limit = smu->adev->pm.ac_power ? @@ -2107,17 +2108,27 @@ static int smu_v14_0_2_enable_gfx_features(struct smu_context *smu) return -EOPNOTSUPP; } -static void smu_v14_0_2_set_smu_mailbox_registers(struct smu_context *smu) +static void smu_v14_0_2_init_msg_ctl(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - - smu->param_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_82); - smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_66); - smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_90); - - smu->debug_param_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_53); - smu->debug_msg_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_75); - smu->debug_resp_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_54); + struct smu_msg_ctl *ctl = &smu->msg_ctl; + + ctl->smu = smu; + mutex_init(&ctl->lock); + ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_66); + ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_90); + ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_82); + ctl->config.num_arg_regs = 1; + ctl->ops = &smu_msg_v1_ops; + ctl->default_timeout = adev->usec_timeout * 20; + ctl->message_map = smu_v14_0_2_message_map; + ctl->flags = 0; + + /* Set up debug mailbox registers */ + ctl->config.debug_param_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_53); + ctl->config.debug_msg_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_75); + ctl->config.debug_resp_reg = SOC15_REG_OFFSET(MP1, 0, regMP1_SMN_C2PMSG_54); + ctl->flags |= SMU_MSG_CTL_DEBUG_MAILBOX; } static ssize_t smu_v14_0_2_get_gpu_metrics(struct smu_context *smu, @@ -2859,11 +2870,10 @@ static const struct pptable_funcs smu_v14_0_2_ppt_funcs = { void smu_v14_0_2_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &smu_v14_0_2_ppt_funcs; - smu->message_map = smu_v14_0_2_message_map; smu->clock_map = smu_v14_0_2_clk_map; smu->feature_map = smu_v14_0_2_feature_mask_map; smu->table_map = smu_v14_0_2_table_map; smu->pwr_src_map = smu_v14_0_2_pwr_src_map; smu->workload_map = smu_v14_0_2_workload_map; - smu_v14_0_2_set_smu_mailbox_registers(smu); + smu_v14_0_2_init_msg_ctl(smu); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c index 631bdf387163..6557085a7c72 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c @@ -1709,17 +1709,21 @@ int smu_v15_0_baco_exit(struct smu_context *smu) int smu_v15_0_set_gfx_power_up_by_imu(struct smu_context *smu) { - uint16_t index; + struct smu_msg_ctl *ctl = &smu->msg_ctl; struct amdgpu_device *adev = smu->adev; + int ret; if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_EnableGfxImu, ENABLE_IMU_ARG_GFXOFF_ENABLE, NULL); } - index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, - SMU_MSG_EnableGfxImu); - return smu_cmn_send_msg_without_waiting(smu, index, ENABLE_IMU_ARG_GFXOFF_ENABLE); + mutex_lock(&ctl->lock); + ret = smu_msg_send_async_locked(ctl, SMU_MSG_EnableGfxImu, + ENABLE_IMU_ARG_GFXOFF_ENABLE); + mutex_unlock(&ctl->lock); + + return ret; } int smu_v15_0_set_default_dpm_tables(struct smu_context *smu) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c index 05d4e8d293ea..b48444706c1e 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c @@ -883,15 +883,14 @@ static int smu_v15_0_common_get_dpm_level_count(struct smu_context *smu, return 0; } -static int smu_v15_0_0_print_clk_levels(struct smu_context *smu, - enum smu_clk_type clk_type, char *buf) +static int smu_v15_0_0_emit_clk_levels(struct smu_context *smu, + enum smu_clk_type clk_type, char *buf, + int *offset) { - int i, idx, ret = 0, size = 0; + int i, idx, ret = 0, size = *offset; uint32_t cur_value = 0, value = 0, count = 0; uint32_t min, max; - smu_cmn_get_sysfs_buf(&buf, &size); - switch (clk_type) { case SMU_OD_SCLK: size += sysfs_emit_at(buf, size, "%s:\n", "OD_SCLK"); @@ -915,19 +914,20 @@ static int smu_v15_0_0_print_clk_levels(struct smu_context *smu, case SMU_FCLK: ret = smu_v15_0_0_get_current_clk_freq(smu, clk_type, &cur_value); if (ret) - break; + return ret; ret = smu_v15_0_common_get_dpm_level_count(smu, clk_type, &count); if (ret) - break; + return ret; for (i = 0; i < count; i++) { idx = (clk_type == SMU_MCLK) ? (count - i - 1) : i; ret = smu_v15_0_common_get_dpm_freq_by_index(smu, clk_type, idx, &value); if (ret) - break; + return ret; - size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, value, + size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, + value, cur_value == value ? "*" : ""); } break; @@ -935,7 +935,7 @@ static int smu_v15_0_0_print_clk_levels(struct smu_context *smu, case SMU_SCLK: ret = smu_v15_0_0_get_current_clk_freq(smu, clk_type, &cur_value); if (ret) - break; + return ret; min = (smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq; max = (smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq; if (cur_value == max) @@ -946,9 +946,10 @@ static int smu_v15_0_0_print_clk_levels(struct smu_context *smu, i = 1; size += sysfs_emit_at(buf, size, "0: %uMhz %s\n", min, i == 0 ? "*" : ""); - size += sysfs_emit_at(buf, size, "1: %uMhz %s\n", - i == 1 ? cur_value : 1100, /* UMD PSTATE GFXCLK 1100 */ - i == 1 ? "*" : ""); + size += sysfs_emit_at( + buf, size, "1: %uMhz %s\n", + i == 1 ? cur_value : 1100, /* UMD PSTATE GFXCLK 1100 */ + i == 1 ? "*" : ""); size += sysfs_emit_at(buf, size, "2: %uMhz %s\n", max, i == 2 ? "*" : ""); break; @@ -956,7 +957,9 @@ static int smu_v15_0_0_print_clk_levels(struct smu_context *smu, break; } - return size; + *offset = size; + + return 0; } static int smu_v15_0_0_set_soft_freq_limited_range(struct smu_context *smu, @@ -1307,8 +1310,6 @@ static const struct pptable_funcs smu_v15_0_0_ppt_funcs = { .fini_smc_tables = smu_v15_0_0_fini_smc_tables, .get_vbios_bootup_values = smu_v15_0_get_vbios_bootup_values, .system_features_control = smu_v15_0_0_system_features_control, - .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, - .send_smc_msg = smu_cmn_send_smc_msg, .dpm_set_vcn_enable = smu_v15_0_set_vcn_enable, .dpm_set_jpeg_enable = smu_v15_0_set_jpeg_enable, .set_default_dpm_table = smu_v15_0_set_default_dpm_tables, @@ -1323,7 +1324,7 @@ static const struct pptable_funcs smu_v15_0_0_ppt_funcs = { .mode2_reset = smu_v15_0_0_mode2_reset, .get_dpm_ultimate_freq = smu_v15_0_common_get_dpm_ultimate_freq, .od_edit_dpm_table = smu_v15_0_od_edit_dpm_table, - .print_clk_levels = smu_v15_0_0_print_clk_levels, + .emit_clk_levels = smu_v15_0_0_emit_clk_levels, .force_clk_levels = smu_v15_0_0_force_clk_levels, .set_performance_level = smu_v15_0_common_set_performance_level, .set_fine_grain_gfx_freq_parameters = smu_v15_0_common_set_fine_grain_gfx_freq_parameters, @@ -1333,23 +1334,28 @@ static const struct pptable_funcs smu_v15_0_0_ppt_funcs = { .get_dpm_clock_table = smu_v15_0_common_get_dpm_table, }; -static void smu_v15_0_0_set_smu_mailbox_registers(struct smu_context *smu) +static void smu_v15_0_0_init_msg_ctl(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - - smu->param_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_32); - smu->msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_30); - smu->resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_31); + struct smu_msg_ctl *ctl = &smu->msg_ctl; + + ctl->smu = smu; + mutex_init(&ctl->lock); + ctl->config.msg_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_30); + ctl->config.resp_reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_31); + ctl->config.arg_regs[0] = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_32); + ctl->config.num_arg_regs = 1; + ctl->ops = &smu_msg_v1_ops; + ctl->default_timeout = adev->usec_timeout * 20; + ctl->message_map = smu_v15_0_0_message_map; } void smu_v15_0_0_set_ppt_funcs(struct smu_context *smu) { - smu->ppt_funcs = &smu_v15_0_0_ppt_funcs; - smu->message_map = smu_v15_0_0_message_map; smu->feature_map = smu_v15_0_0_feature_mask_map; smu->table_map = smu_v15_0_0_table_map; smu->is_apu = true; - smu_v15_0_0_set_smu_mailbox_registers(smu); + smu_v15_0_0_init_msg_ctl(smu); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index ef5aa4e42a17..24835600c1cd 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -53,6 +53,9 @@ static const char * const __smu_message_names[] = { -ENOTSUPP) : \ -EINVAL) +#define SMU_MSG_V1_DEFAULT_RATELIMIT_INTERVAL (5 * HZ) +#define SMU_MSG_V1_DEFAULT_RATELIMIT_BURST 10 + static const char *smu_get_message_name(struct smu_context *smu, enum smu_message_type type) { @@ -62,14 +65,6 @@ static const char *smu_get_message_name(struct smu_context *smu, return __smu_message_names[type]; } -static void smu_cmn_read_arg(struct smu_context *smu, - uint32_t *arg) -{ - struct amdgpu_device *adev = smu->adev; - - *arg = RREG32(smu->param_reg); -} - /* Redefine the SMU error codes here. * * Note that these definitions are redundant and should be removed @@ -87,117 +82,134 @@ static void smu_cmn_read_arg(struct smu_context *smu, #define SMU_RESP_DEBUG_END 0xFB #define SMU_RESP_UNEXP (~0U) + +static int smu_msg_v1_send_debug_msg(struct smu_msg_ctl *ctl, u32 msg, u32 param) +{ + struct amdgpu_device *adev = ctl->smu->adev; + struct smu_msg_config *cfg = &ctl->config; + + if (!(ctl->flags & SMU_MSG_CTL_DEBUG_MAILBOX)) + return -EOPNOTSUPP; + + mutex_lock(&ctl->lock); + + WREG32(cfg->debug_param_reg, param); + WREG32(cfg->debug_msg_reg, msg); + WREG32(cfg->debug_resp_reg, 0); + + mutex_unlock(&ctl->lock); + + return 0; +} + +static int __smu_cmn_send_debug_msg(struct smu_msg_ctl *ctl, + u32 msg, + u32 param) +{ + if (!ctl->ops || !ctl->ops->send_debug_msg) + return -EOPNOTSUPP; + + return ctl->ops->send_debug_msg(ctl, msg, param); +} + /** - * __smu_cmn_poll_stat -- poll for a status from the SMU - * @smu: a pointer to SMU context + * smu_cmn_wait_for_response -- wait for response from the SMU + * @smu: pointer to an SMU context * - * Returns the status of the SMU, which could be, - * 0, the SMU is busy with your command; - * 1, execution status: success, execution result: success; - * 0xFF, execution status: success, execution result: failure; - * 0xFE, unknown command; - * 0xFD, valid command, but bad (command) prerequisites; - * 0xFC, the command was rejected as the SMU is busy; - * 0xFB, "SMC_Result_DebugDataDumpEnd". + * Wait for status from the SMU. * - * The values here are not defined by macros, because I'd rather we - * include a single header file which defines them, which is - * maintained by the SMU FW team, so that we're impervious to firmware - * changes. At the moment those values are defined in various header - * files, one for each ASIC, yet here we're a single ASIC-agnostic - * interface. Such a change can be followed-up by a subsequent patch. + * Return 0 on success, -errno on error, indicating the execution + * status and result of the message being waited for. See + * smu_msg_v1_decode_response() for details of the -errno. */ -static u32 __smu_cmn_poll_stat(struct smu_context *smu) +int smu_cmn_wait_for_response(struct smu_context *smu) { - struct amdgpu_device *adev = smu->adev; - int timeout = adev->usec_timeout * 20; - u32 reg; + return smu_msg_wait_response(&smu->msg_ctl, 0); +} - for ( ; timeout > 0; timeout--) { - reg = RREG32(smu->resp_reg); - if ((reg & MP1_C2PMSG_90__CONTENT_MASK) != 0) - break; +/** + * smu_cmn_send_smc_msg_with_param -- send a message with parameter + * @smu: pointer to an SMU context + * @msg: message to send + * @param: parameter to send to the SMU + * @read_arg: pointer to u32 to return a value from the SMU back + * to the caller + * + * Send the message @msg with parameter @param to the SMU, wait for + * completion of the command, and return back a value from the SMU in + * @read_arg pointer. + * + * Return 0 on success, -errno when a problem is encountered sending + * message or receiving reply. If there is a PCI bus recovery or + * the destination is a virtual GPU which does not allow this message + * type, the message is simply dropped and success is also returned. + * See smu_msg_v1_decode_response() for details of the -errno. + * + * If we weren't able to send the message to the SMU, we also print + * the error to the standard log. + * + * Command completion status is printed only if the -errno is + * -EREMOTEIO, indicating that the SMU returned back an + * undefined/unknown/unspecified result. All other cases are + * well-defined, not printed, but instead given back to the client to + * decide what further to do. + * + * The return value, @read_arg is read back regardless, to give back + * more information to the client, which on error would most likely be + * @param, but we can't assume that. This also eliminates more + * conditionals. + */ +int smu_cmn_send_smc_msg_with_param(struct smu_context *smu, + enum smu_message_type msg, + uint32_t param, + uint32_t *read_arg) +{ + struct smu_msg_ctl *ctl = &smu->msg_ctl; + struct smu_msg_args args = { + .msg = msg, + .args[0] = param, + .num_args = 1, + .num_out_args = read_arg ? 1 : 0, + .flags = 0, + .timeout = 0, + }; + int ret; - udelay(1); - } + ret = ctl->ops->send_msg(ctl, &args); - return reg; + if (read_arg) + *read_arg = args.out_args[0]; + + return ret; } -static void __smu_cmn_reg_print_error(struct smu_context *smu, - u32 reg_c2pmsg_90, - int msg_index, - u32 param, - enum smu_message_type msg) +int smu_cmn_send_smc_msg(struct smu_context *smu, + enum smu_message_type msg, + uint32_t *read_arg) { - struct amdgpu_device *adev = smu->adev; - const char *message = smu_get_message_name(smu, msg); - u32 msg_idx, prm; - - switch (reg_c2pmsg_90) { - case SMU_RESP_NONE: { - msg_idx = RREG32(smu->msg_reg); - prm = RREG32(smu->param_reg); - dev_err_ratelimited(adev->dev, - "SMU: I'm not done with your previous command: SMN_C2PMSG_66:0x%08X SMN_C2PMSG_82:0x%08X", - msg_idx, prm); - } - break; - case SMU_RESP_OK: - /* The SMU executed the command. It completed with a - * successful result. - */ - break; - case SMU_RESP_CMD_FAIL: - /* The SMU executed the command. It completed with an - * unsuccessful result. - */ - break; - case SMU_RESP_CMD_UNKNOWN: - dev_err_ratelimited(adev->dev, - "SMU: unknown command: index:%d param:0x%08X message:%s", - msg_index, param, message); - break; - case SMU_RESP_CMD_BAD_PREREQ: - dev_err_ratelimited(adev->dev, - "SMU: valid command, bad prerequisites: index:%d param:0x%08X message:%s", - msg_index, param, message); - break; - case SMU_RESP_BUSY_OTHER: - /* It is normal for SMU_MSG_GetBadPageCount to return busy - * so don't print error at this case. - */ - if (msg != SMU_MSG_GetBadPageCount) - dev_err_ratelimited(adev->dev, - "SMU: I'm very busy for your command: index:%d param:0x%08X message:%s", - msg_index, param, message); - break; - case SMU_RESP_DEBUG_END: - dev_err_ratelimited(adev->dev, - "SMU: I'm debugging!"); - break; - case SMU_RESP_UNEXP: - if (amdgpu_device_bus_status_check(smu->adev)) { - /* print error immediately if device is off the bus */ - dev_err(adev->dev, - "SMU: response:0x%08X for index:%d param:0x%08X message:%s?", - reg_c2pmsg_90, msg_index, param, message); - break; - } - fallthrough; - default: - dev_err_ratelimited(adev->dev, - "SMU: response:0x%08X for index:%d param:0x%08X message:%s?", - reg_c2pmsg_90, msg_index, param, message); - break; - } + return smu_cmn_send_smc_msg_with_param(smu, + msg, + 0, + read_arg); } -static int __smu_cmn_reg2errno(struct smu_context *smu, u32 reg_c2pmsg_90) +int smu_cmn_send_debug_smc_msg(struct smu_context *smu, + uint32_t msg) +{ + return __smu_cmn_send_debug_msg(&smu->msg_ctl, msg, 0); +} + +int smu_cmn_send_debug_smc_msg_with_param(struct smu_context *smu, + uint32_t msg, uint32_t param) +{ + return __smu_cmn_send_debug_msg(&smu->msg_ctl, msg, param); +} + +static int smu_msg_v1_decode_response(u32 resp) { int res; - switch (reg_c2pmsg_90) { + switch (resp) { case SMU_RESP_NONE: /* The SMU is busy--still executing your command. */ @@ -238,281 +250,345 @@ static int __smu_cmn_reg2errno(struct smu_context *smu, u32 reg_c2pmsg_90) return res; } -static void __smu_cmn_send_msg(struct smu_context *smu, - u16 msg, - u32 param) +static u32 __smu_msg_v1_poll_stat(struct smu_msg_ctl *ctl, u32 timeout_us) { - struct amdgpu_device *adev = smu->adev; + struct amdgpu_device *adev = ctl->smu->adev; + struct smu_msg_config *cfg = &ctl->config; + u32 timeout = timeout_us ? timeout_us : ctl->default_timeout; + u32 reg; + + for (; timeout > 0; timeout--) { + reg = RREG32(cfg->resp_reg); + if ((reg & MP1_C2PMSG_90__CONTENT_MASK) != 0) + break; + udelay(1); + } - WREG32(smu->resp_reg, 0); - WREG32(smu->param_reg, param); - WREG32(smu->msg_reg, msg); + return reg; } -static inline uint32_t __smu_cmn_get_msg_flags(struct smu_context *smu, - enum smu_message_type msg) +static void __smu_msg_v1_send(struct smu_msg_ctl *ctl, u16 index, + struct smu_msg_args *args) { - return smu->message_map[msg].flags; + struct amdgpu_device *adev = ctl->smu->adev; + struct smu_msg_config *cfg = &ctl->config; + int i; + + WREG32(cfg->resp_reg, 0); + for (i = 0; i < args->num_args; i++) + WREG32(cfg->arg_regs[i], args->args[i]); + WREG32(cfg->msg_reg, index); } -static int __smu_cmn_ras_filter_msg(struct smu_context *smu, - enum smu_message_type msg, bool *poll) +static void __smu_msg_v1_read_out_args(struct smu_msg_ctl *ctl, + struct smu_msg_args *args) { - struct amdgpu_device *adev = smu->adev; - uint32_t flags, resp; - bool fed_status, pri; + struct amdgpu_device *adev = ctl->smu->adev; + int i; - flags = __smu_cmn_get_msg_flags(smu, msg); - *poll = true; + for (i = 0; i < args->num_out_args; i++) + args->out_args[i] = RREG32(ctl->config.arg_regs[i]); +} - pri = !!(flags & SMU_MSG_NO_PRECHECK); - /* When there is RAS fatal error, FW won't process non-RAS priority - * messages. Don't allow any messages other than RAS priority messages. - */ - fed_status = amdgpu_ras_get_fed_status(adev); - if (fed_status) { - if (!(flags & SMU_MSG_RAS_PRI)) { - dev_dbg(adev->dev, - "RAS error detected, skip sending %s", - smu_get_message_name(smu, msg)); - return -EACCES; - } - } +static void __smu_msg_v1_print_err_limited(struct smu_msg_ctl *ctl, + struct smu_msg_args *args, + char *err_msg) +{ + static DEFINE_RATELIMIT_STATE(_rs, + SMU_MSG_V1_DEFAULT_RATELIMIT_INTERVAL, + SMU_MSG_V1_DEFAULT_RATELIMIT_BURST); + struct smu_context *smu = ctl->smu; + struct amdgpu_device *adev = smu->adev; - if (pri || fed_status) { - /* FW will ignore non-priority messages when a RAS fatal error - * or reset condition is detected. Hence it is possible that a - * previous message wouldn't have got response. Allow to - * continue without polling for response status for priority - * messages. - */ - resp = RREG32(smu->resp_reg); - dev_dbg(adev->dev, - "Sending priority message %s response status: %x", - smu_get_message_name(smu, msg), resp); - if (resp == 0) - *poll = false; + if (__ratelimit(&_rs)) { + u32 in[SMU_MSG_MAX_ARGS]; + int i; + + dev_err(adev->dev, "%s msg_reg: %x resp_reg: %x", err_msg, + RREG32(ctl->config.msg_reg), + RREG32(ctl->config.resp_reg)); + if (args->num_args > 0) { + for (i = 0; i < args->num_args; i++) + in[i] = RREG32(ctl->config.arg_regs[i]); + print_hex_dump(KERN_ERR, "in params:", DUMP_PREFIX_NONE, + 16, 4, in, args->num_args * sizeof(u32), + false); + } } - - return 0; } -static int __smu_cmn_send_debug_msg(struct smu_context *smu, - u32 msg, - u32 param) +static void __smu_msg_v1_print_error(struct smu_msg_ctl *ctl, + u32 resp, + struct smu_msg_args *args) { + struct smu_context *smu = ctl->smu; struct amdgpu_device *adev = smu->adev; + int index = ctl->message_map[args->msg].map_to; - WREG32(smu->debug_param_reg, param); - WREG32(smu->debug_msg_reg, msg); - WREG32(smu->debug_resp_reg, 0); - - return 0; + switch (resp) { + case SMU_RESP_NONE: + __smu_msg_v1_print_err_limited(ctl, args, "SMU: No response"); + break; + case SMU_RESP_OK: + break; + case SMU_RESP_CMD_FAIL: + break; + case SMU_RESP_CMD_UNKNOWN: + __smu_msg_v1_print_err_limited(ctl, args, + "SMU: unknown command"); + break; + case SMU_RESP_CMD_BAD_PREREQ: + __smu_msg_v1_print_err_limited( + ctl, args, "SMU: valid command, bad prerequisites"); + break; + case SMU_RESP_BUSY_OTHER: + if (args->msg != SMU_MSG_GetBadPageCount) + __smu_msg_v1_print_err_limited(ctl, args, + "SMU: I'm very busy"); + break; + case SMU_RESP_DEBUG_END: + __smu_msg_v1_print_err_limited(ctl, args, "SMU: Debug Err"); + break; + case SMU_RESP_UNEXP: + if (amdgpu_device_bus_status_check(adev)) { + dev_err(adev->dev, + "SMU: bus error for message: %s(%d) response:0x%08X ", + smu_get_message_name(smu, args->msg), index, + resp); + if (args->num_args > 0) + print_hex_dump(KERN_ERR, + "in params:", DUMP_PREFIX_NONE, + 16, 4, args->args, + args->num_args * sizeof(u32), + false); + } + break; + default: + __smu_msg_v1_print_err_limited(ctl, args, + "SMU: unknown response"); + break; + } } -/** - * smu_cmn_send_msg_without_waiting -- send the message; don't wait for status - * @smu: pointer to an SMU context - * @msg_index: message index - * @param: message parameter to send to the SMU - * - * Send a message to the SMU with the parameter passed. Do not wait - * for status/result of the message, thus the "without_waiting". - * - * Return 0 on success, -errno on error if we weren't able to _send_ - * the message for some reason. See __smu_cmn_reg2errno() for details - * of the -errno. - */ -int smu_cmn_send_msg_without_waiting(struct smu_context *smu, - uint16_t msg_index, - uint32_t param) + +static int __smu_msg_v1_ras_filter(struct smu_msg_ctl *ctl, + enum smu_message_type msg, u32 msg_flags, + bool *skip_pre_poll) { + struct smu_context *smu = ctl->smu; struct amdgpu_device *adev = smu->adev; + bool fed_status; u32 reg; - int res; - if (adev->no_hw_access) + if (!(smu->smc_fw_caps & SMU_FW_CAP_RAS_PRI)) return 0; - if (smu->smc_fw_state == SMU_FW_HANG) { - dev_err(adev->dev, "SMU is in hanged state, failed to send smu message!\n"); - res = -EREMOTEIO; - goto Out; - } + fed_status = amdgpu_ras_get_fed_status(adev); - if (smu->smc_fw_state == SMU_FW_INIT) { - smu->smc_fw_state = SMU_FW_RUNTIME; - } else { - reg = __smu_cmn_poll_stat(smu); - res = __smu_cmn_reg2errno(smu, reg); - if (reg == SMU_RESP_NONE || res == -EREMOTEIO) - goto Out; + /* Block non-RAS-priority messages during RAS error */ + if (fed_status && !(msg_flags & SMU_MSG_RAS_PRI)) { + dev_dbg(adev->dev, "RAS error detected, skip sending %s", + smu_get_message_name(smu, msg)); + return -EACCES; } - __smu_cmn_send_msg(smu, msg_index, param); - res = 0; -Out: - if (unlikely(adev->pm.smu_debug_mask & SMU_DEBUG_HALT_ON_ERROR) && - res && (res != -ETIME)) { - amdgpu_device_halt(adev); - WARN_ON(1); + /* Skip pre-poll for priority messages or during RAS error */ + if ((msg_flags & SMU_MSG_NO_PRECHECK) || fed_status) { + reg = RREG32(ctl->config.resp_reg); + dev_dbg(adev->dev, + "Sending priority message %s response status: %x", + smu_get_message_name(smu, msg), reg); + if (reg == 0) + *skip_pre_poll = true; } - return res; + return 0; } /** - * smu_cmn_wait_for_response -- wait for response from the SMU - * @smu: pointer to an SMU context + * smu_msg_proto_v1_send_msg - Complete V1 protocol with all filtering + * @ctl: Message control block + * @args: Message arguments * - * Wait for status from the SMU. - * - * Return 0 on success, -errno on error, indicating the execution - * status and result of the message being waited for. See - * __smu_cmn_reg2errno() for details of the -errno. + * Return: 0 on success, negative errno on failure */ -int smu_cmn_wait_for_response(struct smu_context *smu) +static int smu_msg_v1_send_msg(struct smu_msg_ctl *ctl, + struct smu_msg_args *args) { - u32 reg; - int res; + struct smu_context *smu = ctl->smu; + struct amdgpu_device *adev = smu->adev; + const struct cmn2asic_msg_mapping *mapping; + u32 reg, msg_flags; + int ret, index; + bool skip_pre_poll = false; + bool lock_held = args->flags & SMU_MSG_FLAG_LOCK_HELD; - reg = __smu_cmn_poll_stat(smu); - res = __smu_cmn_reg2errno(smu, reg); + /* Early exit if no HW access */ + if (adev->no_hw_access) + return 0; - if (res == -EREMOTEIO) - smu->smc_fw_state = SMU_FW_HANG; + /* Message index translation */ + if (args->msg >= SMU_MSG_MAX_COUNT || !ctl->message_map) + return -EINVAL; - if (unlikely(smu->adev->pm.smu_debug_mask & SMU_DEBUG_HALT_ON_ERROR) && - res && (res != -ETIME)) { - amdgpu_device_halt(smu->adev); - WARN_ON(1); - } + if (args->num_args > ctl->config.num_arg_regs || + args->num_out_args > ctl->config.num_arg_regs) + return -EINVAL; - return res; -} + mapping = &ctl->message_map[args->msg]; + if (!mapping->valid_mapping) + return -EINVAL; -/** - * smu_cmn_send_smc_msg_with_param -- send a message with parameter - * @smu: pointer to an SMU context - * @msg: message to send - * @param: parameter to send to the SMU - * @read_arg: pointer to u32 to return a value from the SMU back - * to the caller - * - * Send the message @msg with parameter @param to the SMU, wait for - * completion of the command, and return back a value from the SMU in - * @read_arg pointer. - * - * Return 0 on success, -errno when a problem is encountered sending - * message or receiving reply. If there is a PCI bus recovery or - * the destination is a virtual GPU which does not allow this message - * type, the message is simply dropped and success is also returned. - * See __smu_cmn_reg2errno() for details of the -errno. - * - * If we weren't able to send the message to the SMU, we also print - * the error to the standard log. - * - * Command completion status is printed only if the -errno is - * -EREMOTEIO, indicating that the SMU returned back an - * undefined/unknown/unspecified result. All other cases are - * well-defined, not printed, but instead given back to the client to - * decide what further to do. - * - * The return value, @read_arg is read back regardless, to give back - * more information to the client, which on error would most likely be - * @param, but we can't assume that. This also eliminates more - * conditionals. - */ -int smu_cmn_send_smc_msg_with_param(struct smu_context *smu, - enum smu_message_type msg, - uint32_t param, - uint32_t *read_arg) -{ - struct amdgpu_device *adev = smu->adev; - int res, index; - bool poll = true; - u32 reg; + msg_flags = mapping->flags; + index = mapping->map_to; - if (adev->no_hw_access) + /* VF filter - skip messages not valid for VF */ + if (amdgpu_sriov_vf(adev) && !(msg_flags & SMU_MSG_VF_FLAG)) return 0; - index = smu_cmn_to_asic_specific_index(smu, - CMN2ASIC_MAPPING_MSG, - msg); - if (index < 0) - return index == -EACCES ? 0 : index; - - mutex_lock(&smu->message_lock); + if (!lock_held) + mutex_lock(&ctl->lock); - if (smu->smc_fw_caps & SMU_FW_CAP_RAS_PRI) { - res = __smu_cmn_ras_filter_msg(smu, msg, &poll); - if (res) - goto Out; - } + /* RAS priority filter */ + ret = __smu_msg_v1_ras_filter(ctl, args->msg, msg_flags, + &skip_pre_poll); + if (ret) + goto out; + /* FW state checks */ if (smu->smc_fw_state == SMU_FW_HANG) { - dev_err(adev->dev, "SMU is in hanged state, failed to send smu message!\n"); - res = -EREMOTEIO; - goto Out; + dev_err(adev->dev, + "SMU is in hanged state, failed to send smu message!\n"); + ret = -EREMOTEIO; + goto out; } else if (smu->smc_fw_state == SMU_FW_INIT) { - /* Ignore initial smu response register value */ - poll = false; + skip_pre_poll = true; smu->smc_fw_state = SMU_FW_RUNTIME; } - if (poll) { - reg = __smu_cmn_poll_stat(smu); - res = __smu_cmn_reg2errno(smu, reg); - if (reg == SMU_RESP_NONE || res == -EREMOTEIO) { - __smu_cmn_reg_print_error(smu, reg, index, param, msg); - goto Out; + /* Pre-poll: ensure previous message completed */ + if (!skip_pre_poll) { + reg = __smu_msg_v1_poll_stat(ctl, args->timeout); + ret = smu_msg_v1_decode_response(reg); + if (reg == SMU_RESP_NONE || ret == -EREMOTEIO) { + __smu_msg_v1_print_error(ctl, reg, args); + goto out; } } - __smu_cmn_send_msg(smu, (uint16_t) index, param); - reg = __smu_cmn_poll_stat(smu); - res = __smu_cmn_reg2errno(smu, reg); - if (res != 0) { - if (res == -EREMOTEIO) - smu->smc_fw_state = SMU_FW_HANG; - __smu_cmn_reg_print_error(smu, reg, index, param, msg); + + /* Send message */ + __smu_msg_v1_send(ctl, (u16)index, args); + + /* Post-poll (skip if ASYNC) */ + if (args->flags & SMU_MSG_FLAG_ASYNC) { + ret = 0; + goto out; } - if (read_arg) { - smu_cmn_read_arg(smu, read_arg); - dev_dbg(adev->dev, "smu send message: %s(%d) param: 0x%08x, resp: 0x%08x, readval: 0x%08x\n", - smu_get_message_name(smu, msg), index, param, reg, *read_arg); + + reg = __smu_msg_v1_poll_stat(ctl, args->timeout); + ret = smu_msg_v1_decode_response(reg); + + /* FW state update on fatal error */ + if (ret == -EREMOTEIO) { + smu->smc_fw_state = SMU_FW_HANG; + __smu_msg_v1_print_error(ctl, reg, args); + } else if (ret != 0) { + __smu_msg_v1_print_error(ctl, reg, args); + } + + /* Read output args */ + if (ret == 0 && args->num_out_args > 0) { + __smu_msg_v1_read_out_args(ctl, args); + dev_dbg(adev->dev, "smu send message: %s(%d) resp : 0x%08x", + smu_get_message_name(smu, args->msg), index, reg); + if (args->num_args > 0) + print_hex_dump_debug("in params:", DUMP_PREFIX_NONE, 16, + 4, args->args, + args->num_args * sizeof(u32), + false); + print_hex_dump_debug("out params:", DUMP_PREFIX_NONE, 16, 4, + args->out_args, + args->num_out_args * sizeof(u32), false); } else { - dev_dbg(adev->dev, "smu send message: %s(%d) param: 0x%08x, resp: 0x%08x\n", - smu_get_message_name(smu, msg), index, param, reg); + dev_dbg(adev->dev, "smu send message: %s(%d), resp: 0x%08x\n", + smu_get_message_name(smu, args->msg), index, reg); + if (args->num_args > 0) + print_hex_dump_debug("in params:", DUMP_PREFIX_NONE, 16, + 4, args->args, + args->num_args * sizeof(u32), + false); } -Out: - if (unlikely(adev->pm.smu_debug_mask & SMU_DEBUG_HALT_ON_ERROR) && res) { + +out: + /* Debug halt on error */ + if (unlikely(adev->pm.smu_debug_mask & SMU_DEBUG_HALT_ON_ERROR) && + ret) { amdgpu_device_halt(adev); WARN_ON(1); } - mutex_unlock(&smu->message_lock); - return res; + if (!lock_held) + mutex_unlock(&ctl->lock); + return ret; } -int smu_cmn_send_smc_msg(struct smu_context *smu, - enum smu_message_type msg, - uint32_t *read_arg) +static int smu_msg_v1_wait_response(struct smu_msg_ctl *ctl, u32 timeout_us) { - return smu_cmn_send_smc_msg_with_param(smu, - msg, - 0, - read_arg); + struct smu_context *smu = ctl->smu; + struct amdgpu_device *adev = smu->adev; + u32 reg; + int ret; + + reg = __smu_msg_v1_poll_stat(ctl, timeout_us); + ret = smu_msg_v1_decode_response(reg); + + if (ret == -EREMOTEIO) + smu->smc_fw_state = SMU_FW_HANG; + + if (unlikely(adev->pm.smu_debug_mask & SMU_DEBUG_HALT_ON_ERROR) && + ret && (ret != -ETIME)) { + amdgpu_device_halt(adev); + WARN_ON(1); + } + + return ret; } -int smu_cmn_send_debug_smc_msg(struct smu_context *smu, - uint32_t msg) +const struct smu_msg_ops smu_msg_v1_ops = { + .send_msg = smu_msg_v1_send_msg, + .wait_response = smu_msg_v1_wait_response, + .decode_response = smu_msg_v1_decode_response, + .send_debug_msg = smu_msg_v1_send_debug_msg, +}; + +int smu_msg_wait_response(struct smu_msg_ctl *ctl, u32 timeout_us) { - return __smu_cmn_send_debug_msg(smu, msg, 0); + return ctl->ops->wait_response(ctl, timeout_us); } -int smu_cmn_send_debug_smc_msg_with_param(struct smu_context *smu, - uint32_t msg, uint32_t param) +/** + * smu_msg_send_async_locked - Send message asynchronously, caller holds lock + * @ctl: Message control block + * @msg: Message type + * @param: Message parameter + * + * Send an SMU message without waiting for response. Caller must hold ctl->lock + * and call smu_msg_wait_response() later to get the result. + * + * Return: 0 on success, negative errno on failure + */ +int smu_msg_send_async_locked(struct smu_msg_ctl *ctl, + enum smu_message_type msg, u32 param) { - return __smu_cmn_send_debug_msg(smu, msg, param); + struct smu_msg_args args = { + .msg = msg, + .args[0] = param, + .num_args = 1, + .num_out_args = 0, + .flags = SMU_MSG_FLAG_ASYNC | SMU_MSG_FLAG_LOCK_HELD, + .timeout = 0, + }; + + return ctl->ops->send_msg(ctl, &args); } int smu_cmn_to_asic_specific_index(struct smu_context *smu, @@ -525,10 +601,10 @@ int smu_cmn_to_asic_specific_index(struct smu_context *smu, switch (type) { case CMN2ASIC_MAPPING_MSG: if (index >= SMU_MSG_MAX_COUNT || - !smu->message_map) + !smu->msg_ctl.message_map) return -EINVAL; - msg_mapping = smu->message_map[index]; + msg_mapping = smu->msg_ctl.message_map[index]; if (!msg_mapping.valid_mapping) return -EINVAL; @@ -1210,11 +1286,11 @@ int smu_cmn_print_dpm_clk_levels(struct smu_context *smu, struct smu_dpm_table *dpm_table, uint32_t cur_clk, char *buf, int *offset) { - uint32_t min_clk, level_index, count; - uint32_t freq_values[3] = { 0 }; + uint32_t min_clk, max_clk, level_index, count; + uint32_t freq_values[3]; + int size, lvl, i; bool is_fine_grained; bool is_deep_sleep; - int size, lvl, i; bool freq_match; if (!dpm_table || !buf) @@ -1225,6 +1301,7 @@ int smu_cmn_print_dpm_clk_levels(struct smu_context *smu, count = dpm_table->count; is_fine_grained = dpm_table->flags & SMU_DPM_TABLE_FINE_GRAINED; min_clk = SMU_DPM_TABLE_MIN(dpm_table); + max_clk = SMU_DPM_TABLE_MAX(dpm_table); /* Deep sleep - current clock < min_clock/2, TBD: cur_clk = 0 as GFXOFF */ is_deep_sleep = cur_clk < min_clk / 2; @@ -1245,22 +1322,22 @@ int smu_cmn_print_dpm_clk_levels(struct smu_context *smu, freq_match ? "*" : ""); } } else { + count = 2; freq_values[0] = min_clk; - freq_values[2] = SMU_DPM_TABLE_MAX(dpm_table); - freq_values[1] = cur_clk; + freq_values[1] = max_clk; - lvl = -1; if (!is_deep_sleep) { - lvl = 1; - if (smu_cmn_freqs_match(cur_clk, freq_values[0])) + if (smu_cmn_freqs_match(cur_clk, min_clk)) { lvl = 0; - else if (smu_cmn_freqs_match(cur_clk, freq_values[2])) - lvl = 2; - } - count = 3; - if (lvl != 1) { - count = 2; - freq_values[1] = freq_values[2]; + } else if (smu_cmn_freqs_match(cur_clk, max_clk)) { + lvl = 1; + } else { + /* NOTE: use index '1' to show current clock value */ + lvl = 1; + count = 3; + freq_values[1] = cur_clk; + freq_values[2] = max_clk; + } } for (i = 0; i < count; i++) { diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h index 3a8d05afa654..92ad2ece7a36 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h @@ -25,6 +25,12 @@ #include "amdgpu_smu.h" +extern const struct smu_msg_ops smu_msg_v1_ops; + +int smu_msg_wait_response(struct smu_msg_ctl *ctl, u32 timeout_us); +int smu_msg_send_async_locked(struct smu_msg_ctl *ctl, + enum smu_message_type msg, u32 param); + #if defined(SWSMU_CODE_LAYER_L2) || defined(SWSMU_CODE_LAYER_L3) || defined(SWSMU_CODE_LAYER_L4) #define FDO_PWM_MODE_STATIC 1 @@ -104,9 +110,6 @@ static inline int pcie_gen_to_speed(uint32_t gen) return ((gen == 0) ? link_speed[0] : link_speed[gen - 1]); } -int smu_cmn_send_msg_without_waiting(struct smu_context *smu, - uint16_t msg_index, - uint32_t param); int smu_cmn_send_smc_msg_with_param(struct smu_context *smu, enum smu_message_type msg, uint32_t param, @@ -184,19 +187,6 @@ int smu_cmn_get_combo_pptable(struct smu_context *smu); int smu_cmn_set_mp1_state(struct smu_context *smu, enum pp_mp1_state mp1_state); -/* - * Helper function to make sysfs_emit_at() happy. Align buf to - * the current page boundary and record the offset. - */ -static inline void smu_cmn_get_sysfs_buf(char **buf, int *offset) -{ - if (!*buf || !offset) - return; - - *offset = offset_in_page(*buf); - *buf -= *offset; -} - bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev); void smu_cmn_generic_soc_policy_desc(struct smu_dpm_policy *policy); void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h b/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h index 34f6b4b1c3ba..0f7778410a3a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h @@ -54,8 +54,6 @@ #define smu_system_features_control(smu, en) smu_ppt_funcs(system_features_control, 0, smu, en) #define smu_init_max_sustainable_clocks(smu) smu_ppt_funcs(init_max_sustainable_clocks, 0, smu) #define smu_set_default_od_settings(smu) smu_ppt_funcs(set_default_od_settings, 0, smu) -#define smu_send_smc_msg_with_param(smu, msg, param, read_arg) smu_ppt_funcs(send_smc_msg_with_param, 0, smu, msg, param, read_arg) -#define smu_send_smc_msg(smu, msg, read_arg) smu_ppt_funcs(send_smc_msg, 0, smu, msg, read_arg) #define smu_init_display_count(smu, count) smu_ppt_funcs(init_display_count, 0, smu, count) #define smu_feature_set_allowed_mask(smu) smu_ppt_funcs(set_allowed_mask, 0, smu) #define smu_feature_get_enabled_mask(smu, mask) smu_ppt_funcs(get_enabled_mask, -EOPNOTSUPP, smu, mask) diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h index f902add31fc6..1d34daa0ebcd 100644 --- a/include/uapi/drm/amdgpu_drm.h +++ b/include/uapi/drm/amdgpu_drm.h @@ -105,8 +105,6 @@ extern "C" { * * %AMDGPU_GEM_DOMAIN_DOORBELL Doorbell. It is an MMIO region for * signalling user mode queues. - * - * %AMDGPU_GEM_DOMAIN_MMIO_REMAP MMIO remap page (special mapping for HDP flushing). */ #define AMDGPU_GEM_DOMAIN_CPU 0x1 #define AMDGPU_GEM_DOMAIN_GTT 0x2 @@ -115,15 +113,13 @@ extern "C" { #define AMDGPU_GEM_DOMAIN_GWS 0x10 #define AMDGPU_GEM_DOMAIN_OA 0x20 #define AMDGPU_GEM_DOMAIN_DOORBELL 0x40 -#define AMDGPU_GEM_DOMAIN_MMIO_REMAP 0x80 #define AMDGPU_GEM_DOMAIN_MASK (AMDGPU_GEM_DOMAIN_CPU | \ AMDGPU_GEM_DOMAIN_GTT | \ AMDGPU_GEM_DOMAIN_VRAM | \ AMDGPU_GEM_DOMAIN_GDS | \ AMDGPU_GEM_DOMAIN_GWS | \ AMDGPU_GEM_DOMAIN_OA | \ - AMDGPU_GEM_DOMAIN_DOORBELL | \ - AMDGPU_GEM_DOMAIN_MMIO_REMAP) + AMDGPU_GEM_DOMAIN_DOORBELL) /* Flag that CPU access will be required for the case of VRAM domain */ #define AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED (1 << 0) |
