xref: /linux/drivers/gpu/drm/xe/xe_sriov_pf_service.c (revision 220994d61cebfc04f071d69049127657c7e8191b)
1*a6c384b2SMichal Wajdeczko // SPDX-License-Identifier: MIT
2*a6c384b2SMichal Wajdeczko /*
3*a6c384b2SMichal Wajdeczko  * Copyright © 2023-2025 Intel Corporation
4*a6c384b2SMichal Wajdeczko  */
5*a6c384b2SMichal Wajdeczko 
6*a6c384b2SMichal Wajdeczko #include "abi/guc_relay_actions_abi.h"
7*a6c384b2SMichal Wajdeczko 
8*a6c384b2SMichal Wajdeczko #include "xe_device_types.h"
9*a6c384b2SMichal Wajdeczko #include "xe_sriov.h"
10*a6c384b2SMichal Wajdeczko #include "xe_sriov_pf_helpers.h"
11*a6c384b2SMichal Wajdeczko #include "xe_sriov_printk.h"
12*a6c384b2SMichal Wajdeczko 
13*a6c384b2SMichal Wajdeczko #include "xe_sriov_pf_service.h"
14*a6c384b2SMichal Wajdeczko #include "xe_sriov_pf_service_types.h"
15*a6c384b2SMichal Wajdeczko 
16*a6c384b2SMichal Wajdeczko /**
17*a6c384b2SMichal Wajdeczko  * xe_sriov_pf_service_init - Early initialization of the SR-IOV PF service.
18*a6c384b2SMichal Wajdeczko  * @xe: the &xe_device to initialize
19*a6c384b2SMichal Wajdeczko  *
20*a6c384b2SMichal Wajdeczko  * Performs early initialization of the SR-IOV PF service.
21*a6c384b2SMichal Wajdeczko  *
22*a6c384b2SMichal Wajdeczko  * This function can only be called on PF.
23*a6c384b2SMichal Wajdeczko  */
xe_sriov_pf_service_init(struct xe_device * xe)24*a6c384b2SMichal Wajdeczko void xe_sriov_pf_service_init(struct xe_device *xe)
25*a6c384b2SMichal Wajdeczko {
26*a6c384b2SMichal Wajdeczko 	BUILD_BUG_ON(!GUC_RELAY_VERSION_BASE_MAJOR && !GUC_RELAY_VERSION_BASE_MINOR);
27*a6c384b2SMichal Wajdeczko 	BUILD_BUG_ON(GUC_RELAY_VERSION_BASE_MAJOR > GUC_RELAY_VERSION_LATEST_MAJOR);
28*a6c384b2SMichal Wajdeczko 
29*a6c384b2SMichal Wajdeczko 	xe_assert(xe, IS_SRIOV_PF(xe));
30*a6c384b2SMichal Wajdeczko 
31*a6c384b2SMichal Wajdeczko 	/* base versions may differ between platforms */
32*a6c384b2SMichal Wajdeczko 	xe->sriov.pf.service.version.base.major = GUC_RELAY_VERSION_BASE_MAJOR;
33*a6c384b2SMichal Wajdeczko 	xe->sriov.pf.service.version.base.minor = GUC_RELAY_VERSION_BASE_MINOR;
34*a6c384b2SMichal Wajdeczko 
35*a6c384b2SMichal Wajdeczko 	/* latest version is same for all platforms */
36*a6c384b2SMichal Wajdeczko 	xe->sriov.pf.service.version.latest.major = GUC_RELAY_VERSION_LATEST_MAJOR;
37*a6c384b2SMichal Wajdeczko 	xe->sriov.pf.service.version.latest.minor = GUC_RELAY_VERSION_LATEST_MINOR;
38*a6c384b2SMichal Wajdeczko }
39*a6c384b2SMichal Wajdeczko 
40*a6c384b2SMichal Wajdeczko /* Return: 0 on success or a negative error code on failure. */
pf_negotiate_version(struct xe_device * xe,u32 wanted_major,u32 wanted_minor,u32 * major,u32 * minor)41*a6c384b2SMichal Wajdeczko static int pf_negotiate_version(struct xe_device *xe,
42*a6c384b2SMichal Wajdeczko 				u32 wanted_major, u32 wanted_minor,
43*a6c384b2SMichal Wajdeczko 				u32 *major, u32 *minor)
44*a6c384b2SMichal Wajdeczko {
45*a6c384b2SMichal Wajdeczko 	struct xe_sriov_pf_service_version base = xe->sriov.pf.service.version.base;
46*a6c384b2SMichal Wajdeczko 	struct xe_sriov_pf_service_version latest = xe->sriov.pf.service.version.latest;
47*a6c384b2SMichal Wajdeczko 
48*a6c384b2SMichal Wajdeczko 	xe_assert(xe, IS_SRIOV_PF(xe));
49*a6c384b2SMichal Wajdeczko 	xe_assert(xe, base.major);
50*a6c384b2SMichal Wajdeczko 	xe_assert(xe, base.major <= latest.major);
51*a6c384b2SMichal Wajdeczko 	xe_assert(xe, (base.major < latest.major) || (base.minor <= latest.minor));
52*a6c384b2SMichal Wajdeczko 
53*a6c384b2SMichal Wajdeczko 	/* VF doesn't care - return our latest  */
54*a6c384b2SMichal Wajdeczko 	if (wanted_major == VF2PF_HANDSHAKE_MAJOR_ANY &&
55*a6c384b2SMichal Wajdeczko 	    wanted_minor == VF2PF_HANDSHAKE_MINOR_ANY) {
56*a6c384b2SMichal Wajdeczko 		*major = latest.major;
57*a6c384b2SMichal Wajdeczko 		*minor = latest.minor;
58*a6c384b2SMichal Wajdeczko 		return 0;
59*a6c384b2SMichal Wajdeczko 	}
60*a6c384b2SMichal Wajdeczko 
61*a6c384b2SMichal Wajdeczko 	/* VF wants newer than our - return our latest  */
62*a6c384b2SMichal Wajdeczko 	if (wanted_major > latest.major) {
63*a6c384b2SMichal Wajdeczko 		*major = latest.major;
64*a6c384b2SMichal Wajdeczko 		*minor = latest.minor;
65*a6c384b2SMichal Wajdeczko 		return 0;
66*a6c384b2SMichal Wajdeczko 	}
67*a6c384b2SMichal Wajdeczko 
68*a6c384b2SMichal Wajdeczko 	/* VF wants older than min required - reject */
69*a6c384b2SMichal Wajdeczko 	if (wanted_major < base.major ||
70*a6c384b2SMichal Wajdeczko 	    (wanted_major == base.major && wanted_minor < base.minor)) {
71*a6c384b2SMichal Wajdeczko 		return -EPERM;
72*a6c384b2SMichal Wajdeczko 	}
73*a6c384b2SMichal Wajdeczko 
74*a6c384b2SMichal Wajdeczko 	/* previous major - return wanted, as we should still support it */
75*a6c384b2SMichal Wajdeczko 	if (wanted_major < latest.major) {
76*a6c384b2SMichal Wajdeczko 		/* XXX: we are not prepared for multi-versions yet */
77*a6c384b2SMichal Wajdeczko 		xe_assert(xe, base.major == latest.major);
78*a6c384b2SMichal Wajdeczko 		return -ENOPKG;
79*a6c384b2SMichal Wajdeczko 	}
80*a6c384b2SMichal Wajdeczko 
81*a6c384b2SMichal Wajdeczko 	/* same major - return common minor */
82*a6c384b2SMichal Wajdeczko 	*major = wanted_major;
83*a6c384b2SMichal Wajdeczko 	*minor = min_t(u32, latest.minor, wanted_minor);
84*a6c384b2SMichal Wajdeczko 	return 0;
85*a6c384b2SMichal Wajdeczko }
86*a6c384b2SMichal Wajdeczko 
pf_connect(struct xe_device * xe,u32 vfid,u32 major,u32 minor)87*a6c384b2SMichal Wajdeczko static void pf_connect(struct xe_device *xe, u32 vfid, u32 major, u32 minor)
88*a6c384b2SMichal Wajdeczko {
89*a6c384b2SMichal Wajdeczko 	xe_sriov_pf_assert_vfid(xe, vfid);
90*a6c384b2SMichal Wajdeczko 	xe_assert(xe, major || minor);
91*a6c384b2SMichal Wajdeczko 
92*a6c384b2SMichal Wajdeczko 	xe->sriov.pf.vfs[vfid].version.major = major;
93*a6c384b2SMichal Wajdeczko 	xe->sriov.pf.vfs[vfid].version.minor = minor;
94*a6c384b2SMichal Wajdeczko }
95*a6c384b2SMichal Wajdeczko 
pf_disconnect(struct xe_device * xe,u32 vfid)96*a6c384b2SMichal Wajdeczko static void pf_disconnect(struct xe_device *xe, u32 vfid)
97*a6c384b2SMichal Wajdeczko {
98*a6c384b2SMichal Wajdeczko 	xe_sriov_pf_assert_vfid(xe, vfid);
99*a6c384b2SMichal Wajdeczko 
100*a6c384b2SMichal Wajdeczko 	xe->sriov.pf.vfs[vfid].version.major = 0;
101*a6c384b2SMichal Wajdeczko 	xe->sriov.pf.vfs[vfid].version.minor = 0;
102*a6c384b2SMichal Wajdeczko }
103*a6c384b2SMichal Wajdeczko 
104*a6c384b2SMichal Wajdeczko /**
105*a6c384b2SMichal Wajdeczko  * xe_sriov_pf_service_is_negotiated - Check if VF has negotiated given ABI version.
106*a6c384b2SMichal Wajdeczko  * @xe: the &xe_device
107*a6c384b2SMichal Wajdeczko  * @vfid: the VF identifier
108*a6c384b2SMichal Wajdeczko  * @major: the major version to check
109*a6c384b2SMichal Wajdeczko  * @minor: the minor version to check
110*a6c384b2SMichal Wajdeczko  *
111*a6c384b2SMichal Wajdeczko  * Performs early initialization of the SR-IOV PF service.
112*a6c384b2SMichal Wajdeczko  *
113*a6c384b2SMichal Wajdeczko  * This function can only be called on PF.
114*a6c384b2SMichal Wajdeczko  *
115*a6c384b2SMichal Wajdeczko  * Returns: true if VF can use given ABI version functionality.
116*a6c384b2SMichal Wajdeczko  */
xe_sriov_pf_service_is_negotiated(struct xe_device * xe,u32 vfid,u32 major,u32 minor)117*a6c384b2SMichal Wajdeczko bool xe_sriov_pf_service_is_negotiated(struct xe_device *xe, u32 vfid, u32 major, u32 minor)
118*a6c384b2SMichal Wajdeczko {
119*a6c384b2SMichal Wajdeczko 	xe_sriov_pf_assert_vfid(xe, vfid);
120*a6c384b2SMichal Wajdeczko 
121*a6c384b2SMichal Wajdeczko 	return major == xe->sriov.pf.vfs[vfid].version.major &&
122*a6c384b2SMichal Wajdeczko 	       minor <= xe->sriov.pf.vfs[vfid].version.minor;
123*a6c384b2SMichal Wajdeczko }
124*a6c384b2SMichal Wajdeczko 
125*a6c384b2SMichal Wajdeczko /**
126*a6c384b2SMichal Wajdeczko  * xe_sriov_pf_service_handshake_vf - Confirm a connection with the VF.
127*a6c384b2SMichal Wajdeczko  * @xe: the &xe_device
128*a6c384b2SMichal Wajdeczko  * @vfid: the VF identifier
129*a6c384b2SMichal Wajdeczko  * @wanted_major: the major service version expected by the VF
130*a6c384b2SMichal Wajdeczko  * @wanted_minor: the minor service version expected by the VF
131*a6c384b2SMichal Wajdeczko  * @major: the major service version to be used by the VF
132*a6c384b2SMichal Wajdeczko  * @minor: the minor service version to be used by the VF
133*a6c384b2SMichal Wajdeczko  *
134*a6c384b2SMichal Wajdeczko  * Negotiate a VF/PF ABI version to allow VF use the PF services.
135*a6c384b2SMichal Wajdeczko  *
136*a6c384b2SMichal Wajdeczko  * This function can only be called on PF.
137*a6c384b2SMichal Wajdeczko  *
138*a6c384b2SMichal Wajdeczko  * Return: 0 on success or a negative error code on failure.
139*a6c384b2SMichal Wajdeczko  */
xe_sriov_pf_service_handshake_vf(struct xe_device * xe,u32 vfid,u32 wanted_major,u32 wanted_minor,u32 * major,u32 * minor)140*a6c384b2SMichal Wajdeczko int xe_sriov_pf_service_handshake_vf(struct xe_device *xe, u32 vfid,
141*a6c384b2SMichal Wajdeczko 				     u32 wanted_major, u32 wanted_minor,
142*a6c384b2SMichal Wajdeczko 				     u32 *major, u32 *minor)
143*a6c384b2SMichal Wajdeczko {
144*a6c384b2SMichal Wajdeczko 	int err;
145*a6c384b2SMichal Wajdeczko 
146*a6c384b2SMichal Wajdeczko 	xe_sriov_dbg_verbose(xe, "VF%u wants ABI version %u.%u\n",
147*a6c384b2SMichal Wajdeczko 			     vfid, wanted_major, wanted_minor);
148*a6c384b2SMichal Wajdeczko 
149*a6c384b2SMichal Wajdeczko 	err = pf_negotiate_version(xe, wanted_major, wanted_minor, major, minor);
150*a6c384b2SMichal Wajdeczko 
151*a6c384b2SMichal Wajdeczko 	if (err < 0) {
152*a6c384b2SMichal Wajdeczko 		xe_sriov_notice(xe, "VF%u failed to negotiate ABI %u.%u (%pe)\n",
153*a6c384b2SMichal Wajdeczko 				vfid, wanted_major, wanted_minor, ERR_PTR(err));
154*a6c384b2SMichal Wajdeczko 		pf_disconnect(xe, vfid);
155*a6c384b2SMichal Wajdeczko 	} else {
156*a6c384b2SMichal Wajdeczko 		xe_sriov_dbg(xe, "VF%u negotiated ABI version %u.%u\n",
157*a6c384b2SMichal Wajdeczko 			     vfid, *major, *minor);
158*a6c384b2SMichal Wajdeczko 		pf_connect(xe, vfid, *major, *minor);
159*a6c384b2SMichal Wajdeczko 	}
160*a6c384b2SMichal Wajdeczko 
161*a6c384b2SMichal Wajdeczko 	return err;
162*a6c384b2SMichal Wajdeczko }
163*a6c384b2SMichal Wajdeczko 
164*a6c384b2SMichal Wajdeczko /**
165*a6c384b2SMichal Wajdeczko  * xe_sriov_pf_service_reset_vf - Reset a connection with the VF.
166*a6c384b2SMichal Wajdeczko  * @xe: the &xe_device
167*a6c384b2SMichal Wajdeczko  * @vfid: the VF identifier
168*a6c384b2SMichal Wajdeczko  *
169*a6c384b2SMichal Wajdeczko  * Reset a VF driver negotiated VF/PF ABI version.
170*a6c384b2SMichal Wajdeczko  *
171*a6c384b2SMichal Wajdeczko  * After that point, the VF driver will have to perform new version handshake
172*a6c384b2SMichal Wajdeczko  * to continue use of the PF services again.
173*a6c384b2SMichal Wajdeczko  *
174*a6c384b2SMichal Wajdeczko  * This function can only be called on PF.
175*a6c384b2SMichal Wajdeczko  */
xe_sriov_pf_service_reset_vf(struct xe_device * xe,unsigned int vfid)176*a6c384b2SMichal Wajdeczko void xe_sriov_pf_service_reset_vf(struct xe_device *xe, unsigned int vfid)
177*a6c384b2SMichal Wajdeczko {
178*a6c384b2SMichal Wajdeczko 	pf_disconnect(xe, vfid);
179*a6c384b2SMichal Wajdeczko }
180*a6c384b2SMichal Wajdeczko 
print_pf_version(struct drm_printer * p,const char * name,const struct xe_sriov_pf_service_version * version)181*a6c384b2SMichal Wajdeczko static void print_pf_version(struct drm_printer *p, const char *name,
182*a6c384b2SMichal Wajdeczko 			     const struct xe_sriov_pf_service_version *version)
183*a6c384b2SMichal Wajdeczko {
184*a6c384b2SMichal Wajdeczko 	drm_printf(p, "%s:\t%u.%u\n", name, version->major, version->minor);
185*a6c384b2SMichal Wajdeczko }
186*a6c384b2SMichal Wajdeczko 
187*a6c384b2SMichal Wajdeczko /**
188*a6c384b2SMichal Wajdeczko  * xe_sriov_pf_service_print_versions - Print ABI versions negotiated with VFs.
189*a6c384b2SMichal Wajdeczko  * @xe: the &xe_device
190*a6c384b2SMichal Wajdeczko  * @p: the &drm_printer
191*a6c384b2SMichal Wajdeczko  *
192*a6c384b2SMichal Wajdeczko  * This function is for PF use only.
193*a6c384b2SMichal Wajdeczko  */
xe_sriov_pf_service_print_versions(struct xe_device * xe,struct drm_printer * p)194*a6c384b2SMichal Wajdeczko void xe_sriov_pf_service_print_versions(struct xe_device *xe, struct drm_printer *p)
195*a6c384b2SMichal Wajdeczko {
196*a6c384b2SMichal Wajdeczko 	unsigned int n, total_vfs = xe_sriov_pf_get_totalvfs(xe);
197*a6c384b2SMichal Wajdeczko 	struct xe_sriov_pf_service_version *version;
198*a6c384b2SMichal Wajdeczko 	char name[8];
199*a6c384b2SMichal Wajdeczko 
200*a6c384b2SMichal Wajdeczko 	xe_assert(xe, IS_SRIOV_PF(xe));
201*a6c384b2SMichal Wajdeczko 
202*a6c384b2SMichal Wajdeczko 	print_pf_version(p, "base", &xe->sriov.pf.service.version.base);
203*a6c384b2SMichal Wajdeczko 	print_pf_version(p, "latest", &xe->sriov.pf.service.version.latest);
204*a6c384b2SMichal Wajdeczko 
205*a6c384b2SMichal Wajdeczko 	for (n = 1; n <= total_vfs; n++) {
206*a6c384b2SMichal Wajdeczko 		version = &xe->sriov.pf.vfs[n].version;
207*a6c384b2SMichal Wajdeczko 		if (!version->major && !version->minor)
208*a6c384b2SMichal Wajdeczko 			continue;
209*a6c384b2SMichal Wajdeczko 
210*a6c384b2SMichal Wajdeczko 		print_pf_version(p, xe_sriov_function_name(n, name, sizeof(name)), version);
211*a6c384b2SMichal Wajdeczko 	}
212*a6c384b2SMichal Wajdeczko }
213*a6c384b2SMichal Wajdeczko 
214*a6c384b2SMichal Wajdeczko #if IS_BUILTIN(CONFIG_DRM_XE_KUNIT_TEST)
215*a6c384b2SMichal Wajdeczko #include "tests/xe_sriov_pf_service_kunit.c"
216*a6c384b2SMichal Wajdeczko #endif
217