mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
amd-drm-next-7.2-2026-05-29:
amdgpu: - GEM_OP warning fix - GEM_OP locking fix - Userq fixes - DCN 2.1 refclk fix - SI fixes - HMM fixes - Add DC KUNIT tests - UML fixes - Switch to system_dfl_wq - Old DC power state cleanup - RAS fixes amdkfd: - svm_range_set_attr locking fix - CRIU restore fix - KFD debugger fix radeon: - Use struct drm_edid instead of struct edid -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQQgO5Idg2tXNTSZAr293/aFa7yZ2AUCahoHWgAKCRC93/aFa7yZ 2GLXAQCrU7fTQgRln2bqDXIx1V/KA85OSxDCzc8FGHoxtQny0AD+Lh/HeiZ2ISR1 7Ydh1S2vhvnzf9QIlNWYYExyQvXyXgM= =ntZ8 -----END PGP SIGNATURE----- Merge tag 'amd-drm-next-7.2-2026-05-29' of https://gitlab.freedesktop.org/agd5f/linux into drm-next amd-drm-next-7.2-2026-05-29: amdgpu: - GEM_OP warning fix - GEM_OP locking fix - Userq fixes - DCN 2.1 refclk fix - SI fixes - HMM fixes - Add DC KUNIT tests - UML fixes - Switch to system_dfl_wq - Old DC power state cleanup - RAS fixes amdkfd: - svm_range_set_attr locking fix - CRIU restore fix - KFD debugger fix radeon: - Use struct drm_edid instead of struct edid Signed-off-by: Dave Airlie <airlied@redhat.com> From: Alex Deucher <alexander.deucher@amd.com> Link: https://patch.msgid.link/20260529214346.2328355-1-alexander.deucher@amd.com
This commit is contained in:
commit
9bb8af2770
|
|
@ -586,7 +586,7 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
|
|||
*/
|
||||
adev->coredump = coredump;
|
||||
/* Kick off coredump formatting to a worker thread. */
|
||||
queue_work(system_unbound_wq, &adev->coredump_work);
|
||||
queue_work(system_dfl_wq, &adev->coredump_work);
|
||||
|
||||
drm_info(dev, "AMDGPU device coredump file has been created\n");
|
||||
drm_info(dev, "Check your /sys/class/drm/card%d/device/devcoredump/data\n",
|
||||
|
|
|
|||
|
|
@ -1913,6 +1913,19 @@ static void amdgpu_uid_fini(struct amdgpu_device *adev)
|
|||
adev->uid_info = NULL;
|
||||
}
|
||||
|
||||
static struct pci_dev *amdgpu_device_find_parent(struct amdgpu_device *adev)
|
||||
{
|
||||
struct pci_dev *parent = adev->pdev;
|
||||
|
||||
/* skip upstream/downstream switches internal to dGPU */
|
||||
while ((parent = pci_upstream_bridge(parent))) {
|
||||
if (parent->vendor == PCI_VENDOR_ID_ATI)
|
||||
continue;
|
||||
}
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_device_ip_early_init - run early init for hardware IPs
|
||||
*
|
||||
|
|
@ -5921,8 +5934,6 @@ static void amdgpu_device_partner_bandwidth(struct amdgpu_device *adev,
|
|||
enum pci_bus_speed *speed,
|
||||
enum pcie_link_width *width)
|
||||
{
|
||||
struct pci_dev *parent = adev->pdev;
|
||||
|
||||
if (!speed || !width)
|
||||
return;
|
||||
|
||||
|
|
@ -5930,13 +5941,11 @@ static void amdgpu_device_partner_bandwidth(struct amdgpu_device *adev,
|
|||
*width = PCIE_LNK_WIDTH_UNKNOWN;
|
||||
|
||||
if (amdgpu_device_pcie_dynamic_switching_supported(adev)) {
|
||||
while ((parent = pci_upstream_bridge(parent))) {
|
||||
/* skip upstream/downstream switches internal to dGPU*/
|
||||
if (parent->vendor == PCI_VENDOR_ID_ATI)
|
||||
continue;
|
||||
struct pci_dev *parent = amdgpu_device_find_parent(adev);
|
||||
|
||||
if (parent) {
|
||||
*speed = pcie_get_speed_cap(parent);
|
||||
*width = pcie_get_width_cap(parent);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* use the current speeds rather than max if switching is not supported */
|
||||
|
|
@ -5963,22 +5972,15 @@ static void amdgpu_device_gpu_bandwidth(struct amdgpu_device *adev,
|
|||
if (!speed || !width)
|
||||
return;
|
||||
|
||||
parent = pci_upstream_bridge(parent);
|
||||
if (parent && parent->vendor == PCI_VENDOR_ID_ATI) {
|
||||
/* use the upstream/downstream switches internal to dGPU */
|
||||
/* use the device itself */
|
||||
*speed = pcie_get_speed_cap(adev->pdev);
|
||||
*width = pcie_get_width_cap(adev->pdev);
|
||||
|
||||
/* use the link outside the device */
|
||||
parent = amdgpu_device_find_parent(adev);
|
||||
if (parent) {
|
||||
*speed = pcie_get_speed_cap(parent);
|
||||
*width = pcie_get_width_cap(parent);
|
||||
while ((parent = pci_upstream_bridge(parent))) {
|
||||
if (parent->vendor == PCI_VENDOR_ID_ATI) {
|
||||
/* use the upstream/downstream switches internal to dGPU */
|
||||
*speed = pcie_get_speed_cap(parent);
|
||||
*width = pcie_get_width_cap(parent);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* use the device itself */
|
||||
*speed = pcie_get_speed_cap(adev->pdev);
|
||||
*width = pcie_get_width_cap(adev->pdev);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1094,9 +1094,16 @@ int amdgpu_gem_op_ioctl(struct drm_device *dev, void *data,
|
|||
* If that number is larger than the size of the array, the ioctl must
|
||||
* be retried.
|
||||
*/
|
||||
if (args->num_entries > INT_MAX / sizeof(*vm_entries)) {
|
||||
r = -EINVAL;
|
||||
goto out_exec;
|
||||
}
|
||||
|
||||
vm_entries = kvcalloc(args->num_entries, sizeof(*vm_entries), GFP_KERNEL);
|
||||
if (!vm_entries)
|
||||
return -ENOMEM;
|
||||
if (!vm_entries) {
|
||||
r = -ENOMEM;
|
||||
goto out_exec;
|
||||
}
|
||||
|
||||
amdgpu_vm_bo_va_for_each_valid_mapping(bo_va, mapping) {
|
||||
if (num_mappings < args->num_entries) {
|
||||
|
|
|
|||
|
|
@ -51,8 +51,6 @@
|
|||
#include "amdgpu_amdkfd.h"
|
||||
#include "amdgpu_hmm.h"
|
||||
|
||||
#define MAX_WALK_BYTE (2UL << 30)
|
||||
|
||||
/**
|
||||
* amdgpu_hmm_invalidate_gfx - callback to notify about mm change
|
||||
*
|
||||
|
|
@ -78,6 +76,7 @@ static bool amdgpu_hmm_invalidate_gfx(struct mmu_interval_notifier *mni,
|
|||
|
||||
mmu_interval_set_seq(mni, cur_seq);
|
||||
|
||||
amdgpu_vm_bo_invalidate(bo, false);
|
||||
r = dma_resv_wait_timeout(bo->tbo.base.resv, DMA_RESV_USAGE_BOOKKEEP,
|
||||
false, MAX_SCHEDULE_TIMEOUT);
|
||||
mutex_unlock(&adev->notifier_lock);
|
||||
|
|
@ -170,11 +169,13 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,
|
|||
void *owner,
|
||||
struct amdgpu_hmm_range *range)
|
||||
{
|
||||
unsigned long end;
|
||||
const u64 max_bytes = SZ_2G;
|
||||
|
||||
struct hmm_range *hmm_range = &range->hmm_range;
|
||||
unsigned long timeout;
|
||||
unsigned long *pfns;
|
||||
int r = 0;
|
||||
struct hmm_range *hmm_range = &range->hmm_range;
|
||||
unsigned long end;
|
||||
int r;
|
||||
|
||||
pfns = kvmalloc_array(npages, sizeof(*pfns), GFP_KERNEL);
|
||||
if (unlikely(!pfns)) {
|
||||
|
|
@ -191,8 +192,9 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,
|
|||
end = start + npages * PAGE_SIZE;
|
||||
hmm_range->dev_private_owner = owner;
|
||||
|
||||
hmm_range->notifier_seq = mmu_interval_read_begin(notifier);
|
||||
do {
|
||||
hmm_range->end = min(hmm_range->start + MAX_WALK_BYTE, end);
|
||||
hmm_range->end = min(hmm_range->start + max_bytes, end);
|
||||
|
||||
pr_debug("hmm range: start = 0x%lx, end = 0x%lx",
|
||||
hmm_range->start, hmm_range->end);
|
||||
|
|
@ -200,7 +202,6 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,
|
|||
timeout = jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
|
||||
|
||||
retry:
|
||||
hmm_range->notifier_seq = mmu_interval_read_begin(notifier);
|
||||
r = hmm_range_fault(hmm_range);
|
||||
if (unlikely(r)) {
|
||||
if (r == -EBUSY && !time_after(jiffies, timeout))
|
||||
|
|
@ -210,7 +211,7 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,
|
|||
|
||||
if (hmm_range->end == end)
|
||||
break;
|
||||
hmm_range->hmm_pfns += MAX_WALK_BYTE >> PAGE_SHIFT;
|
||||
hmm_range->hmm_pfns += max_bytes >> PAGE_SHIFT;
|
||||
hmm_range->start = hmm_range->end;
|
||||
} while (hmm_range->end < end);
|
||||
|
||||
|
|
|
|||
|
|
@ -2280,7 +2280,8 @@ void amdgpu_ras_debugfs_create_all(struct amdgpu_device *adev)
|
|||
list_for_each_entry(obj, &con->head, node) {
|
||||
if (amdgpu_ras_is_supported(adev, obj->head.block) &&
|
||||
(obj->attr_inuse == 1)) {
|
||||
sprintf(fs_info.debugfs_name, "%s_err_inject",
|
||||
snprintf(fs_info.debugfs_name, sizeof(fs_info.debugfs_name),
|
||||
"%s_err_inject",
|
||||
get_ras_block_str(&obj->head));
|
||||
fs_info.head = obj->head;
|
||||
amdgpu_ras_debugfs_create(adev, &fs_info, dir);
|
||||
|
|
|
|||
|
|
@ -215,33 +215,15 @@ void amdgpu_userq_process_fence_irq(struct amdgpu_device *adev, u32 doorbell)
|
|||
xa_unlock_irqrestore(xa, flags);
|
||||
}
|
||||
|
||||
static int amdgpu_userq_buffer_va_list_add(struct amdgpu_usermode_queue *queue,
|
||||
struct amdgpu_bo_va_mapping *va_map, u64 addr)
|
||||
{
|
||||
struct amdgpu_userq_va_cursor *va_cursor;
|
||||
struct userq_va_list;
|
||||
|
||||
va_cursor = kzalloc_obj(*va_cursor);
|
||||
if (!va_cursor)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&va_cursor->list);
|
||||
va_cursor->gpu_addr = addr;
|
||||
va_map->bo_va->userq_va_mapped = true;
|
||||
list_add(&va_cursor->list, &queue->userq_va_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amdgpu_userq_input_va_validate(struct amdgpu_device *adev,
|
||||
struct amdgpu_usermode_queue *queue,
|
||||
u64 addr, u64 expected_size)
|
||||
u64 addr, u64 expected_size,
|
||||
u64 *va_out)
|
||||
{
|
||||
struct amdgpu_bo_va_mapping *va_map;
|
||||
struct amdgpu_vm *vm = queue->vm;
|
||||
u64 user_addr;
|
||||
u64 size;
|
||||
int r = 0;
|
||||
|
||||
/* Caller must hold vm->root.bo reservation */
|
||||
dma_resv_assert_held(queue->vm->root.bo->tbo.base.resv);
|
||||
|
|
@ -250,20 +232,18 @@ int amdgpu_userq_input_va_validate(struct amdgpu_device *adev,
|
|||
size = expected_size >> AMDGPU_GPU_PAGE_SHIFT;
|
||||
|
||||
va_map = amdgpu_vm_bo_lookup_mapping(vm, user_addr);
|
||||
if (!va_map) {
|
||||
r = -EINVAL;
|
||||
goto out_err;
|
||||
}
|
||||
if (!va_map)
|
||||
return -EINVAL;
|
||||
|
||||
/* Only validate the userq whether resident in the VM mapping range */
|
||||
if (user_addr >= va_map->start &&
|
||||
va_map->last - user_addr + 1 >= size) {
|
||||
amdgpu_userq_buffer_va_list_add(queue, va_map, user_addr);
|
||||
va_map->bo_va->userq_va_mapped = true;
|
||||
*va_out = user_addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = -EINVAL;
|
||||
out_err:
|
||||
return r;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static bool amdgpu_userq_buffer_va_mapped(struct amdgpu_vm *vm, u64 addr)
|
||||
|
|
@ -284,14 +264,16 @@ static bool amdgpu_userq_buffer_va_mapped(struct amdgpu_vm *vm, u64 addr)
|
|||
|
||||
static bool amdgpu_userq_buffer_vas_mapped(struct amdgpu_usermode_queue *queue)
|
||||
{
|
||||
struct amdgpu_userq_va_cursor *va_cursor, *tmp;
|
||||
int r = 0;
|
||||
int i, r = 0;
|
||||
|
||||
list_for_each_entry_safe(va_cursor, tmp, &queue->userq_va_list, list) {
|
||||
r += amdgpu_userq_buffer_va_mapped(queue->vm, va_cursor->gpu_addr);
|
||||
for (i = 0; i < ARRAY_SIZE(queue->userq_vas.va_array); i++) {
|
||||
if (!queue->userq_vas.va_array[i])
|
||||
continue;
|
||||
r += amdgpu_userq_buffer_va_mapped(queue->vm,
|
||||
queue->userq_vas.va_array[i]);
|
||||
dev_dbg(queue->userq_mgr->adev->dev,
|
||||
"validate the userq mapping:%p va:%llx r:%d\n",
|
||||
queue, va_cursor->gpu_addr, r);
|
||||
queue, queue->userq_vas.va_array[i], r);
|
||||
}
|
||||
|
||||
if (r != 0)
|
||||
|
|
@ -300,24 +282,7 @@ static bool amdgpu_userq_buffer_vas_mapped(struct amdgpu_usermode_queue *queue)
|
|||
return false;
|
||||
}
|
||||
|
||||
static void amdgpu_userq_buffer_vas_list_cleanup(struct amdgpu_device *adev,
|
||||
struct amdgpu_usermode_queue *queue)
|
||||
{
|
||||
struct amdgpu_userq_va_cursor *va_cursor, *tmp;
|
||||
struct amdgpu_bo_va_mapping *mapping;
|
||||
|
||||
/* Caller must hold vm->root.bo reservation */
|
||||
dma_resv_assert_held(queue->vm->root.bo->tbo.base.resv);
|
||||
|
||||
list_for_each_entry_safe(va_cursor, tmp, &queue->userq_va_list, list) {
|
||||
mapping = amdgpu_vm_bo_lookup_mapping(queue->vm, va_cursor->gpu_addr);
|
||||
if (mapping)
|
||||
dev_dbg(adev->dev, "delete the userq:%p va:%llx\n",
|
||||
queue, va_cursor->gpu_addr);
|
||||
list_del(&va_cursor->list);
|
||||
kfree(va_cursor);
|
||||
}
|
||||
}
|
||||
|
||||
static int amdgpu_userq_preempt_helper(struct amdgpu_usermode_queue *queue)
|
||||
{
|
||||
|
|
@ -417,18 +382,14 @@ static void amdgpu_userq_cleanup(struct amdgpu_usermode_queue *queue)
|
|||
{
|
||||
struct amdgpu_userq_mgr *uq_mgr = queue->userq_mgr;
|
||||
struct amdgpu_device *adev = uq_mgr->adev;
|
||||
const struct amdgpu_userq_funcs *uq_funcs = adev->userq_funcs[queue->queue_type];
|
||||
|
||||
/* Wait for mode-1 reset to complete */
|
||||
down_read(&adev->reset_domain->sem);
|
||||
|
||||
uq_funcs->mqd_destroy(queue);
|
||||
/* Use interrupt-safe locking since IRQ handlers may access these XArrays */
|
||||
xa_erase_irq(&adev->userq_doorbell_xa, queue->doorbell_index);
|
||||
amdgpu_userq_fence_driver_free(queue);
|
||||
queue->fence_drv = NULL;
|
||||
queue->userq_mgr = NULL;
|
||||
list_del(&queue->userq_va_list);
|
||||
|
||||
up_read(&adev->reset_domain->sem);
|
||||
}
|
||||
|
|
@ -467,81 +428,15 @@ amdgpu_userq_ensure_ev_fence(struct amdgpu_userq_mgr *uq_mgr,
|
|||
dma_fence_put(ev_fence);
|
||||
}
|
||||
|
||||
int amdgpu_userq_create_object(struct amdgpu_userq_mgr *uq_mgr,
|
||||
struct amdgpu_userq_obj *userq_obj,
|
||||
int size)
|
||||
{
|
||||
struct amdgpu_device *adev = uq_mgr->adev;
|
||||
struct amdgpu_bo_param bp;
|
||||
int r;
|
||||
|
||||
memset(&bp, 0, sizeof(bp));
|
||||
bp.byte_align = PAGE_SIZE;
|
||||
bp.domain = AMDGPU_GEM_DOMAIN_GTT;
|
||||
bp.flags = AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS |
|
||||
AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
|
||||
bp.type = ttm_bo_type_kernel;
|
||||
bp.size = size;
|
||||
bp.resv = NULL;
|
||||
bp.bo_ptr_size = sizeof(struct amdgpu_bo);
|
||||
|
||||
r = amdgpu_bo_create(adev, &bp, &userq_obj->obj);
|
||||
if (r) {
|
||||
drm_file_err(uq_mgr->file, "Failed to allocate BO for userqueue (%d)", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = amdgpu_bo_reserve(userq_obj->obj, true);
|
||||
if (r) {
|
||||
drm_file_err(uq_mgr->file, "Failed to reserve BO to map (%d)", r);
|
||||
goto free_obj;
|
||||
}
|
||||
|
||||
r = amdgpu_bo_pin(userq_obj->obj, AMDGPU_GEM_DOMAIN_GTT);
|
||||
if (r)
|
||||
goto unresv;
|
||||
|
||||
r = amdgpu_ttm_alloc_gart(&(userq_obj->obj)->tbo);
|
||||
if (r) {
|
||||
drm_file_err(uq_mgr->file, "Failed to alloc GART for userqueue object (%d)", r);
|
||||
goto unpin_bo;
|
||||
}
|
||||
|
||||
r = amdgpu_bo_kmap(userq_obj->obj, &userq_obj->cpu_ptr);
|
||||
if (r) {
|
||||
drm_file_err(uq_mgr->file, "Failed to map BO for userqueue (%d)", r);
|
||||
goto unpin_bo;
|
||||
}
|
||||
|
||||
userq_obj->gpu_addr = amdgpu_bo_gpu_offset(userq_obj->obj);
|
||||
amdgpu_bo_unreserve(userq_obj->obj);
|
||||
memset(userq_obj->cpu_ptr, 0, size);
|
||||
return 0;
|
||||
|
||||
unpin_bo:
|
||||
amdgpu_bo_unpin(userq_obj->obj);
|
||||
unresv:
|
||||
amdgpu_bo_unreserve(userq_obj->obj);
|
||||
free_obj:
|
||||
amdgpu_bo_unref(&userq_obj->obj);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void amdgpu_userq_destroy_object(struct amdgpu_userq_mgr *uq_mgr,
|
||||
struct amdgpu_userq_obj *userq_obj)
|
||||
{
|
||||
amdgpu_bo_kunmap(userq_obj->obj);
|
||||
amdgpu_bo_unpin(userq_obj->obj);
|
||||
amdgpu_bo_unref(&userq_obj->obj);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
static int
|
||||
amdgpu_userq_get_doorbell_index(struct amdgpu_userq_mgr *uq_mgr,
|
||||
struct amdgpu_db_info *db_info,
|
||||
struct drm_file *filp)
|
||||
struct drm_file *filp,
|
||||
u64 *index)
|
||||
{
|
||||
uint64_t index;
|
||||
u64 doorbell_index;
|
||||
struct drm_gem_object *gobj;
|
||||
struct amdgpu_userq_obj *db_obj = db_info->db_obj;
|
||||
int r, db_size;
|
||||
|
|
@ -588,12 +483,13 @@ amdgpu_userq_get_doorbell_index(struct amdgpu_userq_mgr *uq_mgr,
|
|||
goto unpin_bo;
|
||||
}
|
||||
|
||||
index = amdgpu_doorbell_index_on_bar(uq_mgr->adev, db_obj->obj,
|
||||
db_info->doorbell_offset, db_size);
|
||||
doorbell_index = amdgpu_doorbell_index_on_bar(uq_mgr->adev, db_obj->obj,
|
||||
db_info->doorbell_offset, db_size);
|
||||
drm_dbg_driver(adev_to_drm(uq_mgr->adev),
|
||||
"[Usermode queues] doorbell index=%lld\n", index);
|
||||
"[Usermode queues] doorbell index=%lld\n", doorbell_index);
|
||||
amdgpu_bo_unreserve(db_obj->obj);
|
||||
return index;
|
||||
*index = doorbell_index;
|
||||
return 0;
|
||||
|
||||
unpin_bo:
|
||||
amdgpu_bo_unpin(db_obj->obj);
|
||||
|
|
@ -608,9 +504,7 @@ static int
|
|||
amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_queue *queue)
|
||||
{
|
||||
struct amdgpu_device *adev = uq_mgr->adev;
|
||||
struct amdgpu_fpriv *fpriv = uq_mgr_to_fpriv(uq_mgr);
|
||||
struct amdgpu_vm *vm = &fpriv->vm;
|
||||
|
||||
const struct amdgpu_userq_funcs *uq_funcs = adev->userq_funcs[queue->queue_type];
|
||||
int r = 0;
|
||||
|
||||
cancel_delayed_work_sync(&uq_mgr->resume_work);
|
||||
|
|
@ -618,14 +512,6 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que
|
|||
/* Cancel any pending hang detection work and cleanup */
|
||||
cancel_delayed_work_sync(&queue->hang_detect_work);
|
||||
|
||||
r = amdgpu_bo_reserve(vm->root.bo, false);
|
||||
if (r) {
|
||||
drm_file_err(uq_mgr->file, "Failed to reserve root bo during userqueue destroy\n");
|
||||
return r;
|
||||
}
|
||||
amdgpu_userq_buffer_vas_list_cleanup(adev, queue);
|
||||
amdgpu_bo_unreserve(vm->root.bo);
|
||||
|
||||
mutex_lock(&uq_mgr->userq_mutex);
|
||||
amdgpu_userq_wait_for_last_fence(queue);
|
||||
|
||||
|
|
@ -637,6 +523,10 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que
|
|||
amdgpu_userq_cleanup(queue);
|
||||
mutex_unlock(&uq_mgr->userq_mutex);
|
||||
|
||||
cancel_delayed_work_sync(&queue->hang_detect_work);
|
||||
uq_funcs->mqd_destroy(queue);
|
||||
queue->userq_mgr = NULL;
|
||||
|
||||
amdgpu_bo_reserve(queue->db_obj.obj, true);
|
||||
amdgpu_bo_unpin(queue->db_obj.obj);
|
||||
amdgpu_bo_unreserve(queue->db_obj.obj);
|
||||
|
|
@ -739,7 +629,6 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
|
|||
}
|
||||
|
||||
kref_init(&queue->refcount);
|
||||
INIT_LIST_HEAD(&queue->userq_va_list);
|
||||
queue->doorbell_handle = args->in.doorbell_handle;
|
||||
queue->queue_type = args->in.ip_type;
|
||||
queue->vm = &fpriv->vm;
|
||||
|
|
@ -748,26 +637,29 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
|
|||
INIT_DELAYED_WORK(&queue->hang_detect_work,
|
||||
amdgpu_userq_hang_detect_work);
|
||||
|
||||
mutex_init(&queue->fence_drv_lock);
|
||||
xa_init_flags(&queue->fence_drv_xa, XA_FLAGS_ALLOC);
|
||||
r = amdgpu_userq_fence_driver_alloc(adev, &queue->fence_drv);
|
||||
if (r)
|
||||
goto free_queue;
|
||||
|
||||
xa_init_flags(&queue->fence_drv_xa, XA_FLAGS_ALLOC);
|
||||
mutex_init(&queue->fence_drv_lock);
|
||||
/* Make sure the queue can actually run with those virtual addresses. */
|
||||
r = amdgpu_bo_reserve(fpriv->vm.root.bo, false);
|
||||
if (r)
|
||||
goto free_fence_drv;
|
||||
|
||||
if (amdgpu_userq_input_va_validate(adev, queue, args->in.queue_va,
|
||||
args->in.queue_size) ||
|
||||
args->in.queue_size,
|
||||
&queue->userq_vas.va.queue_rb) ||
|
||||
amdgpu_userq_input_va_validate(adev, queue, args->in.rptr_va,
|
||||
AMDGPU_GPU_PAGE_SIZE) ||
|
||||
AMDGPU_GPU_PAGE_SIZE,
|
||||
&queue->userq_vas.va.rptr) ||
|
||||
amdgpu_userq_input_va_validate(adev, queue, args->in.wptr_va,
|
||||
AMDGPU_GPU_PAGE_SIZE)) {
|
||||
AMDGPU_GPU_PAGE_SIZE,
|
||||
&queue->userq_vas.va.wptr)) {
|
||||
r = -EINVAL;
|
||||
amdgpu_bo_unreserve(fpriv->vm.root.bo);
|
||||
goto clean_mapping;
|
||||
goto free_fence_drv;
|
||||
}
|
||||
amdgpu_bo_unreserve(fpriv->vm.root.bo);
|
||||
|
||||
|
|
@ -776,18 +668,17 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
|
|||
db_info.doorbell_handle = queue->doorbell_handle;
|
||||
db_info.db_obj = &queue->db_obj;
|
||||
db_info.doorbell_offset = args->in.doorbell_offset;
|
||||
index = amdgpu_userq_get_doorbell_index(uq_mgr, &db_info, filp);
|
||||
if (index == (uint64_t)-EINVAL) {
|
||||
r = amdgpu_userq_get_doorbell_index(uq_mgr, &db_info, filp, &index);
|
||||
if (r) {
|
||||
drm_file_err(uq_mgr->file, "Failed to get doorbell for queue\n");
|
||||
r = -EINVAL;
|
||||
goto clean_mapping;
|
||||
goto free_fence_drv;
|
||||
}
|
||||
|
||||
queue->doorbell_index = index;
|
||||
r = uq_funcs->mqd_create(queue, &args->in);
|
||||
if (r) {
|
||||
drm_file_err(uq_mgr->file, "Failed to create Queue\n");
|
||||
goto clean_mapping;
|
||||
goto clean_doorbell_bo;
|
||||
}
|
||||
|
||||
/* Update VM owner at userq submit-time for page-fault attribution. */
|
||||
|
|
@ -808,7 +699,7 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
|
|||
if (r) {
|
||||
drm_file_err(uq_mgr->file, "Failed to map Queue\n");
|
||||
mutex_unlock(&uq_mgr->userq_mutex);
|
||||
goto clean_doorbell;
|
||||
goto erase_doorbell;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -831,15 +722,15 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
|
|||
args->out.queue_id = qid;
|
||||
return 0;
|
||||
|
||||
clean_doorbell:
|
||||
erase_doorbell:
|
||||
xa_erase_irq(&adev->userq_doorbell_xa, index);
|
||||
clean_mqd:
|
||||
uq_funcs->mqd_destroy(queue);
|
||||
clean_mapping:
|
||||
amdgpu_bo_reserve(fpriv->vm.root.bo, true);
|
||||
amdgpu_userq_buffer_vas_list_cleanup(adev, queue);
|
||||
amdgpu_bo_unreserve(fpriv->vm.root.bo);
|
||||
mutex_destroy(&queue->fence_drv_lock);
|
||||
clean_doorbell_bo:
|
||||
amdgpu_bo_reserve(queue->db_obj.obj, true);
|
||||
amdgpu_bo_unpin(queue->db_obj.obj);
|
||||
amdgpu_bo_unreserve(queue->db_obj.obj);
|
||||
amdgpu_bo_unref(&queue->db_obj.obj);
|
||||
free_fence_drv:
|
||||
amdgpu_userq_fence_driver_free(queue);
|
||||
free_queue:
|
||||
|
|
|
|||
|
|
@ -48,11 +48,6 @@ struct amdgpu_userq_obj {
|
|||
struct amdgpu_bo *obj;
|
||||
};
|
||||
|
||||
struct amdgpu_userq_va_cursor {
|
||||
u64 gpu_addr;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct amdgpu_usermode_queue {
|
||||
int queue_type;
|
||||
enum amdgpu_userq_state state;
|
||||
|
|
@ -93,7 +88,17 @@ struct amdgpu_usermode_queue {
|
|||
struct delayed_work hang_detect_work;
|
||||
struct kref refcount;
|
||||
|
||||
struct list_head userq_va_list;
|
||||
union {
|
||||
struct {
|
||||
u64 queue_rb;
|
||||
u64 wptr;
|
||||
u64 rptr;
|
||||
u64 eop;
|
||||
u64 shadow;
|
||||
u64 csa;
|
||||
} va;
|
||||
u64 va_array[6];
|
||||
} userq_vas;
|
||||
};
|
||||
|
||||
struct amdgpu_userq_funcs {
|
||||
|
|
@ -151,22 +156,11 @@ void amdgpu_userq_mgr_cancel_reset_work(struct amdgpu_device *adev);
|
|||
void amdgpu_userq_mgr_cancel_resume(struct amdgpu_userq_mgr *userq_mgr);
|
||||
void amdgpu_userq_mgr_fini(struct amdgpu_userq_mgr *userq_mgr);
|
||||
|
||||
int amdgpu_userq_create_object(struct amdgpu_userq_mgr *uq_mgr,
|
||||
struct amdgpu_userq_obj *userq_obj,
|
||||
int size);
|
||||
|
||||
void amdgpu_userq_destroy_object(struct amdgpu_userq_mgr *uq_mgr,
|
||||
struct amdgpu_userq_obj *userq_obj);
|
||||
|
||||
void amdgpu_userq_evict(struct amdgpu_userq_mgr *uq_mgr);
|
||||
|
||||
void amdgpu_userq_ensure_ev_fence(struct amdgpu_userq_mgr *userq_mgr,
|
||||
struct amdgpu_eviction_fence_mgr *evf_mgr);
|
||||
|
||||
uint64_t amdgpu_userq_get_doorbell_index(struct amdgpu_userq_mgr *uq_mgr,
|
||||
struct amdgpu_db_info *db_info,
|
||||
struct drm_file *filp);
|
||||
|
||||
u32 amdgpu_userq_get_supported_ip_mask(struct amdgpu_device *adev);
|
||||
bool amdgpu_userq_enabled(struct drm_device *dev);
|
||||
|
||||
|
|
@ -185,7 +179,8 @@ void amdgpu_userq_process_fence_irq(struct amdgpu_device *adev, u32 doorbell);
|
|||
|
||||
int amdgpu_userq_input_va_validate(struct amdgpu_device *adev,
|
||||
struct amdgpu_usermode_queue *queue,
|
||||
u64 addr, u64 expected_size);
|
||||
u64 addr, u64 expected_size, u64 *va_out);
|
||||
|
||||
void amdgpu_userq_gem_va_unmap_validate(struct amdgpu_device *adev,
|
||||
struct amdgpu_bo_va_mapping *mapping,
|
||||
uint64_t saddr);
|
||||
|
|
|
|||
|
|
@ -1804,13 +1804,15 @@ amdgpu_virt_write_cpers_to_ring(struct amdgpu_device *adev,
|
|||
struct amd_sriov_ras_cper_dump *cper_dump = NULL;
|
||||
struct cper_hdr *entry = NULL;
|
||||
struct amdgpu_ring *ring = &adev->cper.ring_buf;
|
||||
uint32_t checksum, used_size, i;
|
||||
uint32_t checksum, used_size;
|
||||
u64 remaining, cnt, i;
|
||||
int ret = 0;
|
||||
|
||||
checksum = host_telemetry->header.checksum;
|
||||
used_size = host_telemetry->header.used_size;
|
||||
|
||||
if (used_size > (AMD_SRIOV_MSG_RAS_TELEMETRY_SIZE_KB_V1 << 10))
|
||||
if (used_size < offsetof(struct amd_sriov_ras_cper_dump, buf) ||
|
||||
used_size > (AMD_SRIOV_MSG_RAS_TELEMETRY_SIZE_KB_V1 << 10))
|
||||
return -EINVAL;
|
||||
|
||||
cper_dump = kmemdup(&host_telemetry->body.cper_dump, used_size, GFP_KERNEL);
|
||||
|
|
@ -1835,11 +1837,19 @@ amdgpu_virt_write_cpers_to_ring(struct amdgpu_device *adev,
|
|||
}
|
||||
|
||||
entry = (struct cper_hdr *)&cper_dump->buf[0];
|
||||
remaining = (u64)used_size - offsetof(struct amd_sriov_ras_cper_dump, buf);
|
||||
cnt = min_t(u64, cper_dump->count, CPER_MAX_ALLOWED_COUNT);
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
if (entry->record_length < sizeof(struct cper_hdr) ||
|
||||
entry->record_length > remaining) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < cper_dump->count; i++) {
|
||||
amdgpu_cper_ring_write(ring, entry, entry->record_length);
|
||||
entry = (struct cper_hdr *)((char *)entry +
|
||||
entry->record_length);
|
||||
remaining -= entry->record_length;
|
||||
entry = (struct cper_hdr *)((char *)entry + entry->record_length);
|
||||
}
|
||||
|
||||
if (cper_dump->overflow_count)
|
||||
|
|
|
|||
|
|
@ -266,12 +266,23 @@ static void amdgpu_vm_bo_idle(struct amdgpu_vm_bo_base *vm_bo)
|
|||
*/
|
||||
static void amdgpu_vm_bo_reset_state_machine(struct amdgpu_vm *vm)
|
||||
{
|
||||
struct amdgpu_vm_bo_base *vm_bo, *tmp;
|
||||
|
||||
/*
|
||||
* Don't use list splice here, we need the special handling for the root
|
||||
* PD and set the moved flag appropriately.
|
||||
*/
|
||||
amdgpu_vm_assert_locked(vm);
|
||||
list_splice_init(&vm->kernel.idle, &vm->kernel.moved);
|
||||
list_splice_init(&vm->always_valid.idle, &vm->always_valid.moved);
|
||||
list_for_each_entry_safe(vm_bo, tmp, &vm->kernel.idle, vm_status)
|
||||
amdgpu_vm_bo_moved(vm_bo);
|
||||
list_for_each_entry_safe(vm_bo, tmp, &vm->always_valid.idle, vm_status)
|
||||
amdgpu_vm_bo_moved(vm_bo);
|
||||
|
||||
spin_lock(&vm->individual_lock);
|
||||
list_splice_init(&vm->individual.idle, &vm->individual.moved);
|
||||
list_for_each_entry_safe(vm_bo, tmp, &vm->individual.idle, vm_status) {
|
||||
vm_bo->moved = true;
|
||||
list_move(&vm_bo->vm_status, &vm->individual.moved);
|
||||
}
|
||||
spin_unlock(&vm->individual_lock);
|
||||
}
|
||||
|
||||
|
|
@ -1600,6 +1611,7 @@ int amdgpu_vm_handle_moved(struct amdgpu_device *adev,
|
|||
{
|
||||
struct amdgpu_bo_va *bo_va, *tmp;
|
||||
struct dma_resv *resv;
|
||||
struct amdgpu_bo *bo;
|
||||
bool clear, unlock;
|
||||
int r;
|
||||
|
||||
|
|
@ -1615,11 +1627,13 @@ int amdgpu_vm_handle_moved(struct amdgpu_device *adev,
|
|||
while (!list_empty(&vm->individual.moved)) {
|
||||
bo_va = list_first_entry(&vm->individual.moved,
|
||||
typeof(*bo_va), base.vm_status);
|
||||
resv = bo_va->base.bo->tbo.base.resv;
|
||||
bo = bo_va->base.bo;
|
||||
resv = bo->tbo.base.resv;
|
||||
spin_unlock(&vm->individual_lock);
|
||||
|
||||
/* Try to reserve the BO to avoid clearing its ptes */
|
||||
if (!adev->debug_vm && dma_resv_trylock(resv)) {
|
||||
if (!adev->debug_vm && !amdgpu_ttm_tt_get_usermm(bo->tbo.ttm) &&
|
||||
dma_resv_trylock(resv)) {
|
||||
clear = false;
|
||||
unlock = true;
|
||||
/* The caller is already holding the reservation lock */
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ mes_userq_create_wptr_mapping(struct amdgpu_device *adev,
|
|||
ret = amdgpu_ttm_alloc_gart(&wptr_obj->obj->tbo);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to bind bo to GART. ret %d\n", ret);
|
||||
goto fail_map;
|
||||
goto fail_alloc_gart;
|
||||
}
|
||||
|
||||
queue->wptr_obj.gpu_addr = amdgpu_bo_gpu_offset(wptr_obj->obj);
|
||||
|
|
@ -89,6 +89,8 @@ mes_userq_create_wptr_mapping(struct amdgpu_device *adev,
|
|||
drm_exec_fini(&exec);
|
||||
return 0;
|
||||
|
||||
fail_alloc_gart:
|
||||
amdgpu_bo_unpin(wptr_obj->obj);
|
||||
fail_map:
|
||||
amdgpu_bo_unref(&wptr_obj->obj);
|
||||
fail_lock:
|
||||
|
|
@ -190,12 +192,16 @@ static int mes_userq_create_ctx_space(struct amdgpu_userq_mgr *uq_mgr,
|
|||
* for the same.
|
||||
*/
|
||||
size = AMDGPU_USERQ_PROC_CTX_SZ + AMDGPU_USERQ_GANG_CTX_SZ;
|
||||
r = amdgpu_userq_create_object(uq_mgr, ctx, size);
|
||||
r = amdgpu_bo_create_kernel(uq_mgr->adev, size, 0,
|
||||
AMDGPU_GEM_DOMAIN_GTT,
|
||||
&ctx->obj, &ctx->gpu_addr,
|
||||
&ctx->cpu_ptr);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed to allocate ctx space bo for userqueue, err:%d\n", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
memset(ctx->cpu_ptr, 0, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -268,13 +274,19 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = amdgpu_userq_create_object(uq_mgr, &queue->mqd,
|
||||
AMDGPU_MQD_SIZE_ALIGN(mqd_hw_default->mqd_size));
|
||||
r = amdgpu_bo_create_kernel(adev,
|
||||
AMDGPU_MQD_SIZE_ALIGN(mqd_hw_default->mqd_size),
|
||||
0, AMDGPU_GEM_DOMAIN_GTT,
|
||||
&queue->mqd.obj, &queue->mqd.gpu_addr,
|
||||
&queue->mqd.cpu_ptr);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed to create MQD object for userqueue\n");
|
||||
goto free_props;
|
||||
}
|
||||
|
||||
memset(queue->mqd.cpu_ptr, 0,
|
||||
AMDGPU_MQD_SIZE_ALIGN(mqd_hw_default->mqd_size));
|
||||
|
||||
/* Initialize the MQD BO with user given values */
|
||||
userq_props->wptr_gpu_addr = mqd_user->wptr_va;
|
||||
userq_props->rptr_gpu_addr = mqd_user->rptr_va;
|
||||
|
|
@ -306,8 +318,9 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
|
|||
kfree(compute_mqd);
|
||||
goto free_mqd;
|
||||
}
|
||||
r = amdgpu_userq_input_va_validate(adev, queue, compute_mqd->eop_va,
|
||||
2048);
|
||||
r = amdgpu_userq_input_va_validate(adev, queue,
|
||||
compute_mqd->eop_va, 2048,
|
||||
&queue->userq_vas.va.eop);
|
||||
amdgpu_bo_unreserve(queue->vm->root.bo);
|
||||
if (r) {
|
||||
kfree(compute_mqd);
|
||||
|
|
@ -356,7 +369,8 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
|
|||
goto free_mqd;
|
||||
}
|
||||
r = amdgpu_userq_input_va_validate(adev, queue, mqd_gfx_v11->shadow_va,
|
||||
shadow_info.shadow_size);
|
||||
shadow_info.shadow_size,
|
||||
&queue->userq_vas.va.shadow);
|
||||
if (r) {
|
||||
amdgpu_bo_unreserve(queue->vm->root.bo);
|
||||
kfree(mqd_gfx_v11);
|
||||
|
|
@ -364,7 +378,8 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
|
|||
}
|
||||
|
||||
r = amdgpu_userq_input_va_validate(adev, queue, mqd_gfx_v11->csa_va,
|
||||
shadow_info.csa_size);
|
||||
shadow_info.csa_size,
|
||||
&queue->userq_vas.va.csa);
|
||||
amdgpu_bo_unreserve(queue->vm->root.bo);
|
||||
if (r) {
|
||||
kfree(mqd_gfx_v11);
|
||||
|
|
@ -394,7 +409,8 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
|
|||
goto free_mqd;
|
||||
}
|
||||
r = amdgpu_userq_input_va_validate(adev, queue, mqd_sdma_v11->csa_va,
|
||||
32);
|
||||
32,
|
||||
&queue->userq_vas.va.csa);
|
||||
amdgpu_bo_unreserve(queue->vm->root.bo);
|
||||
if (r) {
|
||||
kfree(mqd_sdma_v11);
|
||||
|
|
@ -430,10 +446,12 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
|
|||
return 0;
|
||||
|
||||
free_ctx:
|
||||
amdgpu_userq_destroy_object(uq_mgr, &queue->fw_obj);
|
||||
amdgpu_bo_free_kernel(&queue->fw_obj.obj, &queue->fw_obj.gpu_addr,
|
||||
&queue->fw_obj.cpu_ptr);
|
||||
|
||||
free_mqd:
|
||||
amdgpu_userq_destroy_object(uq_mgr, &queue->mqd);
|
||||
amdgpu_bo_free_kernel(&queue->mqd.obj, &queue->mqd.gpu_addr,
|
||||
&queue->mqd.cpu_ptr);
|
||||
|
||||
free_props:
|
||||
kfree(userq_props);
|
||||
|
|
@ -443,11 +461,12 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
|
|||
|
||||
static void mes_userq_mqd_destroy(struct amdgpu_usermode_queue *queue)
|
||||
{
|
||||
struct amdgpu_userq_mgr *uq_mgr = queue->userq_mgr;
|
||||
|
||||
amdgpu_userq_destroy_object(uq_mgr, &queue->fw_obj);
|
||||
amdgpu_bo_free_kernel(&queue->fw_obj.obj, &queue->fw_obj.gpu_addr,
|
||||
&queue->fw_obj.cpu_ptr);
|
||||
kfree(queue->userq_prop);
|
||||
amdgpu_userq_destroy_object(uq_mgr, &queue->mqd);
|
||||
amdgpu_bo_free_kernel(&queue->mqd.obj, &queue->mqd.gpu_addr,
|
||||
&queue->mqd.cpu_ptr);
|
||||
}
|
||||
|
||||
static int mes_userq_preempt(struct amdgpu_usermode_queue *queue)
|
||||
|
|
|
|||
|
|
@ -285,7 +285,8 @@ static int umc_v12_0_convert_error_address(struct amdgpu_device *adev,
|
|||
struct ta_ras_query_address_output *addr_out,
|
||||
bool dump_addr)
|
||||
{
|
||||
uint32_t col, col_lower, row, row_lower, row_high, bank;
|
||||
uint32_t row = 0, row_lower = 0, row_high = 0;
|
||||
uint32_t col = 0, col_lower = 0, bank = 0;
|
||||
uint32_t channel_index = 0, umc_inst = 0;
|
||||
uint32_t i, bit_num, retire_unit, *flip_bits;
|
||||
uint64_t soc_pa, column, err_addr;
|
||||
|
|
|
|||
|
|
@ -2399,6 +2399,11 @@ static int criu_restore_devices(struct kfd_process *p,
|
|||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (pdd->drm_file) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
pdd->user_gpu_id = device_buckets[i].user_gpu_id;
|
||||
|
||||
drm_file = fget(device_buckets[i].drm_fd);
|
||||
|
|
@ -2409,11 +2414,6 @@ static int criu_restore_devices(struct kfd_process *p,
|
|||
goto exit;
|
||||
}
|
||||
|
||||
if (pdd->drm_file) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* create the vm using render nodes for kfd pdd */
|
||||
if (kfd_process_device_init_vm(pdd, drm_file)) {
|
||||
pr_err("could not init vm for given pdd\n");
|
||||
|
|
|
|||
|
|
@ -1821,7 +1821,7 @@ static int kfd_fill_mem_info_for_cpu(int numa_node_id, int *avail_size,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
#if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
|
||||
static int kfd_fill_iolink_info_for_cpu(int numa_node_id, int *avail_size,
|
||||
uint32_t *num_entries,
|
||||
struct crat_subtype_iolink *sub_type_hdr)
|
||||
|
|
@ -1880,7 +1880,7 @@ static int kfd_create_vcrat_image_cpu(void *pcrat_image, size_t *size)
|
|||
struct crat_subtype_generic *sub_type_hdr;
|
||||
int avail_size = *size;
|
||||
int numa_node_id;
|
||||
#ifdef CONFIG_X86_64
|
||||
#if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
|
||||
uint32_t entries = 0;
|
||||
#endif
|
||||
int ret = 0;
|
||||
|
|
@ -1945,7 +1945,7 @@ static int kfd_create_vcrat_image_cpu(void *pcrat_image, size_t *size)
|
|||
sub_type_hdr->length);
|
||||
|
||||
/* Fill in Subtype: IO Link */
|
||||
#ifdef CONFIG_X86_64
|
||||
#if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
|
||||
ret = kfd_fill_iolink_info_for_cpu(numa_node_id, &avail_size,
|
||||
&entries,
|
||||
(struct crat_subtype_iolink *)sub_type_hdr);
|
||||
|
|
|
|||
|
|
@ -3477,12 +3477,14 @@ static void copy_context_work_handler(struct work_struct *work)
|
|||
|
||||
static uint32_t *get_queue_ids(uint32_t num_queues, uint32_t *usr_queue_id_array)
|
||||
{
|
||||
size_t array_size = num_queues * sizeof(uint32_t);
|
||||
|
||||
if (!usr_queue_id_array)
|
||||
return NULL;
|
||||
|
||||
return memdup_user(usr_queue_id_array, array_size);
|
||||
if (num_queues > KFD_MAX_NUM_OF_QUEUES_PER_PROCESS)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return memdup_user(usr_queue_id_array,
|
||||
array_size(num_queues, sizeof(uint32_t)));
|
||||
}
|
||||
|
||||
int resume_queues(struct kfd_process *p,
|
||||
|
|
|
|||
|
|
@ -3732,6 +3732,9 @@ svm_range_set_attr(struct kfd_process *p, struct mm_struct *mm,
|
|||
|
||||
svms = &p->svms;
|
||||
|
||||
if (!process_info)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&process_info->lock);
|
||||
|
||||
svm_range_list_lock_and_flush_work(svms, mm);
|
||||
|
|
|
|||
|
|
@ -2350,7 +2350,7 @@ static int kfd_cpumask_to_apic_id(const struct cpumask *cpumask)
|
|||
first_cpu_of_numa_node = cpumask_first(cpumask);
|
||||
if (first_cpu_of_numa_node >= nr_cpu_ids)
|
||||
return -1;
|
||||
#ifdef CONFIG_X86_64
|
||||
#if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
|
||||
return cpu_data(first_cpu_of_numa_node).topo.apicid;
|
||||
#else
|
||||
return first_cpu_of_numa_node;
|
||||
|
|
|
|||
|
|
@ -56,4 +56,16 @@ config DRM_AMD_SECURE_DISPLAY
|
|||
This option enables the calculation of crc of specific region via
|
||||
debugfs. Cooperate with specific DMCU FW.
|
||||
|
||||
config DRM_AMD_DC_KUNIT_TEST
|
||||
tristate "KUnit tests for the AMD DC display driver" if !KUNIT_ALL_TESTS
|
||||
depends on DRM_AMD_DC && KUNIT && DEBUG_FS
|
||||
default KUNIT_ALL_TESTS
|
||||
help
|
||||
This option enables KUnit tests for the AMD Display Core driver.
|
||||
These tests validate core functionality like CRC source parsing,
|
||||
color management, and other utility functions.
|
||||
|
||||
For more information on KUnit and unit tests in general, please
|
||||
refer to the KUnit documentation in Documentation/dev-tools/kunit/.
|
||||
|
||||
endmenu
|
||||
|
|
|
|||
|
|
@ -59,3 +59,8 @@ AMDGPU_DM = $(addprefix $(AMDDALPATH)/amdgpu_dm/,$(AMDGPUDM))
|
|||
|
||||
AMD_DISPLAY_FILES += $(AMDGPU_DM)
|
||||
endif
|
||||
|
||||
# KUnit tests as separate module
|
||||
ifneq ($(CONFIG_DRM_AMD_DC_KUNIT_TEST),)
|
||||
obj-y += $(AMDDALPATH)/amdgpu_dm/tests/
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -7473,7 +7473,7 @@ create_stream_for_sink(struct drm_connector *connector,
|
|||
int preferred_refresh = 0;
|
||||
enum color_transfer_func tf = TRANSFER_FUNC_UNKNOWN;
|
||||
#if defined(CONFIG_DRM_AMD_DC_FP)
|
||||
struct dsc_dec_dpcd_caps dsc_caps;
|
||||
struct dsc_dec_dpcd_caps dsc_caps = {0};
|
||||
#endif
|
||||
struct dc_link *link = NULL;
|
||||
struct dc_sink *sink = NULL;
|
||||
|
|
|
|||
|
|
@ -45,8 +45,6 @@
|
|||
* in amdgpu_dm_kms.h file
|
||||
*/
|
||||
|
||||
#define AMDGPU_DM_MAX_DISPLAY_INDEX 31
|
||||
|
||||
#define AMDGPU_DM_MAX_CRTC 6
|
||||
|
||||
#define AMDGPU_DM_MAX_NUM_EDP 2
|
||||
|
|
|
|||
|
|
@ -29,9 +29,12 @@
|
|||
#include "amdgpu.h"
|
||||
#include "amdgpu_mode.h"
|
||||
#include "amdgpu_dm.h"
|
||||
#include "amdgpu_dm_color.h"
|
||||
#include "amdgpu_dm_colorop.h"
|
||||
#include "dc.h"
|
||||
#include "modules/color/color_gamma.h"
|
||||
#include "amdgpu_dm_kunit_helpers.h"
|
||||
|
||||
|
||||
/**
|
||||
* DOC: overview
|
||||
|
|
@ -157,8 +160,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#define MAX_DRM_LUT_VALUE 0xFFFF
|
||||
#define MAX_DRM_LUT32_VALUE 0xFFFFFFFF
|
||||
#define SDR_WHITE_LEVEL_INIT_VALUE 80
|
||||
|
||||
/**
|
||||
|
|
@ -172,7 +173,8 @@ void amdgpu_dm_init_color_mod(void)
|
|||
setup_x_points_distribution();
|
||||
}
|
||||
|
||||
static inline struct fixed31_32 amdgpu_dm_fixpt_from_s3132(__u64 x)
|
||||
STATIC_IFN_KUNIT INLINE_IFN_KUNIT
|
||||
struct fixed31_32 amdgpu_dm_fixpt_from_s3132(__u64 x)
|
||||
{
|
||||
struct fixed31_32 val;
|
||||
|
||||
|
|
@ -183,6 +185,7 @@ static inline struct fixed31_32 amdgpu_dm_fixpt_from_s3132(__u64 x)
|
|||
val.value = x;
|
||||
return val;
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_fixpt_from_s3132);
|
||||
|
||||
#ifdef AMD_PRIVATE_COLOR
|
||||
/* Pre-defined Transfer Functions (TF)
|
||||
|
|
@ -421,12 +424,14 @@ amdgpu_dm_create_color_properties(struct amdgpu_device *adev)
|
|||
* Returns:
|
||||
* DRM LUT or NULL
|
||||
*/
|
||||
static const struct drm_color_lut *
|
||||
STATIC_IFN_KUNIT
|
||||
const struct drm_color_lut *
|
||||
__extract_blob_lut(const struct drm_property_blob *blob, uint32_t *size)
|
||||
{
|
||||
*size = blob ? drm_color_lut_size(blob) : 0;
|
||||
return blob ? (struct drm_color_lut *)blob->data : NULL;
|
||||
}
|
||||
EXPORT_IF_KUNIT(__extract_blob_lut);
|
||||
|
||||
/**
|
||||
* __extract_blob_lut32 - Extracts the DRM lut and lut size from a blob.
|
||||
|
|
@ -436,12 +441,14 @@ __extract_blob_lut(const struct drm_property_blob *blob, uint32_t *size)
|
|||
* Returns:
|
||||
* DRM LUT or NULL
|
||||
*/
|
||||
static const struct drm_color_lut32 *
|
||||
STATIC_IFN_KUNIT
|
||||
const struct drm_color_lut32 *
|
||||
__extract_blob_lut32(const struct drm_property_blob *blob, uint32_t *size)
|
||||
{
|
||||
*size = blob ? drm_color_lut32_size(blob) : 0;
|
||||
return blob ? (struct drm_color_lut32 *)blob->data : NULL;
|
||||
}
|
||||
EXPORT_IF_KUNIT(__extract_blob_lut32);
|
||||
|
||||
/**
|
||||
* __is_lut_linear - check if the given lut is a linear mapping of values
|
||||
|
|
@ -456,7 +463,8 @@ __extract_blob_lut32(const struct drm_property_blob *blob, uint32_t *size)
|
|||
* True if the given lut is a linear mapping of values, i.e. it acts like a
|
||||
* bypass LUT. Otherwise, false.
|
||||
*/
|
||||
static bool __is_lut_linear(const struct drm_color_lut *lut, uint32_t size)
|
||||
STATIC_IFN_KUNIT
|
||||
bool __is_lut_linear(const struct drm_color_lut *lut, uint32_t size)
|
||||
{
|
||||
int i;
|
||||
uint32_t expected;
|
||||
|
|
@ -476,6 +484,7 @@ static bool __is_lut_linear(const struct drm_color_lut *lut, uint32_t size)
|
|||
}
|
||||
return true;
|
||||
}
|
||||
EXPORT_IF_KUNIT(__is_lut_linear);
|
||||
|
||||
/**
|
||||
* __drm_lut_to_dc_gamma - convert the drm_color_lut to dc_gamma.
|
||||
|
|
@ -485,7 +494,8 @@ static bool __is_lut_linear(const struct drm_color_lut *lut, uint32_t size)
|
|||
*
|
||||
* The conversion depends on the size of the lut - whether or not it's legacy.
|
||||
*/
|
||||
static void __drm_lut_to_dc_gamma(const struct drm_color_lut *lut,
|
||||
STATIC_IFN_KUNIT
|
||||
void __drm_lut_to_dc_gamma(const struct drm_color_lut *lut,
|
||||
struct dc_gamma *gamma, bool is_legacy)
|
||||
{
|
||||
uint32_t r, g, b;
|
||||
|
|
@ -515,6 +525,7 @@ static void __drm_lut_to_dc_gamma(const struct drm_color_lut *lut,
|
|||
gamma->entries.blue[i] = dc_fixpt_from_fraction(b, MAX_DRM_LUT_VALUE);
|
||||
}
|
||||
}
|
||||
EXPORT_IF_KUNIT(__drm_lut_to_dc_gamma);
|
||||
|
||||
/**
|
||||
* __drm_lut32_to_dc_gamma - convert the drm_color_lut to dc_gamma.
|
||||
|
|
@ -523,7 +534,8 @@ static void __drm_lut_to_dc_gamma(const struct drm_color_lut *lut,
|
|||
*
|
||||
* The conversion depends on the size of the lut - whether or not it's legacy.
|
||||
*/
|
||||
static void __drm_lut32_to_dc_gamma(const struct drm_color_lut32 *lut, struct dc_gamma *gamma)
|
||||
STATIC_IFN_KUNIT
|
||||
void __drm_lut32_to_dc_gamma(const struct drm_color_lut32 *lut, struct dc_gamma *gamma)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
|
@ -533,6 +545,7 @@ static void __drm_lut32_to_dc_gamma(const struct drm_color_lut32 *lut, struct dc
|
|||
gamma->entries.blue[i] = dc_fixpt_from_fraction(lut[i].blue, MAX_DRM_LUT32_VALUE);
|
||||
}
|
||||
}
|
||||
EXPORT_IF_KUNIT(__drm_lut32_to_dc_gamma);
|
||||
|
||||
/**
|
||||
* __drm_ctm_to_dc_matrix - converts a DRM CTM to a DC CSC float matrix
|
||||
|
|
@ -541,8 +554,9 @@ static void __drm_lut32_to_dc_gamma(const struct drm_color_lut32 *lut, struct dc
|
|||
*
|
||||
* The matrix needs to be a 3x4 (12 entry) matrix.
|
||||
*/
|
||||
static void __drm_ctm_to_dc_matrix(const struct drm_color_ctm *ctm,
|
||||
struct fixed31_32 *matrix)
|
||||
STATIC_IFN_KUNIT
|
||||
void __drm_ctm_to_dc_matrix(const struct drm_color_ctm *ctm,
|
||||
struct fixed31_32 *matrix)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
|
@ -565,6 +579,7 @@ static void __drm_ctm_to_dc_matrix(const struct drm_color_ctm *ctm,
|
|||
matrix[i] = amdgpu_dm_fixpt_from_s3132(ctm->matrix[i - (i / 4)]);
|
||||
}
|
||||
}
|
||||
EXPORT_IF_KUNIT(__drm_ctm_to_dc_matrix);
|
||||
|
||||
/**
|
||||
* __drm_ctm_3x4_to_dc_matrix - converts a DRM CTM 3x4 to a DC CSC float matrix
|
||||
|
|
@ -573,8 +588,9 @@ static void __drm_ctm_to_dc_matrix(const struct drm_color_ctm *ctm,
|
|||
*
|
||||
* The matrix needs to be a 3x4 (12 entry) matrix.
|
||||
*/
|
||||
static void __drm_ctm_3x4_to_dc_matrix(const struct drm_color_ctm_3x4 *ctm,
|
||||
struct fixed31_32 *matrix)
|
||||
STATIC_IFN_KUNIT
|
||||
void __drm_ctm_3x4_to_dc_matrix(const struct drm_color_ctm_3x4 *ctm,
|
||||
struct fixed31_32 *matrix)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
|
@ -587,6 +603,7 @@ static void __drm_ctm_3x4_to_dc_matrix(const struct drm_color_ctm_3x4 *ctm,
|
|||
matrix[i] = amdgpu_dm_fixpt_from_s3132(ctm->matrix[i]);
|
||||
}
|
||||
}
|
||||
EXPORT_IF_KUNIT(__drm_ctm_3x4_to_dc_matrix);
|
||||
|
||||
/**
|
||||
* __set_legacy_tf - Calculates the legacy transfer function
|
||||
|
|
@ -851,7 +868,8 @@ static int __set_input_tf_32(struct dc_color_caps *caps, struct dc_transfer_func
|
|||
return res ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
static enum dc_transfer_func_predefined
|
||||
STATIC_IFN_KUNIT
|
||||
enum dc_transfer_func_predefined
|
||||
amdgpu_tf_to_dc_tf(enum amdgpu_transfer_function tf)
|
||||
{
|
||||
switch (tf) {
|
||||
|
|
@ -879,8 +897,10 @@ amdgpu_tf_to_dc_tf(enum amdgpu_transfer_function tf)
|
|||
return TRANSFER_FUNCTION_GAMMA26;
|
||||
}
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_tf_to_dc_tf);
|
||||
|
||||
static enum dc_transfer_func_predefined
|
||||
STATIC_IFN_KUNIT
|
||||
enum dc_transfer_func_predefined
|
||||
amdgpu_colorop_tf_to_dc_tf(enum drm_colorop_curve_1d_type tf)
|
||||
{
|
||||
switch (tf) {
|
||||
|
|
@ -900,8 +920,10 @@ amdgpu_colorop_tf_to_dc_tf(enum drm_colorop_curve_1d_type tf)
|
|||
return TRANSFER_FUNCTION_LINEAR;
|
||||
}
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_colorop_tf_to_dc_tf);
|
||||
|
||||
static void __to_dc_lut3d_color(struct dc_rgb *rgb,
|
||||
STATIC_IFN_KUNIT
|
||||
void __to_dc_lut3d_color(struct dc_rgb *rgb,
|
||||
const struct drm_color_lut lut,
|
||||
int bit_precision)
|
||||
{
|
||||
|
|
@ -909,8 +931,10 @@ static void __to_dc_lut3d_color(struct dc_rgb *rgb,
|
|||
rgb->green = drm_color_lut_extract(lut.green, bit_precision);
|
||||
rgb->blue = drm_color_lut_extract(lut.blue, bit_precision);
|
||||
}
|
||||
EXPORT_IF_KUNIT(__to_dc_lut3d_color);
|
||||
|
||||
static void __drm_3dlut_to_dc_3dlut(const struct drm_color_lut *lut,
|
||||
STATIC_IFN_KUNIT
|
||||
void __drm_3dlut_to_dc_3dlut(const struct drm_color_lut *lut,
|
||||
uint32_t lut3d_size,
|
||||
struct tetrahedral_params *params,
|
||||
bool use_tetrahedral_9,
|
||||
|
|
@ -953,8 +977,10 @@ static void __drm_3dlut_to_dc_3dlut(const struct drm_color_lut *lut,
|
|||
/* lut0 has 1229 points (lut_size/4 + 1) */
|
||||
__to_dc_lut3d_color(&lut0[lut_i], lut[i], bit_depth);
|
||||
}
|
||||
EXPORT_IF_KUNIT(__drm_3dlut_to_dc_3dlut);
|
||||
|
||||
static void __to_dc_lut3d_32_color(struct dc_rgb *rgb,
|
||||
STATIC_IFN_KUNIT
|
||||
void __to_dc_lut3d_32_color(struct dc_rgb *rgb,
|
||||
const struct drm_color_lut32 lut,
|
||||
int bit_precision)
|
||||
{
|
||||
|
|
@ -962,8 +988,10 @@ static void __to_dc_lut3d_32_color(struct dc_rgb *rgb,
|
|||
rgb->green = drm_color_lut32_extract(lut.green, bit_precision);
|
||||
rgb->blue = drm_color_lut32_extract(lut.blue, bit_precision);
|
||||
}
|
||||
EXPORT_IF_KUNIT(__to_dc_lut3d_32_color);
|
||||
|
||||
static void __drm_3dlut32_to_dc_3dlut(const struct drm_color_lut32 *lut,
|
||||
STATIC_IFN_KUNIT
|
||||
void __drm_3dlut32_to_dc_3dlut(const struct drm_color_lut32 *lut,
|
||||
uint32_t lut3d_size,
|
||||
struct tetrahedral_params *params,
|
||||
bool use_tetrahedral_9,
|
||||
|
|
@ -1006,6 +1034,7 @@ static void __drm_3dlut32_to_dc_3dlut(const struct drm_color_lut32 *lut,
|
|||
/* lut0 has 1229 points (lut_size/4 + 1) */
|
||||
__to_dc_lut3d_32_color(&lut0[lut_i], lut[i], bit_depth);
|
||||
}
|
||||
EXPORT_IF_KUNIT(__drm_3dlut32_to_dc_3dlut);
|
||||
|
||||
/* amdgpu_dm_atomic_lut3d - set DRM 3D LUT to DC stream
|
||||
* @drm_lut3d: user 3D LUT
|
||||
|
|
|
|||
89
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.h
Normal file
89
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.h
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright 2026 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 __AMDGPU_DM_COLOR_H__
|
||||
#define __AMDGPU_DM_COLOR_H__
|
||||
|
||||
#define MAX_DRM_LUT_VALUE 0xFFFF
|
||||
#define MAX_DRM_LUT32_VALUE 0xFFFFFFFF
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct drm_color_lut;
|
||||
struct drm_color_lut32;
|
||||
struct drm_color_ctm;
|
||||
struct drm_color_ctm_3x4;
|
||||
struct drm_property_blob;
|
||||
struct dc_gamma;
|
||||
struct dc_rgb;
|
||||
struct fixed31_32;
|
||||
struct tetrahedral_params;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
|
||||
/*
|
||||
* Prototypes for functions exposed to KUnit tests. The enum types
|
||||
* used below (dc_transfer_func_predefined, amdgpu_transfer_function,
|
||||
* drm_colorop_curve_1d_type) must be defined before this header is
|
||||
* included — the source file (amdgpu_dm_color.c) ensures this via
|
||||
* its own includes of dc.h, amdgpu_dm.h, and drm/drm_colorop.h.
|
||||
*/
|
||||
struct fixed31_32 amdgpu_dm_fixpt_from_s3132(__u64 x);
|
||||
bool __is_lut_linear(const struct drm_color_lut *lut, uint32_t size);
|
||||
void __drm_lut_to_dc_gamma(const struct drm_color_lut *lut,
|
||||
struct dc_gamma *gamma, bool is_legacy);
|
||||
void __drm_lut32_to_dc_gamma(const struct drm_color_lut32 *lut,
|
||||
struct dc_gamma *gamma);
|
||||
void __drm_ctm_to_dc_matrix(const struct drm_color_ctm *ctm,
|
||||
struct fixed31_32 *matrix);
|
||||
void __drm_ctm_3x4_to_dc_matrix(const struct drm_color_ctm_3x4 *ctm,
|
||||
struct fixed31_32 *matrix);
|
||||
enum dc_transfer_func_predefined
|
||||
amdgpu_tf_to_dc_tf(enum amdgpu_transfer_function tf);
|
||||
enum dc_transfer_func_predefined
|
||||
amdgpu_colorop_tf_to_dc_tf(enum drm_colorop_curve_1d_type tf);
|
||||
const struct drm_color_lut *
|
||||
__extract_blob_lut(const struct drm_property_blob *blob, uint32_t *size);
|
||||
const struct drm_color_lut32 *
|
||||
__extract_blob_lut32(const struct drm_property_blob *blob, uint32_t *size);
|
||||
void __to_dc_lut3d_color(struct dc_rgb *rgb,
|
||||
const struct drm_color_lut lut,
|
||||
int bit_precision);
|
||||
void __drm_3dlut_to_dc_3dlut(const struct drm_color_lut *lut,
|
||||
uint32_t lut3d_size,
|
||||
struct tetrahedral_params *params,
|
||||
bool use_tetrahedral_9,
|
||||
int bit_depth);
|
||||
void __to_dc_lut3d_32_color(struct dc_rgb *rgb,
|
||||
const struct drm_color_lut32 lut,
|
||||
int bit_precision);
|
||||
void __drm_3dlut32_to_dc_3dlut(const struct drm_color_lut32 *lut,
|
||||
uint32_t lut3d_size,
|
||||
struct tetrahedral_params *params,
|
||||
bool use_tetrahedral_9,
|
||||
int bit_depth);
|
||||
#endif
|
||||
|
||||
#endif /* __AMDGPU_DM_COLOR_H__ */
|
||||
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
#include "amdgpu.h"
|
||||
#include "amdgpu_dm_colorop.h"
|
||||
#include "amdgpu_dm_kunit_helpers.h"
|
||||
#include "dc.h"
|
||||
|
||||
const u64 amdgpu_dm_supported_degam_tfs =
|
||||
|
|
@ -38,18 +39,21 @@ const u64 amdgpu_dm_supported_degam_tfs =
|
|||
BIT(DRM_COLOROP_1D_CURVE_PQ_125_EOTF) |
|
||||
BIT(DRM_COLOROP_1D_CURVE_BT2020_INV_OETF) |
|
||||
BIT(DRM_COLOROP_1D_CURVE_GAMMA22);
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_supported_degam_tfs);
|
||||
|
||||
const u64 amdgpu_dm_supported_shaper_tfs =
|
||||
BIT(DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF) |
|
||||
BIT(DRM_COLOROP_1D_CURVE_PQ_125_INV_EOTF) |
|
||||
BIT(DRM_COLOROP_1D_CURVE_BT2020_OETF) |
|
||||
BIT(DRM_COLOROP_1D_CURVE_GAMMA22_INV);
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_supported_shaper_tfs);
|
||||
|
||||
const u64 amdgpu_dm_supported_blnd_tfs =
|
||||
BIT(DRM_COLOROP_1D_CURVE_SRGB_EOTF) |
|
||||
BIT(DRM_COLOROP_1D_CURVE_PQ_125_EOTF) |
|
||||
BIT(DRM_COLOROP_1D_CURVE_BT2020_INV_OETF) |
|
||||
BIT(DRM_COLOROP_1D_CURVE_GAMMA22);
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_supported_blnd_tfs);
|
||||
|
||||
#define MAX_COLOR_PIPELINE_OPS 10
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include "amdgpu_securedisplay.h"
|
||||
#include "amdgpu_dm_psr.h"
|
||||
#include "amdgpu_dm_replay.h"
|
||||
#include "amdgpu_dm_kunit_helpers.h"
|
||||
|
||||
static const char *const pipe_crc_sources[] = {
|
||||
"none",
|
||||
|
|
@ -43,7 +44,8 @@ static const char *const pipe_crc_sources[] = {
|
|||
"auto",
|
||||
};
|
||||
|
||||
static enum amdgpu_dm_pipe_crc_source dm_parse_crc_source(const char *source)
|
||||
STATIC_IFN_KUNIT
|
||||
enum amdgpu_dm_pipe_crc_source dm_parse_crc_source(const char *source)
|
||||
{
|
||||
if (!source || !strcmp(source, "none"))
|
||||
return AMDGPU_DM_PIPE_CRC_SOURCE_NONE;
|
||||
|
|
@ -58,25 +60,32 @@ static enum amdgpu_dm_pipe_crc_source dm_parse_crc_source(const char *source)
|
|||
|
||||
return AMDGPU_DM_PIPE_CRC_SOURCE_INVALID;
|
||||
}
|
||||
EXPORT_IF_KUNIT(dm_parse_crc_source);
|
||||
|
||||
static bool dm_is_crc_source_crtc(enum amdgpu_dm_pipe_crc_source src)
|
||||
STATIC_IFN_KUNIT
|
||||
bool dm_is_crc_source_crtc(enum amdgpu_dm_pipe_crc_source src)
|
||||
{
|
||||
return (src == AMDGPU_DM_PIPE_CRC_SOURCE_CRTC) ||
|
||||
(src == AMDGPU_DM_PIPE_CRC_SOURCE_CRTC_DITHER);
|
||||
}
|
||||
EXPORT_IF_KUNIT(dm_is_crc_source_crtc);
|
||||
|
||||
static bool dm_is_crc_source_dprx(enum amdgpu_dm_pipe_crc_source src)
|
||||
STATIC_IFN_KUNIT
|
||||
bool dm_is_crc_source_dprx(enum amdgpu_dm_pipe_crc_source src)
|
||||
{
|
||||
return (src == AMDGPU_DM_PIPE_CRC_SOURCE_DPRX) ||
|
||||
(src == AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER);
|
||||
}
|
||||
EXPORT_IF_KUNIT(dm_is_crc_source_dprx);
|
||||
|
||||
static bool dm_need_crc_dither(enum amdgpu_dm_pipe_crc_source src)
|
||||
STATIC_IFN_KUNIT
|
||||
bool dm_need_crc_dither(enum amdgpu_dm_pipe_crc_source src)
|
||||
{
|
||||
return (src == AMDGPU_DM_PIPE_CRC_SOURCE_CRTC_DITHER) ||
|
||||
(src == AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER) ||
|
||||
(src == AMDGPU_DM_PIPE_CRC_SOURCE_NONE);
|
||||
}
|
||||
EXPORT_IF_KUNIT(dm_need_crc_dither);
|
||||
|
||||
const char *const *amdgpu_dm_crtc_get_crc_sources(struct drm_crtc *crtc,
|
||||
size_t *count)
|
||||
|
|
|
|||
|
|
@ -27,8 +27,11 @@
|
|||
#ifndef AMD_DAL_DEV_AMDGPU_DM_AMDGPU_DM_CRC_H_
|
||||
#define AMD_DAL_DEV_AMDGPU_DM_AMDGPU_DM_CRC_H_
|
||||
|
||||
#include "dc_types.h"
|
||||
|
||||
struct drm_crtc;
|
||||
struct dm_crtc_state;
|
||||
struct amdgpu_device;
|
||||
|
||||
enum amdgpu_dm_pipe_crc_source {
|
||||
AMDGPU_DM_PIPE_CRC_SOURCE_NONE = 0,
|
||||
|
|
@ -148,4 +151,11 @@ void amdgpu_dm_crtc_secure_display_create_contexts(struct amdgpu_device *adev);
|
|||
#define amdgpu_dm_crtc_secure_display_create_contexts(x)
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
|
||||
enum amdgpu_dm_pipe_crc_source dm_parse_crc_source(const char *source);
|
||||
bool dm_is_crc_source_crtc(enum amdgpu_dm_pipe_crc_source src);
|
||||
bool dm_is_crc_source_dprx(enum amdgpu_dm_pipe_crc_source src);
|
||||
bool dm_need_crc_dither(enum amdgpu_dm_pipe_crc_source src);
|
||||
#endif
|
||||
|
||||
#endif /* AMD_DAL_DEV_AMDGPU_DM_AMDGPU_DM_CRC_H_ */
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "dm_helpers.h"
|
||||
#include <drm/display/drm_hdcp_helper.h>
|
||||
#include "hdcp_psp.h"
|
||||
#include "amdgpu_dm_kunit_helpers.h"
|
||||
|
||||
/*
|
||||
* If the SRM version being loaded is less than or equal to the
|
||||
|
|
@ -158,7 +159,8 @@ static int psp_set_srm(struct psp_context *psp,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void process_output(struct hdcp_workqueue *hdcp_work)
|
||||
STATIC_IFN_KUNIT
|
||||
void process_output(struct hdcp_workqueue *hdcp_work)
|
||||
{
|
||||
struct mod_hdcp_output output = hdcp_work->output;
|
||||
|
||||
|
|
@ -178,6 +180,7 @@ static void process_output(struct hdcp_workqueue *hdcp_work)
|
|||
|
||||
schedule_delayed_work(&hdcp_work->property_validate_dwork, msecs_to_jiffies(0));
|
||||
}
|
||||
EXPORT_IF_KUNIT(process_output);
|
||||
|
||||
static void link_lock(struct hdcp_workqueue *work, bool lock)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -31,12 +31,19 @@
|
|||
#include "hdcp.h"
|
||||
#include "dc.h"
|
||||
#include "dm_cp_psp.h"
|
||||
#include "amdgpu.h"
|
||||
|
||||
/*
|
||||
* Minimal declarations needed by this header.
|
||||
* Full amdgpu/DM definitions come from amdgpu_dm.h included by each .c file.
|
||||
*/
|
||||
#define AMDGPU_DM_MAX_DISPLAY_INDEX 31
|
||||
struct amdgpu_dm_connector;
|
||||
|
||||
struct mod_hdcp;
|
||||
struct mod_hdcp_link;
|
||||
struct mod_hdcp_display;
|
||||
struct cp_psp;
|
||||
struct amdgpu_device;
|
||||
|
||||
struct hdcp_workqueue {
|
||||
struct work_struct cpirq_work;
|
||||
|
|
@ -87,4 +94,8 @@ void hdcp_destroy(struct kobject *kobj, struct hdcp_workqueue *work);
|
|||
|
||||
struct hdcp_workqueue *hdcp_create_workqueue(struct amdgpu_device *adev, struct cp_psp *cp_psp, struct dc *dc);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
|
||||
void process_output(struct hdcp_workqueue *hdcp_work);
|
||||
#endif
|
||||
|
||||
#endif /* AMDGPU_DM_AMDGPU_DM_HDCP_H_ */
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@
|
|||
#include "amdgpu_dm_ism.h"
|
||||
#include "amdgpu_dm_crtc.h"
|
||||
#include "amdgpu_dm_trace.h"
|
||||
#include "amdgpu_dm_kunit_helpers.h"
|
||||
|
||||
|
||||
/**
|
||||
* dm_ism_next_state - Get next state based on current state and event
|
||||
|
|
@ -42,9 +44,10 @@
|
|||
* This function defines the idle state management FSM. Invalid transitions
|
||||
* are ignored and will not progress the FSM.
|
||||
*/
|
||||
static bool dm_ism_next_state(enum amdgpu_dm_ism_state current_state,
|
||||
enum amdgpu_dm_ism_event event,
|
||||
enum amdgpu_dm_ism_state *next_state)
|
||||
STATIC_IFN_KUNIT
|
||||
bool dm_ism_next_state(enum amdgpu_dm_ism_state current_state,
|
||||
enum amdgpu_dm_ism_event event,
|
||||
enum amdgpu_dm_ism_state *next_state)
|
||||
{
|
||||
switch (STATE_EVENT(current_state, event)) {
|
||||
case STATE_EVENT(DM_ISM_STATE_FULL_POWER_RUNNING,
|
||||
|
|
@ -125,8 +128,10 @@ static bool dm_ism_next_state(enum amdgpu_dm_ism_state current_state,
|
|||
}
|
||||
return true;
|
||||
}
|
||||
EXPORT_IF_KUNIT(dm_ism_next_state);
|
||||
|
||||
static uint64_t dm_ism_get_sso_delay(const struct amdgpu_dm_ism *ism,
|
||||
STATIC_IFN_KUNIT
|
||||
uint64_t dm_ism_get_sso_delay(const struct amdgpu_dm_ism *ism,
|
||||
const struct dc_stream_state *stream)
|
||||
{
|
||||
const struct amdgpu_dm_ism_config *config = &ism->config;
|
||||
|
|
@ -148,6 +153,7 @@ static uint64_t dm_ism_get_sso_delay(const struct amdgpu_dm_ism *ism,
|
|||
|
||||
return sso_delay_ns;
|
||||
}
|
||||
EXPORT_IF_KUNIT(dm_ism_get_sso_delay);
|
||||
|
||||
/**
|
||||
* dm_ism_get_idle_allow_delay - Calculate hysteresis-based idle allow delay
|
||||
|
|
@ -157,8 +163,9 @@ static uint64_t dm_ism_get_sso_delay(const struct amdgpu_dm_ism *ism,
|
|||
* Calculates the delay before allowing idle optimizations based on recent
|
||||
* idle history and the current stream timing.
|
||||
*/
|
||||
static uint64_t dm_ism_get_idle_allow_delay(const struct amdgpu_dm_ism *ism,
|
||||
const struct dc_stream_state *stream)
|
||||
STATIC_IFN_KUNIT
|
||||
uint64_t dm_ism_get_idle_allow_delay(const struct amdgpu_dm_ism *ism,
|
||||
const struct dc_stream_state *stream)
|
||||
{
|
||||
const struct amdgpu_dm_ism_config *config = &ism->config;
|
||||
uint32_t v_total, h_total;
|
||||
|
|
@ -217,6 +224,7 @@ static uint64_t dm_ism_get_idle_allow_delay(const struct amdgpu_dm_ism *ism,
|
|||
|
||||
return ret_ns;
|
||||
}
|
||||
EXPORT_IF_KUNIT(dm_ism_get_idle_allow_delay);
|
||||
|
||||
/**
|
||||
* dm_ism_insert_record - Insert a record into the circular history buffer
|
||||
|
|
@ -375,7 +383,7 @@ static enum amdgpu_dm_ism_event dm_ism_dispatch_power_state(
|
|||
}
|
||||
|
||||
/* Schedule worker */
|
||||
mod_delayed_work(system_unbound_wq, &ism->delayed_work,
|
||||
mod_delayed_work(system_dfl_wq, &ism->delayed_work,
|
||||
nsecs_to_jiffies(delay_ns));
|
||||
|
||||
break;
|
||||
|
|
@ -391,14 +399,14 @@ static enum amdgpu_dm_ism_event dm_ism_dispatch_power_state(
|
|||
* have a negative power impact. Skip idle allow here,
|
||||
* and let the sso_delayed_work handle it.
|
||||
*/
|
||||
mod_delayed_work(system_unbound_wq,
|
||||
mod_delayed_work(system_dfl_wq,
|
||||
&ism->sso_delayed_work,
|
||||
nsecs_to_jiffies(sso_delay_ns));
|
||||
} else {
|
||||
/* Enable idle optimization without SSO */
|
||||
dm_ism_commit_idle_optimization_state(
|
||||
ism, acrtc_state->stream, false, false);
|
||||
mod_delayed_work(system_unbound_wq,
|
||||
mod_delayed_work(system_dfl_wq,
|
||||
&ism->sso_delayed_work,
|
||||
nsecs_to_jiffies(sso_delay_ns));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -149,4 +149,14 @@ void amdgpu_dm_ism_disable(struct amdgpu_display_manager *dm);
|
|||
void amdgpu_dm_ism_force_full_power(struct amdgpu_display_manager *dm);
|
||||
void amdgpu_dm_ism_enable(struct amdgpu_display_manager *dm);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
|
||||
bool dm_ism_next_state(enum amdgpu_dm_ism_state current_state,
|
||||
enum amdgpu_dm_ism_event event,
|
||||
enum amdgpu_dm_ism_state *next_state);
|
||||
uint64_t dm_ism_get_sso_delay(const struct amdgpu_dm_ism *ism,
|
||||
const struct dc_stream_state *stream);
|
||||
uint64_t dm_ism_get_idle_allow_delay(const struct amdgpu_dm_ism *ism,
|
||||
const struct dc_stream_state *stream);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright 2026 Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#ifndef AMDGPU_DM_KUNIT_HELPERS_H
|
||||
#define AMDGPU_DM_KUNIT_HELPERS_H
|
||||
|
||||
#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
|
||||
#define STATIC_IFN_KUNIT
|
||||
#define INLINE_IFN_KUNIT inline
|
||||
#define EXPORT_IF_KUNIT(symbol) EXPORT_SYMBOL(symbol)
|
||||
#else
|
||||
#define STATIC_IFN_KUNIT static
|
||||
#define INLINE_IFN_KUNIT
|
||||
#define EXPORT_IF_KUNIT(symbol)
|
||||
#endif
|
||||
|
||||
#endif /* AMDGPU_DM_KUNIT_HELPERS_H */
|
||||
|
|
@ -183,33 +183,6 @@ static enum amd_pp_clock_type dc_to_pp_clock_type(
|
|||
return amd_pp_clk_type;
|
||||
}
|
||||
|
||||
static enum dm_pp_clocks_state pp_to_dc_powerlevel_state(
|
||||
enum PP_DAL_POWERLEVEL max_clocks_state)
|
||||
{
|
||||
switch (max_clocks_state) {
|
||||
case PP_DAL_POWERLEVEL_0:
|
||||
return DM_PP_CLOCKS_DPM_STATE_LEVEL_0;
|
||||
case PP_DAL_POWERLEVEL_1:
|
||||
return DM_PP_CLOCKS_DPM_STATE_LEVEL_1;
|
||||
case PP_DAL_POWERLEVEL_2:
|
||||
return DM_PP_CLOCKS_DPM_STATE_LEVEL_2;
|
||||
case PP_DAL_POWERLEVEL_3:
|
||||
return DM_PP_CLOCKS_DPM_STATE_LEVEL_3;
|
||||
case PP_DAL_POWERLEVEL_4:
|
||||
return DM_PP_CLOCKS_DPM_STATE_LEVEL_4;
|
||||
case PP_DAL_POWERLEVEL_5:
|
||||
return DM_PP_CLOCKS_DPM_STATE_LEVEL_5;
|
||||
case PP_DAL_POWERLEVEL_6:
|
||||
return DM_PP_CLOCKS_DPM_STATE_LEVEL_6;
|
||||
case PP_DAL_POWERLEVEL_7:
|
||||
return DM_PP_CLOCKS_DPM_STATE_LEVEL_7;
|
||||
default:
|
||||
DRM_ERROR("DM_PPLIB: invalid powerlevel state: %d!\n",
|
||||
max_clocks_state);
|
||||
return DM_PP_CLOCKS_STATE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
static void pp_to_dc_clock_levels(
|
||||
const struct amd_pp_clocks *pp_clks,
|
||||
struct dm_pp_clock_levels *dc_clks,
|
||||
|
|
@ -315,7 +288,6 @@ bool dm_pp_get_clock_levels_by_type(
|
|||
DRM_INFO("DM_PPLIB: Warning: using default validation clocks!\n");
|
||||
validation_clks.engine_max_clock = 72000;
|
||||
validation_clks.memory_max_clock = 80000;
|
||||
validation_clks.level = 0;
|
||||
}
|
||||
|
||||
DRM_INFO("DM_PPLIB: Validation clocks:\n");
|
||||
|
|
@ -323,8 +295,6 @@ bool dm_pp_get_clock_levels_by_type(
|
|||
validation_clks.engine_max_clock);
|
||||
DRM_INFO("DM_PPLIB: memory_max_clock: %d\n",
|
||||
validation_clks.memory_max_clock);
|
||||
DRM_INFO("DM_PPLIB: level : %d\n",
|
||||
validation_clks.level);
|
||||
|
||||
/* Translate 10 kHz to kHz. */
|
||||
validation_clks.engine_max_clock *= 10;
|
||||
|
|
@ -417,14 +387,6 @@ bool dm_pp_notify_wm_clock_changes(
|
|||
return false;
|
||||
}
|
||||
|
||||
bool dm_pp_apply_power_level_change_request(
|
||||
const struct dc_context *ctx,
|
||||
struct dm_pp_power_level_change_request *level_change_req)
|
||||
{
|
||||
/* TODO: to be implemented */
|
||||
return false;
|
||||
}
|
||||
|
||||
bool dm_pp_apply_clock_for_voltage_request(
|
||||
const struct dc_context *ctx,
|
||||
struct dm_pp_clock_for_voltage_req *clock_for_voltage_req)
|
||||
|
|
@ -446,23 +408,6 @@ bool dm_pp_apply_clock_for_voltage_request(
|
|||
return true;
|
||||
}
|
||||
|
||||
bool dm_pp_get_static_clocks(
|
||||
const struct dc_context *ctx,
|
||||
struct dm_pp_static_clock_info *static_clk_info)
|
||||
{
|
||||
struct amdgpu_device *adev = ctx->driver_context;
|
||||
struct amd_pp_clock_info pp_clk_info = {0};
|
||||
|
||||
if (amdgpu_dpm_get_current_clocks(adev, &pp_clk_info))
|
||||
return false;
|
||||
|
||||
static_clk_info->max_clocks_state = pp_to_dc_powerlevel_state(pp_clk_info.max_clocks_state);
|
||||
static_clk_info->max_mclk_khz = pp_clk_info.max_memory_clock * 10;
|
||||
static_clk_info->max_sclk_khz = pp_clk_info.max_engine_clock * 10;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void pp_rv_set_wm_ranges(struct pp_smu *pp,
|
||||
struct pp_smu_wm_range_sets *ranges)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@
|
|||
#include "dc.h"
|
||||
#include "amdgpu_dm.h"
|
||||
#include "modules/power/power_helpers.h"
|
||||
#include "amdgpu_dm_kunit_helpers.h"
|
||||
|
||||
|
||||
static bool link_supports_psrsu(struct dc_link *link)
|
||||
{
|
||||
|
|
@ -58,7 +60,8 @@ static bool link_supports_psrsu(struct dc_link *link)
|
|||
return false;
|
||||
}
|
||||
|
||||
static void amdgpu_dm_psr_fill_caps(struct dc_link *link, struct psr_caps *caps)
|
||||
STATIC_IFN_KUNIT
|
||||
void amdgpu_dm_psr_fill_caps(struct dc_link *link, struct psr_caps *caps)
|
||||
{
|
||||
struct dpcd_caps *dpcd_caps = &link->dpcd_caps;
|
||||
unsigned int power_opts = 0;
|
||||
|
|
@ -86,6 +89,7 @@ static void amdgpu_dm_psr_fill_caps(struct dc_link *link, struct psr_caps *caps)
|
|||
caps->rate_control_caps = 0; /* TODO: read in rc caps from aux */
|
||||
caps->psr_power_opt_flag = power_opts;
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_psr_fill_caps);
|
||||
|
||||
/*
|
||||
* amdgpu_dm_set_psr_caps() - set link psr capabilities
|
||||
|
|
|
|||
|
|
@ -39,4 +39,9 @@ bool amdgpu_dm_psr_is_active_allowed(struct amdgpu_display_manager *dm);
|
|||
bool amdgpu_dm_psr_set_event(struct amdgpu_display_manager *dm,
|
||||
struct dc_stream_state *stream, bool set_event, enum psr_event event,
|
||||
bool wait_for_disable);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
|
||||
void amdgpu_dm_psr_fill_caps(struct dc_link *link, struct psr_caps *caps);
|
||||
#endif
|
||||
|
||||
#endif /* AMDGPU_DM_AMDGPU_DM_PSR_H_ */
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@
|
|||
#include "modules/power/power_helpers.h"
|
||||
#include "dmub/inc/dmub_cmd.h"
|
||||
#include "dc/inc/link_service.h"
|
||||
#include "amdgpu_dm_kunit_helpers.h"
|
||||
|
||||
|
||||
/*
|
||||
* amdgpu_dm_link_supports_replay() - check if the link supports replay
|
||||
|
|
@ -68,6 +70,7 @@ bool amdgpu_dm_link_supports_replay(struct dc_link *link, struct amdgpu_dm_conne
|
|||
|
||||
return true;
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_link_supports_replay);
|
||||
|
||||
/*
|
||||
* amdgpu_dm_set_replay_caps() - setup Replay capabilities
|
||||
|
|
|
|||
14
drivers/gpu/drm/amd/display/amdgpu_dm/tests/.kunitconfig
Normal file
14
drivers/gpu/drm/amd/display/amdgpu_dm/tests/.kunitconfig
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
CONFIG_KUNIT=y
|
||||
CONFIG_PCI=y
|
||||
CONFIG_DRM=y
|
||||
CONFIG_DRM_AMDGPU=y
|
||||
CONFIG_DRM_AMD_DC=y
|
||||
CONFIG_DEBUG_FS=y
|
||||
CONFIG_DRM_AMD_DC_KUNIT_TEST=y
|
||||
CONFIG_FW_LOADER=y
|
||||
CONFIG_DRM_KMS_HELPER=y
|
||||
CONFIG_DRM_TTM=y
|
||||
CONFIG_HWMON=y
|
||||
CONFIG_I2C=y
|
||||
CONFIG_POWER_SUPPLY=y
|
||||
CONFIG_CRC16=y
|
||||
18
drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile
Normal file
18
drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Makefile for amdgpu_dm KUnit tests.
|
||||
|
||||
ccflags-y += -I$(src)/..
|
||||
ccflags-y += -I$(src)/../..
|
||||
ccflags-y += -I$(src)/../../include
|
||||
ccflags-y += -I$(src)/../../modules/inc
|
||||
ccflags-y += -I$(src)/../../dc
|
||||
ccflags-y += -I$(src)/../../../amdgpu
|
||||
|
||||
obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_crc_test.o
|
||||
obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_hdcp_test.o
|
||||
obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_color_test.o
|
||||
obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_colorop_test.o
|
||||
obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_psr_test.o
|
||||
obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_replay_test.o
|
||||
obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_ism_test.o
|
||||
1071
drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c
Normal file
1071
drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,161 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR MIT
|
||||
/*
|
||||
* KUnit tests for amdgpu_dm_colorop.c
|
||||
*
|
||||
* Copyright 2026 Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#include <kunit/test.h>
|
||||
#include <drm/drm_colorop.h>
|
||||
|
||||
#include "amdgpu_dm_colorop.h"
|
||||
|
||||
/* Tests for amdgpu_dm_supported_degam_tfs */
|
||||
|
||||
static void dm_test_supported_degam_tfs_has_srgb_eotf(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_TRUE(test, amdgpu_dm_supported_degam_tfs &
|
||||
BIT(DRM_COLOROP_1D_CURVE_SRGB_EOTF));
|
||||
}
|
||||
|
||||
static void dm_test_supported_degam_tfs_has_pq125_eotf(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_TRUE(test, amdgpu_dm_supported_degam_tfs &
|
||||
BIT(DRM_COLOROP_1D_CURVE_PQ_125_EOTF));
|
||||
}
|
||||
|
||||
static void dm_test_supported_degam_tfs_has_bt2020_inv_oetf(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_TRUE(test, amdgpu_dm_supported_degam_tfs &
|
||||
BIT(DRM_COLOROP_1D_CURVE_BT2020_INV_OETF));
|
||||
}
|
||||
|
||||
static void dm_test_supported_degam_tfs_has_gamma22_inv(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_TRUE(test, amdgpu_dm_supported_degam_tfs &
|
||||
BIT(DRM_COLOROP_1D_CURVE_GAMMA22_INV));
|
||||
}
|
||||
|
||||
static void dm_test_supported_degam_tfs_no_extra_bits(struct kunit *test)
|
||||
{
|
||||
u64 expected = BIT(DRM_COLOROP_1D_CURVE_SRGB_EOTF) |
|
||||
BIT(DRM_COLOROP_1D_CURVE_PQ_125_EOTF) |
|
||||
BIT(DRM_COLOROP_1D_CURVE_BT2020_INV_OETF) |
|
||||
BIT(DRM_COLOROP_1D_CURVE_GAMMA22_INV);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, amdgpu_dm_supported_degam_tfs, expected);
|
||||
}
|
||||
|
||||
/* Tests for amdgpu_dm_supported_shaper_tfs */
|
||||
|
||||
static void dm_test_supported_shaper_tfs_has_srgb_inv_eotf(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_TRUE(test, amdgpu_dm_supported_shaper_tfs &
|
||||
BIT(DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF));
|
||||
}
|
||||
|
||||
static void dm_test_supported_shaper_tfs_has_pq125_inv_eotf(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_TRUE(test, amdgpu_dm_supported_shaper_tfs &
|
||||
BIT(DRM_COLOROP_1D_CURVE_PQ_125_INV_EOTF));
|
||||
}
|
||||
|
||||
static void dm_test_supported_shaper_tfs_has_bt2020_oetf(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_TRUE(test, amdgpu_dm_supported_shaper_tfs &
|
||||
BIT(DRM_COLOROP_1D_CURVE_BT2020_OETF));
|
||||
}
|
||||
|
||||
static void dm_test_supported_shaper_tfs_has_gamma22(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_TRUE(test, amdgpu_dm_supported_shaper_tfs &
|
||||
BIT(DRM_COLOROP_1D_CURVE_GAMMA22));
|
||||
}
|
||||
|
||||
static void dm_test_supported_shaper_tfs_no_extra_bits(struct kunit *test)
|
||||
{
|
||||
u64 expected = BIT(DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF) |
|
||||
BIT(DRM_COLOROP_1D_CURVE_PQ_125_INV_EOTF) |
|
||||
BIT(DRM_COLOROP_1D_CURVE_BT2020_OETF) |
|
||||
BIT(DRM_COLOROP_1D_CURVE_GAMMA22);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, amdgpu_dm_supported_shaper_tfs, expected);
|
||||
}
|
||||
|
||||
/* Tests for amdgpu_dm_supported_blnd_tfs */
|
||||
|
||||
static void dm_test_supported_blnd_tfs_has_srgb_eotf(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_TRUE(test, amdgpu_dm_supported_blnd_tfs &
|
||||
BIT(DRM_COLOROP_1D_CURVE_SRGB_EOTF));
|
||||
}
|
||||
|
||||
static void dm_test_supported_blnd_tfs_has_pq125_eotf(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_TRUE(test, amdgpu_dm_supported_blnd_tfs &
|
||||
BIT(DRM_COLOROP_1D_CURVE_PQ_125_EOTF));
|
||||
}
|
||||
|
||||
static void dm_test_supported_blnd_tfs_has_bt2020_inv_oetf(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_TRUE(test, amdgpu_dm_supported_blnd_tfs &
|
||||
BIT(DRM_COLOROP_1D_CURVE_BT2020_INV_OETF));
|
||||
}
|
||||
|
||||
static void dm_test_supported_blnd_tfs_has_gamma22_inv(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_TRUE(test, amdgpu_dm_supported_blnd_tfs &
|
||||
BIT(DRM_COLOROP_1D_CURVE_GAMMA22_INV));
|
||||
}
|
||||
|
||||
static void dm_test_supported_blnd_tfs_no_extra_bits(struct kunit *test)
|
||||
{
|
||||
u64 expected = BIT(DRM_COLOROP_1D_CURVE_SRGB_EOTF) |
|
||||
BIT(DRM_COLOROP_1D_CURVE_PQ_125_EOTF) |
|
||||
BIT(DRM_COLOROP_1D_CURVE_BT2020_INV_OETF) |
|
||||
BIT(DRM_COLOROP_1D_CURVE_GAMMA22_INV);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, amdgpu_dm_supported_blnd_tfs, expected);
|
||||
}
|
||||
|
||||
/* degam and blnd should support the same set of EOTF curves */
|
||||
static void dm_test_degam_and_blnd_tfs_match(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_EQ(test, amdgpu_dm_supported_degam_tfs,
|
||||
amdgpu_dm_supported_blnd_tfs);
|
||||
}
|
||||
|
||||
static struct kunit_case dm_colorop_test_cases[] = {
|
||||
/* degam TFs */
|
||||
KUNIT_CASE(dm_test_supported_degam_tfs_has_srgb_eotf),
|
||||
KUNIT_CASE(dm_test_supported_degam_tfs_has_pq125_eotf),
|
||||
KUNIT_CASE(dm_test_supported_degam_tfs_has_bt2020_inv_oetf),
|
||||
KUNIT_CASE(dm_test_supported_degam_tfs_has_gamma22_inv),
|
||||
KUNIT_CASE(dm_test_supported_degam_tfs_no_extra_bits),
|
||||
/* shaper TFs */
|
||||
KUNIT_CASE(dm_test_supported_shaper_tfs_has_srgb_inv_eotf),
|
||||
KUNIT_CASE(dm_test_supported_shaper_tfs_has_pq125_inv_eotf),
|
||||
KUNIT_CASE(dm_test_supported_shaper_tfs_has_bt2020_oetf),
|
||||
KUNIT_CASE(dm_test_supported_shaper_tfs_has_gamma22),
|
||||
KUNIT_CASE(dm_test_supported_shaper_tfs_no_extra_bits),
|
||||
/* blnd TFs */
|
||||
KUNIT_CASE(dm_test_supported_blnd_tfs_has_srgb_eotf),
|
||||
KUNIT_CASE(dm_test_supported_blnd_tfs_has_pq125_eotf),
|
||||
KUNIT_CASE(dm_test_supported_blnd_tfs_has_bt2020_inv_oetf),
|
||||
KUNIT_CASE(dm_test_supported_blnd_tfs_has_gamma22_inv),
|
||||
KUNIT_CASE(dm_test_supported_blnd_tfs_no_extra_bits),
|
||||
/* cross-check */
|
||||
KUNIT_CASE(dm_test_degam_and_blnd_tfs_match),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite dm_colorop_test_suite = {
|
||||
.name = "amdgpu_dm_colorop",
|
||||
.test_cases = dm_colorop_test_cases,
|
||||
};
|
||||
|
||||
kunit_test_suite(dm_colorop_test_suite);
|
||||
|
||||
MODULE_LICENSE("Dual MIT/GPL");
|
||||
MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_colorop");
|
||||
MODULE_AUTHOR("AMD");
|
||||
121
drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c
Normal file
121
drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR MIT
|
||||
/*
|
||||
* KUnit tests for amdgpu_dm_crc.c
|
||||
*
|
||||
* Copyright 2026 Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#include <kunit/test.h>
|
||||
|
||||
#include "amdgpu_dm_crc.h"
|
||||
|
||||
static void dm_test_parse_crc_source_none(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_EQ(test, AMDGPU_DM_PIPE_CRC_SOURCE_NONE, dm_parse_crc_source("none"));
|
||||
KUNIT_EXPECT_EQ(test, AMDGPU_DM_PIPE_CRC_SOURCE_NONE, dm_parse_crc_source(NULL));
|
||||
}
|
||||
|
||||
static void dm_test_parse_crc_source_crtc(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_EQ(test, AMDGPU_DM_PIPE_CRC_SOURCE_CRTC, dm_parse_crc_source("crtc"));
|
||||
KUNIT_EXPECT_EQ(test, AMDGPU_DM_PIPE_CRC_SOURCE_CRTC, dm_parse_crc_source("auto"));
|
||||
}
|
||||
|
||||
static void dm_test_parse_crc_source_dprx(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_EQ(test, AMDGPU_DM_PIPE_CRC_SOURCE_DPRX, dm_parse_crc_source("dprx"));
|
||||
}
|
||||
|
||||
static void dm_test_parse_crc_source_crtc_dither(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_EQ(test, AMDGPU_DM_PIPE_CRC_SOURCE_CRTC_DITHER,
|
||||
dm_parse_crc_source("crtc dither"));
|
||||
}
|
||||
|
||||
static void dm_test_parse_crc_source_dprx_dither(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_EQ(test, AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER,
|
||||
dm_parse_crc_source("dprx dither"));
|
||||
}
|
||||
|
||||
static void dm_test_parse_crc_source_invalid(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_EQ(test, AMDGPU_DM_PIPE_CRC_SOURCE_INVALID,
|
||||
dm_parse_crc_source("invalid"));
|
||||
KUNIT_EXPECT_EQ(test, AMDGPU_DM_PIPE_CRC_SOURCE_INVALID,
|
||||
dm_parse_crc_source("unknown"));
|
||||
KUNIT_EXPECT_EQ(test, AMDGPU_DM_PIPE_CRC_SOURCE_INVALID,
|
||||
dm_parse_crc_source(""));
|
||||
}
|
||||
|
||||
static void dm_test_is_crc_source_crtc(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_TRUE(test, dm_is_crc_source_crtc(AMDGPU_DM_PIPE_CRC_SOURCE_CRTC));
|
||||
KUNIT_EXPECT_TRUE(test, dm_is_crc_source_crtc(AMDGPU_DM_PIPE_CRC_SOURCE_CRTC_DITHER));
|
||||
|
||||
KUNIT_EXPECT_FALSE(test, dm_is_crc_source_crtc(AMDGPU_DM_PIPE_CRC_SOURCE_NONE));
|
||||
KUNIT_EXPECT_FALSE(test, dm_is_crc_source_crtc(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX));
|
||||
KUNIT_EXPECT_FALSE(test, dm_is_crc_source_crtc(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER));
|
||||
KUNIT_EXPECT_FALSE(test, dm_is_crc_source_crtc(AMDGPU_DM_PIPE_CRC_SOURCE_INVALID));
|
||||
}
|
||||
|
||||
static void dm_test_is_crc_source_dprx(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_TRUE(test, dm_is_crc_source_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX));
|
||||
KUNIT_EXPECT_TRUE(test, dm_is_crc_source_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER));
|
||||
|
||||
KUNIT_EXPECT_FALSE(test, dm_is_crc_source_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_NONE));
|
||||
KUNIT_EXPECT_FALSE(test, dm_is_crc_source_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_CRTC));
|
||||
KUNIT_EXPECT_FALSE(test, dm_is_crc_source_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_CRTC_DITHER));
|
||||
KUNIT_EXPECT_FALSE(test, dm_is_crc_source_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_INVALID));
|
||||
}
|
||||
|
||||
static void dm_test_need_crc_dither(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_TRUE(test, dm_need_crc_dither(AMDGPU_DM_PIPE_CRC_SOURCE_NONE));
|
||||
KUNIT_EXPECT_TRUE(test, dm_need_crc_dither(AMDGPU_DM_PIPE_CRC_SOURCE_CRTC_DITHER));
|
||||
KUNIT_EXPECT_TRUE(test, dm_need_crc_dither(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER));
|
||||
|
||||
KUNIT_EXPECT_FALSE(test, dm_need_crc_dither(AMDGPU_DM_PIPE_CRC_SOURCE_CRTC));
|
||||
KUNIT_EXPECT_FALSE(test, dm_need_crc_dither(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX));
|
||||
KUNIT_EXPECT_FALSE(test, dm_need_crc_dither(AMDGPU_DM_PIPE_CRC_SOURCE_INVALID));
|
||||
}
|
||||
|
||||
static void dm_test_is_valid_crc_source(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_TRUE(test, amdgpu_dm_is_valid_crc_source(AMDGPU_DM_PIPE_CRC_SOURCE_CRTC));
|
||||
KUNIT_EXPECT_TRUE(test, amdgpu_dm_is_valid_crc_source(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX));
|
||||
KUNIT_EXPECT_TRUE(test,
|
||||
amdgpu_dm_is_valid_crc_source(AMDGPU_DM_PIPE_CRC_SOURCE_CRTC_DITHER));
|
||||
KUNIT_EXPECT_TRUE(test,
|
||||
amdgpu_dm_is_valid_crc_source(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER));
|
||||
|
||||
KUNIT_EXPECT_FALSE(test, amdgpu_dm_is_valid_crc_source(AMDGPU_DM_PIPE_CRC_SOURCE_NONE));
|
||||
KUNIT_EXPECT_FALSE(test, amdgpu_dm_is_valid_crc_source(AMDGPU_DM_PIPE_CRC_SOURCE_MAX));
|
||||
KUNIT_EXPECT_FALSE(test, amdgpu_dm_is_valid_crc_source(AMDGPU_DM_PIPE_CRC_SOURCE_INVALID));
|
||||
}
|
||||
|
||||
static struct kunit_case dm_crc_test_cases[] = {
|
||||
KUNIT_CASE(dm_test_parse_crc_source_none),
|
||||
KUNIT_CASE(dm_test_parse_crc_source_crtc),
|
||||
KUNIT_CASE(dm_test_parse_crc_source_dprx),
|
||||
KUNIT_CASE(dm_test_parse_crc_source_crtc_dither),
|
||||
KUNIT_CASE(dm_test_parse_crc_source_dprx_dither),
|
||||
KUNIT_CASE(dm_test_parse_crc_source_invalid),
|
||||
KUNIT_CASE(dm_test_is_crc_source_crtc),
|
||||
KUNIT_CASE(dm_test_is_crc_source_dprx),
|
||||
KUNIT_CASE(dm_test_need_crc_dither),
|
||||
KUNIT_CASE(dm_test_is_valid_crc_source),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite dm_crc_test_suite = {
|
||||
.name = "amdgpu_dm_crc",
|
||||
.test_cases = dm_crc_test_cases,
|
||||
};
|
||||
|
||||
kunit_test_suite(dm_crc_test_suite);
|
||||
|
||||
MODULE_LICENSE("Dual MIT/GPL");
|
||||
MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_crc");
|
||||
MODULE_AUTHOR("AMD");
|
||||
|
|
@ -0,0 +1,175 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR MIT
|
||||
/*
|
||||
* KUnit tests for amdgpu_dm_hdcp.c
|
||||
*
|
||||
* Copyright 2026 Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#include <kunit/test.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "amdgpu_dm_hdcp.h"
|
||||
|
||||
static void dummy_work_fn(struct work_struct *work) {}
|
||||
|
||||
/* Tests for process_output() */
|
||||
|
||||
/*
|
||||
* Helper: allocate and initialise a minimal hdcp_workqueue sufficient for
|
||||
* process_output() testing. Only the three delayed works accessed by
|
||||
* process_output() are initialised; everything else is zeroed.
|
||||
*/
|
||||
static struct hdcp_workqueue *alloc_test_workqueue(struct kunit *test)
|
||||
{
|
||||
struct hdcp_workqueue *work;
|
||||
|
||||
work = kunit_kzalloc(test, sizeof(*work), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, work);
|
||||
|
||||
INIT_DELAYED_WORK(&work->callback_dwork, dummy_work_fn);
|
||||
INIT_DELAYED_WORK(&work->watchdog_timer_dwork, dummy_work_fn);
|
||||
INIT_DELAYED_WORK(&work->property_validate_dwork, dummy_work_fn);
|
||||
|
||||
return work;
|
||||
}
|
||||
|
||||
/*
|
||||
* process_output() always schedules property_validate_dwork with delay=0,
|
||||
* which queues the work item directly (bypassing the timer). Use
|
||||
* work_pending() rather than delayed_work_pending() to detect this.
|
||||
*/
|
||||
static void dm_test_process_output_property_validate_always_scheduled(struct kunit *test)
|
||||
{
|
||||
struct hdcp_workqueue *work = alloc_test_workqueue(test);
|
||||
|
||||
/* No flags set: only property_validate_dwork should be enqueued */
|
||||
process_output(work);
|
||||
|
||||
KUNIT_EXPECT_TRUE(test, work_pending(&work->property_validate_dwork.work));
|
||||
KUNIT_EXPECT_FALSE(test, delayed_work_pending(&work->callback_dwork));
|
||||
KUNIT_EXPECT_FALSE(test, delayed_work_pending(&work->watchdog_timer_dwork));
|
||||
|
||||
cancel_delayed_work_sync(&work->property_validate_dwork);
|
||||
}
|
||||
|
||||
/*
|
||||
* output.callback_needed=true must schedule callback_dwork.
|
||||
*/
|
||||
static void dm_test_process_output_callback_needed(struct kunit *test)
|
||||
{
|
||||
struct hdcp_workqueue *work = alloc_test_workqueue(test);
|
||||
|
||||
work->output.callback_needed = true;
|
||||
work->output.callback_delay = 500;
|
||||
|
||||
process_output(work);
|
||||
|
||||
KUNIT_EXPECT_TRUE(test, delayed_work_pending(&work->callback_dwork));
|
||||
|
||||
cancel_delayed_work_sync(&work->callback_dwork);
|
||||
cancel_delayed_work_sync(&work->property_validate_dwork);
|
||||
}
|
||||
|
||||
/*
|
||||
* output.callback_stop=true must cancel a previously scheduled callback_dwork.
|
||||
*/
|
||||
static void dm_test_process_output_callback_stop(struct kunit *test)
|
||||
{
|
||||
struct hdcp_workqueue *work = alloc_test_workqueue(test);
|
||||
|
||||
/* Pre-schedule callback_dwork with a long delay so it won't fire. */
|
||||
schedule_delayed_work(&work->callback_dwork, msecs_to_jiffies(10000));
|
||||
KUNIT_ASSERT_TRUE(test, delayed_work_pending(&work->callback_dwork));
|
||||
|
||||
work->output.callback_stop = true;
|
||||
|
||||
process_output(work);
|
||||
|
||||
KUNIT_EXPECT_FALSE(test, delayed_work_pending(&work->callback_dwork));
|
||||
|
||||
cancel_delayed_work_sync(&work->property_validate_dwork);
|
||||
}
|
||||
|
||||
/*
|
||||
* output.watchdog_timer_needed=true must schedule watchdog_timer_dwork.
|
||||
*/
|
||||
static void dm_test_process_output_watchdog_needed(struct kunit *test)
|
||||
{
|
||||
struct hdcp_workqueue *work = alloc_test_workqueue(test);
|
||||
|
||||
work->output.watchdog_timer_needed = true;
|
||||
work->output.watchdog_timer_delay = 1000;
|
||||
|
||||
process_output(work);
|
||||
|
||||
KUNIT_EXPECT_TRUE(test, delayed_work_pending(&work->watchdog_timer_dwork));
|
||||
|
||||
cancel_delayed_work_sync(&work->watchdog_timer_dwork);
|
||||
cancel_delayed_work_sync(&work->property_validate_dwork);
|
||||
}
|
||||
|
||||
/*
|
||||
* output.watchdog_timer_stop=true must cancel a previously scheduled
|
||||
* watchdog_timer_dwork.
|
||||
*/
|
||||
static void dm_test_process_output_watchdog_stop(struct kunit *test)
|
||||
{
|
||||
struct hdcp_workqueue *work = alloc_test_workqueue(test);
|
||||
|
||||
/* Pre-schedule watchdog_timer_dwork with a long delay. */
|
||||
schedule_delayed_work(&work->watchdog_timer_dwork, msecs_to_jiffies(10000));
|
||||
KUNIT_ASSERT_TRUE(test, delayed_work_pending(&work->watchdog_timer_dwork));
|
||||
|
||||
work->output.watchdog_timer_stop = true;
|
||||
|
||||
process_output(work);
|
||||
|
||||
KUNIT_EXPECT_FALSE(test, delayed_work_pending(&work->watchdog_timer_dwork));
|
||||
|
||||
cancel_delayed_work_sync(&work->property_validate_dwork);
|
||||
}
|
||||
|
||||
/*
|
||||
* Both callback_needed and watchdog_timer_needed set: both dworks are
|
||||
* scheduled independently.
|
||||
*/
|
||||
static void dm_test_process_output_callback_and_watchdog_needed(struct kunit *test)
|
||||
{
|
||||
struct hdcp_workqueue *work = alloc_test_workqueue(test);
|
||||
|
||||
work->output.callback_needed = true;
|
||||
work->output.callback_delay = 200;
|
||||
work->output.watchdog_timer_needed = true;
|
||||
work->output.watchdog_timer_delay = 800;
|
||||
|
||||
process_output(work);
|
||||
|
||||
KUNIT_EXPECT_TRUE(test, delayed_work_pending(&work->callback_dwork));
|
||||
KUNIT_EXPECT_TRUE(test, delayed_work_pending(&work->watchdog_timer_dwork));
|
||||
|
||||
cancel_delayed_work_sync(&work->callback_dwork);
|
||||
cancel_delayed_work_sync(&work->watchdog_timer_dwork);
|
||||
cancel_delayed_work_sync(&work->property_validate_dwork);
|
||||
}
|
||||
/* End of tests for process_output() */
|
||||
|
||||
static struct kunit_case dm_hdcp_test_cases[] = {
|
||||
KUNIT_CASE(dm_test_process_output_property_validate_always_scheduled),
|
||||
KUNIT_CASE(dm_test_process_output_callback_needed),
|
||||
KUNIT_CASE(dm_test_process_output_callback_stop),
|
||||
KUNIT_CASE(dm_test_process_output_watchdog_needed),
|
||||
KUNIT_CASE(dm_test_process_output_watchdog_stop),
|
||||
KUNIT_CASE(dm_test_process_output_callback_and_watchdog_needed),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite dm_hdcp_test_suite = {
|
||||
.name = "amdgpu_dm_hdcp",
|
||||
.test_cases = dm_hdcp_test_cases,
|
||||
};
|
||||
|
||||
kunit_test_suite(dm_hdcp_test_suite);
|
||||
|
||||
MODULE_LICENSE("Dual MIT/GPL");
|
||||
MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_hdcp");
|
||||
MODULE_AUTHOR("AMD");
|
||||
636
drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_ism_test.c
Normal file
636
drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_ism_test.c
Normal file
|
|
@ -0,0 +1,636 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR MIT
|
||||
/*
|
||||
* KUnit tests for amdgpu_dm_ism.c
|
||||
*
|
||||
* Copyright 2026 Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#include <kunit/test.h>
|
||||
|
||||
#include "dc.h"
|
||||
#include "amdgpu_dm_ism.h"
|
||||
|
||||
/*
|
||||
* Helper: allocate and zero-initialise a dc_stream_state for timing tests.
|
||||
* Only the timing sub-struct is accessed by the functions under test.
|
||||
*/
|
||||
static struct dc_stream_state *alloc_test_stream(struct kunit *test)
|
||||
{
|
||||
struct dc_stream_state *stream;
|
||||
|
||||
stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, stream);
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper: allocate and zero-initialise an ISM instance.
|
||||
*/
|
||||
static struct amdgpu_dm_ism *alloc_test_ism(struct kunit *test)
|
||||
{
|
||||
struct amdgpu_dm_ism *ism;
|
||||
|
||||
ism = kunit_kzalloc(test, sizeof(*ism), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, ism);
|
||||
|
||||
return ism;
|
||||
}
|
||||
|
||||
/* ===== Tests for dm_ism_next_state — FULL_POWER_RUNNING transitions ===== */
|
||||
|
||||
static void dm_test_ism_next_state_running_enter_idle(struct kunit *test)
|
||||
{
|
||||
enum amdgpu_dm_ism_state next;
|
||||
bool ok;
|
||||
|
||||
ok = dm_ism_next_state(DM_ISM_STATE_FULL_POWER_RUNNING,
|
||||
DM_ISM_EVENT_ENTER_IDLE_REQUESTED, &next);
|
||||
KUNIT_EXPECT_TRUE(test, ok);
|
||||
KUNIT_EXPECT_EQ(test, (int)next, (int)DM_ISM_STATE_HYSTERESIS_WAITING);
|
||||
}
|
||||
|
||||
static void dm_test_ism_next_state_running_begin_cursor(struct kunit *test)
|
||||
{
|
||||
enum amdgpu_dm_ism_state next;
|
||||
bool ok;
|
||||
|
||||
ok = dm_ism_next_state(DM_ISM_STATE_FULL_POWER_RUNNING,
|
||||
DM_ISM_EVENT_BEGIN_CURSOR_UPDATE, &next);
|
||||
KUNIT_EXPECT_TRUE(test, ok);
|
||||
KUNIT_EXPECT_EQ(test, (int)next, (int)DM_ISM_STATE_FULL_POWER_BUSY);
|
||||
}
|
||||
|
||||
static void dm_test_ism_next_state_running_invalid(struct kunit *test)
|
||||
{
|
||||
enum amdgpu_dm_ism_state next = DM_ISM_NUM_STATES;
|
||||
bool ok;
|
||||
|
||||
ok = dm_ism_next_state(DM_ISM_STATE_FULL_POWER_RUNNING,
|
||||
DM_ISM_EVENT_EXIT_IDLE_REQUESTED, &next);
|
||||
KUNIT_EXPECT_FALSE(test, ok);
|
||||
/* next should remain untouched on invalid transition */
|
||||
KUNIT_EXPECT_EQ(test, (int)next, (int)DM_ISM_NUM_STATES);
|
||||
}
|
||||
|
||||
/* ===== Tests for dm_ism_next_state — FULL_POWER_BUSY transitions ===== */
|
||||
|
||||
static void dm_test_ism_next_state_busy_enter_idle(struct kunit *test)
|
||||
{
|
||||
enum amdgpu_dm_ism_state next;
|
||||
bool ok;
|
||||
|
||||
ok = dm_ism_next_state(DM_ISM_STATE_FULL_POWER_BUSY,
|
||||
DM_ISM_EVENT_ENTER_IDLE_REQUESTED, &next);
|
||||
KUNIT_EXPECT_TRUE(test, ok);
|
||||
KUNIT_EXPECT_EQ(test, (int)next, (int)DM_ISM_STATE_HYSTERESIS_BUSY);
|
||||
}
|
||||
|
||||
static void dm_test_ism_next_state_busy_end_cursor(struct kunit *test)
|
||||
{
|
||||
enum amdgpu_dm_ism_state next;
|
||||
bool ok;
|
||||
|
||||
ok = dm_ism_next_state(DM_ISM_STATE_FULL_POWER_BUSY,
|
||||
DM_ISM_EVENT_END_CURSOR_UPDATE, &next);
|
||||
KUNIT_EXPECT_TRUE(test, ok);
|
||||
KUNIT_EXPECT_EQ(test, (int)next, (int)DM_ISM_STATE_FULL_POWER_RUNNING);
|
||||
}
|
||||
|
||||
/* ===== Tests for dm_ism_next_state — HYSTERESIS_WAITING transitions ===== */
|
||||
|
||||
static void dm_test_ism_next_state_hyst_wait_exit_idle(struct kunit *test)
|
||||
{
|
||||
enum amdgpu_dm_ism_state next;
|
||||
bool ok;
|
||||
|
||||
ok = dm_ism_next_state(DM_ISM_STATE_HYSTERESIS_WAITING,
|
||||
DM_ISM_EVENT_EXIT_IDLE_REQUESTED, &next);
|
||||
KUNIT_EXPECT_TRUE(test, ok);
|
||||
KUNIT_EXPECT_EQ(test, (int)next, (int)DM_ISM_STATE_TIMER_ABORTED);
|
||||
}
|
||||
|
||||
static void dm_test_ism_next_state_hyst_wait_begin_cursor(struct kunit *test)
|
||||
{
|
||||
enum amdgpu_dm_ism_state next;
|
||||
bool ok;
|
||||
|
||||
ok = dm_ism_next_state(DM_ISM_STATE_HYSTERESIS_WAITING,
|
||||
DM_ISM_EVENT_BEGIN_CURSOR_UPDATE, &next);
|
||||
KUNIT_EXPECT_TRUE(test, ok);
|
||||
KUNIT_EXPECT_EQ(test, (int)next, (int)DM_ISM_STATE_HYSTERESIS_BUSY);
|
||||
}
|
||||
|
||||
static void dm_test_ism_next_state_hyst_wait_timer(struct kunit *test)
|
||||
{
|
||||
enum amdgpu_dm_ism_state next;
|
||||
bool ok;
|
||||
|
||||
ok = dm_ism_next_state(DM_ISM_STATE_HYSTERESIS_WAITING,
|
||||
DM_ISM_EVENT_TIMER_ELAPSED, &next);
|
||||
KUNIT_EXPECT_TRUE(test, ok);
|
||||
KUNIT_EXPECT_EQ(test, (int)next, (int)DM_ISM_STATE_OPTIMIZED_IDLE);
|
||||
}
|
||||
|
||||
static void dm_test_ism_next_state_hyst_wait_immediate(struct kunit *test)
|
||||
{
|
||||
enum amdgpu_dm_ism_state next;
|
||||
bool ok;
|
||||
|
||||
ok = dm_ism_next_state(DM_ISM_STATE_HYSTERESIS_WAITING,
|
||||
DM_ISM_EVENT_IMMEDIATE, &next);
|
||||
KUNIT_EXPECT_TRUE(test, ok);
|
||||
KUNIT_EXPECT_EQ(test, (int)next, (int)DM_ISM_STATE_OPTIMIZED_IDLE);
|
||||
}
|
||||
|
||||
/* ===== Tests for dm_ism_next_state — HYSTERESIS_BUSY transitions ===== */
|
||||
|
||||
static void dm_test_ism_next_state_hyst_busy_exit_idle(struct kunit *test)
|
||||
{
|
||||
enum amdgpu_dm_ism_state next;
|
||||
bool ok;
|
||||
|
||||
ok = dm_ism_next_state(DM_ISM_STATE_HYSTERESIS_BUSY,
|
||||
DM_ISM_EVENT_EXIT_IDLE_REQUESTED, &next);
|
||||
KUNIT_EXPECT_TRUE(test, ok);
|
||||
KUNIT_EXPECT_EQ(test, (int)next, (int)DM_ISM_STATE_FULL_POWER_BUSY);
|
||||
}
|
||||
|
||||
static void dm_test_ism_next_state_hyst_busy_end_cursor(struct kunit *test)
|
||||
{
|
||||
enum amdgpu_dm_ism_state next;
|
||||
bool ok;
|
||||
|
||||
ok = dm_ism_next_state(DM_ISM_STATE_HYSTERESIS_BUSY,
|
||||
DM_ISM_EVENT_END_CURSOR_UPDATE, &next);
|
||||
KUNIT_EXPECT_TRUE(test, ok);
|
||||
KUNIT_EXPECT_EQ(test, (int)next, (int)DM_ISM_STATE_HYSTERESIS_WAITING);
|
||||
}
|
||||
|
||||
/* ===== Tests for dm_ism_next_state — OPTIMIZED_IDLE transitions ===== */
|
||||
|
||||
static void dm_test_ism_next_state_opt_idle_exit(struct kunit *test)
|
||||
{
|
||||
enum amdgpu_dm_ism_state next;
|
||||
bool ok;
|
||||
|
||||
ok = dm_ism_next_state(DM_ISM_STATE_OPTIMIZED_IDLE,
|
||||
DM_ISM_EVENT_EXIT_IDLE_REQUESTED, &next);
|
||||
KUNIT_EXPECT_TRUE(test, ok);
|
||||
KUNIT_EXPECT_EQ(test, (int)next, (int)DM_ISM_STATE_FULL_POWER_RUNNING);
|
||||
}
|
||||
|
||||
static void dm_test_ism_next_state_opt_idle_begin_cursor(struct kunit *test)
|
||||
{
|
||||
enum amdgpu_dm_ism_state next;
|
||||
bool ok;
|
||||
|
||||
ok = dm_ism_next_state(DM_ISM_STATE_OPTIMIZED_IDLE,
|
||||
DM_ISM_EVENT_BEGIN_CURSOR_UPDATE, &next);
|
||||
KUNIT_EXPECT_TRUE(test, ok);
|
||||
KUNIT_EXPECT_EQ(test, (int)next, (int)DM_ISM_STATE_HYSTERESIS_BUSY);
|
||||
}
|
||||
|
||||
static void dm_test_ism_next_state_opt_idle_sso_timer(struct kunit *test)
|
||||
{
|
||||
enum amdgpu_dm_ism_state next;
|
||||
bool ok;
|
||||
|
||||
ok = dm_ism_next_state(DM_ISM_STATE_OPTIMIZED_IDLE,
|
||||
DM_ISM_EVENT_SSO_TIMER_ELAPSED, &next);
|
||||
KUNIT_EXPECT_TRUE(test, ok);
|
||||
KUNIT_EXPECT_EQ(test, (int)next, (int)DM_ISM_STATE_OPTIMIZED_IDLE_SSO);
|
||||
}
|
||||
|
||||
static void dm_test_ism_next_state_opt_idle_immediate(struct kunit *test)
|
||||
{
|
||||
enum amdgpu_dm_ism_state next;
|
||||
bool ok;
|
||||
|
||||
ok = dm_ism_next_state(DM_ISM_STATE_OPTIMIZED_IDLE,
|
||||
DM_ISM_EVENT_IMMEDIATE, &next);
|
||||
KUNIT_EXPECT_TRUE(test, ok);
|
||||
KUNIT_EXPECT_EQ(test, (int)next, (int)DM_ISM_STATE_OPTIMIZED_IDLE_SSO);
|
||||
}
|
||||
|
||||
/* ===== Tests for dm_ism_next_state — OPTIMIZED_IDLE_SSO transitions ===== */
|
||||
|
||||
static void dm_test_ism_next_state_opt_idle_sso_exit(struct kunit *test)
|
||||
{
|
||||
enum amdgpu_dm_ism_state next;
|
||||
bool ok;
|
||||
|
||||
ok = dm_ism_next_state(DM_ISM_STATE_OPTIMIZED_IDLE_SSO,
|
||||
DM_ISM_EVENT_EXIT_IDLE_REQUESTED, &next);
|
||||
KUNIT_EXPECT_TRUE(test, ok);
|
||||
KUNIT_EXPECT_EQ(test, (int)next, (int)DM_ISM_STATE_FULL_POWER_RUNNING);
|
||||
}
|
||||
|
||||
static void dm_test_ism_next_state_opt_idle_sso_cursor(struct kunit *test)
|
||||
{
|
||||
enum amdgpu_dm_ism_state next;
|
||||
bool ok;
|
||||
|
||||
ok = dm_ism_next_state(DM_ISM_STATE_OPTIMIZED_IDLE_SSO,
|
||||
DM_ISM_EVENT_BEGIN_CURSOR_UPDATE, &next);
|
||||
KUNIT_EXPECT_TRUE(test, ok);
|
||||
KUNIT_EXPECT_EQ(test, (int)next, (int)DM_ISM_STATE_HYSTERESIS_BUSY);
|
||||
}
|
||||
|
||||
/* ===== Tests for dm_ism_next_state — TIMER_ABORTED transitions ===== */
|
||||
|
||||
static void dm_test_ism_next_state_aborted_immediate(struct kunit *test)
|
||||
{
|
||||
enum amdgpu_dm_ism_state next;
|
||||
bool ok;
|
||||
|
||||
ok = dm_ism_next_state(DM_ISM_STATE_TIMER_ABORTED,
|
||||
DM_ISM_EVENT_IMMEDIATE, &next);
|
||||
KUNIT_EXPECT_TRUE(test, ok);
|
||||
KUNIT_EXPECT_EQ(test, (int)next, (int)DM_ISM_STATE_FULL_POWER_RUNNING);
|
||||
}
|
||||
|
||||
static void dm_test_ism_next_state_aborted_invalid(struct kunit *test)
|
||||
{
|
||||
enum amdgpu_dm_ism_state next = DM_ISM_NUM_STATES;
|
||||
bool ok;
|
||||
|
||||
ok = dm_ism_next_state(DM_ISM_STATE_TIMER_ABORTED,
|
||||
DM_ISM_EVENT_ENTER_IDLE_REQUESTED, &next);
|
||||
KUNIT_EXPECT_FALSE(test, ok);
|
||||
KUNIT_EXPECT_EQ(test, (int)next, (int)DM_ISM_NUM_STATES);
|
||||
}
|
||||
|
||||
/* ===== Tests for dm_ism_get_sso_delay ===== */
|
||||
|
||||
static void dm_test_ism_sso_delay_null_stream(struct kunit *test)
|
||||
{
|
||||
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
|
||||
|
||||
ism->config.sso_num_frames = 5;
|
||||
|
||||
KUNIT_EXPECT_EQ(test, dm_ism_get_sso_delay(ism, NULL), (uint64_t)0);
|
||||
}
|
||||
|
||||
static void dm_test_ism_sso_delay_zero_frames(struct kunit *test)
|
||||
{
|
||||
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
|
||||
struct dc_stream_state *stream = alloc_test_stream(test);
|
||||
|
||||
stream->timing.v_total = 1125;
|
||||
stream->timing.h_total = 2200;
|
||||
stream->timing.pix_clk_100hz = 1485000;
|
||||
ism->config.sso_num_frames = 0;
|
||||
|
||||
KUNIT_EXPECT_EQ(test, dm_ism_get_sso_delay(ism, stream), (uint64_t)0);
|
||||
}
|
||||
|
||||
static void dm_test_ism_sso_delay_1080p60_3frames(struct kunit *test)
|
||||
{
|
||||
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
|
||||
struct dc_stream_state *stream = alloc_test_stream(test);
|
||||
uint64_t expected_one_frame_ns, expected;
|
||||
|
||||
/*
|
||||
* 1080p@60Hz: v_total=1125, h_total=2200, pix_clk=148.5MHz
|
||||
* pix_clk_100hz = 1485000
|
||||
* one_frame_ns = (1125 * 2200 * 10000000) / 1485000 = 16666666 ns
|
||||
*/
|
||||
stream->timing.v_total = 1125;
|
||||
stream->timing.h_total = 2200;
|
||||
stream->timing.pix_clk_100hz = 1485000;
|
||||
ism->config.sso_num_frames = 3;
|
||||
|
||||
expected_one_frame_ns = div64_u64((uint64_t)1125 * 2200 * 10000000ULL,
|
||||
1485000);
|
||||
expected = 3 * expected_one_frame_ns;
|
||||
|
||||
KUNIT_EXPECT_EQ(test, dm_ism_get_sso_delay(ism, stream), expected);
|
||||
}
|
||||
|
||||
static void dm_test_ism_sso_delay_4k60_1frame(struct kunit *test)
|
||||
{
|
||||
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
|
||||
struct dc_stream_state *stream = alloc_test_stream(test);
|
||||
uint64_t expected_one_frame_ns;
|
||||
|
||||
/*
|
||||
* 4K@60Hz: v_total=2250, h_total=4400, pix_clk=594MHz
|
||||
* pix_clk_100hz = 5940000
|
||||
*/
|
||||
stream->timing.v_total = 2250;
|
||||
stream->timing.h_total = 4400;
|
||||
stream->timing.pix_clk_100hz = 5940000;
|
||||
ism->config.sso_num_frames = 1;
|
||||
|
||||
expected_one_frame_ns = div64_u64((uint64_t)2250 * 4400 * 10000000ULL,
|
||||
5940000);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, dm_ism_get_sso_delay(ism, stream),
|
||||
expected_one_frame_ns);
|
||||
}
|
||||
|
||||
/* ===== Tests for dm_ism_get_idle_allow_delay ===== */
|
||||
|
||||
static void dm_test_ism_idle_delay_null_stream(struct kunit *test)
|
||||
{
|
||||
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
|
||||
|
||||
ism->config.filter_num_frames = 5;
|
||||
ism->config.filter_entry_count = 3;
|
||||
ism->config.activation_num_delay_frames = 10;
|
||||
|
||||
KUNIT_EXPECT_EQ(test, dm_ism_get_idle_allow_delay(ism, NULL),
|
||||
(uint64_t)0);
|
||||
}
|
||||
|
||||
static void dm_test_ism_idle_delay_zero_filter_frames(struct kunit *test)
|
||||
{
|
||||
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
|
||||
struct dc_stream_state *stream = alloc_test_stream(test);
|
||||
|
||||
stream->timing.v_total = 1125;
|
||||
stream->timing.h_total = 2200;
|
||||
stream->timing.pix_clk_100hz = 1485000;
|
||||
ism->config.filter_num_frames = 0;
|
||||
|
||||
KUNIT_EXPECT_EQ(test, dm_ism_get_idle_allow_delay(ism, stream),
|
||||
(uint64_t)0);
|
||||
}
|
||||
|
||||
static void dm_test_ism_idle_delay_zero_entry_count(struct kunit *test)
|
||||
{
|
||||
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
|
||||
struct dc_stream_state *stream = alloc_test_stream(test);
|
||||
|
||||
stream->timing.v_total = 1125;
|
||||
stream->timing.h_total = 2200;
|
||||
stream->timing.pix_clk_100hz = 1485000;
|
||||
ism->config.filter_num_frames = 5;
|
||||
ism->config.filter_entry_count = 0;
|
||||
|
||||
KUNIT_EXPECT_EQ(test, dm_ism_get_idle_allow_delay(ism, stream),
|
||||
(uint64_t)0);
|
||||
}
|
||||
|
||||
static void dm_test_ism_idle_delay_zero_delay_frames(struct kunit *test)
|
||||
{
|
||||
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
|
||||
struct dc_stream_state *stream = alloc_test_stream(test);
|
||||
|
||||
stream->timing.v_total = 1125;
|
||||
stream->timing.h_total = 2200;
|
||||
stream->timing.pix_clk_100hz = 1485000;
|
||||
ism->config.filter_num_frames = 5;
|
||||
ism->config.filter_entry_count = 3;
|
||||
ism->config.activation_num_delay_frames = 0;
|
||||
|
||||
KUNIT_EXPECT_EQ(test, dm_ism_get_idle_allow_delay(ism, stream),
|
||||
(uint64_t)0);
|
||||
}
|
||||
|
||||
static void dm_test_ism_idle_delay_no_short_idles(struct kunit *test)
|
||||
{
|
||||
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
|
||||
struct dc_stream_state *stream = alloc_test_stream(test);
|
||||
uint64_t one_frame_ns;
|
||||
|
||||
/*
|
||||
* All history records have long durations (well above the
|
||||
* short_idle_ns threshold), so no delay should be applied.
|
||||
*/
|
||||
stream->timing.v_total = 1125;
|
||||
stream->timing.h_total = 2200;
|
||||
stream->timing.pix_clk_100hz = 1485000;
|
||||
|
||||
one_frame_ns = div64_u64((uint64_t)1125 * 2200 * 10000000ULL,
|
||||
1485000);
|
||||
|
||||
ism->config.filter_num_frames = 5;
|
||||
ism->config.filter_entry_count = 3;
|
||||
ism->config.activation_num_delay_frames = 10;
|
||||
ism->config.filter_history_size = 8;
|
||||
ism->config.filter_old_history_threshold = 0;
|
||||
|
||||
/* Fill history with long idle durations */
|
||||
for (int i = 0; i < 8; i++) {
|
||||
ism->records[i].duration_ns = one_frame_ns * 100;
|
||||
ism->records[i].timestamp_ns = 0;
|
||||
}
|
||||
ism->next_record_idx = 8;
|
||||
|
||||
KUNIT_EXPECT_EQ(test, dm_ism_get_idle_allow_delay(ism, stream),
|
||||
(uint64_t)0);
|
||||
}
|
||||
|
||||
static void dm_test_ism_idle_delay_enough_short_idles(struct kunit *test)
|
||||
{
|
||||
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
|
||||
struct dc_stream_state *stream = alloc_test_stream(test);
|
||||
uint64_t one_frame_ns, expected;
|
||||
|
||||
/*
|
||||
* Fill history with short idle durations that meet the threshold.
|
||||
* filter_entry_count=3, so 3 short idles should trigger the delay.
|
||||
*/
|
||||
stream->timing.v_total = 1125;
|
||||
stream->timing.h_total = 2200;
|
||||
stream->timing.pix_clk_100hz = 1485000;
|
||||
|
||||
one_frame_ns = div64_u64((uint64_t)1125 * 2200 * 10000000ULL,
|
||||
1485000);
|
||||
|
||||
ism->config.filter_num_frames = 5;
|
||||
ism->config.filter_entry_count = 3;
|
||||
ism->config.activation_num_delay_frames = 10;
|
||||
ism->config.filter_history_size = 8;
|
||||
ism->config.filter_old_history_threshold = 0;
|
||||
|
||||
/* Fill history with short idle durations (1 frame each) */
|
||||
for (int i = 0; i < 8; i++) {
|
||||
ism->records[i].duration_ns = one_frame_ns;
|
||||
ism->records[i].timestamp_ns = 0;
|
||||
}
|
||||
ism->next_record_idx = 8;
|
||||
|
||||
expected = 10 * one_frame_ns;
|
||||
KUNIT_EXPECT_EQ(test, dm_ism_get_idle_allow_delay(ism, stream),
|
||||
expected);
|
||||
}
|
||||
|
||||
static void dm_test_ism_idle_delay_wraps_around_buffer(struct kunit *test)
|
||||
{
|
||||
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
|
||||
struct dc_stream_state *stream = alloc_test_stream(test);
|
||||
uint64_t one_frame_ns, expected;
|
||||
|
||||
/*
|
||||
* Test the circular buffer wraparound: next_record_idx at 2 means
|
||||
* the most recent records are at indices 1, 0, 15, 14, ...
|
||||
*/
|
||||
stream->timing.v_total = 1125;
|
||||
stream->timing.h_total = 2200;
|
||||
stream->timing.pix_clk_100hz = 1485000;
|
||||
|
||||
one_frame_ns = div64_u64((uint64_t)1125 * 2200 * 10000000ULL,
|
||||
1485000);
|
||||
|
||||
ism->config.filter_num_frames = 5;
|
||||
ism->config.filter_entry_count = 3;
|
||||
ism->config.activation_num_delay_frames = 10;
|
||||
ism->config.filter_history_size = 8;
|
||||
ism->config.filter_old_history_threshold = 0;
|
||||
|
||||
/* Fill entire buffer with short idles */
|
||||
for (int i = 0; i < AMDGPU_DM_IDLE_HIST_LEN; i++) {
|
||||
ism->records[i].duration_ns = one_frame_ns;
|
||||
ism->records[i].timestamp_ns = 0;
|
||||
}
|
||||
/* Position next_record_idx at 2 to test wraparound */
|
||||
ism->next_record_idx = 2;
|
||||
|
||||
expected = 10 * one_frame_ns;
|
||||
KUNIT_EXPECT_EQ(test, dm_ism_get_idle_allow_delay(ism, stream),
|
||||
expected);
|
||||
}
|
||||
|
||||
static void dm_test_ism_idle_delay_old_history_cutoff(struct kunit *test)
|
||||
{
|
||||
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
|
||||
struct dc_stream_state *stream = alloc_test_stream(test);
|
||||
uint64_t one_frame_ns;
|
||||
|
||||
/*
|
||||
* Test old_history_threshold: only recent entries within the
|
||||
* threshold should be counted. Set up 2 recent short idles but
|
||||
* require 3 — older entries are outside the threshold.
|
||||
*/
|
||||
stream->timing.v_total = 1125;
|
||||
stream->timing.h_total = 2200;
|
||||
stream->timing.pix_clk_100hz = 1485000;
|
||||
|
||||
one_frame_ns = div64_u64((uint64_t)1125 * 2200 * 10000000ULL,
|
||||
1485000);
|
||||
|
||||
ism->config.filter_num_frames = 5;
|
||||
ism->config.filter_entry_count = 3;
|
||||
ism->config.activation_num_delay_frames = 10;
|
||||
ism->config.filter_history_size = 8;
|
||||
/* Threshold: entries older than 20 frames are ignored */
|
||||
ism->config.filter_old_history_threshold = 20;
|
||||
|
||||
ism->last_idle_timestamp_ns = one_frame_ns * 100;
|
||||
|
||||
/* 2 recent short idles (within threshold) */
|
||||
ism->records[6].duration_ns = one_frame_ns;
|
||||
ism->records[6].timestamp_ns = one_frame_ns * 95;
|
||||
ism->records[7].duration_ns = one_frame_ns;
|
||||
ism->records[7].timestamp_ns = one_frame_ns * 98;
|
||||
|
||||
/* Older entries outside the threshold with long durations */
|
||||
for (int i = 0; i < 6; i++) {
|
||||
ism->records[i].duration_ns = one_frame_ns * 100;
|
||||
ism->records[i].timestamp_ns = one_frame_ns * 10;
|
||||
}
|
||||
ism->next_record_idx = 8;
|
||||
|
||||
/*
|
||||
* Only 2 short idles within threshold, but 3 required —
|
||||
* should return 0 (no delay).
|
||||
*/
|
||||
KUNIT_EXPECT_EQ(test, dm_ism_get_idle_allow_delay(ism, stream),
|
||||
(uint64_t)0);
|
||||
}
|
||||
|
||||
static void dm_test_ism_idle_delay_mixed_durations(struct kunit *test)
|
||||
{
|
||||
struct amdgpu_dm_ism *ism = alloc_test_ism(test);
|
||||
struct dc_stream_state *stream = alloc_test_stream(test);
|
||||
uint64_t one_frame_ns;
|
||||
|
||||
/*
|
||||
* Mix of short and long idle durations. Only 2 short idles
|
||||
* in 8 entries, but filter_entry_count=3, so no delay.
|
||||
*/
|
||||
stream->timing.v_total = 1125;
|
||||
stream->timing.h_total = 2200;
|
||||
stream->timing.pix_clk_100hz = 1485000;
|
||||
|
||||
one_frame_ns = div64_u64((uint64_t)1125 * 2200 * 10000000ULL,
|
||||
1485000);
|
||||
|
||||
ism->config.filter_num_frames = 5;
|
||||
ism->config.filter_entry_count = 3;
|
||||
ism->config.activation_num_delay_frames = 10;
|
||||
ism->config.filter_history_size = 8;
|
||||
ism->config.filter_old_history_threshold = 0;
|
||||
|
||||
/* 2 short idles, 6 long idles */
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (i == 6 || i == 7)
|
||||
ism->records[i].duration_ns = one_frame_ns;
|
||||
else
|
||||
ism->records[i].duration_ns = one_frame_ns * 100;
|
||||
ism->records[i].timestamp_ns = 0;
|
||||
}
|
||||
ism->next_record_idx = 8;
|
||||
|
||||
KUNIT_EXPECT_EQ(test, dm_ism_get_idle_allow_delay(ism, stream),
|
||||
(uint64_t)0);
|
||||
}
|
||||
|
||||
static struct kunit_case dm_ism_test_cases[] = {
|
||||
/* dm_ism_next_state — FULL_POWER_RUNNING */
|
||||
KUNIT_CASE(dm_test_ism_next_state_running_enter_idle),
|
||||
KUNIT_CASE(dm_test_ism_next_state_running_begin_cursor),
|
||||
KUNIT_CASE(dm_test_ism_next_state_running_invalid),
|
||||
/* dm_ism_next_state — FULL_POWER_BUSY */
|
||||
KUNIT_CASE(dm_test_ism_next_state_busy_enter_idle),
|
||||
KUNIT_CASE(dm_test_ism_next_state_busy_end_cursor),
|
||||
/* dm_ism_next_state — HYSTERESIS_WAITING */
|
||||
KUNIT_CASE(dm_test_ism_next_state_hyst_wait_exit_idle),
|
||||
KUNIT_CASE(dm_test_ism_next_state_hyst_wait_begin_cursor),
|
||||
KUNIT_CASE(dm_test_ism_next_state_hyst_wait_timer),
|
||||
KUNIT_CASE(dm_test_ism_next_state_hyst_wait_immediate),
|
||||
/* dm_ism_next_state — HYSTERESIS_BUSY */
|
||||
KUNIT_CASE(dm_test_ism_next_state_hyst_busy_exit_idle),
|
||||
KUNIT_CASE(dm_test_ism_next_state_hyst_busy_end_cursor),
|
||||
/* dm_ism_next_state — OPTIMIZED_IDLE */
|
||||
KUNIT_CASE(dm_test_ism_next_state_opt_idle_exit),
|
||||
KUNIT_CASE(dm_test_ism_next_state_opt_idle_begin_cursor),
|
||||
KUNIT_CASE(dm_test_ism_next_state_opt_idle_sso_timer),
|
||||
KUNIT_CASE(dm_test_ism_next_state_opt_idle_immediate),
|
||||
/* dm_ism_next_state — OPTIMIZED_IDLE_SSO */
|
||||
KUNIT_CASE(dm_test_ism_next_state_opt_idle_sso_exit),
|
||||
KUNIT_CASE(dm_test_ism_next_state_opt_idle_sso_cursor),
|
||||
/* dm_ism_next_state — TIMER_ABORTED */
|
||||
KUNIT_CASE(dm_test_ism_next_state_aborted_immediate),
|
||||
KUNIT_CASE(dm_test_ism_next_state_aborted_invalid),
|
||||
/* dm_ism_get_sso_delay */
|
||||
KUNIT_CASE(dm_test_ism_sso_delay_null_stream),
|
||||
KUNIT_CASE(dm_test_ism_sso_delay_zero_frames),
|
||||
KUNIT_CASE(dm_test_ism_sso_delay_1080p60_3frames),
|
||||
KUNIT_CASE(dm_test_ism_sso_delay_4k60_1frame),
|
||||
/* dm_ism_get_idle_allow_delay */
|
||||
KUNIT_CASE(dm_test_ism_idle_delay_null_stream),
|
||||
KUNIT_CASE(dm_test_ism_idle_delay_zero_filter_frames),
|
||||
KUNIT_CASE(dm_test_ism_idle_delay_zero_entry_count),
|
||||
KUNIT_CASE(dm_test_ism_idle_delay_zero_delay_frames),
|
||||
KUNIT_CASE(dm_test_ism_idle_delay_no_short_idles),
|
||||
KUNIT_CASE(dm_test_ism_idle_delay_enough_short_idles),
|
||||
KUNIT_CASE(dm_test_ism_idle_delay_wraps_around_buffer),
|
||||
KUNIT_CASE(dm_test_ism_idle_delay_old_history_cutoff),
|
||||
KUNIT_CASE(dm_test_ism_idle_delay_mixed_durations),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite dm_ism_test_suite = {
|
||||
.name = "amdgpu_dm_ism",
|
||||
.test_cases = dm_ism_test_cases,
|
||||
};
|
||||
|
||||
kunit_test_suite(dm_ism_test_suite);
|
||||
|
||||
MODULE_LICENSE("Dual MIT/GPL");
|
||||
MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_ism");
|
||||
MODULE_AUTHOR("AMD");
|
||||
255
drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_psr_test.c
Normal file
255
drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_psr_test.c
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR MIT
|
||||
/*
|
||||
* KUnit tests for amdgpu_dm_psr.c
|
||||
*
|
||||
* Copyright 2026 Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#include <kunit/test.h>
|
||||
|
||||
#include "dc.h"
|
||||
|
||||
/* Extern declaration for the function under test */
|
||||
extern void amdgpu_dm_psr_fill_caps(struct dc_link *link,
|
||||
struct psr_caps *caps);
|
||||
|
||||
/*
|
||||
* Helper: allocate and zero-initialise a dc_link sufficient for
|
||||
* amdgpu_dm_psr_fill_caps() testing. The function only accesses
|
||||
* embedded members (dpcd_caps, psr_settings) so no pointer fields
|
||||
* need to be wired up.
|
||||
*/
|
||||
static struct dc_link *alloc_test_link(struct kunit *test)
|
||||
{
|
||||
struct dc_link *link;
|
||||
|
||||
link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, link);
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
/* Tests for amdgpu_dm_psr_fill_caps() — PSR version mapping */
|
||||
|
||||
static void dm_test_psr_fill_caps_version_1(struct kunit *test)
|
||||
{
|
||||
struct dc_link *link = alloc_test_link(test);
|
||||
struct psr_caps caps;
|
||||
|
||||
memset(&caps, 0, sizeof(caps));
|
||||
link->psr_settings.psr_version = DC_PSR_VERSION_1;
|
||||
|
||||
amdgpu_dm_psr_fill_caps(link, &caps);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, (int)caps.psr_version, 1);
|
||||
}
|
||||
|
||||
static void dm_test_psr_fill_caps_version_su1(struct kunit *test)
|
||||
{
|
||||
struct dc_link *link = alloc_test_link(test);
|
||||
struct psr_caps caps;
|
||||
|
||||
memset(&caps, 0, sizeof(caps));
|
||||
link->psr_settings.psr_version = DC_PSR_VERSION_SU_1;
|
||||
|
||||
amdgpu_dm_psr_fill_caps(link, &caps);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, (int)caps.psr_version, 2);
|
||||
}
|
||||
|
||||
static void dm_test_psr_fill_caps_version_unsupported(struct kunit *test)
|
||||
{
|
||||
struct dc_link *link = alloc_test_link(test);
|
||||
struct psr_caps caps;
|
||||
|
||||
memset(&caps, 0, sizeof(caps));
|
||||
link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED;
|
||||
|
||||
amdgpu_dm_psr_fill_caps(link, &caps);
|
||||
|
||||
/*
|
||||
* Neither DC_PSR_VERSION_1 nor DC_PSR_VERSION_SU_1,
|
||||
* so psr_version stays at its zero-initialised value.
|
||||
*/
|
||||
KUNIT_EXPECT_EQ(test, (int)caps.psr_version, 0);
|
||||
}
|
||||
|
||||
/* Tests for amdgpu_dm_psr_fill_caps() — RFB setup time */
|
||||
|
||||
static void dm_test_psr_fill_caps_setup_time_zero(struct kunit *test)
|
||||
{
|
||||
struct dc_link *link = alloc_test_link(test);
|
||||
struct psr_caps caps;
|
||||
|
||||
memset(&caps, 0, sizeof(caps));
|
||||
/* PSR_SETUP_TIME = 0 → (6 - 0) * 55 = 330 */
|
||||
link->dpcd_caps.psr_info.psr_dpcd_caps.bits.PSR_SETUP_TIME = 0;
|
||||
|
||||
amdgpu_dm_psr_fill_caps(link, &caps);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, caps.psr_rfb_setup_time, 330U);
|
||||
}
|
||||
|
||||
static void dm_test_psr_fill_caps_setup_time_mid(struct kunit *test)
|
||||
{
|
||||
struct dc_link *link = alloc_test_link(test);
|
||||
struct psr_caps caps;
|
||||
|
||||
memset(&caps, 0, sizeof(caps));
|
||||
/* PSR_SETUP_TIME = 3 → (6 - 3) * 55 = 165 */
|
||||
link->dpcd_caps.psr_info.psr_dpcd_caps.bits.PSR_SETUP_TIME = 3;
|
||||
|
||||
amdgpu_dm_psr_fill_caps(link, &caps);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, caps.psr_rfb_setup_time, 165U);
|
||||
}
|
||||
|
||||
static void dm_test_psr_fill_caps_setup_time_max(struct kunit *test)
|
||||
{
|
||||
struct dc_link *link = alloc_test_link(test);
|
||||
struct psr_caps caps;
|
||||
|
||||
memset(&caps, 0, sizeof(caps));
|
||||
/* PSR_SETUP_TIME = 6 → (6 - 6) * 55 = 0 */
|
||||
link->dpcd_caps.psr_info.psr_dpcd_caps.bits.PSR_SETUP_TIME = 6;
|
||||
|
||||
amdgpu_dm_psr_fill_caps(link, &caps);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, caps.psr_rfb_setup_time, 0U);
|
||||
}
|
||||
|
||||
/* Tests for amdgpu_dm_psr_fill_caps() — link training flag */
|
||||
|
||||
static void dm_test_psr_fill_caps_link_training_required(struct kunit *test)
|
||||
{
|
||||
struct dc_link *link = alloc_test_link(test);
|
||||
struct psr_caps caps;
|
||||
|
||||
memset(&caps, 0, sizeof(caps));
|
||||
link->dpcd_caps.psr_info.psr_dpcd_caps.bits.LINK_TRAINING_ON_EXIT_NOT_REQUIRED = 0;
|
||||
|
||||
amdgpu_dm_psr_fill_caps(link, &caps);
|
||||
|
||||
KUNIT_EXPECT_TRUE(test, caps.psr_exit_link_training_required);
|
||||
}
|
||||
|
||||
static void dm_test_psr_fill_caps_link_training_not_required(struct kunit *test)
|
||||
{
|
||||
struct dc_link *link = alloc_test_link(test);
|
||||
struct psr_caps caps;
|
||||
|
||||
memset(&caps, 0, sizeof(caps));
|
||||
link->dpcd_caps.psr_info.psr_dpcd_caps.bits.LINK_TRAINING_ON_EXIT_NOT_REQUIRED = 1;
|
||||
|
||||
amdgpu_dm_psr_fill_caps(link, &caps);
|
||||
|
||||
KUNIT_EXPECT_FALSE(test, caps.psr_exit_link_training_required);
|
||||
}
|
||||
|
||||
/* Tests for amdgpu_dm_psr_fill_caps() — DPCD field passthrough */
|
||||
|
||||
static void dm_test_psr_fill_caps_dpcd_fields(struct kunit *test)
|
||||
{
|
||||
struct dc_link *link = alloc_test_link(test);
|
||||
struct psr_caps caps;
|
||||
|
||||
memset(&caps, 0, sizeof(caps));
|
||||
|
||||
link->dpcd_caps.edp_rev = 0x14;
|
||||
link->dpcd_caps.psr_info.psr_version = 2;
|
||||
link->dpcd_caps.psr_info.psr_dpcd_caps.bits.SU_GRANULARITY_REQUIRED = 1;
|
||||
link->dpcd_caps.psr_info.psr_dpcd_caps.bits.Y_COORDINATE_REQUIRED = 1;
|
||||
link->dpcd_caps.psr_info.psr2_su_y_granularity_cap = 4;
|
||||
link->dpcd_caps.alpm_caps.bits.AUX_WAKE_ALPM_CAP = 1;
|
||||
link->dpcd_caps.alpm_caps.bits.PM_STATE_2A_SUPPORT = 1;
|
||||
|
||||
amdgpu_dm_psr_fill_caps(link, &caps);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, (int)caps.edp_revision, 0x14);
|
||||
KUNIT_EXPECT_EQ(test, (int)caps.support_ver, 2);
|
||||
KUNIT_EXPECT_TRUE(test, caps.su_granularity_required);
|
||||
KUNIT_EXPECT_TRUE(test, caps.y_coordinate_required);
|
||||
KUNIT_EXPECT_EQ(test, (int)caps.su_y_granularity, 4);
|
||||
KUNIT_EXPECT_TRUE(test, caps.alpm_cap);
|
||||
KUNIT_EXPECT_TRUE(test, caps.standby_support);
|
||||
}
|
||||
|
||||
static void dm_test_psr_fill_caps_dpcd_fields_unset(struct kunit *test)
|
||||
{
|
||||
struct dc_link *link = alloc_test_link(test);
|
||||
struct psr_caps caps;
|
||||
|
||||
memset(&caps, 0xFF, sizeof(caps));
|
||||
|
||||
/* All dpcd_caps fields are zero from kzalloc */
|
||||
amdgpu_dm_psr_fill_caps(link, &caps);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, (int)caps.edp_revision, 0);
|
||||
KUNIT_EXPECT_EQ(test, (int)caps.support_ver, 0);
|
||||
KUNIT_EXPECT_FALSE(test, caps.su_granularity_required);
|
||||
KUNIT_EXPECT_FALSE(test, caps.y_coordinate_required);
|
||||
KUNIT_EXPECT_EQ(test, (int)caps.su_y_granularity, 0);
|
||||
KUNIT_EXPECT_FALSE(test, caps.alpm_cap);
|
||||
KUNIT_EXPECT_FALSE(test, caps.standby_support);
|
||||
}
|
||||
|
||||
/* Tests for amdgpu_dm_psr_fill_caps() — rate control and power opts */
|
||||
|
||||
static void dm_test_psr_fill_caps_rate_control_always_zero(struct kunit *test)
|
||||
{
|
||||
struct dc_link *link = alloc_test_link(test);
|
||||
struct psr_caps caps;
|
||||
|
||||
/* Pre-fill caps with non-zero to verify overwrite */
|
||||
memset(&caps, 0xFF, sizeof(caps));
|
||||
|
||||
amdgpu_dm_psr_fill_caps(link, &caps);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, (int)caps.rate_control_caps, 0);
|
||||
}
|
||||
|
||||
static void dm_test_psr_fill_caps_power_opts_z10_always_set(struct kunit *test)
|
||||
{
|
||||
struct dc_link *link = alloc_test_link(test);
|
||||
struct psr_caps caps;
|
||||
|
||||
memset(&caps, 0, sizeof(caps));
|
||||
|
||||
amdgpu_dm_psr_fill_caps(link, &caps);
|
||||
|
||||
/*
|
||||
* psr_power_opt_z10_static_screen is always added to power_opts
|
||||
* regardless of amdgpu_dc_feature_mask.
|
||||
*/
|
||||
KUNIT_EXPECT_TRUE(test,
|
||||
(caps.psr_power_opt_flag &
|
||||
psr_power_opt_z10_static_screen) != 0);
|
||||
}
|
||||
/* End of tests for amdgpu_dm_psr_fill_caps() */
|
||||
|
||||
static struct kunit_case dm_psr_test_cases[] = {
|
||||
KUNIT_CASE(dm_test_psr_fill_caps_version_1),
|
||||
KUNIT_CASE(dm_test_psr_fill_caps_version_su1),
|
||||
KUNIT_CASE(dm_test_psr_fill_caps_version_unsupported),
|
||||
KUNIT_CASE(dm_test_psr_fill_caps_setup_time_zero),
|
||||
KUNIT_CASE(dm_test_psr_fill_caps_setup_time_mid),
|
||||
KUNIT_CASE(dm_test_psr_fill_caps_setup_time_max),
|
||||
KUNIT_CASE(dm_test_psr_fill_caps_link_training_required),
|
||||
KUNIT_CASE(dm_test_psr_fill_caps_link_training_not_required),
|
||||
KUNIT_CASE(dm_test_psr_fill_caps_dpcd_fields),
|
||||
KUNIT_CASE(dm_test_psr_fill_caps_dpcd_fields_unset),
|
||||
KUNIT_CASE(dm_test_psr_fill_caps_rate_control_always_zero),
|
||||
KUNIT_CASE(dm_test_psr_fill_caps_power_opts_z10_always_set),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite dm_psr_test_suite = {
|
||||
.name = "amdgpu_dm_psr",
|
||||
.test_cases = dm_psr_test_cases,
|
||||
};
|
||||
|
||||
kunit_test_suite(dm_psr_test_suite);
|
||||
|
||||
MODULE_LICENSE("Dual MIT/GPL");
|
||||
MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_psr");
|
||||
MODULE_AUTHOR("AMD");
|
||||
|
|
@ -0,0 +1,206 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR MIT
|
||||
/*
|
||||
* KUnit tests for amdgpu_dm_replay.c
|
||||
*
|
||||
* Copyright 2026 Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#include <kunit/test.h>
|
||||
|
||||
#include "dc.h"
|
||||
#include "amdgpu_mode.h"
|
||||
#include "amdgpu_dm.h"
|
||||
|
||||
/* Extern declaration for the function under test */
|
||||
extern bool amdgpu_dm_link_supports_replay(struct dc_link *link,
|
||||
struct amdgpu_dm_connector *aconnector);
|
||||
|
||||
/*
|
||||
* Helper: allocate a dc_link, amdgpu_dm_connector, and dm_connector_state
|
||||
* wired up so that to_dm_connector_state(aconnector->base.state) works.
|
||||
*/
|
||||
struct replay_test_ctx {
|
||||
struct dc_link *link;
|
||||
struct amdgpu_dm_connector *aconnector;
|
||||
struct dm_connector_state *dm_state;
|
||||
};
|
||||
|
||||
static struct replay_test_ctx *alloc_replay_ctx(struct kunit *test)
|
||||
{
|
||||
struct replay_test_ctx *ctx;
|
||||
|
||||
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, ctx);
|
||||
|
||||
ctx->link = kunit_kzalloc(test, sizeof(*ctx->link), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, ctx->link);
|
||||
|
||||
ctx->aconnector = kunit_kzalloc(test, sizeof(*ctx->aconnector), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector);
|
||||
|
||||
ctx->dm_state = kunit_kzalloc(test, sizeof(*ctx->dm_state), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, ctx->dm_state);
|
||||
|
||||
/* Wire connector state so to_dm_connector_state() works */
|
||||
ctx->aconnector->base.state = &ctx->dm_state->base;
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper: set all conditions for replay support to pass so individual
|
||||
* tests can disable one condition at a time.
|
||||
*/
|
||||
static void set_all_replay_caps(struct replay_test_ctx *ctx)
|
||||
{
|
||||
ctx->dm_state->freesync_capable = true;
|
||||
ctx->aconnector->vsdb_info.replay_mode = true;
|
||||
ctx->link->dpcd_caps.edp_rev = EDP_REVISION_13;
|
||||
ctx->link->dpcd_caps.alpm_caps.bits.AUX_WAKE_ALPM_CAP = 1;
|
||||
ctx->link->dpcd_caps.adaptive_sync_caps.dp_adap_sync_caps.bits.ADAPTIVE_SYNC_SDP_SUPPORT = 1;
|
||||
ctx->link->dpcd_caps.pr_info.pixel_deviation_per_line = 1;
|
||||
ctx->link->dpcd_caps.pr_info.max_deviation_line = 1;
|
||||
}
|
||||
|
||||
/* Tests for amdgpu_dm_link_supports_replay() — all caps met */
|
||||
|
||||
static void dm_test_replay_supports_all_caps(struct kunit *test)
|
||||
{
|
||||
struct replay_test_ctx *ctx = alloc_replay_ctx(test);
|
||||
|
||||
set_all_replay_caps(ctx);
|
||||
|
||||
KUNIT_EXPECT_TRUE(test,
|
||||
amdgpu_dm_link_supports_replay(ctx->link, ctx->aconnector));
|
||||
}
|
||||
|
||||
/* Tests for amdgpu_dm_link_supports_replay() — freesync not capable */
|
||||
|
||||
static void dm_test_replay_no_freesync(struct kunit *test)
|
||||
{
|
||||
struct replay_test_ctx *ctx = alloc_replay_ctx(test);
|
||||
|
||||
set_all_replay_caps(ctx);
|
||||
ctx->dm_state->freesync_capable = false;
|
||||
|
||||
KUNIT_EXPECT_FALSE(test,
|
||||
amdgpu_dm_link_supports_replay(ctx->link, ctx->aconnector));
|
||||
}
|
||||
|
||||
/* Tests for amdgpu_dm_link_supports_replay() — no replay mode in VSDB */
|
||||
|
||||
static void dm_test_replay_no_vsdb_replay_mode(struct kunit *test)
|
||||
{
|
||||
struct replay_test_ctx *ctx = alloc_replay_ctx(test);
|
||||
|
||||
set_all_replay_caps(ctx);
|
||||
ctx->aconnector->vsdb_info.replay_mode = false;
|
||||
|
||||
KUNIT_EXPECT_FALSE(test,
|
||||
amdgpu_dm_link_supports_replay(ctx->link, ctx->aconnector));
|
||||
}
|
||||
|
||||
/* Tests for amdgpu_dm_link_supports_replay() — eDP revision too low */
|
||||
|
||||
static void dm_test_replay_edp_rev_too_low(struct kunit *test)
|
||||
{
|
||||
struct replay_test_ctx *ctx = alloc_replay_ctx(test);
|
||||
|
||||
set_all_replay_caps(ctx);
|
||||
ctx->link->dpcd_caps.edp_rev = EDP_REVISION_12;
|
||||
|
||||
KUNIT_EXPECT_FALSE(test,
|
||||
amdgpu_dm_link_supports_replay(ctx->link, ctx->aconnector));
|
||||
}
|
||||
|
||||
/* Tests for amdgpu_dm_link_supports_replay() — no ALPM AUX wake cap */
|
||||
|
||||
static void dm_test_replay_no_alpm_aux_wake(struct kunit *test)
|
||||
{
|
||||
struct replay_test_ctx *ctx = alloc_replay_ctx(test);
|
||||
|
||||
set_all_replay_caps(ctx);
|
||||
ctx->link->dpcd_caps.alpm_caps.bits.AUX_WAKE_ALPM_CAP = 0;
|
||||
|
||||
KUNIT_EXPECT_FALSE(test,
|
||||
amdgpu_dm_link_supports_replay(ctx->link, ctx->aconnector));
|
||||
}
|
||||
|
||||
/* Tests for amdgpu_dm_link_supports_replay() — no adaptive sync SDP */
|
||||
|
||||
static void dm_test_replay_no_adaptive_sync_sdp(struct kunit *test)
|
||||
{
|
||||
struct replay_test_ctx *ctx = alloc_replay_ctx(test);
|
||||
|
||||
set_all_replay_caps(ctx);
|
||||
ctx->link->dpcd_caps.adaptive_sync_caps.dp_adap_sync_caps.bits.ADAPTIVE_SYNC_SDP_SUPPORT = 0;
|
||||
|
||||
KUNIT_EXPECT_FALSE(test,
|
||||
amdgpu_dm_link_supports_replay(ctx->link, ctx->aconnector));
|
||||
}
|
||||
|
||||
/* Tests for amdgpu_dm_link_supports_replay() — zero pixel deviation */
|
||||
|
||||
static void dm_test_replay_zero_pixel_deviation(struct kunit *test)
|
||||
{
|
||||
struct replay_test_ctx *ctx = alloc_replay_ctx(test);
|
||||
|
||||
set_all_replay_caps(ctx);
|
||||
ctx->link->dpcd_caps.pr_info.pixel_deviation_per_line = 0;
|
||||
|
||||
KUNIT_EXPECT_FALSE(test,
|
||||
amdgpu_dm_link_supports_replay(ctx->link, ctx->aconnector));
|
||||
}
|
||||
|
||||
/* Tests for amdgpu_dm_link_supports_replay() — zero max deviation line */
|
||||
|
||||
static void dm_test_replay_zero_max_deviation_line(struct kunit *test)
|
||||
{
|
||||
struct replay_test_ctx *ctx = alloc_replay_ctx(test);
|
||||
|
||||
set_all_replay_caps(ctx);
|
||||
ctx->link->dpcd_caps.pr_info.max_deviation_line = 0;
|
||||
|
||||
KUNIT_EXPECT_FALSE(test,
|
||||
amdgpu_dm_link_supports_replay(ctx->link, ctx->aconnector));
|
||||
}
|
||||
|
||||
/* Tests for amdgpu_dm_link_supports_replay() — both deviation fields zero */
|
||||
|
||||
static void dm_test_replay_both_deviations_zero(struct kunit *test)
|
||||
{
|
||||
struct replay_test_ctx *ctx = alloc_replay_ctx(test);
|
||||
|
||||
set_all_replay_caps(ctx);
|
||||
ctx->link->dpcd_caps.pr_info.pixel_deviation_per_line = 0;
|
||||
ctx->link->dpcd_caps.pr_info.max_deviation_line = 0;
|
||||
|
||||
KUNIT_EXPECT_FALSE(test,
|
||||
amdgpu_dm_link_supports_replay(ctx->link, ctx->aconnector));
|
||||
}
|
||||
|
||||
/* End of tests for amdgpu_dm_link_supports_replay() */
|
||||
|
||||
static struct kunit_case dm_replay_test_cases[] = {
|
||||
KUNIT_CASE(dm_test_replay_supports_all_caps),
|
||||
KUNIT_CASE(dm_test_replay_no_freesync),
|
||||
KUNIT_CASE(dm_test_replay_no_vsdb_replay_mode),
|
||||
KUNIT_CASE(dm_test_replay_edp_rev_too_low),
|
||||
KUNIT_CASE(dm_test_replay_no_alpm_aux_wake),
|
||||
KUNIT_CASE(dm_test_replay_no_adaptive_sync_sdp),
|
||||
KUNIT_CASE(dm_test_replay_zero_pixel_deviation),
|
||||
KUNIT_CASE(dm_test_replay_zero_max_deviation_line),
|
||||
KUNIT_CASE(dm_test_replay_both_deviations_zero),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite dm_replay_test_suite = {
|
||||
.name = "amdgpu_dm_replay",
|
||||
.test_cases = dm_replay_test_cases,
|
||||
};
|
||||
|
||||
kunit_test_suite(dm_replay_test_suite);
|
||||
|
||||
MODULE_LICENSE("Dual MIT/GPL");
|
||||
MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_replay");
|
||||
MODULE_AUTHOR("AMD");
|
||||
|
|
@ -2419,15 +2419,6 @@ static enum bp_result get_integrated_info_v8(
|
|||
info->dentist_vco_freq = le32_to_cpu(info_v8->ulDentistVCOFreq) * 10;
|
||||
info->boot_up_uma_clock = le32_to_cpu(info_v8->ulBootUpUMAClock) * 10;
|
||||
|
||||
for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
|
||||
/* Convert [10KHz] into [KHz] */
|
||||
info->disp_clk_voltage[i].max_supported_clk =
|
||||
le32_to_cpu(info_v8->sDISPCLK_Voltage[i].
|
||||
ulMaximumSupportedCLK) * 10;
|
||||
info->disp_clk_voltage[i].voltage_index =
|
||||
le32_to_cpu(info_v8->sDISPCLK_Voltage[i].ulVoltageIndex);
|
||||
}
|
||||
|
||||
info->boot_up_req_display_vector =
|
||||
le32_to_cpu(info_v8->ulBootUpReqDisplayVector);
|
||||
info->gpu_cap_info =
|
||||
|
|
@ -2570,14 +2561,6 @@ static enum bp_result get_integrated_info_v9(
|
|||
info->dentist_vco_freq = le32_to_cpu(info_v9->ulDentistVCOFreq) * 10;
|
||||
info->boot_up_uma_clock = le32_to_cpu(info_v9->ulBootUpUMAClock) * 10;
|
||||
|
||||
for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
|
||||
/* Convert [10KHz] into [KHz] */
|
||||
info->disp_clk_voltage[i].max_supported_clk =
|
||||
le32_to_cpu(info_v9->sDISPCLK_Voltage[i].ulMaximumSupportedCLK) * 10;
|
||||
info->disp_clk_voltage[i].voltage_index =
|
||||
le32_to_cpu(info_v9->sDISPCLK_Voltage[i].ulVoltageIndex);
|
||||
}
|
||||
|
||||
info->boot_up_req_display_vector =
|
||||
le32_to_cpu(info_v9->ulBootUpReqDisplayVector);
|
||||
info->gpu_cap_info = le32_to_cpu(info_v9->ulGPUCapInfo);
|
||||
|
|
@ -2719,25 +2702,6 @@ static enum bp_result construct_integrated_info(
|
|||
}
|
||||
}
|
||||
|
||||
/* Sort voltage table from low to high*/
|
||||
if (result == BP_RESULT_OK) {
|
||||
int32_t i;
|
||||
int32_t j;
|
||||
|
||||
for (i = 1; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
|
||||
for (j = i; j > 0; --j) {
|
||||
if (
|
||||
info->disp_clk_voltage[j].max_supported_clk <
|
||||
info->disp_clk_voltage[j-1].max_supported_clk) {
|
||||
/* swap j and j - 1*/
|
||||
swap(info->disp_clk_voltage[j - 1],
|
||||
info->disp_clk_voltage[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2671,15 +2671,6 @@ static enum bp_result get_integrated_info_v11(
|
|||
info->dentist_vco_freq = le32_to_cpu(info_v11->ulDentistVCOFreq) * 10;
|
||||
info->boot_up_uma_clock = le32_to_cpu(info_v8->ulBootUpUMAClock) * 10;
|
||||
|
||||
for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
|
||||
/* Convert [10KHz] into [KHz] */
|
||||
info->disp_clk_voltage[i].max_supported_clk =
|
||||
le32_to_cpu(info_v11->sDISPCLK_Voltage[i].
|
||||
ulMaximumSupportedCLK) * 10;
|
||||
info->disp_clk_voltage[i].voltage_index =
|
||||
le32_to_cpu(info_v11->sDISPCLK_Voltage[i].ulVoltageIndex);
|
||||
}
|
||||
|
||||
info->boot_up_req_display_vector =
|
||||
le32_to_cpu(info_v11->ulBootUpReqDisplayVector);
|
||||
info->boot_up_nb_voltage =
|
||||
|
|
@ -3032,7 +3023,6 @@ static enum bp_result construct_integrated_info(
|
|||
struct atom_data_revision revision;
|
||||
|
||||
int32_t i;
|
||||
int32_t j;
|
||||
|
||||
if (!info)
|
||||
return result;
|
||||
|
|
@ -3134,14 +3124,6 @@ static enum bp_result construct_integrated_info(
|
|||
DC_LOG_BIOS("driver forced fixdpvoltageswing = %d\n", info->ext_disp_conn_info.fixdpvoltageswing);
|
||||
}
|
||||
}
|
||||
/* Sort voltage table from low to high*/
|
||||
for (i = 1; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
|
||||
for (j = i; j > 0; --j) {
|
||||
if (info->disp_clk_voltage[j].max_supported_clk <
|
||||
info->disp_clk_voltage[j-1].max_supported_clk)
|
||||
swap(info->disp_clk_voltage[j-1], info->disp_clk_voltage[j]);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,32 +62,6 @@ static const struct clk_mgr_mask disp_clk_mask = {
|
|||
CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK)
|
||||
};
|
||||
|
||||
/* Max clock values for each state indexed by "enum clocks_state": */
|
||||
static const struct state_dependent_clocks dce60_max_clks_by_state[] = {
|
||||
/* ClocksStateInvalid - should not be used */
|
||||
{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
|
||||
/* ClocksStateUltraLow - not expected to be used for DCE 6.0 */
|
||||
{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
|
||||
/* ClocksStateLow */
|
||||
{ .display_clk_khz = 352000, .pixel_clk_khz = 330000},
|
||||
/* ClocksStateNominal */
|
||||
{ .display_clk_khz = 600000, .pixel_clk_khz = 400000 },
|
||||
/* ClocksStatePerformance */
|
||||
{ .display_clk_khz = 600000, .pixel_clk_khz = 400000 } };
|
||||
|
||||
/* Max clock values for each state indexed by "enum clocks_state": */
|
||||
static const struct state_dependent_clocks dce80_max_clks_by_state[] = {
|
||||
/* ClocksStateInvalid - should not be used */
|
||||
{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
|
||||
/* ClocksStateUltraLow - not expected to be used for DCE 8.0 */
|
||||
{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
|
||||
/* ClocksStateLow */
|
||||
{ .display_clk_khz = 352000, .pixel_clk_khz = 330000},
|
||||
/* ClocksStateNominal */
|
||||
{ .display_clk_khz = 625000, .pixel_clk_khz = 400000 },
|
||||
/* ClocksStatePerformance */
|
||||
{ .display_clk_khz = 625000, .pixel_clk_khz = 400000 } };
|
||||
|
||||
unsigned int dentist_get_divider_from_did(unsigned int did)
|
||||
{
|
||||
if (did < DENTIST_BASE_DID_1)
|
||||
|
|
@ -220,40 +194,6 @@ uint32_t dce_get_max_pixel_clock_for_all_paths(struct dc_state *context)
|
|||
return max_pix_clk;
|
||||
}
|
||||
|
||||
enum dm_pp_clocks_state dce_get_required_clocks_state(
|
||||
struct clk_mgr *clk_mgr_base,
|
||||
struct dc_state *context)
|
||||
{
|
||||
struct clk_mgr_internal *clk_mgr_dce = TO_CLK_MGR_INTERNAL(clk_mgr_base);
|
||||
int i;
|
||||
enum dm_pp_clocks_state low_req_clk;
|
||||
int max_pix_clk = dce_get_max_pixel_clock_for_all_paths(context);
|
||||
|
||||
/* Iterate from highest supported to lowest valid state, and update
|
||||
* lowest RequiredState with the lowest state that satisfies
|
||||
* all required clocks
|
||||
*/
|
||||
for (i = clk_mgr_dce->max_clks_state; i >= DM_PP_CLOCKS_STATE_ULTRA_LOW; i--)
|
||||
if (context->bw_ctx.bw.dce.dispclk_khz >
|
||||
clk_mgr_dce->max_clks_by_state[i].display_clk_khz
|
||||
|| max_pix_clk >
|
||||
clk_mgr_dce->max_clks_by_state[i].pixel_clk_khz)
|
||||
break;
|
||||
|
||||
low_req_clk = i + 1;
|
||||
if (low_req_clk > clk_mgr_dce->max_clks_state) {
|
||||
/* set max clock state for high phyclock, invalid on exceeding display clock */
|
||||
if (clk_mgr_dce->max_clks_by_state[clk_mgr_dce->max_clks_state].display_clk_khz
|
||||
< context->bw_ctx.bw.dce.dispclk_khz)
|
||||
low_req_clk = DM_PP_CLOCKS_STATE_INVALID;
|
||||
else
|
||||
low_req_clk = clk_mgr_dce->max_clks_state;
|
||||
}
|
||||
|
||||
return low_req_clk;
|
||||
}
|
||||
|
||||
|
||||
/* TODO: remove use the two broken down functions */
|
||||
int dce_set_clock(
|
||||
struct clk_mgr *clk_mgr_base,
|
||||
|
|
@ -291,11 +231,6 @@ int dce_set_clock(
|
|||
actual_clock = pxl_clk_params.dfs_bypass_display_clock;
|
||||
}
|
||||
|
||||
/* from power down, we need mark the clock state as ClocksStateNominal
|
||||
* from HWReset, so when resume we will call pplib voltage regulator.*/
|
||||
if (requested_clk_khz == 0)
|
||||
clk_mgr_dce->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
|
||||
|
||||
if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu))
|
||||
dmcu->funcs->set_psr_wait_loop(dmcu, actual_clock / 1000 / 7);
|
||||
|
||||
|
|
@ -307,7 +242,6 @@ static void dce_clock_read_integrated_info(struct clk_mgr_internal *clk_mgr_dce)
|
|||
{
|
||||
struct dc_debug_options *debug = &clk_mgr_dce->base.ctx->dc->debug;
|
||||
struct dc_bios *bp = clk_mgr_dce->base.ctx->dc_bios;
|
||||
int i;
|
||||
|
||||
if (bp->integrated_info)
|
||||
clk_mgr_dce->base.dentist_vco_freq_khz = bp->integrated_info->dentist_vco_freq;
|
||||
|
|
@ -317,40 +251,6 @@ static void dce_clock_read_integrated_info(struct clk_mgr_internal *clk_mgr_dce)
|
|||
clk_mgr_dce->base.dentist_vco_freq_khz = 3600000;
|
||||
}
|
||||
|
||||
/*update the maximum display clock for each power state*/
|
||||
for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
|
||||
enum dm_pp_clocks_state clk_state = DM_PP_CLOCKS_STATE_INVALID;
|
||||
|
||||
switch (i) {
|
||||
case 0:
|
||||
clk_state = DM_PP_CLOCKS_STATE_ULTRA_LOW;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
clk_state = DM_PP_CLOCKS_STATE_LOW;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
clk_state = DM_PP_CLOCKS_STATE_NOMINAL;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
clk_state = DM_PP_CLOCKS_STATE_PERFORMANCE;
|
||||
break;
|
||||
|
||||
default:
|
||||
clk_state = DM_PP_CLOCKS_STATE_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
/*Do not allow bad VBIOS/SBIOS to override with invalid values,
|
||||
* check for > 100MHz*/
|
||||
if (bp->integrated_info)
|
||||
if (bp->integrated_info->disp_clk_voltage[i].max_supported_clk >= 100000)
|
||||
clk_mgr_dce->max_clks_by_state[clk_state].display_clk_khz =
|
||||
bp->integrated_info->disp_clk_voltage[i].max_supported_clk;
|
||||
}
|
||||
|
||||
if (!debug->disable_dfs_bypass && bp->integrated_info)
|
||||
if (bp->integrated_info->gpu_cap_info & DFS_BYPASS_ENABLE)
|
||||
clk_mgr_dce->dfs_bypass_enabled = true;
|
||||
|
|
@ -430,20 +330,9 @@ static void dce_update_clocks(struct clk_mgr *clk_mgr_base,
|
|||
struct dc_state *context,
|
||||
bool safe_to_lower)
|
||||
{
|
||||
struct clk_mgr_internal *clk_mgr_dce = TO_CLK_MGR_INTERNAL(clk_mgr_base);
|
||||
struct dm_pp_power_level_change_request level_change_req;
|
||||
const int max_disp_clk =
|
||||
clk_mgr_dce->max_clks_by_state[DM_PP_CLOCKS_STATE_PERFORMANCE].display_clk_khz;
|
||||
const int max_disp_clk = clk_mgr_base->clks.max_supported_dispclk_khz;
|
||||
int patched_disp_clk = MIN(max_disp_clk, context->bw_ctx.bw.dce.dispclk_khz);
|
||||
|
||||
level_change_req.power_level = dce_get_required_clocks_state(clk_mgr_base, context);
|
||||
/* get max clock state from PPLIB */
|
||||
if ((level_change_req.power_level < clk_mgr_dce->cur_min_clks_state && safe_to_lower)
|
||||
|| level_change_req.power_level > clk_mgr_dce->cur_min_clks_state) {
|
||||
if (dm_pp_apply_power_level_change_request(clk_mgr_base->ctx, &level_change_req))
|
||||
clk_mgr_dce->cur_min_clks_state = level_change_req.power_level;
|
||||
}
|
||||
|
||||
if (should_set_clock(safe_to_lower, patched_disp_clk, clk_mgr_base->clks.dispclk_khz)) {
|
||||
patched_disp_clk = dce_set_clock(clk_mgr_base, patched_disp_clk);
|
||||
clk_mgr_base->clks.dispclk_khz = patched_disp_clk;
|
||||
|
|
@ -468,17 +357,6 @@ void dce_clk_mgr_construct(
|
|||
struct clk_mgr_internal *clk_mgr)
|
||||
{
|
||||
struct clk_mgr *base = &clk_mgr->base;
|
||||
struct dm_pp_static_clock_info static_clk_info = {0};
|
||||
|
||||
if (ctx->dce_version <= DCE_VERSION_6_4)
|
||||
memcpy(clk_mgr->max_clks_by_state,
|
||||
dce60_max_clks_by_state,
|
||||
sizeof(dce60_max_clks_by_state));
|
||||
else
|
||||
memcpy(clk_mgr->max_clks_by_state,
|
||||
dce80_max_clks_by_state,
|
||||
sizeof(dce80_max_clks_by_state));
|
||||
|
||||
|
||||
base->ctx = ctx;
|
||||
base->funcs = &dce_funcs;
|
||||
|
|
@ -494,16 +372,16 @@ void dce_clk_mgr_construct(
|
|||
clk_mgr->dprefclk_ss_divider = 1000;
|
||||
clk_mgr->ss_on_dprefclk = false;
|
||||
|
||||
if (ctx->dce_version >= DCE_VERSION_8_0) {
|
||||
if (dm_pp_get_static_clocks(ctx, &static_clk_info))
|
||||
clk_mgr->max_clks_state = static_clk_info.max_clocks_state;
|
||||
else
|
||||
clk_mgr->max_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
|
||||
clk_mgr->cur_min_clks_state = DM_PP_CLOCKS_STATE_INVALID;
|
||||
}
|
||||
|
||||
base->clks.max_supported_dispclk_khz =
|
||||
clk_mgr->max_clks_by_state[DM_PP_CLOCKS_STATE_PERFORMANCE].display_clk_khz;
|
||||
if (ctx->dce_version >= DCE_VERSION_12_0)
|
||||
base->clks.max_supported_dispclk_khz = 1133000;
|
||||
else if (ctx->dce_version >= DCE_VERSION_11_2)
|
||||
base->clks.max_supported_dispclk_khz = 1132000;
|
||||
else if (ctx->dce_version >= DCE_VERSION_11_0)
|
||||
base->clks.max_supported_dispclk_khz = 643000;
|
||||
else if (ctx->dce_version >= DCE_VERSION_8_0)
|
||||
base->clks.max_supported_dispclk_khz = 625000;
|
||||
else
|
||||
base->clks.max_supported_dispclk_khz = 600000;
|
||||
|
||||
dce_clock_read_integrated_info(clk_mgr);
|
||||
dce_clock_read_ss_info(clk_mgr);
|
||||
|
|
|
|||
|
|
@ -32,9 +32,6 @@
|
|||
/* functions shared by other dce clk mgrs */
|
||||
int dce_adjust_dp_ref_freq_for_ss(struct clk_mgr_internal *clk_mgr_dce, int dp_ref_clk_khz);
|
||||
int dce_get_dp_ref_freq_khz(struct clk_mgr *clk_mgr_base);
|
||||
enum dm_pp_clocks_state dce_get_required_clocks_state(
|
||||
struct clk_mgr *clk_mgr_base,
|
||||
struct dc_state *context);
|
||||
|
||||
uint32_t dce_get_max_pixel_clock_for_all_paths(struct dc_state *context);
|
||||
|
||||
|
|
|
|||
|
|
@ -51,18 +51,6 @@ static const struct clk_mgr_mask disp_clk_mask = {
|
|||
CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK)
|
||||
};
|
||||
|
||||
static const struct state_dependent_clocks dce110_max_clks_by_state[] = {
|
||||
/*ClocksStateInvalid - should not be used*/
|
||||
{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
|
||||
/*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
|
||||
{ .display_clk_khz = 352000, .pixel_clk_khz = 330000 },
|
||||
/*ClocksStateLow*/
|
||||
{ .display_clk_khz = 352000, .pixel_clk_khz = 330000 },
|
||||
/*ClocksStateNominal*/
|
||||
{ .display_clk_khz = 467000, .pixel_clk_khz = 400000 },
|
||||
/*ClocksStatePerformance*/
|
||||
{ .display_clk_khz = 643000, .pixel_clk_khz = 400000 } };
|
||||
|
||||
static uint32_t determine_sclk_from_bounding_box(
|
||||
const struct dc *dc,
|
||||
uint32_t required_sclk)
|
||||
|
|
@ -257,21 +245,12 @@ static void dce11_update_clocks(struct clk_mgr *clk_mgr_base,
|
|||
bool safe_to_lower)
|
||||
{
|
||||
struct clk_mgr_internal *clk_mgr_dce = TO_CLK_MGR_INTERNAL(clk_mgr_base);
|
||||
struct dm_pp_power_level_change_request level_change_req;
|
||||
int patched_disp_clk = context->bw_ctx.bw.dce.dispclk_khz;
|
||||
|
||||
/*TODO: W/A for dal3 linux, investigate why this works */
|
||||
if (!clk_mgr_dce->dfs_bypass_active)
|
||||
patched_disp_clk = patched_disp_clk * 115 / 100;
|
||||
|
||||
level_change_req.power_level = dce_get_required_clocks_state(clk_mgr_base, context);
|
||||
/* get max clock state from PPLIB */
|
||||
if ((level_change_req.power_level < clk_mgr_dce->cur_min_clks_state && safe_to_lower)
|
||||
|| level_change_req.power_level > clk_mgr_dce->cur_min_clks_state) {
|
||||
if (dm_pp_apply_power_level_change_request(clk_mgr_base->ctx, &level_change_req))
|
||||
clk_mgr_dce->cur_min_clks_state = level_change_req.power_level;
|
||||
}
|
||||
|
||||
if (should_set_clock(safe_to_lower, patched_disp_clk, clk_mgr_base->clks.dispclk_khz)) {
|
||||
context->bw_ctx.bw.dce.dispclk_khz = dce_set_clock(clk_mgr_base, patched_disp_clk);
|
||||
clk_mgr_base->clks.dispclk_khz = patched_disp_clk;
|
||||
|
|
@ -290,10 +269,6 @@ void dce110_clk_mgr_construct(
|
|||
{
|
||||
dce_clk_mgr_construct(ctx, clk_mgr);
|
||||
|
||||
memcpy(clk_mgr->max_clks_by_state,
|
||||
dce110_max_clks_by_state,
|
||||
sizeof(dce110_max_clks_by_state));
|
||||
|
||||
clk_mgr->regs = &disp_clk_regs;
|
||||
clk_mgr->clk_mgr_shift = &disp_clk_shift;
|
||||
clk_mgr->clk_mgr_mask = &disp_clk_mask;
|
||||
|
|
|
|||
|
|
@ -53,19 +53,6 @@ static const struct clk_mgr_mask disp_clk_mask = {
|
|||
CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK)
|
||||
};
|
||||
|
||||
static const struct state_dependent_clocks dce112_max_clks_by_state[] = {
|
||||
/*ClocksStateInvalid - should not be used*/
|
||||
{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
|
||||
/*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
|
||||
{ .display_clk_khz = 389189, .pixel_clk_khz = 346672 },
|
||||
/*ClocksStateLow*/
|
||||
{ .display_clk_khz = 459000, .pixel_clk_khz = 400000 },
|
||||
/*ClocksStateNominal*/
|
||||
{ .display_clk_khz = 667000, .pixel_clk_khz = 600000 },
|
||||
/*ClocksStatePerformance*/
|
||||
{ .display_clk_khz = 1132000, .pixel_clk_khz = 600000 } };
|
||||
|
||||
|
||||
//TODO: remove use the two broken down functions
|
||||
int dce112_set_clock(struct clk_mgr *clk_mgr_base, int requested_clk_khz)
|
||||
{
|
||||
|
|
@ -89,13 +76,6 @@ int dce112_set_clock(struct clk_mgr *clk_mgr_base, int requested_clk_khz)
|
|||
bp->funcs->set_dce_clock(bp, &dce_clk_params);
|
||||
actual_clock = dce_clk_params.target_clock_frequency;
|
||||
|
||||
/*
|
||||
* from power down, we need mark the clock state as ClocksStateNominal
|
||||
* from HWReset, so when resume we will call pplib voltage regulator.
|
||||
*/
|
||||
if (requested_clk_khz == 0)
|
||||
clk_mgr_dce->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
|
||||
|
||||
/*Program DP ref Clock*/
|
||||
/*VBIOS will determine DPREFCLK frequency, so we don't set it*/
|
||||
dce_clk_params.target_clock_frequency = 0;
|
||||
|
|
@ -143,14 +123,6 @@ int dce112_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_clk_khz)
|
|||
bp->funcs->set_dce_clock(bp, &dce_clk_params);
|
||||
actual_clock = dce_clk_params.target_clock_frequency;
|
||||
|
||||
/*
|
||||
* from power down, we need mark the clock state as ClocksStateNominal
|
||||
* from HWReset, so when resume we will call pplib voltage regulator.
|
||||
*/
|
||||
if (requested_clk_khz == 0)
|
||||
clk_mgr->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
|
||||
|
||||
|
||||
if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) {
|
||||
if (clk_mgr->dfs_bypass_disp_clk != actual_clock)
|
||||
dmcu->funcs->set_psr_wait_loop(dmcu,
|
||||
|
|
@ -193,21 +165,12 @@ static void dce112_update_clocks(struct clk_mgr *clk_mgr_base,
|
|||
bool safe_to_lower)
|
||||
{
|
||||
struct clk_mgr_internal *clk_mgr_dce = TO_CLK_MGR_INTERNAL(clk_mgr_base);
|
||||
struct dm_pp_power_level_change_request level_change_req;
|
||||
int patched_disp_clk = context->bw_ctx.bw.dce.dispclk_khz;
|
||||
|
||||
/*TODO: W/A for dal3 linux, investigate why this works */
|
||||
if (!clk_mgr_dce->dfs_bypass_active)
|
||||
patched_disp_clk = patched_disp_clk * 115 / 100;
|
||||
|
||||
level_change_req.power_level = dce_get_required_clocks_state(clk_mgr_base, context);
|
||||
/* get max clock state from PPLIB */
|
||||
if ((level_change_req.power_level < clk_mgr_dce->cur_min_clks_state && safe_to_lower)
|
||||
|| level_change_req.power_level > clk_mgr_dce->cur_min_clks_state) {
|
||||
if (dm_pp_apply_power_level_change_request(clk_mgr_base->ctx, &level_change_req))
|
||||
clk_mgr_dce->cur_min_clks_state = level_change_req.power_level;
|
||||
}
|
||||
|
||||
if (should_set_clock(safe_to_lower, patched_disp_clk, clk_mgr_base->clks.dispclk_khz)) {
|
||||
patched_disp_clk = dce112_set_clock(clk_mgr_base, patched_disp_clk);
|
||||
clk_mgr_base->clks.dispclk_khz = patched_disp_clk;
|
||||
|
|
@ -226,10 +189,6 @@ void dce112_clk_mgr_construct(
|
|||
{
|
||||
dce_clk_mgr_construct(ctx, clk_mgr);
|
||||
|
||||
memcpy(clk_mgr->max_clks_by_state,
|
||||
dce112_max_clks_by_state,
|
||||
sizeof(dce112_max_clks_by_state));
|
||||
|
||||
clk_mgr->regs = &disp_clk_regs;
|
||||
clk_mgr->clk_mgr_shift = &disp_clk_shift;
|
||||
clk_mgr->clk_mgr_mask = &disp_clk_mask;
|
||||
|
|
|
|||
|
|
@ -32,18 +32,6 @@
|
|||
#include "dce100/dce_clk_mgr.h"
|
||||
#include "dce120/dce120_hwseq.h"
|
||||
|
||||
static const struct state_dependent_clocks dce120_max_clks_by_state[] = {
|
||||
/*ClocksStateInvalid - should not be used*/
|
||||
{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
|
||||
/*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
|
||||
{ .display_clk_khz = 0, .pixel_clk_khz = 0 },
|
||||
/*ClocksStateLow*/
|
||||
{ .display_clk_khz = 460000, .pixel_clk_khz = 400000 },
|
||||
/*ClocksStateNominal*/
|
||||
{ .display_clk_khz = 670000, .pixel_clk_khz = 600000 },
|
||||
/*ClocksStatePerformance*/
|
||||
{ .display_clk_khz = 1133000, .pixel_clk_khz = 600000 } };
|
||||
|
||||
/**
|
||||
* dce121_clock_patch_xgmi_ss_info() - Save XGMI spread spectrum info
|
||||
* @clk_mgr_dce: clock manager internal structure
|
||||
|
|
@ -129,10 +117,6 @@ void dce120_clk_mgr_construct(struct dc_context *ctx, struct clk_mgr_internal *c
|
|||
{
|
||||
dce_clk_mgr_construct(ctx, clk_mgr);
|
||||
|
||||
memcpy(clk_mgr->max_clks_by_state,
|
||||
dce120_max_clks_by_state,
|
||||
sizeof(dce120_max_clks_by_state));
|
||||
|
||||
clk_mgr->base.dprefclk_khz = 600000;
|
||||
clk_mgr->base.funcs = &dce120_funcs;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -272,9 +272,9 @@ char *dc_status_to_str(enum dc_status status)
|
|||
return "Fail DP Tunnel BW validation";
|
||||
case DC_ERROR_UNEXPECTED:
|
||||
return "Unexpected error";
|
||||
default:
|
||||
return "Unexpected status error";
|
||||
}
|
||||
|
||||
return "Unexpected status error";
|
||||
}
|
||||
|
||||
char *dc_pixel_encoding_to_str(enum dc_pixel_encoding pixel_encoding)
|
||||
|
|
|
|||
|
|
@ -105,15 +105,26 @@ static void dccg21_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppcl
|
|||
* dccg2_init() unconditionally overwrites MICROSECOND_TIME_BASE_DIV to
|
||||
* 0x00120264, destroying the marker before it can be read.
|
||||
*
|
||||
* Guard the call: if the S0i3 marker is present, skip dccg2_init() so the
|
||||
* Guard the call: if the S0i3 marker is present, skip init so the
|
||||
* WA can function correctly. bios_golden_init() will handle init in that case.
|
||||
*
|
||||
* DCN21 uses 48MHz refclk, not 100MHz, so we must explicitly set the correct
|
||||
* values (48MHz is taken from rn_clk_mgr_construct()).
|
||||
*/
|
||||
static void dccg21_init(struct dccg *dccg)
|
||||
{
|
||||
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
|
||||
|
||||
if (dccg2_is_s0i3_golden_init_wa_done(dccg))
|
||||
return;
|
||||
|
||||
dccg2_init(dccg);
|
||||
/* 48MHz refclk from rn_clk_mgr_construct() */
|
||||
REG_WRITE(MICROSECOND_TIME_BASE_DIV, 0x00120230);
|
||||
REG_WRITE(MILLISECOND_TIME_BASE_DIV, 0x0010bb80);
|
||||
REG_WRITE(DISPCLK_FREQ_CHANGE_CNTL, 0x0e01003c);
|
||||
|
||||
if (REG(REFCLK_CNTL))
|
||||
REG_WRITE(REFCLK_CNTL, 0);
|
||||
}
|
||||
|
||||
static const struct dccg_funcs dccg21_funcs = {
|
||||
|
|
|
|||
|
|
@ -224,18 +224,10 @@ bool dm_pp_apply_display_requirements(
|
|||
const struct dc_context *ctx,
|
||||
const struct dm_pp_display_configuration *pp_display_cfg);
|
||||
|
||||
bool dm_pp_apply_power_level_change_request(
|
||||
const struct dc_context *ctx,
|
||||
struct dm_pp_power_level_change_request *level_change_req);
|
||||
|
||||
bool dm_pp_apply_clock_for_voltage_request(
|
||||
const struct dc_context *ctx,
|
||||
struct dm_pp_clock_for_voltage_req *clock_for_voltage_req);
|
||||
|
||||
bool dm_pp_get_static_clocks(
|
||||
const struct dc_context *ctx,
|
||||
struct dm_pp_static_clock_info *static_clk_info);
|
||||
|
||||
/****** end of PP interfaces ******/
|
||||
|
||||
struct persistent_data_flag {
|
||||
|
|
|
|||
|
|
@ -36,30 +36,7 @@ struct dm_pp_clock_range {
|
|||
int max_khz;
|
||||
};
|
||||
|
||||
enum dm_pp_clocks_state {
|
||||
DM_PP_CLOCKS_STATE_INVALID,
|
||||
DM_PP_CLOCKS_STATE_ULTRA_LOW,
|
||||
DM_PP_CLOCKS_STATE_LOW,
|
||||
DM_PP_CLOCKS_STATE_NOMINAL,
|
||||
DM_PP_CLOCKS_STATE_PERFORMANCE,
|
||||
|
||||
/* Starting from DCE11, Max 8 levels of DPM state supported. */
|
||||
DM_PP_CLOCKS_DPM_STATE_LEVEL_INVALID = DM_PP_CLOCKS_STATE_INVALID,
|
||||
DM_PP_CLOCKS_DPM_STATE_LEVEL_0,
|
||||
DM_PP_CLOCKS_DPM_STATE_LEVEL_1,
|
||||
DM_PP_CLOCKS_DPM_STATE_LEVEL_2,
|
||||
/* to be backward compatible */
|
||||
DM_PP_CLOCKS_DPM_STATE_LEVEL_3,
|
||||
DM_PP_CLOCKS_DPM_STATE_LEVEL_4,
|
||||
DM_PP_CLOCKS_DPM_STATE_LEVEL_5,
|
||||
DM_PP_CLOCKS_DPM_STATE_LEVEL_6,
|
||||
DM_PP_CLOCKS_DPM_STATE_LEVEL_7,
|
||||
|
||||
DM_PP_CLOCKS_MAX_STATES
|
||||
};
|
||||
|
||||
struct dm_pp_gpu_clock_range {
|
||||
enum dm_pp_clocks_state clock_state;
|
||||
struct dm_pp_clock_range sclk;
|
||||
struct dm_pp_clock_range mclk;
|
||||
struct dm_pp_clock_range eclk;
|
||||
|
|
@ -246,10 +223,6 @@ enum dm_acpi_display_type {
|
|||
AcpiDisplayType_DFP6 = 12
|
||||
};
|
||||
|
||||
struct dm_pp_power_level_change_request {
|
||||
enum dm_pp_clocks_state power_level;
|
||||
};
|
||||
|
||||
struct dm_pp_clock_for_voltage_req {
|
||||
enum dm_pp_clock_type clk_type;
|
||||
uint32_t clocks_in_khz;
|
||||
|
|
@ -258,9 +231,6 @@ struct dm_pp_clock_for_voltage_req {
|
|||
struct dm_pp_static_clock_info {
|
||||
uint32_t max_sclk_khz;
|
||||
uint32_t max_mclk_khz;
|
||||
|
||||
/* max possible display block clocks state */
|
||||
enum dm_pp_clocks_state max_clocks_state;
|
||||
};
|
||||
|
||||
struct dtn_min_clk_info {
|
||||
|
|
|
|||
|
|
@ -405,12 +405,6 @@ enum clock_type {
|
|||
clock_type_dtbclk,
|
||||
};
|
||||
|
||||
|
||||
struct state_dependent_clocks {
|
||||
int display_clk_khz;
|
||||
int pixel_clk_khz;
|
||||
};
|
||||
|
||||
struct clk_mgr_internal {
|
||||
struct clk_mgr base;
|
||||
int smu_ver;
|
||||
|
|
@ -429,8 +423,6 @@ struct clk_mgr_internal {
|
|||
const struct clk_mgr_shift *clk_mgr_shift;
|
||||
const struct clk_mgr_mask *clk_mgr_mask;
|
||||
|
||||
struct state_dependent_clocks max_clks_by_state[DM_PP_CLOCKS_MAX_STATES];
|
||||
|
||||
/*TODO: figure out which of the below fields should be here vs in asic specific portion */
|
||||
/* Cache the status of DFS-bypass feature*/
|
||||
bool dfs_bypass_enabled;
|
||||
|
|
@ -477,8 +469,6 @@ struct clk_mgr_internal {
|
|||
*/
|
||||
int dprefclk_ss_divider;
|
||||
|
||||
enum dm_pp_clocks_state max_clks_state;
|
||||
enum dm_pp_clocks_state cur_min_clks_state;
|
||||
bool periodic_retraining_disabled;
|
||||
|
||||
unsigned int cur_phyclk_req_table[MAX_LINKS];
|
||||
|
|
|
|||
|
|
@ -273,7 +273,6 @@ struct transmitter_configuration {
|
|||
#define NUMBER_OF_UCHAR_FOR_GUID 16
|
||||
#define MAX_NUMBER_OF_EXT_DISPLAY_PATH 7
|
||||
#define NUMBER_OF_CSR_M3_ARB 10
|
||||
#define NUMBER_OF_DISP_CLK_VOLTAGE 4
|
||||
#define NUMBER_OF_AVAILABLE_SCLK 5
|
||||
|
||||
struct i2c_reg_info {
|
||||
|
|
@ -302,14 +301,6 @@ struct edp_info {
|
|||
|
||||
/* V6 */
|
||||
struct integrated_info {
|
||||
struct clock_voltage_caps {
|
||||
/* The Voltage Index indicated by FUSE, same voltage index
|
||||
shared with SCLK DPM fuse table */
|
||||
uint32_t voltage_index;
|
||||
/* Maximum clock supported with specified voltage index */
|
||||
uint32_t max_supported_clk; /* in KHz */
|
||||
} disp_clk_voltage[NUMBER_OF_DISP_CLK_VOLTAGE];
|
||||
|
||||
struct display_connection_info {
|
||||
struct external_display_path {
|
||||
/* A bit vector to show what devices are supported */
|
||||
|
|
|
|||
|
|
@ -113,24 +113,6 @@ struct amd_pp_display_configuration {
|
|||
struct amd_pp_simple_clock_info {
|
||||
uint32_t engine_max_clock;
|
||||
uint32_t memory_max_clock;
|
||||
uint32_t level;
|
||||
};
|
||||
|
||||
enum PP_DAL_POWERLEVEL {
|
||||
PP_DAL_POWERLEVEL_INVALID = 0,
|
||||
PP_DAL_POWERLEVEL_ULTRALOW,
|
||||
PP_DAL_POWERLEVEL_LOW,
|
||||
PP_DAL_POWERLEVEL_NOMINAL,
|
||||
PP_DAL_POWERLEVEL_PERFORMANCE,
|
||||
|
||||
PP_DAL_POWERLEVEL_0 = PP_DAL_POWERLEVEL_ULTRALOW,
|
||||
PP_DAL_POWERLEVEL_1 = PP_DAL_POWERLEVEL_LOW,
|
||||
PP_DAL_POWERLEVEL_2 = PP_DAL_POWERLEVEL_NOMINAL,
|
||||
PP_DAL_POWERLEVEL_3 = PP_DAL_POWERLEVEL_PERFORMANCE,
|
||||
PP_DAL_POWERLEVEL_4 = PP_DAL_POWERLEVEL_3+1,
|
||||
PP_DAL_POWERLEVEL_5 = PP_DAL_POWERLEVEL_4+1,
|
||||
PP_DAL_POWERLEVEL_6 = PP_DAL_POWERLEVEL_5+1,
|
||||
PP_DAL_POWERLEVEL_7 = PP_DAL_POWERLEVEL_6+1,
|
||||
};
|
||||
|
||||
struct amd_pp_clock_info {
|
||||
|
|
@ -142,7 +124,6 @@ struct amd_pp_clock_info {
|
|||
uint32_t max_bus_bandwidth;
|
||||
uint32_t max_engine_clock_in_sr;
|
||||
uint32_t min_engine_clock_in_sr;
|
||||
enum PP_DAL_POWERLEVEL max_clocks_state;
|
||||
};
|
||||
|
||||
enum amd_pp_clock_type {
|
||||
|
|
|
|||
|
|
@ -417,7 +417,7 @@ struct amd_pm_funcs {
|
|||
void (*display_configuration_changed)(void *handle);
|
||||
void (*print_power_state)(void *handle, void *ps);
|
||||
bool (*vblank_too_short)(void *handle);
|
||||
void (*enable_bapm)(void *handle, bool enable);
|
||||
void (*notify_ac_dc)(void *handle);
|
||||
int (*check_state_equal)(void *handle,
|
||||
void *cps,
|
||||
void *rps,
|
||||
|
|
@ -476,8 +476,6 @@ struct amd_pm_funcs {
|
|||
u32 (*get_mclk)(void *handle, bool low);
|
||||
int (*display_configuration_change)(void *handle,
|
||||
const struct amd_pp_display_configuration *input);
|
||||
int (*get_display_power_level)(void *handle,
|
||||
struct amd_pp_simple_clock_info *output);
|
||||
int (*get_current_clocks)(void *handle,
|
||||
struct amd_pp_clock_info *clocks);
|
||||
int (*get_clock_by_type)(void *handle,
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@
|
|||
#include <linux/power_supply.h>
|
||||
#include "amdgpu_smu.h"
|
||||
|
||||
#define amdgpu_dpm_enable_bapm(adev, e) \
|
||||
((adev)->powerplay.pp_funcs->enable_bapm((adev)->powerplay.pp_handle, (e)))
|
||||
#define amdgpu_dpm_notify_ac_dc(adev) \
|
||||
((adev)->powerplay.pp_funcs->notify_ac_dc((adev)->powerplay.pp_handle))
|
||||
|
||||
#define amdgpu_dpm_is_legacy_dpm(adev) ((adev)->powerplay.pp_handle == (adev))
|
||||
|
||||
|
|
@ -504,8 +504,8 @@ void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev)
|
|||
adev->pm.ac_power = false;
|
||||
|
||||
if (adev->powerplay.pp_funcs &&
|
||||
adev->powerplay.pp_funcs->enable_bapm)
|
||||
amdgpu_dpm_enable_bapm(adev, adev->pm.ac_power);
|
||||
adev->powerplay.pp_funcs->notify_ac_dc)
|
||||
amdgpu_dpm_notify_ac_dc(adev);
|
||||
|
||||
if (is_support_sw_smu(adev))
|
||||
smu_set_ac_dc(adev->powerplay.pp_handle);
|
||||
|
|
|
|||
|
|
@ -1233,14 +1233,14 @@ static void kv_update_requested_ps(struct amdgpu_device *adev,
|
|||
adev->pm.dpm.requested_ps = &pi->requested_rps;
|
||||
}
|
||||
|
||||
static void kv_dpm_enable_bapm(void *handle, bool enable)
|
||||
static void kv_dpm_enable_bapm(void *handle)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
struct kv_power_info *pi = kv_get_pi(adev);
|
||||
int ret;
|
||||
|
||||
if (pi->bapm_enable) {
|
||||
ret = amdgpu_kv_smc_bapm_enable(adev, enable);
|
||||
ret = amdgpu_kv_smc_bapm_enable(adev, adev->pm.ac_power);
|
||||
if (ret)
|
||||
drm_err(adev_to_drm(adev), "amdgpu_kv_smc_bapm_enable failed\n");
|
||||
}
|
||||
|
|
@ -3341,7 +3341,7 @@ static const struct amd_pm_funcs kv_dpm_funcs = {
|
|||
.debugfs_print_current_performance_level = &kv_dpm_debugfs_print_current_performance_level,
|
||||
.force_performance_level = &kv_dpm_force_performance_level,
|
||||
.set_powergating_by_smu = kv_set_powergating_by_smu,
|
||||
.enable_bapm = &kv_dpm_enable_bapm,
|
||||
.notify_ac_dc = &kv_dpm_enable_bapm,
|
||||
.get_vce_clock_state = amdgpu_get_vce_clock_state,
|
||||
.check_state_equal = kv_check_state_equal,
|
||||
.read_sensor = &kv_dpm_read_sensor,
|
||||
|
|
|
|||
|
|
@ -3076,6 +3076,10 @@ static bool si_dpm_vblank_too_short(void *handle)
|
|||
/* we never hit the non-gddr5 limit so disable it */
|
||||
u32 switch_limit = adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5 ? 450 : 0;
|
||||
|
||||
/* Disregard vblank time when there are no displays connected */
|
||||
if (!adev->pm.pm_display_cfg.num_display)
|
||||
return false;
|
||||
|
||||
/* Consider zero vblank time too short and disable MCLK switching.
|
||||
* Note that the vblank time is set to maximum when no displays are attached,
|
||||
* so we'll still enable MCLK switching in that case.
|
||||
|
|
@ -3884,16 +3888,18 @@ static void si_notify_hardware_vpu_recovery_event(struct amdgpu_device *adev)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
static int si_notify_hw_of_powersource(struct amdgpu_device *adev, bool ac_power)
|
||||
static void si_notify_hw_of_powersource(void *handle)
|
||||
{
|
||||
if (ac_power)
|
||||
return (amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_RunningOnAC) == PPSMC_Result_OK) ?
|
||||
0 : -EINVAL;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
return 0;
|
||||
/* Check if the platform already manages the AC/DC switch via dedicated GPIO. */
|
||||
if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC)
|
||||
return;
|
||||
|
||||
/* The SMU automatically notices DC, but needs to be notified when switching to AC. */
|
||||
if (adev->pm.ac_power)
|
||||
amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_RunningOnAC);
|
||||
}
|
||||
#endif
|
||||
|
||||
static PPSMC_Result si_send_msg_to_smc_with_parameter(struct amdgpu_device *adev,
|
||||
PPSMC_Msg msg, u32 parameter)
|
||||
|
|
@ -7236,6 +7242,7 @@ static void si_parse_pplib_clock_info(struct amdgpu_device *adev,
|
|||
struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
|
||||
struct si_power_info *si_pi = si_get_pi(adev);
|
||||
struct si_ps *ps = si_get_ps(rps);
|
||||
struct amdgpu_clock_and_voltage_limits *limits;
|
||||
u16 leakage_voltage;
|
||||
struct rv7xx_pl *pl = &ps->performance_levels[index];
|
||||
int ret;
|
||||
|
|
@ -7295,12 +7302,30 @@ static void si_parse_pplib_clock_info(struct amdgpu_device *adev,
|
|||
si_pi->mvdd_bootup_value = mvdd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update maximum allowed clock limits.
|
||||
* VBIOS can contain conflicting values between:
|
||||
* - the maximum allowed clocks and voltages on AC or DC
|
||||
* - the clocks and voltages in power states on AC or DC
|
||||
*/
|
||||
if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) ==
|
||||
ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) {
|
||||
adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk = pl->sclk;
|
||||
adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.mclk = pl->mclk;
|
||||
adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddc = pl->vddc;
|
||||
adev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddci = pl->vddci;
|
||||
ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE)
|
||||
limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
|
||||
else if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) ==
|
||||
ATOM_PPLIB_CLASSIFICATION_UI_BATTERY)
|
||||
limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
|
||||
else
|
||||
limits = NULL;
|
||||
|
||||
if (limits) {
|
||||
if (pl->sclk > limits->sclk)
|
||||
limits->sclk = pl->sclk;
|
||||
if (pl->mclk > limits->mclk)
|
||||
limits->mclk = pl->mclk;
|
||||
if (pl->vddc > limits->vddc)
|
||||
limits->vddc = pl->vddc;
|
||||
if (pl->vddci > limits->vddci)
|
||||
limits->vddci = pl->vddci;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -8140,6 +8165,7 @@ static const struct amd_pm_funcs si_dpm_funcs = {
|
|||
.get_vce_clock_state = amdgpu_get_vce_clock_state,
|
||||
.read_sensor = &si_dpm_read_sensor,
|
||||
.pm_compute_clocks = amdgpu_legacy_dpm_compute_clocks,
|
||||
.notify_ac_dc = si_notify_hw_of_powersource,
|
||||
};
|
||||
|
||||
static const struct amdgpu_irq_src_funcs si_dpm_irq_funcs = {
|
||||
|
|
|
|||
|
|
@ -1020,21 +1020,9 @@ static int pp_display_configuration_change(void *handle,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int pp_get_display_power_level(void *handle,
|
||||
struct amd_pp_simple_clock_info *output)
|
||||
{
|
||||
struct pp_hwmgr *hwmgr = handle;
|
||||
|
||||
if (!hwmgr || !hwmgr->pm_en || !output)
|
||||
return -EINVAL;
|
||||
|
||||
return phm_get_dal_power_level(hwmgr, output);
|
||||
}
|
||||
|
||||
static int pp_get_current_clocks(void *handle,
|
||||
struct amd_pp_clock_info *clocks)
|
||||
{
|
||||
struct amd_pp_simple_clock_info simple_clocks = { 0 };
|
||||
struct pp_clock_info hw_clocks;
|
||||
struct pp_hwmgr *hwmgr = handle;
|
||||
int ret = 0;
|
||||
|
|
@ -1042,8 +1030,6 @@ static int pp_get_current_clocks(void *handle,
|
|||
if (!hwmgr || !hwmgr->pm_en)
|
||||
return -EINVAL;
|
||||
|
||||
phm_get_dal_power_level(hwmgr, &simple_clocks);
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_PowerContainment))
|
||||
ret = phm_get_clock_info(hwmgr, &hwmgr->current_ps->hardware,
|
||||
|
|
@ -1068,11 +1054,6 @@ static int pp_get_current_clocks(void *handle,
|
|||
clocks->max_engine_clock_in_sr = hw_clocks.max_eng_clk;
|
||||
clocks->min_engine_clock_in_sr = hw_clocks.min_eng_clk;
|
||||
|
||||
if (simple_clocks.level == 0)
|
||||
clocks->max_clocks_state = PP_DAL_POWERLEVEL_7;
|
||||
else
|
||||
clocks->max_clocks_state = simple_clocks.level;
|
||||
|
||||
if (0 == phm_get_current_shallow_sleep_clocks(hwmgr, &hwmgr->current_ps->hardware, &hw_clocks)) {
|
||||
clocks->max_engine_clock_in_sr = hw_clocks.max_eng_clk;
|
||||
clocks->min_engine_clock_in_sr = hw_clocks.min_eng_clk;
|
||||
|
|
@ -1149,8 +1130,6 @@ static int pp_get_display_mode_validation_clocks(void *handle,
|
|||
if (!hwmgr || !hwmgr->pm_en || !clocks)
|
||||
return -EINVAL;
|
||||
|
||||
clocks->level = PP_DAL_POWERLEVEL_7;
|
||||
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DynamicPatchPowerState))
|
||||
ret = phm_get_max_high_clocks(hwmgr, clocks);
|
||||
|
||||
|
|
@ -1550,6 +1529,17 @@ static void pp_pm_compute_clocks(void *handle)
|
|||
NULL);
|
||||
}
|
||||
|
||||
static void pp_dpm_notify_ac_dc(void *handle)
|
||||
{
|
||||
struct pp_hwmgr *hwmgr = handle;
|
||||
|
||||
if (!hwmgr || !hwmgr->pm_en)
|
||||
return;
|
||||
|
||||
if (hwmgr->hwmgr_func->notify_ac_dc)
|
||||
hwmgr->hwmgr_func->notify_ac_dc(hwmgr);
|
||||
}
|
||||
|
||||
static const struct amd_pm_funcs pp_dpm_funcs = {
|
||||
.load_firmware = pp_dpm_load_fw,
|
||||
.wait_for_fw_loading_complete = pp_dpm_fw_loading_complete,
|
||||
|
|
@ -1588,7 +1578,6 @@ static const struct amd_pm_funcs pp_dpm_funcs = {
|
|||
.get_sclk = pp_dpm_get_sclk,
|
||||
.get_mclk = pp_dpm_get_mclk,
|
||||
.display_configuration_change = pp_display_configuration_change,
|
||||
.get_display_power_level = pp_get_display_power_level,
|
||||
.get_current_clocks = pp_get_current_clocks,
|
||||
.get_clock_by_type = pp_get_clock_by_type,
|
||||
.get_clock_by_type_with_latency = pp_get_clock_by_type_with_latency,
|
||||
|
|
@ -1615,4 +1604,5 @@ static const struct amd_pm_funcs pp_dpm_funcs = {
|
|||
.gfx_state_change_set = pp_gfx_state_change_set,
|
||||
.get_smu_prv_buf_details = pp_get_prv_buffer_details,
|
||||
.pm_compute_clocks = pp_pm_compute_clocks,
|
||||
.notify_ac_dc = pp_dpm_notify_ac_dc,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -328,16 +328,6 @@ int phm_store_dal_configuration_data(struct pp_hwmgr *hwmgr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int phm_get_dal_power_level(struct pp_hwmgr *hwmgr,
|
||||
struct amd_pp_simple_clock_info *info)
|
||||
{
|
||||
PHM_FUNC_CHECK(hwmgr);
|
||||
|
||||
if (info == NULL || hwmgr->hwmgr_func->get_dal_power_level == NULL)
|
||||
return -EINVAL;
|
||||
return hwmgr->hwmgr_func->get_dal_power_level(hwmgr, info);
|
||||
}
|
||||
|
||||
int phm_set_cpu_power_state(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
PHM_FUNC_CHECK(hwmgr);
|
||||
|
|
|
|||
|
|
@ -1319,7 +1319,6 @@ static int init_clock_voltage_dependency(struct pp_hwmgr *hwmgr,
|
|||
hwmgr->dyn_state.vddc_dependency_on_sclk = NULL;
|
||||
hwmgr->dyn_state.vddci_dependency_on_mclk = NULL;
|
||||
hwmgr->dyn_state.vddc_dependency_on_mclk = NULL;
|
||||
hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
|
||||
hwmgr->dyn_state.mvdd_dependency_on_mclk = NULL;
|
||||
hwmgr->dyn_state.vce_clock_voltage_dependency_table = NULL;
|
||||
hwmgr->dyn_state.uvd_clock_voltage_dependency_table = NULL;
|
||||
|
|
|
|||
|
|
@ -127,41 +127,6 @@ static int smu10_construct_max_power_limits_table(struct pp_hwmgr *hwmgr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int smu10_init_dynamic_state_adjustment_rule_settings(
|
||||
struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int count = 8;
|
||||
struct phm_clock_voltage_dependency_table *table_clk_vlt;
|
||||
|
||||
table_clk_vlt = kzalloc_flex(*table_clk_vlt, entries, count);
|
||||
|
||||
if (NULL == table_clk_vlt) {
|
||||
pr_err("Can not allocate memory!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
table_clk_vlt->count = count;
|
||||
table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_0;
|
||||
table_clk_vlt->entries[0].v = 0;
|
||||
table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_1;
|
||||
table_clk_vlt->entries[1].v = 1;
|
||||
table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_2;
|
||||
table_clk_vlt->entries[2].v = 2;
|
||||
table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_3;
|
||||
table_clk_vlt->entries[3].v = 3;
|
||||
table_clk_vlt->entries[4].clk = PP_DAL_POWERLEVEL_4;
|
||||
table_clk_vlt->entries[4].v = 4;
|
||||
table_clk_vlt->entries[5].clk = PP_DAL_POWERLEVEL_5;
|
||||
table_clk_vlt->entries[5].v = 5;
|
||||
table_clk_vlt->entries[6].clk = PP_DAL_POWERLEVEL_6;
|
||||
table_clk_vlt->entries[6].v = 6;
|
||||
table_clk_vlt->entries[7].clk = PP_DAL_POWERLEVEL_7;
|
||||
table_clk_vlt->entries[7].v = 7;
|
||||
hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smu10_get_system_info_data(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)hwmgr->backend;
|
||||
|
|
@ -175,8 +140,6 @@ static int smu10_get_system_info_data(struct pp_hwmgr *hwmgr)
|
|||
smu10_construct_max_power_limits_table (hwmgr,
|
||||
&hwmgr->dyn_state.max_clock_voltage_on_ac);
|
||||
|
||||
smu10_init_dynamic_state_adjustment_rule_settings(hwmgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -611,9 +574,6 @@ static int smu10_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
|
|||
kfree(pinfo->vdd_dep_on_phyclk);
|
||||
pinfo->vdd_dep_on_phyclk = NULL;
|
||||
|
||||
kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl);
|
||||
hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
|
||||
|
||||
kfree(hwmgr->backend);
|
||||
hwmgr->backend = NULL;
|
||||
|
||||
|
|
@ -962,12 +922,6 @@ static int smu10_store_cc6_data(struct pp_hwmgr *hwmgr, uint32_t separation_time
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int smu10_get_dal_power_level(struct pp_hwmgr *hwmgr,
|
||||
struct amd_pp_simple_clock_info *info)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int smu10_force_clock_level(struct pp_hwmgr *hwmgr,
|
||||
enum pp_clock_type type, uint32_t mask)
|
||||
{
|
||||
|
|
@ -1663,7 +1617,6 @@ static const struct pp_hwmgr_func smu10_hwmgr_funcs = {
|
|||
.store_cc6_data = smu10_store_cc6_data,
|
||||
.force_clock_level = smu10_force_clock_level,
|
||||
.emit_clock_levels = smu10_emit_clock_levels,
|
||||
.get_dal_power_level = smu10_get_dal_power_level,
|
||||
.get_performance_level = smu10_get_performance_level,
|
||||
.get_current_shallow_sleep_clocks = smu10_get_current_shallow_sleep_clocks,
|
||||
.get_clock_by_type_with_latency = smu10_get_clock_by_type_with_latency,
|
||||
|
|
|
|||
|
|
@ -5854,6 +5854,20 @@ static int smu7_power_off_asic(struct pp_hwmgr *hwmgr)
|
|||
return result;
|
||||
}
|
||||
|
||||
static void smu7_notify_ac_dc(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
|
||||
|
||||
/* Check if the platform already manages the AC/DC switch via dedicated GPIO. */
|
||||
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
||||
PHM_PlatformCaps_AutomaticDCTransition))
|
||||
return;
|
||||
|
||||
/* The SMU automatically notices DC, but needs to be notified when switching to AC. */
|
||||
if (adev->pm.ac_power)
|
||||
smum_send_msg_to_smc(hwmgr, PPSMC_MSG_RunningOnAC, NULL);
|
||||
}
|
||||
|
||||
static const struct pp_hwmgr_func smu7_hwmgr_funcs = {
|
||||
.backend_init = &smu7_hwmgr_backend_init,
|
||||
.backend_fini = &smu7_hwmgr_backend_fini,
|
||||
|
|
@ -5916,6 +5930,7 @@ static const struct pp_hwmgr_func smu7_hwmgr_funcs = {
|
|||
.get_asic_baco_state = smu7_baco_get_state,
|
||||
.set_asic_baco_state = smu7_baco_set_state,
|
||||
.power_off_asic = smu7_power_off_asic,
|
||||
.notify_ac_dc = smu7_notify_ac_dc,
|
||||
};
|
||||
|
||||
uint8_t smu7_get_sleep_divider_id_from_clock(uint32_t clock,
|
||||
|
|
|
|||
|
|
@ -270,41 +270,6 @@ static int smu8_construct_max_power_limits_table(struct pp_hwmgr *hwmgr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int smu8_init_dynamic_state_adjustment_rule_settings(
|
||||
struct pp_hwmgr *hwmgr,
|
||||
ATOM_CLK_VOLT_CAPABILITY *disp_voltage_table)
|
||||
{
|
||||
struct phm_clock_voltage_dependency_table *table_clk_vlt;
|
||||
|
||||
table_clk_vlt = kzalloc_flex(*table_clk_vlt, entries, 8);
|
||||
|
||||
if (NULL == table_clk_vlt) {
|
||||
pr_err("Can not allocate memory!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
table_clk_vlt->count = 8;
|
||||
table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_0;
|
||||
table_clk_vlt->entries[0].v = 0;
|
||||
table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_1;
|
||||
table_clk_vlt->entries[1].v = 1;
|
||||
table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_2;
|
||||
table_clk_vlt->entries[2].v = 2;
|
||||
table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_3;
|
||||
table_clk_vlt->entries[3].v = 3;
|
||||
table_clk_vlt->entries[4].clk = PP_DAL_POWERLEVEL_4;
|
||||
table_clk_vlt->entries[4].v = 4;
|
||||
table_clk_vlt->entries[5].clk = PP_DAL_POWERLEVEL_5;
|
||||
table_clk_vlt->entries[5].v = 5;
|
||||
table_clk_vlt->entries[6].clk = PP_DAL_POWERLEVEL_6;
|
||||
table_clk_vlt->entries[6].v = 6;
|
||||
table_clk_vlt->entries[7].clk = PP_DAL_POWERLEVEL_7;
|
||||
table_clk_vlt->entries[7].v = 7;
|
||||
hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smu8_get_system_info_data(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
struct smu8_hwmgr *data = hwmgr->backend;
|
||||
|
|
@ -403,9 +368,6 @@ static int smu8_get_system_info_data(struct pp_hwmgr *hwmgr)
|
|||
smu8_construct_max_power_limits_table (hwmgr,
|
||||
&hwmgr->dyn_state.max_clock_voltage_on_ac);
|
||||
|
||||
smu8_init_dynamic_state_adjustment_rule_settings(hwmgr,
|
||||
&info->sDISPCLK_Voltage[0]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -1149,9 +1111,6 @@ static int smu8_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
|
|||
static int smu8_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
if (hwmgr != NULL) {
|
||||
kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl);
|
||||
hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
|
||||
|
||||
kfree(hwmgr->backend);
|
||||
hwmgr->backend = NULL;
|
||||
}
|
||||
|
|
@ -1521,27 +1480,6 @@ static int smu8_store_cc6_data(struct pp_hwmgr *hwmgr, uint32_t separation_time,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int smu8_get_dal_power_level(struct pp_hwmgr *hwmgr,
|
||||
struct amd_pp_simple_clock_info *info)
|
||||
{
|
||||
uint32_t i;
|
||||
const struct phm_clock_voltage_dependency_table *table =
|
||||
hwmgr->dyn_state.vddc_dep_on_dal_pwrl;
|
||||
const struct phm_clock_and_voltage_limits *limits =
|
||||
&hwmgr->dyn_state.max_clock_voltage_on_ac;
|
||||
|
||||
info->engine_max_clock = limits->sclk;
|
||||
info->memory_max_clock = limits->mclk;
|
||||
|
||||
for (i = table->count - 1; i > 0; i--) {
|
||||
if (limits->vddc >= table->entries[i].v) {
|
||||
info->level = table->entries[i].clk;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int smu8_force_clock_level(struct pp_hwmgr *hwmgr,
|
||||
enum pp_clock_type type, uint32_t mask)
|
||||
{
|
||||
|
|
@ -2062,7 +2000,6 @@ static const struct pp_hwmgr_func smu8_hwmgr_funcs = {
|
|||
.store_cc6_data = smu8_store_cc6_data,
|
||||
.force_clock_level = smu8_force_clock_level,
|
||||
.emit_clock_levels = smu8_emit_clock_levels,
|
||||
.get_dal_power_level = smu8_get_dal_power_level,
|
||||
.get_performance_level = smu8_get_performance_level,
|
||||
.get_current_shallow_sleep_clocks = smu8_get_current_shallow_sleep_clocks,
|
||||
.get_clock_by_type = smu8_get_clock_by_type,
|
||||
|
|
|
|||
|
|
@ -814,9 +814,6 @@ static int vega10_set_private_data_based_on_pptable(struct pp_hwmgr *hwmgr)
|
|||
|
||||
static int vega10_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl);
|
||||
hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
|
||||
|
||||
kfree(hwmgr->backend);
|
||||
hwmgr->backend = NULL;
|
||||
|
||||
|
|
@ -4386,20 +4383,6 @@ static uint32_t vega10_get_fan_control_mode(struct pp_hwmgr *hwmgr)
|
|||
return AMD_FAN_CTRL_AUTO;
|
||||
}
|
||||
|
||||
static int vega10_get_dal_power_level(struct pp_hwmgr *hwmgr,
|
||||
struct amd_pp_simple_clock_info *info)
|
||||
{
|
||||
struct phm_ppt_v2_information *table_info =
|
||||
(struct phm_ppt_v2_information *)hwmgr->pptable;
|
||||
struct phm_clock_and_voltage_limits *max_limits =
|
||||
&table_info->max_clock_voltage_on_ac;
|
||||
|
||||
info->engine_max_clock = max_limits->sclk;
|
||||
info->memory_max_clock = max_limits->mclk;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vega10_get_sclks(struct pp_hwmgr *hwmgr,
|
||||
struct pp_clock_levels_with_latency *clocks)
|
||||
{
|
||||
|
|
@ -5644,7 +5627,6 @@ static const struct pp_hwmgr_func vega10_hwmgr_funcs = {
|
|||
.set_fan_control_mode = vega10_set_fan_control_mode,
|
||||
.get_fan_control_mode = vega10_get_fan_control_mode,
|
||||
.read_sensor = vega10_read_sensor,
|
||||
.get_dal_power_level = vega10_get_dal_power_level,
|
||||
.get_clock_by_type_with_latency = vega10_get_clock_by_type_with_latency,
|
||||
.get_clock_by_type_with_voltage = vega10_get_clock_by_type_with_voltage,
|
||||
.set_watermarks_for_clocks_ranges = vega10_set_watermarks_for_clocks_ranges,
|
||||
|
|
|
|||
|
|
@ -1822,21 +1822,6 @@ static uint32_t vega12_get_fan_control_mode(struct pp_hwmgr *hwmgr)
|
|||
return AMD_FAN_CTRL_AUTO;
|
||||
}
|
||||
|
||||
static int vega12_get_dal_power_level(struct pp_hwmgr *hwmgr,
|
||||
struct amd_pp_simple_clock_info *info)
|
||||
{
|
||||
#if 0
|
||||
struct phm_ppt_v2_information *table_info =
|
||||
(struct phm_ppt_v2_information *)hwmgr->pptable;
|
||||
struct phm_clock_and_voltage_limits *max_limits =
|
||||
&table_info->max_clock_voltage_on_ac;
|
||||
|
||||
info->engine_max_clock = max_limits->sclk;
|
||||
info->memory_max_clock = max_limits->mclk;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vega12_get_clock_ranges(struct pp_hwmgr *hwmgr,
|
||||
uint32_t *clock,
|
||||
PPCLK_e clock_select,
|
||||
|
|
@ -2963,7 +2948,6 @@ static const struct pp_hwmgr_func vega12_hwmgr_funcs = {
|
|||
.set_fan_control_mode = vega12_set_fan_control_mode,
|
||||
.get_fan_control_mode = vega12_get_fan_control_mode,
|
||||
.read_sensor = vega12_read_sensor,
|
||||
.get_dal_power_level = vega12_get_dal_power_level,
|
||||
.get_clock_by_type_with_latency = vega12_get_clock_by_type_with_latency,
|
||||
.get_clock_by_type_with_voltage = vega12_get_clock_by_type_with_voltage,
|
||||
.set_watermarks_for_clocks_ranges = vega12_set_watermarks_for_clocks_ranges,
|
||||
|
|
|
|||
|
|
@ -2796,22 +2796,6 @@ static void vega20_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
|
|||
}
|
||||
}
|
||||
|
||||
static int vega20_get_dal_power_level(struct pp_hwmgr *hwmgr,
|
||||
struct amd_pp_simple_clock_info *info)
|
||||
{
|
||||
#if 0
|
||||
struct phm_ppt_v2_information *table_info =
|
||||
(struct phm_ppt_v2_information *)hwmgr->pptable;
|
||||
struct phm_clock_and_voltage_limits *max_limits =
|
||||
&table_info->max_clock_voltage_on_ac;
|
||||
|
||||
info->engine_max_clock = max_limits->sclk;
|
||||
info->memory_max_clock = max_limits->mclk;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int vega20_get_sclks(struct pp_hwmgr *hwmgr,
|
||||
struct pp_clock_levels_with_latency *clocks)
|
||||
{
|
||||
|
|
@ -4446,7 +4430,6 @@ static const struct pp_hwmgr_func vega20_hwmgr_funcs = {
|
|||
/* export to DAL */
|
||||
.get_sclk = vega20_dpm_get_sclk,
|
||||
.get_mclk = vega20_dpm_get_mclk,
|
||||
.get_dal_power_level = vega20_get_dal_power_level,
|
||||
.get_clock_by_type_with_latency = vega20_get_clock_by_type_with_latency,
|
||||
.get_clock_by_type_with_voltage = vega20_get_clock_by_type_with_voltage,
|
||||
.set_watermarks_for_clocks_ranges = vega20_set_watermarks_for_clocks_ranges,
|
||||
|
|
|
|||
|
|
@ -426,9 +426,6 @@ extern int phm_check_states_equal(struct pp_hwmgr *hwmgr,
|
|||
extern int phm_store_dal_configuration_data(struct pp_hwmgr *hwmgr,
|
||||
const struct amd_pp_display_configuration *display_config);
|
||||
|
||||
extern int phm_get_dal_power_level(struct pp_hwmgr *hwmgr,
|
||||
struct amd_pp_simple_clock_info *info);
|
||||
|
||||
extern int phm_set_cpu_power_state(struct pp_hwmgr *hwmgr);
|
||||
|
||||
extern int phm_power_down_asic(struct pp_hwmgr *hwmgr);
|
||||
|
|
|
|||
|
|
@ -292,8 +292,6 @@ struct pp_hwmgr_func {
|
|||
int (*store_cc6_data)(struct pp_hwmgr *hwmgr, uint32_t separation_time,
|
||||
bool cc6_disable, bool pstate_disable,
|
||||
bool pstate_switch_disable);
|
||||
int (*get_dal_power_level)(struct pp_hwmgr *hwmgr,
|
||||
struct amd_pp_simple_clock_info *info);
|
||||
int (*get_performance_level)(struct pp_hwmgr *, const struct pp_hw_power_state *,
|
||||
PHM_PerformanceLevelDesignation, uint32_t, PHM_PerformanceLevel *);
|
||||
int (*get_current_shallow_sleep_clocks)(struct pp_hwmgr *hwmgr,
|
||||
|
|
@ -364,6 +362,7 @@ struct pp_hwmgr_func {
|
|||
bool disable);
|
||||
ssize_t (*get_gpu_metrics)(struct pp_hwmgr *hwmgr, void **table);
|
||||
int (*gfx_state_change)(struct pp_hwmgr *hwmgr, uint32_t state);
|
||||
void (*notify_ac_dc)(struct pp_hwmgr *hwmgr);
|
||||
};
|
||||
|
||||
struct pp_table_func {
|
||||
|
|
@ -540,7 +539,6 @@ struct phm_ppt_v1_information {
|
|||
struct phm_clock_array *valid_dcefclk_values;
|
||||
struct phm_clock_and_voltage_limits max_clock_voltage_on_dc;
|
||||
struct phm_clock_and_voltage_limits max_clock_voltage_on_ac;
|
||||
struct phm_clock_voltage_dependency_table *vddc_dep_on_dal_pwrl;
|
||||
struct phm_ppm_table *ppm_parameter_table;
|
||||
struct phm_cac_tdp_table *cac_dtp_table;
|
||||
struct phm_tdp_table *tdp_table;
|
||||
|
|
@ -632,7 +630,6 @@ struct phm_dynamic_state_info {
|
|||
struct phm_clock_voltage_dependency_table *vddc_dependency_on_mclk;
|
||||
struct phm_clock_voltage_dependency_table *mvdd_dependency_on_mclk;
|
||||
struct phm_clock_voltage_dependency_table *vddc_dependency_on_display_clock;
|
||||
struct phm_clock_voltage_dependency_table *vddc_dep_on_dal_pwrl;
|
||||
struct phm_clock_array *valid_sclk_values;
|
||||
struct phm_clock_array *valid_mclk_values;
|
||||
struct phm_clock_and_voltage_limits max_clock_voltage_on_dc;
|
||||
|
|
|
|||
|
|
@ -108,15 +108,19 @@ static int amdgpu_virt_ras_remote_ioctl_cmd(struct ras_core_context *ras_core,
|
|||
ret = amdgpu_virt_send_remote_ras_cmd(ras_core->dev,
|
||||
shared_mem.gpa, mem_len);
|
||||
if (!ret) {
|
||||
if (rcmd->cmd_res) {
|
||||
ret = rcmd->cmd_res;
|
||||
uint32_t cmd_res = READ_ONCE(rcmd->cmd_res);
|
||||
uint32_t osz;
|
||||
|
||||
if (cmd_res) {
|
||||
ret = cmd_res;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cmd->cmd_res = rcmd->cmd_res;
|
||||
cmd->output_size = rcmd->output_size;
|
||||
if (rcmd->output_size && (rcmd->output_size <= output_size) && output_data)
|
||||
memcpy(output_data, rcmd->output_buff_raw, rcmd->output_size);
|
||||
osz = READ_ONCE(rcmd->output_size);
|
||||
cmd->cmd_res = cmd_res;
|
||||
cmd->output_size = osz;
|
||||
if (osz && osz <= output_size && output_data)
|
||||
memcpy(output_data, rcmd->output_buff_raw, osz);
|
||||
}
|
||||
|
||||
out:
|
||||
|
|
|
|||
|
|
@ -46,6 +46,15 @@
|
|||
printk(KERN_WARNING fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define RAS_DEV_WARN_RATELIMITED(device, fmt, ...) \
|
||||
do { \
|
||||
if (device) \
|
||||
dev_warn_ratelimited(((struct amdgpu_device *)device)->dev, \
|
||||
fmt, ##__VA_ARGS__); \
|
||||
else \
|
||||
printk_ratelimited(KERN_WARNING fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define RAS_DEV_INFO(device, fmt, ...) \
|
||||
do { \
|
||||
if (device) \
|
||||
|
|
|
|||
|
|
@ -193,12 +193,29 @@ static void ras_umc_reserve_eeprom_record(struct ras_core_context *ras_core,
|
|||
}
|
||||
|
||||
/* When gpu reset is ongoing, ecc logging operations will be pended.
|
||||
*
|
||||
* The pending list is bounded by RAS_UMC_PENDING_ECC_MAX so that an ECC
|
||||
* storm or repeated UMC error injection cannot make this list (and the
|
||||
* kernel allocations behind it) grow without bound. Once the limit is
|
||||
* reached, additional events are dropped and counted in
|
||||
* pending_ecc_dropped, with a rate-limited warning emitted.
|
||||
*/
|
||||
int ras_umc_log_bad_bank_pending(struct ras_core_context *ras_core, struct ras_bank_ecc *bank)
|
||||
{
|
||||
struct ras_umc *ras_umc = &ras_core->ras_umc;
|
||||
struct ras_bank_ecc_node *ecc_node;
|
||||
|
||||
mutex_lock(&ras_umc->pending_ecc_lock);
|
||||
if (ras_umc->pending_ecc_count >= RAS_UMC_PENDING_ECC_MAX) {
|
||||
ras_umc->pending_ecc_dropped++;
|
||||
mutex_unlock(&ras_umc->pending_ecc_lock);
|
||||
RAS_DEV_WARN_RATELIMITED(ras_core->dev,
|
||||
"pending ECC list full (%u), dropping bad bank event (total dropped:%u)\n",
|
||||
RAS_UMC_PENDING_ECC_MAX, ras_umc->pending_ecc_dropped);
|
||||
return -ENOSPC;
|
||||
}
|
||||
mutex_unlock(&ras_umc->pending_ecc_lock);
|
||||
|
||||
ecc_node = kzalloc_obj(*ecc_node);
|
||||
if (!ecc_node)
|
||||
return -ENOMEM;
|
||||
|
|
@ -206,7 +223,15 @@ int ras_umc_log_bad_bank_pending(struct ras_core_context *ras_core, struct ras_b
|
|||
memcpy(&ecc_node->ecc, bank, sizeof(ecc_node->ecc));
|
||||
|
||||
mutex_lock(&ras_umc->pending_ecc_lock);
|
||||
/* re-check under the lock to honor the cap across concurrent callers */
|
||||
if (ras_umc->pending_ecc_count >= RAS_UMC_PENDING_ECC_MAX) {
|
||||
ras_umc->pending_ecc_dropped++;
|
||||
mutex_unlock(&ras_umc->pending_ecc_lock);
|
||||
kfree(ecc_node);
|
||||
return -ENOSPC;
|
||||
}
|
||||
list_add_tail(&ecc_node->node, &ras_umc->pending_ecc_list);
|
||||
ras_umc->pending_ecc_count++;
|
||||
mutex_unlock(&ras_umc->pending_ecc_lock);
|
||||
|
||||
return 0;
|
||||
|
|
@ -225,8 +250,16 @@ int ras_umc_log_pending_bad_bank(struct ras_core_context *ras_core)
|
|||
if (!ras_umc_log_bad_bank(ras_core, &ecc_node->ecc)) {
|
||||
list_del(&ecc_node->node);
|
||||
kfree(ecc_node);
|
||||
if (ras_umc->pending_ecc_count)
|
||||
ras_umc->pending_ecc_count--;
|
||||
}
|
||||
}
|
||||
if (ras_umc->pending_ecc_dropped) {
|
||||
RAS_DEV_WARN(ras_core->dev,
|
||||
"%u pending ECC bad-bank events were dropped during GPU reset\n",
|
||||
ras_umc->pending_ecc_dropped);
|
||||
ras_umc->pending_ecc_dropped = 0;
|
||||
}
|
||||
mutex_unlock(&ras_umc->pending_ecc_lock);
|
||||
|
||||
return 0;
|
||||
|
|
@ -609,6 +642,8 @@ int ras_umc_sw_fini(struct ras_core_context *ras_core)
|
|||
list_del(&ecc_node->node);
|
||||
kfree(ecc_node);
|
||||
}
|
||||
ras_umc->pending_ecc_count = 0;
|
||||
ras_umc->pending_ecc_dropped = 0;
|
||||
mutex_unlock(&ras_umc->pending_ecc_lock);
|
||||
|
||||
mutex_destroy(&ras_umc->tree_lock);
|
||||
|
|
|
|||
|
|
@ -139,8 +139,20 @@ struct ras_umc {
|
|||
struct mutex pending_ecc_lock;
|
||||
struct ras_umc_err_data umc_err_data;
|
||||
struct list_head pending_ecc_list;
|
||||
/* number of entries currently queued on pending_ecc_list */
|
||||
u32 pending_ecc_count;
|
||||
/* number of entries dropped because pending_ecc_list was full */
|
||||
u32 pending_ecc_dropped;
|
||||
};
|
||||
|
||||
/*
|
||||
* Upper bound on entries that can be queued on pending_ecc_list while a
|
||||
* GPU reset is in progress. Beyond this, new ECC events are dropped to
|
||||
* prevent unbounded kernel memory growth in case of an ECC storm or
|
||||
* malicious/repeated UMC error injection.
|
||||
*/
|
||||
#define RAS_UMC_PENDING_ECC_MAX 8192
|
||||
|
||||
int ras_umc_sw_init(struct ras_core_context *ras);
|
||||
int ras_umc_sw_fini(struct ras_core_context *ras);
|
||||
int ras_umc_hw_init(struct ras_core_context *ras);
|
||||
|
|
|
|||
|
|
@ -311,7 +311,7 @@ static void radeon_audio_write_sad_regs(struct drm_encoder *encoder)
|
|||
if (!connector)
|
||||
return;
|
||||
|
||||
sad_count = drm_edid_to_sad(radeon_connector->edid, &sads);
|
||||
sad_count = drm_edid_to_sad(drm_edid_raw(radeon_connector->edid), &sads);
|
||||
if (sad_count < 0)
|
||||
DRM_ERROR("Couldn't read SADs: %d\n", sad_count);
|
||||
if (sad_count <= 0)
|
||||
|
|
@ -335,7 +335,7 @@ static void radeon_audio_write_speaker_allocation(struct drm_encoder *encoder)
|
|||
if (!connector)
|
||||
return;
|
||||
|
||||
sad_count = drm_edid_to_speaker_allocation(radeon_connector->edid, &sadb);
|
||||
sad_count = drm_edid_to_speaker_allocation(drm_edid_raw(radeon_connector->edid), &sadb);
|
||||
if (sad_count < 0) {
|
||||
DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n",
|
||||
sad_count);
|
||||
|
|
|
|||
|
|
@ -390,10 +390,10 @@ bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev)
|
|||
}
|
||||
|
||||
/* this is used for atom LCDs as well */
|
||||
struct edid *
|
||||
const struct drm_edid *
|
||||
radeon_bios_get_hardcoded_edid(struct radeon_device *rdev)
|
||||
{
|
||||
return drm_edid_duplicate(drm_edid_raw(rdev->mode_info.bios_hardcoded_edid));
|
||||
return drm_edid_dup(rdev->mode_info.bios_hardcoded_edid);
|
||||
}
|
||||
|
||||
static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rdev,
|
||||
|
|
|
|||
|
|
@ -271,8 +271,8 @@ static void radeon_connector_get_edid(struct drm_connector *connector)
|
|||
if ((radeon_connector_encoder_get_dp_bridge_encoder_id(connector) !=
|
||||
ENCODER_OBJECT_ID_NONE) &&
|
||||
radeon_connector->ddc_bus->has_aux) {
|
||||
radeon_connector->edid = drm_get_edid(connector,
|
||||
&radeon_connector->ddc_bus->aux.ddc);
|
||||
radeon_connector->edid = drm_edid_read_ddc(connector,
|
||||
&radeon_connector->ddc_bus->aux.ddc);
|
||||
} else if ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
|
||||
(connector->connector_type == DRM_MODE_CONNECTOR_eDP)) {
|
||||
struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
|
||||
|
|
@ -280,19 +280,19 @@ static void radeon_connector_get_edid(struct drm_connector *connector)
|
|||
if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT ||
|
||||
dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) &&
|
||||
radeon_connector->ddc_bus->has_aux)
|
||||
radeon_connector->edid = drm_get_edid(&radeon_connector->base,
|
||||
&radeon_connector->ddc_bus->aux.ddc);
|
||||
radeon_connector->edid = drm_edid_read_ddc(&radeon_connector->base,
|
||||
&radeon_connector->ddc_bus->aux.ddc);
|
||||
else if (radeon_connector->ddc_bus)
|
||||
radeon_connector->edid = drm_get_edid(&radeon_connector->base,
|
||||
&radeon_connector->ddc_bus->adapter);
|
||||
radeon_connector->edid = drm_edid_read_ddc(&radeon_connector->base,
|
||||
&radeon_connector->ddc_bus->adapter);
|
||||
} else if (vga_switcheroo_handler_flags() & VGA_SWITCHEROO_CAN_SWITCH_DDC &&
|
||||
connector->connector_type == DRM_MODE_CONNECTOR_LVDS &&
|
||||
radeon_connector->ddc_bus) {
|
||||
radeon_connector->edid = drm_get_edid_switcheroo(&radeon_connector->base,
|
||||
&radeon_connector->ddc_bus->adapter);
|
||||
radeon_connector->edid = drm_edid_read_switcheroo(&radeon_connector->base,
|
||||
&radeon_connector->ddc_bus->adapter);
|
||||
} else if (radeon_connector->ddc_bus) {
|
||||
radeon_connector->edid = drm_get_edid(&radeon_connector->base,
|
||||
&radeon_connector->ddc_bus->adapter);
|
||||
radeon_connector->edid = drm_edid_read_ddc(&radeon_connector->base,
|
||||
&radeon_connector->ddc_bus->adapter);
|
||||
}
|
||||
|
||||
if (!radeon_connector->edid) {
|
||||
|
|
@ -314,25 +314,17 @@ static void radeon_connector_get_edid(struct drm_connector *connector)
|
|||
}
|
||||
}
|
||||
|
||||
static void radeon_connector_free_edid(struct drm_connector *connector)
|
||||
{
|
||||
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
|
||||
|
||||
kfree(radeon_connector->edid);
|
||||
radeon_connector->edid = NULL;
|
||||
}
|
||||
|
||||
static int radeon_ddc_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
|
||||
int ret;
|
||||
|
||||
if (radeon_connector->edid) {
|
||||
drm_connector_update_edid_property(connector, radeon_connector->edid);
|
||||
ret = drm_add_edid_modes(connector, radeon_connector->edid);
|
||||
drm_edid_connector_update(connector, radeon_connector->edid);
|
||||
ret = drm_edid_connector_add_modes(connector);
|
||||
return ret;
|
||||
}
|
||||
drm_connector_update_edid_property(connector, NULL);
|
||||
drm_edid_connector_update(connector, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -895,7 +887,9 @@ static void radeon_connector_destroy(struct drm_connector *connector)
|
|||
{
|
||||
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
|
||||
|
||||
radeon_connector_free_edid(connector);
|
||||
drm_edid_free(radeon_connector->edid);
|
||||
radeon_connector->edid = NULL;
|
||||
|
||||
kfree(radeon_connector->con_priv);
|
||||
drm_connector_unregister(connector);
|
||||
drm_connector_cleanup(connector);
|
||||
|
|
@ -1007,7 +1001,8 @@ radeon_vga_detect(struct drm_connector *connector, bool force)
|
|||
dret = radeon_ddc_probe(radeon_connector, false);
|
||||
if (dret) {
|
||||
radeon_connector->detected_by_load = false;
|
||||
radeon_connector_free_edid(connector);
|
||||
drm_edid_free(radeon_connector->edid);
|
||||
radeon_connector->edid = NULL;
|
||||
radeon_connector_get_edid(connector);
|
||||
|
||||
if (!radeon_connector->edid) {
|
||||
|
|
@ -1016,13 +1011,14 @@ radeon_vga_detect(struct drm_connector *connector, bool force)
|
|||
ret = connector_status_connected;
|
||||
} else {
|
||||
radeon_connector->use_digital =
|
||||
!!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
|
||||
drm_edid_is_digital(radeon_connector->edid);
|
||||
|
||||
/* some oems have boards with separate digital and analog connectors
|
||||
* with a shared ddc line (often vga + hdmi)
|
||||
*/
|
||||
if (radeon_connector->use_digital && radeon_connector->shared_ddc) {
|
||||
radeon_connector_free_edid(connector);
|
||||
drm_edid_free(radeon_connector->edid);
|
||||
radeon_connector->edid = NULL;
|
||||
ret = connector_status_disconnected;
|
||||
} else {
|
||||
ret = connector_status_connected;
|
||||
|
|
@ -1251,7 +1247,8 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
|
|||
}
|
||||
if (dret) {
|
||||
radeon_connector->detected_by_load = false;
|
||||
radeon_connector_free_edid(connector);
|
||||
drm_edid_free(radeon_connector->edid);
|
||||
radeon_connector->edid = NULL;
|
||||
radeon_connector_get_edid(connector);
|
||||
|
||||
if (!radeon_connector->edid) {
|
||||
|
|
@ -1271,13 +1268,14 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
|
|||
}
|
||||
} else {
|
||||
radeon_connector->use_digital =
|
||||
!!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
|
||||
drm_edid_is_digital(radeon_connector->edid);
|
||||
|
||||
/* some oems have boards with separate digital and analog connectors
|
||||
* with a shared ddc line (often vga + hdmi)
|
||||
*/
|
||||
if ((!radeon_connector->use_digital) && radeon_connector->shared_ddc) {
|
||||
radeon_connector_free_edid(connector);
|
||||
drm_edid_free(radeon_connector->edid);
|
||||
radeon_connector->edid = NULL;
|
||||
ret = connector_status_disconnected;
|
||||
} else {
|
||||
ret = connector_status_connected;
|
||||
|
|
@ -1301,7 +1299,8 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
|
|||
if (list_connector->connector_type != DRM_MODE_CONNECTOR_VGA) {
|
||||
/* hpd is our only option in this case */
|
||||
if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) {
|
||||
radeon_connector_free_edid(connector);
|
||||
drm_edid_free(radeon_connector->edid);
|
||||
radeon_connector->edid = NULL;
|
||||
ret = connector_status_disconnected;
|
||||
}
|
||||
}
|
||||
|
|
@ -1635,7 +1634,8 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
|
|||
goto out;
|
||||
}
|
||||
|
||||
radeon_connector_free_edid(connector);
|
||||
drm_edid_free(radeon_connector->edid);
|
||||
radeon_connector->edid = NULL;
|
||||
|
||||
if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
|
||||
(connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
|
||||
|
|
|
|||
|
|
@ -525,7 +525,7 @@ struct radeon_connector {
|
|||
bool use_digital;
|
||||
/* we need to mind the EDID between detect
|
||||
and get modes due to analog/digital/tvencoder */
|
||||
struct edid *edid;
|
||||
const struct drm_edid *edid;
|
||||
void *con_priv;
|
||||
bool dac_load_detect;
|
||||
bool detected_by_load; /* if the connection status was determined by load */
|
||||
|
|
@ -839,7 +839,7 @@ radeon_get_crtc_scanout_position(struct drm_crtc *crtc, bool in_vblank_irq,
|
|||
const struct drm_display_mode *mode);
|
||||
|
||||
extern bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev);
|
||||
extern struct edid *
|
||||
extern const struct drm_edid *
|
||||
radeon_bios_get_hardcoded_edid(struct radeon_device *rdev);
|
||||
extern bool radeon_atom_get_clock_info(struct drm_device *dev);
|
||||
extern bool radeon_combios_get_clock_info(struct drm_device *dev);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user