xref: /linux/drivers/gpu/drm/xe/xe_sriov_vf.c (revision 360a1f3e96dc21794d688bb4f885542b2b14e619)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2023-2024 Intel Corporation
4  */
5 
6 #include <drm/drm_managed.h>
7 
8 #include "xe_assert.h"
9 #include "xe_device.h"
10 #include "xe_gt_sriov_printk.h"
11 #include "xe_sriov.h"
12 #include "xe_sriov_printk.h"
13 #include "xe_sriov_vf.h"
14 
15 /**
16  * DOC: VF restore procedure in PF KMD and VF KMD
17  *
18  * Restoring previously saved state of a VF is one of core features of
19  * SR-IOV. All major VM Management applications allow saving and restoring
20  * the VM state, and doing that to a VM which uses SRIOV VF as one of
21  * the accessible devices requires support from KMD on both PF and VF side.
22  * VMM initiates all required operations through VFIO module, which then
23  * translates them into PF KMD calls. This description will focus on these
24  * calls, leaving out the module which initiates these steps (VFIO).
25  *
26  * In order to start the restore procedure, GuC needs to keep the VF in
27  * proper state. The PF driver can ensure GuC set it to VF_READY state
28  * by provisioning the VF, which in turn can be done after Function Level
29  * Reset of said VF (or after it was freshly created - in that case FLR
30  * is not needed). The FLR procedure ends with GuC sending message
31  * `GUC_PF_NOTIFY_VF_FLR_DONE`, and then provisioning data is sent to GuC.
32  * After the provisioning is completed, the VF needs to be paused, and
33  * at that point the actual restore can begin.
34  *
35  * During VF Restore, state of several resources is restored. These may
36  * include local memory content (system memory is restored by VMM itself),
37  * values of MMIO registers, stateless compression metadata and others.
38  * The final resource which also needs restoring is state of the VF
39  * submission maintained within GuC. For that, `GUC_PF_OPCODE_VF_RESTORE`
40  * message is used, with reference to the state blob to be consumed by
41  * GuC.
42  *
43  * Next, when VFIO is asked to set the VM into running state, the PF driver
44  * sends `GUC_PF_TRIGGER_VF_RESUME` to GuC. When sent after restore, this
45  * changes VF state within GuC to `VF_RESFIX_BLOCKED` rather than the
46  * usual `VF_RUNNING`. At this point GuC triggers an interrupt to inform
47  * the VF KMD within the VM that it was migrated.
48  *
49  * As soon as Virtual GPU of the VM starts, the VF driver within receives
50  * the MIGRATED interrupt and schedules post-migration recovery worker.
51  * That worker queries GuC for new provisioning (using MMIO communication),
52  * and applies fixups to any non-virtualized resources used by the VF.
53  *
54  * When the VF driver is ready to continue operation on the newly connected
55  * hardware, it sends `VF2GUC_NOTIFY_RESFIX_DONE` which causes it to
56  * enter the long awaited `VF_RUNNING` state, and therefore start handling
57  * CTB messages and scheduling workloads from the VF::
58  *
59  *      PF                             GuC                              VF
60  *     [ ]                              |                               |
61  *     [ ] PF2GUC_VF_CONTROL(pause)     |                               |
62  *     [ ]---------------------------> [ ]                              |
63  *     [ ]                             [ ]  GuC sets new VF state to    |
64  *     [ ]                             [ ]------- VF_READY_PAUSED       |
65  *     [ ]                             [ ]      |                       |
66  *     [ ]                             [ ] <-----                       |
67  *     [ ] success                     [ ]                              |
68  *     [ ] <---------------------------[ ]                              |
69  *     [ ]                              |                               |
70  *     [ ] PF loads resources from the  |                               |
71  *     [ ]------- saved image supplied  |                               |
72  *     [ ]      |                       |                               |
73  *     [ ] <-----                       |                               |
74  *     [ ]                              |                               |
75  *     [ ] GUC_PF_OPCODE_VF_RESTORE     |                               |
76  *     [ ]---------------------------> [ ]                              |
77  *     [ ]                             [ ]  GuC loads contexts and CTB  |
78  *     [ ]                             [ ]------- state from image      |
79  *     [ ]                             [ ]      |                       |
80  *     [ ]                             [ ] <-----                       |
81  *     [ ]                             [ ]                              |
82  *     [ ]                             [ ]  GuC sets new VF state to    |
83  *     [ ]                             [ ]------- VF_RESFIX_PAUSED      |
84  *     [ ]                             [ ]      |                       |
85  *     [ ] success                     [ ] <-----                       |
86  *     [ ] <---------------------------[ ]                              |
87  *     [ ]                              |                               |
88  *     [ ] GUC_PF_TRIGGER_VF_RESUME     |                               |
89  *     [ ]---------------------------> [ ]                              |
90  *     [ ]                             [ ]  GuC sets new VF state to    |
91  *     [ ]                             [ ]------- VF_RESFIX_BLOCKED     |
92  *     [ ]                             [ ]      |                       |
93  *     [ ]                             [ ] <-----                       |
94  *     [ ]                             [ ]                              |
95  *     [ ]                             [ ] GUC_INTR_SW_INT_0            |
96  *     [ ] success                     [ ]---------------------------> [ ]
97  *     [ ] <---------------------------[ ]                             [ ]
98  *      |                               |      VF2GUC_QUERY_SINGLE_KLV [ ]
99  *      |                              [ ] <---------------------------[ ]
100  *      |                              [ ]                             [ ]
101  *      |                              [ ]        new VF provisioning  [ ]
102  *      |                              [ ]---------------------------> [ ]
103  *      |                               |                              [ ]
104  *      |                               |       VF driver applies post [ ]
105  *      |                               |      migration fixups -------[ ]
106  *      |                               |                       |      [ ]
107  *      |                               |                       -----> [ ]
108  *      |                               |                              [ ]
109  *      |                               |    VF2GUC_NOTIFY_RESFIX_DONE [ ]
110  *      |                              [ ] <---------------------------[ ]
111  *      |                              [ ]                             [ ]
112  *      |                              [ ]  GuC sets new VF state to   [ ]
113  *      |                              [ ]------- VF_RUNNING           [ ]
114  *      |                              [ ]      |                      [ ]
115  *      |                              [ ] <-----                      [ ]
116  *      |                              [ ]                     success [ ]
117  *      |                              [ ]---------------------------> [ ]
118  *      |                               |                               |
119  *      |                               |                               |
120  */
121 
122 static void migration_worker_func(struct work_struct *w);
123 
124 /**
125  * xe_sriov_vf_init_early - Initialize SR-IOV VF specific data.
126  * @xe: the &xe_device to initialize
127  */
128 void xe_sriov_vf_init_early(struct xe_device *xe)
129 {
130 	INIT_WORK(&xe->sriov.vf.migration.worker, migration_worker_func);
131 }
132 
133 static void vf_post_migration_recovery(struct xe_device *xe)
134 {
135 	drm_dbg(&xe->drm, "migration recovery in progress\n");
136 	/* FIXME: add the recovery steps */
137 	drm_notice(&xe->drm, "migration recovery ended\n");
138 }
139 
140 static void migration_worker_func(struct work_struct *w)
141 {
142 	struct xe_device *xe = container_of(w, struct xe_device,
143 					    sriov.vf.migration.worker);
144 
145 	vf_post_migration_recovery(xe);
146 }
147 
148 static bool vf_ready_to_recovery_on_all_gts(struct xe_device *xe)
149 {
150 	struct xe_gt *gt;
151 	unsigned int id;
152 
153 	for_each_gt(gt, xe, id) {
154 		if (!test_bit(id, &xe->sriov.vf.migration.gt_flags)) {
155 			xe_gt_sriov_dbg_verbose(gt, "still not ready to recover\n");
156 			return false;
157 		}
158 	}
159 	return true;
160 }
161 
162 /**
163  * xe_sriov_vf_start_migration_recovery - Start VF migration recovery.
164  * @xe: the &xe_device to start recovery on
165  *
166  * This function shall be called only by VF.
167  */
168 void xe_sriov_vf_start_migration_recovery(struct xe_device *xe)
169 {
170 	bool started;
171 
172 	xe_assert(xe, IS_SRIOV_VF(xe));
173 
174 	if (!vf_ready_to_recovery_on_all_gts(xe))
175 		return;
176 
177 	WRITE_ONCE(xe->sriov.vf.migration.gt_flags, 0);
178 	/* Ensure other threads see that no flags are set now. */
179 	smp_mb();
180 
181 	started = queue_work(xe->sriov.wq, &xe->sriov.vf.migration.worker);
182 	drm_info(&xe->drm, "VF migration recovery %s\n", started ?
183 		 "scheduled" : "already in progress");
184 }
185