xref: /linux/drivers/gpu/drm/xe/xe_sriov_packet.c (revision 24f171c7e145f43b9f187578e89b0982ce87e54c)
1644a699eSMichał Winiarski // SPDX-License-Identifier: MIT
2644a699eSMichał Winiarski /*
3644a699eSMichał Winiarski  * Copyright © 2025 Intel Corporation
4644a699eSMichał Winiarski  */
5644a699eSMichał Winiarski 
6644a699eSMichał Winiarski #include "xe_bo.h"
7644a699eSMichał Winiarski #include "xe_device.h"
8*70e2fa91SMichał Winiarski #include "xe_guc_klv_helpers.h"
9644a699eSMichał Winiarski #include "xe_printk.h"
10644a699eSMichał Winiarski #include "xe_sriov_packet.h"
11644a699eSMichał Winiarski #include "xe_sriov_packet_types.h"
121ed30397SMichał Winiarski #include "xe_sriov_pf_helpers.h"
131ed30397SMichał Winiarski #include "xe_sriov_pf_migration.h"
141ed30397SMichał Winiarski #include "xe_sriov_printk.h"
151ed30397SMichał Winiarski 
161ed30397SMichał Winiarski static struct mutex *pf_migration_mutex(struct xe_device *xe, unsigned int vfid)
171ed30397SMichał Winiarski {
181ed30397SMichał Winiarski 	xe_assert(xe, IS_SRIOV_PF(xe));
191ed30397SMichał Winiarski 	xe_assert(xe, vfid <= xe_sriov_pf_get_totalvfs(xe));
201ed30397SMichał Winiarski 
211ed30397SMichał Winiarski 	return &xe->sriov.pf.vfs[vfid].migration.lock;
221ed30397SMichał Winiarski }
231ed30397SMichał Winiarski 
241ed30397SMichał Winiarski static struct xe_sriov_packet **pf_pick_pending(struct xe_device *xe, unsigned int vfid)
251ed30397SMichał Winiarski {
261ed30397SMichał Winiarski 	xe_assert(xe, IS_SRIOV_PF(xe));
271ed30397SMichał Winiarski 	xe_assert(xe, vfid <= xe_sriov_pf_get_totalvfs(xe));
281ed30397SMichał Winiarski 	lockdep_assert_held(pf_migration_mutex(xe, vfid));
291ed30397SMichał Winiarski 
301ed30397SMichał Winiarski 	return &xe->sriov.pf.vfs[vfid].migration.pending;
311ed30397SMichał Winiarski }
321ed30397SMichał Winiarski 
331ed30397SMichał Winiarski static struct xe_sriov_packet **
341ed30397SMichał Winiarski pf_pick_descriptor(struct xe_device *xe, unsigned int vfid)
351ed30397SMichał Winiarski {
361ed30397SMichał Winiarski 	xe_assert(xe, IS_SRIOV_PF(xe));
371ed30397SMichał Winiarski 	xe_assert(xe, vfid <= xe_sriov_pf_get_totalvfs(xe));
381ed30397SMichał Winiarski 	lockdep_assert_held(pf_migration_mutex(xe, vfid));
391ed30397SMichał Winiarski 
401ed30397SMichał Winiarski 	return &xe->sriov.pf.vfs[vfid].migration.descriptor;
411ed30397SMichał Winiarski }
421ed30397SMichał Winiarski 
431ed30397SMichał Winiarski static struct xe_sriov_packet **pf_pick_trailer(struct xe_device *xe, unsigned int vfid)
441ed30397SMichał Winiarski {
451ed30397SMichał Winiarski 	xe_assert(xe, IS_SRIOV_PF(xe));
461ed30397SMichał Winiarski 	xe_assert(xe, vfid <= xe_sriov_pf_get_totalvfs(xe));
471ed30397SMichał Winiarski 	lockdep_assert_held(pf_migration_mutex(xe, vfid));
481ed30397SMichał Winiarski 
491ed30397SMichał Winiarski 	return &xe->sriov.pf.vfs[vfid].migration.trailer;
501ed30397SMichał Winiarski }
511ed30397SMichał Winiarski 
521ed30397SMichał Winiarski static struct xe_sriov_packet **pf_pick_read_packet(struct xe_device *xe,
531ed30397SMichał Winiarski 						    unsigned int vfid)
541ed30397SMichał Winiarski {
551ed30397SMichał Winiarski 	struct xe_sriov_packet **data;
561ed30397SMichał Winiarski 
571ed30397SMichał Winiarski 	data = pf_pick_descriptor(xe, vfid);
581ed30397SMichał Winiarski 	if (*data)
591ed30397SMichał Winiarski 		return data;
601ed30397SMichał Winiarski 
611ed30397SMichał Winiarski 	data = pf_pick_pending(xe, vfid);
621ed30397SMichał Winiarski 	if (!*data)
631ed30397SMichał Winiarski 		*data = xe_sriov_pf_migration_save_consume(xe, vfid);
641ed30397SMichał Winiarski 	if (*data)
651ed30397SMichał Winiarski 		return data;
661ed30397SMichał Winiarski 
671ed30397SMichał Winiarski 	data = pf_pick_trailer(xe, vfid);
681ed30397SMichał Winiarski 	if (*data)
691ed30397SMichał Winiarski 		return data;
701ed30397SMichał Winiarski 
711ed30397SMichał Winiarski 	return NULL;
721ed30397SMichał Winiarski }
73644a699eSMichał Winiarski 
74644a699eSMichał Winiarski static bool pkt_needs_bo(struct xe_sriov_packet *data)
75644a699eSMichał Winiarski {
76644a699eSMichał Winiarski 	return data->hdr.type == XE_SRIOV_PACKET_TYPE_VRAM;
77644a699eSMichał Winiarski }
78644a699eSMichał Winiarski 
79644a699eSMichał Winiarski /**
80644a699eSMichał Winiarski  * xe_sriov_packet_alloc() - Allocate migration data packet
81644a699eSMichał Winiarski  * @xe: the &xe_device
82644a699eSMichał Winiarski  *
83644a699eSMichał Winiarski  * Only allocates the "outer" structure, without initializing the migration
84644a699eSMichał Winiarski  * data backing storage.
85644a699eSMichał Winiarski  *
86644a699eSMichał Winiarski  * Return: Pointer to &xe_sriov_packet on success,
87644a699eSMichał Winiarski  *         NULL in case of error.
88644a699eSMichał Winiarski  */
89644a699eSMichał Winiarski struct xe_sriov_packet *xe_sriov_packet_alloc(struct xe_device *xe)
90644a699eSMichał Winiarski {
91644a699eSMichał Winiarski 	struct xe_sriov_packet *data;
92644a699eSMichał Winiarski 
93644a699eSMichał Winiarski 	data = kzalloc(sizeof(*data), GFP_KERNEL);
94644a699eSMichał Winiarski 	if (!data)
95644a699eSMichał Winiarski 		return NULL;
96644a699eSMichał Winiarski 
97644a699eSMichał Winiarski 	data->xe = xe;
98644a699eSMichał Winiarski 	data->hdr_remaining = sizeof(data->hdr);
99644a699eSMichał Winiarski 
100644a699eSMichał Winiarski 	return data;
101644a699eSMichał Winiarski }
102644a699eSMichał Winiarski 
103644a699eSMichał Winiarski /**
104644a699eSMichał Winiarski  * xe_sriov_packet_free() - Free migration data packet.
105644a699eSMichał Winiarski  * @data: the &xe_sriov_packet
106644a699eSMichał Winiarski  */
107644a699eSMichał Winiarski void xe_sriov_packet_free(struct xe_sriov_packet *data)
108644a699eSMichał Winiarski {
109644a699eSMichał Winiarski 	if (IS_ERR_OR_NULL(data))
110644a699eSMichał Winiarski 		return;
111644a699eSMichał Winiarski 
112644a699eSMichał Winiarski 	if (pkt_needs_bo(data))
113644a699eSMichał Winiarski 		xe_bo_unpin_map_no_vm(data->bo);
114644a699eSMichał Winiarski 	else
115644a699eSMichał Winiarski 		kvfree(data->buff);
116644a699eSMichał Winiarski 
117644a699eSMichał Winiarski 	kfree(data);
118644a699eSMichał Winiarski }
119644a699eSMichał Winiarski 
120644a699eSMichał Winiarski static int pkt_init(struct xe_sriov_packet *data)
121644a699eSMichał Winiarski {
122644a699eSMichał Winiarski 	struct xe_gt *gt = xe_device_get_gt(data->xe, data->hdr.gt_id);
123644a699eSMichał Winiarski 
124644a699eSMichał Winiarski 	if (!gt)
125644a699eSMichał Winiarski 		return -EINVAL;
126644a699eSMichał Winiarski 
127644a699eSMichał Winiarski 	if (data->hdr.size == 0)
128644a699eSMichał Winiarski 		return 0;
129644a699eSMichał Winiarski 
130644a699eSMichał Winiarski 	if (pkt_needs_bo(data)) {
131644a699eSMichał Winiarski 		struct xe_bo *bo;
132644a699eSMichał Winiarski 
133644a699eSMichał Winiarski 		bo = xe_bo_create_pin_map_novm(data->xe, gt->tile, PAGE_ALIGN(data->hdr.size),
134644a699eSMichał Winiarski 					       ttm_bo_type_kernel,
135644a699eSMichał Winiarski 					       XE_BO_FLAG_SYSTEM | XE_BO_FLAG_PINNED, false);
136644a699eSMichał Winiarski 		if (IS_ERR(bo))
137644a699eSMichał Winiarski 			return PTR_ERR(bo);
138644a699eSMichał Winiarski 
139644a699eSMichał Winiarski 		data->bo = bo;
140644a699eSMichał Winiarski 		data->vaddr = bo->vmap.vaddr;
141644a699eSMichał Winiarski 	} else {
142644a699eSMichał Winiarski 		void *buff = kvzalloc(data->hdr.size, GFP_KERNEL);
143644a699eSMichał Winiarski 
144644a699eSMichał Winiarski 		if (!buff)
145644a699eSMichał Winiarski 			return -ENOMEM;
146644a699eSMichał Winiarski 
147644a699eSMichał Winiarski 		data->buff = buff;
148644a699eSMichał Winiarski 		data->vaddr = buff;
149644a699eSMichał Winiarski 	}
150644a699eSMichał Winiarski 
151644a699eSMichał Winiarski 	return 0;
152644a699eSMichał Winiarski }
153644a699eSMichał Winiarski 
154644a699eSMichał Winiarski #define XE_SRIOV_PACKET_SUPPORTED_VERSION 1
155644a699eSMichał Winiarski 
156644a699eSMichał Winiarski /**
157644a699eSMichał Winiarski  * xe_sriov_packet_init() - Initialize migration packet header and backing storage.
158644a699eSMichał Winiarski  * @data: the &xe_sriov_packet
159644a699eSMichał Winiarski  * @tile_id: tile identifier
160644a699eSMichał Winiarski  * @gt_id: GT identifier
161644a699eSMichał Winiarski  * @type: &xe_sriov_packet_type
162644a699eSMichał Winiarski  * @offset: offset of data packet payload (within wider resource)
163644a699eSMichał Winiarski  * @size: size of data packet payload
164644a699eSMichał Winiarski  *
165644a699eSMichał Winiarski  * Return: 0 on success or a negative error code on failure.
166644a699eSMichał Winiarski  */
167644a699eSMichał Winiarski int xe_sriov_packet_init(struct xe_sriov_packet *data, u8 tile_id, u8 gt_id,
168644a699eSMichał Winiarski 			 enum xe_sriov_packet_type type, loff_t offset, size_t size)
169644a699eSMichał Winiarski {
170644a699eSMichał Winiarski 	data->hdr.version = XE_SRIOV_PACKET_SUPPORTED_VERSION;
171644a699eSMichał Winiarski 	data->hdr.type = type;
172644a699eSMichał Winiarski 	data->hdr.tile_id = tile_id;
173644a699eSMichał Winiarski 	data->hdr.gt_id = gt_id;
174644a699eSMichał Winiarski 	data->hdr.offset = offset;
175644a699eSMichał Winiarski 	data->hdr.size = size;
176644a699eSMichał Winiarski 	data->remaining = size;
177644a699eSMichał Winiarski 
178644a699eSMichał Winiarski 	return pkt_init(data);
179644a699eSMichał Winiarski }
180644a699eSMichał Winiarski 
181644a699eSMichał Winiarski /**
182644a699eSMichał Winiarski  * xe_sriov_packet_init_from_hdr() - Initialize migration packet backing storage based on header.
183644a699eSMichał Winiarski  * @data: the &xe_sriov_packet
184644a699eSMichał Winiarski  *
185644a699eSMichał Winiarski  * Header data is expected to be filled prior to calling this function.
186644a699eSMichał Winiarski  *
187644a699eSMichał Winiarski  * Return: 0 on success or a negative error code on failure.
188644a699eSMichał Winiarski  */
189644a699eSMichał Winiarski int xe_sriov_packet_init_from_hdr(struct xe_sriov_packet *data)
190644a699eSMichał Winiarski {
191644a699eSMichał Winiarski 	xe_assert(data->xe, !data->hdr_remaining);
192644a699eSMichał Winiarski 
193644a699eSMichał Winiarski 	if (data->hdr.version != XE_SRIOV_PACKET_SUPPORTED_VERSION)
194644a699eSMichał Winiarski 		return -EINVAL;
195644a699eSMichał Winiarski 
196644a699eSMichał Winiarski 	data->remaining = data->hdr.size;
197644a699eSMichał Winiarski 
198644a699eSMichał Winiarski 	return pkt_init(data);
199644a699eSMichał Winiarski }
2001ed30397SMichał Winiarski 
2011ed30397SMichał Winiarski static ssize_t pkt_hdr_read(struct xe_sriov_packet *data,
2021ed30397SMichał Winiarski 			    char __user *buf, size_t len)
2031ed30397SMichał Winiarski {
2041ed30397SMichał Winiarski 	loff_t offset = sizeof(data->hdr) - data->hdr_remaining;
2051ed30397SMichał Winiarski 
2061ed30397SMichał Winiarski 	if (!data->hdr_remaining)
2071ed30397SMichał Winiarski 		return -EINVAL;
2081ed30397SMichał Winiarski 
2091ed30397SMichał Winiarski 	if (len > data->hdr_remaining)
2101ed30397SMichał Winiarski 		len = data->hdr_remaining;
2111ed30397SMichał Winiarski 
2121ed30397SMichał Winiarski 	if (copy_to_user(buf, (void *)&data->hdr + offset, len))
2131ed30397SMichał Winiarski 		return -EFAULT;
2141ed30397SMichał Winiarski 
2151ed30397SMichał Winiarski 	data->hdr_remaining -= len;
2161ed30397SMichał Winiarski 
2171ed30397SMichał Winiarski 	return len;
2181ed30397SMichał Winiarski }
2191ed30397SMichał Winiarski 
2201ed30397SMichał Winiarski static ssize_t pkt_data_read(struct xe_sriov_packet *data,
2211ed30397SMichał Winiarski 			     char __user *buf, size_t len)
2221ed30397SMichał Winiarski {
2231ed30397SMichał Winiarski 	if (len > data->remaining)
2241ed30397SMichał Winiarski 		len = data->remaining;
2251ed30397SMichał Winiarski 
2261ed30397SMichał Winiarski 	if (copy_to_user(buf, data->vaddr + (data->hdr.size - data->remaining), len))
2271ed30397SMichał Winiarski 		return -EFAULT;
2281ed30397SMichał Winiarski 
2291ed30397SMichał Winiarski 	data->remaining -= len;
2301ed30397SMichał Winiarski 
2311ed30397SMichał Winiarski 	return len;
2321ed30397SMichał Winiarski }
2331ed30397SMichał Winiarski 
2341ed30397SMichał Winiarski static ssize_t pkt_read_single(struct xe_sriov_packet **data,
2351ed30397SMichał Winiarski 			       unsigned int vfid, char __user *buf, size_t len)
2361ed30397SMichał Winiarski {
2371ed30397SMichał Winiarski 	ssize_t copied = 0;
2381ed30397SMichał Winiarski 
2391ed30397SMichał Winiarski 	if ((*data)->hdr_remaining)
2401ed30397SMichał Winiarski 		copied = pkt_hdr_read(*data, buf, len);
2411ed30397SMichał Winiarski 	else
2421ed30397SMichał Winiarski 		copied = pkt_data_read(*data, buf, len);
2431ed30397SMichał Winiarski 
2441ed30397SMichał Winiarski 	if ((*data)->remaining == 0 && (*data)->hdr_remaining == 0) {
2451ed30397SMichał Winiarski 		xe_sriov_packet_free(*data);
2461ed30397SMichał Winiarski 		*data = NULL;
2471ed30397SMichał Winiarski 	}
2481ed30397SMichał Winiarski 
2491ed30397SMichał Winiarski 	return copied;
2501ed30397SMichał Winiarski }
2511ed30397SMichał Winiarski 
2521ed30397SMichał Winiarski /**
2531ed30397SMichał Winiarski  * xe_sriov_packet_read_single() - Read migration data from a single packet.
2541ed30397SMichał Winiarski  * @xe: the &xe_device
2551ed30397SMichał Winiarski  * @vfid: the VF identifier
2561ed30397SMichał Winiarski  * @buf: start address of userspace buffer
2571ed30397SMichał Winiarski  * @len: requested read size from userspace
2581ed30397SMichał Winiarski  *
2591ed30397SMichał Winiarski  * Return: number of bytes that has been successfully read,
2601ed30397SMichał Winiarski  *	   0 if no more migration data is available,
2611ed30397SMichał Winiarski  *	   -errno on failure.
2621ed30397SMichał Winiarski  */
2631ed30397SMichał Winiarski ssize_t xe_sriov_packet_read_single(struct xe_device *xe, unsigned int vfid,
2641ed30397SMichał Winiarski 				    char __user *buf, size_t len)
2651ed30397SMichał Winiarski {
2661ed30397SMichał Winiarski 	struct xe_sriov_packet **data = pf_pick_read_packet(xe, vfid);
2671ed30397SMichał Winiarski 
2681ed30397SMichał Winiarski 	if (!data)
2691ed30397SMichał Winiarski 		return -ENODATA;
2701ed30397SMichał Winiarski 	if (IS_ERR(*data))
2711ed30397SMichał Winiarski 		return PTR_ERR(*data);
2721ed30397SMichał Winiarski 
2731ed30397SMichał Winiarski 	return pkt_read_single(data, vfid, buf, len);
2741ed30397SMichał Winiarski }
2751ed30397SMichał Winiarski 
2761ed30397SMichał Winiarski static ssize_t pkt_hdr_write(struct xe_sriov_packet *data,
2771ed30397SMichał Winiarski 			     const char __user *buf, size_t len)
2781ed30397SMichał Winiarski {
2791ed30397SMichał Winiarski 	loff_t offset = sizeof(data->hdr) - data->hdr_remaining;
2801ed30397SMichał Winiarski 	int ret;
2811ed30397SMichał Winiarski 
2821ed30397SMichał Winiarski 	if (len > data->hdr_remaining)
2831ed30397SMichał Winiarski 		len = data->hdr_remaining;
2841ed30397SMichał Winiarski 
2851ed30397SMichał Winiarski 	if (copy_from_user((void *)&data->hdr + offset, buf, len))
2861ed30397SMichał Winiarski 		return -EFAULT;
2871ed30397SMichał Winiarski 
2881ed30397SMichał Winiarski 	data->hdr_remaining -= len;
2891ed30397SMichał Winiarski 
2901ed30397SMichał Winiarski 	if (!data->hdr_remaining) {
2911ed30397SMichał Winiarski 		ret = xe_sriov_packet_init_from_hdr(data);
2921ed30397SMichał Winiarski 		if (ret)
2931ed30397SMichał Winiarski 			return ret;
2941ed30397SMichał Winiarski 	}
2951ed30397SMichał Winiarski 
2961ed30397SMichał Winiarski 	return len;
2971ed30397SMichał Winiarski }
2981ed30397SMichał Winiarski 
2991ed30397SMichał Winiarski static ssize_t pkt_data_write(struct xe_sriov_packet *data,
3001ed30397SMichał Winiarski 			      const char __user *buf, size_t len)
3011ed30397SMichał Winiarski {
3021ed30397SMichał Winiarski 	if (len > data->remaining)
3031ed30397SMichał Winiarski 		len = data->remaining;
3041ed30397SMichał Winiarski 
3051ed30397SMichał Winiarski 	if (copy_from_user(data->vaddr + (data->hdr.size - data->remaining), buf, len))
3061ed30397SMichał Winiarski 		return -EFAULT;
3071ed30397SMichał Winiarski 
3081ed30397SMichał Winiarski 	data->remaining -= len;
3091ed30397SMichał Winiarski 
3101ed30397SMichał Winiarski 	return len;
3111ed30397SMichał Winiarski }
3121ed30397SMichał Winiarski 
3131ed30397SMichał Winiarski /**
3141ed30397SMichał Winiarski  * xe_sriov_packet_write_single() - Write migration data to a single packet.
3151ed30397SMichał Winiarski  * @xe: the &xe_device
3161ed30397SMichał Winiarski  * @vfid: the VF identifier
3171ed30397SMichał Winiarski  * @buf: start address of userspace buffer
3181ed30397SMichał Winiarski  * @len: requested write size from userspace
3191ed30397SMichał Winiarski  *
3201ed30397SMichał Winiarski  * Return: number of bytes that has been successfully written,
3211ed30397SMichał Winiarski  *	   -errno on failure.
3221ed30397SMichał Winiarski  */
3231ed30397SMichał Winiarski ssize_t xe_sriov_packet_write_single(struct xe_device *xe, unsigned int vfid,
3241ed30397SMichał Winiarski 				     const char __user *buf, size_t len)
3251ed30397SMichał Winiarski {
3261ed30397SMichał Winiarski 	struct xe_sriov_packet **data = pf_pick_pending(xe, vfid);
3271ed30397SMichał Winiarski 	int ret;
3281ed30397SMichał Winiarski 	ssize_t copied;
3291ed30397SMichał Winiarski 
3301ed30397SMichał Winiarski 	if (IS_ERR_OR_NULL(*data)) {
3311ed30397SMichał Winiarski 		*data = xe_sriov_packet_alloc(xe);
3321ed30397SMichał Winiarski 		if (!*data)
3331ed30397SMichał Winiarski 			return -ENOMEM;
3341ed30397SMichał Winiarski 	}
3351ed30397SMichał Winiarski 
3361ed30397SMichał Winiarski 	if ((*data)->hdr_remaining)
3371ed30397SMichał Winiarski 		copied = pkt_hdr_write(*data, buf, len);
3381ed30397SMichał Winiarski 	else
3391ed30397SMichał Winiarski 		copied = pkt_data_write(*data, buf, len);
3401ed30397SMichał Winiarski 
3411ed30397SMichał Winiarski 	if ((*data)->hdr_remaining == 0 && (*data)->remaining == 0) {
3421ed30397SMichał Winiarski 		ret = xe_sriov_pf_migration_restore_produce(xe, vfid, *data);
3431ed30397SMichał Winiarski 		if (ret) {
3441ed30397SMichał Winiarski 			xe_sriov_packet_free(*data);
3451ed30397SMichał Winiarski 			return ret;
3461ed30397SMichał Winiarski 		}
3471ed30397SMichał Winiarski 
3481ed30397SMichał Winiarski 		*data = NULL;
3491ed30397SMichał Winiarski 	}
3501ed30397SMichał Winiarski 
3511ed30397SMichał Winiarski 	return copied;
3521ed30397SMichał Winiarski }
3531ed30397SMichał Winiarski 
354*70e2fa91SMichał Winiarski #define MIGRATION_KLV_DEVICE_DEVID_KEY	0xf001u
355*70e2fa91SMichał Winiarski #define MIGRATION_KLV_DEVICE_DEVID_LEN	1u
356*70e2fa91SMichał Winiarski #define MIGRATION_KLV_DEVICE_REVID_KEY	0xf002u
357*70e2fa91SMichał Winiarski #define MIGRATION_KLV_DEVICE_REVID_LEN	1u
358*70e2fa91SMichał Winiarski 
359*70e2fa91SMichał Winiarski #define MIGRATION_DESCRIPTOR_DWORDS	(GUC_KLV_LEN_MIN + MIGRATION_KLV_DEVICE_DEVID_LEN + \
360*70e2fa91SMichał Winiarski 					 GUC_KLV_LEN_MIN + MIGRATION_KLV_DEVICE_REVID_LEN)
3611ed30397SMichał Winiarski static size_t pf_descriptor_init(struct xe_device *xe, unsigned int vfid)
3621ed30397SMichał Winiarski {
3631ed30397SMichał Winiarski 	struct xe_sriov_packet **desc = pf_pick_descriptor(xe, vfid);
3641ed30397SMichał Winiarski 	struct xe_sriov_packet *data;
365*70e2fa91SMichał Winiarski 	unsigned int len = 0;
366*70e2fa91SMichał Winiarski 	u32 *klvs;
3671ed30397SMichał Winiarski 	int ret;
3681ed30397SMichał Winiarski 
3691ed30397SMichał Winiarski 	data = xe_sriov_packet_alloc(xe);
3701ed30397SMichał Winiarski 	if (!data)
3711ed30397SMichał Winiarski 		return -ENOMEM;
3721ed30397SMichał Winiarski 
3731ed30397SMichał Winiarski 	ret = xe_sriov_packet_init(data, 0, 0, XE_SRIOV_PACKET_TYPE_DESCRIPTOR,
3741ed30397SMichał Winiarski 				   0, MIGRATION_DESCRIPTOR_DWORDS * sizeof(u32));
3751ed30397SMichał Winiarski 	if (ret) {
3761ed30397SMichał Winiarski 		xe_sriov_packet_free(data);
3771ed30397SMichał Winiarski 		return ret;
3781ed30397SMichał Winiarski 	}
3791ed30397SMichał Winiarski 
380*70e2fa91SMichał Winiarski 	klvs = data->vaddr;
381*70e2fa91SMichał Winiarski 	klvs[len++] = PREP_GUC_KLV_CONST(MIGRATION_KLV_DEVICE_DEVID_KEY,
382*70e2fa91SMichał Winiarski 					 MIGRATION_KLV_DEVICE_DEVID_LEN);
383*70e2fa91SMichał Winiarski 	klvs[len++] = xe->info.devid;
384*70e2fa91SMichał Winiarski 	klvs[len++] = PREP_GUC_KLV_CONST(MIGRATION_KLV_DEVICE_REVID_KEY,
385*70e2fa91SMichał Winiarski 					 MIGRATION_KLV_DEVICE_REVID_LEN);
386*70e2fa91SMichał Winiarski 	klvs[len++] = xe->info.revid;
387*70e2fa91SMichał Winiarski 
388*70e2fa91SMichał Winiarski 	xe_assert(xe, len == MIGRATION_DESCRIPTOR_DWORDS);
389*70e2fa91SMichał Winiarski 
3901ed30397SMichał Winiarski 	*desc = data;
3911ed30397SMichał Winiarski 
3921ed30397SMichał Winiarski 	return 0;
3931ed30397SMichał Winiarski }
3941ed30397SMichał Winiarski 
395*70e2fa91SMichał Winiarski /**
396*70e2fa91SMichał Winiarski  * xe_sriov_packet_process_descriptor() - Process migration data descriptor packet.
397*70e2fa91SMichał Winiarski  * @xe: the &xe_device
398*70e2fa91SMichał Winiarski  * @vfid: the VF identifier
399*70e2fa91SMichał Winiarski  * @data: the &xe_sriov_packet containing the descriptor
400*70e2fa91SMichał Winiarski  *
401*70e2fa91SMichał Winiarski  * The descriptor uses the same KLV format as GuC, and contains metadata used for
402*70e2fa91SMichał Winiarski  * checking migration data compatibility.
403*70e2fa91SMichał Winiarski  *
404*70e2fa91SMichał Winiarski  * Return: 0 on success, -errno on failure.
405*70e2fa91SMichał Winiarski  */
406*70e2fa91SMichał Winiarski int xe_sriov_packet_process_descriptor(struct xe_device *xe, unsigned int vfid,
407*70e2fa91SMichał Winiarski 				       struct xe_sriov_packet *data)
408*70e2fa91SMichał Winiarski {
409*70e2fa91SMichał Winiarski 	u32 num_dwords = data->hdr.size / sizeof(u32);
410*70e2fa91SMichał Winiarski 	u32 *klvs = data->vaddr;
411*70e2fa91SMichał Winiarski 
412*70e2fa91SMichał Winiarski 	xe_assert(xe, data->hdr.type == XE_SRIOV_PACKET_TYPE_DESCRIPTOR);
413*70e2fa91SMichał Winiarski 
414*70e2fa91SMichał Winiarski 	if (data->hdr.size % sizeof(u32)) {
415*70e2fa91SMichał Winiarski 		xe_sriov_warn(xe, "Aborting migration, descriptor not in KLV format (size=%llu)\n",
416*70e2fa91SMichał Winiarski 			      data->hdr.size);
417*70e2fa91SMichał Winiarski 		return -EINVAL;
418*70e2fa91SMichał Winiarski 	}
419*70e2fa91SMichał Winiarski 
420*70e2fa91SMichał Winiarski 	while (num_dwords >= GUC_KLV_LEN_MIN) {
421*70e2fa91SMichał Winiarski 		u32 key = FIELD_GET(GUC_KLV_0_KEY, klvs[0]);
422*70e2fa91SMichał Winiarski 		u32 len = FIELD_GET(GUC_KLV_0_LEN, klvs[0]);
423*70e2fa91SMichał Winiarski 
424*70e2fa91SMichał Winiarski 		klvs += GUC_KLV_LEN_MIN;
425*70e2fa91SMichał Winiarski 		num_dwords -= GUC_KLV_LEN_MIN;
426*70e2fa91SMichał Winiarski 
427*70e2fa91SMichał Winiarski 		if (len > num_dwords) {
428*70e2fa91SMichał Winiarski 			xe_sriov_warn(xe, "Aborting migration, truncated KLV %#x, len %u\n",
429*70e2fa91SMichał Winiarski 				      key, len);
430*70e2fa91SMichał Winiarski 			return -EINVAL;
431*70e2fa91SMichał Winiarski 		}
432*70e2fa91SMichał Winiarski 
433*70e2fa91SMichał Winiarski 		switch (key) {
434*70e2fa91SMichał Winiarski 		case MIGRATION_KLV_DEVICE_DEVID_KEY:
435*70e2fa91SMichał Winiarski 			if (*klvs != xe->info.devid) {
436*70e2fa91SMichał Winiarski 				xe_sriov_warn(xe,
437*70e2fa91SMichał Winiarski 					      "Aborting migration, devid mismatch %#06x!=%#06x\n",
438*70e2fa91SMichał Winiarski 					      *klvs, xe->info.devid);
439*70e2fa91SMichał Winiarski 				return -ENODEV;
440*70e2fa91SMichał Winiarski 			}
441*70e2fa91SMichał Winiarski 			break;
442*70e2fa91SMichał Winiarski 		case MIGRATION_KLV_DEVICE_REVID_KEY:
443*70e2fa91SMichał Winiarski 			if (*klvs != xe->info.revid) {
444*70e2fa91SMichał Winiarski 				xe_sriov_warn(xe,
445*70e2fa91SMichał Winiarski 					      "Aborting migration, revid mismatch %#06x!=%#06x\n",
446*70e2fa91SMichał Winiarski 					      *klvs, xe->info.revid);
447*70e2fa91SMichał Winiarski 				return -ENODEV;
448*70e2fa91SMichał Winiarski 			}
449*70e2fa91SMichał Winiarski 			break;
450*70e2fa91SMichał Winiarski 		default:
451*70e2fa91SMichał Winiarski 			xe_sriov_dbg(xe,
452*70e2fa91SMichał Winiarski 				     "Skipping unknown migration KLV %#x, len=%u\n",
453*70e2fa91SMichał Winiarski 				     key, len);
454*70e2fa91SMichał Winiarski 			print_hex_dump_bytes("desc: ", DUMP_PREFIX_OFFSET, klvs,
455*70e2fa91SMichał Winiarski 					     min(SZ_64, len * sizeof(u32)));
456*70e2fa91SMichał Winiarski 			break;
457*70e2fa91SMichał Winiarski 		}
458*70e2fa91SMichał Winiarski 
459*70e2fa91SMichał Winiarski 		klvs += len;
460*70e2fa91SMichał Winiarski 		num_dwords -= len;
461*70e2fa91SMichał Winiarski 	}
462*70e2fa91SMichał Winiarski 
463*70e2fa91SMichał Winiarski 	return 0;
464*70e2fa91SMichał Winiarski }
465*70e2fa91SMichał Winiarski 
4661ed30397SMichał Winiarski static void pf_pending_init(struct xe_device *xe, unsigned int vfid)
4671ed30397SMichał Winiarski {
4681ed30397SMichał Winiarski 	struct xe_sriov_packet **data = pf_pick_pending(xe, vfid);
4691ed30397SMichał Winiarski 
4701ed30397SMichał Winiarski 	*data = NULL;
4711ed30397SMichał Winiarski }
4721ed30397SMichał Winiarski 
4731ed30397SMichał Winiarski #define MIGRATION_TRAILER_SIZE 0
4741ed30397SMichał Winiarski static int pf_trailer_init(struct xe_device *xe, unsigned int vfid)
4751ed30397SMichał Winiarski {
4761ed30397SMichał Winiarski 	struct xe_sriov_packet **trailer = pf_pick_trailer(xe, vfid);
4771ed30397SMichał Winiarski 	struct xe_sriov_packet *data;
4781ed30397SMichał Winiarski 	int ret;
4791ed30397SMichał Winiarski 
4801ed30397SMichał Winiarski 	data = xe_sriov_packet_alloc(xe);
4811ed30397SMichał Winiarski 	if (!data)
4821ed30397SMichał Winiarski 		return -ENOMEM;
4831ed30397SMichał Winiarski 
4841ed30397SMichał Winiarski 	ret = xe_sriov_packet_init(data, 0, 0, XE_SRIOV_PACKET_TYPE_TRAILER,
4851ed30397SMichał Winiarski 				   0, MIGRATION_TRAILER_SIZE);
4861ed30397SMichał Winiarski 	if (ret) {
4871ed30397SMichał Winiarski 		xe_sriov_packet_free(data);
4881ed30397SMichał Winiarski 		return ret;
4891ed30397SMichał Winiarski 	}
4901ed30397SMichał Winiarski 
4911ed30397SMichał Winiarski 	*trailer = data;
4921ed30397SMichał Winiarski 
4931ed30397SMichał Winiarski 	return 0;
4941ed30397SMichał Winiarski }
4951ed30397SMichał Winiarski 
4961ed30397SMichał Winiarski /**
4971ed30397SMichał Winiarski  * xe_sriov_packet_save_init() - Initialize the pending save migration packets.
4981ed30397SMichał Winiarski  * @xe: the &xe_device
4991ed30397SMichał Winiarski  * @vfid: the VF identifier
5001ed30397SMichał Winiarski  *
5011ed30397SMichał Winiarski  * Return: 0 on success, -errno on failure.
5021ed30397SMichał Winiarski  */
5031ed30397SMichał Winiarski int xe_sriov_packet_save_init(struct xe_device *xe, unsigned int vfid)
5041ed30397SMichał Winiarski {
5051ed30397SMichał Winiarski 	int ret;
5061ed30397SMichał Winiarski 
5071ed30397SMichał Winiarski 	scoped_cond_guard(mutex_intr, return -EINTR, pf_migration_mutex(xe, vfid)) {
5081ed30397SMichał Winiarski 		ret = pf_descriptor_init(xe, vfid);
5091ed30397SMichał Winiarski 		if (ret)
5101ed30397SMichał Winiarski 			return ret;
5111ed30397SMichał Winiarski 
5121ed30397SMichał Winiarski 		ret = pf_trailer_init(xe, vfid);
5131ed30397SMichał Winiarski 		if (ret)
5141ed30397SMichał Winiarski 			return ret;
5151ed30397SMichał Winiarski 
5161ed30397SMichał Winiarski 		pf_pending_init(xe, vfid);
5171ed30397SMichał Winiarski 	}
5181ed30397SMichał Winiarski 
5191ed30397SMichał Winiarski 	return 0;
5201ed30397SMichał Winiarski }
521