Linux-Next discussions
 help / color / mirror / Atom feed
From: Mark Brown <broonie@kernel.org>
To: Dave Airlie <airlied@redhat.com>, DRI <dri-devel@lists.freedesktop.org>
Cc: Alex Deucher <alexander.deucher@amd.com>,
	Jesse Zhang <Jesse.Zhang@amd.com>,
	Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
	Linux Next Mailing List <linux-next@vger.kernel.org>
Subject: linux-next: manual merge of the drm tree with the drm-fixes tree
Date: Fri, 17 Jul 2026 15:40:39 +0100	[thread overview]
Message-ID: <alo-58eAjlzRkrjF@sirena.org.uk> (raw)

[-- Attachment #1: Type: text/plain, Size: 14782 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c

between commits:

  614e8a989d462 ("drm/amdgpu: trigger GPU recovery when userq destroy fails to unmap a hung queue")
  cee666427f280 ("drm/amdgpu/userq: fix indefinite fence wait during GPU reset")

from the drm-fixes tree and commits:

  8396b9de4198a ("drm/amdgpu: trigger GPU recovery when userq destroy fails to unmap a hung queue")
  9102b39fa924d ("drm/amdgpu/userq: fix indefinite fence wait during GPU reset")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --combined drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
index 572f2949cb64e,babaabe2d891d..0000000000000
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
@@@ -33,6 -33,7 +33,7 @@@
  #include "amdgpu_userq.h"
  #include "amdgpu_hmm.h"
  #include "amdgpu_userq_fence.h"
+ #include "amdgpu_trace.h"
  
  u32 amdgpu_userq_get_supported_ip_mask(struct amdgpu_device *adev)
  {
@@@ -88,14 -89,7 +89,7 @@@ static void amdgpu_userq_mgr_reset_work
  		container_of(work, struct amdgpu_userq_mgr,
  			     reset_work);
  	struct amdgpu_device *adev = uq_mgr->adev;
- 	const int queue_types[] = {
- 		AMDGPU_RING_TYPE_COMPUTE,
- 		AMDGPU_RING_TYPE_GFX,
- 		AMDGPU_RING_TYPE_SDMA
- 	};
- 	const int num_queue_types = ARRAY_SIZE(queue_types);
- 	bool gpu_reset = false;
- 	int i, r;
+ 	struct amdgpu_reset_context reset_context;
  
  	if (unlikely(adev->debug_disable_gpu_ring_reset)) {
  		dev_err(adev->dev, "userq reset disabled by debug mask\n");
@@@ -109,42 -103,15 +103,15 @@@
  	if (!amdgpu_gpu_recovery)
  		return;
  
- 	/*
- 	 * Iterate through all queue types to detect and reset problematic queues
- 	 * Process each queue type in the defined order
- 	 */
- 	for (i = 0; i < num_queue_types; i++) {
- 		int ring_type = queue_types[i];
- 		const struct amdgpu_userq_funcs *funcs =
- 			adev->userq_funcs[ring_type];
+ 	memset(&reset_context, 0, sizeof(reset_context));
  
- 		if (!amdgpu_userq_is_reset_type_supported(adev, ring_type,
- 							  AMDGPU_RESET_TYPE_PER_QUEUE))
- 				continue;
+ 	reset_context.method = AMD_RESET_METHOD_NONE;
+ 	reset_context.reset_req_dev = adev;
+ 	reset_context.src = AMDGPU_RESET_SRC_USERQ;
+ 	set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags);
+ 	/*set_bit(AMDGPU_SKIP_COREDUMP, &reset_context.flags);*/
  
- 		if (atomic_read(&uq_mgr->userq_count[ring_type]) > 0 &&
- 		    funcs && funcs->detect_and_reset) {
- 			r = funcs->detect_and_reset(adev, ring_type);
- 			if (r) {
- 				gpu_reset = true;
- 				break;
- 			}
- 		}
- 	}
- 
- 	if (gpu_reset) {
- 		struct amdgpu_reset_context reset_context;
- 
- 		memset(&reset_context, 0, sizeof(reset_context));
- 
- 		reset_context.method = AMD_RESET_METHOD_NONE;
- 		reset_context.reset_req_dev = adev;
- 		reset_context.src = AMDGPU_RESET_SRC_USERQ;
- 		set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags);
- 		/*set_bit(AMDGPU_SKIP_COREDUMP, &reset_context.flags);*/
- 
- 		amdgpu_device_gpu_recover(adev, NULL, &reset_context);
- 	}
+ 	amdgpu_device_gpu_recover(adev, NULL, &reset_context);
  }
  
  static void amdgpu_userq_hang_detect_work(struct work_struct *work)
@@@ -152,12 -119,45 +119,45 @@@
  	struct amdgpu_usermode_queue *queue =
  		container_of(work, struct amdgpu_usermode_queue,
  			     hang_detect_work.work);
+ 	struct amdgpu_userq_mgr *uq_mgr = queue->userq_mgr;
+ 	struct amdgpu_device *adev = uq_mgr->adev;
+ 	const struct amdgpu_userq_funcs *userq_funcs =
+ 		adev->userq_funcs[queue->queue_type];
+ 	bool gpu_reset = false;
+ 
+ 	if (unlikely(adev->debug_disable_gpu_ring_reset)) {
+ 		dev_err(adev->dev, "userq reset disabled by debug mask\n");
+ 		return;
+ 	}
+ 
+ 	/*
+ 	 * If GPU recovery feature is disabled system-wide,
+ 	 * skip all reset detection logic
+ 	 */
+ 	if (!amdgpu_gpu_recovery)
+ 		return;
+ 
+ 	if (amdgpu_userq_is_reset_type_supported(adev, queue->queue_type,
+ 						 AMDGPU_RESET_TYPE_PER_QUEUE)) {
+ 		int r;
+ 
+ 		if (queue->queue_type == AMDGPU_HW_IP_COMPUTE)
+ 			r = amdgpu_gfx_reset_mes_compute(adev, NULL, NULL,
+ 							 queue, NULL, NULL);
+ 		else
+ 			r = userq_funcs->reset(queue);
+ 		if (r)
+ 			gpu_reset = true;
+ 	} else {
+ 		gpu_reset = true;
+ 	}
  
  	/*
  	 * Don't schedule the work here! Scheduling or queue work from one reset
  	 * handler to another is illegal if you don't take extra precautions!
  	 */
- 	amdgpu_userq_mgr_reset_work(&queue->userq_mgr->reset_work);
+ 	if (gpu_reset)
+ 		amdgpu_userq_mgr_reset_work(&queue->userq_mgr->reset_work);
  }
  
  /*
@@@ -293,11 -293,15 +293,15 @@@ static int amdgpu_userq_preempt_helper(
  	int r;
  
  	if (queue->state == AMDGPU_USERQ_STATE_MAPPED) {
+ 		trace_amdgpu_userq_state_start(queue);
+ 
  		r = userq_funcs->preempt(queue);
  		if (r) {
+ 			trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_HUNG);
  			queue->state = AMDGPU_USERQ_STATE_HUNG;
  			return r;
  		} else {
+ 			trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_PREEMPTED);
  			queue->state = AMDGPU_USERQ_STATE_PREEMPTED;
  		}
  	}
@@@ -313,10 -317,14 +317,14 @@@ static int amdgpu_userq_restore_helper(
  	int r = 0;
  
  	if (queue->state == AMDGPU_USERQ_STATE_PREEMPTED) {
+ 		trace_amdgpu_userq_state_start(queue);
+ 
  		r = userq_funcs->restore(queue);
  		if (r) {
+ 			trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_HUNG);
  			queue->state = AMDGPU_USERQ_STATE_HUNG;
  		} else {
+ 			trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_MAPPED);
  			queue->state = AMDGPU_USERQ_STATE_MAPPED;
  		}
  	}
@@@ -334,12 -342,15 +342,15 @@@ static int amdgpu_userq_unmap_helper(st
  
  	if ((queue->state == AMDGPU_USERQ_STATE_MAPPED) ||
  	    (queue->state == AMDGPU_USERQ_STATE_PREEMPTED)) {
+ 		trace_amdgpu_userq_state_start(queue);
  
  		r = userq_funcs->unmap(queue);
  		if (r) {
+ 			trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_HUNG);
  			queue->state = AMDGPU_USERQ_STATE_HUNG;
  			return r;
  		} else {
+ 			trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_UNMAPPED);
  			queue->state = AMDGPU_USERQ_STATE_UNMAPPED;
  		}
  	}
@@@ -356,11 -367,15 +367,15 @@@ static int amdgpu_userq_map_helper(stru
  	int r;
  
  	if (queue->state == AMDGPU_USERQ_STATE_UNMAPPED) {
+ 		trace_amdgpu_userq_state_start(queue);
+ 
  		r = userq_funcs->map(queue);
  		if (r) {
+ 			trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_HUNG);
  			queue->state = AMDGPU_USERQ_STATE_HUNG;
  			return r;
  		} else {
+ 			trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_MAPPED);
  			queue->state = AMDGPU_USERQ_STATE_MAPPED;
  		}
  	}
@@@ -507,6 -522,8 +522,8 @@@ amdgpu_userq_destroy(struct amdgpu_user
  	const struct amdgpu_userq_funcs *uq_funcs = adev->userq_funcs[queue->queue_type];
  	int r = 0;
  
+ 	trace_amdgpu_userq_destroy_start(queue);
+ 
  	cancel_delayed_work_sync(&uq_mgr->resume_work);
  
  	/* Cancel any pending hang detection work and cleanup */
@@@ -541,6 -558,7 +558,7 @@@
  	amdgpu_bo_unreserve(queue->db_obj.obj);
  	amdgpu_bo_unref(&queue->db_obj.obj);
  
+ 	trace_amdgpu_userq_destroy_end(queue, r);
  	kfree(queue);
  
  	pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
@@@ -638,6 -656,8 +656,8 @@@ amdgpu_userq_create(struct drm_file *fi
  	queue->queue_type = args->in.ip_type;
  	queue->vm = &fpriv->vm;
  	queue->priority = priority;
+ 	queue->xcp_id = (fpriv->xcp_id != AMDGPU_XCP_NO_PARTITION) ?
+ 				fpriv->xcp_id : 0;
  	queue->userq_mgr = uq_mgr;
  	INIT_DELAYED_WORK(&queue->hang_detect_work,
  			  amdgpu_userq_hang_detect_work);
@@@ -680,6 -700,8 +700,8 @@@
  	}
  
  	queue->doorbell_index = index;
+ 	queue->doorbell_offset = (u32)args->in.doorbell_offset;
+ 	trace_amdgpu_userq_create_start(queue);
  	r = uq_funcs->mqd_create(queue, &args->in);
  	if (r) {
  		drm_file_err(uq_mgr->file, "Failed to create Queue\n");
@@@ -703,6 -725,7 +725,7 @@@
  		r = amdgpu_userq_map_helper(queue);
  		if (r) {
  			drm_file_err(uq_mgr->file, "Failed to map Queue\n");
+ 			trace_amdgpu_userq_create_end(queue, r);
  			mutex_unlock(&uq_mgr->userq_mutex);
  			goto erase_doorbell;
  		}
@@@ -719,11 -742,13 +742,13 @@@
  		 * This drops the last reference which should take care of
  		 * all cleanup.
  		 */
+ 		trace_amdgpu_userq_create_end(queue, r);
  		amdgpu_userq_put(queue);
  		return r;
  	}
  
  	amdgpu_debugfs_userq_init(filp, queue, qid);
+ 	trace_amdgpu_userq_create_end(queue, 0);
  	args->out.queue_id = qid;
  	return 0;
  
@@@ -739,6 -764,7 +764,7 @@@ clean_doorbell_bo
  free_fence_drv:
  	amdgpu_userq_fence_driver_free(queue);
  free_queue:
+ 	trace_amdgpu_userq_create_end(queue, r);
  	kfree(queue);
  err_pm_runtime:
  	pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
@@@ -871,16 -897,10 +897,10 @@@ int amdgpu_userq_ioctl(struct drm_devic
  static int
  amdgpu_userq_restore_all(struct amdgpu_userq_mgr *uq_mgr)
  {
- 	struct amdgpu_fpriv *fpriv = uq_mgr_to_fpriv(uq_mgr);
- 	struct amdgpu_vm *vm = &fpriv->vm;
  	struct amdgpu_usermode_queue *queue;
  	unsigned long queue_id;
  	int ret = 0, r;
  
- 
- 	if (amdgpu_bo_reserve(vm->root.bo, false))
- 		return false;
- 
  	mutex_lock(&uq_mgr->userq_mutex);
  	/* Resume all the queues for this process */
  	xa_for_each(&uq_mgr->userq_xa, queue_id, queue) {
@@@ -888,6 -908,7 +908,7 @@@
  		if (!amdgpu_userq_buffer_vas_mapped(queue)) {
  			drm_file_err(uq_mgr->file,
  				     "trying restore queue without va mapping\n");
+ 			trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_INVALID_VA);
  			queue->state = AMDGPU_USERQ_STATE_INVALID_VA;
  			continue;
  		}
@@@ -895,10 -916,8 +916,8 @@@
  		r = amdgpu_userq_map_helper(queue);
  		if (r)
  			ret = r;
- 
  	}
  	mutex_unlock(&uq_mgr->userq_mutex);
- 	amdgpu_bo_unreserve(vm->root.bo);
  
  	if (ret)
  		drm_file_err(uq_mgr->file,
@@@ -932,7 -951,8 +951,8 @@@ amdgpu_userq_bo_validate(struct amdgpu_
  		spin_unlock(&vm->individual_lock);
  
  		bo = bo_va->base.bo;
- 		ret = drm_exec_prepare_obj(exec, &bo->tbo.base, 2);
+ 		ret = drm_exec_prepare_obj(exec, &bo->tbo.base,
+ 					   TTM_NUM_MOVE_FENCES + 1);
  		if (unlikely(ret))
  			return ret;
  
@@@ -955,7 -975,7 +975,7 @@@
  
  /* Make sure the whole VM is ready to be used */
  static int
- amdgpu_userq_vm_validate(struct amdgpu_userq_mgr *uq_mgr)
+ amdgpu_userq_vm_validate_and_restore_queue(struct amdgpu_userq_mgr *uq_mgr)
  {
  	struct amdgpu_fpriv *fpriv = uq_mgr_to_fpriv(uq_mgr);
  	bool invalidated = false, new_addition = false;
@@@ -1081,8 -1101,12 +1101,12 @@@ retry_lock
  	dma_fence_wait(vm->last_update, false);
  
  	ret = amdgpu_evf_mgr_rearm(&fpriv->evf_mgr, &exec);
- 	if (ret)
+ 	if (ret) {
  		drm_file_err(uq_mgr->file, "Failed to replace eviction fence\n");
+ 		goto unlock_all;
+ 	}
+ 
+ 	ret = amdgpu_userq_restore_all(uq_mgr);
  
  unlock_all:
  	drm_exec_fini(&exec);
@@@ -1108,18 -1132,34 +1132,34 @@@ static void amdgpu_userq_restore_worker
  	if (!dma_fence_is_signaled(ev_fence))
  		goto put_fence;
  
- 	ret = amdgpu_userq_vm_validate(uq_mgr);
+ 	ret = amdgpu_userq_vm_validate_and_restore_queue(uq_mgr);
  	if (ret) {
  		drm_file_err(uq_mgr->file, "Failed to validate BOs to restore ret=%d\n", ret);
  		goto put_fence;
  	}
  
- 	amdgpu_userq_restore_all(uq_mgr);
- 
  put_fence:
  	dma_fence_put(ev_fence);
  }
  
+ void amdgpu_userq_process_reset_irq(struct amdgpu_device *adev,
+ 				    u32 pasid, u32 doorbell_offset)
+ {
+ 	struct xarray *xa = &adev->userq_doorbell_xa;
+ 	struct amdgpu_usermode_queue *queue;
+ 	unsigned long flags, idx;
+ 
+ 	xa_lock_irqsave(xa, flags);
+ 	xa_for_each(xa, idx, queue) {
+ 		if (queue->vm && queue->vm->pasid == pasid &&
+ 		    queue->doorbell_offset == doorbell_offset) {
+ 			amdgpu_userq_start_hang_detect_work(queue);
+ 			break;
+ 		}
+ 	}
+ 	xa_unlock_irqrestore(xa, flags);
+ }
+ 
  static int
  amdgpu_userq_evict_all(struct amdgpu_userq_mgr *uq_mgr)
  {
@@@ -1175,6 -1215,7 +1215,7 @@@ int amdgpu_userq_mgr_init(struct amdgpu
  	xa_init_flags(&userq_mgr->userq_xa, XA_FLAGS_ALLOC);
  	userq_mgr->adev = adev;
  	userq_mgr->file = file_priv;
+ 	mutex_init(&userq_mgr->proc_ctx_lock);
  
  	INIT_DELAYED_WORK(&userq_mgr->resume_work, amdgpu_userq_restore_worker);
  	INIT_WORK(&userq_mgr->reset_work, amdgpu_userq_mgr_reset_work);
@@@ -1228,6 -1269,11 +1269,11 @@@ void amdgpu_userq_mgr_fini(struct amdgp
  	 */
  	cancel_work_sync(&userq_mgr->reset_work);
  
+ 	amdgpu_bo_free_kernel(&userq_mgr->proc_ctx_obj.obj,
+ 			      &userq_mgr->proc_ctx_obj.gpu_addr,
+ 			      &userq_mgr->proc_ctx_obj.cpu_ptr);
+ 
+ 	mutex_destroy(&userq_mgr->proc_ctx_lock);
  	mutex_destroy(&userq_mgr->userq_mutex);
  }
  
@@@ -1377,12 -1423,14 +1423,14 @@@ void amdgpu_userq_pre_reset(struct amdg
  	/* TODO: We probably need a new lock for the queue state */
  	xa_for_each(&adev->userq_doorbell_xa, queue_id, queue) {
  		if (queue->state == AMDGPU_USERQ_STATE_MAPPED) {
+ 			trace_amdgpu_userq_state_start(queue);
  			userq_funcs = adev->userq_funcs[queue->queue_type];
  			userq_funcs->unmap(queue);
  			/* just mark all queues as hung at this point.
  			 * if unmap succeeds, we could map again
  			 * in amdgpu_userq_post_reset() if vram is not lost
  			 */
+ 			trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_HUNG);
  			queue->state = AMDGPU_USERQ_STATE_HUNG;
  		}
  		/* Force-complete any pending fence regardless of queue state so
@@@ -1406,6 -1454,8 +1454,8 @@@ int amdgpu_userq_post_reset(struct amdg
  
  	xa_for_each(&adev->userq_doorbell_xa, queue_id, queue) {
  		if (queue->state == AMDGPU_USERQ_STATE_HUNG && !vram_lost) {
+ 			trace_amdgpu_userq_state_start(queue);
+ 
  			userq_funcs = adev->userq_funcs[queue->queue_type];
  			/* Re-map queue */
  			r = userq_funcs->map(queue);
@@@ -1413,6 -1463,7 +1463,7 @@@
  				dev_err(adev->dev, "Failed to remap queue %ld\n", queue_id);
  				continue;
  			}
+ 			trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_MAPPED);
  			queue->state = AMDGPU_USERQ_STATE_MAPPED;
  		}
  	}

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

             reply	other threads:[~2026-07-17 14:40 UTC|newest]

Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-17 14:40 Mark Brown [this message]
  -- strict thread matches above, loose matches on Subject: below --
2026-07-17 14:41 linux-next: manual merge of the drm tree with the drm-fixes tree Mark Brown
2026-07-17 14:40 Mark Brown
2026-07-17 14:40 Mark Brown
2026-07-17 14:40 Mark Brown
2026-07-17 14:40 Mark Brown
2026-07-17 15:12 ` Mark Brown
2026-07-10 12:11 Mark Brown
2026-05-29 22:00 Mark Brown
2026-04-03 13:33 Mark Brown
2026-03-27 20:52 Mark Brown
2026-03-27 20:46 Mark Brown
2026-03-09 14:35 Mark Brown
2026-03-06 13:47 Mark Brown
2026-03-06 13:47 Mark Brown
2026-01-30 15:37 Mark Brown
2026-01-30 15:28 Mark Brown
2026-01-23 17:45 Mark Brown
2025-06-27  2:58 Stephen Rothwell
2024-10-18  1:56 Stephen Rothwell
2024-06-27 15:08 Mark Brown
2024-06-27 15:00 Mark Brown
2024-06-21 13:21 Mark Brown
2023-08-18  1:53 Stephen Rothwell
2023-02-13  0:23 Stephen Rothwell
2022-09-26 17:49 broonie
2022-02-25 16:37 broonie
2022-02-24 16:33 broonie
2021-08-06 12:04 Mark Brown
2021-08-10 11:56 ` Geert Uytterhoeven
2021-08-10 12:53   ` Stephen Rothwell
2020-07-10  2:28 Stephen Rothwell
2019-08-23  3:20 Stephen Rothwell
2019-07-05  2:50 Stephen Rothwell
2019-03-01  2:23 Stephen Rothwell
2019-03-01 23:29 ` Alex Deucher
2019-03-04  0:54   ` Stephen Rothwell
2019-03-11 12:36     ` Daniel Vetter
2018-12-14  1:51 Stephen Rothwell
2018-12-07  2:38 Stephen Rothwell
2018-12-07  2:31 Stephen Rothwell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=alo-58eAjlzRkrjF@sirena.org.uk \
    --to=broonie@kernel.org \
    --cc=Jesse.Zhang@amd.com \
    --cc=airlied@redhat.com \
    --cc=alexander.deucher@amd.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-next@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox