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
  ...
This commit is contained in:
Linus Torvalds
2026-04-21 17:39:21 -07:00
85 changed files with 1165 additions and 780 deletions

View File

@@ -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

View File

@@ -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"

View File

@@ -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 \

View File

@@ -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

View File

@@ -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)

View File

@@ -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);

View File

@@ -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 {

View File

@@ -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;

View File

@@ -210,12 +210,24 @@ static void amdgpu_devcoredump_fw_info(struct amdgpu_device *adev,
static ssize_t
amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_info *coredump)
{
struct amdgpu_device *adev = coredump->adev;
struct drm_printer p;
struct drm_print_iterator iter;
struct amdgpu_vm_fault_info *fault_info;
struct amdgpu_bo_va_mapping *mapping;
struct amdgpu_ip_block *ip_block;
int ver;
struct amdgpu_res_cursor cursor;
struct amdgpu_bo *abo, *root;
uint64_t va_start, offset;
struct amdgpu_ring *ring;
struct amdgpu_vm *vm;
u32 *ib_content;
uint8_t *kptr;
int ver, i, j, r;
u32 ring_idx, off;
bool sizing_pass;
sizing_pass = buffer == NULL;
iter.data = buffer;
iter.offset = 0;
iter.remain = count;
@@ -303,23 +315,25 @@ amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_inf
/* Add ring buffer information */
drm_printf(&p, "Ring buffer information\n");
for (int i = 0; i < coredump->adev->num_rings; i++) {
int j = 0;
struct amdgpu_ring *ring = coredump->adev->rings[i];
if (coredump->num_rings) {
for (i = 0; i < coredump->num_rings; i++) {
ring_idx = coredump->rings[i].ring_index;
ring = coredump->adev->rings[ring_idx];
off = coredump->rings[i].offset;
drm_printf(&p, "ring name: %s\n", ring->name);
drm_printf(&p, "Rptr: 0x%llx Wptr: 0x%llx RB mask: %x\n",
amdgpu_ring_get_rptr(ring),
amdgpu_ring_get_wptr(ring),
ring->buf_mask);
drm_printf(&p, "Ring size in dwords: %d\n",
ring->ring_size / 4);
drm_printf(&p, "Ring contents\n");
drm_printf(&p, "Offset \t Value\n");
drm_printf(&p, "ring name: %s\n", ring->name);
drm_printf(&p, "Rptr: 0x%llx Wptr: 0x%llx RB mask: %x\n",
coredump->rings[i].rptr,
coredump->rings[i].wptr,
ring->buf_mask);
drm_printf(&p, "Ring size in dwords: %d\n",
ring->ring_size / 4);
drm_printf(&p, "Ring contents\n");
drm_printf(&p, "Offset \t Value\n");
while (j < ring->ring_size) {
drm_printf(&p, "0x%x \t 0x%x\n", j, ring->ring[j / 4]);
j += 4;
for (j = 0; j < ring->ring_size; j += 4)
drm_printf(&p, "0x%x \t 0x%x\n", j,
coredump->rings_dw[off + j / 4]);
}
}
@@ -328,6 +342,87 @@ amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_inf
else if (coredump->reset_vram_lost)
drm_printf(&p, "VRAM is lost due to GPU reset!\n");
if (coredump->num_ibs) {
/* Don't try to lookup the VM or map the BOs when calculating the
* size required to store the devcoredump.
*/
if (sizing_pass)
vm = NULL;
else
vm = amdgpu_vm_lock_by_pasid(adev, &root, coredump->pasid);
for (int i = 0; i < coredump->num_ibs && (sizing_pass || vm); i++) {
ib_content = kvmalloc_array(coredump->ibs[i].ib_size_dw, 4,
GFP_KERNEL);
if (!ib_content)
continue;
/* vm=NULL can only happen when 'sizing_pass' is true. Skip to the
* drm_printf() calls (ib_content doesn't need to be initialized
* as its content won't be written anywhere).
*/
if (!vm)
goto output_ib_content;
va_start = coredump->ibs[i].gpu_addr & AMDGPU_GMC_HOLE_MASK;
mapping = amdgpu_vm_bo_lookup_mapping(vm, va_start / AMDGPU_GPU_PAGE_SIZE);
if (!mapping)
goto free_ib_content;
offset = va_start - (mapping->start * AMDGPU_GPU_PAGE_SIZE);
abo = amdgpu_bo_ref(mapping->bo_va->base.bo);
r = amdgpu_bo_reserve(abo, false);
if (r)
goto free_ib_content;
if (abo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS) {
off = 0;
if (abo->tbo.resource->mem_type != TTM_PL_VRAM)
goto unreserve_abo;
amdgpu_res_first(abo->tbo.resource, offset,
coredump->ibs[i].ib_size_dw * 4,
&cursor);
while (cursor.remaining) {
amdgpu_device_mm_access(adev, cursor.start / 4,
&ib_content[off], cursor.size / 4,
false);
off += cursor.size;
amdgpu_res_next(&cursor, cursor.size);
}
} else {
r = ttm_bo_kmap(&abo->tbo, 0,
PFN_UP(abo->tbo.base.size),
&abo->kmap);
if (r)
goto unreserve_abo;
kptr = amdgpu_bo_kptr(abo);
kptr += offset;
memcpy(ib_content, kptr,
coredump->ibs[i].ib_size_dw * 4);
amdgpu_bo_kunmap(abo);
}
output_ib_content:
drm_printf(&p, "\nIB #%d 0x%llx %d dw\n",
i, coredump->ibs[i].gpu_addr, coredump->ibs[i].ib_size_dw);
for (int j = 0; j < coredump->ibs[i].ib_size_dw; j++)
drm_printf(&p, "0x%08x\n", ib_content[j]);
unreserve_abo:
if (vm)
amdgpu_bo_unreserve(abo);
free_ib_content:
kvfree(ib_content);
}
if (vm) {
amdgpu_bo_unreserve(root);
amdgpu_bo_unref(&root);
}
}
return count - iter.remain;
}
@@ -359,6 +454,8 @@ static void amdgpu_devcoredump_free(void *data)
struct amdgpu_coredump_info *coredump = data;
kvfree(coredump->formatted);
kvfree(coredump->rings);
kvfree(coredump->rings_dw);
kvfree(data);
}
@@ -395,18 +492,26 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
{
struct drm_device *dev = adev_to_drm(adev);
struct amdgpu_coredump_info *coredump;
size_t size = sizeof(*coredump);
struct drm_sched_job *s_job;
u64 total_ring_size, ring_count;
struct amdgpu_ring *ring;
int i, off, idx;
/* No need to generate a new coredump if there's one in progress already. */
if (work_pending(&adev->coredump_work))
return;
coredump = kzalloc_obj(*coredump, GFP_NOWAIT);
if (job && job->pasid)
size += sizeof(struct amdgpu_coredump_ib_info) * job->num_ibs;
coredump = kzalloc(size, GFP_NOWAIT);
if (!coredump)
return;
coredump->skip_vram_check = skip_vram_check;
coredump->reset_vram_lost = vram_lost;
coredump->pasid = job->pasid;
if (job && job->pasid) {
struct amdgpu_task_info *ti;
@@ -416,6 +521,11 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
coredump->reset_task_info = *ti;
amdgpu_vm_put_task_info(ti);
}
coredump->num_ibs = job->num_ibs;
for (i = 0; i < job->num_ibs; ++i) {
coredump->ibs[i].gpu_addr = job->ibs[i].gpu_addr;
coredump->ibs[i].ib_size_dw = job->ibs[i].length_dw;
}
}
if (job) {
@@ -423,6 +533,47 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
coredump->ring = to_amdgpu_ring(s_job->sched);
}
/* Dump ring content if memory allocation succeeds. */
ring_count = 0;
total_ring_size = 0;
for (i = 0; i < adev->num_rings; i++) {
ring = adev->rings[i];
/* Only dump rings with unsignalled fences. */
if (atomic_read(&ring->fence_drv.last_seq) == ring->fence_drv.sync_seq &&
coredump->ring != ring)
continue;
total_ring_size += ring->ring_size;
ring_count++;
}
coredump->rings_dw = kzalloc(total_ring_size, GFP_NOWAIT);
coredump->rings = kcalloc(ring_count, sizeof(struct amdgpu_coredump_ring), GFP_NOWAIT);
if (coredump->rings && coredump->rings_dw) {
for (i = 0, off = 0, idx = 0; i < adev->num_rings; i++) {
ring = adev->rings[i];
if (atomic_read(&ring->fence_drv.last_seq) == ring->fence_drv.sync_seq &&
coredump->ring != ring)
continue;
coredump->rings[idx].ring_index = ring->idx;
coredump->rings[idx].rptr = amdgpu_ring_get_rptr(ring);
coredump->rings[idx].wptr = amdgpu_ring_get_wptr(ring);
coredump->rings[idx].offset = off;
memcpy(&coredump->rings_dw[off], ring->ring, ring->ring_size);
off += ring->ring_size;
idx++;
}
coredump->num_rings = idx;
} else {
kvfree(coredump->rings_dw);
kvfree(coredump->rings);
coredump->rings_dw = NULL;
coredump->rings = NULL;
}
coredump->adev = adev;
ktime_get_ts64(&coredump->reset_time);

View File

@@ -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

View File

@@ -3757,15 +3757,13 @@ int amdgpu_device_init(struct amdgpu_device *adev,
spin_lock_init(&adev->virt.rlcg_reg_lock);
spin_lock_init(&adev->wb.lock);
xa_init_flags(&adev->userq_xa, XA_FLAGS_LOCK_IRQ);
INIT_LIST_HEAD(&adev->reset_list);
INIT_LIST_HEAD(&adev->ras_list);
INIT_LIST_HEAD(&adev->pm.od_kobj_list);
xa_init(&adev->userq_doorbell_xa);
xa_init_flags(&adev->userq_doorbell_xa, XA_FLAGS_LOCK_IRQ);
INIT_DELAYED_WORK(&adev->delayed_init_work,
amdgpu_device_delayed_init_work_handler);
@@ -4065,7 +4063,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
}
/* must succeed. */
amdgpu_ras_resume(adev);
queue_delayed_work(system_wq, &adev->delayed_init_work,
queue_delayed_work(system_dfl_wq, &adev->delayed_init_work,
msecs_to_jiffies(AMDGPU_RESUME_MS));
}
@@ -4630,7 +4628,7 @@ int amdgpu_device_resume(struct drm_device *dev, bool notify_clients)
if (r)
goto exit;
queue_delayed_work(system_wq, &adev->delayed_init_work,
queue_delayed_work(system_dfl_wq, &adev->delayed_init_work,
msecs_to_jiffies(AMDGPU_RESUME_MS));
exit:
if (amdgpu_sriov_vf(adev)) {
@@ -5339,7 +5337,7 @@ int amdgpu_do_asic_reset(struct list_head *device_list_handle,
list_for_each_entry(tmp_adev, device_list_handle, reset_list) {
/* For XGMI run all resets in parallel to speed up the process */
if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) {
if (!queue_work(system_unbound_wq,
if (!queue_work(system_dfl_wq,
&tmp_adev->xgmi_reset_work))
r = -EALREADY;
} else

View File

@@ -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:

View File

@@ -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);

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -5726,7 +5726,7 @@ int amdgpu_ras_add_critical_region(struct amdgpu_device *adev,
static void amdgpu_ras_critical_region_init(struct amdgpu_device *adev)
{
amdgpu_ras_add_critical_region(adev, adev->mman.fw_reserved_memory);
amdgpu_ras_add_critical_region(adev, adev->mman.resv_region[AMDGPU_RESV_FW].bo);
}
static void amdgpu_ras_critical_region_fini(struct amdgpu_device *adev)

View File

@@ -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,

View File

@@ -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,

View File

@@ -1671,87 +1671,160 @@ static struct ttm_device_funcs amdgpu_bo_driver = {
.access_memory = &amdgpu_ttm_access_memory,
};
/*
* Firmware Reservation functions
*/
/**
* amdgpu_ttm_fw_reserve_vram_fini - free fw reserved vram
*
* @adev: amdgpu_device pointer
*
* free fw reserved vram if it has been reserved.
*/
static void amdgpu_ttm_fw_reserve_vram_fini(struct amdgpu_device *adev)
void amdgpu_ttm_init_vram_resv(struct amdgpu_device *adev,
enum amdgpu_resv_region_id id,
uint64_t offset, uint64_t size,
bool needs_cpu_map)
{
amdgpu_bo_free_kernel(&adev->mman.fw_vram_usage_reserved_bo,
NULL, &adev->mman.fw_vram_usage_va);
struct amdgpu_vram_resv *resv;
if (id >= AMDGPU_RESV_MAX)
return;
resv = &adev->mman.resv_region[id];
resv->offset = offset;
resv->size = size;
resv->needs_cpu_map = needs_cpu_map;
}
/*
* Driver Reservation functions
*/
/**
* amdgpu_ttm_drv_reserve_vram_fini - free drv reserved vram
*
* @adev: amdgpu_device pointer
*
* free drv reserved vram if it has been reserved.
*/
static void amdgpu_ttm_drv_reserve_vram_fini(struct amdgpu_device *adev)
static void amdgpu_ttm_init_fw_resv_region(struct amdgpu_device *adev)
{
amdgpu_bo_free_kernel(&adev->mman.drv_vram_usage_reserved_bo,
NULL,
&adev->mman.drv_vram_usage_va);
uint32_t reserve_size = 0;
if (!adev->discovery.reserve_tmr)
return;
/*
* Query reserved tmr size through atom firmwareinfo for Sienna_Cichlid and onwards for all
* the use cases (IP discovery/G6 memory training/profiling/diagnostic data.etc)
*
* Otherwise, fallback to legacy approach to check and reserve tmr block for ip
* discovery data and G6 memory training data respectively
*/
if (adev->bios)
reserve_size =
amdgpu_atomfirmware_get_fw_reserved_fb_size(adev);
if (!adev->bios &&
(amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 3) ||
amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 4) ||
amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 5, 0)))
reserve_size = max(reserve_size, (uint32_t)280 << 20);
else if (!adev->bios &&
amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(12, 1, 0)) {
if (hweight32(adev->aid_mask) == 1)
reserve_size = max(reserve_size, (uint32_t)128 << 20);
else
reserve_size = max(reserve_size, (uint32_t)144 << 20);
} else if (!reserve_size)
reserve_size = DISCOVERY_TMR_OFFSET;
amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_FW,
adev->gmc.real_vram_size - reserve_size,
reserve_size, false);
}
/**
* amdgpu_ttm_fw_reserve_vram_init - create bo vram reservation from fw
*
* @adev: amdgpu_device pointer
*
* create bo vram reservation from fw.
*/
static int amdgpu_ttm_fw_reserve_vram_init(struct amdgpu_device *adev)
static void amdgpu_ttm_init_mem_train_resv_region(struct amdgpu_device *adev)
{
uint64_t reserve_size;
uint64_t offset;
if (!adev->discovery.reserve_tmr)
return;
if (!adev->bios || amdgpu_sriov_vf(adev))
return;
if (!amdgpu_atomfirmware_mem_training_supported(adev))
return;
reserve_size = adev->mman.resv_region[AMDGPU_RESV_FW].size;
offset = ALIGN((adev->gmc.mc_vram_size - reserve_size - SZ_1M), SZ_1M);
amdgpu_ttm_init_vram_resv(adev, AMDGPU_RESV_MEM_TRAIN,
offset,
GDDR6_MEM_TRAINING_DATA_SIZE_IN_BYTES,
false);
}
static void amdgpu_ttm_init_vram_resv_regions(struct amdgpu_device *adev)
{
uint64_t vram_size = adev->gmc.visible_vram_size;
adev->mman.fw_vram_usage_va = NULL;
adev->mman.fw_vram_usage_reserved_bo = NULL;
/* Initialize memory reservations as required for VGA.
* This is used for VGA emulation and pre-OS scanout buffers to
* avoid display artifacts while transitioning between pre-OS
* and driver.
*/
amdgpu_gmc_init_vga_resv_regions(adev);
amdgpu_ttm_init_fw_resv_region(adev);
amdgpu_ttm_init_mem_train_resv_region(adev);
if (adev->mman.fw_vram_usage_size == 0 ||
adev->mman.fw_vram_usage_size > vram_size)
return 0;
if (adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].size > vram_size)
adev->mman.resv_region[AMDGPU_RESV_FW_VRAM_USAGE].size = 0;
return amdgpu_bo_create_kernel_at(adev,
adev->mman.fw_vram_usage_start_offset,
adev->mman.fw_vram_usage_size,
&adev->mman.fw_vram_usage_reserved_bo,
&adev->mman.fw_vram_usage_va);
if (adev->mman.resv_region[AMDGPU_RESV_DRV_VRAM_USAGE].size > vram_size)
adev->mman.resv_region[AMDGPU_RESV_DRV_VRAM_USAGE].size = 0;
}
/**
* amdgpu_ttm_drv_reserve_vram_init - create bo vram reservation from driver
*
* @adev: amdgpu_device pointer
*
* create bo vram reservation from drv.
*/
static int amdgpu_ttm_drv_reserve_vram_init(struct amdgpu_device *adev)
int amdgpu_ttm_mark_vram_reserved(struct amdgpu_device *adev,
enum amdgpu_resv_region_id id)
{
u64 vram_size = adev->gmc.visible_vram_size;
struct amdgpu_vram_resv *resv;
int ret;
adev->mman.drv_vram_usage_va = NULL;
adev->mman.drv_vram_usage_reserved_bo = NULL;
if (id >= AMDGPU_RESV_MAX)
return -EINVAL;
if (adev->mman.drv_vram_usage_size == 0 ||
adev->mman.drv_vram_usage_size > vram_size)
resv = &adev->mman.resv_region[id];
if (!resv->size)
return 0;
return amdgpu_bo_create_kernel_at(adev,
adev->mman.drv_vram_usage_start_offset,
adev->mman.drv_vram_usage_size,
&adev->mman.drv_vram_usage_reserved_bo,
&adev->mman.drv_vram_usage_va);
ret = amdgpu_bo_create_kernel_at(adev, resv->offset, resv->size,
&resv->bo,
resv->needs_cpu_map ? &resv->cpu_ptr : NULL);
if (ret) {
dev_err(adev->dev,
"reserve vram failed: id=%d offset=0x%llx size=0x%llx ret=%d\n",
id, resv->offset, resv->size, ret);
memset(resv, 0, sizeof(*resv));
}
return ret;
}
void amdgpu_ttm_unmark_vram_reserved(struct amdgpu_device *adev,
enum amdgpu_resv_region_id id)
{
struct amdgpu_vram_resv *resv;
if (id >= AMDGPU_RESV_MAX)
return;
resv = &adev->mman.resv_region[id];
if (!resv->bo)
return;
amdgpu_bo_free_kernel(&resv->bo, NULL,
resv->needs_cpu_map ? &resv->cpu_ptr : NULL);
memset(resv, 0, sizeof(*resv));
}
/*
* Reserve all regions with non-zero size. Regions whose info is not
* yet available (e.g., fw extended region) may still be reserved
* during runtime.
*/
static int amdgpu_ttm_alloc_vram_resv_regions(struct amdgpu_device *adev)
{
int i, r;
for (i = 0; i < AMDGPU_RESV_MAX; i++) {
r = amdgpu_ttm_mark_vram_reserved(adev, i);
if (r)
return r;
}
return 0;
}
/*
@@ -1770,25 +1843,23 @@ static int amdgpu_ttm_training_reserve_vram_fini(struct amdgpu_device *adev)
struct psp_memory_training_context *ctx = &adev->psp.mem_train_ctx;
ctx->init = PSP_MEM_TRAIN_NOT_SUPPORT;
amdgpu_bo_free_kernel(&ctx->c2p_bo, NULL, NULL);
ctx->c2p_bo = NULL;
amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_MEM_TRAIN);
return 0;
}
static void amdgpu_ttm_training_data_block_init(struct amdgpu_device *adev,
uint32_t reserve_size)
static void amdgpu_ttm_training_data_block_init(struct amdgpu_device *adev)
{
struct psp_memory_training_context *ctx = &adev->psp.mem_train_ctx;
struct amdgpu_vram_resv *resv =
&adev->mman.resv_region[AMDGPU_RESV_MEM_TRAIN];
memset(ctx, 0, sizeof(*ctx));
ctx->c2p_train_data_offset =
ALIGN((adev->gmc.mc_vram_size - reserve_size - SZ_1M), SZ_1M);
ctx->c2p_train_data_offset = resv->offset;
ctx->p2c_train_data_offset =
(adev->gmc.mc_vram_size - GDDR6_MEM_TRAINING_OFFSET);
ctx->train_data_size =
GDDR6_MEM_TRAINING_DATA_SIZE_IN_BYTES;
ctx->train_data_size = resv->size;
DRM_DEBUG("train_data_size:%llx,p2c_train_data_offset:%llx,c2p_train_data_offset:%llx.\n",
ctx->train_data_size,
@@ -1796,78 +1867,6 @@ static void amdgpu_ttm_training_data_block_init(struct amdgpu_device *adev,
ctx->c2p_train_data_offset);
}
/*
* reserve TMR memory at the top of VRAM which holds
* IP Discovery data and is protected by PSP.
*/
static int amdgpu_ttm_reserve_tmr(struct amdgpu_device *adev)
{
struct psp_memory_training_context *ctx = &adev->psp.mem_train_ctx;
bool mem_train_support = false;
uint32_t reserve_size = 0;
int ret;
if (adev->bios && !amdgpu_sriov_vf(adev)) {
if (amdgpu_atomfirmware_mem_training_supported(adev))
mem_train_support = true;
else
DRM_DEBUG("memory training does not support!\n");
}
/*
* Query reserved tmr size through atom firmwareinfo for Sienna_Cichlid and onwards for all
* the use cases (IP discovery/G6 memory training/profiling/diagnostic data.etc)
*
* Otherwise, fallback to legacy approach to check and reserve tmr block for ip
* discovery data and G6 memory training data respectively
*/
if (adev->bios)
reserve_size =
amdgpu_atomfirmware_get_fw_reserved_fb_size(adev);
if (!adev->bios &&
(amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 3) ||
amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 4) ||
amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 5, 0)))
reserve_size = max(reserve_size, (uint32_t)280 << 20);
else if (!adev->bios &&
amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(12, 1, 0)) {
if (hweight32(adev->aid_mask) == 1)
reserve_size = max(reserve_size, (uint32_t)128 << 20);
else
reserve_size = max(reserve_size, (uint32_t)144 << 20);
} else if (!reserve_size)
reserve_size = DISCOVERY_TMR_OFFSET;
if (mem_train_support) {
/* reserve vram for mem train according to TMR location */
amdgpu_ttm_training_data_block_init(adev, reserve_size);
ret = amdgpu_bo_create_kernel_at(adev,
ctx->c2p_train_data_offset,
ctx->train_data_size,
&ctx->c2p_bo,
NULL);
if (ret) {
dev_err(adev->dev, "alloc c2p_bo failed(%d)!\n", ret);
amdgpu_ttm_training_reserve_vram_fini(adev);
return ret;
}
ctx->init = PSP_MEM_TRAIN_RESERVE_SUCCESS;
}
ret = amdgpu_bo_create_kernel_at(
adev, adev->gmc.real_vram_size - reserve_size, reserve_size,
&adev->mman.fw_reserved_memory, NULL);
if (ret) {
dev_err(adev->dev, "alloc tmr failed(%d)!\n", ret);
amdgpu_bo_free_kernel(&adev->mman.fw_reserved_memory, NULL,
NULL);
return ret;
}
return 0;
}
static int amdgpu_ttm_pools_init(struct amdgpu_device *adev)
{
int i;
@@ -2115,63 +2114,18 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
adev->gmc.visible_vram_size);
#endif
/*
*The reserved vram for firmware must be pinned to the specified
*place on the VRAM, so reserve it early.
*/
r = amdgpu_ttm_fw_reserve_vram_init(adev);
amdgpu_ttm_init_vram_resv_regions(adev);
r = amdgpu_ttm_alloc_vram_resv_regions(adev);
if (r)
return r;
/*
* The reserved VRAM for the driver must be pinned to a specific
* location in VRAM, so reserve it early.
*/
r = amdgpu_ttm_drv_reserve_vram_init(adev);
if (r)
return r;
if (adev->mman.resv_region[AMDGPU_RESV_MEM_TRAIN].size) {
struct psp_memory_training_context *ctx =
&adev->psp.mem_train_ctx;
/*
* only NAVI10 and later ASICs support IP discovery.
* If IP discovery is enabled, a block of memory should be
* reserved for it.
*/
if (adev->discovery.reserve_tmr) {
r = amdgpu_ttm_reserve_tmr(adev);
if (r)
return r;
}
/* allocate memory as required for VGA
* This is used for VGA emulation and pre-OS scanout buffers to
* avoid display artifacts while transitioning between pre-OS
* and driver.
*/
if (!adev->gmc.is_app_apu) {
r = amdgpu_bo_create_kernel_at(adev, 0,
adev->mman.stolen_vga_size,
&adev->mman.stolen_vga_memory,
NULL);
if (r)
return r;
r = amdgpu_bo_create_kernel_at(adev, adev->mman.stolen_vga_size,
adev->mman.stolen_extended_size,
&adev->mman.stolen_extended_memory,
NULL);
if (r)
return r;
r = amdgpu_bo_create_kernel_at(adev,
adev->mman.stolen_reserved_offset,
adev->mman.stolen_reserved_size,
&adev->mman.stolen_reserved_memory,
NULL);
if (r)
return r;
} else {
DRM_DEBUG_DRIVER("Skipped stolen memory reservation\n");
amdgpu_ttm_training_data_block_init(adev);
ctx->init = PSP_MEM_TRAIN_RESERVE_SUCCESS;
}
dev_info(adev->dev, " %uM of VRAM memory ready\n",
@@ -2284,23 +2238,19 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev)
amdgpu_ttm_training_reserve_vram_fini(adev);
/* return the stolen vga memory back to VRAM */
if (!adev->gmc.is_app_apu) {
amdgpu_bo_free_kernel(&adev->mman.stolen_vga_memory, NULL, NULL);
amdgpu_bo_free_kernel(&adev->mman.stolen_extended_memory, NULL, NULL);
amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_STOLEN_VGA);
amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_STOLEN_EXTENDED);
/* return the FW reserved memory back to VRAM */
amdgpu_bo_free_kernel(&adev->mman.fw_reserved_memory, NULL,
NULL);
amdgpu_bo_free_kernel(&adev->mman.fw_reserved_memory_extend, NULL,
NULL);
if (adev->mman.stolen_reserved_size)
amdgpu_bo_free_kernel(&adev->mman.stolen_reserved_memory,
NULL, NULL);
amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_FW);
amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_FW_EXTEND);
amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_STOLEN_RESERVED);
}
amdgpu_bo_free_kernel(&adev->mman.sdma_access_bo, NULL,
&adev->mman.sdma_access_ptr);
amdgpu_ttm_free_mmio_remap_bo(adev);
amdgpu_ttm_fw_reserve_vram_fini(adev);
amdgpu_ttm_drv_reserve_vram_fini(adev);
amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_FW_VRAM_USAGE);
amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_DRV_VRAM_USAGE);
if (drm_dev_enter(adev_to_drm(adev), &idx)) {

View File

@@ -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,

View File

@@ -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)

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -1978,7 +1978,6 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
struct amdgpu_bo_va_mapping *mapping;
struct amdgpu_vm *vm = bo_va->base.vm;
bool valid = true;
int r;
saddr /= AMDGPU_GPU_PAGE_SIZE;
@@ -2003,12 +2002,8 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
* during user requests GEM unmap IOCTL except for forcing the unmap
* from user space.
*/
if (unlikely(atomic_read(&bo_va->userq_va_mapped) > 0)) {
r = amdgpu_userq_gem_va_unmap_validate(adev, mapping, saddr);
if (unlikely(r == -EBUSY))
dev_warn_once(adev->dev,
"Attempt to unmap an active userq buffer\n");
}
if (unlikely(atomic_read(&bo_va->userq_va_mapped) > 0))
amdgpu_userq_gem_va_unmap_validate(adev, mapping, saddr);
list_del(&mapping->list);
amdgpu_vm_it_remove(mapping, &vm->va);
@@ -2954,6 +2949,50 @@ int amdgpu_vm_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
return 0;
}
/**
* amdgpu_vm_lock_by_pasid - return an amdgpu_vm and its root bo from a pasid, if possible.
* @adev: amdgpu device pointer
* @root: root BO of the VM
* @pasid: PASID of the VM
* The caller needs to unreserve and unref the root bo on success.
*/
struct amdgpu_vm *amdgpu_vm_lock_by_pasid(struct amdgpu_device *adev,
struct amdgpu_bo **root, u32 pasid)
{
unsigned long irqflags;
struct amdgpu_vm *vm;
int r;
xa_lock_irqsave(&adev->vm_manager.pasids, irqflags);
vm = xa_load(&adev->vm_manager.pasids, pasid);
*root = vm ? amdgpu_bo_ref(vm->root.bo) : NULL;
xa_unlock_irqrestore(&adev->vm_manager.pasids, irqflags);
if (!*root)
return NULL;
r = amdgpu_bo_reserve(*root, true);
if (r)
goto error_unref;
/* Double check that the VM still exists */
xa_lock_irqsave(&adev->vm_manager.pasids, irqflags);
vm = xa_load(&adev->vm_manager.pasids, pasid);
if (vm && vm->root.bo != *root)
vm = NULL;
xa_unlock_irqrestore(&adev->vm_manager.pasids, irqflags);
if (!vm)
goto error_unlock;
return vm;
error_unlock:
amdgpu_bo_unreserve(*root);
error_unref:
amdgpu_bo_unref(root);
return NULL;
}
/**
* amdgpu_vm_handle_fault - graceful handling of VM faults.
* @adev: amdgpu device pointer
@@ -2969,50 +3008,29 @@ int amdgpu_vm_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
* shouldn't be reported any more.
*/
bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, u32 pasid,
u32 vmid, u32 node_id, uint64_t addr, uint64_t ts,
bool write_fault)
u32 vmid, u32 node_id, uint64_t addr,
uint64_t ts, bool write_fault)
{
bool is_compute_context = false;
struct amdgpu_bo *root;
unsigned long irqflags;
uint64_t value, flags;
struct amdgpu_vm *vm;
int r;
xa_lock_irqsave(&adev->vm_manager.pasids, irqflags);
vm = xa_load(&adev->vm_manager.pasids, pasid);
if (vm) {
root = amdgpu_bo_ref(vm->root.bo);
is_compute_context = vm->is_compute_context;
} else {
root = NULL;
}
xa_unlock_irqrestore(&adev->vm_manager.pasids, irqflags);
if (!root)
vm = amdgpu_vm_lock_by_pasid(adev, &root, pasid);
if (!vm)
return false;
is_compute_context = vm->is_compute_context;
if (is_compute_context && !svm_range_restore_pages(adev, pasid, vmid,
node_id, addr >> PAGE_SHIFT, ts, write_fault)) {
amdgpu_bo_unreserve(root);
amdgpu_bo_unref(&root);
return true;
}
addr /= AMDGPU_GPU_PAGE_SIZE;
r = amdgpu_bo_reserve(root, true);
if (r)
goto error_unref;
/* Double check that the VM still exists */
xa_lock_irqsave(&adev->vm_manager.pasids, irqflags);
vm = xa_load(&adev->vm_manager.pasids, pasid);
if (vm && vm->root.bo != root)
vm = NULL;
xa_unlock_irqrestore(&adev->vm_manager.pasids, irqflags);
if (!vm)
goto error_unlock;
flags = AMDGPU_PTE_VALID | AMDGPU_PTE_SNOOPED |
AMDGPU_PTE_SYSTEM;
@@ -3051,7 +3069,6 @@ bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, u32 pasid,
if (r < 0)
dev_err(adev->dev, "Can't handle page fault (%d)\n", r);
error_unref:
amdgpu_bo_unref(&root);
return false;

View File

@@ -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,

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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)

View File

@@ -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)

View File

@@ -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);

View File

@@ -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;

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -1826,7 +1826,7 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
struct ttm_operation_ctx ctx = { false, false };
struct amdgpu_device *adev = p->adev;
struct amdgpu_bo_va_mapping *map;
uint32_t *msg, num_buffers;
uint32_t *msg, num_buffers, len_dw;
struct amdgpu_bo *bo;
uint64_t start, end;
unsigned int i;
@@ -1847,6 +1847,11 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
return -EINVAL;
}
if (end - addr < 16) {
DRM_ERROR("VCN messages must be at least 4 DWORDs!\n");
return -EINVAL;
}
bo->flags |= AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
amdgpu_bo_placement_from_domain(bo, bo->allowed_domains);
r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
@@ -1863,8 +1868,8 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
msg = ptr + addr - start;
/* Check length */
if (msg[1] > end - addr) {
DRM_ERROR("VCN message header does not fit in BO!\n");
r = -EINVAL;
goto out;
}
@@ -1872,7 +1877,16 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
if (msg[3] != RDECODE_MSG_CREATE)
goto out;
len_dw = msg[1] / 4;
num_buffers = msg[2];
/* Verify that all indices fit within the claimed length. Each index is 4 DWORDs */
if (num_buffers > len_dw || 6 + num_buffers * 4 > len_dw) {
DRM_ERROR("VCN message has too many buffers!\n");
r = -EINVAL;
goto out;
}
for (i = 0, msg = &msg[6]; i < num_buffers; ++i, msg += 4) {
uint32_t offset, size, *create;
@@ -1882,7 +1896,8 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
offset = msg[1];
size = msg[2];
if (offset + size > end) {
if (size < 4 || offset + size > end - addr) {
DRM_ERROR("VCN message buffer exceeds BO bounds!\n");
r = -EINVAL;
goto out;
}
@@ -1913,9 +1928,10 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
static int vcn_v4_0_enc_find_ib_param(struct amdgpu_ib *ib, uint32_t id, int start)
{
int i;
uint32_t len;
for (i = start; i < ib->length_dw && ib->ptr[i] >= 8; i += ib->ptr[i] / 4) {
if (ib->ptr[i + 1] == id)
for (i = start; (len = amdgpu_ib_get_value(ib, i)) >= 8; i += len / 4) {
if (amdgpu_ib_get_value(ib, i + 1) == id)
return i;
}
return -1;
@@ -1926,8 +1942,6 @@ static int vcn_v4_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p,
struct amdgpu_ib *ib)
{
struct amdgpu_ring *ring = amdgpu_job_ring(job);
struct amdgpu_vcn_decode_buffer *decode_buffer;
uint64_t addr;
uint32_t val;
int idx = 0, sidx;
@@ -1938,20 +1952,22 @@ static int vcn_v4_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p,
while ((idx = vcn_v4_0_enc_find_ib_param(ib, RADEON_VCN_ENGINE_INFO, idx)) >= 0) {
val = amdgpu_ib_get_value(ib, idx + 2); /* RADEON_VCN_ENGINE_TYPE */
if (val == RADEON_VCN_ENGINE_TYPE_DECODE) {
decode_buffer = (struct amdgpu_vcn_decode_buffer *)&ib->ptr[idx + 6];
uint32_t valid_buf_flag = amdgpu_ib_get_value(ib, idx + 6);
uint64_t msg_buffer_addr;
if (!(decode_buffer->valid_buf_flag & 0x1))
if (!(valid_buf_flag & 0x1))
return 0;
addr = ((u64)decode_buffer->msg_buffer_address_hi) << 32 |
decode_buffer->msg_buffer_address_lo;
return vcn_v4_0_dec_msg(p, job, addr);
msg_buffer_addr = ((u64)amdgpu_ib_get_value(ib, idx + 7)) << 32 |
amdgpu_ib_get_value(ib, idx + 8);
return vcn_v4_0_dec_msg(p, job, msg_buffer_addr);
} else if (val == RADEON_VCN_ENGINE_TYPE_ENCODE) {
sidx = vcn_v4_0_enc_find_ib_param(ib, RENCODE_IB_PARAM_SESSION_INIT, idx);
if (sidx >= 0 && ib->ptr[sidx + 2] == RENCODE_ENCODE_STANDARD_AV1)
if (sidx >= 0 &&
amdgpu_ib_get_value(ib, sidx + 2) == RENCODE_ENCODE_STANDARD_AV1)
return vcn_v4_0_limit_sched(p, job);
}
idx += ib->ptr[idx] / 4;
idx += amdgpu_ib_get_value(ib, idx) / 4;
}
return 0;
}

View File

@@ -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);

View File

@@ -572,7 +572,7 @@ static void schedule_dc_vmin_vmax(struct amdgpu_device *adev,
offload_work->stream = stream;
offload_work->adjust = adjust_copy;
queue_work(system_wq, &offload_work->work);
queue_work(system_percpu_wq, &offload_work->work);
}
static void dm_vupdate_high_irq(void *interrupt_params)
@@ -3833,6 +3833,66 @@ static struct drm_mode_config_helper_funcs amdgpu_dm_mode_config_helperfuncs = {
.atomic_commit_setup = amdgpu_dm_atomic_setup_commit,
};
#define DDC_MANUFACTURERNAME_SAMSUNG 0x2D4C
static void dm_set_panel_type(struct amdgpu_dm_connector *aconnector)
{
struct drm_connector *connector = &aconnector->base;
struct drm_display_info *display_info = &connector->display_info;
struct dc_link *link = aconnector->dc_link;
struct amdgpu_device *adev;
adev = drm_to_adev(connector->dev);
link->panel_type = PANEL_TYPE_NONE;
switch (display_info->amd_vsdb.panel_type) {
case AMD_VSDB_PANEL_TYPE_OLED:
link->panel_type = PANEL_TYPE_OLED;
break;
case AMD_VSDB_PANEL_TYPE_MINILED:
link->panel_type = PANEL_TYPE_MINILED;
break;
}
/* If VSDB didn't determine panel type, check DPCD ext caps */
if (link->panel_type == PANEL_TYPE_NONE) {
if (link->dpcd_sink_ext_caps.bits.miniled == 1)
link->panel_type = PANEL_TYPE_MINILED;
if (link->dpcd_sink_ext_caps.bits.oled == 1)
link->panel_type = PANEL_TYPE_OLED;
}
/*
* TODO: get panel type from DID2 that has device technology field
* to specify if it's OLED or not. But we need to wait for DID2
* support in DC and EDID parser to be able to use it here.
*/
if (link->panel_type == PANEL_TYPE_NONE) {
struct drm_amd_vsdb_info *vsdb = &display_info->amd_vsdb;
u32 lum1_max = vsdb->luminance_range1.max_luminance;
u32 lum2_max = vsdb->luminance_range2.max_luminance;
if (vsdb->version && link->local_sink &&
link->local_sink->edid_caps.manufacturer_id ==
DDC_MANUFACTURERNAME_SAMSUNG &&
lum1_max >= ((lum2_max * 3) / 2))
link->panel_type = PANEL_TYPE_MINILED;
}
if (link->panel_type == PANEL_TYPE_OLED)
drm_object_property_set_value(&connector->base,
adev_to_drm(adev)->mode_config.panel_type_property,
DRM_MODE_PANEL_TYPE_OLED);
else
drm_object_property_set_value(&connector->base,
adev_to_drm(adev)->mode_config.panel_type_property,
DRM_MODE_PANEL_TYPE_UNKNOWN);
drm_dbg_kms(aconnector->base.dev, "Panel type: %d\n", link->panel_type);
}
static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
{
const struct drm_panel_backlight_quirk *panel_backlight_quirk;
@@ -3854,10 +3914,6 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
caps->ext_caps = &aconnector->dc_link->dpcd_sink_ext_caps;
caps->aux_support = false;
drm_object_property_set_value(&conn_base->base,
adev_to_drm(adev)->mode_config.panel_type_property,
caps->ext_caps->bits.oled ? DRM_MODE_PANEL_TYPE_OLED : DRM_MODE_PANEL_TYPE_UNKNOWN);
if (caps->ext_caps->bits.oled == 1
/*
* ||
@@ -4031,6 +4087,7 @@ void amdgpu_dm_update_connector_after_detect(
amdgpu_dm_update_freesync_caps(connector, aconnector->drm_edid);
update_connector_ext_caps(aconnector);
dm_set_panel_type(aconnector);
} else {
hdmi_cec_unset_edid(aconnector);
drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux);
@@ -4211,7 +4268,7 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector)
dc_sink_retain(aconnector->hdmi_prev_sink);
/* Schedule delayed detection. */
if (mod_delayed_work(system_wq,
if (mod_delayed_work(system_percpu_wq,
&aconnector->hdmi_hpd_debounce_work,
msecs_to_jiffies(aconnector->hdmi_hpd_debounce_delay_ms)))
drm_dbg_kms(dev, "HDMI HPD: Re-scheduled debounce work\n");
@@ -11142,8 +11199,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
if (!adev->in_suspend) {
/* return the stolen vga memory back to VRAM */
if (!adev->mman.keep_stolen_vga_memory)
amdgpu_bo_free_kernel(&adev->mman.stolen_vga_memory, NULL, NULL);
amdgpu_bo_free_kernel(&adev->mman.stolen_extended_memory, NULL, NULL);
amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_STOLEN_VGA);
amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_STOLEN_EXTENDED);
}
/*
@@ -13155,56 +13212,15 @@ static void parse_edid_displayid_vrr(struct drm_connector *connector,
}
}
static int parse_amd_vsdb(struct amdgpu_dm_connector *aconnector,
const struct edid *edid, struct amdgpu_hdmi_vsdb_info *vsdb_info)
static int get_amd_vsdb(struct amdgpu_dm_connector *aconnector,
struct amdgpu_hdmi_vsdb_info *vsdb_info)
{
u8 *edid_ext = NULL;
int i;
int j = 0;
int total_ext_block_len;
struct drm_connector *connector = &aconnector->base;
if (edid == NULL || edid->extensions == 0)
return -ENODEV;
vsdb_info->replay_mode = connector->display_info.amd_vsdb.replay_mode;
vsdb_info->amd_vsdb_version = connector->display_info.amd_vsdb.version;
/* Find DisplayID extension */
for (i = 0; i < edid->extensions; i++) {
edid_ext = (void *)(edid + (i + 1));
if (edid_ext[0] == DISPLAYID_EXT)
break;
}
total_ext_block_len = EDID_LENGTH * edid->extensions;
while (j < total_ext_block_len - sizeof(struct amd_vsdb_block)) {
struct amd_vsdb_block *amd_vsdb = (struct amd_vsdb_block *)&edid_ext[j];
unsigned int ieeeId = (amd_vsdb->ieee_id[2] << 16) | (amd_vsdb->ieee_id[1] << 8) | (amd_vsdb->ieee_id[0]);
if (ieeeId == HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_IEEE_REGISTRATION_ID &&
amd_vsdb->version == HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_VERSION_3) {
u8 panel_type;
vsdb_info->replay_mode = (amd_vsdb->feature_caps & AMD_VSDB_VERSION_3_FEATURECAP_REPLAYMODE) ? true : false;
vsdb_info->amd_vsdb_version = HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_VERSION_3;
drm_dbg_kms(aconnector->base.dev, "Panel supports Replay Mode: %d\n", vsdb_info->replay_mode);
panel_type = (amd_vsdb->color_space_eotf_support & AMD_VDSB_VERSION_3_PANEL_TYPE_MASK) >> AMD_VDSB_VERSION_3_PANEL_TYPE_SHIFT;
switch (panel_type) {
case AMD_VSDB_PANEL_TYPE_OLED:
aconnector->dc_link->panel_type = PANEL_TYPE_OLED;
break;
case AMD_VSDB_PANEL_TYPE_MINILED:
aconnector->dc_link->panel_type = PANEL_TYPE_MINILED;
break;
default:
aconnector->dc_link->panel_type = PANEL_TYPE_NONE;
break;
}
drm_dbg_kms(aconnector->base.dev, "Panel type: %d\n",
aconnector->dc_link->panel_type);
return true;
}
j++;
}
return false;
return connector->display_info.amd_vsdb.version != 0;
}
static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
@@ -13307,7 +13323,7 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
freesync_capable = true;
}
parse_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
get_amd_vsdb(amdgpu_dm_connector, &vsdb_info);
if (vsdb_info.replay_mode) {
amdgpu_dm_connector->vsdb_info.replay_mode = vsdb_info.replay_mode;

View File

@@ -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;

View File

@@ -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

View File

@@ -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)
{

View File

@@ -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

View File

@@ -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++)

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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);

View File

@@ -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

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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,

View File

@@ -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;

View File

@@ -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;

View File

@@ -344,7 +344,12 @@ static int smu_v15_0_8_get_metrics_table_internal(struct smu_context *smu, uint3
}
amdgpu_device_invalidate_hdp(smu->adev, NULL);
memcpy(smu_table->metrics_table, table->cpu_addr, table_size);
ret = smu_cmn_vram_cpy(smu, smu_table->metrics_table,
table->cpu_addr, table_size);
if (ret) {
mutex_unlock(&smu_table->metrics_lock);
return ret;
}
smu_table->metrics_time = jiffies;
}
@@ -551,9 +556,14 @@ static int smu_v15_0_8_get_system_metrics_table(struct smu_context *smu)
}
amdgpu_hdp_invalidate(smu->adev, NULL);
ret = smu_cmn_vram_cpy(smu, sys_table->cache.buffer,
table->cpu_addr,
sizeof(SystemMetricsTable_t));
if (ret)
return ret;
smu_table_cache_update_time(sys_table, jiffies);
memcpy(sys_table->cache.buffer, table->cpu_addr,
sizeof(SystemMetricsTable_t));
return 0;
}
@@ -988,9 +998,9 @@ static int smu_v15_0_8_get_static_metrics_table(struct smu_context *smu)
}
amdgpu_hdp_invalidate(smu->adev, NULL);
memcpy(smu_table->metrics_table, table->cpu_addr, table_size);
return 0;
return smu_cmn_vram_cpy(smu, smu_table->metrics_table,
table->cpu_addr, table_size);
}
static int smu_v15_0_8_fru_get_product_info(struct smu_context *smu,
@@ -1601,8 +1611,6 @@ static ssize_t smu_v15_0_8_get_gpu_metrics(struct smu_context *smu, void **table
uint32_t mid_mask = adev->aid_mask;
MetricsTable_t *metrics;
metrics = kzalloc(sizeof(MetricsTable_t), GFP_KERNEL);
ret = smu_v15_0_8_get_metrics_table_internal(smu, 1, NULL);
if (ret)
return ret;
@@ -1775,7 +1783,7 @@ static int smu_v15_0_8_get_power_limit(struct smu_context *smu,
*current_power_limit = power_limit;
if (default_power_limit)
*max_power_limit = pptable->MaxSocketPowerLimit;
*default_power_limit = pptable->MaxSocketPowerLimit;
if (max_power_limit)
*max_power_limit = pptable->MaxSocketPowerLimit;
@@ -1901,42 +1909,36 @@ static int smu_v15_0_8_set_soft_freq_limited_range(struct smu_context *smu,
if (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL)
return -EINVAL;
if (smu_dpm->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) {
if (min >= max) {
dev_err(smu->adev->dev,
"Minimum clk should be less than the maximum allowed clock\n");
return -EINVAL;
}
if (clk_type == SMU_GFXCLK || clk_type == SMU_SCLK) {
if ((min == pstate_table->gfxclk_pstate.curr.min) &&
(max == pstate_table->gfxclk_pstate.curr.max))
return 0;
ret = smu_v15_0_8_set_gfx_soft_freq_limited_range(smu,
min, max);
if (!ret) {
pstate_table->gfxclk_pstate.curr.min = min;
pstate_table->gfxclk_pstate.curr.max = max;
}
}
if (clk_type == SMU_UCLK) {
if (max == pstate_table->uclk_pstate.curr.max)
return 0;
ret = smu_v15_0_set_soft_freq_limited_range(smu,
SMU_UCLK,
0, max,
false);
if (!ret)
pstate_table->uclk_pstate.curr.max = max;
}
return ret;
if (min >= max) {
dev_err(smu->adev->dev,
"Minimum clk should be less than the maximum allowed clock\n");
return -EINVAL;
}
return 0;
if (clk_type == SMU_GFXCLK || clk_type == SMU_SCLK) {
if ((min == pstate_table->gfxclk_pstate.curr.min) &&
(max == pstate_table->gfxclk_pstate.curr.max))
return 0;
ret = smu_v15_0_8_set_gfx_soft_freq_limited_range(smu, min,
max);
if (!ret) {
pstate_table->gfxclk_pstate.curr.min = min;
pstate_table->gfxclk_pstate.curr.max = max;
}
}
if (clk_type == SMU_UCLK) {
if (max == pstate_table->uclk_pstate.curr.max)
return 0;
ret = smu_v15_0_set_soft_freq_limited_range(smu, SMU_UCLK, 0,
max, false);
if (!ret)
pstate_table->uclk_pstate.curr.max = max;
}
return ret;
}
static int smu_v15_0_8_od_edit_dpm_table(struct smu_context *smu,

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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,

View File

@@ -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 @@ static int __intel_crtc_init(struct intel_display *display, enum pipe pipe)
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;
}

View File

@@ -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);

View File

@@ -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_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(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, 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, \

View File

@@ -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 */

View File

@@ -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;

View File

@@ -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

View File

@@ -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)

View File

@@ -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,

View File

@@ -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;

View File

@@ -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:

View File

@@ -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"

View File

@@ -693,6 +693,39 @@ enum drm_bus_flags {
DRM_BUS_FLAG_SHARP_SIGNALS = BIT(8),
};
/**
* struct drm_amd_vsdb_info - AMD-specific VSDB information
*
* This structure holds information parsed from the AMD Vendor-Specific Data
* Block (VSDB) version 3.
*/
struct drm_amd_vsdb_info {
/**
* @version: Version of the Vendor-Specific Data Block (VSDB)
*/
u8 version;
/**
* @replay_mode: Panel Replay supported
*/
bool replay_mode;
/**
* @panel_type: Panel technology type
*/
u8 panel_type;
/**
* @luminance_range1: Luminance for max back light
*/
struct drm_luminance_range_info luminance_range1;
/**
* @luminance_range2: Luminance for min back light
*/
struct drm_luminance_range_info luminance_range2;
};
/**
* struct drm_display_info - runtime data about the connected sink
*
@@ -883,6 +916,11 @@ struct drm_display_info {
* Defaults to CEC_PHYS_ADDR_INVALID (0xffff).
*/
u16 source_physical_address;
/**
* @amd_vsdb: AMD-specific VSDB information.
*/
struct drm_amd_vsdb_info amd_vsdb;
};
int drm_display_info_set_bus_formats(struct drm_display_info *info,