Intel-XE Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Matthew Brost <matthew.brost@intel.com>
To: <sashiko-reviews@lists.linux.dev>
Cc: <intel-xe@lists.freedesktop.org>
Subject: Re: [PATCH v4 16/25] drm/xe: Add CPU bind layer
Date: Thu, 3 Sep 2026 18:18:46 -0700	[thread overview]
Message-ID: <apocdrrhQzWr/1v4@gsse-cloud1.jf.intel.com> (raw)
In-Reply-To: <20260904003150.1ABBA1F000E9@smtp.kernel.org>

On Fri, Sep 04, 2026 at 12:31:49AM +0000, sashiko-bot@kernel.org wrote:
> 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.
> --

All of these are correct. Will fix.

Matt

> 
> 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  1:18 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
2026-09-04  1:18     ` Matthew Brost [this message]
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=apocdrrhQzWr/1v4@gsse-cloud1.jf.intel.com \
    --to=matthew.brost@intel.com \
    --cc=intel-xe@lists.freedesktop.org \
    --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