mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-16 04:21:09 -04:00
Merge tag 'amd-drm-next-7.1-2026-04-03' of https://gitlab.freedesktop.org/agd5f/linux into drm-next
amd-drm-next-7.1-2026-04-03: amdgpu: - Audio regression fix - Use drm edid parser for AMD VSDB - Misc cleanups - VCE cs parse fixes - VCN cs parse fixes - RAS fixes - Clean up and unify vram reservation handling - GPU Partition updates - system_wq cleanups - Add CONFIG_GCOV_PROFILE_AMDGPU kconfig option - SMU vram copy updates - SMU 15 fixes - SMU 13 fixes - SMU 14 fixes - UserQ fixes - Replace pasid idr with an xarray - Dither handling fix - Enable amdgpu by default for CIK APUs - Add IBs to devcoredump amdkfd: - system_wq cleanups radeon: - system_wq cleanups drm: - Add support for AMD VSDB parsing to drm_edid Signed-off-by: Dave Airlie <airlied@redhat.com> From: Alex Deucher <alexander.deucher@amd.com> Link: https://patch.msgid.link/20260403214329.2976329-1-alexander.deucher@amd.com
This commit is contained in:
@@ -103,6 +103,23 @@ config DRM_AMDGPU_WERROR
|
||||
Add -Werror to the build flags for amdgpu.ko.
|
||||
Only enable this if you are warning code for amdgpu.ko.
|
||||
|
||||
|
||||
config GCOV_PROFILE_AMDGPU
|
||||
bool "Enable GCOV profiling on amdgpu"
|
||||
depends on DRM_AMDGPU
|
||||
depends on GCOV_KERNEL
|
||||
default n
|
||||
help
|
||||
Enable GCOV profiling on the amdgpu driver for checking which
|
||||
functions/lines are executed during testing. This adds compiler
|
||||
instrumentation flags to all amdgpu source files, producing
|
||||
.gcda/.gcno coverage data accessible via debugfs.
|
||||
|
||||
This increases the amdgpu module size by ~50% and adds ~2-5%
|
||||
runtime overhead on GPU submission paths.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
source "drivers/gpu/drm/amd/acp/Kconfig"
|
||||
source "drivers/gpu/drm/amd/display/Kconfig"
|
||||
source "drivers/gpu/drm/amd/amdkfd/Kconfig"
|
||||
|
||||
@@ -27,6 +27,10 @@ FULL_AMD_PATH=$(src)/..
|
||||
DISPLAY_FOLDER_NAME=display
|
||||
FULL_AMD_DISPLAY_PATH = $(FULL_AMD_PATH)/$(DISPLAY_FOLDER_NAME)
|
||||
|
||||
ifdef CONFIG_GCOV_PROFILE_AMDGPU
|
||||
GCOV_PROFILE := y
|
||||
endif
|
||||
|
||||
ccflags-y := -I$(FULL_AMD_PATH)/include/asic_reg \
|
||||
-I$(FULL_AMD_PATH)/include \
|
||||
-I$(FULL_AMD_PATH)/amdgpu \
|
||||
|
||||
@@ -179,7 +179,7 @@ aldebaran_mode2_perform_reset(struct amdgpu_reset_control *reset_ctl,
|
||||
list_for_each_entry(tmp_adev, reset_device_list, reset_list) {
|
||||
/* For XGMI run all resets in parallel to speed up the process */
|
||||
if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) {
|
||||
if (!queue_work(system_unbound_wq,
|
||||
if (!queue_work(system_dfl_wq,
|
||||
&tmp_adev->reset_cntl->reset_work))
|
||||
r = -EALREADY;
|
||||
} else
|
||||
|
||||
@@ -1045,11 +1045,6 @@ struct amdgpu_device {
|
||||
struct amdgpu_mqd mqds[AMDGPU_HW_IP_NUM];
|
||||
const struct amdgpu_userq_funcs *userq_funcs[AMDGPU_HW_IP_NUM];
|
||||
|
||||
/* xarray used to retrieve the user queue fence driver reference
|
||||
* in the EOP interrupt handler to signal the particular user
|
||||
* queue fence.
|
||||
*/
|
||||
struct xarray userq_xa;
|
||||
/**
|
||||
* @userq_doorbell_xa: Global user queue map (doorbell index → queue)
|
||||
* Key: doorbell_index (unique global identifier for the queue)
|
||||
|
||||
@@ -805,7 +805,10 @@ u64 amdgpu_amdkfd_xcp_memory_size(struct amdgpu_device *adev, int xcp_id)
|
||||
} else {
|
||||
tmp = adev->gmc.mem_partitions[mem_id].size;
|
||||
}
|
||||
do_div(tmp, adev->xcp_mgr->num_xcp_per_mem_partition);
|
||||
|
||||
if (adev->xcp_mgr->mem_alloc_mode == AMDGPU_PARTITION_MEM_CAPPING_EVEN)
|
||||
do_div(tmp, adev->xcp_mgr->num_xcp_per_mem_partition);
|
||||
|
||||
return ALIGN_DOWN(tmp, PAGE_SIZE);
|
||||
} else if (adev->apu_prefer_gtt) {
|
||||
return (ttm_tt_pages_limit() << PAGE_SHIFT);
|
||||
|
||||
@@ -1685,9 +1685,9 @@ static int amdgpu_atombios_allocate_fb_scratch(struct amdgpu_device *adev)
|
||||
(uint32_t)(ATOM_VRAM_BLOCK_SRIOV_MSG_SHARE_RESERVATION <<
|
||||
ATOM_VRAM_OPERATION_FLAGS_SHIFT)) {
|
||||
/* Firmware request VRAM reservation for SR-IOV */
|
||||
adev->mman.fw_vram_usage_start_offset = (start_addr &
|
||||
(~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10;
|
||||
adev->mman.fw_vram_usage_size = size << 10;
|
||||
amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_FW_VRAM_USAGE,
|
||||
(start_addr & (~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10,
|
||||
size << 10, true);
|
||||
/* Use the default scratch size */
|
||||
usage_bytes = 0;
|
||||
} else {
|
||||
|
||||
@@ -120,9 +120,9 @@ static int amdgpu_atomfirmware_allocate_fb_v2_1(struct amdgpu_device *adev,
|
||||
(u32)(ATOM_VRAM_BLOCK_SRIOV_MSG_SHARE_RESERVATION <<
|
||||
ATOM_VRAM_OPERATION_FLAGS_SHIFT)) {
|
||||
/* Firmware request VRAM reservation for SR-IOV */
|
||||
adev->mman.fw_vram_usage_start_offset = (start_addr &
|
||||
(~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10;
|
||||
adev->mman.fw_vram_usage_size = fw_size << 10;
|
||||
amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_FW_VRAM_USAGE,
|
||||
(start_addr & (~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10,
|
||||
fw_size << 10, true);
|
||||
/* Use the default scratch size */
|
||||
*usage_bytes = 0;
|
||||
} else {
|
||||
@@ -152,18 +152,18 @@ static int amdgpu_atomfirmware_allocate_fb_v2_2(struct amdgpu_device *adev,
|
||||
((fw_start_addr & (ATOM_VRAM_BLOCK_NEEDS_NO_RESERVATION <<
|
||||
ATOM_VRAM_OPERATION_FLAGS_SHIFT)) == 0)) {
|
||||
/* Firmware request VRAM reservation for SR-IOV */
|
||||
adev->mman.fw_vram_usage_start_offset = (fw_start_addr &
|
||||
(~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10;
|
||||
adev->mman.fw_vram_usage_size = fw_size << 10;
|
||||
amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_FW_VRAM_USAGE,
|
||||
(fw_start_addr & (~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10,
|
||||
fw_size << 10, true);
|
||||
}
|
||||
|
||||
if (amdgpu_sriov_vf(adev) &&
|
||||
((drv_start_addr & (ATOM_VRAM_BLOCK_NEEDS_NO_RESERVATION <<
|
||||
ATOM_VRAM_OPERATION_FLAGS_SHIFT)) == 0)) {
|
||||
/* driver request VRAM reservation for SR-IOV */
|
||||
adev->mman.drv_vram_usage_start_offset = (drv_start_addr &
|
||||
(~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10;
|
||||
adev->mman.drv_vram_usage_size = drv_size << 10;
|
||||
amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_DRV_VRAM_USAGE,
|
||||
(drv_start_addr & (~ATOM_VRAM_OPERATION_FLAGS_MASK)) << 10,
|
||||
drv_size << 10, true);
|
||||
}
|
||||
|
||||
*usage_bytes = 0;
|
||||
|
||||
@@ -210,12 +210,24 @@ static void amdgpu_devcoredump_fw_info(struct amdgpu_device *adev,
|
||||
static ssize_t
|
||||
amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_info *coredump)
|
||||
{
|
||||
struct amdgpu_device *adev = coredump->adev;
|
||||
struct drm_printer p;
|
||||
struct drm_print_iterator iter;
|
||||
struct amdgpu_vm_fault_info *fault_info;
|
||||
struct amdgpu_bo_va_mapping *mapping;
|
||||
struct amdgpu_ip_block *ip_block;
|
||||
int ver;
|
||||
struct amdgpu_res_cursor cursor;
|
||||
struct amdgpu_bo *abo, *root;
|
||||
uint64_t va_start, offset;
|
||||
struct amdgpu_ring *ring;
|
||||
struct amdgpu_vm *vm;
|
||||
u32 *ib_content;
|
||||
uint8_t *kptr;
|
||||
int ver, i, j, r;
|
||||
u32 ring_idx, off;
|
||||
bool sizing_pass;
|
||||
|
||||
sizing_pass = buffer == NULL;
|
||||
iter.data = buffer;
|
||||
iter.offset = 0;
|
||||
iter.remain = count;
|
||||
@@ -303,23 +315,25 @@ amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_inf
|
||||
|
||||
/* Add ring buffer information */
|
||||
drm_printf(&p, "Ring buffer information\n");
|
||||
for (int i = 0; i < coredump->adev->num_rings; i++) {
|
||||
int j = 0;
|
||||
struct amdgpu_ring *ring = coredump->adev->rings[i];
|
||||
if (coredump->num_rings) {
|
||||
for (i = 0; i < coredump->num_rings; i++) {
|
||||
ring_idx = coredump->rings[i].ring_index;
|
||||
ring = coredump->adev->rings[ring_idx];
|
||||
off = coredump->rings[i].offset;
|
||||
|
||||
drm_printf(&p, "ring name: %s\n", ring->name);
|
||||
drm_printf(&p, "Rptr: 0x%llx Wptr: 0x%llx RB mask: %x\n",
|
||||
amdgpu_ring_get_rptr(ring),
|
||||
amdgpu_ring_get_wptr(ring),
|
||||
ring->buf_mask);
|
||||
drm_printf(&p, "Ring size in dwords: %d\n",
|
||||
ring->ring_size / 4);
|
||||
drm_printf(&p, "Ring contents\n");
|
||||
drm_printf(&p, "Offset \t Value\n");
|
||||
drm_printf(&p, "ring name: %s\n", ring->name);
|
||||
drm_printf(&p, "Rptr: 0x%llx Wptr: 0x%llx RB mask: %x\n",
|
||||
coredump->rings[i].rptr,
|
||||
coredump->rings[i].wptr,
|
||||
ring->buf_mask);
|
||||
drm_printf(&p, "Ring size in dwords: %d\n",
|
||||
ring->ring_size / 4);
|
||||
drm_printf(&p, "Ring contents\n");
|
||||
drm_printf(&p, "Offset \t Value\n");
|
||||
|
||||
while (j < ring->ring_size) {
|
||||
drm_printf(&p, "0x%x \t 0x%x\n", j, ring->ring[j / 4]);
|
||||
j += 4;
|
||||
for (j = 0; j < ring->ring_size; j += 4)
|
||||
drm_printf(&p, "0x%x \t 0x%x\n", j,
|
||||
coredump->rings_dw[off + j / 4]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,6 +342,87 @@ amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_inf
|
||||
else if (coredump->reset_vram_lost)
|
||||
drm_printf(&p, "VRAM is lost due to GPU reset!\n");
|
||||
|
||||
if (coredump->num_ibs) {
|
||||
/* Don't try to lookup the VM or map the BOs when calculating the
|
||||
* size required to store the devcoredump.
|
||||
*/
|
||||
if (sizing_pass)
|
||||
vm = NULL;
|
||||
else
|
||||
vm = amdgpu_vm_lock_by_pasid(adev, &root, coredump->pasid);
|
||||
|
||||
for (int i = 0; i < coredump->num_ibs && (sizing_pass || vm); i++) {
|
||||
ib_content = kvmalloc_array(coredump->ibs[i].ib_size_dw, 4,
|
||||
GFP_KERNEL);
|
||||
if (!ib_content)
|
||||
continue;
|
||||
|
||||
/* vm=NULL can only happen when 'sizing_pass' is true. Skip to the
|
||||
* drm_printf() calls (ib_content doesn't need to be initialized
|
||||
* as its content won't be written anywhere).
|
||||
*/
|
||||
if (!vm)
|
||||
goto output_ib_content;
|
||||
|
||||
va_start = coredump->ibs[i].gpu_addr & AMDGPU_GMC_HOLE_MASK;
|
||||
mapping = amdgpu_vm_bo_lookup_mapping(vm, va_start / AMDGPU_GPU_PAGE_SIZE);
|
||||
if (!mapping)
|
||||
goto free_ib_content;
|
||||
|
||||
offset = va_start - (mapping->start * AMDGPU_GPU_PAGE_SIZE);
|
||||
abo = amdgpu_bo_ref(mapping->bo_va->base.bo);
|
||||
r = amdgpu_bo_reserve(abo, false);
|
||||
if (r)
|
||||
goto free_ib_content;
|
||||
|
||||
if (abo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS) {
|
||||
off = 0;
|
||||
|
||||
if (abo->tbo.resource->mem_type != TTM_PL_VRAM)
|
||||
goto unreserve_abo;
|
||||
|
||||
amdgpu_res_first(abo->tbo.resource, offset,
|
||||
coredump->ibs[i].ib_size_dw * 4,
|
||||
&cursor);
|
||||
while (cursor.remaining) {
|
||||
amdgpu_device_mm_access(adev, cursor.start / 4,
|
||||
&ib_content[off], cursor.size / 4,
|
||||
false);
|
||||
off += cursor.size;
|
||||
amdgpu_res_next(&cursor, cursor.size);
|
||||
}
|
||||
} else {
|
||||
r = ttm_bo_kmap(&abo->tbo, 0,
|
||||
PFN_UP(abo->tbo.base.size),
|
||||
&abo->kmap);
|
||||
if (r)
|
||||
goto unreserve_abo;
|
||||
|
||||
kptr = amdgpu_bo_kptr(abo);
|
||||
kptr += offset;
|
||||
memcpy(ib_content, kptr,
|
||||
coredump->ibs[i].ib_size_dw * 4);
|
||||
|
||||
amdgpu_bo_kunmap(abo);
|
||||
}
|
||||
|
||||
output_ib_content:
|
||||
drm_printf(&p, "\nIB #%d 0x%llx %d dw\n",
|
||||
i, coredump->ibs[i].gpu_addr, coredump->ibs[i].ib_size_dw);
|
||||
for (int j = 0; j < coredump->ibs[i].ib_size_dw; j++)
|
||||
drm_printf(&p, "0x%08x\n", ib_content[j]);
|
||||
unreserve_abo:
|
||||
if (vm)
|
||||
amdgpu_bo_unreserve(abo);
|
||||
free_ib_content:
|
||||
kvfree(ib_content);
|
||||
}
|
||||
if (vm) {
|
||||
amdgpu_bo_unreserve(root);
|
||||
amdgpu_bo_unref(&root);
|
||||
}
|
||||
}
|
||||
|
||||
return count - iter.remain;
|
||||
}
|
||||
|
||||
@@ -359,6 +454,8 @@ static void amdgpu_devcoredump_free(void *data)
|
||||
struct amdgpu_coredump_info *coredump = data;
|
||||
|
||||
kvfree(coredump->formatted);
|
||||
kvfree(coredump->rings);
|
||||
kvfree(coredump->rings_dw);
|
||||
kvfree(data);
|
||||
}
|
||||
|
||||
@@ -395,18 +492,26 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
|
||||
{
|
||||
struct drm_device *dev = adev_to_drm(adev);
|
||||
struct amdgpu_coredump_info *coredump;
|
||||
size_t size = sizeof(*coredump);
|
||||
struct drm_sched_job *s_job;
|
||||
u64 total_ring_size, ring_count;
|
||||
struct amdgpu_ring *ring;
|
||||
int i, off, idx;
|
||||
|
||||
/* No need to generate a new coredump if there's one in progress already. */
|
||||
if (work_pending(&adev->coredump_work))
|
||||
return;
|
||||
|
||||
coredump = kzalloc_obj(*coredump, GFP_NOWAIT);
|
||||
if (job && job->pasid)
|
||||
size += sizeof(struct amdgpu_coredump_ib_info) * job->num_ibs;
|
||||
|
||||
coredump = kzalloc(size, GFP_NOWAIT);
|
||||
if (!coredump)
|
||||
return;
|
||||
|
||||
coredump->skip_vram_check = skip_vram_check;
|
||||
coredump->reset_vram_lost = vram_lost;
|
||||
coredump->pasid = job->pasid;
|
||||
|
||||
if (job && job->pasid) {
|
||||
struct amdgpu_task_info *ti;
|
||||
@@ -416,6 +521,11 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
|
||||
coredump->reset_task_info = *ti;
|
||||
amdgpu_vm_put_task_info(ti);
|
||||
}
|
||||
coredump->num_ibs = job->num_ibs;
|
||||
for (i = 0; i < job->num_ibs; ++i) {
|
||||
coredump->ibs[i].gpu_addr = job->ibs[i].gpu_addr;
|
||||
coredump->ibs[i].ib_size_dw = job->ibs[i].length_dw;
|
||||
}
|
||||
}
|
||||
|
||||
if (job) {
|
||||
@@ -423,6 +533,47 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
|
||||
coredump->ring = to_amdgpu_ring(s_job->sched);
|
||||
}
|
||||
|
||||
/* Dump ring content if memory allocation succeeds. */
|
||||
ring_count = 0;
|
||||
total_ring_size = 0;
|
||||
for (i = 0; i < adev->num_rings; i++) {
|
||||
ring = adev->rings[i];
|
||||
|
||||
/* Only dump rings with unsignalled fences. */
|
||||
if (atomic_read(&ring->fence_drv.last_seq) == ring->fence_drv.sync_seq &&
|
||||
coredump->ring != ring)
|
||||
continue;
|
||||
|
||||
total_ring_size += ring->ring_size;
|
||||
ring_count++;
|
||||
}
|
||||
coredump->rings_dw = kzalloc(total_ring_size, GFP_NOWAIT);
|
||||
coredump->rings = kcalloc(ring_count, sizeof(struct amdgpu_coredump_ring), GFP_NOWAIT);
|
||||
if (coredump->rings && coredump->rings_dw) {
|
||||
for (i = 0, off = 0, idx = 0; i < adev->num_rings; i++) {
|
||||
ring = adev->rings[i];
|
||||
|
||||
if (atomic_read(&ring->fence_drv.last_seq) == ring->fence_drv.sync_seq &&
|
||||
coredump->ring != ring)
|
||||
continue;
|
||||
|
||||
coredump->rings[idx].ring_index = ring->idx;
|
||||
coredump->rings[idx].rptr = amdgpu_ring_get_rptr(ring);
|
||||
coredump->rings[idx].wptr = amdgpu_ring_get_wptr(ring);
|
||||
coredump->rings[idx].offset = off;
|
||||
|
||||
memcpy(&coredump->rings_dw[off], ring->ring, ring->ring_size);
|
||||
off += ring->ring_size;
|
||||
idx++;
|
||||
}
|
||||
coredump->num_rings = idx;
|
||||
} else {
|
||||
kvfree(coredump->rings_dw);
|
||||
kvfree(coredump->rings);
|
||||
coredump->rings_dw = NULL;
|
||||
coredump->rings = NULL;
|
||||
}
|
||||
|
||||
coredump->adev = adev;
|
||||
|
||||
ktime_get_ts64(&coredump->reset_time);
|
||||
|
||||
@@ -31,6 +31,18 @@
|
||||
|
||||
#define AMDGPU_COREDUMP_VERSION "1"
|
||||
|
||||
struct amdgpu_coredump_ring {
|
||||
u64 rptr;
|
||||
u64 wptr;
|
||||
u32 ring_index;
|
||||
u32 offset;
|
||||
};
|
||||
|
||||
struct amdgpu_coredump_ib_info {
|
||||
uint64_t gpu_addr;
|
||||
u32 ib_size_dw;
|
||||
};
|
||||
|
||||
struct amdgpu_coredump_info {
|
||||
struct amdgpu_device *adev;
|
||||
struct amdgpu_task_info reset_task_info;
|
||||
@@ -39,11 +51,20 @@ struct amdgpu_coredump_info {
|
||||
bool skip_vram_check;
|
||||
bool reset_vram_lost;
|
||||
struct amdgpu_ring *ring;
|
||||
|
||||
struct amdgpu_coredump_ring *rings;
|
||||
u32 *rings_dw;
|
||||
u32 num_rings;
|
||||
|
||||
/* Readable form of coredevdump, generate once to speed up
|
||||
* reading it (see drm_coredump_printer's documentation).
|
||||
*/
|
||||
ssize_t formatted_size;
|
||||
char *formatted;
|
||||
|
||||
unsigned int pasid;
|
||||
int num_ibs;
|
||||
struct amdgpu_coredump_ib_info ibs[] __counted_by(num_ibs);
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
@@ -3757,15 +3757,13 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
||||
spin_lock_init(&adev->virt.rlcg_reg_lock);
|
||||
spin_lock_init(&adev->wb.lock);
|
||||
|
||||
xa_init_flags(&adev->userq_xa, XA_FLAGS_LOCK_IRQ);
|
||||
|
||||
INIT_LIST_HEAD(&adev->reset_list);
|
||||
|
||||
INIT_LIST_HEAD(&adev->ras_list);
|
||||
|
||||
INIT_LIST_HEAD(&adev->pm.od_kobj_list);
|
||||
|
||||
xa_init(&adev->userq_doorbell_xa);
|
||||
xa_init_flags(&adev->userq_doorbell_xa, XA_FLAGS_LOCK_IRQ);
|
||||
|
||||
INIT_DELAYED_WORK(&adev->delayed_init_work,
|
||||
amdgpu_device_delayed_init_work_handler);
|
||||
@@ -4065,7 +4063,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
||||
}
|
||||
/* must succeed. */
|
||||
amdgpu_ras_resume(adev);
|
||||
queue_delayed_work(system_wq, &adev->delayed_init_work,
|
||||
queue_delayed_work(system_dfl_wq, &adev->delayed_init_work,
|
||||
msecs_to_jiffies(AMDGPU_RESUME_MS));
|
||||
}
|
||||
|
||||
@@ -4630,7 +4628,7 @@ int amdgpu_device_resume(struct drm_device *dev, bool notify_clients)
|
||||
if (r)
|
||||
goto exit;
|
||||
|
||||
queue_delayed_work(system_wq, &adev->delayed_init_work,
|
||||
queue_delayed_work(system_dfl_wq, &adev->delayed_init_work,
|
||||
msecs_to_jiffies(AMDGPU_RESUME_MS));
|
||||
exit:
|
||||
if (amdgpu_sriov_vf(adev)) {
|
||||
@@ -5339,7 +5337,7 @@ int amdgpu_do_asic_reset(struct list_head *device_list_handle,
|
||||
list_for_each_entry(tmp_adev, device_list_handle, reset_list) {
|
||||
/* For XGMI run all resets in parallel to speed up the process */
|
||||
if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) {
|
||||
if (!queue_work(system_unbound_wq,
|
||||
if (!queue_work(system_dfl_wq,
|
||||
&tmp_adev->xgmi_reset_work))
|
||||
r = -EALREADY;
|
||||
} else
|
||||
|
||||
@@ -641,9 +641,7 @@ module_param_named(si_support, amdgpu_si_support, int, 0444);
|
||||
* CIK (Sea Islands) are second generation GCN GPUs, supported by both
|
||||
* drivers: radeon (old) and amdgpu (new). This parameter controls whether
|
||||
* amdgpu should support CIK.
|
||||
* By default:
|
||||
* - CIK dedicated GPUs are supported by amdgpu.
|
||||
* - CIK APUs are supported by radeon (except when radeon is not built).
|
||||
* By default, CIK dedicated GPUs and APUs are supported by amdgpu.
|
||||
* Only relevant when CONFIG_DRM_AMDGPU_CIK is enabled to build CIK support in amdgpu.
|
||||
* See also radeon.cik_support which should be disabled when amdgpu.cik_support is
|
||||
* enabled, and vice versa.
|
||||
@@ -2323,8 +2321,6 @@ static bool amdgpu_support_enabled(struct device *dev,
|
||||
|
||||
case CHIP_BONAIRE:
|
||||
case CHIP_HAWAII:
|
||||
support_by_default = true;
|
||||
fallthrough;
|
||||
case CHIP_KAVERI:
|
||||
case CHIP_KABINI:
|
||||
case CHIP_MULLINS:
|
||||
@@ -2332,6 +2328,7 @@ static bool amdgpu_support_enabled(struct device *dev,
|
||||
param = "cik_support";
|
||||
module_param = amdgpu_cik_support;
|
||||
amdgpu_support_built = IS_ENABLED(CONFIG_DRM_AMDGPU_CIK);
|
||||
support_by_default = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -1580,6 +1580,36 @@ static ssize_t amdgpu_gfx_set_compute_partition(struct device *dev,
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t compute_partition_mem_alloc_mode_show(struct device *dev,
|
||||
struct device_attribute *addr,
|
||||
char *buf)
|
||||
{
|
||||
struct drm_device *ddev = dev_get_drvdata(dev);
|
||||
struct amdgpu_device *adev = drm_to_adev(ddev);
|
||||
int mode = adev->xcp_mgr->mem_alloc_mode;
|
||||
|
||||
return sysfs_emit(buf, "%s\n",
|
||||
amdgpu_gfx_compute_mem_alloc_mode_desc(mode));
|
||||
}
|
||||
|
||||
|
||||
static ssize_t compute_partition_mem_alloc_mode_store(struct device *dev,
|
||||
struct device_attribute *addr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct drm_device *ddev = dev_get_drvdata(dev);
|
||||
struct amdgpu_device *adev = drm_to_adev(ddev);
|
||||
|
||||
if (!strncasecmp("CAPPING", buf, strlen("CAPPING")))
|
||||
adev->xcp_mgr->mem_alloc_mode = AMDGPU_PARTITION_MEM_CAPPING_EVEN;
|
||||
else if (!strncasecmp("ALL", buf, strlen("ALL")))
|
||||
adev->xcp_mgr->mem_alloc_mode = AMDGPU_PARTITION_MEM_ALLOC_ALL;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const char *xcp_desc[] = {
|
||||
[AMDGPU_SPX_PARTITION_MODE] = "SPX",
|
||||
[AMDGPU_DPX_PARTITION_MODE] = "DPX",
|
||||
@@ -1935,6 +1965,10 @@ static DEVICE_ATTR(gfx_reset_mask, 0444,
|
||||
static DEVICE_ATTR(compute_reset_mask, 0444,
|
||||
amdgpu_gfx_get_compute_reset_mask, NULL);
|
||||
|
||||
static DEVICE_ATTR(compute_partition_mem_alloc_mode, 0644,
|
||||
compute_partition_mem_alloc_mode_show,
|
||||
compute_partition_mem_alloc_mode_store);
|
||||
|
||||
static int amdgpu_gfx_sysfs_xcp_init(struct amdgpu_device *adev)
|
||||
{
|
||||
struct amdgpu_xcp_mgr *xcp_mgr = adev->xcp_mgr;
|
||||
@@ -1955,6 +1989,11 @@ static int amdgpu_gfx_sysfs_xcp_init(struct amdgpu_device *adev)
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = device_create_file(adev->dev,
|
||||
&dev_attr_compute_partition_mem_alloc_mode);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (xcp_switch_supported)
|
||||
r = device_create_file(adev->dev,
|
||||
&dev_attr_available_compute_partition);
|
||||
|
||||
@@ -71,6 +71,11 @@ enum amdgpu_gfx_partition {
|
||||
AMDGPU_AUTO_COMPUTE_PARTITION_MODE = -2,
|
||||
};
|
||||
|
||||
enum amdgpu_gfx_partition_mem_alloc_mode {
|
||||
AMDGPU_PARTITION_MEM_CAPPING_EVEN = 0,
|
||||
AMDGPU_PARTITION_MEM_ALLOC_ALL = 1,
|
||||
};
|
||||
|
||||
#define NUM_XCC(x) hweight16(x)
|
||||
|
||||
enum amdgpu_gfx_ras_mem_id_type {
|
||||
@@ -677,4 +682,16 @@ static inline const char *amdgpu_gfx_compute_mode_desc(int mode)
|
||||
}
|
||||
}
|
||||
|
||||
static inline const char *amdgpu_gfx_compute_mem_alloc_mode_desc(int mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case AMDGPU_PARTITION_MEM_CAPPING_EVEN:
|
||||
return "CAPPING";
|
||||
case AMDGPU_PARTITION_MEM_ALLOC_ALL:
|
||||
return "ALL";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1033,17 +1033,17 @@ void amdgpu_gmc_set_vm_fault_masks(struct amdgpu_device *adev, int hub_type,
|
||||
}
|
||||
}
|
||||
|
||||
void amdgpu_gmc_get_vbios_allocations(struct amdgpu_device *adev)
|
||||
void amdgpu_gmc_init_vga_resv_regions(struct amdgpu_device *adev)
|
||||
{
|
||||
unsigned size;
|
||||
|
||||
if (adev->gmc.is_app_apu)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Some ASICs need to reserve a region of video memory to avoid access
|
||||
* from driver
|
||||
*/
|
||||
adev->mman.stolen_reserved_offset = 0;
|
||||
adev->mman.stolen_reserved_size = 0;
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* Currently there is a bug where some memory client outside
|
||||
@@ -1060,8 +1060,8 @@ void amdgpu_gmc_get_vbios_allocations(struct amdgpu_device *adev)
|
||||
*/
|
||||
#ifdef CONFIG_X86
|
||||
if (amdgpu_sriov_vf(adev) && hypervisor_is_type(X86_HYPER_MS_HYPERV)) {
|
||||
adev->mman.stolen_reserved_offset = 0x500000;
|
||||
adev->mman.stolen_reserved_size = 0x200000;
|
||||
amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_STOLEN_RESERVED,
|
||||
0x500000, 0x200000, false);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
@@ -1099,11 +1099,14 @@ void amdgpu_gmc_get_vbios_allocations(struct amdgpu_device *adev)
|
||||
size = 0;
|
||||
|
||||
if (size > AMDGPU_VBIOS_VGA_ALLOCATION) {
|
||||
adev->mman.stolen_vga_size = AMDGPU_VBIOS_VGA_ALLOCATION;
|
||||
adev->mman.stolen_extended_size = size - adev->mman.stolen_vga_size;
|
||||
amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_STOLEN_VGA,
|
||||
0, AMDGPU_VBIOS_VGA_ALLOCATION, false);
|
||||
amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_STOLEN_EXTENDED,
|
||||
AMDGPU_VBIOS_VGA_ALLOCATION,
|
||||
size - AMDGPU_VBIOS_VGA_ALLOCATION, false);
|
||||
} else {
|
||||
adev->mman.stolen_vga_size = size;
|
||||
adev->mman.stolen_extended_size = 0;
|
||||
amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_STOLEN_VGA,
|
||||
0, size, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -456,7 +456,7 @@ extern void
|
||||
amdgpu_gmc_set_vm_fault_masks(struct amdgpu_device *adev, int hub_type,
|
||||
bool enable);
|
||||
|
||||
void amdgpu_gmc_get_vbios_allocations(struct amdgpu_device *adev);
|
||||
void amdgpu_gmc_init_vga_resv_regions(struct amdgpu_device *adev);
|
||||
|
||||
void amdgpu_gmc_init_pdb0(struct amdgpu_device *adev);
|
||||
uint64_t amdgpu_gmc_vram_mc2pa(struct amdgpu_device *adev, uint64_t mc_addr);
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
*/
|
||||
#include "amdgpu_ids.h"
|
||||
|
||||
#include <linux/idr.h>
|
||||
#include <linux/xarray.h>
|
||||
#include <linux/dma-fence-array.h>
|
||||
|
||||
|
||||
@@ -40,8 +40,8 @@
|
||||
* VMs are looked up from the PASID per amdgpu_device.
|
||||
*/
|
||||
|
||||
static DEFINE_IDR(amdgpu_pasid_idr);
|
||||
static DEFINE_SPINLOCK(amdgpu_pasid_idr_lock);
|
||||
static DEFINE_XARRAY_FLAGS(amdgpu_pasid_xa, XA_FLAGS_LOCK_IRQ | XA_FLAGS_ALLOC1);
|
||||
static u32 amdgpu_pasid_xa_next;
|
||||
|
||||
/* Helper to free pasid from a fence callback */
|
||||
struct amdgpu_pasid_cb {
|
||||
@@ -62,36 +62,37 @@ struct amdgpu_pasid_cb {
|
||||
*/
|
||||
int amdgpu_pasid_alloc(unsigned int bits)
|
||||
{
|
||||
int pasid;
|
||||
u32 pasid;
|
||||
int r;
|
||||
|
||||
if (bits == 0)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&amdgpu_pasid_idr_lock);
|
||||
/* TODO: Need to replace the idr with an xarry, and then
|
||||
* handle the internal locking with ATOMIC safe paths.
|
||||
*/
|
||||
pasid = idr_alloc_cyclic(&amdgpu_pasid_idr, NULL, 1,
|
||||
1U << bits, GFP_ATOMIC);
|
||||
spin_unlock(&amdgpu_pasid_idr_lock);
|
||||
|
||||
if (pasid >= 0)
|
||||
trace_amdgpu_pasid_allocated(pasid);
|
||||
r = xa_alloc_cyclic_irq(&amdgpu_pasid_xa, &pasid, xa_mk_value(0),
|
||||
XA_LIMIT(1, (1U << bits) - 1),
|
||||
&amdgpu_pasid_xa_next, GFP_KERNEL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
trace_amdgpu_pasid_allocated(pasid);
|
||||
return pasid;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_pasid_free - Free a PASID
|
||||
* @pasid: PASID to free
|
||||
*
|
||||
* Called in IRQ context.
|
||||
*/
|
||||
void amdgpu_pasid_free(u32 pasid)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
trace_amdgpu_pasid_freed(pasid);
|
||||
|
||||
spin_lock(&amdgpu_pasid_idr_lock);
|
||||
idr_remove(&amdgpu_pasid_idr, pasid);
|
||||
spin_unlock(&amdgpu_pasid_idr_lock);
|
||||
xa_lock_irqsave(&amdgpu_pasid_xa, flags);
|
||||
__xa_erase(&amdgpu_pasid_xa, pasid);
|
||||
xa_unlock_irqrestore(&amdgpu_pasid_xa, flags);
|
||||
}
|
||||
|
||||
static void amdgpu_pasid_free_cb(struct dma_fence *fence,
|
||||
@@ -634,7 +635,5 @@ void amdgpu_vmid_mgr_fini(struct amdgpu_device *adev)
|
||||
*/
|
||||
void amdgpu_pasid_mgr_cleanup(void)
|
||||
{
|
||||
spin_lock(&amdgpu_pasid_idr_lock);
|
||||
idr_destroy(&amdgpu_pasid_idr);
|
||||
spin_unlock(&amdgpu_pasid_idr_lock);
|
||||
xa_destroy(&amdgpu_pasid_xa);
|
||||
}
|
||||
|
||||
@@ -1076,24 +1076,25 @@ int psp_update_fw_reservation(struct psp_context *psp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
amdgpu_bo_free_kernel(&adev->mman.fw_reserved_memory, NULL, NULL);
|
||||
amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_FW);
|
||||
|
||||
reserv_size = roundup(reserv_size, SZ_1M);
|
||||
|
||||
ret = amdgpu_bo_create_kernel_at(adev, reserv_addr, reserv_size, &adev->mman.fw_reserved_memory, NULL);
|
||||
amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_FW,
|
||||
reserv_addr, reserv_size, false);
|
||||
ret = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_FW);
|
||||
if (ret) {
|
||||
dev_err(adev->dev, "reserve fw region failed(%d)!\n", ret);
|
||||
amdgpu_bo_free_kernel(&adev->mman.fw_reserved_memory, NULL, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
reserv_size_ext = roundup(reserv_size_ext, SZ_1M);
|
||||
|
||||
ret = amdgpu_bo_create_kernel_at(adev, reserv_addr_ext, reserv_size_ext,
|
||||
&adev->mman.fw_reserved_memory_extend, NULL);
|
||||
amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_FW_EXTEND,
|
||||
reserv_addr_ext, reserv_size_ext, false);
|
||||
ret = amdgpu_ttm_mark_vram_reserved(adev, AMDGPU_RESV_FW_EXTEND);
|
||||
if (ret) {
|
||||
dev_err(adev->dev, "reserve extend fw region failed(%d)!\n", ret);
|
||||
amdgpu_bo_free_kernel(&adev->mman.fw_reserved_memory_extend, NULL, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -277,7 +277,6 @@ struct psp_memory_training_context {
|
||||
|
||||
/*vram offset of the c2p training data*/
|
||||
u64 c2p_train_data_offset;
|
||||
struct amdgpu_bo *c2p_bo;
|
||||
|
||||
enum psp_memory_training_init_flag init;
|
||||
u32 training_cnt;
|
||||
|
||||
@@ -5726,7 +5726,7 @@ int amdgpu_ras_add_critical_region(struct amdgpu_device *adev,
|
||||
|
||||
static void amdgpu_ras_critical_region_init(struct amdgpu_device *adev)
|
||||
{
|
||||
amdgpu_ras_add_critical_region(adev, adev->mman.fw_reserved_memory);
|
||||
amdgpu_ras_add_critical_region(adev, adev->mman.resv_region[AMDGPU_RESV_FW].bo);
|
||||
}
|
||||
|
||||
static void amdgpu_ras_critical_region_fini(struct amdgpu_device *adev)
|
||||
|
||||
@@ -116,7 +116,7 @@ static int amdgpu_reset_xgmi_reset_on_init_perform_reset(
|
||||
/* Mode1 reset needs to be triggered on all devices together */
|
||||
list_for_each_entry(tmp_adev, reset_device_list, reset_list) {
|
||||
/* For XGMI run all resets in parallel to speed up the process */
|
||||
if (!queue_work(system_unbound_wq, &tmp_adev->xgmi_reset_work))
|
||||
if (!queue_work(system_dfl_wq, &tmp_adev->xgmi_reset_work))
|
||||
r = -EALREADY;
|
||||
if (r) {
|
||||
dev_err(tmp_adev->dev,
|
||||
|
||||
@@ -559,15 +559,18 @@ void amdgpu_debugfs_ring_init(struct amdgpu_device *adev,
|
||||
|
||||
int amdgpu_ring_init_mqd(struct amdgpu_ring *ring);
|
||||
|
||||
static inline u32 amdgpu_ib_get_value(struct amdgpu_ib *ib, int idx)
|
||||
static inline u32 amdgpu_ib_get_value(struct amdgpu_ib *ib, uint32_t idx)
|
||||
{
|
||||
return ib->ptr[idx];
|
||||
if (idx < ib->length_dw)
|
||||
return ib->ptr[idx];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void amdgpu_ib_set_value(struct amdgpu_ib *ib, int idx,
|
||||
static inline void amdgpu_ib_set_value(struct amdgpu_ib *ib, uint32_t idx,
|
||||
uint32_t value)
|
||||
{
|
||||
ib->ptr[idx] = value;
|
||||
if (idx < ib->length_dw)
|
||||
ib->ptr[idx] = value;
|
||||
}
|
||||
|
||||
int amdgpu_ib_get(struct amdgpu_device *adev, struct amdgpu_vm *vm,
|
||||
|
||||
@@ -1671,87 +1671,160 @@ static struct ttm_device_funcs amdgpu_bo_driver = {
|
||||
.access_memory = &amdgpu_ttm_access_memory,
|
||||
};
|
||||
|
||||
/*
|
||||
* Firmware Reservation functions
|
||||
*/
|
||||
/**
|
||||
* amdgpu_ttm_fw_reserve_vram_fini - free fw reserved vram
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
*
|
||||
* free fw reserved vram if it has been reserved.
|
||||
*/
|
||||
static void amdgpu_ttm_fw_reserve_vram_fini(struct amdgpu_device *adev)
|
||||
void amdgpu_ttm_init_vram_resv(struct amdgpu_device *adev,
|
||||
enum amdgpu_resv_region_id id,
|
||||
uint64_t offset, uint64_t size,
|
||||
bool needs_cpu_map)
|
||||
{
|
||||
amdgpu_bo_free_kernel(&adev->mman.fw_vram_usage_reserved_bo,
|
||||
NULL, &adev->mman.fw_vram_usage_va);
|
||||
struct amdgpu_vram_resv *resv;
|
||||
|
||||
if (id >= AMDGPU_RESV_MAX)
|
||||
return;
|
||||
|
||||
resv = &adev->mman.resv_region[id];
|
||||
resv->offset = offset;
|
||||
resv->size = size;
|
||||
resv->needs_cpu_map = needs_cpu_map;
|
||||
}
|
||||
|
||||
/*
|
||||
* Driver Reservation functions
|
||||
*/
|
||||
/**
|
||||
* amdgpu_ttm_drv_reserve_vram_fini - free drv reserved vram
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
*
|
||||
* free drv reserved vram if it has been reserved.
|
||||
*/
|
||||
static void amdgpu_ttm_drv_reserve_vram_fini(struct amdgpu_device *adev)
|
||||
static void amdgpu_ttm_init_fw_resv_region(struct amdgpu_device *adev)
|
||||
{
|
||||
amdgpu_bo_free_kernel(&adev->mman.drv_vram_usage_reserved_bo,
|
||||
NULL,
|
||||
&adev->mman.drv_vram_usage_va);
|
||||
uint32_t reserve_size = 0;
|
||||
|
||||
if (!adev->discovery.reserve_tmr)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Query reserved tmr size through atom firmwareinfo for Sienna_Cichlid and onwards for all
|
||||
* the use cases (IP discovery/G6 memory training/profiling/diagnostic data.etc)
|
||||
*
|
||||
* Otherwise, fallback to legacy approach to check and reserve tmr block for ip
|
||||
* discovery data and G6 memory training data respectively
|
||||
*/
|
||||
if (adev->bios)
|
||||
reserve_size =
|
||||
amdgpu_atomfirmware_get_fw_reserved_fb_size(adev);
|
||||
|
||||
if (!adev->bios &&
|
||||
(amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 3) ||
|
||||
amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 4) ||
|
||||
amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 5, 0)))
|
||||
reserve_size = max(reserve_size, (uint32_t)280 << 20);
|
||||
else if (!adev->bios &&
|
||||
amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(12, 1, 0)) {
|
||||
if (hweight32(adev->aid_mask) == 1)
|
||||
reserve_size = max(reserve_size, (uint32_t)128 << 20);
|
||||
else
|
||||
reserve_size = max(reserve_size, (uint32_t)144 << 20);
|
||||
} else if (!reserve_size)
|
||||
reserve_size = DISCOVERY_TMR_OFFSET;
|
||||
|
||||
amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_FW,
|
||||
adev->gmc.real_vram_size - reserve_size,
|
||||
reserve_size, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_ttm_fw_reserve_vram_init - create bo vram reservation from fw
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
*
|
||||
* create bo vram reservation from fw.
|
||||
*/
|
||||
static int amdgpu_ttm_fw_reserve_vram_init(struct amdgpu_device *adev)
|
||||
static void amdgpu_ttm_init_mem_train_resv_region(struct amdgpu_device *adev)
|
||||
{
|
||||
uint64_t reserve_size;
|
||||
uint64_t offset;
|
||||
|
||||
if (!adev->discovery.reserve_tmr)
|
||||
return;
|
||||
|
||||
if (!adev->bios || amdgpu_sriov_vf(adev))
|
||||
return;
|
||||
|
||||
if (!amdgpu_atomfirmware_mem_training_supported(adev))
|
||||
return;
|
||||
|
||||
reserve_size = adev->mman.resv_region[AMDGPU_RESV_FW].size;
|
||||
offset = ALIGN((adev->gmc.mc_vram_size - reserve_size - SZ_1M), SZ_1M);
|
||||
amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_MEM_TRAIN,
|
||||
offset,
|
||||
GDDR6_MEM_TRAINING_DATA_SIZE_IN_BYTES,
|
||||
false);
|
||||
}
|
||||
|
||||
static void amdgpu_ttm_init_vram_resv_regions(struct amdgpu_device *adev)
|
||||
{
|
||||
uint64_t vram_size = adev->gmc.visible_vram_size;
|
||||
|
||||
adev->mman.fw_vram_usage_va = NULL;
|
||||
adev->mman.fw_vram_usage_reserved_bo = NULL;
|
||||
/* Initialize memory reservations as required for VGA.
|
||||
* This is used for VGA emulation and pre-OS scanout buffers to
|
||||
* avoid display artifacts while transitioning between pre-OS
|
||||
* and driver.
|
||||
*/
|
||||
amdgpu_gmc_init_vga_resv_regions(adev);
|
||||
amdgpu_ttm_init_fw_resv_region(adev);
|
||||
amdgpu_ttm_init_mem_train_resv_region(adev);
|
||||
|
||||
if (adev->mman.fw_vram_usage_size == 0 ||
|
||||
adev->mman.fw_vram_usage_size > vram_size)
|
||||
return 0;
|
||||
if (adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].size > vram_size)
|
||||
adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].size = 0;
|
||||
|
||||
return amdgpu_bo_create_kernel_at(adev,
|
||||
adev->mman.fw_vram_usage_start_offset,
|
||||
adev->mman.fw_vram_usage_size,
|
||||
&adev->mman.fw_vram_usage_reserved_bo,
|
||||
&adev->mman.fw_vram_usage_va);
|
||||
if (adev->mman.resv_region[AMDGPU_RESV_DRV_VRAM_USAGE].size > vram_size)
|
||||
adev->mman.resv_region[AMDGPU_RESV_DRV_VRAM_USAGE].size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_ttm_drv_reserve_vram_init - create bo vram reservation from driver
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
*
|
||||
* create bo vram reservation from drv.
|
||||
*/
|
||||
static int amdgpu_ttm_drv_reserve_vram_init(struct amdgpu_device *adev)
|
||||
int amdgpu_ttm_mark_vram_reserved(struct amdgpu_device *adev,
|
||||
enum amdgpu_resv_region_id id)
|
||||
{
|
||||
u64 vram_size = adev->gmc.visible_vram_size;
|
||||
struct amdgpu_vram_resv *resv;
|
||||
int ret;
|
||||
|
||||
adev->mman.drv_vram_usage_va = NULL;
|
||||
adev->mman.drv_vram_usage_reserved_bo = NULL;
|
||||
if (id >= AMDGPU_RESV_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (adev->mman.drv_vram_usage_size == 0 ||
|
||||
adev->mman.drv_vram_usage_size > vram_size)
|
||||
resv = &adev->mman.resv_region[id];
|
||||
if (!resv->size)
|
||||
return 0;
|
||||
|
||||
return amdgpu_bo_create_kernel_at(adev,
|
||||
adev->mman.drv_vram_usage_start_offset,
|
||||
adev->mman.drv_vram_usage_size,
|
||||
&adev->mman.drv_vram_usage_reserved_bo,
|
||||
&adev->mman.drv_vram_usage_va);
|
||||
ret = amdgpu_bo_create_kernel_at(adev, resv->offset, resv->size,
|
||||
&resv->bo,
|
||||
resv->needs_cpu_map ? &resv->cpu_ptr : NULL);
|
||||
if (ret) {
|
||||
dev_err(adev->dev,
|
||||
"reserve vram failed: id=%d offset=0x%llx size=0x%llx ret=%d\n",
|
||||
id, resv->offset, resv->size, ret);
|
||||
memset(resv, 0, sizeof(*resv));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void amdgpu_ttm_unmark_vram_reserved(struct amdgpu_device *adev,
|
||||
enum amdgpu_resv_region_id id)
|
||||
{
|
||||
struct amdgpu_vram_resv *resv;
|
||||
|
||||
if (id >= AMDGPU_RESV_MAX)
|
||||
return;
|
||||
|
||||
resv = &adev->mman.resv_region[id];
|
||||
if (!resv->bo)
|
||||
return;
|
||||
|
||||
amdgpu_bo_free_kernel(&resv->bo, NULL,
|
||||
resv->needs_cpu_map ? &resv->cpu_ptr : NULL);
|
||||
memset(resv, 0, sizeof(*resv));
|
||||
}
|
||||
|
||||
/*
|
||||
* Reserve all regions with non-zero size. Regions whose info is not
|
||||
* yet available (e.g., fw extended region) may still be reserved
|
||||
* during runtime.
|
||||
*/
|
||||
static int amdgpu_ttm_alloc_vram_resv_regions(struct amdgpu_device *adev)
|
||||
{
|
||||
int i, r;
|
||||
|
||||
for (i = 0; i < AMDGPU_RESV_MAX; i++) {
|
||||
r = amdgpu_ttm_mark_vram_reserved(adev, i);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1770,25 +1843,23 @@ static int amdgpu_ttm_training_reserve_vram_fini(struct amdgpu_device *adev)
|
||||
struct psp_memory_training_context *ctx = &adev->psp.mem_train_ctx;
|
||||
|
||||
ctx->init = PSP_MEM_TRAIN_NOT_SUPPORT;
|
||||
amdgpu_bo_free_kernel(&ctx->c2p_bo, NULL, NULL);
|
||||
ctx->c2p_bo = NULL;
|
||||
amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_MEM_TRAIN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void amdgpu_ttm_training_data_block_init(struct amdgpu_device *adev,
|
||||
uint32_t reserve_size)
|
||||
static void amdgpu_ttm_training_data_block_init(struct amdgpu_device *adev)
|
||||
{
|
||||
struct psp_memory_training_context *ctx = &adev->psp.mem_train_ctx;
|
||||
struct amdgpu_vram_resv *resv =
|
||||
&adev->mman.resv_region[AMDGPU_RESV_MEM_TRAIN];
|
||||
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
|
||||
ctx->c2p_train_data_offset =
|
||||
ALIGN((adev->gmc.mc_vram_size - reserve_size - SZ_1M), SZ_1M);
|
||||
ctx->c2p_train_data_offset = resv->offset;
|
||||
ctx->p2c_train_data_offset =
|
||||
(adev->gmc.mc_vram_size - GDDR6_MEM_TRAINING_OFFSET);
|
||||
ctx->train_data_size =
|
||||
GDDR6_MEM_TRAINING_DATA_SIZE_IN_BYTES;
|
||||
ctx->train_data_size = resv->size;
|
||||
|
||||
DRM_DEBUG("train_data_size:%llx,p2c_train_data_offset:%llx,c2p_train_data_offset:%llx.\n",
|
||||
ctx->train_data_size,
|
||||
@@ -1796,78 +1867,6 @@ static void amdgpu_ttm_training_data_block_init(struct amdgpu_device *adev,
|
||||
ctx->c2p_train_data_offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* reserve TMR memory at the top of VRAM which holds
|
||||
* IP Discovery data and is protected by PSP.
|
||||
*/
|
||||
static int amdgpu_ttm_reserve_tmr(struct amdgpu_device *adev)
|
||||
{
|
||||
struct psp_memory_training_context *ctx = &adev->psp.mem_train_ctx;
|
||||
bool mem_train_support = false;
|
||||
uint32_t reserve_size = 0;
|
||||
int ret;
|
||||
|
||||
if (adev->bios && !amdgpu_sriov_vf(adev)) {
|
||||
if (amdgpu_atomfirmware_mem_training_supported(adev))
|
||||
mem_train_support = true;
|
||||
else
|
||||
DRM_DEBUG("memory training does not support!\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Query reserved tmr size through atom firmwareinfo for Sienna_Cichlid and onwards for all
|
||||
* the use cases (IP discovery/G6 memory training/profiling/diagnostic data.etc)
|
||||
*
|
||||
* Otherwise, fallback to legacy approach to check and reserve tmr block for ip
|
||||
* discovery data and G6 memory training data respectively
|
||||
*/
|
||||
if (adev->bios)
|
||||
reserve_size =
|
||||
amdgpu_atomfirmware_get_fw_reserved_fb_size(adev);
|
||||
|
||||
if (!adev->bios &&
|
||||
(amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 3) ||
|
||||
amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 4) ||
|
||||
amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 5, 0)))
|
||||
reserve_size = max(reserve_size, (uint32_t)280 << 20);
|
||||
else if (!adev->bios &&
|
||||
amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(12, 1, 0)) {
|
||||
if (hweight32(adev->aid_mask) == 1)
|
||||
reserve_size = max(reserve_size, (uint32_t)128 << 20);
|
||||
else
|
||||
reserve_size = max(reserve_size, (uint32_t)144 << 20);
|
||||
} else if (!reserve_size)
|
||||
reserve_size = DISCOVERY_TMR_OFFSET;
|
||||
|
||||
if (mem_train_support) {
|
||||
/* reserve vram for mem train according to TMR location */
|
||||
amdgpu_ttm_training_data_block_init(adev, reserve_size);
|
||||
ret = amdgpu_bo_create_kernel_at(adev,
|
||||
ctx->c2p_train_data_offset,
|
||||
ctx->train_data_size,
|
||||
&ctx->c2p_bo,
|
||||
NULL);
|
||||
if (ret) {
|
||||
dev_err(adev->dev, "alloc c2p_bo failed(%d)!\n", ret);
|
||||
amdgpu_ttm_training_reserve_vram_fini(adev);
|
||||
return ret;
|
||||
}
|
||||
ctx->init = PSP_MEM_TRAIN_RESERVE_SUCCESS;
|
||||
}
|
||||
|
||||
ret = amdgpu_bo_create_kernel_at(
|
||||
adev, adev->gmc.real_vram_size - reserve_size, reserve_size,
|
||||
&adev->mman.fw_reserved_memory, NULL);
|
||||
if (ret) {
|
||||
dev_err(adev->dev, "alloc tmr failed(%d)!\n", ret);
|
||||
amdgpu_bo_free_kernel(&adev->mman.fw_reserved_memory, NULL,
|
||||
NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_ttm_pools_init(struct amdgpu_device *adev)
|
||||
{
|
||||
int i;
|
||||
@@ -2115,63 +2114,18 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
|
||||
adev->gmc.visible_vram_size);
|
||||
#endif
|
||||
|
||||
/*
|
||||
*The reserved vram for firmware must be pinned to the specified
|
||||
*place on the VRAM, so reserve it early.
|
||||
*/
|
||||
r = amdgpu_ttm_fw_reserve_vram_init(adev);
|
||||
amdgpu_ttm_init_vram_resv_regions(adev);
|
||||
|
||||
r = amdgpu_ttm_alloc_vram_resv_regions(adev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/*
|
||||
* The reserved VRAM for the driver must be pinned to a specific
|
||||
* location in VRAM, so reserve it early.
|
||||
*/
|
||||
r = amdgpu_ttm_drv_reserve_vram_init(adev);
|
||||
if (r)
|
||||
return r;
|
||||
if (adev->mman.resv_region[AMDGPU_RESV_MEM_TRAIN].size) {
|
||||
struct psp_memory_training_context *ctx =
|
||||
&adev->psp.mem_train_ctx;
|
||||
|
||||
/*
|
||||
* only NAVI10 and later ASICs support IP discovery.
|
||||
* If IP discovery is enabled, a block of memory should be
|
||||
* reserved for it.
|
||||
*/
|
||||
if (adev->discovery.reserve_tmr) {
|
||||
r = amdgpu_ttm_reserve_tmr(adev);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* allocate memory as required for VGA
|
||||
* This is used for VGA emulation and pre-OS scanout buffers to
|
||||
* avoid display artifacts while transitioning between pre-OS
|
||||
* and driver.
|
||||
*/
|
||||
if (!adev->gmc.is_app_apu) {
|
||||
r = amdgpu_bo_create_kernel_at(adev, 0,
|
||||
adev->mman.stolen_vga_size,
|
||||
&adev->mman.stolen_vga_memory,
|
||||
NULL);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = amdgpu_bo_create_kernel_at(adev, adev->mman.stolen_vga_size,
|
||||
adev->mman.stolen_extended_size,
|
||||
&adev->mman.stolen_extended_memory,
|
||||
NULL);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = amdgpu_bo_create_kernel_at(adev,
|
||||
adev->mman.stolen_reserved_offset,
|
||||
adev->mman.stolen_reserved_size,
|
||||
&adev->mman.stolen_reserved_memory,
|
||||
NULL);
|
||||
if (r)
|
||||
return r;
|
||||
} else {
|
||||
DRM_DEBUG_DRIVER("Skipped stolen memory reservation\n");
|
||||
amdgpu_ttm_training_data_block_init(adev);
|
||||
ctx->init = PSP_MEM_TRAIN_RESERVE_SUCCESS;
|
||||
}
|
||||
|
||||
dev_info(adev->dev, " %uM of VRAM memory ready\n",
|
||||
@@ -2284,23 +2238,19 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev)
|
||||
amdgpu_ttm_training_reserve_vram_fini(adev);
|
||||
/* return the stolen vga memory back to VRAM */
|
||||
if (!adev->gmc.is_app_apu) {
|
||||
amdgpu_bo_free_kernel(&adev->mman.stolen_vga_memory, NULL, NULL);
|
||||
amdgpu_bo_free_kernel(&adev->mman.stolen_extended_memory, NULL, NULL);
|
||||
amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_STOLEN_VGA);
|
||||
amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_STOLEN_EXTENDED);
|
||||
/* return the FW reserved memory back to VRAM */
|
||||
amdgpu_bo_free_kernel(&adev->mman.fw_reserved_memory, NULL,
|
||||
NULL);
|
||||
amdgpu_bo_free_kernel(&adev->mman.fw_reserved_memory_extend, NULL,
|
||||
NULL);
|
||||
if (adev->mman.stolen_reserved_size)
|
||||
amdgpu_bo_free_kernel(&adev->mman.stolen_reserved_memory,
|
||||
NULL, NULL);
|
||||
amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_FW);
|
||||
amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_FW_EXTEND);
|
||||
amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_STOLEN_RESERVED);
|
||||
}
|
||||
amdgpu_bo_free_kernel(&adev->mman.sdma_access_bo, NULL,
|
||||
&adev->mman.sdma_access_ptr);
|
||||
|
||||
amdgpu_ttm_free_mmio_remap_bo(adev);
|
||||
amdgpu_ttm_fw_reserve_vram_fini(adev);
|
||||
amdgpu_ttm_drv_reserve_vram_fini(adev);
|
||||
amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_FW_VRAM_USAGE);
|
||||
amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_DRV_VRAM_USAGE);
|
||||
|
||||
if (drm_dev_enter(adev_to_drm(adev), &idx)) {
|
||||
|
||||
|
||||
@@ -59,6 +59,26 @@ struct amdgpu_ttm_buffer_entity {
|
||||
u64 gart_window_offs[2];
|
||||
};
|
||||
|
||||
enum amdgpu_resv_region_id {
|
||||
AMDGPU_RESV_STOLEN_VGA,
|
||||
AMDGPU_RESV_STOLEN_EXTENDED,
|
||||
AMDGPU_RESV_STOLEN_RESERVED,
|
||||
AMDGPU_RESV_FW,
|
||||
AMDGPU_RESV_FW_EXTEND,
|
||||
AMDGPU_RESV_FW_VRAM_USAGE,
|
||||
AMDGPU_RESV_DRV_VRAM_USAGE,
|
||||
AMDGPU_RESV_MEM_TRAIN,
|
||||
AMDGPU_RESV_MAX
|
||||
};
|
||||
|
||||
struct amdgpu_vram_resv {
|
||||
uint64_t offset;
|
||||
uint64_t size;
|
||||
struct amdgpu_bo *bo;
|
||||
void *cpu_ptr;
|
||||
bool needs_cpu_map;
|
||||
};
|
||||
|
||||
struct amdgpu_mman {
|
||||
struct ttm_device bdev;
|
||||
struct ttm_pool *ttm_pools;
|
||||
@@ -83,31 +103,9 @@ struct amdgpu_mman {
|
||||
struct amdgpu_gtt_mgr gtt_mgr;
|
||||
struct ttm_resource_manager preempt_mgr;
|
||||
|
||||
uint64_t stolen_vga_size;
|
||||
struct amdgpu_bo *stolen_vga_memory;
|
||||
uint64_t stolen_extended_size;
|
||||
struct amdgpu_bo *stolen_extended_memory;
|
||||
bool keep_stolen_vga_memory;
|
||||
|
||||
struct amdgpu_bo *stolen_reserved_memory;
|
||||
uint64_t stolen_reserved_offset;
|
||||
uint64_t stolen_reserved_size;
|
||||
|
||||
/* fw reserved memory */
|
||||
struct amdgpu_bo *fw_reserved_memory;
|
||||
struct amdgpu_bo *fw_reserved_memory_extend;
|
||||
|
||||
/* firmware VRAM reservation */
|
||||
u64 fw_vram_usage_start_offset;
|
||||
u64 fw_vram_usage_size;
|
||||
struct amdgpu_bo *fw_vram_usage_reserved_bo;
|
||||
void *fw_vram_usage_va;
|
||||
|
||||
/* driver VRAM reservation */
|
||||
u64 drv_vram_usage_start_offset;
|
||||
u64 drv_vram_usage_size;
|
||||
struct amdgpu_bo *drv_vram_usage_reserved_bo;
|
||||
void *drv_vram_usage_va;
|
||||
struct amdgpu_vram_resv resv_region[AMDGPU_RESV_MAX];
|
||||
|
||||
/* PAGE_SIZE'd BO for process memory r/w over SDMA. */
|
||||
struct amdgpu_bo *sdma_access_bo;
|
||||
@@ -175,6 +173,15 @@ void amdgpu_vram_mgr_clear_reset_blocks(struct amdgpu_device *adev);
|
||||
bool amdgpu_res_cpu_visible(struct amdgpu_device *adev,
|
||||
struct ttm_resource *res);
|
||||
|
||||
void amdgpu_ttm_init_vram_resv(struct amdgpu_device *adev,
|
||||
enum amdgpu_resv_region_id id,
|
||||
uint64_t offset, uint64_t size,
|
||||
bool needs_cpu_map);
|
||||
int amdgpu_ttm_mark_vram_reserved(struct amdgpu_device *adev,
|
||||
enum amdgpu_resv_region_id id);
|
||||
void amdgpu_ttm_unmark_vram_reserved(struct amdgpu_device *adev,
|
||||
enum amdgpu_resv_region_id id);
|
||||
|
||||
int amdgpu_ttm_init(struct amdgpu_device *adev);
|
||||
void amdgpu_ttm_fini(struct amdgpu_device *adev);
|
||||
void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev,
|
||||
|
||||
@@ -427,23 +427,14 @@ static int amdgpu_userq_map_helper(struct amdgpu_usermode_queue *queue)
|
||||
return r;
|
||||
}
|
||||
|
||||
static int amdgpu_userq_wait_for_last_fence(struct amdgpu_usermode_queue *queue)
|
||||
static void amdgpu_userq_wait_for_last_fence(struct amdgpu_usermode_queue *queue)
|
||||
{
|
||||
struct amdgpu_userq_mgr *uq_mgr = queue->userq_mgr;
|
||||
struct dma_fence *f = queue->last_fence;
|
||||
int ret = 0;
|
||||
|
||||
if (f && !dma_fence_is_signaled(f)) {
|
||||
ret = dma_fence_wait_timeout(f, true, MAX_SCHEDULE_TIMEOUT);
|
||||
if (ret <= 0) {
|
||||
drm_file_err(uq_mgr->file, "Timed out waiting for fence=%llu:%llu\n",
|
||||
f->context, f->seqno);
|
||||
queue->state = AMDGPU_USERQ_STATE_HUNG;
|
||||
return -ETIME;
|
||||
}
|
||||
}
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
return ret;
|
||||
dma_fence_wait(f, false);
|
||||
}
|
||||
|
||||
static void amdgpu_userq_cleanup(struct amdgpu_usermode_queue *queue)
|
||||
@@ -458,9 +449,10 @@ static void amdgpu_userq_cleanup(struct amdgpu_usermode_queue *queue)
|
||||
/* Drop the userq reference. */
|
||||
amdgpu_userq_buffer_vas_list_cleanup(adev, queue);
|
||||
uq_funcs->mqd_destroy(queue);
|
||||
amdgpu_userq_fence_driver_free(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);
|
||||
kfree(queue);
|
||||
@@ -799,7 +791,7 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
|
||||
|
||||
queue->doorbell_index = index;
|
||||
xa_init_flags(&queue->fence_drv_xa, XA_FLAGS_ALLOC);
|
||||
r = amdgpu_userq_fence_driver_alloc(adev, queue);
|
||||
r = amdgpu_userq_fence_driver_alloc(adev, &queue->fence_drv);
|
||||
if (r) {
|
||||
drm_file_err(uq_mgr->file, "Failed to alloc fence driver\n");
|
||||
goto free_queue;
|
||||
@@ -1023,7 +1015,8 @@ amdgpu_userq_restore_all(struct amdgpu_userq_mgr *uq_mgr)
|
||||
mutex_unlock(&uq_mgr->userq_mutex);
|
||||
|
||||
if (ret)
|
||||
drm_file_err(uq_mgr->file, "Failed to map all the queues\n");
|
||||
drm_file_err(uq_mgr->file,
|
||||
"Failed to map all the queues, restore failed ret=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1230,13 +1223,11 @@ static void amdgpu_userq_restore_worker(struct work_struct *work)
|
||||
|
||||
ret = amdgpu_userq_vm_validate(uq_mgr);
|
||||
if (ret) {
|
||||
drm_file_err(uq_mgr->file, "Failed to validate BOs to restore\n");
|
||||
drm_file_err(uq_mgr->file, "Failed to validate BOs to restore ret=%d\n", ret);
|
||||
goto put_fence;
|
||||
}
|
||||
|
||||
ret = amdgpu_userq_restore_all(uq_mgr);
|
||||
if (ret)
|
||||
drm_file_err(uq_mgr->file, "Failed to restore all queues\n");
|
||||
amdgpu_userq_restore_all(uq_mgr);
|
||||
|
||||
put_fence:
|
||||
dma_fence_put(ev_fence);
|
||||
@@ -1258,7 +1249,8 @@ amdgpu_userq_evict_all(struct amdgpu_userq_mgr *uq_mgr)
|
||||
}
|
||||
|
||||
if (ret)
|
||||
drm_file_err(uq_mgr->file, "Couldn't unmap all the queues\n");
|
||||
drm_file_err(uq_mgr->file,
|
||||
"Couldn't unmap all the queues, eviction failed ret=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1279,46 +1271,28 @@ void amdgpu_userq_reset_work(struct work_struct *work)
|
||||
amdgpu_device_gpu_recover(adev, NULL, &reset_context);
|
||||
}
|
||||
|
||||
static int
|
||||
static void
|
||||
amdgpu_userq_wait_for_signal(struct amdgpu_userq_mgr *uq_mgr)
|
||||
{
|
||||
struct amdgpu_usermode_queue *queue;
|
||||
unsigned long queue_id;
|
||||
int ret;
|
||||
|
||||
xa_for_each(&uq_mgr->userq_xa, queue_id, queue) {
|
||||
struct dma_fence *f = queue->last_fence;
|
||||
|
||||
if (!f || dma_fence_is_signaled(f))
|
||||
if (!f)
|
||||
continue;
|
||||
|
||||
ret = dma_fence_wait_timeout(f, true, msecs_to_jiffies(100));
|
||||
if (ret <= 0) {
|
||||
drm_file_err(uq_mgr->file, "Timed out waiting for fence=%llu:%llu\n",
|
||||
f->context, f->seqno);
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
dma_fence_wait(f, false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
amdgpu_userq_evict(struct amdgpu_userq_mgr *uq_mgr)
|
||||
{
|
||||
struct amdgpu_device *adev = uq_mgr->adev;
|
||||
int ret;
|
||||
|
||||
/* Wait for any pending userqueue fence work to finish */
|
||||
ret = amdgpu_userq_wait_for_signal(uq_mgr);
|
||||
if (ret)
|
||||
dev_err(adev->dev, "Not evicting userqueue, timeout waiting for work\n");
|
||||
|
||||
ret = amdgpu_userq_evict_all(uq_mgr);
|
||||
if (ret)
|
||||
dev_err(adev->dev, "Failed to evict userqueue\n");
|
||||
|
||||
amdgpu_userq_wait_for_signal(uq_mgr);
|
||||
amdgpu_userq_evict_all(uq_mgr);
|
||||
}
|
||||
|
||||
int amdgpu_userq_mgr_init(struct amdgpu_userq_mgr *userq_mgr, struct drm_file *file_priv,
|
||||
@@ -1480,17 +1454,16 @@ int amdgpu_userq_start_sched_for_enforce_isolation(struct amdgpu_device *adev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int amdgpu_userq_gem_va_unmap_validate(struct amdgpu_device *adev,
|
||||
struct amdgpu_bo_va_mapping *mapping,
|
||||
uint64_t saddr)
|
||||
void amdgpu_userq_gem_va_unmap_validate(struct amdgpu_device *adev,
|
||||
struct amdgpu_bo_va_mapping *mapping,
|
||||
uint64_t saddr)
|
||||
{
|
||||
u32 ip_mask = amdgpu_userq_get_supported_ip_mask(adev);
|
||||
struct amdgpu_bo_va *bo_va = mapping->bo_va;
|
||||
struct dma_resv *resv = bo_va->base.bo->tbo.base.resv;
|
||||
int ret = 0;
|
||||
|
||||
if (!ip_mask)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
dev_warn_once(adev->dev, "now unmapping a vital queue va:%llx\n", saddr);
|
||||
/**
|
||||
@@ -1501,14 +1474,8 @@ int amdgpu_userq_gem_va_unmap_validate(struct amdgpu_device *adev,
|
||||
* unmap is only for one kind of userq VAs, so at this point suppose
|
||||
* the eviction fence is always unsignaled.
|
||||
*/
|
||||
if (!dma_resv_test_signaled(resv, DMA_RESV_USAGE_BOOKKEEP)) {
|
||||
ret = dma_resv_wait_timeout(resv, DMA_RESV_USAGE_BOOKKEEP, true,
|
||||
MAX_SCHEDULE_TIMEOUT);
|
||||
if (ret <= 0)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
dma_resv_wait_timeout(resv, DMA_RESV_USAGE_BOOKKEEP,
|
||||
false, MAX_SCHEDULE_TIMEOUT);
|
||||
}
|
||||
|
||||
void amdgpu_userq_pre_reset(struct amdgpu_device *adev)
|
||||
|
||||
@@ -160,7 +160,7 @@ void amdgpu_userq_start_hang_detect_work(struct amdgpu_usermode_queue *queue);
|
||||
int amdgpu_userq_input_va_validate(struct amdgpu_device *adev,
|
||||
struct amdgpu_usermode_queue *queue,
|
||||
u64 addr, u64 expected_size);
|
||||
int amdgpu_userq_gem_va_unmap_validate(struct amdgpu_device *adev,
|
||||
struct amdgpu_bo_va_mapping *mapping,
|
||||
uint64_t saddr);
|
||||
void amdgpu_userq_gem_va_unmap_validate(struct amdgpu_device *adev,
|
||||
struct amdgpu_bo_va_mapping *mapping,
|
||||
uint64_t saddr);
|
||||
#endif
|
||||
|
||||
@@ -78,12 +78,15 @@ amdgpu_userq_fence_write(struct amdgpu_userq_fence_driver *fence_drv,
|
||||
}
|
||||
|
||||
int amdgpu_userq_fence_driver_alloc(struct amdgpu_device *adev,
|
||||
struct amdgpu_usermode_queue *userq)
|
||||
struct amdgpu_userq_fence_driver **fence_drv_req)
|
||||
{
|
||||
struct amdgpu_userq_fence_driver *fence_drv;
|
||||
unsigned long flags;
|
||||
int r;
|
||||
|
||||
if (!fence_drv_req)
|
||||
return -EINVAL;
|
||||
*fence_drv_req = NULL;
|
||||
|
||||
fence_drv = kzalloc_obj(*fence_drv);
|
||||
if (!fence_drv)
|
||||
return -ENOMEM;
|
||||
@@ -104,19 +107,10 @@ int amdgpu_userq_fence_driver_alloc(struct amdgpu_device *adev,
|
||||
fence_drv->context = dma_fence_context_alloc(1);
|
||||
get_task_comm(fence_drv->timeline_name, current);
|
||||
|
||||
xa_lock_irqsave(&adev->userq_xa, flags);
|
||||
r = xa_err(__xa_store(&adev->userq_xa, userq->doorbell_index,
|
||||
fence_drv, GFP_KERNEL));
|
||||
xa_unlock_irqrestore(&adev->userq_xa, flags);
|
||||
if (r)
|
||||
goto free_seq64;
|
||||
|
||||
userq->fence_drv = fence_drv;
|
||||
*fence_drv_req = fence_drv;
|
||||
|
||||
return 0;
|
||||
|
||||
free_seq64:
|
||||
amdgpu_seq64_free(adev, fence_drv->va);
|
||||
free_fence_drv:
|
||||
kfree(fence_drv);
|
||||
|
||||
@@ -144,10 +138,10 @@ void
|
||||
amdgpu_userq_fence_driver_free(struct amdgpu_usermode_queue *userq)
|
||||
{
|
||||
dma_fence_put(userq->last_fence);
|
||||
|
||||
userq->last_fence = NULL;
|
||||
amdgpu_userq_walk_and_drop_fence_drv(&userq->fence_drv_xa);
|
||||
xa_destroy(&userq->fence_drv_xa);
|
||||
/* Drop the fence_drv reference held by user queue */
|
||||
/* Drop the queue's ownership reference to fence_drv explicitly */
|
||||
amdgpu_userq_fence_driver_put(userq->fence_drv);
|
||||
}
|
||||
|
||||
@@ -187,11 +181,9 @@ void amdgpu_userq_fence_driver_destroy(struct kref *ref)
|
||||
struct amdgpu_userq_fence_driver *fence_drv = container_of(ref,
|
||||
struct amdgpu_userq_fence_driver,
|
||||
refcount);
|
||||
struct amdgpu_userq_fence_driver *xa_fence_drv;
|
||||
struct amdgpu_device *adev = fence_drv->adev;
|
||||
struct amdgpu_userq_fence *fence, *tmp;
|
||||
struct xarray *xa = &adev->userq_xa;
|
||||
unsigned long index, flags;
|
||||
unsigned long flags;
|
||||
struct dma_fence *f;
|
||||
|
||||
spin_lock_irqsave(&fence_drv->fence_list_lock, flags);
|
||||
@@ -208,12 +200,6 @@ void amdgpu_userq_fence_driver_destroy(struct kref *ref)
|
||||
}
|
||||
spin_unlock_irqrestore(&fence_drv->fence_list_lock, flags);
|
||||
|
||||
xa_lock_irqsave(xa, flags);
|
||||
xa_for_each(xa, index, xa_fence_drv)
|
||||
if (xa_fence_drv == fence_drv)
|
||||
__xa_erase(xa, index);
|
||||
xa_unlock_irqrestore(xa, flags);
|
||||
|
||||
/* Free seq64 memory */
|
||||
amdgpu_seq64_free(adev, fence_drv->va);
|
||||
kfree(fence_drv);
|
||||
|
||||
@@ -64,7 +64,7 @@ void amdgpu_userq_fence_slab_fini(void);
|
||||
void amdgpu_userq_fence_driver_get(struct amdgpu_userq_fence_driver *fence_drv);
|
||||
void amdgpu_userq_fence_driver_put(struct amdgpu_userq_fence_driver *fence_drv);
|
||||
int amdgpu_userq_fence_driver_alloc(struct amdgpu_device *adev,
|
||||
struct amdgpu_usermode_queue *userq);
|
||||
struct amdgpu_userq_fence_driver **fence_drv_req);
|
||||
void amdgpu_userq_fence_driver_free(struct amdgpu_usermode_queue *userq);
|
||||
void amdgpu_userq_fence_driver_process(struct amdgpu_userq_fence_driver *fence_drv);
|
||||
void amdgpu_userq_fence_driver_force_completion(struct amdgpu_usermode_queue *userq);
|
||||
|
||||
@@ -680,6 +680,9 @@ static int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, struct amdgpu_ib *ib,
|
||||
uint64_t addr;
|
||||
int r;
|
||||
|
||||
if (lo >= ib->length_dw || hi >= ib->length_dw)
|
||||
return -EINVAL;
|
||||
|
||||
if (index == 0xffffffff)
|
||||
index = 0;
|
||||
|
||||
|
||||
@@ -437,12 +437,9 @@ static void amdgpu_virt_add_bad_page(struct amdgpu_device *adev,
|
||||
struct eeprom_table_record bp;
|
||||
uint64_t retired_page;
|
||||
uint32_t bp_idx, bp_cnt;
|
||||
void *vram_usage_va = NULL;
|
||||
|
||||
if (adev->mman.fw_vram_usage_va)
|
||||
vram_usage_va = adev->mman.fw_vram_usage_va;
|
||||
else
|
||||
vram_usage_va = adev->mman.drv_vram_usage_va;
|
||||
void *fw_va = adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].cpu_ptr;
|
||||
void *drv_va = adev->mman.resv_region[AMDGPU_RESV_DRV_VRAM_USAGE].cpu_ptr;
|
||||
void *vram_usage_va = fw_va ? fw_va : drv_va;
|
||||
|
||||
memset(&bp, 0, sizeof(bp));
|
||||
|
||||
@@ -710,15 +707,17 @@ void amdgpu_virt_fini_data_exchange(struct amdgpu_device *adev)
|
||||
void amdgpu_virt_init_data_exchange(struct amdgpu_device *adev)
|
||||
{
|
||||
uint32_t *pfvf_data = NULL;
|
||||
void *fw_va = adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].cpu_ptr;
|
||||
void *drv_va = adev->mman.resv_region[AMDGPU_RESV_DRV_VRAM_USAGE].cpu_ptr;
|
||||
|
||||
adev->virt.fw_reserve.p_pf2vf = NULL;
|
||||
adev->virt.fw_reserve.p_vf2pf = NULL;
|
||||
adev->virt.vf2pf_update_interval_ms = 0;
|
||||
adev->virt.vf2pf_update_retry_cnt = 0;
|
||||
|
||||
if (adev->mman.fw_vram_usage_va && adev->mman.drv_vram_usage_va) {
|
||||
if (fw_va && drv_va) {
|
||||
dev_warn(adev->dev, "Currently fw_vram and drv_vram should not have values at the same time!");
|
||||
} else if (adev->mman.fw_vram_usage_va || adev->mman.drv_vram_usage_va) {
|
||||
} else if (fw_va || drv_va) {
|
||||
/* go through this logic in ip_init and reset to init workqueue*/
|
||||
amdgpu_virt_exchange_data(adev);
|
||||
|
||||
@@ -763,41 +762,43 @@ void amdgpu_virt_exchange_data(struct amdgpu_device *adev)
|
||||
uint64_t bp_block_offset = 0;
|
||||
uint32_t bp_block_size = 0;
|
||||
struct amd_sriov_msg_pf2vf_info *pf2vf_v2 = NULL;
|
||||
void *fw_va = adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].cpu_ptr;
|
||||
void *drv_va = adev->mman.resv_region[AMDGPU_RESV_DRV_VRAM_USAGE].cpu_ptr;
|
||||
|
||||
if (adev->mman.fw_vram_usage_va || adev->mman.drv_vram_usage_va) {
|
||||
if (adev->mman.fw_vram_usage_va) {
|
||||
if (fw_va || drv_va) {
|
||||
if (fw_va) {
|
||||
if (adev->virt.req_init_data_ver == GPU_CRIT_REGION_V2) {
|
||||
adev->virt.fw_reserve.p_pf2vf =
|
||||
(struct amd_sriov_msg_pf2vf_info_header *)
|
||||
(adev->mman.fw_vram_usage_va +
|
||||
(fw_va +
|
||||
adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID].offset);
|
||||
adev->virt.fw_reserve.p_vf2pf =
|
||||
(struct amd_sriov_msg_vf2pf_info_header *)
|
||||
(adev->mman.fw_vram_usage_va +
|
||||
(fw_va +
|
||||
adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_DATAEXCHANGE_TABLE_ID].offset +
|
||||
(AMD_SRIOV_MSG_SIZE_KB << 10));
|
||||
adev->virt.fw_reserve.ras_telemetry =
|
||||
(adev->mman.fw_vram_usage_va +
|
||||
(fw_va +
|
||||
adev->virt.crit_regn_tbl[AMD_SRIOV_MSG_RAS_TELEMETRY_TABLE_ID].offset);
|
||||
} else {
|
||||
adev->virt.fw_reserve.p_pf2vf =
|
||||
(struct amd_sriov_msg_pf2vf_info_header *)
|
||||
(adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_PF2VF_OFFSET_KB_V1 << 10));
|
||||
(fw_va + (AMD_SRIOV_MSG_PF2VF_OFFSET_KB_V1 << 10));
|
||||
adev->virt.fw_reserve.p_vf2pf =
|
||||
(struct amd_sriov_msg_vf2pf_info_header *)
|
||||
(adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_VF2PF_OFFSET_KB_V1 << 10));
|
||||
(fw_va + (AMD_SRIOV_MSG_VF2PF_OFFSET_KB_V1 << 10));
|
||||
adev->virt.fw_reserve.ras_telemetry =
|
||||
(adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_RAS_TELEMETRY_OFFSET_KB_V1 << 10));
|
||||
(fw_va + (AMD_SRIOV_MSG_RAS_TELEMETRY_OFFSET_KB_V1 << 10));
|
||||
}
|
||||
} else if (adev->mman.drv_vram_usage_va) {
|
||||
} else if (drv_va) {
|
||||
adev->virt.fw_reserve.p_pf2vf =
|
||||
(struct amd_sriov_msg_pf2vf_info_header *)
|
||||
(adev->mman.drv_vram_usage_va + (AMD_SRIOV_MSG_PF2VF_OFFSET_KB_V1 << 10));
|
||||
(drv_va + (AMD_SRIOV_MSG_PF2VF_OFFSET_KB_V1 << 10));
|
||||
adev->virt.fw_reserve.p_vf2pf =
|
||||
(struct amd_sriov_msg_vf2pf_info_header *)
|
||||
(adev->mman.drv_vram_usage_va + (AMD_SRIOV_MSG_VF2PF_OFFSET_KB_V1 << 10));
|
||||
(drv_va + (AMD_SRIOV_MSG_VF2PF_OFFSET_KB_V1 << 10));
|
||||
adev->virt.fw_reserve.ras_telemetry =
|
||||
(adev->mman.drv_vram_usage_va + (AMD_SRIOV_MSG_RAS_TELEMETRY_OFFSET_KB_V1 << 10));
|
||||
(drv_va + (AMD_SRIOV_MSG_RAS_TELEMETRY_OFFSET_KB_V1 << 10));
|
||||
}
|
||||
|
||||
amdgpu_virt_read_pf2vf_data(adev);
|
||||
@@ -1081,13 +1082,14 @@ int amdgpu_virt_init_critical_region(struct amdgpu_device *adev)
|
||||
}
|
||||
|
||||
/* reserved memory starts from crit region base offset with the size of 5MB */
|
||||
adev->mman.fw_vram_usage_start_offset = adev->virt.crit_regn.offset;
|
||||
adev->mman.fw_vram_usage_size = adev->virt.crit_regn.size_kb << 10;
|
||||
amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_FW_VRAM_USAGE,
|
||||
adev->virt.crit_regn.offset,
|
||||
adev->virt.crit_regn.size_kb << 10, true);
|
||||
dev_info(adev->dev,
|
||||
"critical region v%d requested to reserve memory start at %08llx with %llu KB.\n",
|
||||
init_data_hdr->version,
|
||||
adev->mman.fw_vram_usage_start_offset,
|
||||
adev->mman.fw_vram_usage_size >> 10);
|
||||
adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].offset,
|
||||
adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].size >> 10);
|
||||
|
||||
adev->virt.is_dynamic_crit_regn_enabled = true;
|
||||
|
||||
|
||||
@@ -1978,7 +1978,6 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
|
||||
struct amdgpu_bo_va_mapping *mapping;
|
||||
struct amdgpu_vm *vm = bo_va->base.vm;
|
||||
bool valid = true;
|
||||
int r;
|
||||
|
||||
saddr /= AMDGPU_GPU_PAGE_SIZE;
|
||||
|
||||
@@ -2003,12 +2002,8 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
|
||||
* during user requests GEM unmap IOCTL except for forcing the unmap
|
||||
* from user space.
|
||||
*/
|
||||
if (unlikely(atomic_read(&bo_va->userq_va_mapped) > 0)) {
|
||||
r = amdgpu_userq_gem_va_unmap_validate(adev, mapping, saddr);
|
||||
if (unlikely(r == -EBUSY))
|
||||
dev_warn_once(adev->dev,
|
||||
"Attempt to unmap an active userq buffer\n");
|
||||
}
|
||||
if (unlikely(atomic_read(&bo_va->userq_va_mapped) > 0))
|
||||
amdgpu_userq_gem_va_unmap_validate(adev, mapping, saddr);
|
||||
|
||||
list_del(&mapping->list);
|
||||
amdgpu_vm_it_remove(mapping, &vm->va);
|
||||
@@ -2954,6 +2949,50 @@ int amdgpu_vm_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_vm_lock_by_pasid - return an amdgpu_vm and its root bo from a pasid, if possible.
|
||||
* @adev: amdgpu device pointer
|
||||
* @root: root BO of the VM
|
||||
* @pasid: PASID of the VM
|
||||
* The caller needs to unreserve and unref the root bo on success.
|
||||
*/
|
||||
struct amdgpu_vm *amdgpu_vm_lock_by_pasid(struct amdgpu_device *adev,
|
||||
struct amdgpu_bo **root, u32 pasid)
|
||||
{
|
||||
unsigned long irqflags;
|
||||
struct amdgpu_vm *vm;
|
||||
int r;
|
||||
|
||||
xa_lock_irqsave(&adev->vm_manager.pasids, irqflags);
|
||||
vm = xa_load(&adev->vm_manager.pasids, pasid);
|
||||
*root = vm ? amdgpu_bo_ref(vm->root.bo) : NULL;
|
||||
xa_unlock_irqrestore(&adev->vm_manager.pasids, irqflags);
|
||||
|
||||
if (!*root)
|
||||
return NULL;
|
||||
|
||||
r = amdgpu_bo_reserve(*root, true);
|
||||
if (r)
|
||||
goto error_unref;
|
||||
|
||||
/* Double check that the VM still exists */
|
||||
xa_lock_irqsave(&adev->vm_manager.pasids, irqflags);
|
||||
vm = xa_load(&adev->vm_manager.pasids, pasid);
|
||||
if (vm && vm->root.bo != *root)
|
||||
vm = NULL;
|
||||
xa_unlock_irqrestore(&adev->vm_manager.pasids, irqflags);
|
||||
if (!vm)
|
||||
goto error_unlock;
|
||||
|
||||
return vm;
|
||||
error_unlock:
|
||||
amdgpu_bo_unreserve(*root);
|
||||
|
||||
error_unref:
|
||||
amdgpu_bo_unref(root);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_vm_handle_fault - graceful handling of VM faults.
|
||||
* @adev: amdgpu device pointer
|
||||
@@ -2969,50 +3008,29 @@ int amdgpu_vm_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
|
||||
* shouldn't be reported any more.
|
||||
*/
|
||||
bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, u32 pasid,
|
||||
u32 vmid, u32 node_id, uint64_t addr, uint64_t ts,
|
||||
bool write_fault)
|
||||
u32 vmid, u32 node_id, uint64_t addr,
|
||||
uint64_t ts, bool write_fault)
|
||||
{
|
||||
bool is_compute_context = false;
|
||||
struct amdgpu_bo *root;
|
||||
unsigned long irqflags;
|
||||
uint64_t value, flags;
|
||||
struct amdgpu_vm *vm;
|
||||
int r;
|
||||
|
||||
xa_lock_irqsave(&adev->vm_manager.pasids, irqflags);
|
||||
vm = xa_load(&adev->vm_manager.pasids, pasid);
|
||||
if (vm) {
|
||||
root = amdgpu_bo_ref(vm->root.bo);
|
||||
is_compute_context = vm->is_compute_context;
|
||||
} else {
|
||||
root = NULL;
|
||||
}
|
||||
xa_unlock_irqrestore(&adev->vm_manager.pasids, irqflags);
|
||||
|
||||
if (!root)
|
||||
vm = amdgpu_vm_lock_by_pasid(adev, &root, pasid);
|
||||
if (!vm)
|
||||
return false;
|
||||
|
||||
is_compute_context = vm->is_compute_context;
|
||||
|
||||
if (is_compute_context && !svm_range_restore_pages(adev, pasid, vmid,
|
||||
node_id, addr >> PAGE_SHIFT, ts, write_fault)) {
|
||||
amdgpu_bo_unreserve(root);
|
||||
amdgpu_bo_unref(&root);
|
||||
return true;
|
||||
}
|
||||
|
||||
addr /= AMDGPU_GPU_PAGE_SIZE;
|
||||
|
||||
r = amdgpu_bo_reserve(root, true);
|
||||
if (r)
|
||||
goto error_unref;
|
||||
|
||||
/* Double check that the VM still exists */
|
||||
xa_lock_irqsave(&adev->vm_manager.pasids, irqflags);
|
||||
vm = xa_load(&adev->vm_manager.pasids, pasid);
|
||||
if (vm && vm->root.bo != root)
|
||||
vm = NULL;
|
||||
xa_unlock_irqrestore(&adev->vm_manager.pasids, irqflags);
|
||||
if (!vm)
|
||||
goto error_unlock;
|
||||
|
||||
flags = AMDGPU_PTE_VALID | AMDGPU_PTE_SNOOPED |
|
||||
AMDGPU_PTE_SYSTEM;
|
||||
|
||||
@@ -3051,7 +3069,6 @@ bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, u32 pasid,
|
||||
if (r < 0)
|
||||
dev_err(adev->dev, "Can't handle page fault (%d)\n", r);
|
||||
|
||||
error_unref:
|
||||
amdgpu_bo_unref(&root);
|
||||
|
||||
return false;
|
||||
|
||||
@@ -592,6 +592,9 @@ bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, u32 pasid,
|
||||
u32 vmid, u32 node_id, uint64_t addr, uint64_t ts,
|
||||
bool write_fault);
|
||||
|
||||
struct amdgpu_vm *amdgpu_vm_lock_by_pasid(struct amdgpu_device *adev,
|
||||
struct amdgpu_bo **root, u32 pasid);
|
||||
|
||||
void amdgpu_vm_set_task_info(struct amdgpu_vm *vm);
|
||||
|
||||
void amdgpu_vm_move_to_lru_tail(struct amdgpu_device *adev,
|
||||
|
||||
@@ -181,6 +181,7 @@ int amdgpu_xcp_init(struct amdgpu_xcp_mgr *xcp_mgr, int num_xcps, int mode)
|
||||
}
|
||||
|
||||
xcp_mgr->num_xcps = num_xcps;
|
||||
xcp_mgr->mem_alloc_mode = AMDGPU_PARTITION_MEM_CAPPING_EVEN;
|
||||
amdgpu_xcp_update_partition_sched_list(adev);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -132,6 +132,8 @@ struct amdgpu_xcp_mgr {
|
||||
struct amdgpu_xcp_cfg *xcp_cfg;
|
||||
uint32_t supp_xcp_modes;
|
||||
uint32_t avail_xcp_modes;
|
||||
/* used to determin KFD memory alloc mode for each partition */
|
||||
uint32_t mem_alloc_mode;
|
||||
};
|
||||
|
||||
struct amdgpu_xcp_mgr_funcs {
|
||||
|
||||
@@ -6502,14 +6502,14 @@ static int gfx_v11_0_eop_irq(struct amdgpu_device *adev,
|
||||
DRM_DEBUG("IH: CP EOP\n");
|
||||
|
||||
if (adev->enable_mes && doorbell_offset) {
|
||||
struct amdgpu_userq_fence_driver *fence_drv = NULL;
|
||||
struct xarray *xa = &adev->userq_xa;
|
||||
struct amdgpu_usermode_queue *queue;
|
||||
struct xarray *xa = &adev->userq_doorbell_xa;
|
||||
unsigned long flags;
|
||||
|
||||
xa_lock_irqsave(xa, flags);
|
||||
fence_drv = xa_load(xa, doorbell_offset);
|
||||
if (fence_drv)
|
||||
amdgpu_userq_fence_driver_process(fence_drv);
|
||||
queue = xa_load(xa, doorbell_offset);
|
||||
if (queue)
|
||||
amdgpu_userq_fence_driver_process(queue->fence_drv);
|
||||
xa_unlock_irqrestore(xa, flags);
|
||||
} else {
|
||||
me_id = (entry->ring_id & 0x0c) >> 2;
|
||||
|
||||
@@ -4854,14 +4854,14 @@ static int gfx_v12_0_eop_irq(struct amdgpu_device *adev,
|
||||
DRM_DEBUG("IH: CP EOP\n");
|
||||
|
||||
if (adev->enable_mes && doorbell_offset) {
|
||||
struct amdgpu_userq_fence_driver *fence_drv = NULL;
|
||||
struct xarray *xa = &adev->userq_xa;
|
||||
struct xarray *xa = &adev->userq_doorbell_xa;
|
||||
struct amdgpu_usermode_queue *queue;
|
||||
unsigned long flags;
|
||||
|
||||
xa_lock_irqsave(xa, flags);
|
||||
fence_drv = xa_load(xa, doorbell_offset);
|
||||
if (fence_drv)
|
||||
amdgpu_userq_fence_driver_process(fence_drv);
|
||||
queue = xa_load(xa, doorbell_offset);
|
||||
if (queue)
|
||||
amdgpu_userq_fence_driver_process(queue->fence_drv);
|
||||
xa_unlock_irqrestore(xa, flags);
|
||||
} else {
|
||||
me_id = (entry->ring_id & 0x0c) >> 2;
|
||||
|
||||
@@ -3643,14 +3643,15 @@ static int gfx_v12_1_eop_irq(struct amdgpu_device *adev,
|
||||
DRM_DEBUG("IH: CP EOP\n");
|
||||
|
||||
if (adev->enable_mes && doorbell_offset) {
|
||||
struct amdgpu_userq_fence_driver *fence_drv = NULL;
|
||||
struct xarray *xa = &adev->userq_xa;
|
||||
struct xarray *xa = &adev->userq_doorbell_xa;
|
||||
struct amdgpu_usermode_queue *queue;
|
||||
unsigned long flags;
|
||||
|
||||
xa_lock_irqsave(xa, flags);
|
||||
fence_drv = xa_load(xa, doorbell_offset);
|
||||
if (fence_drv)
|
||||
amdgpu_userq_fence_driver_process(fence_drv);
|
||||
queue = xa_load(xa, doorbell_offset);
|
||||
if (queue)
|
||||
amdgpu_userq_fence_driver_process(queue->fence_drv);
|
||||
|
||||
xa_unlock_irqrestore(xa, flags);
|
||||
} else {
|
||||
me_id = (entry->ring_id & 0x0c) >> 2;
|
||||
|
||||
@@ -860,8 +860,6 @@ static int gmc_v10_0_sw_init(struct amdgpu_ip_block *ip_block)
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
amdgpu_gmc_get_vbios_allocations(adev);
|
||||
|
||||
/* Memory manager */
|
||||
r = amdgpu_bo_init(adev);
|
||||
if (r)
|
||||
|
||||
@@ -834,8 +834,6 @@ static int gmc_v11_0_sw_init(struct amdgpu_ip_block *ip_block)
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
amdgpu_gmc_get_vbios_allocations(adev);
|
||||
|
||||
/* Memory manager */
|
||||
r = amdgpu_bo_init(adev);
|
||||
if (r)
|
||||
|
||||
@@ -924,8 +924,6 @@ static int gmc_v12_0_sw_init(struct amdgpu_ip_block *ip_block)
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
amdgpu_gmc_get_vbios_allocations(adev);
|
||||
|
||||
#ifdef HAVE_ACPI_DEV_GET_FIRST_MATCH_DEV
|
||||
if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(12, 1, 0)) {
|
||||
r = amdgpu_gmc_init_mem_ranges(adev);
|
||||
|
||||
@@ -854,8 +854,6 @@ static int gmc_v6_0_sw_init(struct amdgpu_ip_block *ip_block)
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
amdgpu_gmc_get_vbios_allocations(adev);
|
||||
|
||||
r = amdgpu_bo_init(adev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
@@ -1034,8 +1034,6 @@ static int gmc_v7_0_sw_init(struct amdgpu_ip_block *ip_block)
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
amdgpu_gmc_get_vbios_allocations(adev);
|
||||
|
||||
/* Memory manager */
|
||||
r = amdgpu_bo_init(adev);
|
||||
if (r)
|
||||
|
||||
@@ -1149,8 +1149,6 @@ static int gmc_v8_0_sw_init(struct amdgpu_ip_block *ip_block)
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
amdgpu_gmc_get_vbios_allocations(adev);
|
||||
|
||||
/* Memory manager */
|
||||
r = amdgpu_bo_init(adev);
|
||||
if (r)
|
||||
|
||||
@@ -2010,8 +2010,6 @@ static int gmc_v9_0_sw_init(struct amdgpu_ip_block *ip_block)
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
amdgpu_gmc_get_vbios_allocations(adev);
|
||||
|
||||
if (amdgpu_is_multi_aid(adev)) {
|
||||
r = amdgpu_gmc_init_mem_ranges(adev);
|
||||
if (r)
|
||||
|
||||
@@ -1662,16 +1662,16 @@ static int sdma_v6_0_process_fence_irq(struct amdgpu_device *adev,
|
||||
u32 doorbell_offset = entry->src_data[0];
|
||||
|
||||
if (adev->enable_mes && doorbell_offset) {
|
||||
struct amdgpu_userq_fence_driver *fence_drv = NULL;
|
||||
struct xarray *xa = &adev->userq_xa;
|
||||
struct amdgpu_usermode_queue *queue;
|
||||
struct xarray *xa = &adev->userq_doorbell_xa;
|
||||
unsigned long flags;
|
||||
|
||||
doorbell_offset >>= SDMA0_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT;
|
||||
|
||||
xa_lock_irqsave(xa, flags);
|
||||
fence_drv = xa_load(xa, doorbell_offset);
|
||||
if (fence_drv)
|
||||
amdgpu_userq_fence_driver_process(fence_drv);
|
||||
queue = xa_load(xa, doorbell_offset);
|
||||
if (queue)
|
||||
amdgpu_userq_fence_driver_process(queue->fence_drv);
|
||||
xa_unlock_irqrestore(xa, flags);
|
||||
}
|
||||
|
||||
|
||||
@@ -1594,16 +1594,16 @@ static int sdma_v7_0_process_fence_irq(struct amdgpu_device *adev,
|
||||
u32 doorbell_offset = entry->src_data[0];
|
||||
|
||||
if (adev->enable_mes && doorbell_offset) {
|
||||
struct amdgpu_userq_fence_driver *fence_drv = NULL;
|
||||
struct xarray *xa = &adev->userq_xa;
|
||||
struct xarray *xa = &adev->userq_doorbell_xa;
|
||||
struct amdgpu_usermode_queue *queue;
|
||||
unsigned long flags;
|
||||
|
||||
doorbell_offset >>= SDMA0_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT;
|
||||
|
||||
xa_lock_irqsave(xa, flags);
|
||||
fence_drv = xa_load(xa, doorbell_offset);
|
||||
if (fence_drv)
|
||||
amdgpu_userq_fence_driver_process(fence_drv);
|
||||
queue = xa_load(xa, doorbell_offset);
|
||||
if (queue)
|
||||
amdgpu_userq_fence_driver_process(queue->fence_drv);
|
||||
xa_unlock_irqrestore(xa, flags);
|
||||
}
|
||||
|
||||
|
||||
@@ -1909,7 +1909,7 @@ static int vcn_v3_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
|
||||
struct ttm_operation_ctx ctx = { false, false };
|
||||
struct amdgpu_device *adev = p->adev;
|
||||
struct amdgpu_bo_va_mapping *map;
|
||||
uint32_t *msg, num_buffers;
|
||||
uint32_t *msg, num_buffers, len_dw;
|
||||
struct amdgpu_bo *bo;
|
||||
uint64_t start, end;
|
||||
unsigned int i;
|
||||
@@ -1930,6 +1930,11 @@ static int vcn_v3_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (end - addr < 16) {
|
||||
DRM_ERROR("VCN messages must be at least 4 DWORDs!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bo->flags |= AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
|
||||
amdgpu_bo_placement_from_domain(bo, bo->allowed_domains);
|
||||
r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
|
||||
@@ -1946,8 +1951,8 @@ static int vcn_v3_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
|
||||
|
||||
msg = ptr + addr - start;
|
||||
|
||||
/* Check length */
|
||||
if (msg[1] > end - addr) {
|
||||
DRM_ERROR("VCN message header does not fit in BO!\n");
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -1955,7 +1960,16 @@ static int vcn_v3_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
|
||||
if (msg[3] != RDECODE_MSG_CREATE)
|
||||
goto out;
|
||||
|
||||
len_dw = msg[1] / 4;
|
||||
num_buffers = msg[2];
|
||||
|
||||
/* Verify that all indices fit within the claimed length. Each index is 4 DWORDs */
|
||||
if (num_buffers > len_dw || 6 + num_buffers * 4 > len_dw) {
|
||||
DRM_ERROR("VCN message has too many buffers!\n");
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0, msg = &msg[6]; i < num_buffers; ++i, msg += 4) {
|
||||
uint32_t offset, size, *create;
|
||||
|
||||
@@ -1965,14 +1979,15 @@ static int vcn_v3_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
|
||||
offset = msg[1];
|
||||
size = msg[2];
|
||||
|
||||
if (offset + size > end) {
|
||||
if (size < 4 || offset + size > end - addr) {
|
||||
DRM_ERROR("VCN message buffer exceeds BO bounds!\n");
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
create = ptr + addr + offset - start;
|
||||
|
||||
/* H246, HEVC and VP9 can run on any instance */
|
||||
/* H264, HEVC and VP9 can run on any instance */
|
||||
if (create[0] == 0x7 || create[0] == 0x10 || create[0] == 0x11)
|
||||
continue;
|
||||
|
||||
|
||||
@@ -1826,7 +1826,7 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
|
||||
struct ttm_operation_ctx ctx = { false, false };
|
||||
struct amdgpu_device *adev = p->adev;
|
||||
struct amdgpu_bo_va_mapping *map;
|
||||
uint32_t *msg, num_buffers;
|
||||
uint32_t *msg, num_buffers, len_dw;
|
||||
struct amdgpu_bo *bo;
|
||||
uint64_t start, end;
|
||||
unsigned int i;
|
||||
@@ -1847,6 +1847,11 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (end - addr < 16) {
|
||||
DRM_ERROR("VCN messages must be at least 4 DWORDs!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bo->flags |= AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
|
||||
amdgpu_bo_placement_from_domain(bo, bo->allowed_domains);
|
||||
r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
|
||||
@@ -1863,8 +1868,8 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
|
||||
|
||||
msg = ptr + addr - start;
|
||||
|
||||
/* Check length */
|
||||
if (msg[1] > end - addr) {
|
||||
DRM_ERROR("VCN message header does not fit in BO!\n");
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -1872,7 +1877,16 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
|
||||
if (msg[3] != RDECODE_MSG_CREATE)
|
||||
goto out;
|
||||
|
||||
len_dw = msg[1] / 4;
|
||||
num_buffers = msg[2];
|
||||
|
||||
/* Verify that all indices fit within the claimed length. Each index is 4 DWORDs */
|
||||
if (num_buffers > len_dw || 6 + num_buffers * 4 > len_dw) {
|
||||
DRM_ERROR("VCN message has too many buffers!\n");
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0, msg = &msg[6]; i < num_buffers; ++i, msg += 4) {
|
||||
uint32_t offset, size, *create;
|
||||
|
||||
@@ -1882,7 +1896,8 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
|
||||
offset = msg[1];
|
||||
size = msg[2];
|
||||
|
||||
if (offset + size > end) {
|
||||
if (size < 4 || offset + size > end - addr) {
|
||||
DRM_ERROR("VCN message buffer exceeds BO bounds!\n");
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -1913,9 +1928,10 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
|
||||
static int vcn_v4_0_enc_find_ib_param(struct amdgpu_ib *ib, uint32_t id, int start)
|
||||
{
|
||||
int i;
|
||||
uint32_t len;
|
||||
|
||||
for (i = start; i < ib->length_dw && ib->ptr[i] >= 8; i += ib->ptr[i] / 4) {
|
||||
if (ib->ptr[i + 1] == id)
|
||||
for (i = start; (len = amdgpu_ib_get_value(ib, i)) >= 8; i += len / 4) {
|
||||
if (amdgpu_ib_get_value(ib, i + 1) == id)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
@@ -1926,8 +1942,6 @@ static int vcn_v4_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p,
|
||||
struct amdgpu_ib *ib)
|
||||
{
|
||||
struct amdgpu_ring *ring = amdgpu_job_ring(job);
|
||||
struct amdgpu_vcn_decode_buffer *decode_buffer;
|
||||
uint64_t addr;
|
||||
uint32_t val;
|
||||
int idx = 0, sidx;
|
||||
|
||||
@@ -1938,20 +1952,22 @@ static int vcn_v4_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p,
|
||||
while ((idx = vcn_v4_0_enc_find_ib_param(ib, RADEON_VCN_ENGINE_INFO, idx)) >= 0) {
|
||||
val = amdgpu_ib_get_value(ib, idx + 2); /* RADEON_VCN_ENGINE_TYPE */
|
||||
if (val == RADEON_VCN_ENGINE_TYPE_DECODE) {
|
||||
decode_buffer = (struct amdgpu_vcn_decode_buffer *)&ib->ptr[idx + 6];
|
||||
uint32_t valid_buf_flag = amdgpu_ib_get_value(ib, idx + 6);
|
||||
uint64_t msg_buffer_addr;
|
||||
|
||||
if (!(decode_buffer->valid_buf_flag & 0x1))
|
||||
if (!(valid_buf_flag & 0x1))
|
||||
return 0;
|
||||
|
||||
addr = ((u64)decode_buffer->msg_buffer_address_hi) << 32 |
|
||||
decode_buffer->msg_buffer_address_lo;
|
||||
return vcn_v4_0_dec_msg(p, job, addr);
|
||||
msg_buffer_addr = ((u64)amdgpu_ib_get_value(ib, idx + 7)) << 32 |
|
||||
amdgpu_ib_get_value(ib, idx + 8);
|
||||
return vcn_v4_0_dec_msg(p, job, msg_buffer_addr);
|
||||
} else if (val == RADEON_VCN_ENGINE_TYPE_ENCODE) {
|
||||
sidx = vcn_v4_0_enc_find_ib_param(ib, RENCODE_IB_PARAM_SESSION_INIT, idx);
|
||||
if (sidx >= 0 && ib->ptr[sidx + 2] == RENCODE_ENCODE_STANDARD_AV1)
|
||||
if (sidx >= 0 &&
|
||||
amdgpu_ib_get_value(ib, sidx + 2) == RENCODE_ENCODE_STANDARD_AV1)
|
||||
return vcn_v4_0_limit_sched(p, job);
|
||||
}
|
||||
idx += ib->ptr[idx] / 4;
|
||||
idx += amdgpu_ib_get_value(ib, idx) / 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -689,7 +689,8 @@ void kfd_procfs_del_queue(struct queue *q)
|
||||
int kfd_process_create_wq(void)
|
||||
{
|
||||
if (!kfd_process_wq)
|
||||
kfd_process_wq = alloc_workqueue("kfd_process_wq", 0, 0);
|
||||
kfd_process_wq = alloc_workqueue("kfd_process_wq", WQ_UNBOUND,
|
||||
0);
|
||||
if (!kfd_restore_wq)
|
||||
kfd_restore_wq = alloc_ordered_workqueue("kfd_restore_wq",
|
||||
WQ_FREEZABLE);
|
||||
|
||||
@@ -572,7 +572,7 @@ static void schedule_dc_vmin_vmax(struct amdgpu_device *adev,
|
||||
offload_work->stream = stream;
|
||||
offload_work->adjust = adjust_copy;
|
||||
|
||||
queue_work(system_wq, &offload_work->work);
|
||||
queue_work(system_percpu_wq, &offload_work->work);
|
||||
}
|
||||
|
||||
static void dm_vupdate_high_irq(void *interrupt_params)
|
||||
@@ -3833,6 +3833,66 @@ static struct drm_mode_config_helper_funcs amdgpu_dm_mode_config_helperfuncs = {
|
||||
.atomic_commit_setup = amdgpu_dm_atomic_setup_commit,
|
||||
};
|
||||
|
||||
#define DDC_MANUFACTURERNAME_SAMSUNG 0x2D4C
|
||||
|
||||
static void dm_set_panel_type(struct amdgpu_dm_connector *aconnector)
|
||||
{
|
||||
struct drm_connector *connector = &aconnector->base;
|
||||
struct drm_display_info *display_info = &connector->display_info;
|
||||
struct dc_link *link = aconnector->dc_link;
|
||||
struct amdgpu_device *adev;
|
||||
|
||||
adev = drm_to_adev(connector->dev);
|
||||
|
||||
link->panel_type = PANEL_TYPE_NONE;
|
||||
|
||||
switch (display_info->amd_vsdb.panel_type) {
|
||||
case AMD_VSDB_PANEL_TYPE_OLED:
|
||||
link->panel_type = PANEL_TYPE_OLED;
|
||||
break;
|
||||
case AMD_VSDB_PANEL_TYPE_MINILED:
|
||||
link->panel_type = PANEL_TYPE_MINILED;
|
||||
break;
|
||||
}
|
||||
|
||||
/* If VSDB didn't determine panel type, check DPCD ext caps */
|
||||
if (link->panel_type == PANEL_TYPE_NONE) {
|
||||
if (link->dpcd_sink_ext_caps.bits.miniled == 1)
|
||||
link->panel_type = PANEL_TYPE_MINILED;
|
||||
if (link->dpcd_sink_ext_caps.bits.oled == 1)
|
||||
link->panel_type = PANEL_TYPE_OLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: get panel type from DID2 that has device technology field
|
||||
* to specify if it's OLED or not. But we need to wait for DID2
|
||||
* support in DC and EDID parser to be able to use it here.
|
||||
*/
|
||||
|
||||
if (link->panel_type == PANEL_TYPE_NONE) {
|
||||
struct drm_amd_vsdb_info *vsdb = &display_info->amd_vsdb;
|
||||
u32 lum1_max = vsdb->luminance_range1.max_luminance;
|
||||
u32 lum2_max = vsdb->luminance_range2.max_luminance;
|
||||
|
||||
if (vsdb->version && link->local_sink &&
|
||||
link->local_sink->edid_caps.manufacturer_id ==
|
||||
DDC_MANUFACTURERNAME_SAMSUNG &&
|
||||
lum1_max >= ((lum2_max * 3) / 2))
|
||||
link->panel_type = PANEL_TYPE_MINILED;
|
||||
}
|
||||
|
||||
if (link->panel_type == PANEL_TYPE_OLED)
|
||||
drm_object_property_set_value(&connector->base,
|
||||
adev_to_drm(adev)->mode_config.panel_type_property,
|
||||
DRM_MODE_PANEL_TYPE_OLED);
|
||||
else
|
||||
drm_object_property_set_value(&connector->base,
|
||||
adev_to_drm(adev)->mode_config.panel_type_property,
|
||||
DRM_MODE_PANEL_TYPE_UNKNOWN);
|
||||
|
||||
drm_dbg_kms(aconnector->base.dev, "Panel type: %d\n", link->panel_type);
|
||||
}
|
||||
|
||||
static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
|
||||
{
|
||||
const struct drm_panel_backlight_quirk *panel_backlight_quirk;
|
||||
@@ -3854,10 +3914,6 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
|
||||
caps->ext_caps = &aconnector->dc_link->dpcd_sink_ext_caps;
|
||||
caps->aux_support = false;
|
||||
|
||||
drm_object_property_set_value(&conn_base->base,
|
||||
adev_to_drm(adev)->mode_config.panel_type_property,
|
||||
caps->ext_caps->bits.oled ? DRM_MODE_PANEL_TYPE_OLED : DRM_MODE_PANEL_TYPE_UNKNOWN);
|
||||
|
||||
if (caps->ext_caps->bits.oled == 1
|
||||
/*
|
||||
* ||
|
||||
@@ -4031,6 +4087,7 @@ void amdgpu_dm_update_connector_after_detect(
|
||||
|
||||
amdgpu_dm_update_freesync_caps(connector, aconnector->drm_edid);
|
||||
update_connector_ext_caps(aconnector);
|
||||
dm_set_panel_type(aconnector);
|
||||
} else {
|
||||
hdmi_cec_unset_edid(aconnector);
|
||||
drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux);
|
||||
@@ -4211,7 +4268,7 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector)
|
||||
dc_sink_retain(aconnector->hdmi_prev_sink);
|
||||
|
||||
/* Schedule delayed detection. */
|
||||
if (mod_delayed_work(system_wq,
|
||||
if (mod_delayed_work(system_percpu_wq,
|
||||
&aconnector->hdmi_hpd_debounce_work,
|
||||
msecs_to_jiffies(aconnector->hdmi_hpd_debounce_delay_ms)))
|
||||
drm_dbg_kms(dev, "HDMI HPD: Re-scheduled debounce work\n");
|
||||
@@ -11142,8 +11199,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
if (!adev->in_suspend) {
|
||||
/* return the stolen vga memory back to VRAM */
|
||||
if (!adev->mman.keep_stolen_vga_memory)
|
||||
amdgpu_bo_free_kernel(&adev->mman.stolen_vga_memory, NULL, NULL);
|
||||
amdgpu_bo_free_kernel(&adev->mman.stolen_extended_memory, NULL, NULL);
|
||||
amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_STOLEN_VGA);
|
||||
amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_STOLEN_EXTENDED);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -13155,56 +13212,15 @@ static void parse_edid_displayid_vrr(struct drm_connector *connector,
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_amd_vsdb(struct amdgpu_dm_connector *aconnector,
|
||||
const struct edid *edid, struct amdgpu_hdmi_vsdb_info *vsdb_info)
|
||||
static int get_amd_vsdb(struct amdgpu_dm_connector *aconnector,
|
||||
struct amdgpu_hdmi_vsdb_info *vsdb_info)
|
||||
{
|
||||
u8 *edid_ext = NULL;
|
||||
int i;
|
||||
int j = 0;
|
||||
int total_ext_block_len;
|
||||
struct drm_connector *connector = &aconnector->base;
|
||||
|
||||
if (edid == NULL || edid->extensions == 0)
|
||||
return -ENODEV;
|
||||
vsdb_info->replay_mode = connector->display_info.amd_vsdb.replay_mode;
|
||||
vsdb_info->amd_vsdb_version = connector->display_info.amd_vsdb.version;
|
||||
|
||||
/* Find DisplayID extension */
|
||||
for (i = 0; i < edid->extensions; i++) {
|
||||
edid_ext = (void *)(edid + (i + 1));
|
||||
if (edid_ext[0] == DISPLAYID_EXT)
|
||||
break;
|
||||
}
|
||||
|
||||
total_ext_block_len = EDID_LENGTH * edid->extensions;
|
||||
while (j < total_ext_block_len - sizeof(struct amd_vsdb_block)) {
|
||||
struct amd_vsdb_block *amd_vsdb = (struct amd_vsdb_block *)&edid_ext[j];
|
||||
unsigned int ieeeId = (amd_vsdb->ieee_id[2] << 16) | (amd_vsdb->ieee_id[1] << 8) | (amd_vsdb->ieee_id[0]);
|
||||
|
||||
if (ieeeId == HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_IEEE_REGISTRATION_ID &&
|
||||
amd_vsdb->version == HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_VERSION_3) {
|
||||
u8 panel_type;
|
||||
vsdb_info->replay_mode = (amd_vsdb->feature_caps & AMD_VSDB_VERSION_3_FEATURECAP_REPLAYMODE) ? true : false;
|
||||
vsdb_info->amd_vsdb_version = HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_VERSION_3;
|
||||
drm_dbg_kms(aconnector->base.dev, "Panel supports Replay Mode: %d\n", vsdb_info->replay_mode);
|
||||
panel_type = (amd_vsdb->color_space_eotf_support & AMD_VDSB_VERSION_3_PANEL_TYPE_MASK) >> AMD_VDSB_VERSION_3_PANEL_TYPE_SHIFT;
|
||||
switch (panel_type) {
|
||||
case AMD_VSDB_PANEL_TYPE_OLED:
|
||||
aconnector->dc_link->panel_type = PANEL_TYPE_OLED;
|
||||
break;
|
||||
case AMD_VSDB_PANEL_TYPE_MINILED:
|
||||
aconnector->dc_link->panel_type = PANEL_TYPE_MINILED;
|
||||
break;
|
||||
default:
|
||||
aconnector->dc_link->panel_type = PANEL_TYPE_NONE;
|
||||
break;
|
||||
}
|
||||
drm_dbg_kms(aconnector->base.dev, "Panel type: %d\n",
|
||||
aconnector->dc_link->panel_type);
|
||||
|
||||
return true;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
|
||||
return false;
|
||||
return connector->display_info.amd_vsdb.version != 0;
|
||||
}
|
||||
|
||||
static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
|
||||
@@ -13307,7 +13323,7 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
|
||||
freesync_capable = true;
|
||||
}
|
||||
|
||||
parse_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
|
||||
get_amd_vsdb(amdgpu_dm_connector, &vsdb_info);
|
||||
|
||||
if (vsdb_info.replay_mode) {
|
||||
amdgpu_dm_connector->vsdb_info.replay_mode = vsdb_info.replay_mode;
|
||||
|
||||
@@ -53,12 +53,6 @@
|
||||
|
||||
#define AMDGPU_DMUB_NOTIFICATION_MAX 8
|
||||
|
||||
#define HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_IEEE_REGISTRATION_ID 0x00001A
|
||||
#define AMD_VSDB_VERSION_3_FEATURECAP_REPLAYMODE 0x40
|
||||
#define AMD_VDSB_VERSION_3_PANEL_TYPE_MASK 0xC0
|
||||
#define AMD_VDSB_VERSION_3_PANEL_TYPE_SHIFT 6
|
||||
#define HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_VERSION_3 0x3
|
||||
|
||||
enum amd_vsdb_panel_type {
|
||||
AMD_VSDB_PANEL_TYPE_DEFAULT = 0,
|
||||
AMD_VSDB_PANEL_TYPE_MINILED,
|
||||
@@ -97,14 +91,6 @@ struct dc_plane_state;
|
||||
struct dmub_notification;
|
||||
struct dmub_cmd_fused_request;
|
||||
|
||||
struct amd_vsdb_block {
|
||||
unsigned char ieee_id[3];
|
||||
unsigned char version;
|
||||
unsigned char feature_caps;
|
||||
unsigned char reserved[3];
|
||||
unsigned char color_space_eotf_support;
|
||||
};
|
||||
|
||||
struct common_irq_params {
|
||||
struct amdgpu_device *adev;
|
||||
enum dc_irq_source irq_src;
|
||||
|
||||
@@ -101,23 +101,22 @@ bool amdgpu_dm_crtc_vrr_active(const struct dm_crtc_state *dm_state)
|
||||
|
||||
/**
|
||||
* amdgpu_dm_crtc_set_panel_sr_feature() - Manage panel self-refresh features.
|
||||
*
|
||||
* @vblank_work: is a pointer to a struct vblank_control_work object.
|
||||
* @vblank_enabled: indicates whether the DRM vblank counter is currently
|
||||
* enabled (true) or disabled (false).
|
||||
* @allow_sr_entry: represents whether entry into the self-refresh mode is
|
||||
* allowed (true) or not allowed (false).
|
||||
* @dm: amdgpu display manager instance.
|
||||
* @acrtc: CRTC whose panel self-refresh state is being updated.
|
||||
* @stream: DC stream associated with @acrtc.
|
||||
* @vblank_enabled: Whether the DRM vblank counter is currently enabled.
|
||||
* @allow_sr_entry: Whether entry into self-refresh mode is allowed.
|
||||
*
|
||||
* The DRM vblank counter enable/disable action is used as the trigger to enable
|
||||
* or disable various panel self-refresh features:
|
||||
*
|
||||
* Panel Replay and PSR SU
|
||||
* - Enable when:
|
||||
* - VRR is disabled
|
||||
* - vblank counter is disabled
|
||||
* - entry is allowed: usermode demonstrates an adequate number of fast
|
||||
* commits)
|
||||
* - CRC capture window isn't active
|
||||
* - VRR is disabled
|
||||
* - vblank counter is disabled
|
||||
* - entry is allowed: usermode demonstrates an adequate number of fast
|
||||
* commits
|
||||
* - CRC capture window isn't active
|
||||
* - Keep enabled even when vblank counter gets enabled
|
||||
*
|
||||
* PSR1
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
|
||||
/**
|
||||
* dm_ism_next_state - Get next state based on current state and event
|
||||
* @current_state: current ISM state
|
||||
* @event: event being processed
|
||||
* @next_state: place to store the next state
|
||||
*
|
||||
* This function defines the idle state management FSM. Invalid transitions
|
||||
* are ignored and will not progress the FSM.
|
||||
@@ -148,6 +151,11 @@ static uint64_t dm_ism_get_sso_delay(const struct amdgpu_dm_ism *ism,
|
||||
|
||||
/**
|
||||
* dm_ism_get_idle_allow_delay - Calculate hysteresis-based idle allow delay
|
||||
* @ism: ISM instance containing configuration, history, and current state
|
||||
* @stream: display stream used to derive frame timing values for delay
|
||||
*
|
||||
* 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)
|
||||
@@ -212,6 +220,7 @@ static uint64_t dm_ism_get_idle_allow_delay(const struct amdgpu_dm_ism *ism,
|
||||
|
||||
/**
|
||||
* dm_ism_insert_record - Insert a record into the circular history buffer
|
||||
* @ism: ISM instance
|
||||
*/
|
||||
static void dm_ism_insert_record(struct amdgpu_dm_ism *ism)
|
||||
{
|
||||
|
||||
@@ -59,7 +59,7 @@ inline void dc_assert_fp_enabled(void)
|
||||
}
|
||||
|
||||
/**
|
||||
* dc_assert_fp_enabled - Check if FPU protection is enabled
|
||||
* dc_is_fp_enabled - Check if FPU protection is enabled
|
||||
*
|
||||
* This function tells if the code is already under FPU protection or not. A
|
||||
* function that works as an API for a set of FPU operations can use this
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/array_size.h>
|
||||
|
||||
#include "dm_services.h"
|
||||
#include "core_types.h"
|
||||
#include "timing_generator.h"
|
||||
@@ -40,7 +42,6 @@
|
||||
#include "dcn10/dcn10_hubbub.h"
|
||||
#include "dce/dmub_hw_lock_mgr.h"
|
||||
|
||||
#define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0]))
|
||||
#define MAX_NUM_MCACHE 8
|
||||
|
||||
/* used as index in array of black_color_format */
|
||||
@@ -230,7 +231,7 @@ const uint16_t *find_color_matrix(enum dc_color_space color_space,
|
||||
int i;
|
||||
enum dc_color_space_type type;
|
||||
const uint16_t *val = NULL;
|
||||
int arr_size = NUM_ELEMENTS(output_csc_matrix);
|
||||
int arr_size = ARRAY_SIZE(output_csc_matrix);
|
||||
|
||||
type = get_color_space_type(color_space);
|
||||
for (i = 0; i < arr_size; i++)
|
||||
|
||||
@@ -5062,7 +5062,7 @@ void resource_build_bit_depth_reduction_params(struct dc_stream_state *stream,
|
||||
option = DITHER_OPTION_SPATIAL8;
|
||||
break;
|
||||
case COLOR_DEPTH_101010:
|
||||
option = DITHER_OPTION_TRUN10;
|
||||
option = DITHER_OPTION_SPATIAL10;
|
||||
break;
|
||||
default:
|
||||
option = DITHER_OPTION_DISABLE;
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/array_size.h>
|
||||
|
||||
#include "dm_services.h"
|
||||
|
||||
|
||||
@@ -57,8 +59,6 @@
|
||||
#define CALC_PLL_CLK_SRC_ERR_TOLERANCE 1
|
||||
#define MAX_PLL_CALC_ERROR 0xFFFFFFFF
|
||||
|
||||
#define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
static const struct spread_spectrum_data *get_ss_data_entry(
|
||||
struct dce110_clk_src *clk_src,
|
||||
enum signal_type signal,
|
||||
@@ -1271,7 +1271,7 @@ const struct pixel_rate_range_table_entry *look_up_in_video_optimized_rate_tlb(
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_ELEMENTS(video_optimized_pixel_rates); i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(video_optimized_pixel_rates); i++) {
|
||||
const struct pixel_rate_range_table_entry *e = &video_optimized_pixel_rates[i];
|
||||
|
||||
if (e->range_min_khz <= pixel_rate_khz && pixel_rate_khz <= e->range_max_khz) {
|
||||
|
||||
@@ -49,9 +49,6 @@
|
||||
#define FN(reg_name, field_name) \
|
||||
dpp->tf_shift->field_name, dpp->tf_mask->field_name
|
||||
|
||||
#define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
|
||||
enum dcn10_coef_filter_type_sel {
|
||||
SCL_COEF_LUMA_VERT_FILTER = 0,
|
||||
SCL_COEF_LUMA_HORZ_FILTER = 1,
|
||||
|
||||
@@ -49,9 +49,6 @@
|
||||
#define FN(reg_name, field_name) \
|
||||
dpp->tf_shift->field_name, dpp->tf_mask->field_name
|
||||
|
||||
#define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
|
||||
enum dcn401_coef_filter_type_sel {
|
||||
SCL_COEF_LUMA_VERT_FILTER = 0,
|
||||
SCL_COEF_LUMA_HORZ_FILTER = 1,
|
||||
|
||||
@@ -43,8 +43,6 @@
|
||||
#define FN(reg_name, field_name) \
|
||||
mpc20->mpc_shift->field_name, mpc20->mpc_mask->field_name
|
||||
|
||||
#define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
void mpc2_update_blending(
|
||||
struct mpc *mpc,
|
||||
struct mpcc_blnd_cfg *blnd_cfg,
|
||||
|
||||
@@ -40,10 +40,6 @@
|
||||
#define FN(reg_name, field_name) \
|
||||
mpc30->mpc_shift->field_name, mpc30->mpc_mask->field_name
|
||||
|
||||
|
||||
#define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
|
||||
void mpc3_mpc_init(struct mpc *mpc)
|
||||
{
|
||||
struct dcn30_mpc *mpc30 = TO_DCN30_MPC(mpc);
|
||||
|
||||
@@ -2164,4 +2164,21 @@ static inline void smu_feature_init(struct smu_context *smu, int feature_num)
|
||||
smu_feature_list_clear_all(smu, SMU_FEATURE_LIST_ALLOWED);
|
||||
}
|
||||
|
||||
/*
|
||||
* smu_safe_u16_nn - Make u16 safe by filtering negative overflow errors
|
||||
* @val: Input u16 value, may contain invalid negative overflows
|
||||
*
|
||||
* Convert u16 to non-negative value. Cast to s16 to detect negative values
|
||||
* caused by calculation errors. Return 0 for negative errors, return
|
||||
* original value if valid.
|
||||
*
|
||||
* Return: Valid u16 value or 0
|
||||
*/
|
||||
static inline u16 smu_safe_u16_nn(u16 val)
|
||||
{
|
||||
s16 tmp = (s16)val;
|
||||
|
||||
return tmp < 0 ? 0 : val;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -773,13 +773,13 @@ static int smu_v13_0_0_get_smu_metrics_data(struct smu_context *smu,
|
||||
*value = metrics->AverageGfxclkFrequencyPreDs;
|
||||
break;
|
||||
case METRICS_AVERAGE_FCLK:
|
||||
if (metrics->AverageUclkActivity <= SMU_13_0_0_BUSY_THRESHOLD)
|
||||
if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_13_0_0_BUSY_THRESHOLD)
|
||||
*value = metrics->AverageFclkFrequencyPostDs;
|
||||
else
|
||||
*value = metrics->AverageFclkFrequencyPreDs;
|
||||
break;
|
||||
case METRICS_AVERAGE_UCLK:
|
||||
if (metrics->AverageUclkActivity <= SMU_13_0_0_BUSY_THRESHOLD)
|
||||
if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_13_0_0_BUSY_THRESHOLD)
|
||||
*value = metrics->AverageMemclkFrequencyPostDs;
|
||||
else
|
||||
*value = metrics->AverageMemclkFrequencyPreDs;
|
||||
@@ -800,7 +800,7 @@ static int smu_v13_0_0_get_smu_metrics_data(struct smu_context *smu,
|
||||
*value = metrics->AverageGfxActivity;
|
||||
break;
|
||||
case METRICS_AVERAGE_MEMACTIVITY:
|
||||
*value = metrics->AverageUclkActivity;
|
||||
*value = smu_safe_u16_nn(metrics->AverageUclkActivity);
|
||||
break;
|
||||
case METRICS_AVERAGE_VCNACTIVITY:
|
||||
*value = max(metrics->Vcn0ActivityPercentage,
|
||||
@@ -2085,7 +2085,7 @@ static ssize_t smu_v13_0_0_get_gpu_metrics(struct smu_context *smu,
|
||||
metrics->AvgTemperature[TEMP_VR_MEM1]);
|
||||
|
||||
gpu_metrics->average_gfx_activity = metrics->AverageGfxActivity;
|
||||
gpu_metrics->average_umc_activity = metrics->AverageUclkActivity;
|
||||
gpu_metrics->average_umc_activity = smu_safe_u16_nn(metrics->AverageUclkActivity);
|
||||
gpu_metrics->average_mm_activity = max(metrics->Vcn0ActivityPercentage,
|
||||
metrics->Vcn1ActivityPercentage);
|
||||
|
||||
@@ -2102,7 +2102,7 @@ static ssize_t smu_v13_0_0_get_gpu_metrics(struct smu_context *smu,
|
||||
else
|
||||
gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPreDs;
|
||||
|
||||
if (metrics->AverageUclkActivity <= SMU_13_0_0_BUSY_THRESHOLD)
|
||||
if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_13_0_0_BUSY_THRESHOLD)
|
||||
gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPostDs;
|
||||
else
|
||||
gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPreDs;
|
||||
|
||||
@@ -479,9 +479,14 @@ static int smu_v13_0_12_get_system_metrics_table(struct smu_context *smu)
|
||||
}
|
||||
|
||||
amdgpu_hdp_invalidate(smu->adev, NULL);
|
||||
|
||||
ret = smu_cmn_vram_cpy(smu, sys_table->cache.buffer,
|
||||
table->cpu_addr,
|
||||
smu_v13_0_12_get_system_metrics_size());
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
smu_table_cache_update_time(sys_table, jiffies);
|
||||
memcpy(sys_table->cache.buffer, table->cpu_addr,
|
||||
smu_v13_0_12_get_system_metrics_size());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -778,7 +778,10 @@ int smu_v13_0_6_get_metrics_table(struct smu_context *smu, void *metrics_table,
|
||||
}
|
||||
|
||||
amdgpu_hdp_invalidate(smu->adev, NULL);
|
||||
memcpy(smu_table->metrics_table, table->cpu_addr, table_size);
|
||||
ret = smu_cmn_vram_cpy(smu, smu_table->metrics_table,
|
||||
table->cpu_addr, table_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
smu_table->metrics_time = jiffies;
|
||||
}
|
||||
@@ -857,9 +860,9 @@ int smu_v13_0_6_get_static_metrics_table(struct smu_context *smu)
|
||||
}
|
||||
|
||||
amdgpu_hdp_invalidate(smu->adev, NULL);
|
||||
memcpy(smu_table->metrics_table, table->cpu_addr, table_size);
|
||||
|
||||
return 0;
|
||||
return smu_cmn_vram_cpy(smu, smu_table->metrics_table,
|
||||
table->cpu_addr, table_size);
|
||||
}
|
||||
|
||||
static void smu_v13_0_6_update_caps(struct smu_context *smu)
|
||||
@@ -2404,13 +2407,15 @@ static int smu_v13_0_6_request_i2c_xfer(struct smu_context *smu,
|
||||
|
||||
table_size = smu_table->tables[SMU_TABLE_I2C_COMMANDS].size;
|
||||
|
||||
memcpy(table->cpu_addr, table_data, table_size);
|
||||
ret = smu_cmn_vram_cpy(smu, table->cpu_addr, table_data, table_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Flush hdp cache */
|
||||
amdgpu_hdp_flush(adev, NULL);
|
||||
ret = smu_cmn_send_smc_msg(smu, SMU_MSG_RequestI2cTransaction,
|
||||
NULL);
|
||||
|
||||
return ret;
|
||||
return smu_cmn_send_smc_msg(smu, SMU_MSG_RequestI2cTransaction,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static int smu_v13_0_6_i2c_xfer(struct i2c_adapter *i2c_adap,
|
||||
|
||||
@@ -783,13 +783,13 @@ static int smu_v13_0_7_get_smu_metrics_data(struct smu_context *smu,
|
||||
*value = metrics->AverageGfxclkFrequencyPreDs;
|
||||
break;
|
||||
case METRICS_AVERAGE_FCLK:
|
||||
if (metrics->AverageUclkActivity <= SMU_13_0_7_BUSY_THRESHOLD)
|
||||
if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_13_0_7_BUSY_THRESHOLD)
|
||||
*value = metrics->AverageFclkFrequencyPostDs;
|
||||
else
|
||||
*value = metrics->AverageFclkFrequencyPreDs;
|
||||
break;
|
||||
case METRICS_AVERAGE_UCLK:
|
||||
if (metrics->AverageUclkActivity <= SMU_13_0_7_BUSY_THRESHOLD)
|
||||
if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_13_0_7_BUSY_THRESHOLD)
|
||||
*value = metrics->AverageMemclkFrequencyPostDs;
|
||||
else
|
||||
*value = metrics->AverageMemclkFrequencyPreDs;
|
||||
@@ -814,7 +814,7 @@ static int smu_v13_0_7_get_smu_metrics_data(struct smu_context *smu,
|
||||
*value = metrics->AverageGfxActivity;
|
||||
break;
|
||||
case METRICS_AVERAGE_MEMACTIVITY:
|
||||
*value = metrics->AverageUclkActivity;
|
||||
*value = smu_safe_u16_nn(metrics->AverageUclkActivity);
|
||||
break;
|
||||
case METRICS_AVERAGE_SOCKETPOWER:
|
||||
*value = metrics->AverageSocketPower << 8;
|
||||
@@ -2091,7 +2091,7 @@ static ssize_t smu_v13_0_7_get_gpu_metrics(struct smu_context *smu,
|
||||
metrics->AvgTemperature[TEMP_VR_MEM1]);
|
||||
|
||||
gpu_metrics->average_gfx_activity = metrics->AverageGfxActivity;
|
||||
gpu_metrics->average_umc_activity = metrics->AverageUclkActivity;
|
||||
gpu_metrics->average_umc_activity = smu_safe_u16_nn(metrics->AverageUclkActivity);
|
||||
gpu_metrics->average_mm_activity = max(metrics->Vcn0ActivityPercentage,
|
||||
metrics->Vcn1ActivityPercentage);
|
||||
|
||||
@@ -2104,7 +2104,7 @@ static ssize_t smu_v13_0_7_get_gpu_metrics(struct smu_context *smu,
|
||||
else
|
||||
gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPreDs;
|
||||
|
||||
if (metrics->AverageUclkActivity <= SMU_13_0_7_BUSY_THRESHOLD)
|
||||
if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_13_0_7_BUSY_THRESHOLD)
|
||||
gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPostDs;
|
||||
else
|
||||
gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPreDs;
|
||||
|
||||
@@ -661,13 +661,13 @@ static int smu_v14_0_2_get_smu_metrics_data(struct smu_context *smu,
|
||||
*value = metrics->AverageGfxclkFrequencyPreDs;
|
||||
break;
|
||||
case METRICS_AVERAGE_FCLK:
|
||||
if (metrics->AverageUclkActivity <= SMU_14_0_2_BUSY_THRESHOLD)
|
||||
if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_14_0_2_BUSY_THRESHOLD)
|
||||
*value = metrics->AverageFclkFrequencyPostDs;
|
||||
else
|
||||
*value = metrics->AverageFclkFrequencyPreDs;
|
||||
break;
|
||||
case METRICS_AVERAGE_UCLK:
|
||||
if (metrics->AverageUclkActivity <= SMU_14_0_2_BUSY_THRESHOLD)
|
||||
if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_14_0_2_BUSY_THRESHOLD)
|
||||
*value = metrics->AverageMemclkFrequencyPostDs;
|
||||
else
|
||||
*value = metrics->AverageMemclkFrequencyPreDs;
|
||||
@@ -688,7 +688,7 @@ static int smu_v14_0_2_get_smu_metrics_data(struct smu_context *smu,
|
||||
*value = metrics->AverageGfxActivity;
|
||||
break;
|
||||
case METRICS_AVERAGE_MEMACTIVITY:
|
||||
*value = metrics->AverageUclkActivity;
|
||||
*value = smu_safe_u16_nn(metrics->AverageUclkActivity);
|
||||
break;
|
||||
case METRICS_AVERAGE_VCNACTIVITY:
|
||||
*value = max(metrics->AverageVcn0ActivityPercentage,
|
||||
@@ -2147,7 +2147,7 @@ static ssize_t smu_v14_0_2_get_gpu_metrics(struct smu_context *smu,
|
||||
metrics->AvgTemperature[TEMP_VR_MEM1]);
|
||||
|
||||
gpu_metrics->average_gfx_activity = metrics->AverageGfxActivity;
|
||||
gpu_metrics->average_umc_activity = metrics->AverageUclkActivity;
|
||||
gpu_metrics->average_umc_activity = smu_safe_u16_nn(metrics->AverageUclkActivity);
|
||||
gpu_metrics->average_mm_activity = max(metrics->AverageVcn0ActivityPercentage,
|
||||
metrics->Vcn1ActivityPercentage);
|
||||
|
||||
@@ -2159,7 +2159,7 @@ static ssize_t smu_v14_0_2_get_gpu_metrics(struct smu_context *smu,
|
||||
else
|
||||
gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPreDs;
|
||||
|
||||
if (metrics->AverageUclkActivity <= SMU_14_0_2_BUSY_THRESHOLD)
|
||||
if (smu_safe_u16_nn(metrics->AverageUclkActivity) <= SMU_14_0_2_BUSY_THRESHOLD)
|
||||
gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPostDs;
|
||||
else
|
||||
gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPreDs;
|
||||
|
||||
@@ -344,7 +344,12 @@ static int smu_v15_0_8_get_metrics_table_internal(struct smu_context *smu, uint3
|
||||
}
|
||||
|
||||
amdgpu_device_invalidate_hdp(smu->adev, NULL);
|
||||
memcpy(smu_table->metrics_table, table->cpu_addr, table_size);
|
||||
ret = smu_cmn_vram_cpy(smu, smu_table->metrics_table,
|
||||
table->cpu_addr, table_size);
|
||||
if (ret) {
|
||||
mutex_unlock(&smu_table->metrics_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
smu_table->metrics_time = jiffies;
|
||||
}
|
||||
@@ -551,9 +556,14 @@ static int smu_v15_0_8_get_system_metrics_table(struct smu_context *smu)
|
||||
}
|
||||
|
||||
amdgpu_hdp_invalidate(smu->adev, NULL);
|
||||
|
||||
ret = smu_cmn_vram_cpy(smu, sys_table->cache.buffer,
|
||||
table->cpu_addr,
|
||||
sizeof(SystemMetricsTable_t));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
smu_table_cache_update_time(sys_table, jiffies);
|
||||
memcpy(sys_table->cache.buffer, table->cpu_addr,
|
||||
sizeof(SystemMetricsTable_t));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -988,9 +998,9 @@ static int smu_v15_0_8_get_static_metrics_table(struct smu_context *smu)
|
||||
}
|
||||
|
||||
amdgpu_hdp_invalidate(smu->adev, NULL);
|
||||
memcpy(smu_table->metrics_table, table->cpu_addr, table_size);
|
||||
|
||||
return 0;
|
||||
return smu_cmn_vram_cpy(smu, smu_table->metrics_table,
|
||||
table->cpu_addr, table_size);
|
||||
}
|
||||
|
||||
static int smu_v15_0_8_fru_get_product_info(struct smu_context *smu,
|
||||
@@ -1601,8 +1611,6 @@ static ssize_t smu_v15_0_8_get_gpu_metrics(struct smu_context *smu, void **table
|
||||
uint32_t mid_mask = adev->aid_mask;
|
||||
MetricsTable_t *metrics;
|
||||
|
||||
metrics = kzalloc(sizeof(MetricsTable_t), GFP_KERNEL);
|
||||
|
||||
ret = smu_v15_0_8_get_metrics_table_internal(smu, 1, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -1775,7 +1783,7 @@ static int smu_v15_0_8_get_power_limit(struct smu_context *smu,
|
||||
*current_power_limit = power_limit;
|
||||
|
||||
if (default_power_limit)
|
||||
*max_power_limit = pptable->MaxSocketPowerLimit;
|
||||
*default_power_limit = pptable->MaxSocketPowerLimit;
|
||||
|
||||
if (max_power_limit)
|
||||
*max_power_limit = pptable->MaxSocketPowerLimit;
|
||||
@@ -1901,42 +1909,36 @@ static int smu_v15_0_8_set_soft_freq_limited_range(struct smu_context *smu,
|
||||
if (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL)
|
||||
return -EINVAL;
|
||||
|
||||
if (smu_dpm->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) {
|
||||
if (min >= max) {
|
||||
dev_err(smu->adev->dev,
|
||||
"Minimum clk should be less than the maximum allowed clock\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (clk_type == SMU_GFXCLK || clk_type == SMU_SCLK) {
|
||||
if ((min == pstate_table->gfxclk_pstate.curr.min) &&
|
||||
(max == pstate_table->gfxclk_pstate.curr.max))
|
||||
return 0;
|
||||
|
||||
ret = smu_v15_0_8_set_gfx_soft_freq_limited_range(smu,
|
||||
min, max);
|
||||
if (!ret) {
|
||||
pstate_table->gfxclk_pstate.curr.min = min;
|
||||
pstate_table->gfxclk_pstate.curr.max = max;
|
||||
}
|
||||
}
|
||||
|
||||
if (clk_type == SMU_UCLK) {
|
||||
if (max == pstate_table->uclk_pstate.curr.max)
|
||||
return 0;
|
||||
|
||||
ret = smu_v15_0_set_soft_freq_limited_range(smu,
|
||||
SMU_UCLK,
|
||||
0, max,
|
||||
false);
|
||||
if (!ret)
|
||||
pstate_table->uclk_pstate.curr.max = max;
|
||||
}
|
||||
|
||||
return ret;
|
||||
if (min >= max) {
|
||||
dev_err(smu->adev->dev,
|
||||
"Minimum clk should be less than the maximum allowed clock\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (clk_type == SMU_GFXCLK || clk_type == SMU_SCLK) {
|
||||
if ((min == pstate_table->gfxclk_pstate.curr.min) &&
|
||||
(max == pstate_table->gfxclk_pstate.curr.max))
|
||||
return 0;
|
||||
|
||||
ret = smu_v15_0_8_set_gfx_soft_freq_limited_range(smu, min,
|
||||
max);
|
||||
if (!ret) {
|
||||
pstate_table->gfxclk_pstate.curr.min = min;
|
||||
pstate_table->gfxclk_pstate.curr.max = max;
|
||||
}
|
||||
}
|
||||
|
||||
if (clk_type == SMU_UCLK) {
|
||||
if (max == pstate_table->uclk_pstate.curr.max)
|
||||
return 0;
|
||||
|
||||
ret = smu_v15_0_set_soft_freq_limited_range(smu, SMU_UCLK, 0,
|
||||
max, false);
|
||||
if (!ret)
|
||||
pstate_table->uclk_pstate.curr.max = max;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int smu_v15_0_8_od_edit_dpm_table(struct smu_context *smu,
|
||||
|
||||
@@ -1104,6 +1104,18 @@ int smu_cmn_update_table(struct smu_context *smu,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smu_cmn_vram_cpy(struct smu_context *smu, void *dst, const void *src,
|
||||
size_t len)
|
||||
{
|
||||
memcpy(dst, src, len);
|
||||
|
||||
/* Don't trust the copy operation if RAS fatal error happened. */
|
||||
if (amdgpu_ras_get_fed_status(smu->adev))
|
||||
return -EHWPOISON;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smu_cmn_write_watermarks_table(struct smu_context *smu)
|
||||
{
|
||||
void *watermarks_table = smu->smu_table.watermarks_table;
|
||||
|
||||
@@ -174,6 +174,9 @@ int smu_cmn_update_table(struct smu_context *smu,
|
||||
void *table_data,
|
||||
bool drv2smu);
|
||||
|
||||
int smu_cmn_vram_cpy(struct smu_context *smu, void *dst,
|
||||
const void *src, size_t len);
|
||||
|
||||
int smu_cmn_write_watermarks_table(struct smu_context *smu);
|
||||
|
||||
int smu_cmn_write_pptable(struct smu_context *smu);
|
||||
|
||||
@@ -290,13 +290,10 @@ static int amdgpu_ras_mgr_sw_init(struct amdgpu_ip_block *ip_block)
|
||||
/* Disabled by default */
|
||||
con->uniras_enabled = false;
|
||||
|
||||
/* Enabled only in debug mode */
|
||||
if (adev->debug_enable_ras_aca) {
|
||||
if (amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 14) ||
|
||||
adev->debug_enable_ras_aca)
|
||||
con->uniras_enabled = true;
|
||||
RAS_DEV_INFO(adev, "Debug amdgpu uniras!");
|
||||
}
|
||||
|
||||
if (!con->uniras_enabled)
|
||||
else
|
||||
return 0;
|
||||
|
||||
ras_mgr = kzalloc_obj(*ras_mgr);
|
||||
|
||||
@@ -36,22 +36,22 @@ static int amdgpu_virt_ras_get_cmd_shared_mem(struct ras_core_context *ras_core,
|
||||
struct amdgpu_device *adev = ras_core->dev;
|
||||
struct amdsriov_ras_telemetry *ras_telemetry_cpu;
|
||||
struct amdsriov_ras_telemetry *ras_telemetry_gpu;
|
||||
void *fw_va = adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].cpu_ptr;
|
||||
void *drv_va = adev->mman.resv_region[AMDGPU_RESV_DRV_VRAM_USAGE].cpu_ptr;
|
||||
uint64_t fw_vram_usage_start_offset = 0;
|
||||
uint64_t ras_telemetry_offset = 0;
|
||||
|
||||
if (!adev->virt.fw_reserve.ras_telemetry)
|
||||
return -EINVAL;
|
||||
|
||||
if (adev->mman.fw_vram_usage_va &&
|
||||
adev->mman.fw_vram_usage_va <= adev->virt.fw_reserve.ras_telemetry) {
|
||||
fw_vram_usage_start_offset = adev->mman.fw_vram_usage_start_offset;
|
||||
if (fw_va && fw_va <= adev->virt.fw_reserve.ras_telemetry) {
|
||||
fw_vram_usage_start_offset = adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].offset;
|
||||
ras_telemetry_offset = (uintptr_t)adev->virt.fw_reserve.ras_telemetry -
|
||||
(uintptr_t)adev->mman.fw_vram_usage_va;
|
||||
} else if (adev->mman.drv_vram_usage_va &&
|
||||
adev->mman.drv_vram_usage_va <= adev->virt.fw_reserve.ras_telemetry) {
|
||||
fw_vram_usage_start_offset = adev->mman.drv_vram_usage_start_offset;
|
||||
(uintptr_t)fw_va;
|
||||
} else if (drv_va && drv_va <= adev->virt.fw_reserve.ras_telemetry) {
|
||||
fw_vram_usage_start_offset = adev->mman.resv_region[AMDGPU_RESV_DRV_VRAM_USAGE].offset;
|
||||
ras_telemetry_offset = (uintptr_t)adev->virt.fw_reserve.ras_telemetry -
|
||||
(uintptr_t)adev->mman.drv_vram_usage_va;
|
||||
(uintptr_t)drv_va;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -99,6 +99,29 @@ enum drm_edid_internal_quirk {
|
||||
};
|
||||
|
||||
#define MICROSOFT_IEEE_OUI 0xca125c
|
||||
#define AMD_IEEE_OUI 0x00001A
|
||||
|
||||
#define AMD_VSDB_V3_PAYLOAD_MIN_LEN 15
|
||||
#define AMD_VSDB_V3_PAYLOAD_MAX_LEN 20
|
||||
|
||||
struct amd_vsdb_v3_payload {
|
||||
u8 oui[3];
|
||||
u8 version;
|
||||
u8 feature_caps;
|
||||
u8 rsvd0[3];
|
||||
u8 cs_eotf_support;
|
||||
u8 lum1_max;
|
||||
u8 lum1_min;
|
||||
u8 lum2_max;
|
||||
u8 lum2_min;
|
||||
u8 rsvd1[2];
|
||||
/*
|
||||
* Bytes beyond AMD_VSDB_V3_PAYLOAD_MIN_LEN are optional; a
|
||||
* monitor may provide a payload as short as 15 bytes. Always
|
||||
* check cea_db_payload_len() before accessing extra[].
|
||||
*/
|
||||
u8 extra[AMD_VSDB_V3_PAYLOAD_MAX_LEN - AMD_VSDB_V3_PAYLOAD_MIN_LEN];
|
||||
} __packed;
|
||||
|
||||
struct detailed_mode_closure {
|
||||
struct drm_connector *connector;
|
||||
@@ -5205,6 +5228,13 @@ static bool cea_db_is_microsoft_vsdb(const struct cea_db *db)
|
||||
cea_db_payload_len(db) == 21;
|
||||
}
|
||||
|
||||
static bool cea_db_is_amd_vsdb(const struct cea_db *db)
|
||||
{
|
||||
return cea_db_is_vendor(db, AMD_IEEE_OUI) &&
|
||||
cea_db_payload_len(db) >= AMD_VSDB_V3_PAYLOAD_MIN_LEN &&
|
||||
cea_db_payload_len(db) <= AMD_VSDB_V3_PAYLOAD_MAX_LEN;
|
||||
}
|
||||
|
||||
static bool cea_db_is_vcdb(const struct cea_db *db)
|
||||
{
|
||||
return cea_db_is_extended_tag(db, CTA_EXT_DB_VIDEO_CAP) &&
|
||||
@@ -6401,6 +6431,45 @@ static void drm_parse_microsoft_vsdb(struct drm_connector *connector,
|
||||
connector->base.id, connector->name, version, db[5]);
|
||||
}
|
||||
|
||||
static void drm_parse_amd_vsdb(struct drm_connector *connector,
|
||||
const struct cea_db *db)
|
||||
{
|
||||
struct drm_display_info *info = &connector->display_info;
|
||||
const u8 *data = cea_db_data(db);
|
||||
const struct amd_vsdb_v3_payload *p;
|
||||
|
||||
p = (const struct amd_vsdb_v3_payload *)data;
|
||||
|
||||
if (p->version != 0x03) {
|
||||
drm_dbg_kms(connector->dev,
|
||||
"[CONNECTOR:%d:%s] Unsupported AMD VSDB version %u\n",
|
||||
connector->base.id, connector->name, p->version);
|
||||
return;
|
||||
}
|
||||
|
||||
info->amd_vsdb.version = p->version;
|
||||
info->amd_vsdb.replay_mode = p->feature_caps & 0x40;
|
||||
info->amd_vsdb.panel_type = (p->cs_eotf_support & 0xC0) >> 6;
|
||||
info->amd_vsdb.luminance_range1.max_luminance = p->lum1_max;
|
||||
info->amd_vsdb.luminance_range1.min_luminance = p->lum1_min;
|
||||
info->amd_vsdb.luminance_range2.max_luminance = p->lum2_max;
|
||||
info->amd_vsdb.luminance_range2.min_luminance = p->lum2_min;
|
||||
|
||||
/*
|
||||
* The AMD VSDB v3 payload length is variable (15..20 bytes).
|
||||
* All fields through p->rsvd1 (byte 14) are always present,
|
||||
* but p->extra[] (bytes 15+) may not be. Any future access to
|
||||
* extra[] must be guarded with a runtime length check to avoid
|
||||
* out-of-bounds reads on shorter (but spec-valid) payloads.
|
||||
* For example:
|
||||
*
|
||||
* int len = cea_db_payload_len(db);
|
||||
*
|
||||
* if (len > AMD_VSDB_V3_PAYLOAD_MIN_LEN)
|
||||
* info->amd_vsdb.foo = p->extra[0];
|
||||
*/
|
||||
}
|
||||
|
||||
static void drm_parse_cea_ext(struct drm_connector *connector,
|
||||
const struct drm_edid *drm_edid)
|
||||
{
|
||||
@@ -6449,6 +6518,8 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
|
||||
drm_parse_hdmi_forum_scds(connector, data);
|
||||
else if (cea_db_is_microsoft_vsdb(db))
|
||||
drm_parse_microsoft_vsdb(connector, data);
|
||||
else if (cea_db_is_amd_vsdb(db))
|
||||
drm_parse_amd_vsdb(connector, db);
|
||||
else if (cea_db_is_y420cmdb(db))
|
||||
parse_cta_y420cmdb(connector, db, &y420cmdb_map);
|
||||
else if (cea_db_is_y420vdb(db))
|
||||
@@ -6641,6 +6712,7 @@ static void drm_reset_display_info(struct drm_connector *connector)
|
||||
info->quirks = 0;
|
||||
|
||||
info->source_physical_address = CEC_PHYS_ADDR_INVALID;
|
||||
memset(&info->amd_vsdb, 0, sizeof(info->amd_vsdb));
|
||||
}
|
||||
|
||||
static void update_displayid_info(struct drm_connector *connector,
|
||||
|
||||
@@ -686,7 +686,8 @@ static void radeon_crtc_init(struct drm_device *dev, int index)
|
||||
if (radeon_crtc == NULL)
|
||||
return;
|
||||
|
||||
radeon_crtc->flip_queue = alloc_workqueue("radeon-crtc", WQ_HIGHPRI, 0);
|
||||
radeon_crtc->flip_queue = alloc_workqueue("radeon-crtc",
|
||||
WQ_HIGHPRI | WQ_PERCPU, 0);
|
||||
if (!radeon_crtc->flip_queue) {
|
||||
kfree(radeon_crtc);
|
||||
return;
|
||||
|
||||
@@ -278,14 +278,13 @@ static bool radeon_support_enabled(struct device *dev,
|
||||
|
||||
case CHIP_BONAIRE:
|
||||
case CHIP_HAWAII:
|
||||
support_by_default = false;
|
||||
fallthrough;
|
||||
case CHIP_KAVERI:
|
||||
case CHIP_KABINI:
|
||||
case CHIP_MULLINS:
|
||||
gen = "CIK";
|
||||
module_param = radeon_cik_support;
|
||||
amdgpu_support_built &= IS_ENABLED(CONFIG_DRM_AMDGPU_CIK);
|
||||
support_by_default = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -693,6 +693,39 @@ enum drm_bus_flags {
|
||||
DRM_BUS_FLAG_SHARP_SIGNALS = BIT(8),
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_amd_vsdb_info - AMD-specific VSDB information
|
||||
*
|
||||
* This structure holds information parsed from the AMD Vendor-Specific Data
|
||||
* Block (VSDB) version 3.
|
||||
*/
|
||||
struct drm_amd_vsdb_info {
|
||||
/**
|
||||
* @version: Version of the Vendor-Specific Data Block (VSDB)
|
||||
*/
|
||||
u8 version;
|
||||
|
||||
/**
|
||||
* @replay_mode: Panel Replay supported
|
||||
*/
|
||||
bool replay_mode;
|
||||
|
||||
/**
|
||||
* @panel_type: Panel technology type
|
||||
*/
|
||||
u8 panel_type;
|
||||
|
||||
/**
|
||||
* @luminance_range1: Luminance for max back light
|
||||
*/
|
||||
struct drm_luminance_range_info luminance_range1;
|
||||
|
||||
/**
|
||||
* @luminance_range2: Luminance for min back light
|
||||
*/
|
||||
struct drm_luminance_range_info luminance_range2;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_display_info - runtime data about the connected sink
|
||||
*
|
||||
@@ -883,6 +916,11 @@ struct drm_display_info {
|
||||
* Defaults to CEC_PHYS_ADDR_INVALID (0xffff).
|
||||
*/
|
||||
u16 source_physical_address;
|
||||
|
||||
/**
|
||||
* @amd_vsdb: AMD-specific VSDB information.
|
||||
*/
|
||||
struct drm_amd_vsdb_info amd_vsdb;
|
||||
};
|
||||
|
||||
int drm_display_info_set_bus_formats(struct drm_display_info *info,
|
||||
|
||||
Reference in New Issue
Block a user