diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-04-22 03:39:21 +0300 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-04-22 03:39:21 +0300 |
| commit | 6596a02b207886e9e00bb0161c7fd59fea53c081 (patch) | |
| tree | e62870e85acc21655af12dda4d458ddc4c0148ca | |
| parent | d46dd0d88341e45f8e0226fdef5462f5270898fc (diff) | |
| parent | a7756371e57f69a137f295a418fb56f15ff2c10f (diff) | |
| download | linux-master.tar.xz | |
Pull more drm updates from Dave Airlie:
"This is a followup which is mostly next material with some fixes.
Alex pointed out I missed one of his AMD MRs from last week, so I
added that, then Jani sent the pipe reordering stuff, otherwise it's
just some minor i915 fixes and a dma-buf fix.
drm:
- Add support for AMD VSDB parsing to drm_edid
dma-buf:
- fix documentation formatting
i915:
- add support for reordered pipes to support joined pipes better
- Fix VESA backlight possible check condition
- Verify the correct plane DDB entry
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 13/14/15 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"
* tag 'drm-next-2026-04-22' of https://gitlab.freedesktop.org/drm/kernel: (62 commits)
drm/i915/display: change pipe allocation order for discrete platforms
drm/i915/wm: Verify the correct plane DDB entry
drm/i915/backlight: Fix VESA backlight possible check condition
drm/i915: Walk crtcs in pipe order
drm/i915/joiner: Make joiner "nomodeset" state copy independent of pipe order
dma-buf: fix htmldocs error for dma_buf_attach_revocable
drm/amdgpu: dump job ibs in the devcoredump
drm/amdgpu: store ib info for devcoredump
drm/amdgpu: extract amdgpu_vm_lock_by_pasid from amdgpu_vm_handle_fault
drm/amdgpu: Use amdgpu by default for CIK APUs too
drm/amd/display: Remove unused NUM_ELEMENTS macros
drm/amd/display: Replace inline NUM_ELEMENTS macro with ARRAY_SIZE
drm/amdgpu: save ring content before resetting the device
drm/amdgpu: make userq fence_drv drop explicit in queue destroy
drm/amdgpu: rework userq fence driver alloc/destroy
drm/amdgpu/userq: use dma_fence_wait_timeout without test for signalled
drm/amdgpu/userq: call dma_resv_wait_timeout without test for signalled
drm/amdgpu/userq: add the return code too in error condition
drm/amdgpu/userq: fence wait for max time in amdgpu_userq_wait_for_signal
drm/amd/display: Change dither policy for 10 bpc output back to dithering
...
85 files changed, 1162 insertions, 777 deletions
diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index b0bc204bae14..57d4c296804d 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -1353,6 +1353,7 @@ EXPORT_SYMBOL_NS_GPL(dma_buf_attach_revocable, "DMA_BUF"); * Upon return importers may continue to access the DMA-buf memory. The caller * must do two additional waits to ensure that the memory is no longer being * accessed: + * * 1) Until dma_resv_wait_timeout() retires fences the importer is allowed to * fully access the memory. * 2) Until the importer calls unmap it is allowed to speculatively diff --git a/drivers/gpu/drm/amd/amdgpu/Kconfig b/drivers/gpu/drm/amd/amdgpu/Kconfig index 7f515be5185d..7fb0b93bc1ca 100644 --- a/drivers/gpu/drm/amd/amdgpu/Kconfig +++ b/drivers/gpu/drm/amd/amdgpu/Kconfig @@ -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" diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index 6a7e9bfec59e..db66c6372199 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -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 \ diff --git a/drivers/gpu/drm/amd/amdgpu/aldebaran.c b/drivers/gpu/drm/amd/amdgpu/aldebaran.c index 938fb0b2368d..8686c6dc2c08 100644 --- a/drivers/gpu/drm/amd/amdgpu/aldebaran.c +++ b/drivers/gpu/drm/amd/amdgpu/aldebaran.c @@ -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 diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 49e7881750fa..8bc591deb546 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -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) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 4f27c75abedb..d9e283f3b57d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -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); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c index 9f38b7dd1011..3698dd0330ff 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c @@ -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 { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c index cd9aa5b45e94..6860a3a4d466 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c @@ -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; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c index fddf4e1252bd..3f1cc2265645 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c @@ -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]; - - 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"); - - while (j < ring->ring_size) { - drm_printf(&p, "0x%x \t 0x%x\n", j, ring->ring[j / 4]); - j += 4; + 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", + 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"); + + 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); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h index f8f2f4df129b..2371e20fc68b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.h @@ -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 diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 9c936519bb2b..584c9ec28bf1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -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 @@ fence_driver_init: } /* 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 diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 8ed637f92322..e47921e2a9af 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -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: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c index cab3196a87fb..2956e45c9254 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c @@ -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); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h index 2785eda6fea5..a0cf0a3b41da 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h @@ -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 diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c index ec74f3971732..285e217fba04 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c @@ -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); } } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h index 32e73e8ba778..6ab4c1e297fc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h @@ -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); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c index 569c5a89ff10..124fb38eb465 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c @@ -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); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index d39b695cd925..f0e4d020f4c7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -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; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h index 79a49cba8d40..7e94ec11c57e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h @@ -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; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index 6edcb7713299..6c644cfe6695 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -5726,7 +5726,7 @@ out: 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) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c index 7a2fcb7ded1d..1b982b803e6f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c @@ -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, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h index ce5af137ee40..715c9e43e13a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h @@ -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, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index afaaab6496de..0dc68fb9d88e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -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) +{ + 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); +} + +static void amdgpu_ttm_init_mem_train_resv_region(struct amdgpu_device *adev) { - amdgpu_bo_free_kernel(&adev->mman.drv_vram_usage_reserved_bo, - NULL, - &adev->mman.drv_vram_usage_va); + 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); } -/** - * 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_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.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].size > vram_size) + adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].size = 0; + + if (adev->mman.resv_region[AMDGPU_RESV_DRV_VRAM_USAGE].size > vram_size) + adev->mman.resv_region[AMDGPU_RESV_DRV_VRAM_USAGE].size = 0; +} - if (adev->mman.fw_vram_usage_size == 0 || - adev->mman.fw_vram_usage_size > vram_size) +int amdgpu_ttm_mark_vram_reserved(struct amdgpu_device *adev, + enum amdgpu_resv_region_id id) +{ + struct amdgpu_vram_resv *resv; + int ret; + + if (id >= AMDGPU_RESV_MAX) + return -EINVAL; + + resv = &adev->mman.resv_region[id]; + if (!resv->size) return 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); + 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; } -/** - * 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) +void amdgpu_ttm_unmark_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; - adev->mman.drv_vram_usage_va = NULL; - adev->mman.drv_vram_usage_reserved_bo = NULL; + if (id >= AMDGPU_RESV_MAX) + return; - if (adev->mman.drv_vram_usage_size == 0 || - adev->mman.drv_vram_usage_size > vram_size) - return 0; + resv = &adev->mman.resv_region[id]; + if (!resv->bo) + return; - 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); + 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); - if (r) - return r; + amdgpu_ttm_init_vram_resv_regions(adev); - /* - * 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); + r = amdgpu_ttm_alloc_vram_resv_regions(adev); if (r) return r; - /* - * 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; - } + if (adev->mman.resv_region[AMDGPU_RESV_MEM_TRAIN].size) { + struct psp_memory_training_context *ctx = + &adev->psp.mem_train_ctx; - /* 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)) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h index 3b1973611446..f2f23a42b3cc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h @@ -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, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 366728ed03e3..bfca5b040a32 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -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) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h index a4d44abf24fa..675fe6395ac8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h @@ -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 diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c index fe6d83e859a0..5784f2b3ecae 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c @@ -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); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.h index d76add2afc77..d56246ad8c26 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.h @@ -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); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index eb4a15db2ef2..efdebd9c0a1f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -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; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index dba7ea16a10d..e8d180a412d1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -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; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 73abac6be5b3..115a7b269af3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -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); @@ -2955,6 +2950,50 @@ int amdgpu_vm_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) } /** + * 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 * @pasid: PASID of the VM @@ -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 @@ error_unlock: if (r < 0) dev_err(adev->dev, "Can't handle page fault (%d)\n", r); -error_unref: amdgpu_bo_unref(&root); return false; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h index 3b32f41c3655..d083d7aab75c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h @@ -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, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c index cc5f4e01e38f..42be8ee155dd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c @@ -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; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h index 8058e8f35d41..878c1c422893 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h @@ -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 { diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index ae39b9e1f7d6..5097de940a19 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -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; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c index a418ae609c36..65c33823a688 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c @@ -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; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c index db49582a211f..68fd3c04134d 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c @@ -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; diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c index fd691b2a6e21..e1ace7d44ffd 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c @@ -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) diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c index e6db87b94eb1..94d6631ce0bc 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c @@ -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) diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c index 6e184ea069ef..e10ac9788d13 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c @@ -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); diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c index 886bf77309a5..cc272a96fcef 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c @@ -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; diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c index d25fdedb0d9f..bb16ba2ef6fd 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c @@ -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) diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c index 4910e5557a67..a59174f6bcc1 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c @@ -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) diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index d865059e884a..e7b78027002b 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -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) diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c index b005672f2f96..0f530bb8a9a3 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c @@ -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); } diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c index 5679a94d0815..9ed817b69a3b 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c @@ -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); } diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c index 02d5c5af65f2..6fb4fcdbba4f 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c @@ -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; diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c index d17219be50f3..5dec92691f73 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c @@ -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 @@ out: 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; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index bcd21204aa50..d28ca581cad0 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -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); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 21635e80349a..1d9ceb432ec3 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -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; - - if (edid == NULL || edid->extensions == 0) - return -ENODEV; - - /* 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); + struct drm_connector *connector = &aconnector->base; - return true; - } - j++; - } + vsdb_info->replay_mode = connector->display_info.amd_vsdb.replay_mode; + vsdb_info->amd_vsdb_version = connector->display_info.amd_vsdb.version; - 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; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index d1a14e0c12bd..63ce1f52b697 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -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; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c index c3c588294665..5d2715f78314 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c @@ -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 diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c index 65a5cfe1e106..a3ccb6fdc372 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c @@ -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) { diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c index 8ba9b4f56f87..172999cc84e5 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c @@ -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 diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c index db86e346307c..952968ecd46e 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c @@ -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++) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 66597a1f5b78..00b894602423 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -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; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c index 34e54fdb9d13..71a876e3dfd4 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c @@ -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) { diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp_cm.c index f8f6019d8304..2bdd063cc1e1 100644 --- a/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp_cm.c +++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp_cm.c @@ -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, diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_cm.c index 821d5173b59f..4f3b48ed8679 100644 --- a/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_cm.c +++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_cm.c @@ -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, diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn20/dcn20_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn20/dcn20_mpc.c index ea73473b970a..fa600593f4c1 100644 --- a/drivers/gpu/drm/amd/display/dc/mpc/dcn20/dcn20_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn20/dcn20_mpc.c @@ -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, diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn30/dcn30_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn30/dcn30_mpc.c index 4c7bb0522a8c..4e91e9f6f11a 100644 --- a/drivers/gpu/drm/amd/display/dc/mpc/dcn30/dcn30_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn30/dcn30_mpc.c @@ -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); diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h index 609f5ab07d8a..126fc54cb511 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -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 diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c index b414a74d29fd..0a7f5fa3c1d3 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c @@ -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; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c index 54a86eb77cd5..fe929bd89058 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c @@ -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; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index 475541189782..cd0a23f432ff 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -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, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c index fd0b6215364f..5abf2b0703c6 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c @@ -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; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c index 31f9566f7979..62514e3ac600 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c @@ -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; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c index cc2babc6a341..db85186f2d66 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c @@ -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 (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; + 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; - } + 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; - } + if (clk_type == SMU_UCLK) { + if (max == pstate_table->uclk_pstate.curr.max) + return 0; - return ret; + 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 0; + return ret; } static int smu_v15_0_8_od_edit_dpm_table(struct smu_context *smu, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index 7bd8c435466a..006ef585a377 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -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; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h index b76e86df5da7..d129907535bd 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h @@ -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); diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c index d213eea71cff..ad8862d43263 100644 --- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c +++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c @@ -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); diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_virt_ras_cmd.c b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_virt_ras_cmd.c index c83357307c55..eb552d0cce4a 100644 --- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_virt_ras_cmd.c +++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_virt_ras_cmd.c @@ -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; } diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 5f9fcd7d9ce4..404208bf23a6 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -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, diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c index b8189cd5d864..03de219f7a64 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.c +++ b/drivers/gpu/drm/i915/display/intel_crtc.c @@ -209,6 +209,8 @@ static struct intel_crtc *intel_crtc_alloc(void) crtc->base.state = &crtc_state->uapi; crtc->config = crtc_state; + INIT_LIST_HEAD(&crtc->pipe_head); + return crtc; } @@ -222,6 +224,8 @@ static void intel_crtc_destroy(struct drm_crtc *_crtc) { struct intel_crtc *crtc = to_intel_crtc(_crtc); + list_del(&crtc->pipe_head); + cpu_latency_qos_remove_request(&crtc->vblank_pm_qos); drm_crtc_cleanup(&crtc->base); @@ -308,6 +312,20 @@ static const struct drm_crtc_funcs i8xx_crtc_funcs = { .get_vblank_timestamp = intel_crtc_get_vblank_timestamp, }; +static void add_crtc_to_pipe_list(struct intel_display *display, struct intel_crtc *crtc) +{ + struct intel_crtc *iter; + + list_for_each_entry(iter, &display->pipe_list, pipe_head) { + if (crtc->pipe < iter->pipe) { + list_add_tail(&crtc->pipe_head, &iter->pipe_head); + return; + } + } + + list_add_tail(&crtc->pipe_head, &display->pipe_list); +} + static int __intel_crtc_init(struct intel_display *display, enum pipe pipe) { struct intel_plane *primary, *cursor; @@ -393,11 +411,11 @@ static int __intel_crtc_init(struct intel_display *display, enum pipe pipe) cpu_latency_qos_add_request(&crtc->vblank_pm_qos, PM_QOS_DEFAULT_VALUE); - drm_WARN_ON(display->drm, drm_crtc_index(&crtc->base) != crtc->pipe); - if (HAS_CASF(display) && crtc->num_scalers >= 2) drm_crtc_create_sharpness_strength_property(&crtc->base); + add_crtc_to_pipe_list(display, crtc); + return 0; fail: @@ -406,6 +424,31 @@ fail: return ret; } +#define HAS_PIPE(display, pipe) (DISPLAY_RUNTIME_INFO(display)->pipe_mask & BIT(pipe)) + +/* + * Expose the pipes in order A, C, B, D on discrete platforms to trick user + * space into using pipes that are more likely to be available for both a) user + * space if pipe B has been reserved for the joiner, and b) the joiner if pipe A + * doesn't need the joiner. + * + * Swap pipes B and C only if both are available i.e. not fused off. + */ +static enum pipe reorder_pipe(struct intel_display *display, enum pipe pipe) +{ + if (!display->platform.dgfx || !HAS_PIPE(display, PIPE_B) || !HAS_PIPE(display, PIPE_C)) + return pipe; + + switch (pipe) { + case PIPE_B: + return PIPE_C; + case PIPE_C: + return PIPE_B; + default: + return pipe; + } +} + int intel_crtc_init(struct intel_display *display) { enum pipe pipe; @@ -415,7 +458,7 @@ int intel_crtc_init(struct intel_display *display) INTEL_NUM_PIPES(display), str_plural(INTEL_NUM_PIPES(display))); for_each_pipe(display, pipe) { - ret = __intel_crtc_init(display, pipe); + ret = __intel_crtc_init(display, reorder_pipe(display, pipe)); if (ret) return ret; } diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 10b6c6fcb03f..ad2fe10b6b1f 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -5939,17 +5939,6 @@ static int intel_atomic_check_joiner(struct intel_atomic_state *state, return -EINVAL; } - /* - * The state copy logic assumes the primary crtc gets processed - * before the secondary crtc during the main compute_config loop. - * This works because the crtcs are created in pipe order, - * and the hardware requires primary pipe < secondary pipe as well. - * Should that change we need to rethink the logic. - */ - if (WARN_ON(drm_crtc_index(&primary_crtc->base) > - drm_crtc_index(&secondary_crtc->base))) - return -EINVAL; - drm_dbg_kms(display->drm, "[CRTC:%d:%s] Used as secondary for joiner primary [CRTC:%d:%s]\n", secondary_crtc->base.base.id, secondary_crtc->base.name, @@ -6327,9 +6316,7 @@ static int intel_atomic_check_config(struct intel_atomic_state *state, for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { if (!intel_crtc_needs_modeset(new_crtc_state)) { - if (intel_crtc_is_joiner_secondary(new_crtc_state)) - copy_joiner_crtc_state_nomodeset(state, crtc); - else + if (!intel_crtc_is_joiner_secondary(new_crtc_state)) intel_crtc_copy_uapi_to_hw_state_nomodeset(state, crtc); continue; } @@ -6460,8 +6447,11 @@ int intel_atomic_check(struct drm_device *dev, goto fail; for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { - if (!intel_crtc_needs_modeset(new_crtc_state)) + if (!intel_crtc_needs_modeset(new_crtc_state)) { + if (intel_crtc_is_joiner_secondary(new_crtc_state)) + copy_joiner_crtc_state_nomodeset(state, crtc); continue; + } if (intel_crtc_is_joiner_secondary(new_crtc_state)) { drm_WARN_ON(display->drm, new_crtc_state->uapi.enable); diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 552a59d19e0f..1e76a455d7c4 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -212,22 +212,23 @@ enum phy_fia { base.head) \ for_each_if((intel_plane)->pipe == (intel_crtc)->pipe) -#define for_each_intel_crtc(dev, intel_crtc) \ - list_for_each_entry(intel_crtc, \ - &(dev)->mode_config.crtc_list, \ - base.head) +#define for_each_intel_crtc(dev, crtc) \ + list_for_each_entry((crtc), \ + &to_intel_display(dev)->pipe_list, \ + pipe_head) -#define for_each_intel_crtc_in_pipe_mask(dev, intel_crtc, pipe_mask) \ - list_for_each_entry(intel_crtc, \ - &(dev)->mode_config.crtc_list, \ - base.head) \ - for_each_if((pipe_mask) & BIT(intel_crtc->pipe)) +#define for_each_intel_crtc_reverse(dev, crtc) \ + list_for_each_entry_reverse((crtc), \ + &to_intel_display(dev)->pipe_list, \ + pipe_head) + +#define for_each_intel_crtc_in_pipe_mask(dev, crtc, pipe_mask) \ + for_each_intel_crtc((dev), (crtc)) \ + for_each_if((pipe_mask) & BIT((crtc)->pipe)) -#define for_each_intel_crtc_in_pipe_mask_reverse(dev, intel_crtc, pipe_mask) \ - list_for_each_entry_reverse((intel_crtc), \ - &(dev)->mode_config.crtc_list, \ - base.head) \ - for_each_if((pipe_mask) & BIT((intel_crtc)->pipe)) +#define for_each_intel_crtc_in_pipe_mask_reverse(dev, crtc, pipe_mask) \ + for_each_intel_crtc_reverse((dev), (crtc)) \ + for_each_if((pipe_mask) & BIT((crtc)->pipe)) #define for_each_intel_encoder(dev, intel_encoder) \ list_for_each_entry(intel_encoder, \ @@ -269,14 +270,6 @@ enum phy_fia { (__i)++) \ for_each_if(plane) -#define for_each_old_intel_crtc_in_state(__state, crtc, old_crtc_state, __i) \ - for ((__i) = 0; \ - (__i) < (__state)->base.dev->mode_config.num_crtc && \ - ((crtc) = to_intel_crtc((__state)->base.crtcs[__i].ptr), \ - (old_crtc_state) = to_intel_crtc_state((__state)->base.crtcs[__i].old_state), 1); \ - (__i)++) \ - for_each_if(crtc) - #define for_each_new_intel_plane_in_state(__state, plane, new_plane_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->base.dev->mode_config.num_total_plane && \ @@ -285,22 +278,6 @@ enum phy_fia { (__i)++) \ for_each_if(plane) -#define for_each_new_intel_crtc_in_state(__state, crtc, new_crtc_state, __i) \ - for ((__i) = 0; \ - (__i) < (__state)->base.dev->mode_config.num_crtc && \ - ((crtc) = to_intel_crtc((__state)->base.crtcs[__i].ptr), \ - (new_crtc_state) = to_intel_crtc_state((__state)->base.crtcs[__i].new_state), 1); \ - (__i)++) \ - for_each_if(crtc) - -#define for_each_new_intel_crtc_in_state_reverse(__state, crtc, new_crtc_state, __i) \ - for ((__i) = (__state)->base.dev->mode_config.num_crtc - 1; \ - (__i) >= 0 && \ - ((crtc) = to_intel_crtc((__state)->base.crtcs[__i].ptr), \ - (new_crtc_state) = to_intel_crtc_state((__state)->base.crtcs[__i].new_state), 1); \ - (__i)--) \ - for_each_if(crtc) - #define for_each_oldnew_intel_plane_in_state(__state, plane, old_plane_state, new_plane_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->base.dev->mode_config.num_total_plane && \ @@ -310,23 +287,32 @@ enum phy_fia { (__i)++) \ for_each_if(plane) +#define for_each_old_intel_crtc_in_state(__state, crtc, old_crtc_state, __i) \ + for_each_intel_crtc((__state)->base.dev, (crtc)) \ + for_each_if(((__i) = drm_crtc_index(&(crtc)->base), (void)(__i), \ + (old_crtc_state) = intel_atomic_get_old_crtc_state((__state), (crtc)))) + +#define for_each_new_intel_crtc_in_state(__state, crtc, new_crtc_state, __i) \ + for_each_intel_crtc((__state)->base.dev, (crtc)) \ + for_each_if(((__i) = drm_crtc_index(&(crtc)->base), (void)(__i), \ + (new_crtc_state) = intel_atomic_get_new_crtc_state((__state), (crtc)))) + +#define for_each_new_intel_crtc_in_state_reverse(__state, crtc, new_crtc_state, __i) \ + for_each_intel_crtc_reverse((__state)->base.dev, (crtc)) \ + for_each_if(((__i) = drm_crtc_index(&(crtc)->base), (void)(__i), \ + (new_crtc_state) = intel_atomic_get_new_crtc_state((__state), (crtc)))) + #define for_each_oldnew_intel_crtc_in_state(__state, crtc, old_crtc_state, new_crtc_state, __i) \ - for ((__i) = 0; \ - (__i) < (__state)->base.dev->mode_config.num_crtc && \ - ((crtc) = to_intel_crtc((__state)->base.crtcs[__i].ptr), \ - (old_crtc_state) = to_intel_crtc_state((__state)->base.crtcs[__i].old_state), \ - (new_crtc_state) = to_intel_crtc_state((__state)->base.crtcs[__i].new_state), 1); \ - (__i)++) \ - for_each_if(crtc) + for_each_intel_crtc((__state)->base.dev, (crtc)) \ + for_each_if(((__i) = drm_crtc_index(&(crtc)->base), (void)(__i), \ + (old_crtc_state) = intel_atomic_get_old_crtc_state((__state), (crtc)), \ + (new_crtc_state) = intel_atomic_get_new_crtc_state((__state), (crtc)))) #define for_each_oldnew_intel_crtc_in_state_reverse(__state, crtc, old_crtc_state, new_crtc_state, __i) \ - for ((__i) = (__state)->base.dev->mode_config.num_crtc - 1; \ - (__i) >= 0 && \ - ((crtc) = to_intel_crtc((__state)->base.crtcs[__i].ptr), \ - (old_crtc_state) = to_intel_crtc_state((__state)->base.crtcs[__i].old_state), \ - (new_crtc_state) = to_intel_crtc_state((__state)->base.crtcs[__i].new_state), 1); \ - (__i)--) \ - for_each_if(crtc) + for_each_intel_crtc_reverse((__state)->base.dev, (crtc)) \ + for_each_if(((__i) = drm_crtc_index(&(crtc)->base), (void)(__i), \ + (old_crtc_state) = intel_atomic_get_old_crtc_state((__state), (crtc)), \ + (new_crtc_state) = intel_atomic_get_new_crtc_state((__state), (crtc)))) #define intel_atomic_crtc_state_for_each_plane_state( \ plane, plane_state, \ diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h index d708d322aa85..d9baca2d5aaf 100644 --- a/drivers/gpu/drm/i915/display/intel_display_core.h +++ b/drivers/gpu/drm/i915/display/intel_display_core.h @@ -294,6 +294,9 @@ struct intel_display { /* Parent, or core, driver functions exposed to display */ const struct intel_display_parent_interface *parent; + /* list of all intel_crtcs sorted by pipe */ + struct list_head pipe_list; + /* Display functions */ struct { /* Top level crtc-ish functions */ diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c index 23bfecc983e8..9c2f7ad6c7b7 100644 --- a/drivers/gpu/drm/i915/display/intel_display_driver.c +++ b/drivers/gpu/drm/i915/display/intel_display_driver.c @@ -117,6 +117,7 @@ static void intel_mode_config_init(struct intel_display *display) drm_mode_config_init(display->drm); INIT_LIST_HEAD(&display->global.obj_list); + INIT_LIST_HEAD(&display->pipe_list); mode_config->min_width = 0; mode_config->min_height = 0; diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index e2496db1642a..f6cd0a062090 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1484,6 +1484,7 @@ struct intel_flipq { struct intel_crtc { struct drm_crtc base; + struct list_head pipe_head; enum pipe pipe; /* * Whether the crtc and the connected output pipeline is active. Implies diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c index d0c76632a946..a8d56ebf06a2 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c +++ b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c @@ -615,8 +615,13 @@ check_if_vesa_backlight_possible(struct intel_dp *intel_dp) int ret; u8 bit_min, bit_max; - if (!(intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP)) - return true; + /* + * Since we only support Fully AUX Based VESA Backlight interface make sure + * backlight enable is possible via AUX along with backlight adjustment + */ + if (!(intel_dp->edp_dpcd[1] & DP_EDP_BACKLIGHT_AUX_ENABLE_CAP && + intel_dp->edp_dpcd[2] & DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP)) + return false; ret = drm_dp_dpcd_read_byte(&intel_dp->aux, DP_EDP_PWMGEN_BIT_COUNT_CAP_MIN, &bit_min); if (ret < 0) diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index d45b3bcc6ef0..e0ac4e2ce4dc 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -4028,8 +4028,8 @@ void intel_wm_state_verify(struct intel_atomic_state *state, } /* DDB */ - hw_ddb_entry = &hw->ddb[PLANE_CURSOR]; - sw_ddb_entry = &new_crtc_state->wm.skl.plane_ddb[PLANE_CURSOR]; + hw_ddb_entry = &hw->ddb[plane->id]; + sw_ddb_entry = &new_crtc_state->wm.skl.plane_ddb[plane->id]; if (!skl_ddb_entry_equal(hw_ddb_entry, sw_ddb_entry)) { drm_err(display->drm, diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 5c72aad3dae7..aac6733ddd82 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -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; diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 87fd6255c114..53d06053dec8 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -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: diff --git a/drivers/gpu/drm/xe/display/xe_display.c b/drivers/gpu/drm/xe/display/xe_display.c index a0a4ddf3bb46..00dfa68af29a 100644 --- a/drivers/gpu/drm/xe/display/xe_display.c +++ b/drivers/gpu/drm/xe/display/xe_display.c @@ -21,6 +21,7 @@ #include "intel_audio.h" #include "intel_bw.h" #include "intel_display.h" +#include "intel_display_core.h" #include "intel_display_device.h" #include "intel_display_driver.h" #include "intel_display_irq.h" diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index af8b92d2d5b7..f83f28cae207 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -694,6 +694,39 @@ enum drm_bus_flags { }; /** + * 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 * * Describes a given display (e.g. CRT or flat panel) and its limitations. For @@ -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, |
