1eb9b3473SMichal Wajdeczko // SPDX-License-Identifier: MIT 2eb9b3473SMichal Wajdeczko /* 3eb9b3473SMichal Wajdeczko * Copyright © 2025 Intel Corporation 4eb9b3473SMichal Wajdeczko */ 5eb9b3473SMichal Wajdeczko 6eb9b3473SMichal Wajdeczko #include <drm/drm_managed.h> 7eb9b3473SMichal Wajdeczko 8eb9b3473SMichal Wajdeczko #include "regs/xe_gtt_defs.h" 9eb9b3473SMichal Wajdeczko 10eb9b3473SMichal Wajdeczko #include "xe_assert.h" 11eb9b3473SMichal Wajdeczko #include "xe_ggtt.h" 12eb9b3473SMichal Wajdeczko #include "xe_gt_sriov_vf.h" 13eb9b3473SMichal Wajdeczko #include "xe_sriov.h" 14*c12c729eSMichal Wajdeczko #include "xe_sriov_printk.h" 15eb9b3473SMichal Wajdeczko #include "xe_tile_sriov_vf.h" 16eb9b3473SMichal Wajdeczko #include "xe_wopcm.h" 17eb9b3473SMichal Wajdeczko 18eb9b3473SMichal Wajdeczko static int vf_init_ggtt_balloons(struct xe_tile *tile) 19eb9b3473SMichal Wajdeczko { 20eb9b3473SMichal Wajdeczko struct xe_ggtt *ggtt = tile->mem.ggtt; 21eb9b3473SMichal Wajdeczko 22eb9b3473SMichal Wajdeczko xe_tile_assert(tile, IS_SRIOV_VF(tile_to_xe(tile))); 23eb9b3473SMichal Wajdeczko 24eb9b3473SMichal Wajdeczko tile->sriov.vf.ggtt_balloon[0] = xe_ggtt_node_init(ggtt); 25eb9b3473SMichal Wajdeczko if (IS_ERR(tile->sriov.vf.ggtt_balloon[0])) 26eb9b3473SMichal Wajdeczko return PTR_ERR(tile->sriov.vf.ggtt_balloon[0]); 27eb9b3473SMichal Wajdeczko 28eb9b3473SMichal Wajdeczko tile->sriov.vf.ggtt_balloon[1] = xe_ggtt_node_init(ggtt); 29eb9b3473SMichal Wajdeczko if (IS_ERR(tile->sriov.vf.ggtt_balloon[1])) { 30eb9b3473SMichal Wajdeczko xe_ggtt_node_fini(tile->sriov.vf.ggtt_balloon[0]); 31eb9b3473SMichal Wajdeczko return PTR_ERR(tile->sriov.vf.ggtt_balloon[1]); 32eb9b3473SMichal Wajdeczko } 33eb9b3473SMichal Wajdeczko 34eb9b3473SMichal Wajdeczko return 0; 35eb9b3473SMichal Wajdeczko } 36eb9b3473SMichal Wajdeczko 37eb9b3473SMichal Wajdeczko /** 38eb9b3473SMichal Wajdeczko * xe_tile_sriov_vf_balloon_ggtt_locked - Insert balloon nodes to limit used GGTT address range. 39eb9b3473SMichal Wajdeczko * @tile: the &xe_tile struct instance 40eb9b3473SMichal Wajdeczko * 41eb9b3473SMichal Wajdeczko * Return: 0 on success or a negative error code on failure. 42eb9b3473SMichal Wajdeczko */ 43eb9b3473SMichal Wajdeczko int xe_tile_sriov_vf_balloon_ggtt_locked(struct xe_tile *tile) 44eb9b3473SMichal Wajdeczko { 45eb9b3473SMichal Wajdeczko u64 ggtt_base = xe_gt_sriov_vf_ggtt_base(tile->primary_gt); 46eb9b3473SMichal Wajdeczko u64 ggtt_size = xe_gt_sriov_vf_ggtt(tile->primary_gt); 47eb9b3473SMichal Wajdeczko struct xe_device *xe = tile_to_xe(tile); 48*c12c729eSMichal Wajdeczko u64 wopcm = xe_wopcm_size(xe); 49eb9b3473SMichal Wajdeczko u64 start, end; 50eb9b3473SMichal Wajdeczko int err; 51eb9b3473SMichal Wajdeczko 52eb9b3473SMichal Wajdeczko xe_tile_assert(tile, IS_SRIOV_VF(xe)); 53eb9b3473SMichal Wajdeczko xe_tile_assert(tile, ggtt_size); 54eb9b3473SMichal Wajdeczko lockdep_assert_held(&tile->mem.ggtt->lock); 55eb9b3473SMichal Wajdeczko 56eb9b3473SMichal Wajdeczko /* 57eb9b3473SMichal Wajdeczko * VF can only use part of the GGTT as allocated by the PF: 58eb9b3473SMichal Wajdeczko * 59eb9b3473SMichal Wajdeczko * WOPCM GUC_GGTT_TOP 60eb9b3473SMichal Wajdeczko * |<------------ Total GGTT size ------------------>| 61eb9b3473SMichal Wajdeczko * 62eb9b3473SMichal Wajdeczko * VF GGTT base -->|<- size ->| 63eb9b3473SMichal Wajdeczko * 64eb9b3473SMichal Wajdeczko * +--------------------+----------+-----------------+ 65eb9b3473SMichal Wajdeczko * |////////////////////| block |\\\\\\\\\\\\\\\\\| 66eb9b3473SMichal Wajdeczko * +--------------------+----------+-----------------+ 67eb9b3473SMichal Wajdeczko * 68eb9b3473SMichal Wajdeczko * |<--- balloon[0] --->|<-- VF -->|<-- balloon[1] ->| 69eb9b3473SMichal Wajdeczko */ 70eb9b3473SMichal Wajdeczko 71*c12c729eSMichal Wajdeczko if (ggtt_base < wopcm || ggtt_base > GUC_GGTT_TOP || 72*c12c729eSMichal Wajdeczko ggtt_size > GUC_GGTT_TOP - ggtt_base) { 73*c12c729eSMichal Wajdeczko xe_sriov_err(xe, "tile%u: Invalid GGTT configuration: %#llx-%#llx\n", 74*c12c729eSMichal Wajdeczko tile->id, ggtt_base, ggtt_base + ggtt_size - 1); 75*c12c729eSMichal Wajdeczko return -ERANGE; 76*c12c729eSMichal Wajdeczko } 77*c12c729eSMichal Wajdeczko 78*c12c729eSMichal Wajdeczko start = wopcm; 79eb9b3473SMichal Wajdeczko end = ggtt_base; 80eb9b3473SMichal Wajdeczko if (end != start) { 81eb9b3473SMichal Wajdeczko err = xe_ggtt_node_insert_balloon_locked(tile->sriov.vf.ggtt_balloon[0], 82eb9b3473SMichal Wajdeczko start, end); 83eb9b3473SMichal Wajdeczko if (err) 84eb9b3473SMichal Wajdeczko return err; 85eb9b3473SMichal Wajdeczko } 86eb9b3473SMichal Wajdeczko 87eb9b3473SMichal Wajdeczko start = ggtt_base + ggtt_size; 88eb9b3473SMichal Wajdeczko end = GUC_GGTT_TOP; 89eb9b3473SMichal Wajdeczko if (end != start) { 90eb9b3473SMichal Wajdeczko err = xe_ggtt_node_insert_balloon_locked(tile->sriov.vf.ggtt_balloon[1], 91eb9b3473SMichal Wajdeczko start, end); 92eb9b3473SMichal Wajdeczko if (err) { 93eb9b3473SMichal Wajdeczko xe_ggtt_node_remove_balloon_locked(tile->sriov.vf.ggtt_balloon[0]); 94eb9b3473SMichal Wajdeczko return err; 95eb9b3473SMichal Wajdeczko } 96eb9b3473SMichal Wajdeczko } 97eb9b3473SMichal Wajdeczko 98eb9b3473SMichal Wajdeczko return 0; 99eb9b3473SMichal Wajdeczko } 100eb9b3473SMichal Wajdeczko 101eb9b3473SMichal Wajdeczko static int vf_balloon_ggtt(struct xe_tile *tile) 102eb9b3473SMichal Wajdeczko { 103eb9b3473SMichal Wajdeczko struct xe_ggtt *ggtt = tile->mem.ggtt; 104eb9b3473SMichal Wajdeczko int err; 105eb9b3473SMichal Wajdeczko 106eb9b3473SMichal Wajdeczko mutex_lock(&ggtt->lock); 107eb9b3473SMichal Wajdeczko err = xe_tile_sriov_vf_balloon_ggtt_locked(tile); 108eb9b3473SMichal Wajdeczko mutex_unlock(&ggtt->lock); 109eb9b3473SMichal Wajdeczko 110eb9b3473SMichal Wajdeczko return err; 111eb9b3473SMichal Wajdeczko } 112eb9b3473SMichal Wajdeczko 113eb9b3473SMichal Wajdeczko /** 114eb9b3473SMichal Wajdeczko * xe_tile_sriov_vf_deballoon_ggtt_locked - Remove balloon nodes. 115eb9b3473SMichal Wajdeczko * @tile: the &xe_tile struct instance 116eb9b3473SMichal Wajdeczko */ 117eb9b3473SMichal Wajdeczko void xe_tile_sriov_vf_deballoon_ggtt_locked(struct xe_tile *tile) 118eb9b3473SMichal Wajdeczko { 119eb9b3473SMichal Wajdeczko xe_tile_assert(tile, IS_SRIOV_VF(tile_to_xe(tile))); 120eb9b3473SMichal Wajdeczko 121eb9b3473SMichal Wajdeczko xe_ggtt_node_remove_balloon_locked(tile->sriov.vf.ggtt_balloon[1]); 122eb9b3473SMichal Wajdeczko xe_ggtt_node_remove_balloon_locked(tile->sriov.vf.ggtt_balloon[0]); 123eb9b3473SMichal Wajdeczko } 124eb9b3473SMichal Wajdeczko 125eb9b3473SMichal Wajdeczko static void vf_deballoon_ggtt(struct xe_tile *tile) 126eb9b3473SMichal Wajdeczko { 127eb9b3473SMichal Wajdeczko mutex_lock(&tile->mem.ggtt->lock); 128eb9b3473SMichal Wajdeczko xe_tile_sriov_vf_deballoon_ggtt_locked(tile); 129eb9b3473SMichal Wajdeczko mutex_unlock(&tile->mem.ggtt->lock); 130eb9b3473SMichal Wajdeczko } 131eb9b3473SMichal Wajdeczko 132eb9b3473SMichal Wajdeczko static void vf_fini_ggtt_balloons(struct xe_tile *tile) 133eb9b3473SMichal Wajdeczko { 134eb9b3473SMichal Wajdeczko xe_tile_assert(tile, IS_SRIOV_VF(tile_to_xe(tile))); 135eb9b3473SMichal Wajdeczko 136eb9b3473SMichal Wajdeczko xe_ggtt_node_fini(tile->sriov.vf.ggtt_balloon[1]); 137eb9b3473SMichal Wajdeczko xe_ggtt_node_fini(tile->sriov.vf.ggtt_balloon[0]); 138eb9b3473SMichal Wajdeczko } 139eb9b3473SMichal Wajdeczko 140eb9b3473SMichal Wajdeczko static void cleanup_ggtt(struct drm_device *drm, void *arg) 141eb9b3473SMichal Wajdeczko { 142eb9b3473SMichal Wajdeczko struct xe_tile *tile = arg; 143eb9b3473SMichal Wajdeczko 144eb9b3473SMichal Wajdeczko vf_deballoon_ggtt(tile); 145eb9b3473SMichal Wajdeczko vf_fini_ggtt_balloons(tile); 146eb9b3473SMichal Wajdeczko } 147eb9b3473SMichal Wajdeczko 148eb9b3473SMichal Wajdeczko /** 149eb9b3473SMichal Wajdeczko * xe_tile_sriov_vf_prepare_ggtt - Prepare a VF's GGTT configuration. 150eb9b3473SMichal Wajdeczko * @tile: the &xe_tile 151eb9b3473SMichal Wajdeczko * 152eb9b3473SMichal Wajdeczko * This function is for VF use only. 153eb9b3473SMichal Wajdeczko * 154eb9b3473SMichal Wajdeczko * Return: 0 on success or a negative error code on failure. 155eb9b3473SMichal Wajdeczko */ 156eb9b3473SMichal Wajdeczko int xe_tile_sriov_vf_prepare_ggtt(struct xe_tile *tile) 157eb9b3473SMichal Wajdeczko { 158eb9b3473SMichal Wajdeczko struct xe_device *xe = tile_to_xe(tile); 159eb9b3473SMichal Wajdeczko int err; 160eb9b3473SMichal Wajdeczko 161eb9b3473SMichal Wajdeczko err = vf_init_ggtt_balloons(tile); 162eb9b3473SMichal Wajdeczko if (err) 163eb9b3473SMichal Wajdeczko return err; 164eb9b3473SMichal Wajdeczko 165eb9b3473SMichal Wajdeczko err = vf_balloon_ggtt(tile); 166eb9b3473SMichal Wajdeczko if (err) { 167eb9b3473SMichal Wajdeczko vf_fini_ggtt_balloons(tile); 168eb9b3473SMichal Wajdeczko return err; 169eb9b3473SMichal Wajdeczko } 170eb9b3473SMichal Wajdeczko 171eb9b3473SMichal Wajdeczko return drmm_add_action_or_reset(&xe->drm, cleanup_ggtt, tile); 172eb9b3473SMichal Wajdeczko } 173eb9b3473SMichal Wajdeczko 174eb9b3473SMichal Wajdeczko /** 175eb9b3473SMichal Wajdeczko * DOC: GGTT nodes shifting during VF post-migration recovery 176eb9b3473SMichal Wajdeczko * 177eb9b3473SMichal Wajdeczko * The first fixup applied to the VF KMD structures as part of post-migration 178eb9b3473SMichal Wajdeczko * recovery is shifting nodes within &xe_ggtt instance. The nodes are moved 179eb9b3473SMichal Wajdeczko * from range previously assigned to this VF, into newly provisioned area. 180eb9b3473SMichal Wajdeczko * The changes include balloons, which are resized accordingly. 181eb9b3473SMichal Wajdeczko * 182eb9b3473SMichal Wajdeczko * The balloon nodes are there to eliminate unavailable ranges from use: one 183eb9b3473SMichal Wajdeczko * reserves the GGTT area below the range for current VF, and another one 184eb9b3473SMichal Wajdeczko * reserves area above. 185eb9b3473SMichal Wajdeczko * 186eb9b3473SMichal Wajdeczko * Below is a GGTT layout of example VF, with a certain address range assigned to 187eb9b3473SMichal Wajdeczko * said VF, and inaccessible areas above and below: 188eb9b3473SMichal Wajdeczko * 189eb9b3473SMichal Wajdeczko * 0 4GiB 190eb9b3473SMichal Wajdeczko * |<--------------------------- Total GGTT size ----------------------------->| 191eb9b3473SMichal Wajdeczko * WOPCM GUC_TOP 192eb9b3473SMichal Wajdeczko * |<-------------- Area mappable by xe_ggtt instance ---------------->| 193eb9b3473SMichal Wajdeczko * 194eb9b3473SMichal Wajdeczko * +---+---------------------------------+----------+----------------------+---+ 195eb9b3473SMichal Wajdeczko * |\\\|/////////////////////////////////| VF mem |//////////////////////|\\\| 196eb9b3473SMichal Wajdeczko * +---+---------------------------------+----------+----------------------+---+ 197eb9b3473SMichal Wajdeczko * 198eb9b3473SMichal Wajdeczko * Hardware enforced access rules before migration: 199eb9b3473SMichal Wajdeczko * 200eb9b3473SMichal Wajdeczko * |<------- inaccessible for VF ------->|<VF owned>|<-- inaccessible for VF ->| 201eb9b3473SMichal Wajdeczko * 202eb9b3473SMichal Wajdeczko * GGTT nodes used for tracking allocations: 203eb9b3473SMichal Wajdeczko * 204eb9b3473SMichal Wajdeczko * |<---------- balloon ------------>|<- nodes->|<----- balloon ------>| 205eb9b3473SMichal Wajdeczko * 206eb9b3473SMichal Wajdeczko * After the migration, GGTT area assigned to the VF might have shifted, either 207eb9b3473SMichal Wajdeczko * to lower or to higher address. But we expect the total size and extra areas to 208eb9b3473SMichal Wajdeczko * be identical, as migration can only happen between matching platforms. 209eb9b3473SMichal Wajdeczko * Below is an example of GGTT layout of the VF after migration. Content of the 210eb9b3473SMichal Wajdeczko * GGTT for VF has been moved to a new area, and we receive its address from GuC: 211eb9b3473SMichal Wajdeczko * 212eb9b3473SMichal Wajdeczko * +---+----------------------+----------+---------------------------------+---+ 213eb9b3473SMichal Wajdeczko * |\\\|//////////////////////| VF mem |/////////////////////////////////|\\\| 214eb9b3473SMichal Wajdeczko * +---+----------------------+----------+---------------------------------+---+ 215eb9b3473SMichal Wajdeczko * 216eb9b3473SMichal Wajdeczko * Hardware enforced access rules after migration: 217eb9b3473SMichal Wajdeczko * 218eb9b3473SMichal Wajdeczko * |<- inaccessible for VF -->|<VF owned>|<------- inaccessible for VF ------->| 219eb9b3473SMichal Wajdeczko * 220eb9b3473SMichal Wajdeczko * So the VF has a new slice of GGTT assigned, and during migration process, the 221eb9b3473SMichal Wajdeczko * memory content was copied to that new area. But the &xe_ggtt nodes are still 222eb9b3473SMichal Wajdeczko * tracking allocations using the old addresses. The nodes within VF owned area 223eb9b3473SMichal Wajdeczko * have to be shifted, and balloon nodes need to be resized to properly mask out 224eb9b3473SMichal Wajdeczko * areas not owned by the VF. 225eb9b3473SMichal Wajdeczko * 226eb9b3473SMichal Wajdeczko * Fixed &xe_ggtt nodes used for tracking allocations: 227eb9b3473SMichal Wajdeczko * 228eb9b3473SMichal Wajdeczko * |<------ balloon ------>|<- nodes->|<----------- balloon ----------->| 229eb9b3473SMichal Wajdeczko * 230eb9b3473SMichal Wajdeczko * Due to use of GPU profiles, we do not expect the old and new GGTT ares to 231eb9b3473SMichal Wajdeczko * overlap; but our node shifting will fix addresses properly regardless. 232eb9b3473SMichal Wajdeczko */ 233eb9b3473SMichal Wajdeczko 234eb9b3473SMichal Wajdeczko /** 235eb9b3473SMichal Wajdeczko * xe_tile_sriov_vf_fixup_ggtt_nodes - Shift GGTT allocations to match assigned range. 236eb9b3473SMichal Wajdeczko * @tile: the &xe_tile struct instance 237eb9b3473SMichal Wajdeczko * @shift: the shift value 238eb9b3473SMichal Wajdeczko * 239eb9b3473SMichal Wajdeczko * Since Global GTT is not virtualized, each VF has an assigned range 240eb9b3473SMichal Wajdeczko * within the global space. This range might have changed during migration, 241eb9b3473SMichal Wajdeczko * which requires all memory addresses pointing to GGTT to be shifted. 242eb9b3473SMichal Wajdeczko */ 243eb9b3473SMichal Wajdeczko void xe_tile_sriov_vf_fixup_ggtt_nodes(struct xe_tile *tile, s64 shift) 244eb9b3473SMichal Wajdeczko { 245eb9b3473SMichal Wajdeczko struct xe_ggtt *ggtt = tile->mem.ggtt; 246eb9b3473SMichal Wajdeczko 247eb9b3473SMichal Wajdeczko mutex_lock(&ggtt->lock); 248eb9b3473SMichal Wajdeczko 249eb9b3473SMichal Wajdeczko xe_tile_sriov_vf_deballoon_ggtt_locked(tile); 250eb9b3473SMichal Wajdeczko xe_ggtt_shift_nodes_locked(ggtt, shift); 251eb9b3473SMichal Wajdeczko xe_tile_sriov_vf_balloon_ggtt_locked(tile); 252eb9b3473SMichal Wajdeczko 253eb9b3473SMichal Wajdeczko mutex_unlock(&ggtt->lock); 254eb9b3473SMichal Wajdeczko } 255