xref: /linux/drivers/gpu/drm/xe/xe_sriov_vf_ccs.c (revision face6a3615a649456eb4549f6d474221d877d604)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2025 Intel Corporation
4  */
5 
6 #include "instructions/xe_mi_commands.h"
7 #include "instructions/xe_gpu_commands.h"
8 #include "xe_bb.h"
9 #include "xe_bo.h"
10 #include "xe_device.h"
11 #include "xe_exec_queue.h"
12 #include "xe_exec_queue_types.h"
13 #include "xe_gt_sriov_vf.h"
14 #include "xe_guc.h"
15 #include "xe_guc_submit.h"
16 #include "xe_lrc.h"
17 #include "xe_migrate.h"
18 #include "xe_pm.h"
19 #include "xe_sa.h"
20 #include "xe_sriov_printk.h"
21 #include "xe_sriov_vf.h"
22 #include "xe_sriov_vf_ccs.h"
23 #include "xe_sriov_vf_ccs_types.h"
24 
25 /**
26  * DOC: VF save/restore of compression Meta Data
27  *
28  * VF KMD registers two special contexts/LRCAs.
29  *
30  * Save Context/LRCA: contain necessary cmds+page table to trigger Meta data /
31  * compression control surface (Aka CCS) save in regular System memory in VM.
32  *
33  * Restore Context/LRCA: contain necessary cmds+page table to trigger Meta data /
34  * compression control surface (Aka CCS) Restore from regular System memory in
35  * VM to corresponding CCS pool.
36  *
37  * Below diagram explain steps needed for VF save/Restore of compression Meta Data::
38  *
39  *    CCS Save    CCS Restore          VF KMD                          Guc       BCS
40  *     LRCA        LRCA
41  *      |           |                     |                              |         |
42  *      |           |                     |                              |         |
43  *      |     Create Save LRCA            |                              |         |
44  *     [ ]<----------------------------- [ ]                             |         |
45  *      |           |                     |                              |         |
46  *      |           |                     |                              |         |
47  *      |           |                     |       Register save LRCA     |         |
48  *      |           |                     |           with Guc           |         |
49  *      |           |                    [ ]--------------------------->[ ]        |
50  *      |           |                     |                              |         |
51  *      |           | Create restore LRCA |                              |         |
52  *      |          [ ]<------------------[ ]                             |         |
53  *      |           |                     |                              |         |
54  *      |           |                     |       Register restore LRCA  |         |
55  *      |           |                     |           with Guc           |         |
56  *      |           |                    [ ]--------------------------->[ ]        |
57  *      |           |                     |                              |         |
58  *      |           |                     |                              |         |
59  *      |           |                    [ ]-------------------------    |         |
60  *      |           |                    [ ]  Allocate main memory.  |   |         |
61  *      |           |                    [ ]  Allocate CCS memory.   |   |         |
62  *      |           |                    [ ]  Update Main memory &   |   |         |
63  *     [ ]<------------------------------[ ]  CCS pages PPGTT + BB   |   |         |
64  *      |          [ ]<------------------[ ]  cmds to save & restore.|   |         |
65  *      |           |                    [ ]<------------------------    |         |
66  *      |           |                     |                              |         |
67  *      |           |                     |                              |         |
68  *      |           |                     |                              |         |
69  *      :           :                     :                              :         :
70  *      ---------------------------- VF Paused -------------------------------------
71  *      |           |                     |                              |         |
72  *      |           |                     |                              |         |
73  *      |           |                     |                              |Schedule |
74  *      |           |                     |                              |CCS Save |
75  *      |           |                     |                              | LRCA    |
76  *      |           |                     |                             [ ]------>[ ]
77  *      |           |                     |                              |         |
78  *      |           |                     |                              |         |
79  *      |           |                     |                              |CCS save |
80  *      |           |                     |                              |completed|
81  *      |           |                     |                             [ ]<------[ ]
82  *      |           |                     |                              |         |
83  *      :           :                     :                              :         :
84  *      ---------------------------- VM Migrated -----------------------------------
85  *      |           |                     |                              |         |
86  *      |           |                     |                              |         |
87  *      :           :                     :                              :         :
88  *      ---------------------------- VF Resumed ------------------------------------
89  *      |           |                     |                              |         |
90  *      |           |                     |                              |         |
91  *      |           |                    [ ]--------------               |         |
92  *      |           |                    [ ] Fix up GGTT  |              |         |
93  *      |           |                    [ ]<-------------               |         |
94  *      |           |                     |                              |         |
95  *      |           |                     |                              |         |
96  *      |           |                     |  Notify VF_RESFIX_DONE       |         |
97  *      |           |                    [ ]--------------------------->[ ]        |
98  *      |           |                     |                              |         |
99  *      |           |                     |                              |Schedule |
100  *      |           |                     |                              |CCS      |
101  *      |           |                     |                              |Restore  |
102  *      |           |                     |                              |LRCA     |
103  *      |           |                     |                             [ ]------>[ ]
104  *      |           |                     |                              |         |
105  *      |           |                     |                              |         |
106  *      |           |                     |                              |CCS      |
107  *      |           |                     |                              |restore  |
108  *      |           |                     |                              |completed|
109  *      |           |                     |                             [ ]<------[ ]
110  *      |           |                     |                              |         |
111  *      |           |                     |                              |         |
112  *      |           |                     |  VF_RESFIX_DONE complete     |         |
113  *      |           |                     |       notification           |         |
114  *      |           |                    [ ]<---------------------------[ ]        |
115  *      |           |                     |                              |         |
116  *      |           |                     |                              |         |
117  *      :           :                     :                              :         :
118  *      ------------------------- Continue VM restore ------------------------------
119  */
120 
121 static u64 get_ccs_bb_pool_size(struct xe_device *xe)
122 {
123 	u64 sys_mem_size, ccs_mem_size, ptes, bb_pool_size;
124 	struct sysinfo si;
125 
126 	si_meminfo(&si);
127 	sys_mem_size = si.totalram * si.mem_unit;
128 	ccs_mem_size = div64_u64(sys_mem_size, NUM_BYTES_PER_CCS_BYTE(xe));
129 	ptes = DIV_ROUND_UP_ULL(sys_mem_size + ccs_mem_size, XE_PAGE_SIZE);
130 
131 	/**
132 	 * We need below BB size to hold PTE mappings and some DWs for copy
133 	 * command. In reality, we need space for many copy commands. So, let
134 	 * us allocate double the calculated size which is enough to holds GPU
135 	 * instructions for the whole region.
136 	 */
137 	bb_pool_size = ptes * sizeof(u32);
138 
139 	return round_up(bb_pool_size * 2, SZ_1M);
140 }
141 
142 static int alloc_bb_pool(struct xe_tile *tile, struct xe_sriov_vf_ccs_ctx *ctx)
143 {
144 	struct xe_device *xe = tile_to_xe(tile);
145 	struct xe_sa_manager *sa_manager;
146 	u64 bb_pool_size;
147 	int offset, err;
148 
149 	bb_pool_size = get_ccs_bb_pool_size(xe);
150 	xe_sriov_info(xe, "Allocating %s CCS BB pool size = %lldMB\n",
151 		      ctx->ctx_id ? "Restore" : "Save", bb_pool_size / SZ_1M);
152 
153 	sa_manager = xe_sa_bo_manager_init(tile, bb_pool_size, SZ_16);
154 
155 	if (IS_ERR(sa_manager)) {
156 		xe_sriov_err(xe, "Suballocator init failed with error: %pe\n",
157 			     sa_manager);
158 		err = PTR_ERR(sa_manager);
159 		return err;
160 	}
161 
162 	offset = 0;
163 	xe_map_memset(xe, &sa_manager->bo->vmap, offset, MI_NOOP,
164 		      bb_pool_size);
165 
166 	offset = bb_pool_size - sizeof(u32);
167 	xe_map_wr(xe, &sa_manager->bo->vmap, offset, u32, MI_BATCH_BUFFER_END);
168 
169 	ctx->mem.ccs_bb_pool = sa_manager;
170 
171 	return 0;
172 }
173 
174 static void ccs_rw_update_ring(struct xe_sriov_vf_ccs_ctx *ctx)
175 {
176 	u64 addr = xe_sa_manager_gpu_addr(ctx->mem.ccs_bb_pool);
177 	struct xe_lrc *lrc = xe_exec_queue_lrc(ctx->mig_q);
178 	u32 dw[10], i = 0;
179 
180 	/*
181 	 * XXX: Save/restore fixes — for some reason, the GuC only accepts the
182 	 * save/restore context if the LRC head pointer is zero. This is evident
183 	 * from repeated VF migrations failing when the LRC head pointer is
184 	 * non-zero.
185 	 */
186 	lrc->ring.tail = 0;
187 	xe_lrc_set_ring_head(lrc, 0);
188 
189 	dw[i++] = MI_ARB_ON_OFF | MI_ARB_ENABLE;
190 	dw[i++] = MI_BATCH_BUFFER_START | XE_INSTR_NUM_DW(3);
191 	dw[i++] = lower_32_bits(addr);
192 	dw[i++] = upper_32_bits(addr);
193 	dw[i++] = MI_NOOP;
194 	dw[i++] = MI_NOOP;
195 
196 	xe_lrc_write_ring(lrc, dw, i * sizeof(u32));
197 	xe_lrc_set_ring_tail(lrc, lrc->ring.tail);
198 }
199 
200 /**
201  * xe_sriov_vf_ccs_rebase - Rebase GGTT addresses for CCS save / restore
202  * @xe: the &xe_device.
203  */
204 void xe_sriov_vf_ccs_rebase(struct xe_device *xe)
205 {
206 	enum xe_sriov_vf_ccs_rw_ctxs ctx_id;
207 
208 	if (!IS_VF_CCS_READY(xe))
209 		return;
210 
211 	for_each_ccs_rw_ctx(ctx_id) {
212 		struct xe_sriov_vf_ccs_ctx *ctx =
213 			&xe->sriov.vf.ccs.contexts[ctx_id];
214 
215 		ccs_rw_update_ring(ctx);
216 	}
217 }
218 
219 static int register_save_restore_context(struct xe_sriov_vf_ccs_ctx *ctx)
220 {
221 	int ctx_type;
222 
223 	switch (ctx->ctx_id) {
224 	case XE_SRIOV_VF_CCS_READ_CTX:
225 		ctx_type = GUC_CONTEXT_COMPRESSION_SAVE;
226 		break;
227 	case XE_SRIOV_VF_CCS_WRITE_CTX:
228 		ctx_type = GUC_CONTEXT_COMPRESSION_RESTORE;
229 		break;
230 	default:
231 		return -EINVAL;
232 	}
233 
234 	xe_guc_register_vf_exec_queue(ctx->mig_q, ctx_type);
235 	return 0;
236 }
237 
238 /**
239  * xe_sriov_vf_ccs_register_context - Register read/write contexts with guc.
240  * @xe: the &xe_device to register contexts on.
241  *
242  * This function registers read and write contexts with Guc. Re-registration
243  * is needed whenever resuming from pm runtime suspend.
244  *
245  * Return: 0 on success. Negative error code on failure.
246  */
247 int xe_sriov_vf_ccs_register_context(struct xe_device *xe)
248 {
249 	enum xe_sriov_vf_ccs_rw_ctxs ctx_id;
250 	struct xe_sriov_vf_ccs_ctx *ctx;
251 	int err;
252 
253 	xe_assert(xe, IS_VF_CCS_READY(xe));
254 
255 	for_each_ccs_rw_ctx(ctx_id) {
256 		ctx = &xe->sriov.vf.ccs.contexts[ctx_id];
257 		err = register_save_restore_context(ctx);
258 		if (err)
259 			return err;
260 	}
261 
262 	return err;
263 }
264 
265 /*
266  * Whether GuC requires CCS copy BBs for VF migration.
267  * @xe: the &xe_device instance.
268  *
269  * Only selected platforms require VF KMD to maintain CCS copy BBs and linked LRCAs.
270  *
271  * Return: true if VF driver must participate in the CCS migration, false otherwise.
272  */
273 static bool vf_migration_ccs_bb_needed(struct xe_device *xe)
274 {
275 	xe_assert(xe, IS_SRIOV_VF(xe));
276 
277 	return !IS_DGFX(xe) && xe_device_has_flat_ccs(xe);
278 }
279 
280 /*
281  * Check for disable migration due to no CCS BBs support in GuC FW.
282  * @xe: the &xe_device instance.
283  *
284  * Performs late disable of VF migration feature in case GuC FW cannot support it.
285  *
286  * Returns: True if VF migration with CCS BBs is supported, false otherwise.
287  */
288 static bool vf_migration_ccs_bb_support_check(struct xe_device *xe)
289 {
290 	struct xe_gt *gt = xe_root_mmio_gt(xe);
291 	struct xe_uc_fw_version guc_version;
292 
293 	xe_gt_sriov_vf_guc_versions(gt, NULL, &guc_version);
294 	if (MAKE_GUC_VER_STRUCT(guc_version) < MAKE_GUC_VER(1, 23, 0)) {
295 		xe_sriov_vf_migration_disable(xe,
296 					      "CCS migration requires GuC ABI >= 1.23 but only %u.%u found",
297 					      guc_version.major, guc_version.minor);
298 		return false;
299 	}
300 
301 	return true;
302 }
303 
304 static void xe_sriov_vf_ccs_fini(void *arg)
305 {
306 	struct xe_sriov_vf_ccs_ctx *ctx = arg;
307 	struct xe_lrc *lrc = xe_exec_queue_lrc(ctx->mig_q);
308 
309 	/*
310 	 * Make TAIL = HEAD in the ring so that no issues are seen if Guc
311 	 * submits this context to HW on VF pause after unbinding device.
312 	 */
313 	xe_lrc_set_ring_tail(lrc, xe_lrc_ring_head(lrc));
314 	xe_exec_queue_put(ctx->mig_q);
315 }
316 
317 /**
318  * xe_sriov_vf_ccs_init - Setup LRCA for save & restore.
319  * @xe: the &xe_device to start recovery on
320  *
321  * This function shall be called only by VF. It initializes
322  * LRCA and suballocator needed for CCS save & restore.
323  *
324  * Return: 0 on success. Negative error code on failure.
325  */
326 int xe_sriov_vf_ccs_init(struct xe_device *xe)
327 {
328 	struct xe_tile *tile = xe_device_get_root_tile(xe);
329 	enum xe_sriov_vf_ccs_rw_ctxs ctx_id;
330 	struct xe_sriov_vf_ccs_ctx *ctx;
331 	struct xe_exec_queue *q;
332 	u32 flags;
333 	int err;
334 
335 	xe_assert(xe, IS_SRIOV_VF(xe));
336 
337 	if (!xe_sriov_vf_migration_supported(xe) ||
338 	    !vf_migration_ccs_bb_needed(xe) ||
339 	    !vf_migration_ccs_bb_support_check(xe))
340 		return 0;
341 
342 	for_each_ccs_rw_ctx(ctx_id) {
343 		ctx = &xe->sriov.vf.ccs.contexts[ctx_id];
344 		ctx->ctx_id = ctx_id;
345 
346 		flags = EXEC_QUEUE_FLAG_KERNEL |
347 			EXEC_QUEUE_FLAG_PERMANENT |
348 			EXEC_QUEUE_FLAG_MIGRATE;
349 		q = xe_exec_queue_create_bind(xe, tile, flags, 0);
350 		if (IS_ERR(q)) {
351 			err = PTR_ERR(q);
352 			goto err_ret;
353 		}
354 		ctx->mig_q = q;
355 
356 		err = alloc_bb_pool(tile, ctx);
357 		if (err)
358 			goto err_free_queue;
359 
360 		ccs_rw_update_ring(ctx);
361 
362 		err = register_save_restore_context(ctx);
363 		if (err)
364 			goto err_free_queue;
365 
366 		err = devm_add_action_or_reset(xe->drm.dev,
367 					       xe_sriov_vf_ccs_fini,
368 					       ctx);
369 		if (err)
370 			goto err_ret;
371 	}
372 
373 	xe->sriov.vf.ccs.initialized = 1;
374 
375 	return 0;
376 
377 err_free_queue:
378 	xe_exec_queue_put(q);
379 
380 err_ret:
381 	return err;
382 }
383 
384 /**
385  * xe_sriov_vf_ccs_attach_bo - Insert CCS read write commands in the BO.
386  * @bo: the &buffer object to which batch buffer commands will be added.
387  *
388  * This function shall be called only by VF. It inserts the PTEs and copy
389  * command instructions in the BO by calling xe_migrate_ccs_rw_copy()
390  * function.
391  *
392  * Returns: 0 if successful, negative error code on failure.
393  */
394 int xe_sriov_vf_ccs_attach_bo(struct xe_bo *bo)
395 {
396 	struct xe_device *xe = xe_bo_device(bo);
397 	enum xe_sriov_vf_ccs_rw_ctxs ctx_id;
398 	struct xe_sriov_vf_ccs_ctx *ctx;
399 	struct xe_tile *tile;
400 	struct xe_bb *bb;
401 	int err = 0;
402 
403 	xe_assert(xe, IS_VF_CCS_READY(xe));
404 
405 	tile = xe_device_get_root_tile(xe);
406 
407 	for_each_ccs_rw_ctx(ctx_id) {
408 		bb = bo->bb_ccs[ctx_id];
409 		/* bb should be NULL here. Assert if not NULL */
410 		xe_assert(xe, !bb);
411 
412 		ctx = &xe->sriov.vf.ccs.contexts[ctx_id];
413 		err = xe_migrate_ccs_rw_copy(tile, ctx->mig_q, bo, ctx_id);
414 	}
415 	return err;
416 }
417 
418 /**
419  * xe_sriov_vf_ccs_detach_bo - Remove CCS read write commands from the BO.
420  * @bo: the &buffer object from which batch buffer commands will be removed.
421  *
422  * This function shall be called only by VF. It removes the PTEs and copy
423  * command instructions from the BO. Make sure to update the BB with MI_NOOP
424  * before freeing.
425  *
426  * Returns: 0 if successful.
427  */
428 int xe_sriov_vf_ccs_detach_bo(struct xe_bo *bo)
429 {
430 	struct xe_device *xe = xe_bo_device(bo);
431 	enum xe_sriov_vf_ccs_rw_ctxs ctx_id;
432 	struct xe_bb *bb;
433 
434 	xe_assert(xe, IS_VF_CCS_READY(xe));
435 
436 	if (!xe_bo_has_valid_ccs_bb(bo))
437 		return 0;
438 
439 	for_each_ccs_rw_ctx(ctx_id) {
440 		bb = bo->bb_ccs[ctx_id];
441 		if (!bb)
442 			continue;
443 
444 		memset(bb->cs, MI_NOOP, bb->len * sizeof(u32));
445 		xe_bb_free(bb, NULL);
446 		bo->bb_ccs[ctx_id] = NULL;
447 	}
448 	return 0;
449 }
450 
451 /**
452  * xe_sriov_vf_ccs_print - Print VF CCS details.
453  * @xe: the &xe_device
454  * @p: the &drm_printer
455  *
456  * This function is for VF use only.
457  */
458 void xe_sriov_vf_ccs_print(struct xe_device *xe, struct drm_printer *p)
459 {
460 	struct xe_sa_manager *bb_pool;
461 	enum xe_sriov_vf_ccs_rw_ctxs ctx_id;
462 
463 	if (!IS_VF_CCS_READY(xe))
464 		return;
465 
466 	xe_pm_runtime_get(xe);
467 
468 	for_each_ccs_rw_ctx(ctx_id) {
469 		bb_pool = xe->sriov.vf.ccs.contexts[ctx_id].mem.ccs_bb_pool;
470 		if (!bb_pool)
471 			break;
472 
473 		drm_printf(p, "ccs %s bb suballoc info\n", ctx_id ? "write" : "read");
474 		drm_printf(p, "-------------------------\n");
475 		drm_suballoc_dump_debug_info(&bb_pool->base, p, xe_sa_manager_gpu_addr(bb_pool));
476 		drm_puts(p, "\n");
477 	}
478 
479 	xe_pm_runtime_put(xe);
480 }
481