[PATCH v2 6/9] drm/xe/lrc: Introduce xe_lrc_reinit()

Raag Jadav
2026-02-27T17:03:36Z

In preparation of usecases which require re-initializing LRC after PCIe
FLR, introduce xe_lrc_reinit() helper. The LRC bo already exists but
since it's contents are on VRAM, they are lost on PCIe FLR. Recreate
ring context as part of re-initialization.

Signed-off-by: Raag Jadav <raag.jadav@intel.com>
---
v2: Re-initialize migrate context (Matthew Brost)
---
drivers/gpu/drm/xe/xe_lrc.c | 149 +++++++++++++++++++++---------------
drivers/gpu/drm/xe/xe_lrc.h | 2 +
2 files changed, 90 insertions(+), 61 deletions(-)

diff --git a/drivers/gpu/drm/xe/xe_lrc.c b/drivers/gpu/drm/xe/xe_lrc.c
index 84360fcdf743..9fc8720f62ca 100644
--- a/drivers/gpu/drm/xe/xe_lrc.c
+++ b/drivers/gpu/drm/xe/xe_lrc.c
@@ -1438,65 +1438,16 @@ void xe_lrc_set_multi_queue_priority(struct xe_lrc *lrc, enum xe_multi_queue_pri
lrc->desc |= FIELD_PREP(LRC_PRIORITY, xe_multi_queue_prio_to_lrc(lrc, priority));
}

-static int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe,
- struct xe_vm *vm, void *replay_state, u32 ring_size,
- u16 msix_vec,
- u32 init_flags)
+static int xe_lrc_init_ctx(struct xe_lrc *lrc, struct xe_hw_engine *hwe, struct xe_vm *vm,
+ void *replay_state, u16 msix_vec, u32 init_flags)
{
struct xe_gt *gt = hwe->gt;
- const u32 lrc_size = xe_gt_lrc_size(gt, hwe->class);
- u32 bo_size = ring_size + lrc_size + LRC_WA_BB_SIZE;
struct xe_tile *tile = gt_to_tile(gt);
struct xe_device *xe = gt_to_xe(gt);
- struct xe_bo *seqno_bo;
struct iosys_map map;
u32 arb_enable;
- u32 bo_flags;
int err;

- kref_init(&lrc->refcount);
- lrc->gt = gt;
- lrc->replay_size = xe_gt_lrc_hang_replay_size(gt, hwe->class);
- lrc->size = lrc_size;
- lrc->flags = 0;
- lrc->ring.size = ring_size;
- lrc->ring.tail = 0;
-
- if (gt_engine_needs_indirect_ctx(gt, hwe->class)) {
- lrc->flags |= XE_LRC_FLAG_INDIRECT_CTX;
- bo_size += LRC_INDIRECT_CTX_BO_SIZE;
- }
-
- if (xe_gt_has_indirect_ring_state(gt))
- lrc->flags |= XE_LRC_FLAG_INDIRECT_RING_STATE;
-
- bo_flags = XE_BO_FLAG_VRAM_IF_DGFX(tile) | XE_BO_FLAG_GGTT |
- XE_BO_FLAG_GGTT_INVALIDATE;
-
- if ((vm && vm->xef) || init_flags & XE_LRC_CREATE_USER_CTX) /* userspace */
- bo_flags |= XE_BO_FLAG_PINNED_LATE_RESTORE | XE_BO_FLAG_FORCE_USER_VRAM;
-
- lrc->bo = xe_bo_create_pin_map_novm(xe, tile,
- bo_size,
- ttm_bo_type_kernel,
- bo_flags, false);
- if (IS_ERR(lrc->bo))
- return PTR_ERR(lrc->bo);
-
- seqno_bo = xe_bo_create_pin_map_novm(xe, tile, PAGE_SIZE,
- ttm_bo_type_kernel,
- XE_BO_FLAG_GGTT |
- XE_BO_FLAG_GGTT_INVALIDATE |
- XE_BO_FLAG_SYSTEM, false);
- if (IS_ERR(seqno_bo)) {
- err = PTR_ERR(seqno_bo);
- goto err_lrc_finish;
- }
- lrc->seqno_bo = seqno_bo;
-
- xe_hw_fence_ctx_init(&lrc->fence_ctx, hwe->gt,
- hwe->fence_irq, hwe->name);
-
/*
* Init Per-Process of HW status Page, LRC / context state to known
* values. If there's already a primed default_lrc, just copy it, otherwise
@@ -1508,7 +1459,7 @@ static int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe,
xe_map_memset(xe, &map, 0, 0, LRC_PPHWSP_SIZE); /* PPHWSP */
xe_map_memcpy_to(xe, &map, LRC_PPHWSP_SIZE,
gt->default_lrc[hwe->class] + LRC_PPHWSP_SIZE,
- lrc_size - LRC_PPHWSP_SIZE);
+ lrc->size - LRC_PPHWSP_SIZE);
if (replay_state)
xe_map_memcpy_to(xe, &map, LRC_PPHWSP_SIZE,
replay_state, lrc->replay_size);
@@ -1516,21 +1467,16 @@ static int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe,
void *init_data = empty_lrc_data(hwe);

if (!init_data) {
- err = -ENOMEM;
- goto err_lrc_finish;
+ return -ENOMEM;
}

- xe_map_memcpy_to(xe, &map, 0, init_data, lrc_size);
+ xe_map_memcpy_to(xe, &map, 0, init_data, lrc->size);
kfree(init_data);
}

- if (vm) {
+ if (vm)
xe_lrc_set_ppgtt(lrc, vm);

- if (vm->xef)
- xe_drm_client_add_bo(vm->xef->client, lrc->bo);
- }
-
if (xe_device_has_msix(xe)) {
xe_lrc_write_ctx_reg(lrc, CTX_INT_STATUS_REPORT_PTR,
xe_memirq_status_ptr(&tile->memirq, hwe));
@@ -1602,12 +1548,93 @@ static int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe,

err = setup_wa_bb(lrc, hwe);
if (err)
- goto err_lrc_finish;
+ return err;

err = setup_indirect_ctx(lrc, hwe);
+
+ return err;
+}
+
+/**
+ * xe_lrc_reinit() - Re-initialize LRC
+ * @lrc: Pointer to the LRC
+ * @hwe: Hardware Engine
+ * @vm: The VM (address space)
+ * @replay_state: GPU hang replay state
+ * @msix_vec: MSI-X interrupt vector (for platforms that support it)
+ * @init_flags: LRC initialization flags
+ *
+ * Returns: 0 on success, negative error code otherwise.
+ */
+int xe_lrc_reinit(struct xe_lrc *lrc, struct xe_hw_engine *hwe, struct xe_vm *vm,
+ void *replay_state, u16 msix_vec, u32 init_flags)
+{
+ return xe_lrc_init_ctx(lrc, hwe, vm, replay_state, msix_vec, init_flags);
+}
+
+static int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe, struct xe_vm *vm,
+ void *replay_state, u32 ring_size, u16 msix_vec, u32 init_flags)
+{
+ struct xe_gt *gt = hwe->gt;
+ const u32 lrc_size = xe_gt_lrc_size(gt, hwe->class);
+ u32 bo_size = ring_size + lrc_size + LRC_WA_BB_SIZE;
+ struct xe_tile *tile = gt_to_tile(gt);
+ struct xe_device *xe = gt_to_xe(gt);
+ struct xe_bo *bo;
+ u32 bo_flags;
+ int err;
+
+ kref_init(&lrc->refcount);
+ lrc->gt = gt;
+ lrc->replay_size = xe_gt_lrc_hang_replay_size(gt, hwe->class);
+ lrc->size = lrc_size;
+ lrc->flags = 0;
+ lrc->ring.size = ring_size;
+ lrc->ring.tail = 0;
+
+ if (gt_engine_needs_indirect_ctx(gt, hwe->class)) {
+ lrc->flags |= XE_LRC_FLAG_INDIRECT_CTX;
+ bo_size += LRC_INDIRECT_CTX_BO_SIZE;
+ }
+
+ if (xe_gt_has_indirect_ring_state(gt))
+ lrc->flags |= XE_LRC_FLAG_INDIRECT_RING_STATE;
+
+ bo_flags = XE_BO_FLAG_VRAM_IF_DGFX(tile) | XE_BO_FLAG_GGTT |
+ XE_BO_FLAG_GGTT_INVALIDATE;
+
+ if ((vm && vm->xef) || init_flags & XE_LRC_CREATE_USER_CTX) /* userspace */
+ bo_flags |= XE_BO_FLAG_PINNED_LATE_RESTORE | XE_BO_FLAG_FORCE_USER_VRAM;
+
+ bo = xe_bo_create_pin_map_novm(xe, tile, bo_size,
+ ttm_bo_type_kernel,
+ bo_flags, false);
+ if (IS_ERR(lrc->bo))
+ return PTR_ERR(lrc->bo);
+
+ lrc->bo = bo;
+
+ bo = xe_bo_create_pin_map_novm(xe, tile, PAGE_SIZE,
+ ttm_bo_type_kernel,
+ XE_BO_FLAG_GGTT |
+ XE_BO_FLAG_GGTT_INVALIDATE |
+ XE_BO_FLAG_SYSTEM, false);
+ if (IS_ERR(bo)) {
+ err = PTR_ERR(bo);
+ goto err_lrc_finish;
+ }
+ lrc->seqno_bo = bo;
+
+ xe_hw_fence_ctx_init(&lrc->fence_ctx, hwe->gt,
+ hwe->fence_irq, hwe->name);
+
+ err = xe_lrc_init_ctx(lrc, hwe, vm, replay_state, msix_vec, init_flags);
if (err)
goto err_lrc_finish;

+ if (vm && vm->xef)
+ xe_drm_client_add_bo(vm->xef->client, lrc->bo);
+
return 0;

err_lrc_finish:
diff --git a/drivers/gpu/drm/xe/xe_lrc.h b/drivers/gpu/drm/xe/xe_lrc.h
index 3e500004f1ae..af31de8df408 100644
--- a/drivers/gpu/drm/xe/xe_lrc.h
+++ b/drivers/gpu/drm/xe/xe_lrc.h
@@ -52,6 +52,8 @@ struct xe_lrc_snapshot {

struct xe_lrc *xe_lrc_create(struct xe_hw_engine *hwe, struct xe_vm *vm,
void *replay_state, u32 ring_size, u16 msix_vec, u32 flags);
+int xe_lrc_reinit(struct xe_lrc *lrc, struct xe_hw_engine *hwe, struct xe_vm *vm,
+ void *replay_state, u16 msix_vec, u32 init_flags);
void xe_lrc_destroy(struct kref *ref);

/**
--
2.43.0