summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2026-01-18 23:53:41 +0300
committerDave Airlie <airlied@redhat.com>2026-01-18 23:54:46 +0300
commitc098b1aa2fa60fad42df8a1a6250099329e33311 (patch)
tree59f8067c25de3a4e6bde2fb3bc067b6df2798ff1
parent971c2b68bddb87f4929e66cd4563fca78b722210 (diff)
parent6a681cd9034587fe3550868bacfbd639d1c6891f (diff)
downloadlinux-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
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c15
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h17
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_device.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c11
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c11
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c76
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c65
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_object.c21
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_object.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c77
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c16
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c8
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c4
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_debug.c3
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device.c89
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c36
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_events.c29
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c4
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_migrate.c2
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c14
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c4
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c9
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_priv.h4
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_process.c14
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c12
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_queue.c6
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_svm.c29
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_topology.c22
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c91
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h6
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c25
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c9
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc.c49
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c9
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_dp_types.h34
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_hw_types.h6
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_types.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c13
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c52
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/link_service.h12
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/Makefile2
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c7
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_detection.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_dpms.c8
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_factory.c19
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c49
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c43
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c343
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.h38
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c297
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h10
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c11
-rw-r--r--drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h54
-rw-r--r--drivers/gpu/drm/amd/display/include/dpcd_defs.h30
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h120
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h3
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/smu_v12_0.h3
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h3
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h6
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c5
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c5
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c5
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c27
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c18
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c21
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c18
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c17
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c29
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c32
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c27
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c24
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c23
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c32
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c3
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c5
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c12
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c23
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c34
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c12
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c56
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c731
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h22
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu_internal.h2
-rw-r--r--include/uapi/drm/amdgpu_drm.h6
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.
- * &param: 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)