]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/xe/vf: Move tile-related VF functions to separate file
authorMichal Wajdeczko <michal.wajdeczko@intel.com>
Mon, 2 Jun 2025 10:33:24 +0000 (12:33 +0200)
committerMichal Wajdeczko <michal.wajdeczko@intel.com>
Tue, 3 Jun 2025 10:35:57 +0000 (12:35 +0200)
Some of our VF functions, even if they take a GT pointer, work
only on primary GT and really are tile-related and would be better
to keep them separate from the rest of true GT-oriented functions.
Move them to a file and update to take a tile pointer instead.

Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
Cc: Tomasz Lis <tomasz.lis@intel.com>
Reviewed-by: Tomasz Lis <tomasz.lis@intel.com>
Link: https://lore.kernel.org/r/20250602103325.549-3-michal.wajdeczko@intel.com
drivers/gpu/drm/xe/Makefile
drivers/gpu/drm/xe/xe_ggtt.c
drivers/gpu/drm/xe/xe_gt_sriov_vf.c
drivers/gpu/drm/xe/xe_gt_sriov_vf.h
drivers/gpu/drm/xe/xe_sriov_vf.c
drivers/gpu/drm/xe/xe_tile_sriov_vf.c [new file with mode: 0644]
drivers/gpu/drm/xe/xe_tile_sriov_vf.h [new file with mode: 0644]

index c5d6681645ede4a48f322b30c3eb499b61e033c7..01d231777901a4bbff31cb035f85d74cef82a1c0 100644 (file)
@@ -139,7 +139,8 @@ xe-y += \
        xe_guc_relay.o \
        xe_memirq.o \
        xe_sriov.o \
-       xe_sriov_vf.o
+       xe_sriov_vf.o \
+       xe_tile_sriov_vf.o
 
 xe-$(CONFIG_PCI_IOV) += \
        xe_gt_sriov_pf.o \
index af8e53014b874d6294a5fbb30ecb0308a4b47b6d..b9a0fd5ccaba3c3a7fc4f3f1ce23e2e5ff266d40 100644 (file)
 #include "xe_device.h"
 #include "xe_gt.h"
 #include "xe_gt_printk.h"
-#include "xe_gt_sriov_vf.h"
 #include "xe_gt_tlb_invalidation.h"
 #include "xe_map.h"
 #include "xe_mmio.h"
 #include "xe_pm.h"
 #include "xe_sriov.h"
+#include "xe_tile_sriov_vf.h"
 #include "xe_wa.h"
 #include "xe_wopcm.h"
 
@@ -258,7 +258,7 @@ int xe_ggtt_init_early(struct xe_ggtt *ggtt)
                return err;
 
        if (IS_SRIOV_VF(xe)) {
-               err = xe_gt_sriov_vf_prepare_ggtt(xe_tile_get_gt(ggtt->tile, 0));
+               err = xe_tile_sriov_vf_prepare_ggtt(ggtt->tile);
                if (err)
                        return err;
        }
index acfb3b1b08324ed696723b845f0a461389b343a2..792523cfa6e67deaa3e6775540942597f11d0770 100644 (file)
@@ -613,168 +613,6 @@ s64 xe_gt_sriov_vf_ggtt_shift(struct xe_gt *gt)
        return config->ggtt_shift;
 }
 
-static int vf_init_ggtt_balloons(struct xe_gt *gt)
-{
-       struct xe_tile *tile = gt_to_tile(gt);
-       struct xe_ggtt *ggtt = tile->mem.ggtt;
-
-       xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt)));
-       xe_gt_assert(gt, !xe_gt_is_media_type(gt));
-
-       tile->sriov.vf.ggtt_balloon[0] = xe_ggtt_node_init(ggtt);
-       if (IS_ERR(tile->sriov.vf.ggtt_balloon[0]))
-               return PTR_ERR(tile->sriov.vf.ggtt_balloon[0]);
-
-       tile->sriov.vf.ggtt_balloon[1] = xe_ggtt_node_init(ggtt);
-       if (IS_ERR(tile->sriov.vf.ggtt_balloon[1])) {
-               xe_ggtt_node_fini(tile->sriov.vf.ggtt_balloon[0]);
-               return PTR_ERR(tile->sriov.vf.ggtt_balloon[1]);
-       }
-
-       return 0;
-}
-
-/**
- * xe_gt_sriov_vf_balloon_ggtt_locked - Insert balloon nodes to limit used GGTT address range.
- * @gt: the &xe_gt struct instance
- * Return: 0 on success or a negative error code on failure.
- */
-int xe_gt_sriov_vf_balloon_ggtt_locked(struct xe_gt *gt)
-{
-       struct xe_gt_sriov_vf_selfconfig *config = &gt->sriov.vf.self_config;
-       struct xe_tile *tile = gt_to_tile(gt);
-       struct xe_device *xe = gt_to_xe(gt);
-       u64 start, end;
-       int err;
-
-       xe_gt_assert(gt, IS_SRIOV_VF(xe));
-       xe_gt_assert(gt, !xe_gt_is_media_type(gt));
-       lockdep_assert_held(&tile->mem.ggtt->lock);
-
-       if (!config->ggtt_size)
-               return -ENODATA;
-
-       /*
-        * VF can only use part of the GGTT as allocated by the PF:
-        *
-        *      WOPCM                                  GUC_GGTT_TOP
-        *      |<------------ Total GGTT size ------------------>|
-        *
-        *           VF GGTT base -->|<- size ->|
-        *
-        *      +--------------------+----------+-----------------+
-        *      |////////////////////|   block  |\\\\\\\\\\\\\\\\\|
-        *      +--------------------+----------+-----------------+
-        *
-        *      |<--- balloon[0] --->|<-- VF -->|<-- balloon[1] ->|
-        */
-
-       start = xe_wopcm_size(xe);
-       end = config->ggtt_base;
-       if (end != start) {
-               err = xe_ggtt_node_insert_balloon_locked(tile->sriov.vf.ggtt_balloon[0],
-                                                        start, end);
-               if (err)
-                       return err;
-       }
-
-       start = config->ggtt_base + config->ggtt_size;
-       end = GUC_GGTT_TOP;
-       if (end != start) {
-               err = xe_ggtt_node_insert_balloon_locked(tile->sriov.vf.ggtt_balloon[1],
-                                                        start, end);
-               if (err) {
-                       xe_ggtt_node_remove_balloon_locked(tile->sriov.vf.ggtt_balloon[0]);
-                       return err;
-               }
-       }
-
-       return 0;
-}
-
-static int vf_balloon_ggtt(struct xe_gt *gt)
-{
-       struct xe_ggtt *ggtt = gt_to_tile(gt)->mem.ggtt;
-       int err;
-
-       mutex_lock(&ggtt->lock);
-       err = xe_gt_sriov_vf_balloon_ggtt_locked(gt);
-       mutex_unlock(&ggtt->lock);
-
-       return err;
-}
-
-/**
- * xe_gt_sriov_vf_deballoon_ggtt_locked - Remove balloon nodes.
- * @gt: the &xe_gt struct instance
- */
-void xe_gt_sriov_vf_deballoon_ggtt_locked(struct xe_gt *gt)
-{
-       struct xe_tile *tile = gt_to_tile(gt);
-
-       xe_tile_assert(tile, IS_SRIOV_VF(tile_to_xe(tile)));
-       xe_ggtt_node_remove_balloon_locked(tile->sriov.vf.ggtt_balloon[1]);
-       xe_ggtt_node_remove_balloon_locked(tile->sriov.vf.ggtt_balloon[0]);
-}
-
-static void vf_deballoon_ggtt(struct xe_gt *gt)
-{
-       struct xe_tile *tile = gt_to_tile(gt);
-
-       mutex_lock(&tile->mem.ggtt->lock);
-       xe_gt_sriov_vf_deballoon_ggtt_locked(gt);
-       mutex_unlock(&tile->mem.ggtt->lock);
-}
-
-static void vf_fini_ggtt_balloons(struct xe_gt *gt)
-{
-       struct xe_tile *tile = gt_to_tile(gt);
-
-       xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt)));
-       xe_gt_assert(gt, !xe_gt_is_media_type(gt));
-
-       xe_ggtt_node_fini(tile->sriov.vf.ggtt_balloon[1]);
-       xe_ggtt_node_fini(tile->sriov.vf.ggtt_balloon[0]);
-}
-
-static void cleanup_ggtt(struct drm_device *drm, void *arg)
-{
-       struct xe_gt *gt = arg;
-
-       vf_deballoon_ggtt(gt);
-       vf_fini_ggtt_balloons(gt);
-}
-
-/**
- * xe_gt_sriov_vf_prepare_ggtt - Prepare a VF's GGTT configuration.
- * @gt: the &xe_gt
- *
- * This function is for VF use only.
- *
- * Return: 0 on success or a negative error code on failure.
- */
-int xe_gt_sriov_vf_prepare_ggtt(struct xe_gt *gt)
-{
-       struct xe_tile *tile = gt_to_tile(gt);
-       struct xe_device *xe = tile_to_xe(tile);
-       int err;
-
-       if (xe_gt_is_media_type(gt))
-               return 0;
-
-       err = vf_init_ggtt_balloons(gt);
-       if (err)
-               return err;
-
-       err = vf_balloon_ggtt(gt);
-       if (err) {
-               vf_fini_ggtt_balloons(gt);
-               return err;
-       }
-
-       return drmm_add_action_or_reset(&xe->drm, cleanup_ggtt, gt);
-}
-
 static int relay_action_handshake(struct xe_gt *gt, u32 *major, u32 *minor)
 {
        u32 request[VF2PF_HANDSHAKE_REQUEST_MSG_LEN] = {
@@ -870,89 +708,6 @@ failed:
        return err;
 }
 
-/**
- * DOC: GGTT nodes shifting during VF post-migration recovery
- *
- * The first fixup applied to the VF KMD structures as part of post-migration
- * recovery is shifting nodes within &xe_ggtt instance. The nodes are moved
- * from range previously assigned to this VF, into newly provisioned area.
- * The changes include balloons, which are resized accordingly.
- *
- * The balloon nodes are there to eliminate unavailable ranges from use: one
- * reserves the GGTT area below the range for current VF, and another one
- * reserves area above.
- *
- * Below is a GGTT layout of example VF, with a certain address range assigned to
- * said VF, and inaccessible areas above and below:
- *
- *  0                                                                        4GiB
- *  |<--------------------------- Total GGTT size ----------------------------->|
- *      WOPCM                                                         GUC_TOP
- *      |<-------------- Area mappable by xe_ggtt instance ---------------->|
- *
- *  +---+---------------------------------+----------+----------------------+---+
- *  |\\\|/////////////////////////////////|  VF mem  |//////////////////////|\\\|
- *  +---+---------------------------------+----------+----------------------+---+
- *
- * Hardware enforced access rules before migration:
- *
- *  |<------- inaccessible for VF ------->|<VF owned>|<-- inaccessible for VF ->|
- *
- * GGTT nodes used for tracking allocations:
- *
- *      |<---------- balloon ------------>|<- nodes->|<----- balloon ------>|
- *
- * After the migration, GGTT area assigned to the VF might have shifted, either
- * to lower or to higher address. But we expect the total size and extra areas to
- * be identical, as migration can only happen between matching platforms.
- * Below is an example of GGTT layout of the VF after migration. Content of the
- * GGTT for VF has been moved to a new area, and we receive its address from GuC:
- *
- *  +---+----------------------+----------+---------------------------------+---+
- *  |\\\|//////////////////////|  VF mem  |/////////////////////////////////|\\\|
- *  +---+----------------------+----------+---------------------------------+---+
- *
- * Hardware enforced access rules after migration:
- *
- *  |<- inaccessible for VF -->|<VF owned>|<------- inaccessible for VF ------->|
- *
- * So the VF has a new slice of GGTT assigned, and during migration process, the
- * memory content was copied to that new area. But the &xe_ggtt nodes are still
- * tracking allocations using the old addresses. The nodes within VF owned area
- * have to be shifted, and balloon nodes need to be resized to properly mask out
- * areas not owned by the VF.
- *
- * Fixed &xe_ggtt nodes used for tracking allocations:
- *
- *     |<------ balloon ------>|<- nodes->|<----------- balloon ----------->|
- *
- * Due to use of GPU profiles, we do not expect the old and new GGTT ares to
- * overlap; but our node shifting will fix addresses properly regardless.
- */
-
-/**
- * xe_gt_sriov_vf_fixup_ggtt_nodes - Shift GGTT allocations to match assigned range.
- * @gt: the &xe_gt struct instance
- * @shift: the shift value
- *
- * Since Global GTT is not virtualized, each VF has an assigned range
- * within the global space. This range might have changed during migration,
- * which requires all memory addresses pointing to GGTT to be shifted.
- */
-void xe_gt_sriov_vf_fixup_ggtt_nodes(struct xe_gt *gt, s64 shift)
-{
-       struct xe_tile *tile = gt_to_tile(gt);
-       struct xe_ggtt *ggtt = tile->mem.ggtt;
-
-       xe_gt_assert(gt, !xe_gt_is_media_type(gt));
-
-       mutex_lock(&ggtt->lock);
-       xe_gt_sriov_vf_deballoon_ggtt_locked(gt);
-       xe_ggtt_shift_nodes_locked(ggtt, shift);
-       xe_gt_sriov_vf_balloon_ggtt_locked(gt);
-       mutex_unlock(&ggtt->lock);
-}
-
 /**
  * xe_gt_sriov_vf_migrated_event_handler - Start a VF migration recovery,
  *   or just mark that a GuC is ready for it.
index 2f96ac0c5dcaf279ce1c45b7f3d8379438249b29..6250fe774d89a3436130293849defbdccb1f1321 100644 (file)
@@ -17,10 +17,6 @@ int xe_gt_sriov_vf_bootstrap(struct xe_gt *gt);
 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);
-int xe_gt_sriov_vf_balloon_ggtt_locked(struct xe_gt *gt);
-void xe_gt_sriov_vf_deballoon_ggtt_locked(struct xe_gt *gt);
-void xe_gt_sriov_vf_fixup_ggtt_nodes(struct xe_gt *gt, s64 shift);
 int xe_gt_sriov_vf_notify_resfix_done(struct xe_gt *gt);
 void xe_gt_sriov_vf_migrated_event_handler(struct xe_gt *gt);
 
index 46466932375c2748fc3c686809ebd3f2272c5587..6526fe450e553d143ab7cf42636005be7e7aaf1e 100644 (file)
@@ -15,6 +15,7 @@
 #include "xe_sriov.h"
 #include "xe_sriov_printk.h"
 #include "xe_sriov_vf.h"
+#include "xe_tile_sriov_vf.h"
 
 /**
  * DOC: VF restore procedure in PF KMD and VF KMD
@@ -211,7 +212,7 @@ static bool vf_post_migration_fixup_ggtt_nodes(struct xe_device *xe)
                shift = xe_gt_sriov_vf_ggtt_shift(gt);
                if (shift) {
                        need_fixups = true;
-                       xe_gt_sriov_vf_fixup_ggtt_nodes(gt, shift);
+                       xe_tile_sriov_vf_fixup_ggtt_nodes(tile, shift);
                }
        }
        return need_fixups;
diff --git a/drivers/gpu/drm/xe/xe_tile_sriov_vf.c b/drivers/gpu/drm/xe/xe_tile_sriov_vf.c
new file mode 100644 (file)
index 0000000..88e8328
--- /dev/null
@@ -0,0 +1,245 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2025 Intel Corporation
+ */
+
+#include <drm/drm_managed.h>
+
+#include "regs/xe_gtt_defs.h"
+
+#include "xe_assert.h"
+#include "xe_ggtt.h"
+#include "xe_gt_sriov_vf.h"
+#include "xe_sriov.h"
+#include "xe_tile_sriov_vf.h"
+#include "xe_wopcm.h"
+
+static int vf_init_ggtt_balloons(struct xe_tile *tile)
+{
+       struct xe_ggtt *ggtt = tile->mem.ggtt;
+
+       xe_tile_assert(tile, IS_SRIOV_VF(tile_to_xe(tile)));
+
+       tile->sriov.vf.ggtt_balloon[0] = xe_ggtt_node_init(ggtt);
+       if (IS_ERR(tile->sriov.vf.ggtt_balloon[0]))
+               return PTR_ERR(tile->sriov.vf.ggtt_balloon[0]);
+
+       tile->sriov.vf.ggtt_balloon[1] = xe_ggtt_node_init(ggtt);
+       if (IS_ERR(tile->sriov.vf.ggtt_balloon[1])) {
+               xe_ggtt_node_fini(tile->sriov.vf.ggtt_balloon[0]);
+               return PTR_ERR(tile->sriov.vf.ggtt_balloon[1]);
+       }
+
+       return 0;
+}
+
+/**
+ * xe_tile_sriov_vf_balloon_ggtt_locked - Insert balloon nodes to limit used GGTT address range.
+ * @tile: the &xe_tile struct instance
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int xe_tile_sriov_vf_balloon_ggtt_locked(struct xe_tile *tile)
+{
+       u64 ggtt_base = xe_gt_sriov_vf_ggtt_base(tile->primary_gt);
+       u64 ggtt_size = xe_gt_sriov_vf_ggtt(tile->primary_gt);
+       struct xe_device *xe = tile_to_xe(tile);
+       u64 start, end;
+       int err;
+
+       xe_tile_assert(tile, IS_SRIOV_VF(xe));
+       xe_tile_assert(tile, ggtt_size);
+       lockdep_assert_held(&tile->mem.ggtt->lock);
+
+       /*
+        * VF can only use part of the GGTT as allocated by the PF:
+        *
+        *      WOPCM                                  GUC_GGTT_TOP
+        *      |<------------ Total GGTT size ------------------>|
+        *
+        *           VF GGTT base -->|<- size ->|
+        *
+        *      +--------------------+----------+-----------------+
+        *      |////////////////////|   block  |\\\\\\\\\\\\\\\\\|
+        *      +--------------------+----------+-----------------+
+        *
+        *      |<--- balloon[0] --->|<-- VF -->|<-- balloon[1] ->|
+        */
+
+       start = xe_wopcm_size(xe);
+       end = ggtt_base;
+       if (end != start) {
+               err = xe_ggtt_node_insert_balloon_locked(tile->sriov.vf.ggtt_balloon[0],
+                                                        start, end);
+               if (err)
+                       return err;
+       }
+
+       start = ggtt_base + ggtt_size;
+       end = GUC_GGTT_TOP;
+       if (end != start) {
+               err = xe_ggtt_node_insert_balloon_locked(tile->sriov.vf.ggtt_balloon[1],
+                                                        start, end);
+               if (err) {
+                       xe_ggtt_node_remove_balloon_locked(tile->sriov.vf.ggtt_balloon[0]);
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+static int vf_balloon_ggtt(struct xe_tile *tile)
+{
+       struct xe_ggtt *ggtt = tile->mem.ggtt;
+       int err;
+
+       mutex_lock(&ggtt->lock);
+       err = xe_tile_sriov_vf_balloon_ggtt_locked(tile);
+       mutex_unlock(&ggtt->lock);
+
+       return err;
+}
+
+/**
+ * xe_tile_sriov_vf_deballoon_ggtt_locked - Remove balloon nodes.
+ * @tile: the &xe_tile struct instance
+ */
+void xe_tile_sriov_vf_deballoon_ggtt_locked(struct xe_tile *tile)
+{
+       xe_tile_assert(tile, IS_SRIOV_VF(tile_to_xe(tile)));
+
+       xe_ggtt_node_remove_balloon_locked(tile->sriov.vf.ggtt_balloon[1]);
+       xe_ggtt_node_remove_balloon_locked(tile->sriov.vf.ggtt_balloon[0]);
+}
+
+static void vf_deballoon_ggtt(struct xe_tile *tile)
+{
+       mutex_lock(&tile->mem.ggtt->lock);
+       xe_tile_sriov_vf_deballoon_ggtt_locked(tile);
+       mutex_unlock(&tile->mem.ggtt->lock);
+}
+
+static void vf_fini_ggtt_balloons(struct xe_tile *tile)
+{
+       xe_tile_assert(tile, IS_SRIOV_VF(tile_to_xe(tile)));
+
+       xe_ggtt_node_fini(tile->sriov.vf.ggtt_balloon[1]);
+       xe_ggtt_node_fini(tile->sriov.vf.ggtt_balloon[0]);
+}
+
+static void cleanup_ggtt(struct drm_device *drm, void *arg)
+{
+       struct xe_tile *tile = arg;
+
+       vf_deballoon_ggtt(tile);
+       vf_fini_ggtt_balloons(tile);
+}
+
+/**
+ * xe_tile_sriov_vf_prepare_ggtt - Prepare a VF's GGTT configuration.
+ * @tile: the &xe_tile
+ *
+ * This function is for VF use only.
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int xe_tile_sriov_vf_prepare_ggtt(struct xe_tile *tile)
+{
+       struct xe_device *xe = tile_to_xe(tile);
+       int err;
+
+       err = vf_init_ggtt_balloons(tile);
+       if (err)
+               return err;
+
+       err = vf_balloon_ggtt(tile);
+       if (err) {
+               vf_fini_ggtt_balloons(tile);
+               return err;
+       }
+
+       return drmm_add_action_or_reset(&xe->drm, cleanup_ggtt, tile);
+}
+
+/**
+ * DOC: GGTT nodes shifting during VF post-migration recovery
+ *
+ * The first fixup applied to the VF KMD structures as part of post-migration
+ * recovery is shifting nodes within &xe_ggtt instance. The nodes are moved
+ * from range previously assigned to this VF, into newly provisioned area.
+ * The changes include balloons, which are resized accordingly.
+ *
+ * The balloon nodes are there to eliminate unavailable ranges from use: one
+ * reserves the GGTT area below the range for current VF, and another one
+ * reserves area above.
+ *
+ * Below is a GGTT layout of example VF, with a certain address range assigned to
+ * said VF, and inaccessible areas above and below:
+ *
+ *  0                                                                        4GiB
+ *  |<--------------------------- Total GGTT size ----------------------------->|
+ *      WOPCM                                                         GUC_TOP
+ *      |<-------------- Area mappable by xe_ggtt instance ---------------->|
+ *
+ *  +---+---------------------------------+----------+----------------------+---+
+ *  |\\\|/////////////////////////////////|  VF mem  |//////////////////////|\\\|
+ *  +---+---------------------------------+----------+----------------------+---+
+ *
+ * Hardware enforced access rules before migration:
+ *
+ *  |<------- inaccessible for VF ------->|<VF owned>|<-- inaccessible for VF ->|
+ *
+ * GGTT nodes used for tracking allocations:
+ *
+ *      |<---------- balloon ------------>|<- nodes->|<----- balloon ------>|
+ *
+ * After the migration, GGTT area assigned to the VF might have shifted, either
+ * to lower or to higher address. But we expect the total size and extra areas to
+ * be identical, as migration can only happen between matching platforms.
+ * Below is an example of GGTT layout of the VF after migration. Content of the
+ * GGTT for VF has been moved to a new area, and we receive its address from GuC:
+ *
+ *  +---+----------------------+----------+---------------------------------+---+
+ *  |\\\|//////////////////////|  VF mem  |/////////////////////////////////|\\\|
+ *  +---+----------------------+----------+---------------------------------+---+
+ *
+ * Hardware enforced access rules after migration:
+ *
+ *  |<- inaccessible for VF -->|<VF owned>|<------- inaccessible for VF ------->|
+ *
+ * So the VF has a new slice of GGTT assigned, and during migration process, the
+ * memory content was copied to that new area. But the &xe_ggtt nodes are still
+ * tracking allocations using the old addresses. The nodes within VF owned area
+ * have to be shifted, and balloon nodes need to be resized to properly mask out
+ * areas not owned by the VF.
+ *
+ * Fixed &xe_ggtt nodes used for tracking allocations:
+ *
+ *     |<------ balloon ------>|<- nodes->|<----------- balloon ----------->|
+ *
+ * Due to use of GPU profiles, we do not expect the old and new GGTT ares to
+ * overlap; but our node shifting will fix addresses properly regardless.
+ */
+
+/**
+ * xe_tile_sriov_vf_fixup_ggtt_nodes - Shift GGTT allocations to match assigned range.
+ * @tile: the &xe_tile struct instance
+ * @shift: the shift value
+ *
+ * Since Global GTT is not virtualized, each VF has an assigned range
+ * within the global space. This range might have changed during migration,
+ * which requires all memory addresses pointing to GGTT to be shifted.
+ */
+void xe_tile_sriov_vf_fixup_ggtt_nodes(struct xe_tile *tile, s64 shift)
+{
+       struct xe_ggtt *ggtt = tile->mem.ggtt;
+
+       mutex_lock(&ggtt->lock);
+
+       xe_tile_sriov_vf_deballoon_ggtt_locked(tile);
+       xe_ggtt_shift_nodes_locked(ggtt, shift);
+       xe_tile_sriov_vf_balloon_ggtt_locked(tile);
+
+       mutex_unlock(&ggtt->lock);
+}
diff --git a/drivers/gpu/drm/xe/xe_tile_sriov_vf.h b/drivers/gpu/drm/xe/xe_tile_sriov_vf.h
new file mode 100644 (file)
index 0000000..93eb043
--- /dev/null
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2025 Intel Corporation
+ */
+
+#ifndef _XE_TILE_SRIOV_VF_H_
+#define _XE_TILE_SRIOV_VF_H_
+
+#include <linux/types.h>
+
+struct xe_tile;
+
+int xe_tile_sriov_vf_prepare_ggtt(struct xe_tile *tile);
+int xe_tile_sriov_vf_balloon_ggtt_locked(struct xe_tile *tile);
+void xe_tile_sriov_vf_deballoon_ggtt_locked(struct xe_tile *tile);
+void xe_tile_sriov_vf_fixup_ggtt_nodes(struct xe_tile *tile, s64 shift);
+
+#endif