]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/xe/vf: Redo LRC creation while in VF fixups
authorTomasz Lis <tomasz.lis@intel.com>
Thu, 26 Feb 2026 21:27:01 +0000 (22:27 +0100)
committerMichal Wajdeczko <michal.wajdeczko@intel.com>
Fri, 27 Feb 2026 17:02:07 +0000 (18:02 +0100)
If the xe module within a VM was creating a new LRC during save/
restore, this LRC will be invalid. The fixups procedure may not
be able to reach it, as there will be a race to add the new LRC
reference to an exec queue.

Even if the new LRC which was being created during VM migration is
added to EQ in time for fixups, said LRC may still remain damaged.
In a small percentage of specially crafted test cases, the resulting
LRC was still damaged and caused GPU hang.

Any LRC which could be created in such a situation, have to be
re-created.

Due to VM having arbitrarily set amount of CPU cores, it is possible
to limit the amount to 1. In such case, there is a possibility that
kernel will switch CPU contexts in a way which allows to miss
VF migration recovery running in parallel (by simply not switching
to the LRC creation thread during recovery). Therefore checking
if the migration is in progress just after LRC creation, is not
enough to ensure detection.

Free the incorrectly created LRC, and trigger a re-run of the
creation, but only after waiting for default LRC to get fixups.
Use additional atomic value increased after fixups, to ensure any VF
migration that avoided detection by just checking for recovery in
progress, will be caught.

v2: Merge marker and wait for default LRC, reducing amount of calls
  within xe_init_eq(). Alter the LRC creation loop to remove a race
  with post-migration fixups worker.
v3: Kerneldoc fixes. Rename fixups_complete_count.

Signed-off-by: Tomasz Lis <tomasz.lis@intel.com>
Reviewed-by: Matthew Brost <matthew.brost@intel.com>
Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
Link: https://patch.msgid.link/20260226212701.2937065-5-tomasz.lis@intel.com
drivers/gpu/drm/xe/xe_exec_queue.c
drivers/gpu/drm/xe/xe_gt_sriov_vf.c
drivers/gpu/drm/xe/xe_gt_sriov_vf.h
drivers/gpu/drm/xe/xe_gt_sriov_vf_types.h

index 0e46cbed90069d63c385b91970e046358ebe611c..bb273ca02d28093381686e9e7e92291ac1a404bb 100644 (file)
@@ -368,17 +368,28 @@ static int __xe_exec_queue_init(struct xe_exec_queue *q, u32 exec_queue_flags)
         * from the moment vCPU resumes execution.
         */
        for (i = 0; i < q->width; ++i) {
-               struct xe_lrc *lrc;
+               struct xe_lrc *__lrc = NULL;
+               int marker;
 
-               xe_gt_sriov_vf_wait_valid_ggtt(q->gt);
-               lrc = xe_lrc_create(q->hwe, q->vm, q->replay_state,
-                                   xe_lrc_ring_size(), q->msix_vec, flags);
-               if (IS_ERR(lrc)) {
-                       err = PTR_ERR(lrc);
-                       goto err_lrc;
-               }
+               do {
+                       struct xe_lrc *lrc;
+
+                       marker = xe_gt_sriov_vf_wait_valid_ggtt(q->gt);
+
+                       lrc = xe_lrc_create(q->hwe, q->vm, q->replay_state,
+                                           xe_lrc_ring_size(), q->msix_vec, flags);
+                       if (IS_ERR(lrc)) {
+                               err = PTR_ERR(lrc);
+                               goto err_lrc;
+                       }
+
+                       xe_exec_queue_set_lrc(q, lrc, i);
+
+                       if (__lrc)
+                               xe_lrc_put(__lrc);
+                       __lrc = lrc;
 
-               xe_exec_queue_set_lrc(q, lrc, i);
+               } while (marker != xe_vf_migration_fixups_complete_count(q->gt));
        }
 
        return 0;
index 7f83c0d3b099ba8808d56dd065b7a634875820a7..8989c8e1be95e632b77c017cc94ac8e536ea0956 100644 (file)
@@ -1277,6 +1277,8 @@ static int vf_post_migration_fixups(struct xe_gt *gt)
        if (err)
                return err;
 
+       atomic_inc(&gt->sriov.vf.migration.fixups_complete_count);
+
        return 0;
 }
 
@@ -1515,20 +1517,50 @@ static bool vf_valid_ggtt(struct xe_gt *gt)
        return true;
 }
 
+/**
+ * xe_vf_migration_fixups_complete_count() - Get count of VF fixups completions.
+ * @gt: the &xe_gt instance which contains affected Global GTT
+ *
+ * Return: number of times VF fixups were completed since driver
+ * probe, or 0 if migration is not available, or -1 if fixups are
+ * pending or being applied right now.
+ */
+int xe_vf_migration_fixups_complete_count(struct xe_gt *gt)
+{
+       if (!IS_SRIOV_VF(gt_to_xe(gt)) ||
+           !xe_sriov_vf_migration_supported(gt_to_xe(gt)))
+               return 0;
+
+       /* should never match fixups_complete_count value */
+       if (!vf_valid_ggtt(gt))
+               return -1;
+
+       return atomic_read(&gt->sriov.vf.migration.fixups_complete_count);
+}
+
 /**
  * xe_gt_sriov_vf_wait_valid_ggtt() - wait for valid GGTT nodes and address refs
- * @gt: the &xe_gt
+ * @gt: the &xe_gt instance which contains affected Global GTT
+ *
+ * Return: number of times VF fixups were completed since driver
+ * probe, or 0 if migration is not available.
  */
-void xe_gt_sriov_vf_wait_valid_ggtt(struct xe_gt *gt)
+int xe_gt_sriov_vf_wait_valid_ggtt(struct xe_gt *gt)
 {
        int ret;
 
+       /*
+        * this condition needs to be identical to one in
+        * xe_vf_migration_fixups_complete_count()
+        */
        if (!IS_SRIOV_VF(gt_to_xe(gt)) ||
            !xe_sriov_vf_migration_supported(gt_to_xe(gt)))
-               return;
+               return 0;
 
        ret = wait_event_interruptible_timeout(gt->sriov.vf.migration.wq,
                                               vf_valid_ggtt(gt),
                                               HZ * 5);
        xe_gt_WARN_ON(gt, !ret);
+
+       return atomic_read(&gt->sriov.vf.migration.fixups_complete_count);
 }
index 7d97189c2d3d9da81d1b9a2e73f3ea6308c8ea68..a6f7127521a5dabdb80991eb739a4bd7c1fe8ae6 100644 (file)
@@ -39,6 +39,7 @@ void xe_gt_sriov_vf_print_config(struct xe_gt *gt, struct drm_printer *p);
 void xe_gt_sriov_vf_print_runtime(struct xe_gt *gt, struct drm_printer *p);
 void xe_gt_sriov_vf_print_version(struct xe_gt *gt, struct drm_printer *p);
 
-void xe_gt_sriov_vf_wait_valid_ggtt(struct xe_gt *gt);
+int xe_gt_sriov_vf_wait_valid_ggtt(struct xe_gt *gt);
+int xe_vf_migration_fixups_complete_count(struct xe_gt *gt);
 
 #endif
index fca18be589db97b4bcbd1320133316a5d67ed3f0..80562ffadb169ffa3341716b26bb6a23bc79dcb7 100644 (file)
@@ -54,6 +54,8 @@ struct xe_gt_sriov_vf_migration {
        wait_queue_head_t wq;
        /** @scratch: Scratch memory for VF recovery */
        void *scratch;
+       /** @fixups_complete_count: Counts completed fixups stages */
+       atomic_t fixups_complete_count;
        /** @debug: Debug hooks for delaying migration */
        struct {
                /**