[PATCH 2/3] drm/xe/vf: Move tile-related VF functions to separate file
Michal Wajdeczko
michal.wajdeczko at intel.com
Tue Jun 3 10:33:31 UTC 2025
On 03.06.2025 01:32, Lis, Tomasz wrote:
>
> On 02.06.2025 12:33, Michal Wajdeczko wrote:
>> 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 at intel.com>
>> Cc: Tomasz Lis <tomasz.lis at intel.com>
>
> No issues. We've switched the ballooning error from ENODATA to ENOSPC if
> ggtt_size is zero,
>
> but that was very hard to reach anyway since `vf_get_ggtt_info()`
> returns with ENODATA earlier.
yes, we are checking for zero ggtt_size in vf_get_ggtt_info() and we
shouldn't reach any further function if we didn't get any GGTT
that's why we have asserts elsewhere to enforce that
>
> Reviewed-by: Tomasz Lis <tomasz.lis at intel.com>
thanks!
>
> -Tomasz
>
>> ---
>> drivers/gpu/drm/xe/Makefile | 3 +-
>> drivers/gpu/drm/xe/xe_ggtt.c | 4 +-
>> drivers/gpu/drm/xe/xe_gt_sriov_vf.c | 245 --------------------------
>> drivers/gpu/drm/xe/xe_gt_sriov_vf.h | 4 -
>> drivers/gpu/drm/xe/xe_sriov_vf.c | 3 +-
>> drivers/gpu/drm/xe/xe_tile_sriov_vf.c | 245 ++++++++++++++++++++++++++
>> drivers/gpu/drm/xe/xe_tile_sriov_vf.h | 18 ++
>> 7 files changed, 269 insertions(+), 253 deletions(-)
>> create mode 100644 drivers/gpu/drm/xe/xe_tile_sriov_vf.c
>> create mode 100644 drivers/gpu/drm/xe/xe_tile_sriov_vf.h
>>
>> diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
>> index e4bf484d4121..f5f5775acdc0 100644
>> --- a/drivers/gpu/drm/xe/Makefile
>> +++ b/drivers/gpu/drm/xe/Makefile
>> @@ -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 \
>> diff --git a/drivers/gpu/drm/xe/xe_ggtt.c b/drivers/gpu/drm/xe/xe_ggtt.c
>> index af8e53014b87..b9a0fd5ccaba 100644
>> --- a/drivers/gpu/drm/xe/xe_ggtt.c
>> +++ b/drivers/gpu/drm/xe/xe_ggtt.c
>> @@ -22,12 +22,12 @@
>> #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;
>> }
>> diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_vf.c b/drivers/gpu/drm/xe/
>> xe_gt_sriov_vf.c
>> index acfb3b1b0832..792523cfa6e6 100644
>> --- a/drivers/gpu/drm/xe/xe_gt_sriov_vf.c
>> +++ b/drivers/gpu/drm/xe/xe_gt_sriov_vf.c
>> @@ -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 = >-
>> >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 @@ int xe_gt_sriov_vf_connect(struct xe_gt *gt)
>> 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.
>> diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_vf.h b/drivers/gpu/drm/xe/
>> xe_gt_sriov_vf.h
>> index 2f96ac0c5dca..6250fe774d89 100644
>> --- a/drivers/gpu/drm/xe/xe_gt_sriov_vf.h
>> +++ b/drivers/gpu/drm/xe/xe_gt_sriov_vf.h
>> @@ -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);
>> diff --git a/drivers/gpu/drm/xe/xe_sriov_vf.c b/drivers/gpu/drm/xe/
>> xe_sriov_vf.c
>> index 46466932375c..6526fe450e55 100644
>> --- a/drivers/gpu/drm/xe/xe_sriov_vf.c
>> +++ b/drivers/gpu/drm/xe/xe_sriov_vf.c
>> @@ -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
>> index 000000000000..88e832894432
>> --- /dev/null
>> +++ b/drivers/gpu/drm/xe/xe_tile_sriov_vf.c
>> @@ -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
>> index 000000000000..93eb043171e8
>> --- /dev/null
>> +++ b/drivers/gpu/drm/xe/xe_tile_sriov_vf.h
>> @@ -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
More information about the Intel-xe
mailing list