Commit acab5fbd authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge tag 'amd-drm-next-6.17-2025-07-17' of...

Merge tag 'amd-drm-next-6.17-2025-07-17' of https://gitlab.freedesktop.org/agd5f/linux into drm-next

amd-drm-next-6.17-2025-07-17:

amdgpu:
- Partition fixes
- Reset fixes
- RAS fixes
- i2c fix
- MPC updates
- DSC cleanup
- EDID fixes
- Display idle D3 update
- IPS updates
- DMUB updates
- Retimer fix
- Replay fixes
- Fix DC memory leak
- Initial support for smartmux
- DCN 4.0.1 degamma LUT fix
- Per queue reset cleanups
- Track ring state associated with a fence
- SR-IOV fixes
- SMU fixes
- Per queue reset improvements for GC 9+ compute
- Per queue reset improvements for GC 10+ gfx
- Per queue reset improvements for SDMA 5+
- Per queue reset improvements for JPEG 2+
- Per queue reset improvements for VCN 2+
- GC 8 fix
- ISP updates

amdkfd:
- Enable KFD on LoongArch

radeon:
- Drop console lock during suspend/resume

UAPI:
- Add userq slot info to INFO IOCTL
  Used for IGT userq validation tests (https://lists.freedesktop.org/archives/igt-dev/2025-July/093228.html)

From: Alex Deucher <alexander.deucher@amd.com>
Link: https://lore.kernel.org/r/20250717213827.2061581-1-alexander.deucher@amd.com


Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parents be3cd668 6ac55eab
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1723,7 +1723,7 @@ static inline bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev) { return
#endif

#if defined(CONFIG_DRM_AMD_ISP)
int amdgpu_acpi_get_isp4_dev_hid(u8 (*hid)[ACPI_ID_LEN]);
int amdgpu_acpi_get_isp4_dev(struct acpi_device **dev);
#endif

void amdgpu_register_gpu_instance(struct amdgpu_device *adev);
+2 −2
Original line number Diff line number Diff line
@@ -1545,7 +1545,7 @@ static int isp_match_acpi_device_ids(struct device *dev, const void *data)
	return acpi_match_device(data, dev) ? 1 : 0;
}

int amdgpu_acpi_get_isp4_dev_hid(u8 (*hid)[ACPI_ID_LEN])
int amdgpu_acpi_get_isp4_dev(struct acpi_device **dev)
{
	struct device *pdev __free(put_device) = NULL;
	struct acpi_device *acpi_pdev;
@@ -1559,7 +1559,7 @@ int amdgpu_acpi_get_isp4_dev_hid(u8 (*hid)[ACPI_ID_LEN])
	if (!acpi_pdev)
		return -ENODEV;

	strscpy(*hid, acpi_device_hid(acpi_pdev));
	*dev = acpi_pdev;

	return 0;
}
+2 −10
Original line number Diff line number Diff line
@@ -4220,18 +4220,10 @@ static int amdgpu_device_get_job_timeout_settings(struct amdgpu_device *adev)
	int ret = 0;

	/*
	 * By default timeout for non compute jobs is 10000
	 * and 60000 for compute jobs.
	 * In SR-IOV or passthrough mode, timeout for compute
	 * jobs are 60000 by default.
	 * By default timeout for jobs is 10 sec
	 */
	adev->gfx_timeout = msecs_to_jiffies(10000);
	adev->compute_timeout = adev->gfx_timeout = msecs_to_jiffies(10000);
	adev->sdma_timeout = adev->video_timeout = adev->gfx_timeout;
	if (amdgpu_sriov_vf(adev))
		adev->compute_timeout = amdgpu_sriov_is_pp_one_vf(adev) ?
					msecs_to_jiffies(60000) : msecs_to_jiffies(10000);
	else
		adev->compute_timeout =  msecs_to_jiffies(60000);

	if (strnlen(input, AMDGPU_MAX_TIMEOUT_PARAM_LENGTH)) {
		while ((timeout_setting = strsep(&input, ",")) &&
+6 −5
Original line number Diff line number Diff line
@@ -362,11 +362,11 @@ module_param_named(svm_default_granularity, amdgpu_svm_default_granularity, uint
 *   The second one is for Compute. The third and fourth ones are
 *   for SDMA and Video.
 *
 * By default(with no lockup_timeout settings), the timeout for all non-compute(GFX, SDMA and Video)
 * jobs is 10000. The timeout for compute is 60000.
 * By default(with no lockup_timeout settings), the timeout for all jobs is 10000.
 */
MODULE_PARM_DESC(lockup_timeout, "GPU lockup timeout in ms (default: for bare metal 10000 for non-compute jobs and 60000 for compute jobs; "
		"for passthrough or sriov, 10000 for all jobs. 0: keep default value. negative: infinity timeout), format: for bare metal [Non-Compute] or [GFX,Compute,SDMA,Video]; "
MODULE_PARM_DESC(lockup_timeout,
		 "GPU lockup timeout in ms (default: 10000 for all jobs. "
		 "0: keep default value. negative: infinity timeout), format: for bare metal [Non-Compute] or [GFX,Compute,SDMA,Video]; "
		 "for passthrough or sriov [all jobs] or [GFX,Compute,SDMA,Video].");
module_param_string(lockup_timeout, amdgpu_lockup_timeout, sizeof(amdgpu_lockup_timeout), 0444);

@@ -2512,6 +2512,7 @@ amdgpu_pci_remove(struct pci_dev *pdev)
	struct drm_device *dev = pci_get_drvdata(pdev);
	struct amdgpu_device *adev = drm_to_adev(dev);

	amdgpu_ras_eeprom_check_and_recover(adev);
	amdgpu_xcp_dev_unplug(adev);
	amdgpu_gmc_prepare_nps_mode_change(adev);
	drm_dev_unplug(dev);
+90 −0
Original line number Diff line number Diff line
@@ -120,6 +120,7 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, struct dma_fence **f,
		am_fence = kzalloc(sizeof(*am_fence), GFP_KERNEL);
		if (!am_fence)
			return -ENOMEM;
		am_fence->context = 0;
	} else {
		am_fence = af;
	}
@@ -127,6 +128,7 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, struct dma_fence **f,
	am_fence->ring = ring;

	seq = ++ring->fence_drv.sync_seq;
	am_fence->seq = seq;
	if (af) {
		dma_fence_init(fence, &amdgpu_job_fence_ops,
			       &ring->fence_drv.lock,
@@ -141,6 +143,7 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, struct dma_fence **f,

	amdgpu_ring_emit_fence(ring, ring->fence_drv.gpu_addr,
			       seq, flags | AMDGPU_FENCE_FLAG_INT);
	amdgpu_fence_save_wptr(fence);
	pm_runtime_get_noresume(adev_to_drm(adev)->dev);
	ptr = &ring->fence_drv.fences[seq & ring->fence_drv.num_fences_mask];
	if (unlikely(rcu_dereference_protected(*ptr, 1))) {
@@ -253,6 +256,7 @@ bool amdgpu_fence_process(struct amdgpu_ring *ring)

	do {
		struct dma_fence *fence, **ptr;
		struct amdgpu_fence *am_fence;

		++last_seq;
		last_seq &= drv->num_fences_mask;
@@ -265,6 +269,12 @@ bool amdgpu_fence_process(struct amdgpu_ring *ring)
		if (!fence)
			continue;

		/* Save the wptr in the fence driver so we know what the last processed
		 * wptr was.  This is required for re-emitting the ring state for
		 * queues that are reset but are not guilty and thus have no guilty fence.
		 */
		am_fence = container_of(fence, struct amdgpu_fence, base);
		drv->signalled_wptr = am_fence->wptr;
		dma_fence_signal(fence);
		dma_fence_put(fence);
		pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
@@ -727,6 +737,86 @@ void amdgpu_fence_driver_force_completion(struct amdgpu_ring *ring)
	amdgpu_fence_process(ring);
}


/**
 * Kernel queue reset handling
 *
 * The driver can reset individual queues for most engines, but those queues
 * may contain work from multiple contexts.  Resetting the queue will reset
 * lose all of that state.  In order to minimize the collateral damage, the
 * driver will save the ring contents which are not associated with the guilty
 * context prior to resetting the queue.  After resetting the queue the queue
 * contents from the other contexts is re-emitted to the rings so that it can
 * be processed by the engine.  To handle this, we save the queue's write
 * pointer (wptr) in the fences associated with each context.  If we get a
 * queue timeout, we can then use the wptrs from the fences to determine
 * which data needs to be saved out of the queue's ring buffer.
 */

/**
 * amdgpu_fence_driver_guilty_force_completion - force signal of specified sequence
 *
 * @fence: fence of the ring to signal
 *
 */
void amdgpu_fence_driver_guilty_force_completion(struct amdgpu_fence *fence)
{
	dma_fence_set_error(&fence->base, -ETIME);
	amdgpu_fence_write(fence->ring, fence->seq);
	amdgpu_fence_process(fence->ring);
}

void amdgpu_fence_save_wptr(struct dma_fence *fence)
{
	struct amdgpu_fence *am_fence = container_of(fence, struct amdgpu_fence, base);

	am_fence->wptr = am_fence->ring->wptr;
}

static void amdgpu_ring_backup_unprocessed_command(struct amdgpu_ring *ring,
						   u64 start_wptr, u32 end_wptr)
{
	unsigned int first_idx = start_wptr & ring->buf_mask;
	unsigned int last_idx = end_wptr & ring->buf_mask;
	unsigned int i;

	/* Backup the contents of the ring buffer. */
	for (i = first_idx; i != last_idx; ++i, i &= ring->buf_mask)
		ring->ring_backup[ring->ring_backup_entries_to_copy++] = ring->ring[i];
}

void amdgpu_ring_backup_unprocessed_commands(struct amdgpu_ring *ring,
					     struct amdgpu_fence *guilty_fence)
{
	struct dma_fence *unprocessed;
	struct dma_fence __rcu **ptr;
	struct amdgpu_fence *fence;
	u64 wptr, i, seqno;

	seqno = amdgpu_fence_read(ring);
	wptr = ring->fence_drv.signalled_wptr;
	ring->ring_backup_entries_to_copy = 0;

	for (i = seqno + 1; i <= ring->fence_drv.sync_seq; ++i) {
		ptr = &ring->fence_drv.fences[i & ring->fence_drv.num_fences_mask];
		rcu_read_lock();
		unprocessed = rcu_dereference(*ptr);

		if (unprocessed && !dma_fence_is_signaled(unprocessed)) {
			fence = container_of(unprocessed, struct amdgpu_fence, base);

			/* save everything if the ring is not guilty, otherwise
			 * just save the content from other contexts.
			 */
			if (!guilty_fence || (fence->context != guilty_fence->context))
				amdgpu_ring_backup_unprocessed_command(ring, wptr,
								       fence->wptr);
			wptr = fence->wptr;
		}
		rcu_read_unlock();
	}
}

/*
 * Common fence implementation
 */
Loading