Intel-XE Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Matthew Brost" <matthew.brost@intel.com>
Cc: intel-xe@lists.freedesktop.org
Subject: Re: [PATCH v4 16/25] drm/xe: Add CPU bind layer
Date: Fri, 04 Sep 2026 00:31:49 +0000	[thread overview]
Message-ID: <20260904003150.1ABBA1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260903235842.3401722-17-matthew.brost@intel.com>

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [Critical] TLB invalidation on mirrored (shared) tiles uses uninitialized `start` and `last` addresses, failing to invalidate the correctly updated address range.
- [Critical] Shallow copying of the page reclaim list (PRL) for mirrored tiles leads to a Use-After-Free and double-free of the PRL entries during TLB invalidation.
- [Critical] The arguments `tile_mask` and `usage` are swapped when calling `unbind_op_commit()` in the `DRM_GPUVA_OP_UNMAP` case, leading to un-cleared VMAs and corrupted dma-resv state.
- [High] Missing NULL check for the result of `drmm_kzalloc()` in `xe_cpu_bind_init()`.
- [High] `op_prepare` mistakenly uses `XE_VMA_OPS_FLAG_WAIT_VM_KERNEL` instead of `XE_VMA_OPS_FLAG_WAIT_VM_BOOKKEEP` for REMAP operations, breaking dma-resv wait semantics.
--

commit 87e03e5ddd64ecb931de7c6186e72459d6401535
Author: Matthew Brost <matthew.brost@intel.com>
Subject: drm/xe: Add CPU bind layer

This commit introduces a dedicated CPU bind layer for the xe driver, moving
CPU bind handling out of the migrate layer since it's decoupled from
hardware. It also updates the page table layer to generate a single bind job
when pages are mirrored across tiles.

Link: https://patch.msgid.link/20260228013501.106680-17-matthew.brost@intel.com

> diff --git a/drivers/gpu/drm/xe/xe_cpu_bind.c b/drivers/gpu/drm/xe/xe_cpu_bind.c
> new file mode 100644
> index 0000000000000..ed79e229151b4
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/xe_cpu_bind.c
> @@ -0,0 +1,295 @@
[ ... ]
> +int xe_cpu_bind_init(struct xe_device *xe)
> +{
> +	struct xe_cpu_bind *cpu_bind =
> +		drmm_kzalloc(&xe->drm, sizeof(*cpu_bind), GFP_KERNEL);
> +	struct xe_exec_queue *q;
> +
> +	q = xe_exec_queue_create_bind(xe, xe_device_get_root_tile(xe), NULL,
> +				      EXEC_QUEUE_FLAG_KERNEL |
> +				      EXEC_QUEUE_FLAG_MIGRATE, 0);
> +	if (IS_ERR(q))
> +		return PTR_ERR(q);
> +
> +	cpu_bind->xe = xe;

[Severity: High]
Does this code dereference cpu_bind without checking if drmm_kzalloc()
succeeded? If the allocation fails under memory pressure and returns NULL,
this assignment will cause a NULL pointer dereference kernel panic during
device probe.

> diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c
> index 7c7cd7a0365b7..821edeaecaed9 100644
> --- a/drivers/gpu/drm/xe/xe_pt.c
> +++ b/drivers/gpu/drm/xe/xe_pt.c
[ ... ]
> @@ -2395,7 +2388,7 @@ static int op_prepare(struct xe_vm *vm,
>  
>  		err = bind_op_prepare(vm, tile, pt_update_ops, op->map.vma,
>  				      op->map.invalidate_on_bind);
> -		pt_update_ops->wait_vm_kernel = true;
> +		vops->flags |= XE_VMA_OPS_FLAG_WAIT_VM_KERNEL;
>  		break;
>  	case DRM_GPUVA_OP_REMAP:
>  	{
> @@ -2409,12 +2402,12 @@ static int op_prepare(struct xe_vm *vm,
>  		if (!err && op->remap.prev && !op->remap.skip_prev) {
>  			err = bind_op_prepare(vm, tile, pt_update_ops,
>  					      op->remap.prev, false);
> -			pt_update_ops->wait_vm_bookkeep = true;
> +			vops->flags |= XE_VMA_OPS_FLAG_WAIT_VM_KERNEL;
>  		}
>  		if (!err && op->remap.next && !op->remap.skip_next) {
>  			err = bind_op_prepare(vm, tile, pt_update_ops,
>  					      op->remap.next, false);
> -			pt_update_ops->wait_vm_bookkeep = true;
> +			vops->flags |= XE_VMA_OPS_FLAG_WAIT_VM_KERNEL;
>  		}
>  		break;
>  	}

[Severity: High]
Are the flag updates in the DRM_GPUVA_OP_REMAP branch intentionally setting
XE_VMA_OPS_FLAG_WAIT_VM_KERNEL instead of XE_VMA_OPS_FLAG_WAIT_VM_BOOKKEEP?

The original code correctly set wait_vm_bookkeep to true for remap
operations, but the updated version uses the KERNEL flag. This flips the
expected synchronization dependency semantics, which could cause REMAP
operations to incorrectly wait on KERNEL fences instead of BOOKKEEP fences,
violating the synchronization contract.

[ ... ]
> @@ -2604,21 +2624,19 @@ static void unbind_op_commit(struct xe_vm *vm, struct xe_tile *tile,
>  
>  static void range_present_and_invalidated_tile(struct xe_vm *vm,
>  					       struct xe_svm_range *range,
> -					       u8 tile_id)
> +					       u8 tile_mask)
>  {
>  	/* All WRITE_ONCE pair with READ_ONCE in xe_vm_has_valid_gpu_mapping() */
>  
>  	lockdep_assert_held(&vm->svm.gpusvm.notifier_lock);
>  
> -	WRITE_ONCE(range->tile_present, range->tile_present | BIT(tile_id));
> -	WRITE_ONCE(range->tile_invalidated, range->tile_invalidated & ~BIT(tile_id));
> +	WRITE_ONCE(range->tile_present, range->tile_present | tile_mask);
> +	WRITE_ONCE(range->tile_invalidated, range->tile_invalidated & ~tile_mask);
>  }
>  
> -static void op_commit(struct xe_vm *vm,
> -		      struct xe_tile *tile,
> -		      struct xe_vm_pgtable_update_ops *pt_update_ops,
> -		      struct xe_vma_op *op, struct dma_fence *fence,
> -		      struct dma_fence *fence2)
> +static void op_commit(struct xe_vm *vm, struct xe_vma_op *op,
> +		      struct dma_fence **fences, int fence_count,
> +		      enum dma_resv_usage usage, u8 tile_mask)
>  {
>  	xe_vm_assert_held(vm);
>  
[ ... ]
> @@ -2657,8 +2672,8 @@ static void op_commit(struct xe_vm *vm,
>  		struct xe_vma *vma = gpuva_to_vma(op->base.unmap.va);
>  
>  		if (!xe_vma_is_cpu_addr_mirror(vma))
> -			unbind_op_commit(vm, tile, pt_update_ops, vma, fence,
> -					 fence2);
> +			unbind_op_commit(vm, vma, fences, fence_count,
> +					 tile_mask, usage);
>  		break;
>  	}

[Severity: Critical]
Is it possible the tile_mask and usage arguments are swapped here?

Looking at the signature for unbind_op_commit(), it expects usage before
tile_mask:

unbind_op_commit(struct xe_vm *vm, struct xe_vma *vma,
                 struct dma_fence **fences, int fence_count,
                 enum dma_resv_usage usage, u8 tile_mask)

Because the arguments are passed in reverse order, the dma_resv usage enum
is treated as the tile mask. This would mean vma->tile_present &= ~tile_mask
evaluates with the enum value (e.g. DMA_RESV_USAGE_KERNEL = 0), leaving
the VMA marked fully present, and un-cleared memory could be incorrectly
freed. Simultaneously, the tile mask is passed into the dma_resv tracking
slots as a bogus usage value.

[ ... ]
> @@ -2737,82 +2739,83 @@ static struct xe_dep_scheduler *to_dep_scheduler(struct xe_exec_queue *q,
>  struct dma_fence *
> -xe_pt_update_ops_run(struct xe_tile *tile, struct xe_vma_ops *vops)
> +xe_pt_update_ops_run(struct xe_device *xe, struct xe_vma_ops *vops)
>  {
[ ... ]
> -	if (pt_update_ops->needs_invalidation) {
> -		struct xe_dep_scheduler *dep_scheduler =
> -			to_dep_scheduler(q, tile, tile->primary_gt, &type);
> -
> -		ijob = xe_tlb_inval_job_create(q, &tile->primary_gt->tlb_inval,
> -					       dep_scheduler, vm,
> -					       pt_update_ops->start,
> -					       pt_update_ops->last,
> -					       type);
> -		if (IS_ERR(ijob)) {
> -			err = PTR_ERR(ijob);
> -			goto kill_vm_tile1;
> -		}
> -		update.ijob = ijob;
> -		/*
> -		 * Only add page reclaim for the primary GT. Media GT does not have
> -		 * any PPC to flush, so enabling the PPC flush bit for media is
> -		 * effectively a NOP and provides no performance benefit nor
> -		 * interfere with primary GT.
> -		 */
> -		if (xe_page_reclaim_list_valid(&pt_update_ops->prl)) {
> -			xe_tlb_inval_job_add_page_reclaim(ijob, &pt_update_ops->prl);
> -			/* Release ref from alloc, job will now handle it */
> -			xe_page_reclaim_list_invalidate(&pt_update_ops->prl);
> -		}
> -
> -		if (tile->media_gt) {
> -			dep_scheduler = to_dep_scheduler(q, tile,
> -							 tile->media_gt, &type);
> -
> -			mjob = xe_tlb_inval_job_create(q,
> -						       &tile->media_gt->tlb_inval,
> -						       dep_scheduler, vm,
> -						       pt_update_ops->start,
> -						       pt_update_ops->last,
> -						       type);
> -			if (IS_ERR(mjob)) {
> -				err = PTR_ERR(mjob);
> +	if (needs_invalidation) {
> +		for_each_tlb_inval(q, i) {
> +			struct xe_dep_scheduler *dep_scheduler =
> +				q->tlb_inval[i].dep_scheduler;
> +			struct xe_tile *tile =
> +				&xe->tiles[i / XE_MAX_GT_PER_TILE];
> +			struct xe_vm_pgtable_update_ops *pt_update_ops =
> +				&vops->pt_update_ops[tile->id];
> +			struct xe_page_reclaim_list *prl = &pt_update_ops->prl;
> +			struct xe_tlb_inval_job *ijob;
> +			struct xe_gt *gt = i % XE_MAX_GT_PER_TILE ?
> +				tile->media_gt : tile->primary_gt;
> +
> +			ijob = xe_tlb_inval_job_create(q, &gt->tlb_inval,
> +						       dep_scheduler,
> +						       vm, pt_update_ops->start,
> +						       pt_update_ops->last, i);
> +			if (IS_ERR(ijob)) {
> +				err = PTR_ERR(ijob);
>  				goto free_ijob;
>  			}
> -			update.mjob = mjob;
> +
> +			update.ijobs[i] = ijob;
> +
> +			/*
> +			 * Only add page reclaim for the primary GT. Media GT
> +			 * does not have any PPC to flush, so enabling the PPC
> +			 * flush bit for media is effectively a NOP and provides
> +			 * no performance benefit nor interfere with primary GT.
> +			 */
> +			if (xe_page_reclaim_list_valid(prl)) {
> +				xe_tlb_inval_job_add_page_reclaim(ijob, prl);
> +				/* Release ref from alloc, job will now handle it */
> +				xe_page_reclaim_list_invalidate(prl);
> +			}
>  		}
>  	}

[Severity: Critical]
Does this code inadvertently create TLB invalidation jobs with uninitialized
bounds for secondary mirrored tiles?

When a tile shares a page table (mirroring disabled), the initialization of
pt_update_ops->start and pt_update_ops->last is skipped during the prepare
phase. Consequently, they remain 0. Here, xe_tlb_inval_job_create() relies
on these bounds, meaning the secondary tile's GTs could execute an invalid
TLB flush for the [0, 0] range, leaving stale TLB entries for the actual
modified range.

[Severity: Critical]
Can this loop trigger a use-after-free and double-free on the page reclaim
list (PRL)?

For secondary mirrored tiles, the PRL is set up as a shallow copy of the
primary tile's PRL without taking an additional page reference.
When the loop iterates over the primary tile, it adds the PRL and calls
xe_page_reclaim_list_invalidate(), which drops the page reference.

When the loop then reaches the secondary tile, its shallow-copied
prl.entries pointer is still non-NULL but points to freed memory. The code
will pass this dangling pointer to the secondary job and call
xe_page_reclaim_list_invalidate() a second time, triggering a double-free.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260903235842.3401722-1-matthew.brost@intel.com?part=16

  reply	other threads:[~2026-09-04  0:31 UTC|newest]

Thread overview: 48+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-03 23:58 [PATCH v4 00/25] CPU binds and ULLS on migration queue Matthew Brost
2026-09-03 23:58 ` [PATCH v4 01/25] drm/xe: Drop struct xe_migrate_pt_update argument from populate/clear vfuns Matthew Brost
2026-09-03 23:58 ` [PATCH v4 02/25] drm/xe: Add xe_migrate_update_pgtables_cpu_execute helper Matthew Brost
2026-09-04  0:15   ` sashiko-bot
2026-09-03 23:58 ` [PATCH v4 03/25] drm/xe: Decouple exec queue idle check from LRC Matthew Brost
2026-09-03 23:58 ` [PATCH v4 04/25] drm/xe: Add job count to GuC exec queue snapshot Matthew Brost
2026-09-03 23:58 ` [PATCH v4 05/25] drm/xe: Update xe_bo_put_deferred arguments to include writeback flag Matthew Brost
2026-09-03 23:58 ` [PATCH v4 06/25] drm/xe: Add XE_BO_FLAG_PUT_VM_ASYNC Matthew Brost
2026-09-04  0:18   ` sashiko-bot
2026-09-04  0:41     ` Matthew Brost
2026-09-03 23:58 ` [PATCH v4 07/25] drm/xe: Update scheduler job layer to support PT jobs Matthew Brost
2026-09-04  0:25   ` sashiko-bot
2026-09-03 23:58 ` [PATCH v4 08/25] drm/xe: Add helpers to access PT ops Matthew Brost
2026-09-03 23:58 ` [PATCH v4 09/25] drm/xe: Add struct xe_pt_job_ops Matthew Brost
2026-09-03 23:58 ` [PATCH v4 10/25] drm/xe: Update GuC submission backend to run PT jobs Matthew Brost
2026-09-04  0:36   ` sashiko-bot
2026-09-04  0:57     ` Matthew Brost
2026-09-03 23:58 ` [PATCH v4 11/25] drm/xe: Store level in struct xe_vm_pgtable_update Matthew Brost
2026-09-04  0:19   ` sashiko-bot
2026-09-03 23:58 ` [PATCH v4 12/25] drm/xe: Don't use migrate exec queue for page fault binds Matthew Brost
2026-09-03 23:58 ` [PATCH v4 13/25] drm/xe: Enable CPU binds for jobs Matthew Brost
2026-09-04  0:31   ` sashiko-bot
2026-09-04  1:04     ` Matthew Brost
2026-09-03 23:58 ` [PATCH v4 14/25] drm/xe: Remove unused arguments from xe_migrate_pt_update_ops Matthew Brost
2026-09-03 23:58 ` [PATCH v4 15/25] drm/xe: Make bind queues operate cross-tile Matthew Brost
2026-09-03 23:58 ` [PATCH v4 16/25] drm/xe: Add CPU bind layer Matthew Brost
2026-09-04  0:31   ` sashiko-bot [this message]
2026-09-04  1:18     ` Matthew Brost
2026-09-03 23:58 ` [PATCH v4 17/25] drm/xe: Add device flag to enable PT mirroring across tiles Matthew Brost
2026-09-04  0:29   ` sashiko-bot
2026-09-04  1:33     ` Matthew Brost
2026-09-03 23:58 ` [PATCH v4 18/25] drm/xe: Add xe_hw_engine_write_ring_tail Matthew Brost
2026-09-03 23:58 ` [PATCH v4 19/25] drm/xe: Add ULLS support to LRC Matthew Brost
2026-09-03 23:58 ` [PATCH v4 20/25] drm/xe: Add ULLS migration job support to migration layer Matthew Brost
2026-09-04  0:27   ` sashiko-bot
2026-09-04  1:35     ` Matthew Brost
2026-09-03 23:58 ` [PATCH v4 21/25] drm/xe: Add ULLS migration job support to ring ops Matthew Brost
2026-09-03 23:58 ` [PATCH v4 22/25] drm/xe: Add ULLS migration job support to GuC submission Matthew Brost
2026-09-04  0:38   ` sashiko-bot
2026-09-04  1:41     ` Matthew Brost
2026-09-03 23:58 ` [PATCH v4 23/25] drm/xe: Enter ULLS for migration jobs upon page fault or SVM prefetch Matthew Brost
2026-09-04  0:28   ` sashiko-bot
2026-09-04  1:32     ` Matthew Brost
2026-09-03 23:58 ` [PATCH v4 24/25] drm/xe: Add modparam to enable / disable ULLS on migrate queue Matthew Brost
2026-09-03 23:58 ` [PATCH v4 25/25] drm/xe: Document ULLS for migration jobs Matthew Brost
2026-09-04  0:47 ` ✗ CI.checkpatch: warning for CPU binds and ULLS on migration queue (rev6) Patchwork
2026-09-04  0:49 ` ✓ CI.KUnit: success " Patchwork
2026-09-04  1:33 ` ✓ Xe.CI.BAT: " Patchwork

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=20260904003150.1ABBA1F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=intel-xe@lists.freedesktop.org \
    --cc=matthew.brost@intel.com \
    --cc=sashiko-reviews@lists.linux.dev \
    /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