]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/xe/vf: React to MIGRATED interrupt
authorTomasz Lis <tomasz.lis@intel.com>
Mon, 4 Nov 2024 21:34:45 +0000 (22:34 +0100)
committerMichal Wajdeczko <michal.wajdeczko@intel.com>
Wed, 6 Nov 2024 13:53:35 +0000 (14:53 +0100)
To properly support VF Save/Restore procedure, fixups need to be
applied after PF driver finishes its part of VF Restore. The fixups
are required to adjust the ongoing execution for a hardware switch
that happened, because some GFX resources are not fully virtualized,
and assigned to a VF as range from a global pool. The VF on which
a VM is restored will often have different ranges provisioned than
the VF on which save process happened. Those resource fixups are
applied by the VF driver within a restored VM.

A VF driver gets informed that it was migrated by receiving an
interrupt from each GuC. The interrupt assigned for that purpose
is "GUC SW interrupt 0". Seeing that fields set from within the
irq handler should be the trigger for fixups.

The VF can safely do post-migration fixups on resources associated
to each GuC only after that GuC issued the MIGRATED interrupt.

This change introduces a worker to be used for post-migration fixups,
and a mechanism to schedule said worker when all GuCs sent the irq.

v2: renamed and moved functions, updated logged messages, removed
  unused includes, used anon struct (Michal)
v3: ordering, kerneldoc, asserts, debug messages,
  on_all_tiles -> on_all_gts (Michal)
v4: fixed missing header include
v5: Explained what fixups are, explained which IRQ is used, style
  fixes (Michal)

Bspec: 50868
Signed-off-by: Tomasz Lis <tomasz.lis@intel.com>
Reviewed-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20241104213449.1455694-2-tomasz.lis@intel.com
Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
drivers/gpu/drm/xe/Makefile
drivers/gpu/drm/xe/xe_device_types.h
drivers/gpu/drm/xe/xe_gt_sriov_vf.c
drivers/gpu/drm/xe/xe_gt_sriov_vf.h
drivers/gpu/drm/xe/xe_guc.c
drivers/gpu/drm/xe/xe_memirq.c
drivers/gpu/drm/xe/xe_sriov.c
drivers/gpu/drm/xe/xe_sriov_types.h
drivers/gpu/drm/xe/xe_sriov_vf.c [new file with mode: 0644]
drivers/gpu/drm/xe/xe_sriov_vf.h [new file with mode: 0644]

index 8f81e1c9d018213b4e794301d7f7c3e7cee6de6f..95aabbb74a28445992a2478a224b2977b212c452 100644 (file)
@@ -125,7 +125,8 @@ xe-y += \
        xe_gt_sriov_vf.o \
        xe_guc_relay.o \
        xe_memirq.o \
-       xe_sriov.o
+       xe_sriov.o \
+       xe_sriov_vf.o
 
 xe-$(CONFIG_PCI_IOV) += \
        xe_gt_sriov_pf.o \
index cb193234c7eca0fac7905c010de87dbe16c8eda4..bccca63c8a48c26c933a62e2e2783a2a9b8b1ffd 100644 (file)
@@ -374,6 +374,8 @@ struct xe_device {
 
                /** @sriov.pf: PF specific data */
                struct xe_device_pf pf;
+               /** @sriov.vf: VF specific data */
+               struct xe_device_vf vf;
 
                /** @sriov.wq: workqueue used by the virtualization workers */
                struct workqueue_struct *wq;
index d3baba50f0851541e9e9127380a04b66cbe37358..0e330eb938227c1e32f642154093e49c3d292a97 100644 (file)
@@ -27,6 +27,7 @@
 #include "xe_guc_relay.h"
 #include "xe_mmio.h"
 #include "xe_sriov.h"
+#include "xe_sriov_vf.h"
 #include "xe_uc_fw.h"
 #include "xe_wopcm.h"
 
@@ -692,6 +693,30 @@ failed:
        return err;
 }
 
+/**
+ * xe_gt_sriov_vf_migrated_event_handler - Start a VF migration recovery,
+ *   or just mark that a GuC is ready for it.
+ * @gt: the &xe_gt struct instance linked to target GuC
+ *
+ * This function shall be called only by VF.
+ */
+void xe_gt_sriov_vf_migrated_event_handler(struct xe_gt *gt)
+{
+       struct xe_device *xe = gt_to_xe(gt);
+
+       xe_gt_assert(gt, IS_SRIOV_VF(xe));
+
+       set_bit(gt->info.id, &xe->sriov.vf.migration.gt_flags);
+       /*
+        * We need to be certain that if all flags were set, at least one
+        * thread will notice that and schedule the recovery.
+        */
+       smp_mb__after_atomic();
+
+       xe_gt_sriov_info(gt, "ready for recovery after migration\n");
+       xe_sriov_vf_start_migration_recovery(xe);
+}
+
 static bool vf_is_negotiated(struct xe_gt *gt, u16 major, u16 minor)
 {
        xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt)));
index e541ce57bec246a530ccdeaf99e986a74b6e51ff..9959a296b221a4428f3d8d5d55d46b15f231de5f 100644 (file)
@@ -17,6 +17,7 @@ int xe_gt_sriov_vf_query_config(struct xe_gt *gt);
 int xe_gt_sriov_vf_connect(struct xe_gt *gt);
 int xe_gt_sriov_vf_query_runtime(struct xe_gt *gt);
 int xe_gt_sriov_vf_prepare_ggtt(struct xe_gt *gt);
+void xe_gt_sriov_vf_migrated_event_handler(struct xe_gt *gt);
 
 u32 xe_gt_sriov_vf_gmdid(struct xe_gt *gt);
 u16 xe_gt_sriov_vf_guc_ids(struct xe_gt *gt);
index 7f704346a8f4d298e0264101cf5f73af81fff2ea..7224593c9ce9b924eb64de2730c6ee0a1c650ddd 100644 (file)
@@ -1099,10 +1099,21 @@ int xe_guc_self_cfg64(struct xe_guc *guc, u16 key, u64 val)
        return guc_self_cfg(guc, key, 2, val);
 }
 
+static void xe_guc_sw_0_irq_handler(struct xe_guc *guc)
+{
+       struct xe_gt *gt = guc_to_gt(guc);
+
+       if (IS_SRIOV_VF(gt_to_xe(gt)))
+               xe_gt_sriov_vf_migrated_event_handler(gt);
+}
+
 void xe_guc_irq_handler(struct xe_guc *guc, const u16 iir)
 {
        if (iir & GUC_INTR_GUC2HOST)
                xe_guc_ct_irq_handler(&guc->ct);
+
+       if (iir & GUC_INTR_SW_INT_0)
+               xe_guc_sw_0_irq_handler(guc);
 }
 
 void xe_guc_sanitize(struct xe_guc *guc)
index f833da88150a1ce575e095e5fc09e14766fe858c..51dc90906003ba61c378f82d149a51cf5ce6a304 100644 (file)
@@ -442,6 +442,9 @@ static void memirq_dispatch_guc(struct xe_memirq *memirq, struct iosys_map *stat
 
        if (memirq_received(memirq, status, ilog2(GUC_INTR_GUC2HOST), name))
                xe_guc_irq_handler(guc, GUC_INTR_GUC2HOST);
+
+       if (memirq_received(memirq, status, ilog2(GUC_INTR_SW_INT_0), name))
+               xe_guc_irq_handler(guc, GUC_INTR_SW_INT_0);
 }
 
 /**
index ef10782af65603c85bc43ae0a63e58366c570419..04e2f539ccd94cf69b556c8dd71adfaa6fef698a 100644 (file)
@@ -14,6 +14,7 @@
 #include "xe_mmio.h"
 #include "xe_sriov.h"
 #include "xe_sriov_pf.h"
+#include "xe_sriov_vf.h"
 
 /**
  * xe_sriov_mode_to_string - Convert enum value to string.
@@ -114,6 +115,9 @@ int xe_sriov_init(struct xe_device *xe)
                        return err;
        }
 
+       if (IS_SRIOV_VF(xe))
+               xe_sriov_vf_init_early(xe);
+
        xe_assert(xe, !xe->sriov.wq);
        xe->sriov.wq = alloc_workqueue("xe-sriov-wq", 0, 0);
        if (!xe->sriov.wq)
index c7b7ad4af5c8f6d48713b7a211ffa725bd0653bf..ca94382a721e5bf4f5e96a5794b4381a1b542c06 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/build_bug.h>
 #include <linux/mutex.h>
 #include <linux/types.h>
+#include <linux/workqueue_types.h>
 
 /**
  * VFID - Virtual Function Identifier
@@ -56,4 +57,20 @@ struct xe_device_pf {
        struct mutex master_lock;
 };
 
+/**
+ * struct xe_device_vf - Xe Virtual Function related data
+ *
+ * The data in this structure is valid only if driver is running in the
+ * @XE_SRIOV_MODE_VF mode.
+ */
+struct xe_device_vf {
+       /** @migration: VF Migration state data */
+       struct {
+               /** @migration.worker: VF migration recovery worker */
+               struct work_struct worker;
+               /** @migration.gt_flags: Per-GT request flags for VF migration recovery */
+               unsigned long gt_flags;
+       } migration;
+};
+
 #endif
diff --git a/drivers/gpu/drm/xe/xe_sriov_vf.c b/drivers/gpu/drm/xe/xe_sriov_vf.c
new file mode 100644 (file)
index 0000000..2fe4929
--- /dev/null
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023-2024 Intel Corporation
+ */
+
+#include <drm/drm_managed.h>
+
+#include "xe_assert.h"
+#include "xe_device.h"
+#include "xe_gt_sriov_printk.h"
+#include "xe_sriov.h"
+#include "xe_sriov_printk.h"
+#include "xe_sriov_vf.h"
+
+static void migration_worker_func(struct work_struct *w);
+
+/**
+ * xe_sriov_vf_init_early - Initialize SR-IOV VF specific data.
+ * @xe: the &xe_device to initialize
+ */
+void xe_sriov_vf_init_early(struct xe_device *xe)
+{
+       INIT_WORK(&xe->sriov.vf.migration.worker, migration_worker_func);
+}
+
+static void vf_post_migration_recovery(struct xe_device *xe)
+{
+       drm_dbg(&xe->drm, "migration recovery in progress\n");
+       /* FIXME: add the recovery steps */
+       drm_notice(&xe->drm, "migration recovery ended\n");
+}
+
+static void migration_worker_func(struct work_struct *w)
+{
+       struct xe_device *xe = container_of(w, struct xe_device,
+                                           sriov.vf.migration.worker);
+
+       vf_post_migration_recovery(xe);
+}
+
+static bool vf_ready_to_recovery_on_all_gts(struct xe_device *xe)
+{
+       struct xe_gt *gt;
+       unsigned int id;
+
+       for_each_gt(gt, xe, id) {
+               if (!test_bit(id, &xe->sriov.vf.migration.gt_flags)) {
+                       xe_gt_sriov_dbg_verbose(gt, "still not ready to recover\n");
+                       return false;
+               }
+       }
+       return true;
+}
+
+/**
+ * xe_sriov_vf_start_migration_recovery - Start VF migration recovery.
+ * @xe: the &xe_device to start recovery on
+ *
+ * This function shall be called only by VF.
+ */
+void xe_sriov_vf_start_migration_recovery(struct xe_device *xe)
+{
+       bool started;
+
+       xe_assert(xe, IS_SRIOV_VF(xe));
+
+       if (!vf_ready_to_recovery_on_all_gts(xe))
+               return;
+
+       WRITE_ONCE(xe->sriov.vf.migration.gt_flags, 0);
+       /* Ensure other threads see that no flags are set now. */
+       smp_mb();
+
+       started = queue_work(xe->sriov.wq, &xe->sriov.vf.migration.worker);
+       drm_info(&xe->drm, "VF migration recovery %s\n", started ?
+                "scheduled" : "already in progress");
+}
diff --git a/drivers/gpu/drm/xe/xe_sriov_vf.h b/drivers/gpu/drm/xe/xe_sriov_vf.h
new file mode 100644 (file)
index 0000000..7b8622c
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023-2024 Intel Corporation
+ */
+
+#ifndef _XE_SRIOV_VF_H_
+#define _XE_SRIOV_VF_H_
+
+struct xe_device;
+
+void xe_sriov_vf_init_early(struct xe_device *xe);
+void xe_sriov_vf_start_migration_recovery(struct xe_device *xe);
+
+#endif