File Index
Files and directories
Sign in
FILE

xe_sriov_pf_migration.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/xe/xe_sriov_pf_migration.c C
  1// SPDX-License-Identifier: MIT
  2/*
  3 * Copyright © 2025 Intel Corporation
  4 */
  5
  6#include <drm/drm_managed.h>
  7
  8#include "xe_device.h"
  9#include "xe_gt_sriov_pf_control.h"
 10#include "xe_gt_sriov_pf_migration.h"
 11#include "xe_pm.h"
 12#include "xe_sriov.h"
 13#include "xe_sriov_packet.h"
 14#include "xe_sriov_packet_types.h"
 15#include "xe_sriov_pf_helpers.h"
 16#include "xe_sriov_pf_migration.h"
 17#include "xe_sriov_printk.h"
 18
 19static struct xe_sriov_migration_state *pf_pick_migration(struct xe_device *xe, unsigned int vfid)
 20{
 21	xe_assert(xe, IS_SRIOV_PF(xe));
 22	xe_assert(xe, vfid <= xe_sriov_pf_get_totalvfs(xe));
 23
 24	return &xe->sriov.pf.vfs[vfid].migration;
 25}
 26
 27/**
 28 * xe_sriov_pf_migration_waitqueue() - Get waitqueue for migration.
 29 * @xe: the &xe_device
 30 * @vfid: the VF identifier
 31 *
 32 * Return: pointer to the migration waitqueue.
 33 */
 34wait_queue_head_t *xe_sriov_pf_migration_waitqueue(struct xe_device *xe, unsigned int vfid)
 35{
 36	return &pf_pick_migration(xe, vfid)->wq;
 37}
 38
 39/**
 40 * xe_sriov_pf_migration_supported() - Check if SR-IOV VF migration is supported by the device
 41 * @xe: the &xe_device
 42 *
 43 * Return: true if migration is supported, false otherwise
 44 */
 45bool xe_sriov_pf_migration_supported(struct xe_device *xe)
 46{
 47	xe_assert(xe, IS_SRIOV_PF(xe));
 48
 49	return IS_ENABLED(CONFIG_DRM_XE_DEBUG) || !xe->sriov.pf.migration.disabled;
 50}
 51
 52/**
 53 * xe_sriov_pf_migration_disable() - Turn off SR-IOV VF migration support on PF.
 54 * @xe: the &xe_device instance.
 55 * @fmt: format string for the log message, to be combined with following VAs.
 56 */
 57void xe_sriov_pf_migration_disable(struct xe_device *xe, const char *fmt, ...)
 58{
 59	struct va_format vaf;
 60	va_list va_args;
 61
 62	xe_assert(xe, IS_SRIOV_PF(xe));
 63
 64	va_start(va_args, fmt);
 65	vaf.fmt = fmt;
 66	vaf.va  = &va_args;
 67	xe_sriov_notice(xe, "migration %s: %pV\n",
 68			IS_ENABLED(CONFIG_DRM_XE_DEBUG) ?
 69			"missing prerequisite" : "disabled",
 70			&vaf);
 71	va_end(va_args);
 72
 73	xe->sriov.pf.migration.disabled = true;
 74}
 75
 76static void pf_migration_check_support(struct xe_device *xe)
 77{
 78	if (!xe_device_has_memirq(xe))
 79		xe_sriov_pf_migration_disable(xe, "requires memory-based IRQ support");
 80}
 81
 82static void pf_migration_cleanup(void *arg)
 83{
 84	struct xe_sriov_migration_state *migration = arg;
 85
 86	xe_sriov_packet_free(migration->pending);
 87	xe_sriov_packet_free(migration->trailer);
 88	xe_sriov_packet_free(migration->descriptor);
 89}
 90
 91/**
 92 * xe_sriov_pf_migration_init() - Initialize support for SR-IOV VF migration.
 93 * @xe: the &xe_device
 94 *
 95 * Return: 0 on success or a negative error code on failure.
 96 */
 97int xe_sriov_pf_migration_init(struct xe_device *xe)
 98{
 99	unsigned int n, totalvfs;
100	int err;
101
102	xe_assert(xe, IS_SRIOV_PF(xe));
103
104	pf_migration_check_support(xe);
105
106	if (!xe_sriov_pf_migration_supported(xe))
107		return 0;
108
109	totalvfs = xe_sriov_pf_get_totalvfs(xe);
110	for (n = 1; n <= totalvfs; n++) {
111		struct xe_sriov_migration_state *migration = pf_pick_migration(xe, n);
112
113		err = drmm_mutex_init(&xe->drm, &migration->lock);
114		if (err)
115			return err;
116
117		init_waitqueue_head(&migration->wq);
118
119		err = devm_add_action_or_reset(xe->drm.dev, pf_migration_cleanup, migration);
120		if (err)
121			return err;
122	}
123
124	return 0;
125}
126
127static bool pf_migration_data_ready(struct xe_device *xe, unsigned int vfid)
128{
129	struct xe_gt *gt;
130	u8 gt_id;
131
132	for_each_gt(gt, xe, gt_id) {
133		if (xe_gt_sriov_pf_control_check_save_failed(gt, vfid) ||
134		    xe_gt_sriov_pf_control_check_save_data_done(gt, vfid) ||
135		    !xe_gt_sriov_pf_migration_ring_empty(gt, vfid))
136			return true;
137	}
138
139	return false;
140}
141
142static struct xe_sriov_packet *
143pf_migration_consume(struct xe_device *xe, unsigned int vfid)
144{
145	struct xe_sriov_packet *data;
146	bool more_data = false;
147	struct xe_gt *gt;
148	u8 gt_id;
149
150	for_each_gt(gt, xe, gt_id) {
151		data = xe_gt_sriov_pf_migration_save_consume(gt, vfid);
152		if (data && PTR_ERR(data) != EAGAIN)
153			return data;
154		if (PTR_ERR(data) == -EAGAIN)
155			more_data = true;
156	}
157
158	if (!more_data)
159		return NULL;
160
161	return ERR_PTR(-EAGAIN);
162}
163
164/**
165 * xe_sriov_pf_migration_save_consume() - Consume a VF migration data packet from the device.
166 * @xe: the &xe_device
167 * @vfid: the VF identifier
168 *
169 * Called by the save migration data consumer (userspace) when
170 * processing migration data.
171 * If there is no migration data to process, wait until more data is available.
172 *
173 * Return: Pointer to &xe_sriov_packet on success,
174 *	   NULL if ring is empty and no more migration data is expected,
175 *	   ERR_PTR value in case of error.
176 */
177struct xe_sriov_packet *
178xe_sriov_pf_migration_save_consume(struct xe_device *xe, unsigned int vfid)
179{
180	struct xe_sriov_migration_state *migration = pf_pick_migration(xe, vfid);
181	struct xe_sriov_packet *data;
182	int ret;
183
184	xe_assert(xe, IS_SRIOV_PF(xe));
185
186	for (;;) {
187		data = pf_migration_consume(xe, vfid);
188		if (PTR_ERR(data) != -EAGAIN)
189			break;
190
191		ret = wait_event_interruptible(migration->wq,
192					       pf_migration_data_ready(xe, vfid));
193		if (ret)
194			return ERR_PTR(ret);
195	}
196
197	return data;
198}
199
200static int pf_handle_descriptor(struct xe_device *xe, unsigned int vfid,
201				struct xe_sriov_packet *data)
202{
203	int ret;
204
205	if (data->hdr.tile_id != 0 || data->hdr.gt_id != 0)
206		return -EINVAL;
207
208	ret = xe_sriov_packet_process_descriptor(xe, vfid, data);
209	if (ret)
210		return ret;
211
212	xe_sriov_packet_free(data);
213
214	return 0;
215}
216
217static int pf_handle_trailer(struct xe_device *xe, unsigned int vfid,
218			     struct xe_sriov_packet *data)
219{
220	struct xe_gt *gt;
221	u8 gt_id;
222
223	if (data->hdr.tile_id != 0 || data->hdr.gt_id != 0)
224		return -EINVAL;
225	if (data->hdr.offset != 0 || data->hdr.size != 0 || data->buff || data->bo)
226		return -EINVAL;
227
228	xe_sriov_packet_free(data);
229
230	for_each_gt(gt, xe, gt_id)
231		xe_gt_sriov_pf_control_restore_data_done(gt, vfid);
232
233	return 0;
234}
235
236/**
237 * xe_sriov_pf_migration_restore_produce() - Produce a VF migration data packet to the device.
238 * @xe: the &xe_device
239 * @vfid: the VF identifier
240 * @data: Pointer to &xe_sriov_packet
241 *
242 * Called by the restore migration data producer (userspace) when processing
243 * migration data.
244 * If the underlying data structure is full, wait until there is space.
245 *
246 * Return: 0 on success or a negative error code on failure.
247 */
248int xe_sriov_pf_migration_restore_produce(struct xe_device *xe, unsigned int vfid,
249					  struct xe_sriov_packet *data)
250{
251	struct xe_gt *gt;
252
253	xe_assert(xe, IS_SRIOV_PF(xe));
254
255	if (data->hdr.type == XE_SRIOV_PACKET_TYPE_DESCRIPTOR)
256		return pf_handle_descriptor(xe, vfid, data);
257	if (data->hdr.type == XE_SRIOV_PACKET_TYPE_TRAILER)
258		return pf_handle_trailer(xe, vfid, data);
259
260	gt = xe_device_get_gt(xe, data->hdr.gt_id);
261	if (!gt || data->hdr.tile_id != gt->tile->id || data->hdr.type == 0) {
262		xe_sriov_err_ratelimited(xe, "Received invalid restore packet for VF%u (type:%u, tile:%u, GT:%u)\n",
263					 vfid, data->hdr.type, data->hdr.tile_id, data->hdr.gt_id);
264		return -EINVAL;
265	}
266
267	return xe_gt_sriov_pf_migration_restore_produce(gt, vfid, data);
268}
269
270/**
271 * xe_sriov_pf_migration_read() - Read migration data from the device.
272 * @xe: the &xe_device
273 * @vfid: the VF identifier
274 * @buf: start address of userspace buffer
275 * @len: requested read size from userspace
276 *
277 * Return: number of bytes that has been successfully read,
278 *	   0 if no more migration data is available,
279 *	   -errno on failure.
280 */
281ssize_t xe_sriov_pf_migration_read(struct xe_device *xe, unsigned int vfid,
282				   char __user *buf, size_t len)
283{
284	struct xe_sriov_migration_state *migration = pf_pick_migration(xe, vfid);
285	ssize_t ret, consumed = 0;
286
287	xe_assert(xe, IS_SRIOV_PF(xe));
288
289	scoped_cond_guard(mutex_intr, return -EINTR, &migration->lock) {
290		while (consumed < len) {
291			ret = xe_sriov_packet_read_single(xe, vfid, buf, len - consumed);
292			if (ret == -ENODATA)
293				break;
294			if (ret < 0)
295				return ret;
296
297			consumed += ret;
298			buf += ret;
299		}
300	}
301
302	return consumed;
303}
304
305/**
306 * xe_sriov_pf_migration_write() - Write migration data to the device.
307 * @xe: the &xe_device
308 * @vfid: the VF identifier
309 * @buf: start address of userspace buffer
310 * @len: requested write size from userspace
311 *
312 * Return: number of bytes that has been successfully written,
313 *	   -errno on failure.
314 */
315ssize_t xe_sriov_pf_migration_write(struct xe_device *xe, unsigned int vfid,
316				    const char __user *buf, size_t len)
317{
318	struct xe_sriov_migration_state *migration = pf_pick_migration(xe, vfid);
319	ssize_t ret, produced = 0;
320
321	xe_assert(xe, IS_SRIOV_PF(xe));
322
323	scoped_cond_guard(mutex_intr, return -EINTR, &migration->lock) {
324		while (produced < len) {
325			ret = xe_sriov_packet_write_single(xe, vfid, buf, len - produced);
326			if (ret < 0)
327				return ret;
328
329			produced += ret;
330			buf += ret;
331		}
332	}
333
334	return produced;
335}
336
337/**
338 * xe_sriov_pf_migration_size() - Total size of migration data from all components within a device
339 * @xe: the &xe_device
340 * @vfid: the VF identifier (can't be 0)
341 *
342 * This function is for PF only.
343 *
344 * Return: total migration data size in bytes or a negative error code on failure.
345 */
346ssize_t xe_sriov_pf_migration_size(struct xe_device *xe, unsigned int vfid)
347{
348	size_t size = 0;
349	struct xe_gt *gt;
350	ssize_t ret;
351	u8 gt_id;
352
353	xe_assert(xe, IS_SRIOV_PF(xe));
354	xe_assert(xe, vfid);
355
356	for_each_gt(gt, xe, gt_id) {
357		ret = xe_gt_sriov_pf_migration_size(gt, vfid);
358		if (ret < 0)
359			return ret;
360
361		size += ret;
362	}
363
364	return size;
365}
~/ Read-only file preview.