File Index
Files and directories
Sign in
FILE

xe_sriov_pf_service.c

File preview with syntax highlighting.

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