xref: /linux/drivers/gpu/drm/xe/xe_tile_sriov_vf.c (revision 8d2b0853add1d7534dc0794e3c8e0b9e8c4ec640)
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