From c193fa57f29415aa48e8ba1c0c35cd16dc5c5710 Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Fri, 25 Sep 2026 13:15:14 -0700 Subject: [PATCH] drm/xe: Don't use migrate exec queue for page fault binds Now that the CPU is always used for binds even in jobs, CPU bind jobs can pass GPU jobs in the same exec queue resulting dma-fences signaling out-of-order. Use a dedicated exec queue for binds issued from page faults to avoid ordering issues and avoid blocking kernel binds on unrelated copies / clears. Signed-off-by: Matthew Brost Reviewed-by: Himal Prasad Ghimiray Reviewed-by: Maarten Lankhorst Link: https://patch.msgid.link/20260925201526.1355279-13-matthew.brost@intel.com --- drivers/gpu/drm/xe/xe_migrate.c | 47 ++++++++++++++++++++++++++++++--- drivers/gpu/drm/xe/xe_migrate.h | 1 + drivers/gpu/drm/xe/xe_vm.c | 17 +++++++----- 3 files changed, 55 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_migrate.c b/drivers/gpu/drm/xe/xe_migrate.c index 3007fe0b8535..d8d35671a190 100644 --- a/drivers/gpu/drm/xe/xe_migrate.c +++ b/drivers/gpu/drm/xe/xe_migrate.c @@ -51,6 +51,8 @@ struct xe_migrate { /** @q: Default exec queue used for migration */ struct xe_exec_queue *q; + /** @bind_q: Default exec queue used for binds */ + struct xe_exec_queue *bind_q; /** @tile: Backpointer to the tile this struct xe_migrate belongs to. */ struct xe_tile *tile; /** @job_mutex: Timeline mutex for @eng. */ @@ -115,6 +117,7 @@ static void xe_migrate_fini(void *arg) mutex_destroy(&m->job_mutex); xe_vm_close_and_put(m->q->vm); xe_exec_queue_put(m->q); + xe_exec_queue_put(m->bind_q); } static inline u16 xe_migrate_pat_index(struct xe_device *xe, @@ -504,6 +507,15 @@ int xe_migrate_init(struct xe_migrate *m) goto err_out; } + m->bind_q = xe_exec_queue_create(xe, vm, logical_mask, 1, hwe0, + EXEC_QUEUE_FLAG_KERNEL | + EXEC_QUEUE_FLAG_HIGH_PRIORITY | + EXEC_QUEUE_FLAG_MIGRATE, 0); + if (IS_ERR(m->bind_q)) { + err = PTR_ERR(m->bind_q); + goto err_out; + } + /* * XXX: Currently only reserving 1 (likely slow) BCS instance on * PVC, may want to revisit if performance is needed. @@ -514,6 +526,15 @@ int xe_migrate_init(struct xe_migrate *m) EXEC_QUEUE_FLAG_MIGRATE | EXEC_QUEUE_FLAG_LOW_LATENCY, 0); } else { + m->bind_q = xe_exec_queue_create_class(xe, primary_gt, vm, + XE_ENGINE_CLASS_COPY, + EXEC_QUEUE_FLAG_KERNEL | + EXEC_QUEUE_FLAG_MIGRATE, 0); + if (IS_ERR(m->bind_q)) { + err = PTR_ERR(m->bind_q); + goto err_out; + } + m->q = xe_exec_queue_create_class(xe, primary_gt, vm, XE_ENGINE_CLASS_COPY, EXEC_QUEUE_FLAG_KERNEL | @@ -549,6 +570,8 @@ int xe_migrate_init(struct xe_migrate *m) return err; err_out: + if (!IS_ERR_OR_NULL(m->bind_q)) + xe_exec_queue_put(m->bind_q); xe_vm_close_and_put(vm); return err; @@ -1505,6 +1528,17 @@ static u32 blt_mem_set_cmd_len(struct xe_device *xe) return 7; } +/** + * xe_get_migrate_bind_queue() - Get the bind queue from migrate context. + * @migrate: Migrate context. + * + * Return: Pointer to bind queue on success, error on failure + */ +struct xe_exec_queue *xe_migrate_bind_queue(struct xe_migrate *migrate) +{ + return migrate->bind_q; +} + static void emit_clear_link_copy(struct xe_gt *gt, struct xe_bb *bb, u64 src_ofs, u32 size, u32 pitch) { @@ -1891,6 +1925,11 @@ xe_migrate_update_pgtables_cpu(struct xe_migrate *m, return dma_fence_get_stub(); } +static bool is_migrate_queue(struct xe_migrate *m, struct xe_exec_queue *q) +{ + return m->bind_q == q; +} + static struct dma_fence * __xe_migrate_update_pgtables(struct xe_migrate *m, struct xe_migrate_pt_update *pt_update, @@ -1908,7 +1947,7 @@ __xe_migrate_update_pgtables(struct xe_migrate *m, u32 num_updates = 0, current_update = 0; u64 addr; int err = 0; - bool is_migrate = pt_update_ops->q == m->q; + bool is_migrate = is_migrate_queue(m, pt_update_ops->q); bool usm = is_migrate && xe->info.has_usm; for (i = 0; i < pt_update_ops->num_ops; ++i) { @@ -2630,7 +2669,7 @@ out_err: */ void xe_migrate_job_lock(struct xe_migrate *m, struct xe_exec_queue *q) { - bool is_migrate = q == m->q; + bool is_migrate = is_migrate_queue(m, q); if (is_migrate) mutex_lock(&m->job_mutex); @@ -2648,7 +2687,7 @@ void xe_migrate_job_lock(struct xe_migrate *m, struct xe_exec_queue *q) */ void xe_migrate_job_unlock(struct xe_migrate *m, struct xe_exec_queue *q) { - bool is_migrate = q == m->q; + bool is_migrate = is_migrate_queue(m, q); if (is_migrate) mutex_unlock(&m->job_mutex); @@ -2665,7 +2704,7 @@ void xe_migrate_job_lock_assert(struct xe_exec_queue *q) { struct xe_migrate *m = gt_to_tile(q->gt)->migrate; - xe_gt_assert(q->gt, q == m->q); + xe_gt_assert(q->gt, q == m->bind_q); lockdep_assert_held(&m->job_mutex); } #endif diff --git a/drivers/gpu/drm/xe/xe_migrate.h b/drivers/gpu/drm/xe/xe_migrate.h index c41f6e3ca2c6..e6b7070134e1 100644 --- a/drivers/gpu/drm/xe/xe_migrate.h +++ b/drivers/gpu/drm/xe/xe_migrate.h @@ -146,6 +146,7 @@ void xe_migrate_ccs_rw_copy_clear(struct xe_bo *src_bo, struct xe_lrc *xe_migrate_lrc(struct xe_migrate *migrate); struct xe_exec_queue *xe_migrate_exec_queue(struct xe_migrate *migrate); +struct xe_exec_queue *xe_migrate_bind_queue(struct xe_migrate *migrate); struct dma_fence *xe_migrate_vram_copy_chunk(struct xe_bo *vram_bo, u64 vram_offset, struct xe_bo *sysmem_bo, u64 sysmem_offset, u64 size, enum xe_migrate_copy_dir dir); diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index aad700b92fa7..925d2470747c 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -796,7 +796,9 @@ int xe_vm_rebind(struct xe_vm *vm, bool rebind_worker) struct xe_vma *vma, *next; struct xe_vma_ops vops; struct xe_vma_op *op, *next_op; - int err, i; + struct xe_tile *tile; + u8 id; + int err; lockdep_assert_held(&vm->lock); if ((xe_vm_in_lr_mode(vm) && !rebind_worker) || @@ -804,8 +806,11 @@ int xe_vm_rebind(struct xe_vm *vm, bool rebind_worker) return 0; xe_vma_ops_init(&vops, vm, NULL, NULL, 0); - for (i = 0; i < XE_MAX_TILES_PER_DEVICE; ++i) - vops.pt_update_ops[i].wait_vm_bookkeep = true; + for_each_tile(tile, vm->xe, id) { + vops.pt_update_ops[id].wait_vm_bookkeep = true; + vops.pt_update_ops[id].q = + xe_migrate_bind_queue(tile->migrate); + } xe_vm_assert_held(vm); list_for_each_entry(vma, &vm->rebind_list, combined_links.rebind) { @@ -863,7 +868,7 @@ struct dma_fence *xe_vma_rebind(struct xe_vm *vm, struct xe_vma *vma, u8 tile_ma for_each_tile(tile, vm->xe, id) { vops.pt_update_ops[id].wait_vm_bookkeep = true; vops.pt_update_ops[tile->id].q = - xe_migrate_exec_queue(tile->migrate); + xe_migrate_bind_queue(tile->migrate); } err = xe_vm_ops_add_rebind(&vops, vma, tile_mask); @@ -955,7 +960,7 @@ struct dma_fence *xe_vm_range_rebind(struct xe_vm *vm, for_each_tile(tile, vm->xe, id) { vops.pt_update_ops[id].wait_vm_bookkeep = true; vops.pt_update_ops[tile->id].q = - xe_migrate_exec_queue(tile->migrate); + xe_migrate_bind_queue(tile->migrate); } err = xe_vm_ops_add_range_rebind(&vops, vma, range, tile_mask); @@ -1039,7 +1044,7 @@ struct dma_fence *xe_vm_range_unbind(struct xe_vm *vm, for_each_tile(tile, vm->xe, id) { vops.pt_update_ops[id].wait_vm_bookkeep = true; vops.pt_update_ops[tile->id].q = - xe_migrate_exec_queue(tile->migrate); + xe_migrate_bind_queue(tile->migrate); } err = xe_vm_ops_add_range_unbind(&vops, range);